AMIWeights.C
Go to the documentation of this file.
1 /*---------------------------------------------------------------------------*\
2  ========= |
3  \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
4  \\ / O peration |
5  \\ / A nd | www.openfoam.com
6  \\/ M anipulation |
7 -------------------------------------------------------------------------------
8  Copyright (C) 2018-2021 OpenCFD Ltd.
9 -------------------------------------------------------------------------------
10 License
11  This file is part of OpenFOAM.
12 
13  OpenFOAM is free software: you can redistribute it and/or modify it
14  under the terms of the GNU General Public License as published by
15  the Free Software Foundation, either version 3 of the License, or
16  (at your option) any later version.
17 
18  OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
19  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
20  FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
21  for more details.
22 
23  You should have received a copy of the GNU General Public License
24  along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
25 
26 \*---------------------------------------------------------------------------*/
27 
28 #include "AMIWeights.H"
29 #include "fvMesh.H"
30 #include "foamVtkSurfaceWriter.H"
31 #include "PatchTools.H"
32 #include "cyclicACMIPolyPatch.H"
34 
35 // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
36 
37 namespace Foam
38 {
39 namespace functionObjects
40 {
43 }
44 }
45 
46 // * * * * * * * * * * * * Protected Member Functions * * * * * * * * * * * //
47 
49 {
50  writeHeader(os, "AMI");
51 
52  writeCommented(os, "Time");
53  forAll(patchIDs_, patchi)
54  {
55  writeTabbed(os, "Patch");
56  writeTabbed(os, "nbr_patch");
57 
58  if (UPstream::parRun())
59  {
60  writeTabbed(os, "distributed");
61  }
62 
63  writeTabbed(os, "src_min_weight");
64  writeTabbed(os, "src_max_weight");
65  writeTabbed(os, "src_average_weight");
66  writeTabbed(os, "src_min_neighbours");
67  writeTabbed(os, "src_max_neighbours");
68  writeTabbed(os, "src_average_neighbours");
69  writeTabbed(os, "tgt_min_weight");
70  writeTabbed(os, "tgt_max_weight");
71  writeTabbed(os, "tgt_average_weight");
72  writeTabbed(os, "tgt_min_neighbours");
73  writeTabbed(os, "tgt_max_neighbours");
74  writeTabbed(os, "tgt_average_neighbours");
75  }
76 
77  os << endl;
78 }
79 
80 
82 (
83  const cyclicAMIPolyPatch& pp
84 )
85 {
86  const word& nbrPatchName = pp.neighbPatchName();
87 
88  const Switch distributed = pp.AMI().distributed();
89 
90  const scalarField& srcWeightsSum = pp.AMI().srcWeightsSum();
91  const auto srcWeightLimits = gMinMax(srcWeightsSum);
92  const auto srcWeightAvg = gAverage(srcWeightsSum);
93 
94  const labelListList& srcAddress = pp.AMI().srcAddress();
95 
96  labelMinMax srcNbrLimits(labelMax, labelMin);
97  scalar srcNbrAvg(0);
98  for (const labelList& srcFace : srcAddress)
99  {
100  const label n = srcFace.size();
101 
102  srcNbrAvg += n;
103  srcNbrLimits.add(n);
104  }
105 
106  {
107  reduce(srcNbrLimits, sumOp<labelMinMax>());
108 
109  label count = srcAddress.size();
110  sumReduce(srcNbrAvg, count);
111  srcNbrAvg /= (count + ROOTVSMALL);
112  }
113 
114  const scalarField& tgtWeightsSum = pp.AMI().tgtWeightsSum();
115  const auto tgtWeightLimits = gMinMax(tgtWeightsSum);
116  const auto tgtWeightAvg = gAverage(tgtWeightsSum);
117 
118  const labelListList& tgtAddress = pp.AMI().tgtAddress();
119 
120  labelMinMax tgtNbrLimits(labelMax, labelMin);
121  scalar tgtNbrAvg(0);
122  for (const labelList& tgtFace : tgtAddress)
123  {
124  const label n = tgtFace.size();
125 
126  tgtNbrAvg += n;
127  tgtNbrLimits.add(n);
128  }
129 
130  {
131  reduce(tgtNbrLimits, sumOp<labelMinMax>());
132 
133  label count = tgtAddress.size();
134  sumReduce(tgtNbrAvg, count);
135  tgtNbrAvg /= (count + ROOTVSMALL);
136  }
137 
138  file()
139  << mesh_.time().timeName() << tab
140  << pp.name() << tab
141  << nbrPatchName << tab;
142 
143 
144  if (UPstream::parRun())
145  {
146  file() << distributed << tab;
147  }
148 
149  file()
150  << srcWeightLimits.min() << tab
151  << srcWeightLimits.max() << tab
152  << srcWeightAvg << tab
153  << srcNbrLimits.min() << tab
154  << srcNbrLimits.max() << tab
155  << srcNbrAvg << tab
156  << tgtWeightLimits.min() << tab
157  << tgtWeightLimits.max() << tab
158  << tgtWeightAvg << tab
159  << tgtNbrLimits.min() << tab
160  << tgtNbrLimits.max() << tab
161  << tgtNbrAvg
162  << endl;
163 
164  Log << " Patches: " << nl
165  << " Source: " << pp.name() << nl
166  << " Target: " << nbrPatchName << nl;
167 
168  if (UPstream::parRun())
169  {
170  Log << " Parallel distributed: " << distributed << nl;
171  }
172 
173  Log << nl;
174 
175  const label w = IOstream::defaultPrecision() + 8;
176 
177  Log << " | " << setw(w) << pp.name()
178  << " | " << setw(w) << nbrPatchName << " | " << nl
179  << " min(weight) | " << setw(w) << srcWeightLimits.min()
180  << " | " << setw(w) << tgtWeightLimits.min() << " | " << nl
181  << " max(weight) | " << setw(w) << srcWeightLimits.max()
182  << " | " << setw(w) << tgtWeightLimits.max() << " | " << nl
183  << " ave(weight) | " << setw(w) << srcWeightAvg
184  << " | " << setw(w) << tgtWeightAvg << " | " << nl
185  << " min(address) | " << setw(w) << srcNbrLimits.min()
186  << " | " << setw(w) << tgtNbrLimits.min() << " | " << nl
187  << " max(address) | " << setw(w) << srcNbrLimits.max()
188  << " | " << setw(w) << tgtNbrLimits.max() << " | " << nl
189  << " ave(address) | " << setw(w) << srcNbrAvg
190  << " | " << setw(w) << tgtNbrAvg << " | " << nl
191  << endl;
192 
193  setResult(pp.name() + ":src", pp.name());
194  setResult(pp.name() + ":tgt", nbrPatchName);
195  setResult(pp.name() + ":src:min(weight)", srcWeightLimits.min());
196  setResult(pp.name() + ":src:max(weight)", srcWeightLimits.max());
197  setResult(pp.name() + ":src:ave(weight)", srcWeightAvg);
198  setResult(pp.name() + ":src:min(address)", srcNbrLimits.min());
199  setResult(pp.name() + ":src:max(address)", srcNbrLimits.max());
200  setResult(pp.name() + ":src:ave(address)", srcNbrAvg);
201  setResult(pp.name() + ":tgt:min(weight)", tgtWeightLimits.min());
202  setResult(pp.name() + ":tgt:max(weight)", tgtWeightLimits.max());
203  setResult(pp.name() + ":tgt:ave(weight)", tgtWeightAvg);
204  setResult(pp.name() + ":tgt:min(address)", tgtNbrLimits.min());
205  setResult(pp.name() + ":tgt:max(address)", tgtNbrLimits.max());
206  setResult(pp.name() + ":tgt:ave(address)", tgtNbrAvg);
207 }
208 
209 
211 (
212  const cyclicAMIPolyPatch& cpp,
213  const scalarField& weightSum,
214  const word& side
215 ) const
216 {
217  // Collect geometry
218  labelList pointToGlobal;
219  labelList uniqueMeshPointLabels;
221  autoPtr<globalIndex> globalFaces;
222  faceList mergedFaces;
223  pointField mergedPoints;
225  (
226  mesh_,
227  cpp.localFaces(),
228  cpp.meshPoints(),
229  cpp.meshPointMap(),
230 
231  pointToGlobal,
232  uniqueMeshPointLabels,
233  globalPoints,
234  globalFaces,
235 
236  mergedFaces,
237  mergedPoints
238  );
239 
240  // Collect field
241  scalarField mergedWeights = globalFaces().gather(weightSum);
242 
243  const bool isACMI = isA<cyclicACMIPolyPatch>(cpp);
244 
245  scalarField mergedMask;
246  if (isACMI)
247  {
248  const cyclicACMIPolyPatch& pp = refCast<const cyclicACMIPolyPatch>(cpp);
249 
250  mergedMask = globalFaces().gather(pp.mask());
251  }
252 
253  if (Pstream::master())
254  {
255  instant inst(mesh_.time().value(), mesh_.time().timeName());
256 
258  (
259  mergedPoints,
260  mergedFaces,
261  (baseTimeDir()/cpp.name() + "_" + side),
262  false // serial: master-only
263  );
264 
265  writer.setTime(inst);
266  writer.writeTimeValue();
267  writer.writeGeometry();
268 
269  writer.beginCellData(1 + (isACMI ? 1 : 0));
270  writer.write("weightsSum", mergedWeights);
271 
272  if (isACMI)
273  {
274  writer.write("mask", mergedMask);
275  }
276  }
277 }
278 
279 
281 (
282  const cyclicAMIPolyPatch& cpp
283 ) const
284 {
285  if (cpp.owner())
286  {
287  writeWeightField(cpp, cpp.AMI().srcWeightsSum(), "src");
288  writeWeightField(cpp.neighbPatch(), cpp.AMI().tgtWeightsSum(), "tgt");
289  }
290 }
291 
292 
293 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
294 
296 (
297  const word& name,
298  const Time& runTime,
299  const dictionary& dict
300 )
301 :
302  fvMeshFunctionObject(name, runTime, dict),
303  writeFile(mesh_, name, typeName, dict),
304  writeFields_(false),
305  patchIDs_()
306 {
307  read(dict);
308 }
309 
310 
311 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
312 
314 {
316  {
317  patchIDs_.clear();
318  labelHashSet ids;
319 
320  for (const polyPatch& pp : mesh_.boundaryMesh())
321  {
322  const auto* amicpp = isA<cyclicAMIPolyPatch>(pp);
323 
324  if (amicpp && amicpp->owner())
325  {
326  ids.insert(pp.index());
327  }
328  }
329 
330  patchIDs_ = ids.sortedToc();
331 
332  writeFileHeader(file());
333 
334  writeFields_ = dict.get<bool>("writeFields");
335 
336  return true;
337  }
338 
339  return false;
340 }
341 
344 {
345  return true;
346 }
347 
348 
350 {
351  Log << type() << " " << name() << " write:" << nl;
352 
353  const polyBoundaryMesh& pbm = mesh_.boundaryMesh();
354  for (const label patchi : patchIDs_)
355  {
356  const polyPatch& pp = pbm[patchi];
357  const auto& cpp = static_cast<const cyclicAMIPolyPatch&>(pp);
358 
359  reportPatch(cpp);
360 
361  if (writeFields_)
362  {
363  writeWeightFields(cpp);
364  }
365  }
366 
367  return true;
368 }
369 
370 
371 // ************************************************************************* //
Computes the min/max/average weights of arbitrary mesh interface (AMI) patches, and optionally report...
Definition: AMIWeights.H:147
const polyBoundaryMesh & pbm
const List< face_type > & localFaces() const
Return patch faces addressing into local point list.
dictionary dict
Cyclic patch for Arbitrarily Coupled Mesh Interface (ACMI).
defineTypeNameAndDebug(ObukhovLength, 0)
virtual void writeHeader(Ostream &os, const string &str) const
Write a commented header to stream.
Definition: writeFile.C:344
vtk::lineWriter writer(edgeCentres, edgeList::null(), fileName(aMesh.time().globalPath()/"finiteArea-edgesCentres"))
A list of keyword definitions, which are a keyword followed by a number of values (eg...
Definition: dictionary.H:129
constexpr char nl
The newline &#39;\n&#39; character (0x0a)
Definition: Ostream.H:50
A min/max value pair with additional methods. In addition to conveniently storing values...
Definition: HashSet.H:72
Write faces/points (optionally with fields) as a vtp file or a legacy vtk file.
engineTime & runTime
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:529
static bool & parRun() noexcept
Test if this a parallel run.
Definition: UPstream.H:1586
AMIWeights(const word &name, const Time &runTime, const dictionary &dict)
Construct from Time and dictionary.
Definition: AMIWeights.C:289
A simple wrapper around bool so that it can be read as a word: true/false, on/off, yes/no, any/none. Also accepts 0/1 as a string and shortcuts t/f, y/n.
Definition: Switch.H:77
static unsigned int defaultPrecision() noexcept
Return the default precision.
Definition: IOstream.H:418
const T & min() const noexcept
The min value.
Definition: MinMax.H:207
constexpr char tab
The tab &#39;\t&#39; character(0x09)
Definition: Ostream.H:49
constexpr label labelMin
Definition: label.H:54
Abstract base-class for Time/database function objects.
bool insert(const Key &key)
Insert a new entry, not overwriting existing entries.
Definition: HashSet.H:229
List< labelList > labelListList
List of labelList.
Definition: labelList.H:38
Class to control time during OpenFOAM simulations that is also the top-level objectRegistry.
Definition: Time.H:69
Macros for easy insertion into run-time selection tables.
const labelList & meshPoints() const
Return labelList of mesh points in patch.
void writeWeightField(const cyclicAMIPolyPatch &cpp, const scalarField &weightSum, const word &side) const
Write weight field.
Definition: AMIWeights.C:204
bool read(const char *buf, int32_t &val)
Same as readInt32.
Definition: int32.H:127
void reduce(T &value, [[maybe_unused]] BinaryOp bop, [[maybe_unused]] const int tag=UPstream::msgType(), const int communicator=UPstream::worldComm)
Reduce inplace (cf. MPI Allreduce)
static void gatherAndMerge(const scalar mergeDist, const PrimitivePatch< FaceList, PointField > &pp, Field< typename PrimitivePatch< FaceList, PointField >::point_type > &mergedPoints, List< typename PrimitivePatch< FaceList, PointField >::face_type > &mergedFaces, globalIndex &pointAddr, globalIndex &faceAddr, labelList &pointMergeMap=const_cast< labelList &>(labelList::null()), const bool useLocal=false)
Gather points and faces onto master and merge into single patch.
labelList patchIDs_
List of AMI patch IDs.
Definition: AMIWeights.H:164
#define forAll(list, i)
Loop across all elements in list.
Definition: stdFoam.H:286
void writeWeightFields(const cyclicAMIPolyPatch &cpp) const
Write weight fields if writeFields=true.
Definition: AMIWeights.C:274
fileName::Type type(const fileName &name, const bool followLink=true)
Return the file type: DIRECTORY or FILE, normally following symbolic links.
Definition: POSIX.C:801
virtual void writeCommented(Ostream &os, const string &str) const
Write a commented string to stream.
Definition: writeFile.C:318
unsigned int count(const UList< bool > &bools, const bool val=true)
Count number of &#39;true&#39; entries.
Definition: BitOps.H:73
const Map< label > & meshPointMap() const
Mesh point map.
word name(const expressions::valueTypeCode typeCode)
A word representation of a valueTypeCode. Empty for expressions::valueTypeCode::INVALID.
Definition: exprTraits.C:127
A class for handling words, derived from Foam::string.
Definition: word.H:63
Field< scalar > scalarField
Specialisation of Field<T> for scalar.
virtual void writeFileHeader(Ostream &os)
Output file header information.
Definition: AMIWeights.C:41
MinMax< Type > gMinMax(const FieldField< Field, Type > &f)
virtual void reportPatch(const cyclicAMIPolyPatch &pp)
Helper function to report patch information.
Definition: AMIWeights.C:75
MinMax< label > labelMinMax
A label min/max range.
Definition: MinMax.H:93
Cyclic patch for Arbitrary Mesh Interface (AMI)
A polyBoundaryMesh is a polyPatch list with registered IO, a reference to the associated polyMesh...
const word & name() const noexcept
The patch name.
An Ostream is an abstract base class for all output systems (streams, files, token lists...
Definition: Ostream.H:56
MinMax< T > & add(const MinMax &other)
Extend the range to include the other min/max range.
Definition: MinMaxI.H:240
Type gAverage(const FieldField< Field, Type > &f, const label comm)
The global arithmetic average of a FieldField.
OBJstream os(runTime.globalPath()/outputName)
addToRunTimeSelectionTable(functionObject, ObukhovLength, dictionary)
virtual bool read(const dictionary &dict)
Read.
Definition: writeFile.C:240
virtual bool read(const dictionary &)
Read the field min/max data.
Definition: AMIWeights.C:306
An instant of time. Contains the time value and name. Uses Foam::Time when formatting the name...
Definition: instant.H:53
Calculates points shared by more than two processor patches or cyclic patches.
Definition: globalPoints.H:98
virtual bool write()
Write the AMIWeights.
Definition: AMIWeights.C:342
List< Key > sortedToc() const
The table of contents (the keys) in sorted order.
Definition: HashTable.C:156
static bool master(const label communicator=worldComm)
True if process corresponds to the master rank in the communicator.
Definition: UPstream.H:1619
const T & max() const noexcept
The max value.
Definition: MinMax.H:217
#define Log
Definition: PDRblock.C:28
void sumReduce(T &value, CountType &count, [[maybe_unused]] const int tag=UPstream::msgType(), const int communicator=UPstream::worldComm)
Reduce inplace (cf. MPI Allreduce) the sum of value and counter (eg, for averaging) ...
constexpr label labelMax
Definition: label.H:55
virtual bool read(const dictionary &dict)
Read optional controls.
label n
Pointer management similar to std::unique_ptr, with some additional methods and type checking...
Definition: HashPtrTable.H:48
Omanip< int > setw(const int i)
Definition: IOmanip.H:199
List< label > labelList
A List of labels.
Definition: List.H:61
A patch is a list of labels that address the faces in the global face list.
Definition: polyPatch.H:69
virtual bool execute()
Execute, currently does nothing.
Definition: AMIWeights.C:336
uindirectPrimitivePatch pp(UIndirectList< face >(mesh.faces(), faceLabels), mesh.points())
Namespace for OpenFOAM.
virtual void writeTabbed(Ostream &os, const string &str) const
Write a tabbed string to stream.
Definition: writeFile.C:334