forces.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 | Copyright (C) 2011-2015 OpenFOAM Foundation
6  \\/ M anipulation | Copyright (C) 2015 OpenCFD Ltd.
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 
26 #include "forces.H"
27 #include "volFields.H"
28 #include "dictionary.H"
29 #include "Time.H"
30 #include "wordReList.H"
31 #include "fvcGrad.H"
32 #include "porosityModel.H"
35 
36 // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
37 
38 namespace Foam
39 {
40  defineTypeNameAndDebug(forces, 0);
41 }
42 
43 
44 // * * * * * * * * * * * * Protected Member Functions * * * * * * * * * * * //
45 
47 {
48  return name_ + ":" + name;
49 }
50 
51 
53 {
54  // Note: Only possible to create bin files after bins have been initialised
55 
56  if (writeToFile() && !forceFilePtr_.valid())
57  {
58  forceFilePtr_ = createFile("force");
59  writeIntegratedHeader("Force", forceFilePtr_());
60  momentFilePtr_ = createFile("moment");
61  writeIntegratedHeader("Moment", momentFilePtr_());
62 
63  if (nBin_ > 1)
64  {
65  forceBinFilePtr_ = createFile("forceBin");
66  writeBinHeader("Force", forceBinFilePtr_());
67  momentBinFilePtr_ = createFile("momentBin");
68  writeBinHeader("Moment", momentBinFilePtr_());
69  }
70 
71  if (localSystem_)
72  {
73  localForceFilePtr_ = createFile("localForce");
74  writeIntegratedHeader("Force", localForceFilePtr_());
75  localMomentFilePtr_ = createFile("localMoment");
76  writeIntegratedHeader("Moment", localMomentFilePtr_());
77 
78  if (nBin_ > 1)
79  {
80  localForceBinFilePtr_ = createFile("localForceBin");
81  writeBinHeader("Force", localForceBinFilePtr_());
82  localMomentBinFilePtr_ = createFile("localMomentBin");
83  writeBinHeader("Moment", localMomentBinFilePtr_());
84  }
85  }
86  }
87 }
88 
89 
91 (
92  const word& header,
93  Ostream& os
94 ) const
95 {
96  writeHeader(os, header);
97  writeHeaderValue(os, "CofR", coordSys_.origin());
98  writeHeader(os, "");
99  writeCommented(os, "Time");
100  writeTabbed(os, "(total_x total_y total_z)");
101  writeTabbed(os, "(pressure_x pressure_y pressure_z)");
102  writeTabbed(os, "(viscous_x viscous_y viscous_z)");
103 
104  if (porosity_)
105  {
106  writeTabbed(os, "(porous_x porous_y porous_z)");
107  }
108 
109  os << endl;
110 }
111 
112 
113 void Foam::forces::writeBinHeader(const word& header, Ostream& os) const
114 {
115  writeHeader(os, header + " bins");
116  writeHeaderValue(os, "bins", nBin_);
117  writeHeaderValue(os, "start", binMin_);
118  writeHeaderValue(os, "delta", binDx_);
119  writeHeaderValue(os, "direction", binDir_);
120 
121  vectorField binPoints(nBin_);
122  writeCommented(os, "x co-ords :");
123  forAll(binPoints, pointI)
124  {
125  binPoints[pointI] = (binMin_ + (pointI + 1)*binDx_)*binDir_;
126  os << tab << binPoints[pointI].x();
127  }
128  os << nl;
129 
130  writeCommented(os, "y co-ords :");
131  forAll(binPoints, pointI)
132  {
133  os << tab << binPoints[pointI].y();
134  }
135  os << nl;
136 
137  writeCommented(os, "z co-ords :");
138  forAll(binPoints, pointI)
139  {
140  os << tab << binPoints[pointI].z();
141  }
142  os << nl;
143 
144  writeHeader(os, "");
145  writeCommented(os, "Time");
146 
147  for (label j = 0; j < nBin_; j++)
148  {
149  const word jn(Foam::name(j) + ':');
150  os << tab << jn << "(total_x total_y total_z)"
151  << tab << jn << "(pressure_x pressure_y pressure_z)"
152  << tab << jn << "(viscous_x viscous_y viscous_z)";
153 
154  if (porosity_)
155  {
156  os << tab << jn << "(porous_x porous_y porous_z)";
157  }
158  }
159 
160  os << endl;
161 }
162 
163 
165 {
166  if (initialised_ || !active_)
167  {
168  return;
169  }
170 
171  if (directForceDensity_)
172  {
173  if (!obr_.foundObject<volVectorField>(fDName_))
174  {
175  active_ = false;
177  << "Could not find " << fDName_ << " in database." << nl
178  << " De-activating forces."
179  << endl;
180  }
181  }
182  else
183  {
184  if
185  (
186  !obr_.foundObject<volVectorField>(UName_)
187  || !obr_.foundObject<volScalarField>(pName_)
188  || (
189  rhoName_ != "rhoInf"
190  && !obr_.foundObject<volScalarField>(rhoName_)
191  )
192  )
193  {
194  active_ = false;
195 
197  << "Could not find " << UName_ << ", " << pName_;
198 
199  if (rhoName_ != "rhoInf")
200  {
201  Info<< " or " << rhoName_;
202  }
203 
204  Info<< " in database." << nl
205  << " De-activating forces." << endl;
206  }
207  }
208 
209  initialiseBins();
210 
211  initialised_ = true;
212 }
213 
214 
216 {
217  if (!active_)
218  {
219  return;
220  }
221 
222  if (nBin_ > 1)
223  {
224  const fvMesh& mesh = refCast<const fvMesh>(obr_);
225  const polyBoundaryMesh& pbm = mesh.boundaryMesh();
226 
227  // Determine extents of patches
228  binMin_ = GREAT;
229  scalar binMax = -GREAT;
230  forAllConstIter(labelHashSet, patchSet_, iter)
231  {
232  label patchI = iter.key();
233  const polyPatch& pp = pbm[patchI];
234  scalarField d(pp.faceCentres() & binDir_);
235  binMin_ = min(min(d), binMin_);
236  binMax = max(max(d), binMax);
237  }
238 
239  // Include porosity
240  if (porosity_)
241  {
242  const HashTable<const porosityModel*> models =
243  obr_.lookupClass<porosityModel>();
244 
245  const scalarField dd(mesh.C() & binDir_);
246 
248  {
249  const porosityModel& pm = *iter();
250  const labelList& cellZoneIDs = pm.cellZoneIDs();
251 
252  forAll(cellZoneIDs, i)
253  {
254  label zoneI = cellZoneIDs[i];
255  const cellZone& cZone = mesh.cellZones()[zoneI];
256  const scalarField d(dd, cZone);
257  binMin_ = min(min(d), binMin_);
258  binMax = max(max(d), binMax);
259  }
260  }
261  }
262 
263  reduce(binMin_, minOp<scalar>());
264  reduce(binMax, maxOp<scalar>());
265 
266  // Slightly boost binMax so that region of interest is fully
267  // within bounds
268  binMax = 1.0001*(binMax - binMin_) + binMin_;
269 
270  binDx_ = (binMax - binMin_)/scalar(nBin_);
271 
272  // Create the bin points used for writing
273  binPoints_.setSize(nBin_);
274  forAll(binPoints_, i)
275  {
276  binPoints_[i] = (i + 0.5)*binDir_*binDx_;
277  }
278 
279  // Allocate storage for forces and moments
280  forAll(force_, i)
281  {
282  force_[i].setSize(nBin_);
283  moment_[i].setSize(nBin_);
284  }
285  }
286 }
287 
288 
290 {
291  force_[0] = vector::zero;
292  force_[1] = vector::zero;
293  force_[2] = vector::zero;
294 
295  moment_[0] = vector::zero;
296  moment_[1] = vector::zero;
297  moment_[2] = vector::zero;
298 
299  if (writeFields_)
300  {
301  volVectorField& force =
302  const_cast<volVectorField&>
303  (
304  obr_.lookupObject<volVectorField>(fieldName("force"))
305  );
306 
307  force == dimensionedVector("0", force.dimensions(), vector::zero);
308 
309  volVectorField& moment =
310  const_cast<volVectorField&>
311  (
312  obr_.lookupObject<volVectorField>(fieldName("moment"))
313  );
314 
315  moment == dimensionedVector("0", moment.dimensions(), vector::zero);
316  }
317 }
318 
319 
321 {
322  typedef compressible::turbulenceModel cmpTurbModel;
323  typedef incompressible::turbulenceModel icoTurbModel;
324 
325  if (obr_.foundObject<cmpTurbModel>(cmpTurbModel::propertiesName))
326  {
327  const cmpTurbModel& turb =
328  obr_.lookupObject<cmpTurbModel>(cmpTurbModel::propertiesName);
329 
330  return turb.devRhoReff();
331  }
332  else if (obr_.foundObject<icoTurbModel>(icoTurbModel::propertiesName))
333  {
335  obr_.lookupObject<icoTurbModel>(icoTurbModel::propertiesName);
336 
337  return rho()*turb.devReff();
338  }
339  else if (obr_.foundObject<fluidThermo>(fluidThermo::typeName))
340  {
341  const fluidThermo& thermo =
342  obr_.lookupObject<fluidThermo>(fluidThermo::typeName);
343 
344  const volVectorField& U = obr_.lookupObject<volVectorField>(UName_);
345 
346  return -thermo.mu()*dev(twoSymm(fvc::grad(U)));
347  }
348  else if
349  (
350  obr_.foundObject<transportModel>("transportProperties")
351  )
352  {
353  const transportModel& laminarT =
354  obr_.lookupObject<transportModel>("transportProperties");
355 
356  const volVectorField& U = obr_.lookupObject<volVectorField>(UName_);
357 
358  return -rho()*laminarT.nu()*dev(twoSymm(fvc::grad(U)));
359  }
360  else if (obr_.foundObject<dictionary>("transportProperties"))
361  {
362  const dictionary& transportProperties =
363  obr_.lookupObject<dictionary>("transportProperties");
364 
365  dimensionedScalar nu(transportProperties.lookup("nu"));
366 
367  const volVectorField& U = obr_.lookupObject<volVectorField>(UName_);
368 
369  return -rho()*nu*dev(twoSymm(fvc::grad(U)));
370  }
371  else
372  {
374  << "No valid model for viscous stress calculation"
375  << exit(FatalError);
376 
377  return volSymmTensorField::null();
378  }
379 }
380 
381 
383 {
384  if (obr_.foundObject<fluidThermo>(basicThermo::dictName))
385  {
386  const fluidThermo& thermo =
387  obr_.lookupObject<fluidThermo>(basicThermo::dictName);
388 
389  return thermo.mu();
390  }
391  else if
392  (
393  obr_.foundObject<transportModel>("transportProperties")
394  )
395  {
396  const transportModel& laminarT =
397  obr_.lookupObject<transportModel>("transportProperties");
398 
399  return rho()*laminarT.nu();
400  }
401  else if (obr_.foundObject<dictionary>("transportProperties"))
402  {
403  const dictionary& transportProperties =
404  obr_.lookupObject<dictionary>("transportProperties");
405 
406  dimensionedScalar nu(transportProperties.lookup("nu"));
407 
408  return rho()*nu;
409  }
410  else
411  {
413  << "No valid model for dynamic viscosity calculation"
414  << exit(FatalError);
415 
416  return volScalarField::null();
417  }
418 }
419 
420 
422 {
423  if (rhoName_ == "rhoInf")
424  {
425  const fvMesh& mesh = refCast<const fvMesh>(obr_);
426 
427  return tmp<volScalarField>
428  (
429  new volScalarField
430  (
431  IOobject
432  (
433  "rho",
434  mesh.time().timeName(),
435  mesh
436  ),
437  mesh,
438  dimensionedScalar("rho", dimDensity, rhoRef_)
439  )
440  );
441  }
442  else
443  {
444  return(obr_.lookupObject<volScalarField>(rhoName_));
445  }
446 }
447 
448 
449 Foam::scalar Foam::forces::rho(const volScalarField& p) const
450 {
451  if (p.dimensions() == dimPressure)
452  {
453  return 1.0;
454  }
455  else
456  {
457  if (rhoName_ != "rhoInf")
458  {
460  << "Dynamic pressure is expected but kinematic is provided."
461  << exit(FatalError);
462  }
463 
464  return rhoRef_;
465  }
466 }
467 
468 
470 (
471  const vectorField& Md,
472  const vectorField& fN,
473  const vectorField& fT,
474  const vectorField& fP,
475  const vectorField& d
476 )
477 {
478  if (nBin_ == 1)
479  {
480  force_[0][0] += sum(fN);
481  force_[1][0] += sum(fT);
482  force_[2][0] += sum(fP);
483  moment_[0][0] += sum(Md^fN);
484  moment_[1][0] += sum(Md^fT);
485  moment_[2][0] += sum(Md^fP);
486  }
487  else
488  {
489  scalarField dd((d & binDir_) - binMin_);
490 
491  forAll(dd, i)
492  {
493  label bini = min(max(floor(dd[i]/binDx_), 0), force_[0].size() - 1);
494 
495  force_[0][bini] += fN[i];
496  force_[1][bini] += fT[i];
497  force_[2][bini] += fP[i];
498  moment_[0][bini] += Md[i]^fN[i];
499  moment_[1][bini] += Md[i]^fT[i];
500  moment_[2][bini] += Md[i]^fP[i];
501  }
502  }
503 }
504 
505 
507 (
508  const label patchI,
509  const vectorField& Md,
510  const vectorField& fN,
511  const vectorField& fT,
512  const vectorField& fP
513 )
514 {
515  if (!writeFields_)
516  {
517  return;
518  }
519 
520  volVectorField& force =
521  const_cast<volVectorField&>
522  (
523  obr_.lookupObject<volVectorField>(fieldName("force"))
524  );
525 
526  vectorField& pf = force.boundaryField()[patchI];
527  pf += fN + fT + fP;
528 
529  volVectorField& moment =
530  const_cast<volVectorField&>
531  (
532  obr_.lookupObject<volVectorField>(fieldName("moment"))
533  );
534 
535  vectorField& pm = moment.boundaryField()[patchI];
536  pm += Md;
537 }
538 
539 
541 (
542  const labelList& cellIDs,
543  const vectorField& Md,
544  const vectorField& fN,
545  const vectorField& fT,
546  const vectorField& fP
547 )
548 {
549  if (!writeFields_)
550  {
551  return;
552  }
553 
554  volVectorField& force =
555  const_cast<volVectorField&>
556  (
557  obr_.lookupObject<volVectorField>(fieldName("force"))
558  );
559 
560  volVectorField& moment =
561  const_cast<volVectorField&>
562  (
563  obr_.lookupObject<volVectorField>(fieldName("moment"))
564  );
565 
566  forAll(cellIDs, i)
567  {
568  label cellI = cellIDs[i];
569  force[cellI] += fN[i] + fT[i] + fP[i];
570  moment[cellI] += Md[i];
571  }
572 }
573 
574 
576 (
577  const string& descriptor,
578  const vectorField& fm0,
579  const vectorField& fm1,
580  const vectorField& fm2,
581  autoPtr<OFstream>& osPtr
582 ) const
583 {
584  vector pressure = sum(fm0);
585  vector viscous = sum(fm1);
586  vector porous = sum(fm2);
587  vector total = pressure + viscous + porous;
588 
589  if (log_)
590  {
591  Info<< " Sum of " << descriptor.c_str() << nl
592  << " Total : " << total << nl
593  << " Pressure : " << pressure << nl
594  << " Viscous : " << viscous << nl;
595 
596  if (porosity_)
597  {
598  Info<< " Porous : " << porous << nl;
599  }
600  }
601 
602  if (writeToFile())
603  {
604  Ostream& os = osPtr();
605 
606  os << obr_.time().value()
607  << tab << total
608  << tab << pressure
609  << tab << viscous;
610 
611  if (porosity_)
612  {
613  os << tab << porous;
614  }
615 
616  os << endl;
617  }
618 }
619 
620 
622 {
623  if (log_) Info << type() << " " << name_ << " output:" << nl;
624 
625  writeIntegratedForceMoment
626  (
627  "forces",
628  force_[0],
629  force_[1],
630  force_[2],
631  forceFilePtr_
632  );
633 
634  writeIntegratedForceMoment
635  (
636  "moments",
637  moment_[0],
638  moment_[1],
639  moment_[2],
640  momentFilePtr_
641  );
642 
643  if (localSystem_)
644  {
645  writeIntegratedForceMoment
646  (
647  "local forces",
648  coordSys_.localVector(force_[0]),
649  coordSys_.localVector(force_[1]),
650  coordSys_.localVector(force_[2]),
651  localForceFilePtr_
652  );
653 
654  writeIntegratedForceMoment
655  (
656  "local moments",
657  coordSys_.localVector(moment_[0]),
658  coordSys_.localVector(moment_[1]),
659  coordSys_.localVector(moment_[2]),
660  localMomentFilePtr_
661  );
662  }
663 
664  if (log_) Info << endl;
665 }
666 
667 
669 (
670  const List<Field<vector> >& fm,
671  autoPtr<OFstream>& osPtr
672 ) const
673 {
674  if ((nBin_ == 1) || !writeToFile())
675  {
676  return;
677  }
678 
679  List<Field<vector> > f(fm);
680 
681  if (binCumulative_)
682  {
683  for (label i = 1; i < f[0].size(); i++)
684  {
685  f[0][i] += f[0][i-1];
686  f[1][i] += f[1][i-1];
687  f[2][i] += f[2][i-1];
688  }
689  }
690 
691  Ostream& os = osPtr();
692 
693  writeTime(os);
694 
695  forAll(f[0], i)
696  {
697  vector total = f[0][i] + f[1][i] + f[2][i];
698 
699  os << tab << total
700  << tab << f[0][i]
701  << tab << f[1][i];
702 
703  if (porosity_)
704  {
705  os << tab << f[2][i];
706  }
707  }
708 
709  os << nl;
710 }
711 
712 
714 {
715  writeBinnedForceMoment(force_, forceBinFilePtr_);
716  writeBinnedForceMoment(moment_, momentBinFilePtr_);
717 
718  if (localSystem_)
719  {
720  List<Field<vector> > lf(3);
721  List<Field<vector> > lm(3);
722  lf[0] = coordSys_.localVector(force_[0]);
723  lf[1] = coordSys_.localVector(force_[1]);
724  lf[2] = coordSys_.localVector(force_[2]);
725  lm[0] = coordSys_.localVector(moment_[0]);
726  lm[1] = coordSys_.localVector(moment_[1]);
727  lm[2] = coordSys_.localVector(moment_[2]);
728 
729  writeBinnedForceMoment(lf, localForceBinFilePtr_);
730  writeBinnedForceMoment(lm, localMomentBinFilePtr_);
731  }
732 }
733 
734 
735 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
736 
738 (
739  const word& name,
740  const objectRegistry& obr,
741  const dictionary& dict,
742  const bool loadFromFiles,
743  const bool readFields
744 )
745 :
747  functionObjectFile(obr, name),
748  obr_(obr),
749  log_(true),
750  force_(3),
751  moment_(3),
752  forceFilePtr_(),
753  momentFilePtr_(),
754  forceBinFilePtr_(),
755  momentBinFilePtr_(),
756  localForceFilePtr_(),
757  localMomentFilePtr_(),
758  localForceBinFilePtr_(),
759  localMomentBinFilePtr_(),
760  patchSet_(),
761  pName_(word::null),
762  UName_(word::null),
763  rhoName_(word::null),
764  directForceDensity_(false),
765  fDName_(""),
766  rhoRef_(VGREAT),
767  pRef_(0),
768  coordSys_(),
769  localSystem_(false),
770  porosity_(false),
771  nBin_(1),
772  binDir_(vector::zero),
773  binDx_(0.0),
774  binMin_(GREAT),
775  binPoints_(),
776  binCumulative_(true),
777  writeFields_(false),
778  initialised_(false)
779 {
780  // Check if the available mesh is an fvMesh otherise deactivate
781  if (setActive<fvMesh>())
782  {
783  if (readFields)
784  {
785  read(dict);
786  if (log_) Info << endl;
787  }
788  }
789 }
790 
791 
793 (
794  const word& name,
795  const objectRegistry& obr,
796  const labelHashSet& patchSet,
797  const word& pName,
798  const word& UName,
799  const word& rhoName,
800  const scalar rhoInf,
801  const scalar pRef,
802  const coordinateSystem& coordSys
803 )
804 :
806  functionObjectFile(obr, name),
807  obr_(obr),
808  log_(true),
809  force_(3),
810  moment_(3),
811  forceFilePtr_(),
812  momentFilePtr_(),
813  forceBinFilePtr_(),
814  momentBinFilePtr_(),
815  localForceFilePtr_(),
816  localMomentFilePtr_(),
817  localForceBinFilePtr_(),
818  localMomentBinFilePtr_(),
819  patchSet_(patchSet),
820  pName_(pName),
821  UName_(UName),
822  rhoName_(rhoName),
823  directForceDensity_(false),
824  fDName_(""),
825  rhoRef_(rhoInf),
826  pRef_(pRef),
827  coordSys_(coordSys),
828  localSystem_(false),
829  porosity_(false),
830  nBin_(1),
831  binDir_(vector::zero),
832  binDx_(0.0),
833  binMin_(GREAT),
834  binPoints_(),
835  binCumulative_(true),
836  writeFields_(false),
837  initialised_(false)
838 {
839  // Turn off writing to file
840  writeToFile_ = false;
841 
842  forAll(force_, i)
843  {
844  force_[i].setSize(nBin_);
845  moment_[i].setSize(nBin_);
846  }
847 }
848 
849 
850 // * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * //
851 
853 {}
854 
855 
856 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
857 
859 {
860  if (!active_)
861  {
862  return;
863  }
864 
866 
867  initialised_ = false;
868 
869  log_ = dict.lookupOrDefault<Switch>("log", false);
870 
871  if (log_) Info << type() << " " << name_ << ":" << nl;
872 
873  directForceDensity_ = dict.lookupOrDefault("directForceDensity", false);
874 
875  const fvMesh& mesh = refCast<const fvMesh>(obr_);
876  const polyBoundaryMesh& pbm = mesh.boundaryMesh();
877 
878  patchSet_ = pbm.patchSet(wordReList(dict.lookup("patches")));
879 
880  if (directForceDensity_)
881  {
882  // Optional entry for fDName
883  fDName_ = dict.lookupOrDefault<word>("fDName", "fD");
884  }
885  else
886  {
887  // Optional entries U and p
888  pName_ = dict.lookupOrDefault<word>("pName", "p");
889  UName_ = dict.lookupOrDefault<word>("UName", "U");
890  rhoName_ = dict.lookupOrDefault<word>("rhoName", "rho");
891 
892  // Reference density needed for incompressible calculations
893  rhoRef_ = readScalar(dict.lookup("rhoInf"));
894 
895  // Reference pressure, 0 by default
896  pRef_ = dict.lookupOrDefault<scalar>("pRef", 0.0);
897  }
898 
899  coordSys_.clear();
900 
901  // Centre of rotation for moment calculations
902  // specified directly, from coordinate system, or implicitly (0 0 0)
903  if (!dict.readIfPresent<point>("CofR", coordSys_.origin()))
904  {
905  coordSys_ = coordinateSystem(obr_, dict);
906  localSystem_ = true;
907  }
908 
909  dict.readIfPresent("porosity", porosity_);
910  if (porosity_)
911  {
912  if (log_) Info << " Including porosity effects" << endl;
913  }
914  else
915  {
916  if (log_) Info << " Not including porosity effects" << endl;
917  }
918 
919  if (dict.found("binData"))
920  {
921  const dictionary& binDict(dict.subDict("binData"));
922  binDict.lookup("nBin") >> nBin_;
923 
924  if (nBin_ < 0)
925  {
927  << "Number of bins (nBin) must be zero or greater"
928  << exit(FatalIOError);
929  }
930  else if (nBin_ == 0)
931  {
932  nBin_ = 1;
933  }
934  else
935  {
936  binDict.lookup("cumulative") >> binCumulative_;
937  binDict.lookup("direction") >> binDir_;
938  binDir_ /= mag(binDir_);
939  }
940  }
941 
942  if (nBin_ == 1)
943  {
944  // Allocate storage for forces and moments
945  forAll(force_, i)
946  {
947  force_[i].setSize(1);
948  moment_[i].setSize(1);
949  }
950  }
951 
952  writeFields_ = dict.lookupOrDefault("writeFields", false);
953 
954  if (writeFields_)
955  {
956  if (log_) Info << " Fields will be written" << endl;
957 
958  tmp<volVectorField> tforce
959  (
960  new volVectorField
961  (
962  IOobject
963  (
964  fieldName("force"),
965  mesh.time().timeName(),
966  mesh,
969  ),
970  mesh,
972  )
973  );
974 
975  obr_.store(tforce.ptr());
976 
977  tmp<volVectorField> tmoment
978  (
979  new volVectorField
980  (
981  IOobject
982  (
983  fieldName("moment"),
984  mesh.time().timeName(),
985  mesh,
988  ),
989  mesh,
991  )
992  );
993 
994  obr_.store(tmoment.ptr());
995  }
996 }
997 
998 
1000 {
1001  if (!active_)
1002  {
1003  return;
1004  }
1005 
1006  // calcForcesMoment may have reset the active flag - need to re-check
1007  calcForcesMoment();
1008 
1009  if (!active_)
1010  {
1011  return;
1012  }
1013 
1014  if (Pstream::master())
1015  {
1016  createFiles();
1017 
1018  writeForces();
1019 
1020  writeBins();
1021 
1022  if (log_) Info << endl;
1023  }
1024 
1025  // write state/results information
1026  setResult("normalForce", sum(force_[0]));
1027  setResult("tangentialForce", sum(force_[1]));
1028  setResult("porousForce", sum(force_[2]));
1029 
1030  setResult("normalMoment", sum(moment_[0]));
1031  setResult("tangentialMoment", sum(moment_[1]));
1032  setResult("porousMoment", sum(moment_[2]));
1033 }
1034 
1035 
1037 {
1038  // Do nothing
1039 }
1040 
1041 
1043 {
1044  // Do nothing
1045 }
1046 
1047 
1049 {
1050  if (!active_)
1051  {
1052  return;
1053  }
1054 
1055  if (writeFields_)
1056  {
1057  obr_.lookupObject<volVectorField>(fieldName("force")).write();
1058  obr_.lookupObject<volVectorField>(fieldName("moment")).write();
1059  }
1060 }
1061 
1062 
1064 {
1065  if (!active_)
1066  {
1067  return;
1068  }
1069 
1070  initialise();
1071 
1072  // Initialise may have reset the active flag - need to re-check
1073  if (!active_)
1074  {
1075  return;
1076  }
1077 
1078  resetFields();
1079 
1080  if (directForceDensity_)
1081  {
1082  const volVectorField& fD = obr_.lookupObject<volVectorField>(fDName_);
1083 
1084  const fvMesh& mesh = fD.mesh();
1085 
1087  mesh.Sf().boundaryField();
1088 
1089  forAllConstIter(labelHashSet, patchSet_, iter)
1090  {
1091  label patchI = iter.key();
1092 
1093  vectorField Md
1094  (
1095  mesh.C().boundaryField()[patchI] - coordSys_.origin()
1096  );
1097 
1098  scalarField sA(mag(Sfb[patchI]));
1099 
1100  // Normal force = surfaceUnitNormal*(surfaceNormal & forceDensity)
1101  vectorField fN
1102  (
1103  Sfb[patchI]/sA
1104  *(
1105  Sfb[patchI] & fD.boundaryField()[patchI]
1106  )
1107  );
1108 
1109  // Tangential force (total force minus normal fN)
1110  vectorField fT(sA*fD.boundaryField()[patchI] - fN);
1111 
1112  //- Porous force
1113  vectorField fP(Md.size(), vector::zero);
1114 
1115  addToFields(patchI, Md, fN, fT, fP);
1116 
1117  applyBins(Md, fN, fT, fP, mesh.C().boundaryField()[patchI]);
1118  }
1119  }
1120  else
1121  {
1122  const volVectorField& U = obr_.lookupObject<volVectorField>(UName_);
1123  const volScalarField& p = obr_.lookupObject<volScalarField>(pName_);
1124 
1125  const fvMesh& mesh = U.mesh();
1126 
1128  mesh.Sf().boundaryField();
1129 
1130  tmp<volSymmTensorField> tdevRhoReff = devRhoReff();
1132  = tdevRhoReff().boundaryField();
1133 
1134  // Scale pRef by density for incompressible simulations
1135  scalar pRef = pRef_/rho(p);
1136 
1137  forAllConstIter(labelHashSet, patchSet_, iter)
1138  {
1139  label patchI = iter.key();
1140 
1141  vectorField Md
1142  (
1143  mesh.C().boundaryField()[patchI] - coordSys_.origin()
1144  );
1145 
1146  vectorField fN
1147  (
1148  rho(p)*Sfb[patchI]*(p.boundaryField()[patchI] - pRef)
1149  );
1150 
1151  vectorField fT(Sfb[patchI] & devRhoReffb[patchI]);
1152 
1153  vectorField fP(Md.size(), vector::zero);
1154 
1155  addToFields(patchI, Md, fN, fT, fP);
1156 
1157  applyBins(Md, fN, fT, fP, mesh.C().boundaryField()[patchI]);
1158  }
1159  }
1160 
1161  if (porosity_)
1162  {
1163  const volVectorField& U = obr_.lookupObject<volVectorField>(UName_);
1164  const volScalarField rho(this->rho());
1165  const volScalarField mu(this->mu());
1166 
1167  const fvMesh& mesh = U.mesh();
1168 
1169  const HashTable<const porosityModel*> models =
1170  obr_.lookupClass<porosityModel>();
1171 
1172  if (models.empty())
1173  {
1175  << "Porosity effects requested, but no porosity models found "
1176  << "in the database"
1177  << endl;
1178  }
1179 
1181  {
1182  // non-const access required if mesh is changing
1183  porosityModel& pm = const_cast<porosityModel&>(*iter());
1184 
1185  vectorField fPTot(pm.force(U, rho, mu));
1186 
1187  const labelList& cellZoneIDs = pm.cellZoneIDs();
1188 
1189  forAll(cellZoneIDs, i)
1190  {
1191  label zoneI = cellZoneIDs[i];
1192  const cellZone& cZone = mesh.cellZones()[zoneI];
1193 
1194  const vectorField d(mesh.C(), cZone);
1195  const vectorField fP(fPTot, cZone);
1196  const vectorField Md(d - coordSys_.origin());
1197 
1198  const vectorField fDummy(Md.size(), vector::zero);
1199 
1200  addToFields(cZone, Md, fDummy, fDummy, fP);
1201 
1202  applyBins(Md, fDummy, fDummy, fP, d);
1203  }
1204  }
1205  }
1206 
1210  Pstream::listCombineScatter(moment_);
1211 }
1212 
1213 
1215 {
1216  return sum(force_[0]) + sum(force_[1]) + sum(force_[2]);
1217 }
1218 
1219 
1221 {
1222  return sum(moment_[0]) + sum(moment_[1]) + sum(moment_[2]);
1223 }
1224 
1225 
1226 // ************************************************************************* //
volFields.H
Foam::forces::createFiles
void createFiles()
Create the output files.
Definition: forces.C:52
Foam::dimPressure
const dimensionSet dimPressure
Foam::maxOp
Definition: ops.H:172
Foam::IOobject
IOobject defines the attributes of an object for which implicit objectRegistry management is supporte...
Definition: IOobject.H:91
Foam::Switch
A simple wrapper around bool so that it can be read as a word: true/false, on/off,...
Definition: Switch.H:60
Foam::fvc::grad
tmp< GeometricField< typename outerProduct< vector, Type >::type, fvPatchField, volMesh >> grad(const GeometricField< Type, fvsPatchField, surfaceMesh > &ssf)
Definition: fvcGrad.C:52
Foam::forces::writeBinnedForceMoment
void writeBinnedForceMoment(const List< Field< vector > > &fm, autoPtr< OFstream > &osPtr) const
Helper function to write binned forces and moments.
Definition: forces.C:669
Foam::Vector< scalar >::zero
static const Vector zero
Definition: Vector.H:80
p
p
Definition: pEqn.H:62
Foam::word
A class for handling words, derived from string.
Definition: word.H:59
Foam::porosityModel::cellZoneIDs
const labelList & cellZoneIDs() const
Return const access to the cell zone IDs.
Definition: porosityModelI.H:38
Foam::polyBoundaryMesh
Foam::polyBoundaryMesh.
Definition: polyBoundaryMesh.H:60
Foam::forces::~forces
virtual ~forces()
Destructor.
Definition: forces.C:852
Foam::transportModel::nu
virtual tmp< volScalarField > nu() const =0
Return the laminar viscosity.
Foam::functionObjectState
Base class for function objects, adding functionality to read/write state information (data required ...
Definition: functionObjectState.H:54
Foam::constant::physicoChemical::mu
const dimensionedScalar mu
Atomic mass unit.
Definition: createFields.H:13
Foam::dimLength
const dimensionSet dimLength(0, 1, 0, 0, 0, 0, 0)
Definition: dimensionSets.H:50
forAll
#define forAll(list, i)
Loop across all elements in list.
Definition: UList.H:406
Foam::tmp
A class for managing temporary objects.
Definition: PtrList.H:118
Foam::dimDensity
const dimensionSet dimDensity
Foam::dictionary::readIfPresent
bool readIfPresent(const word &, T &, bool recursive=false, bool patternMatch=true) const
Find an entry if present, and assign to T.
Definition: dictionaryTemplates.C:94
Foam::basicThermo::dictName
static const word dictName
Definition: basicThermo.H:176
Foam::read
bool read(const char *, int32_t &)
Definition: int32IO.C:87
Foam::jn
dimensionedScalar jn(const int n, const dimensionedScalar &ds)
Definition: dimensionedScalar.C:296
Foam::minOp
Definition: ops.H:173
Foam::forces::applyBins
void applyBins(const vectorField &Md, const vectorField &fN, const vectorField &fT, const vectorField &fP, const vectorField &d)
Accumulate bin data.
Definition: forces.C:470
turbulentTransportModel.H
Foam::wordReList
List< wordRe > wordReList
A List of wordRe (word or regular expression)
Definition: wordReList.H:50
Foam::dictionary::lookup
ITstream & lookup(const word &, bool recursive=false, bool patternMatch=true) const
Find and return an entry data stream.
Definition: dictionary.C:449
Foam::forces::writeIntegratedHeader
void writeIntegratedHeader(const word &header, Ostream &os) const
Write header for integrated data.
Definition: forces.C:91
Foam::forces::fieldName
word fieldName(const word &name) const
Create a field name.
Definition: forces.C:46
Foam::fluidThermo
Fundamental fluid thermodynamic properties.
Definition: fluidThermo.H:49
Foam::dictionary::lookupOrDefault
T lookupOrDefault(const word &, const T &, bool recursive=false, bool patternMatch=true) const
Find and return a T,.
Definition: dictionaryTemplates.C:33
thermo
Basic thermodynamics type based on the use of fitting functions for cp, h, s obtained from the templa...
Foam::polyMesh::cellZones
const cellZoneMesh & cellZones() const
Return cell zone mesh.
Definition: polyMesh.H:469
Foam::GeometricField::boundaryField
GeometricBoundaryField & boundaryField()
Return reference to GeometricBoundaryField.
Definition: GeometricField.C:735
Foam::functionObjectFile::read
void read(const dictionary &dict)
Read.
Definition: functionObjectFile.C:178
Foam::FatalIOError
IOerror FatalIOError
Foam::polyMesh::boundaryMesh
const polyBoundaryMesh & boundaryMesh() const
Return boundary mesh.
Definition: polyMesh.H:421
Foam::endl
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:251
porosityModel.H
Foam::forces::write
virtual void write()
Write the forces.
Definition: forces.C:1048
Foam::forces::forceEff
virtual vector forceEff() const
Return the total force.
Definition: forces.C:1214
Foam::mag
dimensioned< scalar > mag(const dimensioned< Type > &)
Foam::dimForce
const dimensionSet dimForce
Foam::readFields
This function object reads fields from the time directories and adds them to the mesh database for fu...
Definition: readFields.H:104
Foam::HashSet< label, Hash< label > >
Foam::forces::end
virtual void end()
Execute at the final time-loop, currently does nothing.
Definition: forces.C:1036
Foam::IOobject::NO_WRITE
@ NO_WRITE
Definition: IOobject.H:118
U
U
Definition: pEqn.H:46
Foam::cellZone
A subset of mesh cells.
Definition: cellZone.H:61
forAllConstIter
forAllConstIter(PtrDictionary< phaseModel >, mixture.phases(), phase)
Definition: pEqn.H:39
Foam::dimensionedVector
dimensioned< vector > dimensionedVector
Dimensioned vector obtained from generic dimensioned type.
Definition: dimensionedVector.H:48
Foam::objectRegistry
Registry of regIOobjects.
Definition: objectRegistry.H:50
nu
volScalarField & nu
Definition: readMechanicalProperties.H:179
Foam::forces::resetFields
void resetFields()
Reset the fields prior to accumulation of force/moments.
Definition: forces.C:289
Foam::forces::writeBins
void writeBins()
Write binned data.
Definition: forces.C:713
Foam::forces::initialiseBins
void initialiseBins()
Initialise the collection bins.
Definition: forces.C:215
Foam::reduce
void reduce(const List< UPstream::commsStruct > &comms, T &Value, const BinaryOp &bop, const int tag, const label comm)
Definition: PstreamReduceOps.H:43
Foam::porosityModel::force
virtual tmp< vectorField > force(const volVectorField &U, const volScalarField &rho, const volScalarField &mu)
Return the force over the cell zone(s)
Foam::label
intWM_LABEL_SIZE_t label
A label is an int32_t or int64_t as specified by the pre-processor macro WM_LABEL_SIZE.
Definition: label.H:59
Foam::dictionary::found
bool found(const word &, bool recursive=false, bool patternMatch=true) const
Search dictionary for given keyword.
Definition: dictionary.C:304
Foam::Field
Pre-declare SubField and related Field type.
Definition: Field.H:57
Foam::forces::execute
virtual void execute()
Execute, currently does nothing.
Definition: forces.C:999
Foam::forces::writeForces
void writeForces()
Write force data.
Definition: forces.C:621
Foam::HashTable::empty
bool empty() const
Return true if the hash table is empty.
Definition: HashTableI.H:72
Foam::IOobject::NO_READ
@ NO_READ
Definition: IOobject.H:111
Foam::nl
static const char nl
Definition: Ostream.H:260
Foam::Info
messageStream Info
Foam::polyPatch
A patch is a list of labels that address the faces in the global face list.
Definition: polyPatch.H:66
dict
dictionary dict
Definition: searchingEngine.H:14
Foam::forces::name
virtual const word & name() const
Return name of the set of forces.
Definition: forces.H:484
Foam::FatalError
error FatalError
Foam::dictionary
A list of keyword definitions, which are a keyword followed by any number of values (e....
Definition: dictionary.H:137
pRef
scalar pRef
Definition: createFields.H:19
mesh
dynamicFvMesh & mesh
Definition: createDynamicFvMesh.H:18
Foam::plusEqOp
Definition: ops.H:71
Foam::dimensioned
Generic dimensioned Type class.
Definition: dimensionedScalarFwd.H:41
Foam::fvMesh::Sf
const surfaceVectorField & Sf() const
Return cell face area vectors.
Definition: fvMeshGeometry.C:347
Foam::fvMesh
Mesh data needed to do the Finite Volume discretisation.
Definition: fvMesh.H:78
Foam::forces::calcForcesMoment
virtual void calcForcesMoment()
Calculate the forces and moments.
Definition: forces.C:1063
Foam
Namespace for OpenFOAM.
Definition: combustionModel.C:30
Foam::tmp::ptr
T * ptr() const
Return tmp pointer for reuse.
Definition: tmpI.H:146
Foam::forces::timeSet
virtual void timeSet()
Called when time was set at the end of the Time::operator++.
Definition: forces.C:1042
Foam::forces::writeIntegratedForceMoment
void writeIntegratedForceMoment(const string &descriptor, const vectorField &fm0, const vectorField &fm1, const vectorField &fm2, autoPtr< OFstream > &osPtr) const
Helper function to write integrated forces and moments.
Definition: forces.C:576
Foam::exit
errorManipArg< error, int > exit(error &err, const int errNo=1)
Definition: errorManip.H:124
Foam::transportModel
Base-class for all transport models used by the incompressible turbulence models.
Definition: transportModel.H:51
rho
rho
Definition: pEqn.H:3
Foam::UPstream::master
static bool master(const label communicator=0)
Am I the master process.
Definition: UPstream.H:399
Foam::HashTable
An STL-conforming hash table.
Definition: HashTable.H:61
Foam::Pstream::listCombineGather
static void listCombineGather(const List< commsStruct > &comms, List< T > &Value, const CombineOp &cop, const int tag, const label comm)
Definition: combineGatherScatter.C:282
Foam::max
dimensioned< Type > max(const dimensioned< Type > &, const dimensioned< Type > &)
Foam::autoPtr
An auto-pointer similar to the STL auto_ptr but with automatic casting to a reference to the type and...
Definition: PtrList.H:117
Foam::forces::addToFields
void addToFields(const label patchI, const vectorField &Md, const vectorField &fN, const vectorField &fT, const vectorField &fP)
Add patch contributions to force and moment fields.
Definition: forces.C:507
Foam::porosityModel
Top level model for porosity models.
Definition: porosityModel.H:55
FatalErrorInFunction
#define FatalErrorInFunction
Report an error message using Foam::FatalError.
Definition: error.H:318
forces.H
Foam::fvMesh::C
const volVectorField & C() const
Return cell centres as volVectorField.
Definition: fvMeshGeometry.C:369
Foam::forces::mu
tmp< volScalarField > mu() const
Dynamic viscosity field.
Definition: forces.C:382
Foam::tab
static const char tab
Definition: Ostream.H:259
Foam::readScalar
bool readScalar(const char *buf, doubleScalar &s)
Read whole of buf as a scalar. Return true if succesful.
Definition: doubleScalar.H:63
Foam::polyPatch::faceCentres
const vectorField::subField faceCentres() const
Return face centres.
Definition: polyPatch.C:308
Foam::forces::momentEff
virtual vector momentEff() const
Return the total moment.
Definition: forces.C:1220
f
labelList f(nPoints)
Foam::functionObjectState::name_
const word name_
Name of model.
Definition: functionObjectState.H:72
Foam::Vector< scalar >
Foam::ThermalDiffusivity
Templated wrapper class to provide compressible turbulence models thermal diffusivity based thermal t...
Definition: ThermalDiffusivity.H:48
wordReList.H
Foam::Time::timeName
static word timeName(const scalar, const int precision=precision_)
Return time name of given scalar time.
Definition: Time.C:741
Foam::List
A 1D array of objects of type <T>, where the size of the vector is known and used for subscript bound...
Definition: HashTable.H:59
fvcGrad.H
Calculate the gradient of the given field.
Foam::functionObjectFile
Base class for output file data handling.
Definition: functionObjectFile.H:57
dictionary.H
Foam::sum
dimensioned< Type > sum(const DimensionedField< Type, GeoMesh > &df)
Definition: DimensionedFieldFunctions.C:333
Foam::word::null
static const word null
An empty word.
Definition: word.H:77
Foam::forces::read
virtual void read(const dictionary &)
Read the forces data.
Definition: forces.C:858
Foam::fvMesh::time
const Time & time() const
Return the top-level database.
Definition: fvMesh.H:243
Foam::forces::writeBinHeader
void writeBinHeader(const word &header, Ostream &os) const
Write header for binned data.
Definition: forces.C:113
Foam::IncompressibleTurbulenceModel
Templated abstract base class for single-phase incompressible turbulence models.
Definition: IncompressibleTurbulenceModel.H:52
FatalIOErrorInFunction
#define FatalIOErrorInFunction(ios)
Report an error message using Foam::FatalIOError.
Definition: error.H:330
Foam::List::size
void size(const label)
Override size to be inconsistent with allocated storage.
Foam::Ostream
An Ostream is an abstract base class for all output systems (streams, files, token lists,...
Definition: Ostream.H:53
Foam::GeometricField::null
static const GeometricField< Type, PatchField, GeoMesh > & null()
Return a null geometric field.
Definition: GeometricFieldI.H:30
Foam::Pstream::listCombineScatter
static void listCombineScatter(const List< commsStruct > &comms, List< T > &Value, const int tag, const label comm)
Scatter data. Reverse of combineGather.
Definition: combineGatherScatter.C:417
Foam::forces::initialise
void initialise()
Initialise the fields.
Definition: forces.C:164
Foam::polyBoundaryMesh::patchSet
labelHashSet patchSet(const UList< wordRe > &patchNames, const bool warnNotFound=true, const bool usePatchGroups=true) const
Return the set of patch IDs corresponding to the given names.
Definition: polyBoundaryMesh.C:750
Foam::type
fileName::Type type(const fileName &)
Return the file type: DIRECTORY or FILE.
Definition: POSIX.C:588
Foam::dictionary::subDict
const dictionary & subDict(const word &) const
Find and return a sub-dictionary.
Definition: dictionary.C:631
Foam::GeometricField
Generic GeometricField class.
Definition: surfaceFieldsFwd.H:52
turb
compressible::turbulenceModel & turb
Definition: setRegionFluidFields.H:10
Foam::forces::devRhoReff
tmp< volSymmTensorField > devRhoReff() const
Return the effective viscous stress (laminar + turbulent).
Definition: forces.C:320
Foam::defineTypeNameAndDebug
defineTypeNameAndDebug(combustionModel, 0)
Foam::min
dimensioned< Type > min(const dimensioned< Type > &, const dimensioned< Type > &)
WarningInFunction
#define WarningInFunction
Report a warning using Foam::Warning.
Definition: messageStream.H:259
Foam::twoSymm
dimensionedSymmTensor twoSymm(const dimensionedSymmTensor &dt)
Definition: dimensionedSymmTensor.C:93
Foam::forces::rho
tmp< volScalarField > rho() const
Return rho if rhoName is specified otherwise rhoRef.
Definition: forces.C:421
Foam::GeometricField::GeometricBoundaryField
Definition: GeometricField.H:105
write
Tcoeff write()
Foam::name
word name(const complex &)
Return a string representation of a complex.
Definition: complex.C:47
Foam::forces::forces
forces(const forces &)
Disallow default bitwise copy construct.
turbulentFluidThermoModel.H
Foam::coordinateSystem
Base class for other coordinate system specifications.
Definition: coordinateSystem.H:85
Foam::dev
dimensionedSymmTensor dev(const dimensionedSymmTensor &dt)
Definition: dimensionedSymmTensor.C:104