populationBalanceMoments.C
Go to the documentation of this file.
1 /*---------------------------------------------------------------------------*\
2  ========= |
3  \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
4  \\ / O peration | Website: https://openfoam.org
5  \\ / A nd | Copyright (C) 2022-2025 OpenFOAM Foundation
6  \\/ M anipulation |
7 -------------------------------------------------------------------------------
8 License
9  This file is part of OpenFOAM.
10 
11  OpenFOAM is free software: you can redistribute it and/or modify it
12  under the terms of the GNU General Public License as published by
13  the Free Software Foundation, either version 3 of the License, or
14  (at your option) any later version.
15 
16  OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
17  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
18  FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
19  for more details.
20 
21  You should have received a copy of the GNU General Public License
22  along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
23 
24 \*---------------------------------------------------------------------------*/
25 
28 
29 // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
30 
31 namespace Foam
32 {
33 namespace functionObjects
34 {
37  (
41  );
42 }
43 }
44 
45 const Foam::NamedEnum
46 <
48  4
49 >
51 {"integerMoment", "mean", "variance", "stdDev"};
52 
53 const Foam::NamedEnum
54 <
56  3
57 >
59 {"volume", "area", "diameter"};
60 
61 const Foam::NamedEnum
62 <
64  3
65 >
67 {
68  "numberConcentration",
69  "volumeConcentration",
70  "areaConcentration"
71 };
72 
73 const Foam::NamedEnum
74 <
76  3
77 >
79 {"arithmetic", "geometric", "notApplicable"};
80 
81 
82 // * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * * //
83 
85 Foam::functionObjects::populationBalanceMoments::coordinateTypeSymbolicName()
86 {
87  word coordinateTypeSymbolicName(word::null);
88 
89  switch (coordinateType_)
90  {
92  {
93  coordinateTypeSymbolicName = "v";
94 
95  break;
96  }
98  {
99  coordinateTypeSymbolicName = "a";
100 
101  break;
102  }
104  {
105  coordinateTypeSymbolicName = "d";
106 
107  break;
108  }
109  }
110 
111  return coordinateTypeSymbolicName;
112 }
113 
114 
116 Foam::functionObjects::populationBalanceMoments::weightTypeSymbolicName()
117 {
118  word weightTypeSymbolicName(word::null);
119 
120  switch (weightType_)
121  {
122  case weightType::numberConcentration:
123  {
124  weightTypeSymbolicName = "N";
125 
126  break;
127  }
128  case weightType::volumeConcentration:
129  {
130  weightTypeSymbolicName = "V";
131 
132  break;
133  }
134  case weightType::areaConcentration:
135  {
136  weightTypeSymbolicName = "A";
137 
138  break;
139  }
140  }
141 
142  return weightTypeSymbolicName;
143 }
144 
145 
146 Foam::word Foam::functionObjects::populationBalanceMoments::defaultFldName()
147 {
148  word meanName
149  (
150  meanType_ == meanType::geometric
151  ? word(meanTypeNames_[meanType_]).capitalise()
152  : word("")
153  );
154 
155  return
156  word
157  (
159  (
160  "weighted"
161  + meanName
162  + word(momentTypeNames_[momentType_]).capitalise()
163  + "("
164  + weightTypeSymbolicName()
165  + ","
166  + coordinateTypeSymbolicName()
167  + ")",
168  popBalName_
169  )
170  );
171 }
172 
173 
175 Foam::functionObjects::populationBalanceMoments::integerMomentFldName()
176 {
177  return
178  word
179  (
181  (
182  word(momentTypeNames_[momentType_])
183  + Foam::name(order_)
184  + "("
185  + weightTypeSymbolicName()
186  + ","
187  + coordinateTypeSymbolicName()
188  + ")",
189  popBalName_
190  )
191  );
192 }
193 
194 
195 void Foam::functionObjects::populationBalanceMoments::setDimensions
196 (
198  momentType momType
199 )
200 {
201  switch (momType)
202  {
203  case momentType::integerMoment:
204  {
205  switch (coordinateType_)
206  {
208  {
209  fld.dimensions().reset
210  (
211  pow(dimVolume, order_)/dimVolume
212  );
213 
214  break;
215  }
217  {
218  fld.dimensions().reset
219  (
220  pow(dimArea, order_)/dimVolume
221  );
222 
223  break;
224  }
225  case coordinateType::diameter:
226  {
227  fld.dimensions().reset
228  (
229  pow(dimLength, order_)/dimVolume
230  );
231 
232  break;
233  }
234  }
235 
236  switch (weightType_)
237  {
238  case weightType::volumeConcentration:
239  {
240  fld.dimensions().reset(fld.dimensions()*dimVolume);
241 
242  break;
243  }
244  case weightType::areaConcentration:
245  {
246  fld.dimensions().reset(fld.dimensions()*dimArea);
247 
248  break;
249  }
250  default:
251  {
252  break;
253  }
254  }
255 
256  break;
257  }
258  case momentType::mean:
259  {
260  switch (coordinateType_)
261  {
263  {
264  fld.dimensions().reset(dimVolume);
265 
266  break;
267  }
269  {
270  fld.dimensions().reset(dimArea);
271 
272  break;
273  }
274  case coordinateType::diameter:
275  {
276  fld.dimensions().reset(dimLength);
277 
278  break;
279  }
280  }
281 
282  break;
283  }
284  case momentType::variance:
285  {
286  switch (coordinateType_)
287  {
289  {
290  fld.dimensions().reset(sqr(dimVolume));
291 
292  break;
293  }
295  {
296  fld.dimensions().reset(sqr(dimArea));
297 
298  break;
299  }
300  case coordinateType::diameter:
301  {
302  fld.dimensions().reset(sqr(dimLength));
303 
304  break;
305  }
306  }
307 
308  if (meanType_ == meanType::geometric)
309  {
310  fld.dimensions().reset(dimless);
311  }
312 
313  break;
314  }
315  case momentType::stdDev:
316  {
317  switch (coordinateType_)
318  {
320  {
321  fld.dimensions().reset(dimVolume);
322 
323  break;
324  }
326  {
327  fld.dimensions().reset(dimArea);
328 
329  break;
330  }
331  case coordinateType::diameter:
332  {
333  fld.dimensions().reset(dimLength);
334 
335  break;
336  }
337  }
338 
339  if (meanType_ == meanType::geometric)
340  {
341  fld.dimensions().reset(dimless);
342  }
343 
344  break;
345  }
346  }
347 }
348 
349 
351 Foam::functionObjects::populationBalanceMoments::totalConcentration
352 (
353  const populationBalanceModel& popBal
354 )
355 {
356  tmp<volScalarField> tTotalConcentration
357  (
359  (
360  "totalConcentration",
361  mesh_,
363  )
364  );
365 
366  volScalarField& totalConcentration = tTotalConcentration.ref();
367 
368  switch (weightType_)
369  {
370  case weightType::volumeConcentration:
371  {
372  totalConcentration.dimensions().reset
373  (
374  totalConcentration.dimensions()*dimVolume
375  );
376 
377  break;
378  }
379  case weightType::areaConcentration:
380  {
381  totalConcentration.dimensions().reset
382  (
383  totalConcentration.dimensions()*dimArea
384  );
385 
386  break;
387  }
388  default:
389  {
390  break;
391  }
392  }
393 
394  forAll(popBal.fs(), i)
395  {
396  const volScalarField& alpha = popBal.phases()[i];
397  const volScalarField& fi = popBal.f(i);
398  const dimensionedScalar& vi = popBal.v(i);
399 
400  switch (weightType_)
401  {
402  case weightType::numberConcentration:
403  {
404  totalConcentration += fi*alpha/vi;
405 
406  break;
407  }
408  case weightType::volumeConcentration:
409  {
410  totalConcentration += fi*alpha;
411 
412  break;
413  }
414  case weightType::areaConcentration:
415  {
416  totalConcentration += popBal.a(i)*fi*alpha/vi;
417 
418  break;
419  }
420  }
421  }
422 
423  return tTotalConcentration;
424 }
425 
426 
428 Foam::functionObjects::populationBalanceMoments::mean
429 (
430  const populationBalanceModel& popBal
431 )
432 {
433  tmp<volScalarField> tMean
434  (
436  (
437  "mean",
438  mesh_,
440  )
441  );
442 
443  volScalarField& mean = tMean.ref();
444 
445  setDimensions(mean, momentType::mean);
446 
447  volScalarField totalConcentration(this->totalConcentration(popBal));
448 
449  forAll(popBal.fs(), i)
450  {
451  const volScalarField& alpha = popBal.phases()[i];
452  const volScalarField& fi = popBal.f(i);
453  const dimensionedScalar& vi = popBal.v(i);
454 
455  volScalarField concentration(fi*alpha/vi);
456 
457  switch (weightType_)
458  {
459  case weightType::volumeConcentration:
460  {
461  concentration *= vi;
462 
463  break;
464  }
465  case weightType::areaConcentration:
466  {
467  concentration *= popBal.a(i);
468 
469  break;
470  }
471  default:
472  {
473  break;
474  }
475  }
476 
477  switch (meanType_)
478  {
479  case meanType::geometric:
480  {
481  mean.dimensions().reset(dimless);
482 
483  switch (coordinateType_)
484  {
486  {
487  dimensionedScalar unitVolume(dimVolume, 1);
488 
489  mean +=
490  Foam::log(vi/unitVolume)
491  *concentration/totalConcentration;
492 
493  break;
494  }
496  {
497  dimensionedScalar unitArea(dimArea, 1);
498 
499  mean +=
500  Foam::log(popBal.a(i)/unitArea)
501  *concentration/totalConcentration;
502 
503  break;
504  }
505  case coordinateType::diameter:
506  {
507  dimensionedScalar unitLength(dimLength, 1);
508 
509  mean +=
510  Foam::log(popBal.d(i)/unitLength)
511  *concentration/totalConcentration;
512 
513  break;
514  }
515  }
516 
517  break;
518  }
519  default:
520  {
521  switch (coordinateType_)
522  {
524  {
525  mean += vi*concentration/totalConcentration;
526 
527  break;
528  }
530  {
531  mean += popBal.a(i)*concentration/totalConcentration;
532 
533  break;
534  }
535  case coordinateType::diameter:
536  {
537  mean += popBal.d(i)*concentration/totalConcentration;
538 
539  break;
540  }
541  }
542 
543  break;
544  }
545  }
546  }
547 
548  if (meanType_ == meanType::geometric)
549  {
550  mean = exp(mean);
551 
552  setDimensions(mean, momentType::mean);
553  }
554 
555  return tMean;
556 }
557 
558 
560 Foam::functionObjects::populationBalanceMoments::variance
561 (
562  const populationBalanceModel& popBal
563 )
564 {
565  tmp<volScalarField> tVariance
566  (
568  (
569  "variance",
570  mesh_,
572  )
573  );
574 
575  volScalarField& variance = tVariance.ref();
576 
577  setDimensions(variance, momentType::variance);
578 
579  volScalarField totalConcentration(this->totalConcentration(popBal));
580  volScalarField mean(this->mean(popBal));
581 
582  forAll(popBal.fs(), i)
583  {
584  const volScalarField& alpha = popBal.phases()[i];
585  const volScalarField& fi = popBal.f(i);
586  const dimensionedScalar& vi = popBal.v(i);
587 
588  volScalarField concentration(fi*alpha/vi);
589 
590  switch (weightType_)
591  {
592  case weightType::volumeConcentration:
593  {
594  concentration *= vi;
595 
596  break;
597  }
598  case weightType::areaConcentration:
599  {
600  concentration *= popBal.a(i);
601 
602  break;
603  }
604  default:
605  {
606  break;
607  }
608  }
609 
610  switch (meanType_)
611  {
612  case meanType::geometric:
613  {
614  switch (coordinateType_)
615  {
617  {
618  variance +=
619  sqr(Foam::log(vi/mean))
620  *concentration/totalConcentration;
621 
622  break;
623  }
625  {
626  variance +=
627  sqr(Foam::log(popBal.a(i)/mean))
628  *concentration/totalConcentration;
629 
630  break;
631  }
632  case coordinateType::diameter:
633  {
634  variance +=
635  sqr(Foam::log(popBal.d(i)/mean))
636  *concentration/totalConcentration;
637 
638  break;
639  }
640  }
641 
642  break;
643  }
644  default:
645  {
646  switch (coordinateType_)
647  {
649  {
650  variance +=
651  sqr(vi - mean)*concentration/totalConcentration;
652 
653  break;
654  }
656  {
657  variance +=
658  sqr(popBal.a(i) - mean)
659  *concentration
660  /totalConcentration;
661 
662  break;
663  }
664  case coordinateType::diameter:
665  {
666  variance +=
667  sqr(popBal.d(i) - mean)
668  *concentration
669  /totalConcentration;
670 
671  break;
672  }
673  }
674 
675  break;
676  }
677  }
678  }
679 
680  return tVariance;
681 }
682 
683 
685 Foam::functionObjects::populationBalanceMoments::stdDev
686 (
687  const populationBalanceModel& popBal
688 )
689 {
690  switch (meanType_)
691  {
692  case meanType::geometric:
693  {
694  return exp(sqrt(this->variance(popBal)));
695  }
696  default:
697  {
698  return sqrt(this->variance(popBal));
699  }
700  }
701 }
702 
703 
704 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
705 
707 (
708  const word& name,
709  const Time& runTime,
710  const dictionary& dict
711 )
712 :
713  fvMeshFunctionObject(name, runTime, dict),
714  popBalName_(dict.lookup("populationBalance")),
715  momentType_(momentTypeNames_.read(dict.lookup("momentType"))),
716  coordinateType_(coordinateTypeNames_.read(dict.lookup("coordinateType"))),
717  weightType_
718  (
719  dict.found("weightType")
720  ? weightTypeNames_.read(dict.lookup("weightType"))
721  : weightType::numberConcentration
722  ),
723  meanType_(meanType::notApplicable),
724  order_(-1),
725  fldPtr_(nullptr)
726 {
727  read(dict);
728 }
729 
730 
731 // * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * //
732 
734 {}
735 
736 
737 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
738 
739 bool
741 {
743 
744  switch (momentType_)
745  {
746  case momentType::integerMoment:
747  {
748  order_ = dict.lookup<int>("order");
749 
750  break;
751  }
752  default:
753  {
754  meanType_ =
755  dict.found("meanType")
756  ? meanTypeNames_.read(dict.lookup("meanType"))
757  : meanType::arithmetic;
758 
759  break;
760  }
761  }
762 
763  switch (momentType_)
764  {
765  case momentType::integerMoment:
766  {
767  fldPtr_.set
768  (
769  new volScalarField
770  (
771  IOobject
772  (
773  this->integerMomentFldName(),
774  mesh_.time().name(),
775  mesh_,
778  ),
779  mesh_,
781  )
782  );
783 
784  volScalarField& integerMoment = fldPtr_();
785 
786  setDimensions(integerMoment, momentType::integerMoment);
787 
788  break;
789  }
790  case momentType::mean:
791  {
792  fldPtr_.set
793  (
794  new volScalarField
795  (
796  IOobject
797  (
798  this->defaultFldName(),
799  mesh_.time().name(),
800  mesh_,
803  ),
804  mesh_,
806  )
807  );
808 
809  setDimensions(fldPtr_(), momentType::mean);
810 
811  break;
812  }
813  case momentType::variance:
814  {
815  fldPtr_.set
816  (
817  new volScalarField
818  (
819  IOobject
820  (
821  this->defaultFldName(),
822  mesh_.time().name(),
823  mesh_,
826  ),
827  mesh_,
829  )
830  );
831 
832  setDimensions(fldPtr_(), momentType::variance);
833 
834  break;
835  }
836  case momentType::stdDev:
837  {
838  fldPtr_.set
839  (
840  new volScalarField
841  (
842  IOobject
843  (
844  this->defaultFldName(),
845  mesh_.time().name(),
846  mesh_,
849  ),
850  mesh_,
852  )
853  );
854 
855  setDimensions(fldPtr_(), momentType::stdDev);
856 
857  break;
858  }
859  }
860 
861  return true;
862 }
863 
864 
866 {
867  const populationBalanceModel& popBal =
868  obr_.lookupObject<populationBalanceModel>(popBalName_);
869 
870  switch (momentType_)
871  {
872  case momentType::integerMoment:
873  {
874  volScalarField& integerMoment = fldPtr_();
875 
876  integerMoment = Zero;
877 
878  forAll(popBal.fs(), i)
879  {
880  const volScalarField& alpha = popBal.phases()[i];
881  const volScalarField& fi = popBal.f(i);
882  const dimensionedScalar& vi = popBal.v(i);
883 
884  volScalarField concentration(fi*alpha/vi);
885 
886  switch (weightType_)
887  {
888  case weightType::volumeConcentration:
889  {
890  concentration *= vi;
891 
892  break;
893  }
894  case weightType::areaConcentration:
895  {
896  concentration *= popBal.a(i);
897 
898  break;
899  }
900  default:
901  {
902  break;
903  }
904  }
905 
906  switch (coordinateType_)
907  {
909  {
910  integerMoment +=
911  pow(vi, order_)*concentration;
912 
913  break;
914  }
916  {
917  integerMoment +=
918  pow(popBal.a(i), order_)*concentration;
919 
920  break;
921  }
922  case coordinateType::diameter:
923  {
924  integerMoment +=
925  pow(popBal.d(i), order_)*concentration;
926 
927  break;
928  }
929  }
930  }
931 
932  break;
933  }
934  case momentType::mean:
935  {
936  fldPtr_() = this->mean(popBal);
937 
938  break;
939  }
940  case momentType::variance:
941  {
942  fldPtr_() = this->variance(popBal);
943 
944  break;
945  }
946  case momentType::stdDev:
947  {
948  fldPtr_() = sqrt(this->variance(popBal));
949 
950  break;
951  }
952  }
953 
954  return true;
955 }
956 
957 
959 {
960  writeObject(fldPtr_->name());
961 
962  return true;
963 }
964 
965 
966 // ************************************************************************* //
bool found
#define forAll(list, i)
Loop across all elements in list.
Definition: UList.H:449
Macros for easy insertion into run-time selection tables.
Generic GeometricField class.
static tmp< GeometricField< Type, GeoMesh, PrimitiveField > > New(const word &name, const Internal &, const PtrList< Patch > &, const HashPtrTable< Source > &=HashPtrTable< Source >())
Return a temporary field constructed from name,.
IOobject defines the attributes of an object for which implicit objectRegistry management is supporte...
Definition: IOobject.H:99
static word groupName(Name name, const word &group)
Initialise the NamedEnum HashTable from the static list of names.
Definition: NamedEnum.H:55
Class to control time during OpenFOAM simulations that is also the top-level objectRegistry.
Definition: Time.H:76
A list of keywords followed by any number of values (e.g. words and numbers) or sub-dictionaries.
Definition: dictionary.H:162
Abstract base-class for Time/database functionObjects.
Specialisation of Foam::functionObject for an Foam::fvMesh, providing a reference to the Foam::fvMesh...
virtual bool read(const dictionary &)
Read optional controls.
Calculates and writes out integral (integer moments) or mean properties (mean, variance,...
static const NamedEnum< coordinateType, 3 > coordinateTypeNames_
Names of the coordinate types.
static const NamedEnum< meanType, 3 > meanTypeNames_
Names of the mean types.
static const NamedEnum< momentType, 4 > momentTypeNames_
Names of the moment types.
static const NamedEnum< weightType, 3 > weightTypeNames_
Names of the weight types.
coordinateType
Enumeration for the coordinate types.
populationBalanceMoments(const word &name, const Time &runTime, const dictionary &)
Construct from Time and dictionary.
virtual bool execute()
Calculate the moment fields.
virtual bool write()
Write the moment fields.
virtual bool read(const dictionary &)
Read the data.
Model for tracking the evolution of a dispersed phase size distribution due to coalescence (synonymou...
const volScalarField & f(const label i) const
Access a group fraction.
const dimensionedScalar & v(const label i) const
Access the representative volumes diameters of a group.
const UPtrList< const phaseModel > & phases() const
Access the list of phases associated with each group.
const PtrList< volScalarField > & fs() const
Access the group fractions.
tmp< volScalarField > d(const label i) const
Return the representative diameter of the group.
tmp< volScalarField > a(const label i) const
Return the representative surface area of the group.
A class for managing temporary objects.
Definition: tmp.H:55
A class for handling words, derived from string.
Definition: word.H:63
static const word null
An empty word.
Definition: word.H:78
gmvFile<< "tracers "<< particles.size()<< nl;{ pointField positions(particles.size());label particlei=0;forAllConstIter(lagrangian::Cloud< passiveParticle >, particles, iter) { positions[particlei++]=iter().position(mesh);} for(i=0;i< pTraits< point >::nComponents;i++) { forAll(positions, particlei) { gmvFile<< component(positions[particlei], i)<< ' ';} gmvFile<< nl;}}forAll(lagrangianScalarNames, i){ const word &name=lagrangianScalarNames[i];IOField< scalar > fld(IOobject(name, runTime.name(), lagrangian::cloud::prefix, mesh, IOobject::MUST_READ, IOobject::NO_WRITE))
volScalarField alpha(IOobject("alpha", runTime.name(), mesh, IOobject::READ_IF_PRESENT, IOobject::AUTO_WRITE), lambda *max(Ua &U, zeroSensitivity))
const dimensionSet area
const dimensionSet volume
Definition: annulus.H:177
defineTypeNameAndDebug(fvMeshFunctionObject, 0)
addToRunTimeSelectionTable(functionObject, fvModel, dictionary)
const unitSet & lookup(const word &unitName)
Lookup and return the named unit from the table.
Definition: units.C:346
Namespace for OpenFOAM.
static const zero Zero
Definition: zero.H:97
dimensionedScalar exp(const dimensionedScalar &ds)
const dimensionSet & dimless
Definition: dimensions.C:138
bool read(const char *, int32_t &)
Definition: int32IO.C:85
const dimensionSet & dimLength
Definition: dimensions.C:141
const dimensionSet & dimVolume
Definition: dimensions.C:150
dimensionedScalar log(const dimensionedScalar &ds)
tmp< DimensionedField< typename outerProduct< Type, Type >::type, GeoMesh, Field >> sqr(const DimensionedField< Type, GeoMesh, PrimitiveField > &df)
void inv(pointPatchField< tensor > &, const pointPatchField< tensor > &)
VolField< scalar > volScalarField
Definition: volFieldsFwd.H:62
word name(const LagrangianState state)
Return a string representation of a Lagrangian state enumeration.
tmp< DimensionedField< typename powProduct< Type, r >::type, GeoMesh, Field > > pow(const DimensionedField< Type, GeoMesh, PrimitiveField > &df, typename powProduct< Type, r >::type)
const dimensionSet & dimArea
Definition: dimensions.C:149
void sqrt(LagrangianPatchField< scalar > &f, const LagrangianPatchField< scalar > &f1)
dimensioned< scalar > dimensionedScalar
Dimensioned scalar obtained from generic dimensioned type.
dictionary dict