00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026 #include "timeVaryingMappedFixedValueFvPatchField.H"
00027 #include <OpenFOAM/Time.H>
00028 #include <meshTools/triSurfaceTools.H>
00029 #include <triSurface/triSurface.H>
00030 #include <OpenFOAM/vector2D.H>
00031 #include <OpenFOAM/OFstream.H>
00032 #include <finiteVolume/AverageIOField.H>
00033 #include <OpenFOAM/Random.H>
00034
00035
00036
00037 namespace Foam
00038 {
00039
00040
00041
00042 template<class Type>
00043 timeVaryingMappedFixedValueFvPatchField<Type>::
00044 timeVaryingMappedFixedValueFvPatchField
00045 (
00046 const fvPatch& p,
00047 const DimensionedField<Type, volMesh>& iF
00048 )
00049 :
00050 fixedValueFvPatchField<Type>(p, iF),
00051 fieldTableName_(iF.name()),
00052 setAverage_(false),
00053 perturb_(0),
00054 referenceCS_(NULL),
00055 nearestVertex_(0),
00056 nearestVertexWeight_(0),
00057 sampleTimes_(0),
00058 startSampleTime_(-1),
00059 startSampledValues_(0),
00060 startAverage_(pTraits<Type>::zero),
00061 endSampleTime_(-1),
00062 endSampledValues_(0),
00063 endAverage_(pTraits<Type>::zero)
00064 {}
00065
00066
00067 template<class Type>
00068 timeVaryingMappedFixedValueFvPatchField<Type>::
00069 timeVaryingMappedFixedValueFvPatchField
00070 (
00071 const timeVaryingMappedFixedValueFvPatchField<Type>& ptf,
00072 const fvPatch& p,
00073 const DimensionedField<Type, volMesh>& iF,
00074 const fvPatchFieldMapper& mapper
00075 )
00076 :
00077 fixedValueFvPatchField<Type>(ptf, p, iF, mapper),
00078 fieldTableName_(ptf.fieldTableName_),
00079 setAverage_(ptf.setAverage_),
00080 perturb_(ptf.perturb_),
00081 referenceCS_(NULL),
00082 nearestVertex_(0),
00083 nearestVertexWeight_(0),
00084 sampleTimes_(0),
00085 startSampleTime_(-1),
00086 startSampledValues_(0),
00087 startAverage_(pTraits<Type>::zero),
00088 endSampleTime_(-1),
00089 endSampledValues_(0),
00090 endAverage_(pTraits<Type>::zero)
00091 {}
00092
00093
00094 template<class Type>
00095 timeVaryingMappedFixedValueFvPatchField<Type>::
00096 timeVaryingMappedFixedValueFvPatchField
00097 (
00098 const fvPatch& p,
00099 const DimensionedField<Type, volMesh>& iF,
00100 const dictionary& dict
00101 )
00102 :
00103 fixedValueFvPatchField<Type>(p, iF),
00104 fieldTableName_(iF.name()),
00105 setAverage_(readBool(dict.lookup("setAverage"))),
00106 perturb_(dict.lookupOrDefault("perturb", 1E-5)),
00107 referenceCS_(NULL),
00108 nearestVertex_(0),
00109 nearestVertexWeight_(0),
00110 sampleTimes_(0),
00111 startSampleTime_(-1),
00112 startSampledValues_(0),
00113 startAverage_(pTraits<Type>::zero),
00114 endSampleTime_(-1),
00115 endSampledValues_(0),
00116 endAverage_(pTraits<Type>::zero)
00117 {
00118 if (dict.found("fieldTableName"))
00119 {
00120 dict.lookup("fieldTableName") >> fieldTableName_;
00121 }
00122
00123 if (dict.found("value"))
00124 {
00125 fvPatchField<Type>::operator==(Field<Type>("value", dict, p.size()));
00126 }
00127 else
00128 {
00129 updateCoeffs();
00130 }
00131 }
00132
00133
00134 template<class Type>
00135 timeVaryingMappedFixedValueFvPatchField<Type>::
00136 timeVaryingMappedFixedValueFvPatchField
00137 (
00138 const timeVaryingMappedFixedValueFvPatchField<Type>& ptf
00139 )
00140 :
00141 fixedValueFvPatchField<Type>(ptf),
00142 fieldTableName_(ptf.fieldTableName_),
00143 setAverage_(ptf.setAverage_),
00144 perturb_(ptf.perturb_),
00145 referenceCS_(ptf.referenceCS_),
00146 nearestVertex_(ptf.nearestVertex_),
00147 nearestVertexWeight_(ptf.nearestVertexWeight_),
00148 sampleTimes_(ptf.sampleTimes_),
00149 startSampleTime_(ptf.startSampleTime_),
00150 startSampledValues_(ptf.startSampledValues_),
00151 startAverage_(ptf.startAverage_),
00152 endSampleTime_(ptf.endSampleTime_),
00153 endSampledValues_(ptf.endSampledValues_),
00154 endAverage_(ptf.endAverage_)
00155 {}
00156
00157
00158
00159 template<class Type>
00160 timeVaryingMappedFixedValueFvPatchField<Type>::
00161 timeVaryingMappedFixedValueFvPatchField
00162 (
00163 const timeVaryingMappedFixedValueFvPatchField<Type>& ptf,
00164 const DimensionedField<Type, volMesh>& iF
00165 )
00166 :
00167 fixedValueFvPatchField<Type>(ptf, iF),
00168 fieldTableName_(ptf.fieldTableName_),
00169 setAverage_(ptf.setAverage_),
00170 perturb_(ptf.perturb_),
00171 referenceCS_(ptf.referenceCS_),
00172 nearestVertex_(ptf.nearestVertex_),
00173 nearestVertexWeight_(ptf.nearestVertexWeight_),
00174 sampleTimes_(ptf.sampleTimes_),
00175 startSampleTime_(ptf.startSampleTime_),
00176 startSampledValues_(ptf.startSampledValues_),
00177 startAverage_(ptf.startAverage_),
00178 endSampleTime_(ptf.endSampleTime_),
00179 endSampledValues_(ptf.endSampledValues_),
00180 endAverage_(ptf.endAverage_)
00181 {}
00182
00183
00184
00185
00186 template<class Type>
00187 void timeVaryingMappedFixedValueFvPatchField<Type>::autoMap
00188 (
00189 const fvPatchFieldMapper& m
00190 )
00191 {
00192 fixedValueFvPatchField<Type>::autoMap(m);
00193 if (startSampledValues_.size())
00194 {
00195 startSampledValues_.autoMap(m);
00196 endSampledValues_.autoMap(m);
00197 }
00198 }
00199
00200
00201 template<class Type>
00202 void timeVaryingMappedFixedValueFvPatchField<Type>::rmap
00203 (
00204 const fvPatchField<Type>& ptf,
00205 const labelList& addr
00206 )
00207 {
00208 fixedValueFvPatchField<Type>::rmap(ptf, addr);
00209
00210 const timeVaryingMappedFixedValueFvPatchField<Type>& tiptf =
00211 refCast<const timeVaryingMappedFixedValueFvPatchField<Type> >(ptf);
00212
00213 startSampledValues_.rmap(tiptf.startSampledValues_, addr);
00214 endSampledValues_.rmap(tiptf.endSampledValues_, addr);
00215 }
00216
00217
00218 template<class Type>
00219 void timeVaryingMappedFixedValueFvPatchField<Type>::readSamplePoints()
00220 {
00221
00222
00223 pointIOField samplePoints
00224 (
00225 IOobject
00226 (
00227 "points",
00228 this->db().time().constant(),
00229 "boundaryData"/this->patch().name(),
00230 this->db(),
00231 IOobject::MUST_READ,
00232 IOobject::AUTO_WRITE,
00233 false
00234 )
00235 );
00236
00237 const fileName samplePointsFile = samplePoints.filePath();
00238
00239 if (debug)
00240 {
00241 Info<< "timeVaryingMappedFixedValueFvPatchField :"
00242 << " Read " << samplePoints.size() << " sample points from "
00243 << samplePointsFile << endl;
00244 }
00245
00246
00247
00248 if (samplePoints.size() < 3)
00249 {
00250 FatalErrorIn
00251 (
00252 "timeVaryingMappedFixedValueFvPatchField<Type>::readSamplePoints()"
00253 ) << "Only " << samplePoints.size() << " points read from file "
00254 << samplePoints.objectPath() << nl
00255 << "Need at least three non-colinear samplePoints"
00256 << " to be able to interpolate."
00257 << "\n on patch " << this->patch().name()
00258 << " of points " << samplePoints.name()
00259 << " in file " << samplePoints.objectPath()
00260 << exit(FatalError);
00261 }
00262
00263 const point& p0 = samplePoints[0];
00264
00265
00266 vector e1;
00267 label index1 = -1;
00268 scalar maxDist = -GREAT;
00269
00270 for (label i = 1; i < samplePoints.size(); i++)
00271 {
00272 const vector d = samplePoints[i] - p0;
00273 scalar magD = mag(d);
00274
00275 if (magD > maxDist)
00276 {
00277 e1 = d/magD;
00278 index1 = i;
00279 maxDist = magD;
00280 }
00281 }
00282
00283
00284 const point& p1 = samplePoints[index1];
00285
00286 label index2 = -1;
00287 maxDist = -GREAT;
00288 for (label i = 1; i < samplePoints.size(); i++)
00289 {
00290 if (i != index1)
00291 {
00292 const point& p2 = samplePoints[i];
00293 vector e2(p2 - p0);
00294 e2 -= (e2&e1)*e1;
00295 scalar magE2 = mag(e2);
00296
00297 if (magE2 > maxDist)
00298 {
00299 index2 = i;
00300 maxDist = magE2;
00301 }
00302 }
00303 }
00304
00305 if (index2 == -1)
00306 {
00307 FatalErrorIn
00308 (
00309 "timeVaryingMappedFixedValueFvPatchField<Type>::readSamplePoints()"
00310 ) << "Cannot find points that make valid normal." << nl
00311 << "Have so far points " << p0 << " and " << p1
00312 << "Need at least three sample points which are not in a line."
00313 << "\n on patch " << this->patch().name()
00314 << " of points " << samplePoints.name()
00315 << " in file " << samplePoints.objectPath()
00316 << exit(FatalError);
00317 }
00318
00319 vector n = e1^(samplePoints[index2]-p0);
00320
00321 n /= mag(n);
00322
00323 if (debug)
00324 {
00325 Info<< "timeVaryingMappedFixedValueFvPatchField :"
00326 << " Used points " << p0 << ' ' << samplePoints[index1]
00327 << ' ' << samplePoints[index2]
00328 << " to define coordinate system with normal " << n << endl;
00329 }
00330
00331 referenceCS_.reset
00332 (
00333 new coordinateSystem
00334 (
00335 "reference",
00336 p0,
00337 n,
00338 e1
00339 )
00340 );
00341
00342 tmp<vectorField> tlocalVertices
00343 (
00344 referenceCS().localPosition(samplePoints)
00345 );
00346 vectorField& localVertices = tlocalVertices();
00347
00348 const boundBox bb(localVertices, true);
00349 const point bbMid(bb.midpoint());
00350
00351 if (debug)
00352 {
00353 Info<< "timeVaryingMappedFixedValueFvPatchField :"
00354 << " Perturbing points with " << perturb_
00355 << " fraction of a random position inside " << bb
00356 << " to break any ties on regular meshes."
00357 << nl << endl;
00358 }
00359
00360 Random rndGen(123456);
00361 forAll(localVertices, i)
00362 {
00363 localVertices[i] +=
00364 perturb_
00365 *(rndGen.position(bb.min(), bb.max())-bbMid);
00366 }
00367
00368
00369 List<vector2D> localVertices2D(localVertices.size());
00370 forAll(localVertices, i)
00371 {
00372 localVertices2D[i][0] = localVertices[i][0];
00373 localVertices2D[i][1] = localVertices[i][1];
00374 }
00375
00376 triSurface s(triSurfaceTools::delaunay2D(localVertices2D));
00377
00378 tmp<pointField> tlocalFaceCentres
00379 (
00380 referenceCS().localPosition
00381 (
00382 this->patch().patch().faceCentres()
00383 )
00384 );
00385 const pointField& localFaceCentres = tlocalFaceCentres();
00386
00387 if (debug)
00388 {
00389 Pout<< "readSamplePoints :"
00390 <<" Dumping triangulated surface to triangulation.stl" << endl;
00391 s.write(this->db().time().path()/"triangulation.stl");
00392
00393 OFstream str(this->db().time().path()/"localFaceCentres.obj");
00394 Pout<< "readSamplePoints :"
00395 << " Dumping face centres to " << str.name() << endl;
00396
00397 forAll(localFaceCentres, i)
00398 {
00399 const point& p = localFaceCentres[i];
00400 str<< "v " << p.x() << ' ' << p.y() << ' ' << p.z() << nl;
00401 }
00402 }
00403
00404
00405 triSurfaceTools::calcInterpolationWeights
00406 (
00407 s,
00408 localFaceCentres,
00409 nearestVertex_,
00410 nearestVertexWeight_
00411 );
00412
00413
00414
00415
00416
00417 const fileName samplePointsDir = samplePointsFile.path();
00418
00419 sampleTimes_ = Time::findTimes(samplePointsDir);
00420
00421 if (debug)
00422 {
00423 Info<< "timeVaryingMappedFixedValueFvPatchField : In directory "
00424 << samplePointsDir << " found times " << timeNames(sampleTimes_)
00425 << endl;
00426 }
00427 }
00428
00429
00430 template<class Type>
00431 wordList timeVaryingMappedFixedValueFvPatchField<Type>::timeNames
00432 (
00433 const instantList& times
00434 )
00435 {
00436 wordList names(times.size());
00437
00438 forAll(times, i)
00439 {
00440 names[i] = times[i].name();
00441 }
00442 return names;
00443 }
00444
00445
00446 template<class Type>
00447 void timeVaryingMappedFixedValueFvPatchField<Type>::findTime
00448 (
00449 const fileName& instance,
00450 const fileName& local,
00451 const scalar timeVal,
00452 label& lo,
00453 label& hi
00454 ) const
00455 {
00456 lo = startSampleTime_;
00457 hi = -1;
00458
00459 for (label i = startSampleTime_+1; i < sampleTimes_.size(); i++)
00460 {
00461 if (sampleTimes_[i].value() > timeVal)
00462 {
00463 break;
00464 }
00465 else
00466 {
00467 lo = i;
00468 }
00469 }
00470
00471 if (lo == -1)
00472 {
00473 FatalErrorIn("findTime")
00474 << "Cannot find starting sampling values for current time "
00475 << timeVal << nl
00476 << "Have sampling values for times "
00477 << timeNames(sampleTimes_) << nl
00478 << "In directory "
00479 << this->db().time().constant()/"boundaryData"/this->patch().name()
00480 << "\n on patch " << this->patch().name()
00481 << " of field " << fieldTableName_
00482 << exit(FatalError);
00483 }
00484
00485 if (lo < sampleTimes_.size()-1)
00486 {
00487 hi = lo+1;
00488 }
00489
00490
00491 if (debug)
00492 {
00493 if (hi == -1)
00494 {
00495 Pout<< "findTime : Found time " << timeVal << " after"
00496 << " index:" << lo << " time:" << sampleTimes_[lo].value()
00497 << endl;
00498 }
00499 else
00500 {
00501 Pout<< "findTime : Found time " << timeVal << " inbetween"
00502 << " index:" << lo << " time:" << sampleTimes_[lo].value()
00503 << " and index:" << hi << " time:" << sampleTimes_[hi].value()
00504 << endl;
00505 }
00506 }
00507 }
00508
00509
00510 template<class Type>
00511 void timeVaryingMappedFixedValueFvPatchField<Type>::checkTable()
00512 {
00513
00514 if (startSampleTime_ == -1 && endSampleTime_ == -1)
00515 {
00516 readSamplePoints();
00517 }
00518
00519
00520 label lo = -1;
00521 label hi = -1;
00522
00523 findTime
00524 (
00525 this->db().time().constant(),
00526 "boundaryData"/this->patch().name(),
00527 this->db().time().value(),
00528 lo,
00529 hi
00530 );
00531
00532
00533
00534 if (lo != startSampleTime_)
00535 {
00536 startSampleTime_ = lo;
00537
00538 if (startSampleTime_ == endSampleTime_)
00539 {
00540
00541 if (debug)
00542 {
00543 Pout<< "checkTable : Setting startValues to (already read) "
00544 << "boundaryData"
00545 /this->patch().name()
00546 /sampleTimes_[startSampleTime_].name()
00547 << endl;
00548 }
00549 startSampledValues_ = endSampledValues_;
00550 startAverage_ = endAverage_;
00551 }
00552 else
00553 {
00554 if (debug)
00555 {
00556 Pout<< "checkTable : Reading startValues from "
00557 << "boundaryData"
00558 /this->patch().name()
00559 /sampleTimes_[lo].name()
00560 << endl;
00561 }
00562
00563
00564
00565 AverageIOField<Type> vals
00566 (
00567 IOobject
00568 (
00569 fieldTableName_,
00570 this->db().time().constant(),
00571 "boundaryData"
00572 /this->patch().name()
00573 /sampleTimes_[startSampleTime_].name(),
00574 this->db(),
00575 IOobject::MUST_READ,
00576 IOobject::AUTO_WRITE,
00577 false
00578 )
00579 );
00580
00581 startAverage_ = vals.average();
00582 startSampledValues_ = interpolate(vals);
00583 }
00584 }
00585
00586 if (hi != endSampleTime_)
00587 {
00588 endSampleTime_ = hi;
00589
00590 if (endSampleTime_ == -1)
00591 {
00592
00593 if (debug)
00594 {
00595 Pout<< "checkTable : Clearing endValues" << endl;
00596 }
00597 endSampledValues_.clear();
00598 }
00599 else
00600 {
00601 if (debug)
00602 {
00603 Pout<< "checkTable : Reading endValues from "
00604 << "boundaryData"
00605 /this->patch().name()
00606 /sampleTimes_[endSampleTime_].name()
00607 << endl;
00608 }
00609
00610 AverageIOField<Type> vals
00611 (
00612 IOobject
00613 (
00614 fieldTableName_,
00615 this->db().time().constant(),
00616 "boundaryData"
00617 /this->patch().name()
00618 /sampleTimes_[endSampleTime_].name(),
00619 this->db(),
00620 IOobject::MUST_READ,
00621 IOobject::AUTO_WRITE,
00622 false
00623 )
00624 );
00625 endAverage_ = vals.average();
00626 endSampledValues_ = interpolate(vals);
00627 }
00628 }
00629 }
00630
00631
00632 template<class Type>
00633 tmp<Field<Type> > timeVaryingMappedFixedValueFvPatchField<Type>::interpolate
00634 (
00635 const Field<Type>& sourceFld
00636 ) const
00637 {
00638 tmp<Field<Type> > tfld(new Field<Type>(nearestVertex_.size()));
00639 Field<Type>& fld = tfld();
00640
00641 forAll(fld, i)
00642 {
00643 const FixedList<label, 3>& verts = nearestVertex_[i];
00644 const FixedList<scalar, 3>& w = nearestVertexWeight_[i];
00645
00646 if (verts[2] == -1)
00647 {
00648 if (verts[1] == -1)
00649 {
00650
00651 fld[i] = sourceFld[verts[0]];
00652 }
00653 else
00654 {
00655
00656 fld[i] =
00657 w[0]*sourceFld[verts[0]]
00658 + w[1]*sourceFld[verts[1]];
00659 }
00660 }
00661 else
00662 {
00663 fld[i] =
00664 w[0]*sourceFld[verts[0]]
00665 + w[1]*sourceFld[verts[1]]
00666 + w[2]*sourceFld[verts[2]];
00667 }
00668 }
00669 return tfld;
00670 }
00671
00672
00673 template<class Type>
00674 void timeVaryingMappedFixedValueFvPatchField<Type>::updateCoeffs()
00675 {
00676 if (this->updated())
00677 {
00678 return;
00679 }
00680
00681 checkTable();
00682
00683
00684
00685 Type wantedAverage;
00686
00687 if (endSampleTime_ == -1)
00688 {
00689
00690 if (debug)
00691 {
00692 Pout<< "updateCoeffs : Sampled, non-interpolated values"
00693 << " from start time:"
00694 << sampleTimes_[startSampleTime_].name() << nl;
00695 }
00696
00697 this->operator==(startSampledValues_);
00698 wantedAverage = startAverage_;
00699 }
00700 else
00701 {
00702 scalar start = sampleTimes_[startSampleTime_].value();
00703 scalar end = sampleTimes_[endSampleTime_].value();
00704
00705 scalar s = (this->db().time().value()-start)/(end-start);
00706
00707 if (debug)
00708 {
00709 Pout<< "updateCoeffs : Sampled, interpolated values"
00710 << " between start time:"
00711 << sampleTimes_[startSampleTime_].name()
00712 << " and end time:" << sampleTimes_[endSampleTime_].name()
00713 << " with weight:" << s << endl;
00714 }
00715
00716 this->operator==((1-s)*startSampledValues_ + s*endSampledValues_);
00717 wantedAverage = (1-s)*startAverage_ + s*endAverage_;
00718 }
00719
00720
00721
00722 if (setAverage_)
00723 {
00724 const Field<Type>& fld = *this;
00725
00726 Type averagePsi =
00727 gSum(this->patch().magSf()*fld)
00728 /gSum(this->patch().magSf());
00729
00730 if (debug)
00731 {
00732 Pout<< "updateCoeffs :"
00733 << " actual average:" << averagePsi
00734 << " wanted average:" << wantedAverage
00735 << endl;
00736 }
00737
00738 if (mag(averagePsi) < VSMALL)
00739 {
00740
00741 const Type offset = wantedAverage - averagePsi;
00742 if (debug)
00743 {
00744 Pout<< "updateCoeffs :"
00745 << " offsetting with:" << offset << endl;
00746 }
00747 this->operator==(fld+offset);
00748 }
00749 else
00750 {
00751 const scalar scale = mag(wantedAverage)/mag(averagePsi);
00752
00753 if (debug)
00754 {
00755 Pout<< "updateCoeffs :"
00756 << " scaling with:" << scale << endl;
00757 }
00758 this->operator==(scale*fld);
00759 }
00760 }
00761
00762 if (debug)
00763 {
00764 Pout<< "updateCoeffs : set fixedValue to min:" << gMin(*this)
00765 << " max:" << gMax(*this) << endl;
00766 }
00767
00768 fixedValueFvPatchField<Type>::updateCoeffs();
00769 }
00770
00771
00772 template<class Type>
00773 void timeVaryingMappedFixedValueFvPatchField<Type>::write(Ostream& os) const
00774 {
00775 fvPatchField<Type>::write(os);
00776 os.writeKeyword("setAverage") << setAverage_ << token::END_STATEMENT << nl;
00777 os.writeKeyword("peturb") << perturb_ << token::END_STATEMENT << nl;
00778
00779 if (fieldTableName_ != this->dimensionedInternalField().name())
00780 {
00781 os.writeKeyword("fieldTableName") << fieldTableName_
00782 << token::END_STATEMENT << nl;
00783 }
00784
00785 this->writeEntry("value", os);
00786 }
00787
00788
00789
00790
00791 }
00792
00793