52 Foam::vector Foam::cyclicAMIPolyPatch::findFaceNormalMaxRadius
63 label facei =
findMax(magRadSqr);
66 <<
"Patch: " <<
name() <<
nl 67 <<
" rotFace = " << facei <<
nl 69 <<
" distance = " <<
Foam::sqrt(magRadSqr[facei])
89 <<
" has transform type " << transformTypeNames[
transform()]
90 <<
", neighbour patch " << neighbPatchName()
91 <<
" has transform type " 92 << neighbPatch().transformTypeNames[neighbPatch().transform()]
105 if (rotationAngleDefined_)
107 const tensor T(rotationAxis_*rotationAxis_);
111 0, -rotationAxis_.z(), rotationAxis_.y(),
112 rotationAxis_.z(), 0, -rotationAxis_.x(),
113 -rotationAxis_.y(), rotationAxis_.x(), 0
120 +
sin(rotationAngle_)*S
127 +
sin(-rotationAngle_)*S
132 const vector transformedAreaPos =
gSum(half1Areas & revTPos);
133 const vector transformedAreaNeg =
gSum(half1Areas & revTNeg);
135 const scalar magArea0 =
mag(area0) + ROOTVSMALL;
139 const scalar errorPos =
mag(transformedAreaPos + area0);
140 const scalar errorNeg =
mag(transformedAreaNeg + area0);
142 const scalar normErrorPos = errorPos/magArea0;
143 const scalar normErrorNeg = errorNeg/magArea0;
145 if (errorPos > errorNeg && normErrorNeg < matchTolerance())
148 rotationAngle_ *= -1;
155 const scalar areaError =
min(normErrorPos, normErrorNeg);
157 if (areaError > matchTolerance())
160 <<
"Patch areas are not consistent within " 161 << 100*matchTolerance()
162 <<
" % indicating a possible error in the specified " 163 <<
"angle of rotation" <<
nl 164 <<
" owner patch : " <<
name() <<
nl 165 <<
" neighbour patch : " << neighbPatch().name()
169 <<
" area error : " << 100*areaError <<
" %" 170 <<
" match tolerance : " << matchTolerance()
176 scalar theta =
radToDeg(rotationAngle_);
178 Pout<<
"cyclicAMIPolyPatch::calcTransforms: patch:" 180 <<
" Specified rotation:" 181 <<
" swept angle: " << theta <<
" [deg]" 182 <<
" reverse transform: " << revT
190 if (half0Ctrs.size())
192 n0 = findFaceNormalMaxRadius(half0Ctrs);
194 if (half1Ctrs.size())
196 n1 = -findFaceNormalMaxRadius(half1Ctrs);
199 reduce(n0, maxMagSqrOp<point>());
200 reduce(n1, maxMagSqrOp<point>());
210 (n0 ^ rotationAxis_),
216 (-n1 ^ rotationAxis_),
225 Pout<<
"cyclicAMIPolyPatch::calcTransforms: patch:" 227 <<
" Specified rotation:" 228 <<
" n0:" << n0 <<
" n1:" << n1
229 <<
" swept angle: " << theta <<
" [deg]" 230 <<
" reverse transform: " << revT
246 Pout<<
"cyclicAMIPolyPatch::calcTransforms : patch:" <<
name()
247 <<
" Specified translation : " << separationVector_
267 <<
" Assuming cyclic AMI pairs are colocated" <<
endl;
282 <<
" forwardT = " << forwardT() <<
nl 283 <<
" reverseT = " << reverseT() <<
nl 284 <<
" separation = " << separation() <<
nl 285 <<
" collocated = " << collocated() <<
nl <<
endl;
293 const label periodicID = periodicPatchID();
294 if (periodicID != -1)
297 const coupledPolyPatch& perPp =
298 refCast<const coupledPolyPatch>(boundaryMesh()[periodicID]);
300 if (!perPp.parallel())
307 const cyclicPolyPatch* cpp = isA<cyclicPolyPatch>(perPp)
310 axis = cpp->rotationAxis();
311 axisPoint = cpp->rotationCentre();
315 const cyclicAMIPolyPatch* cpp = isA<cyclicAMIPolyPatch>(perPp)
318 axis = cpp->rotationAxis();
319 axisPoint = cpp->rotationCentre();
324 <<
" have unsupported periodicPatch " << perPp.name()
340 const word surfType(surfDict_.getOrDefault<
word>(
"type",
"none"));
342 if (!surfPtr_ && owner() && surfType !=
"none")
344 word surfName(surfDict_.getOrDefault(
"name",
name()));
384 const cyclicAMIPolyPatch& nbr = neighbPatch();
388 Info<<
"AMI: Creating AMI for source:" <<
name()
389 <<
" and target:" << nbr.name() <<
endl;
393 const Time& t = boundaryMesh().mesh().time();
394 OFstream
os(t.path()/
name() +
"_neighbourPatch-org.obj");
398 label patchSize0 = size();
399 label nbrPatchSize0 = nbr.size();
404 if (srcFaceIDs_.size())
406 patchSize0 = srcFaceIDs_.size();
408 if (tgtFaceIDs_.size())
410 nbrPatchSize0 = tgtFaceIDs_.size();
415 transformPosition(nbrPoints);
418 SubList<face>(nbr.localFaces(), nbrPatchSize0),
423 SubList<face>(localFaces(), patchSize0),
430 const Time& t = boundaryMesh().mesh().time();
431 OFstream osN(t.path()/
name() +
"_neighbourPatch-trans.obj");
434 OFstream osO(t.path()/
name() +
"_ownerPatch.obj");
439 AMIPtr_->upToDate(
false);
442 AMIPtr_->comm(boundaryMesh().
mesh().comm());
443 AMIPtr_->calculate(patch0, nbrPatch0, surfPtr());
447 AMIPtr_->checkSymmetricWeights(
true);
456 const cyclicAMIPolyPatch& half0 = *
this;
460 half0Areas[facei] = half0[facei].areaNormal(half0.points());
463 const cyclicAMIPolyPatch& half1 = neighbPatch();
467 half1Areas[facei] = half1[facei].areaNormal(half1.points());
480 <<
"calcTransforms() : patch: " <<
name() <<
nl 481 <<
" forwardT = " << forwardT() <<
nl 482 <<
" reverseT = " << reverseT() <<
nl 483 <<
" separation = " << separation() <<
nl 484 <<
" collocated = " << collocated() <<
nl <<
endl;
493 AMIPtr_->upToDate(
false);
533 restoreScaledGeometry();
539 AMIPtr_->upToDate(
false);
599 AMIPtr_->upToDate(
false);
615 const word& patchType,
617 const word& defaultAMIMethod
625 rotationCentre_(
Zero),
626 rotationAngleDefined_(false),
628 separationVector_(
Zero),
629 periodicPatchName_(),
630 periodicPatchID_(-1),
634 createAMIFaces_(false),
635 moveFaceCentres_(false),
653 const word& patchType,
654 const word& defaultAMIMethod
658 nbrPatchName_(
dict.getOrDefault<
word>(
"neighbourPatch",
word::null)),
661 fraction_(
dict.getOrDefault<scalar>(
"fraction",
Zero)),
663 rotationCentre_(
Zero),
664 rotationAngleDefined_(false),
666 separationVector_(
Zero),
667 periodicPatchName_(
dict.getOrDefault<
word>(
"periodicPatch",
word::null)),
668 periodicPatchID_(-1),
673 dict.getOrDefault<
word>(
"AMIMethod", defaultAMIMethod),
675 dict.getOrDefault(
"flipNormals", false)
678 surfDict_(
dict.subOrEmptyDict(
"surface")),
680 createAMIFaces_(
dict.getOrDefault(
"createAMIFaces", false)),
681 moveFaceCentres_(false),
691 <<
"No \"neighbourPatch\" or \"coupleGroup\" provided." 699 <<
" cannot be the same as this patch " <<
name 726 <<
"Please supply a non-zero vector." 760 const cyclicAMIPolyPatch&
pp,
761 const polyBoundaryMesh& bm
764 coupledPolyPatch(
pp, bm),
765 nbrPatchName_(
pp.nbrPatchName_),
766 coupleGroup_(
pp.coupleGroup_),
768 fraction_(
pp.fraction_),
769 rotationAxis_(
pp.rotationAxis_),
770 rotationCentre_(
pp.rotationCentre_),
771 rotationAngleDefined_(
pp.rotationAngleDefined_),
772 rotationAngle_(
pp.rotationAngle_),
773 separationVector_(
pp.separationVector_),
774 periodicPatchName_(
pp.periodicPatchName_),
775 periodicPatchID_(-1),
776 AMIPtr_(
pp.AMIPtr_->clone()),
777 surfDict_(
pp.surfDict_),
779 createAMIFaces_(
pp.createAMIFaces_),
780 moveFaceCentres_(
pp.moveFaceCentres_),
798 const label newStart,
799 const word& nbrPatchName
803 nbrPatchName_(nbrPatchName),
804 coupleGroup_(
pp.coupleGroup_),
806 fraction_(
pp.fraction_),
807 rotationAxis_(
pp.rotationAxis_),
808 rotationCentre_(
pp.rotationCentre_),
809 rotationAngleDefined_(
pp.rotationAngleDefined_),
810 rotationAngle_(
pp.rotationAngle_),
811 separationVector_(
pp.separationVector_),
812 periodicPatchName_(
pp.periodicPatchName_),
813 periodicPatchID_(-1),
814 AMIPtr_(
pp.AMIPtr_->clone()),
815 surfDict_(
pp.surfDict_),
817 createAMIFaces_(
pp.createAMIFaces_),
818 moveFaceCentres_(
pp.moveFaceCentres_),
829 <<
" cannot be the same as this patch " <<
name()
848 nbrPatchName_(
pp.nbrPatchName_),
849 coupleGroup_(
pp.coupleGroup_),
851 fraction_(
pp.fraction_),
852 rotationAxis_(
pp.rotationAxis_),
853 rotationCentre_(
pp.rotationCentre_),
854 rotationAngleDefined_(
pp.rotationAngleDefined_),
855 rotationAngle_(
pp.rotationAngle_),
856 separationVector_(
pp.separationVector_),
857 periodicPatchName_(
pp.periodicPatchName_),
858 periodicPatchID_(-1),
859 AMIPtr_(
pp.AMIPtr_->clone()),
860 surfDict_(
pp.surfDict_),
862 createAMIFaces_(
pp.createAMIFaces_),
863 moveFaceCentres_(
pp.moveFaceCentres_),
882 forAll (addSourceFaces, faceI)
884 const labelList& nbrFaceIs = addSourceFaces[faceI];
888 label nbrFaceI = nbrFaceIs[j];
890 if (nbrFaceI < neighbPatch().size())
907 if (nbrPatchID_ == -1)
909 nbrPatchID_ = this->boundaryMesh().findPatchID(neighbPatchName());
911 if (nbrPatchID_ == -1)
914 <<
"Illegal neighbourPatch name " << neighbPatchName()
915 <<
nl <<
"Valid patch names are " 916 << this->boundaryMesh().names()
921 const cyclicAMIPolyPatch& nbrPatch =
922 refCast<const cyclicAMIPolyPatch>
924 this->boundaryMesh()[nbrPatchID_]
927 if (nbrPatch.neighbPatchName() !=
name())
930 <<
"Patch " <<
name()
931 <<
" specifies neighbour patch " << neighbPatchName()
932 <<
nl <<
" but that in return specifies " 933 << nbrPatch.neighbPatchName() <<
endl;
943 if (periodicPatchName_.empty())
949 if (periodicPatchID_ == -1)
951 periodicPatchID_ = boundaryMesh().findPatchID(periodicPatchName_);
953 if (periodicPatchID_ == -1)
956 <<
"Illegal neighbourPatch name " << periodicPatchName_
957 <<
nl <<
"Valid patch names are " 958 << this->boundaryMesh().names()
962 return periodicPatchID_;
969 return index() < neighbPatchID();
976 return refCast<const cyclicAMIPolyPatch>(
pp);
985 <<
"AMI interpolator only available to owner patch" 989 if (!AMIPtr_->upToDate())
1002 return AMI().applyLowWeightCorrection();
1006 return neighbPatch().AMI().applyLowWeightCorrection();
1025 else if (separated())
1056 forwardT().size() == 1
1070 else if (separated())
1074 separation().size() == 1
1076 : separation()[facei]
1094 reverseT().size() == 1
1108 else if (separated())
1112 separation().size() == 1
1114 : separation()[facei]
1132 reverseT().size() == 1
1189 reverseTransformPosition(prt, facei);
1192 reverseTransformDirection(nrt, facei);
1194 label nbrFacei = -1;
1198 nbrFacei = AMI().tgtPointFace
1209 nbrFacei = neighbPatch().AMI().srcPointFace
1231 if (!nbrPatchName_.empty())
1244 if (rotationAngleDefined_)
1266 if (!periodicPatchName_.empty())
1273 if (!surfDict_.empty())
1275 surfDict_.writeEntry(surfDict_.dictName(),
os);
1278 if (createAMIFaces_)
virtual void clearGeom()
Clear geometry.
virtual void resetAMI() const
Reset the AMI interpolator, use current patch points.
label findMax(const ListType &input, label start=0)
Linear search for the index of the max element, similar to std::max_element but for lists and returns...
vector separationVector_
Translation vector.
dimensionedScalar acos(const dimensionedScalar &ds)
const AMIPatchToPatchInterpolation & AMI() const
Return a reference to the AMI interpolator.
virtual label neighbPatchID() const
Neighbour patch ID.
virtual void write(Ostream &os) const
Write the polyPatch data as a dictionary.
virtual bool order(PstreamBuffers &, const primitivePatch &, labelList &faceMap, labelList &rotation) const
Return new ordering for primitivePatch.
A class for handling file names.
cyclicAMIPolyPatch(const word &name, const label size, const label start, const label index, const polyBoundaryMesh &bm, const word &patchType, const transformType transform=UNKNOWN, const word &defaultAMIMethod=faceAreaWeightAMI::typeName)
Construct from (base coupled patch) components.
autoPtr< coordSystem::cylindrical > cylindricalCS() const
Create a coordinate system from the periodic patch (or nullptr)
errorManipArg< error, int > exit(error &err, const int errNo=1)
virtual void initUpdateMesh(PstreamBuffers &)
Initialise the update of the patch topology.
dimensioned< typename typeOfMag< Type >::type > mag(const dimensioned< Type > &dt)
virtual void initGeometry(PstreamBuffers &)
Initialise the calculation of the patch geometry.
error FatalError
Error stream (stdout output on all processes), with additional 'FOAM FATAL ERROR' header text and sta...
A list of keyword definitions, which are a keyword followed by a number of values (eg...
#define FatalErrorInFunction
Report an error message using Foam::FatalError.
virtual void initUpdateMesh(PstreamBuffers &)
Initialise the update of the patch topology.
bool moveFaceCentres_
Move face centres (default = no)
Unit conversion functions.
virtual void write(Ostream &) const
Write the polyPatch data as a dictionary.
constexpr char nl
The newline '\n' character (0x0a)
static const scalar tolerance_
Tolerance used e.g. for area calculations/limits.
virtual void calcTransforms()
Recalculate the transformation tensors.
Addressing for all faces on surface of mesh. Can either be read from polyMesh or from triSurface...
dimensionedScalar sqrt(const dimensionedScalar &ds)
Ostream & endl(Ostream &os)
Add newline and flush stream.
tmp< DimensionedField< TypeR, GeoMesh > > New(const tmp< DimensionedField< TypeR, GeoMesh >> &tf1, const word &name, const dimensionSet &dimensions, const bool initCopy=false)
Global function forwards to reuseTmpDimensionedField::New.
virtual void transformPosition(pointField &) const
Transform patch-based positions from nbr side to this side.
bool applyLowWeightCorrection() const
Return true if applying the low weight correction.
The coupledPolyPatch is an abstract base class for patches that couple regions of the computational d...
vector rotationAxis_
Axis of rotation for rotational cyclics.
Ostream & writeEntry(const keyType &key, const T &value)
Write a keyword/value entry.
bool rotationAngleDefined_
Flag to show whether the rotation angle is defined.
virtual void reverseTransformDirection(vector &d, const label facei) const
Transform a patch-based direction from this side to nbr side.
Ignore writing from objectRegistry::writeObject()
const Time & time() const
Return the top-level database.
Macros for easy insertion into run-time selection tables.
virtual void newInternalProcFaces(label &, label &) const
Return number of new internal of this polyPatch faces.
Pair< int > faceMap(const label facePi, const face &faceP, const label faceNi, const face &faceN)
virtual void clearGeom()
Clear geometry.
bool createAMIFaces_
Flag to indicate that new AMI faces will created.
#define forAll(list, i)
Loop across all elements in list.
virtual void calcGeometry(PstreamBuffers &)
Calculate the patch geometry.
virtual void movePoints(const Field< point_type > &)
Correct patch after moving points.
const coupleGroupIdentifier coupleGroup_
Optional patchGroup to find neighbPatch.
A list of faces which address into the list of points.
vectorField pointField
pointField is a vectorField.
const dimensionedScalar e
Elementary charge.
void setSize(const label n)
Alias for resize()
Type gSum(const FieldField< Field, Type > &f)
dimensionedScalar cos(const dimensionedScalar &ds)
word name(const expressions::valueTypeCode typeCode)
A word representation of a valueTypeCode. Empty for expressions::valueTypeCode::INVALID.
bool good() const noexcept
The patchGroup has a non-empty name.
static const Identity< scalar > I
A class for handling words, derived from Foam::string.
const autoPtr< searchableSurface > & surfPtr() const
Create and return pointer to the projection surface.
Field< scalar > scalarField
Specialisation of Field<T> for scalar.
#define DebugInFunction
Report an information message using Foam::Info.
point rotationCentre_
Point on axis of rotation for rotational cyclics.
virtual void updateMesh(PstreamBuffers &)
Update of the patch topology.
virtual bool write(const token &tok)=0
Write token to stream or otherwise handle it.
virtual void updateMesh(PstreamBuffers &)
Update of the patch topology.
Cyclic patch for Arbitrary Mesh Interface (AMI)
label periodicPatchID() const
Periodic patch ID (or -1)
label min(const labelHashSet &set, label minValue=labelMax)
Find the min value in labelHashSet, optionally limited by second argument.
errorManip< error > abort(error &err)
Ostream & writeEntryIfDifferent(const word &key, const T &value1, const T &value2)
Write a keyword/value entry only when the two values differ.
A 1D vector of objects of type <T>, where the size of the vector is known and can be used for subscri...
A polyBoundaryMesh is a polyPatch list with additional search methods and registered IO...
const word & name() const noexcept
The patch name.
dimensionedScalar sin(const dimensionedScalar &ds)
A Vector of values with scalar precision, where scalar is float/double depending on the compilation f...
const word & constant() const noexcept
Return constant name.
int debug
Static debugging option.
OBJstream os(runTime.globalPath()/outputName)
defineTypeNameAndDebug(combustionModel, 0)
Buffers for inter-processor communications streams (UOPstream, UIPstream).
void T(FieldField< Field, Type > &f1, const FieldField< Field, Type > &f2)
PrimitivePatch< SubList< face >, const pointField & > primitivePatch
A PrimitivePatch with a SubList addressing for the faces, const reference for the point field...
labelListList srcFaceIDs_
virtual void initGeometry(PstreamBuffers &)
Initialise the calculation of the patch geometry.
Field< tensor > tensorField
Specialisation of Field<T> for tensor.
virtual void initOrder(PstreamBuffers &, const primitivePatch &) const
Initialize ordering for primitivePatch. Does not refer to *this (except for name() and type() etc...
vector point
Point is a vector.
#define WarningInFunction
Report a warning using Foam::Warning.
#define FatalIOErrorInFunction(ios)
Report an error message using Foam::FatalIOError.
constexpr scalar radToDeg(const scalar rad) noexcept
Conversion from radians to degrees.
virtual const cyclicAMIPolyPatch & neighbPatch() const
Return a reference to the neighbour patch.
virtual bool owner() const
Does this side own the patch?
labelListList tgtFaceIDs_
Interpolation class dealing with transfer of data between two primitive patches with an arbitrary mes...
static autoPtr< searchableSurface > New(const word &surfaceType, const IOobject &io, const dictionary &dict)
Return a reference to the selected searchableSurface.
#define DebugPout
Report an information message using Foam::Pout.
messageStream Info
Information stream (stdout output on master, null elsewhere)
virtual transformType transform() const
Type of transform.
Field< vector > vectorField
Specialisation of Field<T> for vector.
Pointer management similar to std::unique_ptr, with some additional methods and type checking...
Mesh consisting of general polyhedral cells.
const bMesh & mesh() const
static autoPtr< T > New(Args &&... args)
Construct autoPtr with forwarding arguments.
A patch is a list of labels that address the faces in the global face list.
gmvFile<< "tracers "<< particles.size()<< nl;for(const passiveParticle &p :particles){ gmvFile<< p.position().x()<< " ";}gmvFile<< nl;for(const passiveParticle &p :particles){ gmvFile<< p.position().y()<< " ";}gmvFile<< nl;for(const passiveParticle &p :particles){ gmvFile<< p.position().z()<< " ";}gmvFile<< nl;forAll(lagrangianScalarNames, i){ word name=lagrangianScalarNames[i];IOField< scalar > s(IOobject(name, runTime.timeName(), cloud::prefix, mesh, IOobject::MUST_READ, IOobject::NO_WRITE))
dimensionSet transform(const dimensionSet &ds)
Return the argument; transformations do not change the dimensions.
constexpr scalar degToRad(const scalar deg) noexcept
Conversion from degrees to radians.
Defines the attributes of an object for which implicit objectRegistry management is supported...
List< bool > boolList
A List of bools.
word nbrPatchName_
Name of other half.
virtual void reverseTransformPosition(point &l, const label facei) const
Transform a patch-based position from this side to nbr side.
prefixOSstream Pout
OSstream wrapped stdout (std::cout) with parallel prefix.
void reduce(T &value, const BinaryOp &bop, const int tag=UPstream::msgType(), const label comm=UPstream::worldComm)
Reduce inplace (cf. MPI Allreduce) using linear/tree communication schedule.
scalar rotationAngle_
Rotation angle.
dimensioned< typename typeOfMag< Type >::type > magSqr(const dimensioned< Type > &dt)
label pointFace(const label facei, const vector &n, point &p) const
Return face index on neighbour patch which shares point p following trajectory vector n...
uindirectPrimitivePatch pp(UIndirectList< face >(mesh.faces(), faceLabels), mesh.points())
addToRunTimeSelectionTable(functionObject, pointHistory, dictionary)
virtual void movePoints(PstreamBuffers &pBufs, const pointField &)
Correct patches after moving points.
virtual void initMovePoints(PstreamBuffers &pBufs, const pointField &)
Initialise the patches for moving points.
IOerror FatalIOError
Error stream (stdout output on all processes), with additional 'FOAM FATAL IO ERROR' header text and ...
static constexpr const zero Zero
Global zero (0)
const vectorField::subField faceCentres() const
Return face centres.