regionSizeDistribution.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) 2013-2016 OpenFOAM Foundation
9  Copyright (C) 2016-2022 OpenCFD Ltd.
10 -------------------------------------------------------------------------------
11 License
12  This file is part of OpenFOAM.
13 
14  OpenFOAM is free software: you can redistribute it and/or modify it
15  under the terms of the GNU General Public License as published by
16  the Free Software Foundation, either version 3 of the License, or
17  (at your option) any later version.
18 
19  OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
20  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
21  FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
22  for more details.
23 
24  You should have received a copy of the GNU General Public License
25  along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
26 
27 \*---------------------------------------------------------------------------*/
28 
29 #include "regionSizeDistribution.H"
30 #include "regionSplit.H"
31 #include "volFields.H"
32 #include "fvcVolumeIntegrate.H"
34 
35 // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
36 
37 namespace Foam
38 {
39  namespace functionObjects
40  {
41  defineTypeNameAndDebug(regionSizeDistribution, 0);
43  (
44  functionObject,
45  regionSizeDistribution,
46  dictionary
47  );
48  }
49 }
50 
51 
52 // * * * * * * * * * * * * * * * Local Functions * * * * * * * * * * * * * * //
53 
54 namespace Foam
55 {
56 
57 template<class Type>
58 static Map<Type> regionSum(const regionSplit& regions, const Field<Type>& fld)
59 {
60  // Per region the sum of fld
61  Map<Type> regionToSum(regions.nRegions()/Pstream::nProcs());
62 
63  forAll(fld, celli)
64  {
65  const label regioni = regions[celli];
66  regionToSum(regioni, Type(Zero)) += fld[celli];
67  }
68 
70 
71  return regionToSum;
72 }
73 
74 
75 template<class Type>
76 static List<Type> extractData(const labelUList& keys, const Map<Type>& regionData)
77 {
78  List<Type> sortedData(keys.size());
79 
80  forAll(keys, i)
81  {
82  sortedData[i] = regionData[keys[i]];
83  }
84  return sortedData;
85 }
86 
87 } // End namespace Foam
88 
89 
90 // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
91 
92 void Foam::functionObjects::regionSizeDistribution::writeAlphaFields
93 (
94  const regionSplit& regions,
95  const Map<label>& patchRegions,
96  const Map<scalar>& regionVolume,
97  const volScalarField& alpha
98 ) const
99 {
100  const scalar maxDropletVol = 1.0/6.0*pow3(maxDiam_);
101 
102  // Split alpha field
103  // ~~~~~~~~~~~~~~~~~
104  // Split into
105  // - liquidCore : region connected to inlet patches
106  // - per region a volume : for all other regions
107  // - backgroundAlpha : remaining alpha
108 
109 
110  // Construct field
111  volScalarField liquidCore
112  (
113  IOobject
114  (
115  scopedName(alphaName_ + "_liquidCore"),
116  obr_.time().timeName(),
117  obr_,
119  ),
120  alpha,
122  );
123 
124  volScalarField backgroundAlpha
125  (
126  IOobject
127  (
128  scopedName(alphaName_ + "_background"),
129  obr_.time().timeName(),
130  obr_,
132  ),
133  alpha,
135  );
136 
137 
138  // Knock out any cell not in patchRegions
139  forAll(liquidCore, celli)
140  {
141  const label regioni = regions[celli];
142  if (patchRegions.found(regioni))
143  {
144  backgroundAlpha[celli] = 0;
145  }
146  else
147  {
148  liquidCore[celli] = 0;
149 
150  const scalar regionVol = regionVolume[regioni];
151  if (regionVol < maxDropletVol)
152  {
153  backgroundAlpha[celli] = 0;
154  }
155  }
156  }
157  liquidCore.correctBoundaryConditions();
158  backgroundAlpha.correctBoundaryConditions();
159 
160  if (log)
161  {
162  Info<< " Volume of liquid-core = "
163  << fvc::domainIntegrate(liquidCore).value()
164  << nl
165  << " Volume of background = "
166  << fvc::domainIntegrate(backgroundAlpha).value()
167  << endl;
168  }
169 
170  Log << " Writing liquid-core field to " << liquidCore.name() << endl;
171  liquidCore.write();
172 
173  Log<< " Writing background field to " << backgroundAlpha.name() << endl;
174  backgroundAlpha.write();
175 }
176 
177 
179 Foam::functionObjects::regionSizeDistribution::findPatchRegions
180 (
181  const regionSplit& regions
182 ) const
183 {
184  // Mark all regions starting at patches
185  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
186 
187  // Count number of patch faces (just for initial sizing)
188  const labelHashSet patchIDs(mesh_.boundaryMesh().patchSet(patchNames_));
189 
190  label nPatchFaces = 0;
191  for (const label patchi : patchIDs)
192  {
193  nPatchFaces += mesh_.boundaryMesh()[patchi].size();
194  }
195 
196 
197  Map<label> patchRegions(nPatchFaces);
198  for (const label patchi : patchIDs)
199  {
200  const polyPatch& pp = mesh_.boundaryMesh()[patchi];
201 
202  // Collect all regions on the patch
203  const labelList& faceCells = pp.faceCells();
204 
205  for (const label celli : faceCells)
206  {
207  patchRegions.insert
208  (
209  regions[celli],
210  Pstream::myProcNo() // dummy value
211  );
212  }
213  }
214 
215 
216  // Make sure all the processors have the same set of regions
217  Pstream::mapCombineReduce(patchRegions, minEqOp<label>());
218 
219  return patchRegions;
220 }
221 
222 
224 Foam::functionObjects::regionSizeDistribution::divide
225 (
226  const scalarField& num,
227  const scalarField& denom
228 )
229 {
230  auto tresult = tmp<scalarField>::New(num.size());
231  auto& result = tresult.ref();
232 
233  forAll(denom, i)
234  {
235  if (denom[i] != 0)
236  {
237  result[i] = num[i]/denom[i];
238  }
239  else
240  {
241  result[i] = 0;
242  }
243  }
244  return tresult;
245 }
246 
247 
248 void Foam::functionObjects::regionSizeDistribution::writeGraphs
249 (
250  const word& fieldName, // name of field
251  const scalarField& sortedField, // per region field data
252 
253  const labelList& indices, // index of bin for each region
254  const scalarField& binCount, // per bin number of regions
255  const coordSet& coords // graph data for bins
256 ) const
257 {
258  if (Pstream::master())
259  {
260  // Calculate per-bin average
261  scalarField binSum(nBins_, Zero);
262  forAll(sortedField, i)
263  {
264  binSum[indices[i]] += sortedField[i];
265  }
266 
267  scalarField binAvg(divide(binSum, binCount));
268 
269  // Per bin deviation
270  scalarField binSqrSum(nBins_, Zero);
271  forAll(sortedField, i)
272  {
273  binSqrSum[indices[i]] += Foam::sqr(sortedField[i]);
274  }
275  scalarField binDev
276  (
277  sqrt(divide(binSqrSum, binCount) - Foam::sqr(binAvg))
278  );
279 
280 
281  auto& writer = formatterPtr_();
282 
283  word outputName;
284  if (writer.buffering())
285  {
286  outputName =
287  (
288  coords.name()
290  (
291  wordList
292  ({
293  fieldName + "_sum",
294  fieldName + "_avg",
295  fieldName + "_dev"
296  })
297  )
298  );
299  }
300  else
301  {
302  outputName = coords.name();
303  }
304 
305  writer.open
306  (
307  coords,
308  (baseTimeDir() / outputName)
309  );
310 
311  Log << " Writing distribution of "
312  << fieldName << " to " << writer.path() << endl;
313 
314  writer.write(fieldName + "_sum", binSum);
315  writer.write(fieldName + "_avg", binAvg);
316  writer.write(fieldName + "_dev", binDev);
317  writer.close(true);
318  }
319 }
320 
321 
322 void Foam::functionObjects::regionSizeDistribution::writeGraphs
323 (
324  const word& fieldName, // name of field
325  const scalarField& cellField, // per cell field data
326  const regionSplit& regions, // per cell the region(=droplet)
327  const labelList& sortedRegions, // valid regions in sorted order
328  const scalarField& sortedNormalisation,
329 
330  const labelList& indices, // per region index of bin
331  const scalarField& binCount, // per bin number of regions
332  const coordSet& coords // graph data for bins
333 ) const
334 {
335  // Sum on a per-region basis. Parallel reduced.
336  Map<scalar> regionField(regionSum(regions, cellField));
337 
338  // Extract in region order
339  scalarField sortedField
340  (
341  sortedNormalisation
342  * extractData(sortedRegions, regionField)
343  );
344 
345  writeGraphs
346  (
347  fieldName, // name of field
348  sortedField, // per region field data
349 
350  indices, // index of bin for each region
351  binCount, // per bin number of regions
352  coords // graph data for bins
353  );
354 }
355 
356 
357 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
358 
360 (
361  const word& name,
362  const Time& runTime,
363  const dictionary& dict
364 )
365 :
367  writeFile(obr_, name),
368  alphaName_(dict.get<word>("field")),
369  patchNames_(dict.get<wordRes>("patches")),
370  isoPlanes_(dict.getOrDefault("isoPlanes", false))
371 {
372  read(dict);
373 }
374 
375 
376 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
377 
379 {
382 
383  dict.readEntry("nBins", nBins_);
384  dict.readEntry("field", alphaName_);
385  dict.readEntry("threshold", threshold_);
386  dict.readEntry("maxDiameter", maxDiam_);
387  minDiam_ = 0.0;
388  dict.readIfPresent("minDiameter", minDiam_);
389  dict.readEntry("patches", patchNames_);
390  dict.readEntry("fields", fields_);
391 
392  const word setFormat(dict.get<word>("setFormat"));
393  formatterPtr_ = coordSetWriter::New
394  (
395  setFormat,
396  dict.subOrEmptyDict("formatOptions").optionalSubDict(setFormat)
397  );
398 
399  csysPtr_ = coordinateSystem::NewIfPresent(obr_, dict);
400 
401  if (csysPtr_)
402  {
403  Info<< "Transforming all vectorFields with coordinate system "
404  << csysPtr_->name() << endl;
405  }
406 
407  if (isoPlanes_)
408  {
409  dict.readEntry("origin", origin_);
410  dict.readEntry("direction", direction_);
411  dict.readEntry("maxD", maxDiameter_);
412  dict.readEntry("nDownstreamBins", nDownstreamBins_);
413  dict.readEntry("maxDownstream", maxDownstream_);
414  direction_.normalise();
415  }
416 
417  return true;
418 }
419 
422 {
423  return true;
424 }
425 
426 
428 {
429  Log << type() << " " << name() << " write:" << nl;
430 
431  tmp<volScalarField> talpha;
432  talpha.cref(obr_.cfindObject<volScalarField>(alphaName_));
433  if (talpha)
434  {
435  Log << " Looking up field " << alphaName_ << endl;
436  }
437  else
438  {
439  Info<< " Reading field " << alphaName_ << endl;
440  talpha.reset
441  (
442  new volScalarField
443  (
444  IOobject
445  (
446  alphaName_,
447  mesh_.time().timeName(),
448  mesh_,
451  ),
452  mesh_
453  )
454  );
455  }
456  const auto& alpha = talpha();
457 
458  Log << " Volume of alpha = "
459  << fvc::domainIntegrate(alpha).value()
460  << endl;
461 
462  const scalar meshVol = gSum(mesh_.V());
463  const scalar maxDropletVol = 1.0/6.0*pow3(maxDiam_);
464  const scalar delta = (maxDiam_-minDiam_)/nBins_;
465 
466  Log << " Mesh volume = " << meshVol << nl
467  << " Maximum droplet diameter = " << maxDiam_ << nl
468  << " Maximum droplet volume = " << maxDropletVol
469  << endl;
470 
471 
472  // Determine blocked faces
473  boolList blockedFace(mesh_.nFaces(), false);
474  label nBlocked = 0;
475 
476  {
477  for (label facei = 0; facei < mesh_.nInternalFaces(); facei++)
478  {
479  scalar ownVal = alpha[mesh_.faceOwner()[facei]];
480  scalar neiVal = alpha[mesh_.faceNeighbour()[facei]];
481 
482  if
483  (
484  (ownVal < threshold_ && neiVal > threshold_)
485  || (ownVal > threshold_ && neiVal < threshold_)
486  )
487  {
488  blockedFace[facei] = true;
489  nBlocked++;
490  }
491  }
492 
493  // Block coupled faces
494  forAll(alpha.boundaryField(), patchi)
495  {
496  const fvPatchScalarField& fvp = alpha.boundaryField()[patchi];
497  if (fvp.coupled())
498  {
499  tmp<scalarField> townFld(fvp.patchInternalField());
500  tmp<scalarField> tnbrFld(fvp.patchNeighbourField());
501  const auto& ownFld = townFld();
502  const auto& nbrFld = tnbrFld();
503 
504  label start = fvp.patch().patch().start();
505 
506  forAll(ownFld, i)
507  {
508  scalar ownVal = ownFld[i];
509  scalar neiVal = nbrFld[i];
510 
511  if
512  (
513  (ownVal < threshold_ && neiVal > threshold_)
514  || (ownVal > threshold_ && neiVal < threshold_)
515  )
516  {
517  blockedFace[start+i] = true;
518  nBlocked++;
519  }
520  }
521  }
522  }
523  }
524 
525 
526  regionSplit regions(mesh_, blockedFace);
527 
528  Log << " Determined " << regions.nRegions()
529  << " disconnected regions" << endl;
530 
531 
532  if (debug)
533  {
534  volScalarField region
535  (
536  IOobject
537  (
538  "region",
539  mesh_.time().timeName(),
540  mesh_,
543  ),
544  mesh_,
546  );
547  Info<< " Dumping region as volScalarField to " << region.name()
548  << endl;
549 
550  forAll(regions, celli)
551  {
552  region[celli] = regions[celli];
553  }
554  region.correctBoundaryConditions();
555  region.write();
556  }
557 
558 
559  // Determine regions connected to supplied patches
560  Map<label> patchRegions(findPatchRegions(regions));
561 
562 
563  // Sum all regions
564  const scalarField alphaVol(alpha.primitiveField()*mesh_.V());
565  Map<scalar> allRegionVolume(regionSum(regions, mesh_.V()));
566  Map<scalar> allRegionAlphaVolume(regionSum(regions, alphaVol));
567  Map<label> allRegionNumCells
568  (
569  regionSum
570  (
571  regions,
572  labelField(mesh_.nCells(), 1.0)
573  )
574  );
575 
576  if (debug)
577  {
578  Info<< " " << token::TAB << "Region"
579  << token::TAB << "Volume(mesh)"
580  << token::TAB << "Volume(" << alpha.name() << "):"
581  << token::TAB << "nCells"
582  << nl;
583  scalar meshSumVol = 0.0;
584  scalar alphaSumVol = 0.0;
585  label nCells = 0;
586 
587  auto vIter = allRegionVolume.cbegin();
588  auto aIter = allRegionAlphaVolume.cbegin();
589  auto numIter = allRegionNumCells.cbegin();
590  for
591  (
592  ;
593  vIter.good() && aIter.good();
594  ++vIter, ++aIter, ++numIter
595  )
596  {
597  Info<< " " << token::TAB << vIter.key()
598  << token::TAB << vIter()
599  << token::TAB << aIter()
600  << token::TAB << numIter()
601  << nl;
602 
603  meshSumVol += vIter();
604  alphaSumVol += aIter();
605  nCells += numIter();
606  }
607  Info<< " " << token::TAB << "Total:"
608  << token::TAB << meshSumVol
609  << token::TAB << alphaSumVol
610  << token::TAB << nCells
611  << endl;
612  }
613 
614 
615  if (log)
616  {
617  Info<< " Patch connected regions (liquid core):" << nl;
618  Info<< token::TAB << " Region"
619  << token::TAB << "Volume(mesh)"
620  << token::TAB << "Volume(" << alpha.name() << "):"
621  << nl;
622 
623  forAllConstIters(patchRegions, iter)
624  {
625  const label regioni = iter.key();
626  Info<< " " << token::TAB << regioni
627  << token::TAB << allRegionVolume[regioni]
628  << token::TAB << allRegionAlphaVolume[regioni] << nl;
629 
630  }
631  Info<< endl;
632  }
633 
634  if (log)
635  {
636  Info<< " Background regions:" << nl;
637  Info<< " " << token::TAB << "Region"
638  << token::TAB << "Volume(mesh)"
639  << token::TAB << "Volume(" << alpha.name() << "):"
640  << nl;
641 
642  auto vIter = allRegionVolume.cbegin();
643  auto aIter = allRegionAlphaVolume.cbegin();
644 
645  for
646  (
647  ;
648  vIter.good() && aIter.good();
649  ++vIter, ++aIter
650  )
651  {
652  if
653  (
654  !patchRegions.found(vIter.key())
655  && vIter() >= maxDropletVol
656  )
657  {
658  Info<< " " << token::TAB << vIter.key()
659  << token::TAB << vIter()
660  << token::TAB << aIter() << nl;
661  }
662  }
663  Info<< endl;
664  }
665 
666 
667 
668  // Split alpha field
669  // ~~~~~~~~~~~~~~~~~
670  // Split into
671  // - liquidCore : region connected to inlet patches
672  // - per region a volume : for all other regions
673  // - backgroundAlpha : remaining alpha
674  writeAlphaFields(regions, patchRegions, allRegionVolume, alpha);
675 
676 
677  // Extract droplet-only allRegionVolume, i.e. delete liquid core
678  // (patchRegions) and background regions from maps.
679  // Note that we have to use mesh volume (allRegionVolume) and not
680  // allRegionAlphaVolume since background might not have alpha in it.
681  // Deleting regions where the volume-alpha-weighted is lower than
682  // threshold
683  forAllIters(allRegionVolume, vIter)
684  {
685  const label regioni = vIter.key();
686  if
687  (
688  patchRegions.found(regioni)
689  || vIter() >= maxDropletVol
690  || (allRegionAlphaVolume[regioni]/vIter() < threshold_)
691  )
692  {
693  allRegionVolume.erase(vIter);
694  allRegionAlphaVolume.erase(regioni);
695  allRegionNumCells.erase(regioni);
696  }
697  }
698 
699  if (allRegionVolume.size())
700  {
701  // Construct mids of bins for plotting
702  pointField xBin(nBins_, Zero);
703 
704  {
705  scalar x = 0.5*delta;
706  for (point& p : xBin)
707  {
708  p.x() = x;
709  x += delta;
710  }
711  }
712 
713  const coordSet coords("diameter", "x", xBin, mag(xBin));
714 
715 
716  // Get in region order the alpha*volume and diameter
717  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
718 
719  const labelList sortedRegions = allRegionAlphaVolume.sortedToc();
720 
721  scalarField sortedVols
722  (
723  extractData(sortedRegions, allRegionAlphaVolume)
724  );
725 
726  vectorField centroids(sortedVols.size(), Zero);
727 
728  // Check if downstream bins are calculated
729  if (isoPlanes_)
730  {
731  vectorField alphaDistance
732  (
733  (alpha.primitiveField()*mesh_.V())
734  *(mesh_.C().primitiveField() - origin_)()
735  );
736 
737  Map<vector> allRegionAlphaDistance
738  (
739  regionSum
740  (
741  regions,
742  alphaDistance
743  )
744  );
745 
746  // 2. centroid
747  vectorField sortedMoment
748  (
749  extractData(sortedRegions, allRegionAlphaDistance)
750  );
751 
752  centroids = sortedMoment/sortedVols + origin_;
753 
754  // Bin according to centroid
755  scalarField distToPlane((centroids - origin_) & direction_);
756 
757  vectorField radialDistToOrigin
758  (
759  (centroids - origin_) - (distToPlane*direction_)
760  );
761 
762  const scalar deltaX = maxDownstream_/nDownstreamBins_;
763  labelList downstreamIndices(distToPlane.size(), -1);
764  forAll(distToPlane, i)
765  {
766  if
767  (
768  (mag(radialDistToOrigin[i]) < maxDiameter_)
769  && (distToPlane[i] < maxDownstream_)
770  )
771  {
772  downstreamIndices[i] = distToPlane[i]/deltaX;
773  }
774  }
775 
776  scalarField binDownCount(nDownstreamBins_, Zero);
777  forAll(distToPlane, i)
778  {
779  if (downstreamIndices[i] != -1)
780  {
781  binDownCount[downstreamIndices[i]] += 1.0;
782  }
783  }
784 
785  // Write
786  if (Pstream::master())
787  {
788  // Construct mids of bins for plotting
789  pointField xBin(nDownstreamBins_, Zero);
790 
791  {
792  scalar x = 0.5*deltaX;
793  for (point& p : xBin)
794  {
795  p.x() = x;
796  x += deltaX;
797  }
798  }
799 
800  const coordSet coords("distance", "x", xBin, mag(xBin));
801 
802  auto& writer = formatterPtr_();
803  writer.nFields(1);
804 
805  writer.open
806  (
807  coords,
808  writeFile::baseTimeDir() / (coords.name() + "_isoPlanes")
809  );
810 
811  writer.write("isoPlanes", binDownCount);
812  writer.close(true);
813  }
814 
815  // Write to log
816  if (log)
817  {
818  Info<< " Iso-planes Bins:" << nl
819  << " " << token::TAB << "Bin"
820  << token::TAB << "Min distance"
821  << token::TAB << "Count:"
822  << nl;
823 
824  scalar delta = 0.0;
825  forAll(binDownCount, bini)
826  {
827  Info<< " " << token::TAB << bini
828  << token::TAB << delta
829  << token::TAB << binDownCount[bini] << nl;
830  delta += deltaX;
831  }
832  Info<< endl;
833 
834  }
835  }
836 
837  // Calculate the diameters
838  scalarField sortedDiameters(sortedVols.size());
839  forAll(sortedDiameters, i)
840  {
841  sortedDiameters[i] = Foam::cbrt
842  (
843  sortedVols[i]
845  );
846  }
847 
848  // Determine the bin index for all the diameters
849  labelList indices(sortedDiameters.size());
850  forAll(sortedDiameters, i)
851  {
852  indices[i] = (sortedDiameters[i]-minDiam_)/delta;
853  }
854 
855  // Calculate the counts per diameter bin
856  scalarField binCount(nBins_, Zero);
857  forAll(sortedDiameters, i)
858  {
859  binCount[indices[i]] += 1.0;
860  }
861 
862  // Write counts
863  if (Pstream::master())
864  {
865  auto& writer = formatterPtr_();
866  writer.nFields(1);
867 
868  writer.open
869  (
870  coords,
871  writeFile::baseTimeDir() / (coords.name() + "_count")
872  );
873 
874  writer.write("count", binCount);
875  writer.close(true);
876  }
877 
878  // Write to log
879  if (log)
880  {
881  Info<< " Bins:" << nl
882  << " " << token::TAB << "Bin"
883  << token::TAB << "Min diameter"
884  << token::TAB << "Count:"
885  << nl;
886 
887  scalar diam = 0.0;
888  forAll(binCount, bini)
889  {
890  Info<< " " << token::TAB << bini
891  << token::TAB << diam
892  << token::TAB << binCount[bini] << nl;
893 
894  diam += delta;
895  }
896 
897  Info<< endl;
898  }
899 
900 
901  // Write average and deviation of droplet volume.
902  writeGraphs
903  (
904  "volume", // name of field
905  sortedVols, // per region field data
906 
907  indices, // per region the bin index
908  binCount, // per bin number of regions
909  coords // graph data for bins
910  );
911 
912  // Collect some more fields
913  {
914  for
915  (
916  const word& fldName
917  : obr_.sortedNames<volScalarField>(fields_)
918  )
919  {
920  Log << " Scalar field " << fldName << endl;
921 
922  tmp<Field<scalar>> tfld
923  (
924  obr_.lookupObject<volScalarField>(fldName).primitiveField()
925  );
926  const auto& fld = tfld();
927 
928  writeGraphs
929  (
930  fldName, // name of field
931  alphaVol*fld, // per cell field data
932 
933  regions, // per cell the region(=droplet)
934  sortedRegions, // valid regions in sorted order
935  1.0/sortedVols, // per region normalisation
936 
937  indices, // index of bin for each region
938  binCount, // per bin number of regions
939  coords // graph data for bins
940  );
941  }
942  }
943 
944  {
945  for
946  (
947  const word& fldName
948  : obr_.sortedNames<volVectorField>(fields_)
949  )
950  {
951  Log << " Vector field " << fldName << endl;
952 
953  tmp<Field<vector>> tfld
954  (
955  obr_.lookupObject<volVectorField>(fldName).primitiveField()
956  );
957 
958  if (csysPtr_)
959  {
960  Log << "Transforming vector field " << fldName
961  << " with coordinate system "
962  << csysPtr_->name()
963  << endl;
964 
965  tfld = csysPtr_->localVector(tfld());
966  }
967  const auto& fld = tfld();
968 
969  // Components
970 
971  for (direction cmpt = 0; cmpt < vector::nComponents; ++cmpt)
972  {
973  writeGraphs
974  (
975  fldName + vector::componentNames[cmpt],
976  alphaVol*fld.component(cmpt),// per cell field data
977 
978  regions, // per cell the region(=droplet)
979  sortedRegions, // valid regions in sorted order
980  1.0/sortedVols, // per region normalisation
981 
982  indices, // index of bin for each region
983  binCount, // per bin number of regions
984  coords // graph data for bins
985  );
986  }
987 
988  // Magnitude
989  writeGraphs
990  (
991  fldName + "mag", // name of field
992  alphaVol*mag(fld), // per cell field data
993 
994  regions, // per cell the region(=droplet)
995  sortedRegions, // valid regions in sorted order
996  1.0/sortedVols, // per region normalisation
997 
998  indices, // index of bin for each region
999  binCount, // per bin number of regions
1000  coords // graph data for bins
1001  );
1002  }
1003  }
1004  }
1005 
1006  return true;
1007 }
1008 
1009 
1010 // ************************************************************************* //
List< ReturnType > get(const UPtrList< T > &list, const AccessOp &aop)
List of values generated by applying the access operation to each list item.
void divide(FieldField< Field, Type > &f, const FieldField< Field, Type > &f1, const FieldField< Field, scalar > &f2)
scalar delta
This class separates the mesh into distinct unconnected regions, each of which is then given a label ...
Definition: regionSplit.H:136
dictionary dict
Field< label > labelField
Specialisation of Field<T> for label.
Definition: labelField.H:48
defineTypeNameAndDebug(ObukhovLength, 0)
virtual bool write()
Calculate the regionSizeDistribution and write.
uint8_t direction
Definition: direction.H:46
const Internal::FieldType & primitiveField() const noexcept
Return a const-reference to the internal field values.
dimensionedScalar log(const dimensionedScalar &ds)
dimensioned< typename typeOfMag< Type >::type > mag(const dimensioned< Type > &dt)
A list of keyword definitions, which are a keyword followed by a number of values (eg...
Definition: dictionary.H:120
Tab [isspace].
Definition: token.H:126
dimensionedSymmTensor sqr(const dimensionedVector &dv)
constexpr char nl
The newline &#39;\n&#39; character (0x0a)
Definition: Ostream.H:49
engineTime & runTime
dimensionedScalar sqrt(const dimensionedScalar &ds)
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:487
const T & cref() const
Return const reference to the object or to the contents of a (non-null) managed pointer.
Definition: tmpI.H:196
dimensioned< Type > domainIntegrate(const GeometricField< Type, fvPatchField, volMesh > &vf)
label size() const noexcept
The number of elements in table.
Definition: HashTableI.H:45
Ignore writing from objectRegistry::writeObject()
const dimensionSet dimless
Dimensionless.
static int myProcNo(const label communicator=worldComm)
Number of this process (starting from masterNo() = 0)
Definition: UPstream.H:688
GeometricField< vector, fvPatchField, volMesh > volVectorField
Definition: volFieldsFwd.H:85
Class to control time during OpenFOAM simulations that is also the top-level objectRegistry.
Definition: Time.H:69
regionSizeDistribution(const word &name, const Time &runTime, const dictionary &)
Construct for given objectRegistry and dictionary.
static const word & calculatedType()
The type name for calculated patch fields.
Macros for easy insertion into run-time selection tables.
UList< label > labelUList
A UList of labels.
Definition: UList.H:80
bool read(const char *buf, int32_t &val)
Same as readInt32.
Definition: int32.H:125
#define forAll(list, i)
Loop across all elements in list.
Definition: stdFoam.H:413
GeometricField< scalar, fvPatchField, volMesh > volScalarField
Definition: volFieldsFwd.H:84
HashSet< label, Hash< label > > labelHashSet
A HashSet of labels, uses label hasher.
Definition: HashSet.H:85
static word suffix(const word &fldName, const word &fileExt=word::null)
Name suffix based on fieldName (underscore separator)
fileName::Type type(const fileName &name, const bool followLink=true)
Return the file type: DIRECTORY or FILE, normally following symbolic links.
Definition: POSIX.C:752
static autoPtr< coordSetWriter > New(const word &writeFormat)
Return a reference to the selected writer.
static label nProcs(const label communicator=worldComm)
Number of ranks in parallel run (for given communicator) is 1 for serial run.
Definition: UPstream.H:656
word outputName("finiteArea-edges.obj")
vectorField pointField
pointField is a vectorField.
Definition: pointFieldFwd.H:38
Type gSum(const FieldField< Field, Type > &f)
word name(const expressions::valueTypeCode typeCode)
A word representation of a valueTypeCode. Empty for INVALID.
Definition: exprTraits.C:52
Generic templated field type.
Definition: Field.H:61
fvPatchField< scalar > fvPatchScalarField
A class for handling words, derived from Foam::string.
Definition: word.H:63
Field< scalar > scalarField
Specialisation of Field<T> for scalar.
const Time & time() const noexcept
Return time registry.
static Map< Type > regionSum(const regionSplit &regions, const Field< Type > &fld)
dimensionedScalar cbrt(const dimensionedScalar &ds)
static List< Type > extractData(const labelUList &keys, const Map< Type > &regionData)
#define forAllIters(container, iter)
Iterate across all elements in the container object.
Definition: stdFoam.H:328
static tmp< T > New(Args &&... args)
Construct tmp with forwarding arguments.
Definition: tmp.H:203
A List of wordRe with additional matching capabilities.
Definition: wordRes.H:47
constexpr scalar pi(M_PI)
Volume integrate volField creating a volField.
virtual bool write(const token &tok)=0
Write token to stream or otherwise handle it.
bool log
Flag to write log into Info.
fileName baseTimeDir() const
Return the base directory for the current time value.
Definition: writeFile.C:66
virtual bool read(const dictionary &)
Read the regionSizeDistribution data.
static word timeName(const scalar t, const int precision=precision_)
Return time name of given scalar time formatted with the given precision.
Definition: Time.C:760
int debug
Static debugging option.
vtk::internalMeshWriter writer(topoMesh, topoCells, vtk::formatType::INLINE_ASCII, runTime.path()/"blockTopology")
addToRunTimeSelectionTable(functionObject, ObukhovLength, dictionary)
virtual bool read(const dictionary &dict)
Read.
Definition: writeFile.C:241
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;for(const word &name :lagrangianScalarNames){ IOField< scalar > fld(IOobject(name, runTime.timeName(), cloud::prefix, mesh, IOobject::MUST_READ, IOobject::NO_WRITE))
const word & name() const noexcept
Return const reference to name.
List< word > wordList
A List of words.
Definition: fileName.H:58
dimensionedScalar pow3(const dimensionedScalar &ds)
vector point
Point is a vector.
Definition: point.H:37
dimensioned< scalar > dimensionedScalar
Dimensioned scalar obtained from generic dimensioned type.
static bool master(const label communicator=worldComm)
Am I the master rank.
Definition: UPstream.H:672
const objectRegistry & obr_
Reference to the region objectRegistry.
Nothing to be read.
#define Log
Definition: PDRblock.C:28
label nRegions() const
Return total number of regions.
Definition: regionSplit.H:328
messageStream Info
Information stream (stdout output on master, null elsewhere)
virtual bool read(const dictionary &dict)
Read optional controls.
Field< vector > vectorField
Specialisation of Field<T> for vector.
Specialization of Foam::functionObject for an Foam::fvMesh, providing a reference to the Foam::fvMesh...
word setFormat(propsDict.getOrDefault< word >("setFormat", "vtk"))
List< label > labelList
A List of labels.
Definition: List.H:62
volScalarField & p
A class for managing temporary objects.
Definition: HashPtrTable.H:50
const dimensionedScalar alpha
Fine-structure constant: default SI units: [].
static void mapCombineReduce(Container &values, const CombineOp &cop, const int tag=UPstream::msgType(), const label comm=UPstream::worldComm)
Reduce inplace (cf. MPI Allreduce) applying cop to inplace combine map values from different processo...
Base class for writing single files from the function objects.
Definition: writeFile.H:112
Defines the attributes of an object for which implicit objectRegistry management is supported...
Definition: IOobject.H:166
List< bool > boolList
A List of bools.
Definition: List.H:60
word scopedName(const word &name) const
Return a scoped (prefixed) name.
void reset(tmp< T > &&other) noexcept
Clear existing and transfer ownership.
Definition: tmpI.H:290
Namespace for OpenFOAM.
forAllConstIters(mixture.phases(), phase)
Definition: pEqn.H:28
A HashTable to objects of type <T> with a label key.
static constexpr const zero Zero
Global zero (0)
Definition: zero.H:157