Loading...
Searching...
No Matches
surfaceFieldValueTemplates.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) 2011-2017 OpenFOAM Foundation
9 Copyright (C) 2015-2023 OpenCFD Ltd.
10-------------------------------------------------------------------------------
11License
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 "surfaceFieldValue.H"
30#include "surfaceFields.H"
31#include "polySurfaceFields.H"
32#include "volFields.H"
33#include "sampledSurface.H"
34#include "surfaceWriter.H"
35#include "interpolationCell.H"
37
38// * * * * * * * * * * * * * Static Member Functions * * * * * * * * * * * * //
39
40template<class WeightType>
42Foam::functionObjects::fieldValues::surfaceFieldValue::weightingFactor
43(
44 const Field<WeightType>& weightField,
45 const bool useMag /* ignore */
46)
47{
48 // The scalar form is specialized.
49 // Other types: use mag() to generate a scalar field.
50 return mag(weightField);
51}
52
53
54// * * * * * * * * * * * * Protected Member Functions * * * * * * * * * * * //
55
56template<class WeightType>
57inline bool Foam::functionObjects::fieldValues::surfaceFieldValue::canWeight
58(
59 const Field<WeightType>& fld
60) const
61{
62 // Non-empty on some processor
63 return returnReduceOr(!fld.empty());
64}
65
66
67template<class Type>
68bool Foam::functionObjects::fieldValues::surfaceFieldValue::validField
69(
70 const word& fieldName
71) const
72{
73 typedef GeometricField<Type, fvsPatchField, surfaceMesh> sf;
74 typedef GeometricField<Type, fvPatchField, volMesh> vf;
75 typedef DimensionedField<Type, polySurfaceGeoMesh> smt;
76
77 return
78 (
79 foundObject<smt>(fieldName)
80 || foundObject<vf>(fieldName)
81 || (withSurfaceFields() && foundObject<sf>(fieldName))
82 );
83}
84
85
86template<class Type>
88Foam::functionObjects::fieldValues::surfaceFieldValue::getFieldValues
89(
90 const word& fieldName,
91 const bool mandatory
92) const
93{
94 typedef GeometricField<Type, fvsPatchField, surfaceMesh> sf;
95 typedef GeometricField<Type, fvPatchField, volMesh> vf;
96 typedef DimensionedField<Type, polySurfaceGeoMesh> smt;
97
98 if (foundObject<smt>(fieldName))
99 {
100 return lookupObject<smt>(fieldName);
101 }
102 else if (withSurfaceFields() && foundObject<sf>(fieldName))
103 {
104 return filterField(lookupObject<sf>(fieldName));
105 }
106 else if (foundObject<vf>(fieldName))
107 {
108 const vf& fld = lookupObject<vf>(fieldName);
109
110 if (sampledPtr_)
111 {
112 // Could be runtime selectable
113 // auto sampler = interpolation<Type>::New(sampleFaceScheme_, fld);
114
115 // const interpolationCellPoint<Type> interp(fld);
116 const interpolationCell<Type> interp(fld);
117
118 return sampledPtr_->sample(interp);
119 }
120 else
121 {
122 return filterField(fld);
123 }
124 }
125
126 if (mandatory)
127 {
129 << "Field " << fieldName << " not found in database" << nl
130 << abort(FatalError);
131 }
132
133 return tmp<Field<Type>>::New();
134}
135
136
137template<class Type, class WeightType>
138Type Foam::functionObjects::fieldValues::surfaceFieldValue::
139processSameTypeValues
140(
141 const Field<Type>& values,
142 const vectorField& Sf,
143 const Field<WeightType>& weightField
144) const
145{
146 Type result = Zero;
147 switch (operation_)
148 {
149 case opNone:
150 case typeScalar:
151 case typeWeighted:
152 case typeAbsolute:
153 {
154 break;
155 }
156 case opMin:
157 {
158 result = gMin(values);
159 break;
160 }
161 case opMax:
162 {
163 result = gMax(values);
164 break;
165 }
166 case opSumMag:
167 {
168 result = gSum(cmptMag(values));
169 break;
170 }
171 case opSum:
172 case opWeightedSum:
173 case opAbsWeightedSum:
174 {
175 if (is_weightedOp() && canWeight(weightField))
176 {
177 tmp<scalarField> weight
178 (
179 weightingFactor(weightField, Sf, is_magOp())
180 );
181
182 result = gSum(weight*values);
183 }
184 else
185 {
186 // Unweighted form
187 result = gSum(values);
188 }
189 break;
190 }
191 case opSumDirection:
192 case opSumDirectionBalance:
193 {
195 << "Operation " << operationTypeNames_[operation_]
196 << " not available for values of type "
197 << pTraits<Type>::typeName
198 << exit(FatalError);
199
200 break;
201 }
202 case opAverage:
203 case opWeightedAverage:
204 case opAbsWeightedAverage:
205 {
206 if (is_weightedOp() && canWeight(weightField))
207 {
208 const scalarField factor
209 (
210 weightingFactor(weightField, Sf, is_magOp())
211 );
212
213 result = gSum(factor*values)/(gSum(factor) + ROOTVSMALL);
214 }
215 else
216 {
217 // Unweighted form
218 const label n = returnReduce(values.size(), sumOp<label>());
219
220 result = gSum(values)/(scalar(n) + ROOTVSMALL);
221 }
222 break;
223 }
224 case opAreaAverage:
225 case opWeightedAreaAverage:
226 case opAbsWeightedAreaAverage:
227 {
228 if (is_weightedOp() && canWeight(weightField))
229 {
230 const scalarField factor
231 (
232 areaWeightingFactor(weightField, Sf, is_magOp())
233 );
234
235 result = gSum(factor*values)/gSum(factor + ROOTVSMALL);
236 }
237 else
238 {
239 // Unweighted form
240 const scalarField factor(mag(Sf));
241
242 result = gSum(factor*values)/gSum(factor + ROOTVSMALL);
243 }
244 break;
245 }
246 case opAreaIntegrate:
247 case opWeightedAreaIntegrate:
248 case opAbsWeightedAreaIntegrate:
249 {
250 if (is_weightedOp() && canWeight(weightField))
251 {
252 tmp<scalarField> factor
253 (
254 areaWeightingFactor(weightField, Sf, is_magOp())
255 );
256
257 result = gSum(factor*values);
258 }
259 else
260 {
261 // Unweighted form
262 tmp<scalarField> factor(mag(Sf));
263
264 result = gSum(factor*values);
265 }
266 break;
267 }
268 case opCoV:
269 {
270 const scalarField magSf(mag(Sf));
271 const scalar gSumMagSf = gSum(magSf);
272
273 Type meanValue = gSum(values*magSf)/gSumMagSf;
274
275 for (direction d=0; d < pTraits<Type>::nComponents; ++d)
276 {
277 tmp<scalarField> vals(values.component(d));
278 const scalar mean = component(meanValue, d);
279 scalar& res = setComponent(result, d);
280
281 res =
282 sqrt(gSum(magSf*sqr(vals - mean))/gSumMagSf)
283 /(mean + ROOTVSMALL);
284 }
285
286 break;
287 }
288
289 case opAreaNormalAverage:
290 case opAreaNormalIntegrate:
291 case opUniformity:
292 {
293 // Handled in specializations only
294 break;
295 }
296
297 case opWeightedUniformity:
298 case opAbsWeightedUniformity:
299 {
300 if (is_weightedOp() && canWeight(weightField))
301 {
302 // Change weighting from vector -> scalar and dispatch again
303 return processValues<Type, scalar>
304 (
305 values,
306 Sf,
307 weightingFactor(weightField, is_magOp())
308 );
309 }
310
311 break;
312 }
313 }
314
315 return result;
316}
317
318
319template<class Type, class WeightType>
320Type Foam::functionObjects::fieldValues::surfaceFieldValue::processValues
321(
322 const Field<Type>& values,
323 const vectorField& Sf,
324 const Field<WeightType>& weightField
325) const
326{
327 return processSameTypeValues(values, Sf, weightField);
328}
329
330
331template<class WeightType>
332Foam::label Foam::functionObjects::fieldValues::surfaceFieldValue::writeAll
333(
334 const vectorField& Sf,
335 const Field<WeightType>& weightField,
336 const pointField& points,
337 const faceList& faces
338)
339{
340 label nProcessed = 0;
341
342 // If using the surface writer, the points/faces parameters have already
343 // been merged on the master and the writeValues routine will also gather
344 // all data onto the master before calling the writer.
345 // Thus only call the writer on master!
346
347 // Begin writer time step
348 if (Pstream::master() && surfaceWriterPtr_ && surfaceWriterPtr_->enabled())
349 {
350 auto& writer = *surfaceWriterPtr_;
351
352 writer.open
353 (
354 points,
355 faces,
356 (
357 outputDir()
358 / regionTypeNames_[regionType_] + ("_" + regionName_)
359 ),
360 false // serial - already merged
361 );
362
363 writer.beginTime(time_);
364 }
365
366 for (const word& fieldName : fields_)
367 {
368 if
369 (
370 writeValues<scalar>(fieldName, Sf, weightField, points, faces)
371 || writeValues<vector>(fieldName, Sf, weightField, points, faces)
372 || writeValues<sphericalTensor>
373 (
374 fieldName, Sf, weightField, points, faces
375 )
376 || writeValues<symmTensor>(fieldName, Sf, weightField, points, faces)
377 || writeValues<tensor>(fieldName, Sf, weightField, points, faces)
378 )
379 {
380 ++nProcessed;
381 }
382 else
383 {
385 << "Requested field " << fieldName
386 << " not found in database and not processed"
387 << endl;
388 }
389 }
390
391 // Finish writer time step
392 if (Pstream::master() && surfaceWriterPtr_ && surfaceWriterPtr_->enabled())
393 {
394 auto& writer = *surfaceWriterPtr_;
395
396 // Write geometry if no fields were written so that we still
397 // can have something to look at.
398
399 if (!writer.wroteData())
400 {
401 writer.write();
402 }
403
404 writer.endTime();
405 writer.clear();
406 }
407
408 return nProcessed;
409}
410
411
412template<class Type, class WeightType>
413bool Foam::functionObjects::fieldValues::surfaceFieldValue::writeValues
414(
415 const word& fieldName,
416 const vectorField& Sf,
417 const Field<WeightType>& weightField,
418 const pointField& points,
419 const faceList& faces
420)
421{
422 const bool ok = validField<Type>(fieldName);
423
424 if (ok)
425 {
426 Field<Type> values(getFieldValues<Type>(fieldName, true));
427
428 // Write raw values on surface if specified
429 if (surfaceWriterPtr_ && surfaceWriterPtr_->enabled())
430 {
431 Field<Type> allValues(values);
432 combineFields(allValues);
433
434 if (Pstream::master())
435 {
436 fileName outputName =
437 surfaceWriterPtr_->write(fieldName, allValues);
438
439 // Case-local file name with "<case>" to make relocatable
441 propsDict.add("file", time_.relativePath(outputName, true));
442 this->setProperty(fieldName, propsDict);
443 }
444 }
445
446 if (operation_ != opNone)
447 {
448 // Apply scale factor
449 values *= scaleFactor_;
450
451 Type result = processValues(values, Sf, weightField);
452
453 switch (postOperation_)
454 {
455 case postOpSqrt:
456 {
457 // sqrt: component-wise - does not change the type
458 for (direction d=0; d < pTraits<Type>::nComponents; ++d)
459 {
460 setComponent(result, d)
461 = sqrt(mag(component(result, d)));
462 }
463 break;
464 }
465 default:
466 {
467 break;
468 }
469 }
470
471 // Write state/results information
472 word prefix, suffix;
473 {
474 if (postOperation_ != postOpNone)
475 {
476 // Adjust result name to include post-operation
477 prefix += postOperationTypeNames_[postOperation_];
478 prefix += '(';
479 suffix += ')';
480 }
481
482 prefix += operationTypeNames_[operation_];
483 prefix += '(';
484 suffix += ')';
485 }
486
487 word resultName = prefix + regionName_ + ',' + fieldName + suffix;
488
489 // Write state/results information
490
491 Log << " " << prefix << regionName_ << suffix
492 << " of " << fieldName << " = ";
493
494
495 // Operation or post-operation returns scalar?
496
497 scalar sresult{0};
498
499 bool alwaysScalar(operation_ & typeScalar);
500
501 if (alwaysScalar)
502 {
503 sresult = component(result, 0);
504
505 if (postOperation_ == postOpMag)
506 {
507 sresult = mag(sresult);
508 }
509 }
510 else if (postOperation_ == postOpMag)
511 {
512 sresult = mag(result);
513 alwaysScalar = true;
514 }
515
516
517 if (alwaysScalar)
518 {
519 file()<< tab << sresult;
520
521 Log << sresult << endl;
522
523 this->setResult(resultName, sresult);
524 }
525 else
526 {
527 file()<< tab << result;
528
529 Log << result << endl;
530
531 this->setResult(resultName, result);
532 }
533 }
534 }
535
536 return ok;
537}
538
539
540template<class Type>
542Foam::functionObjects::fieldValues::surfaceFieldValue::filterField
543(
544 const GeometricField<Type, fvPatchField, volMesh>& field
545) const
546{
547 const labelList& own = field.mesh().faceOwner();
548 const labelList& nei = field.mesh().faceNeighbour();
549
550 auto tvalues = tmp<Field<Type>>::New(faceId_.size());
551 auto& values = tvalues.ref();
552
553 forAll(values, i)
554 {
555 const label facei = faceId_[i];
556 const label patchi = facePatchId_[i];
557
558 if (patchi >= 0)
559 {
560 // Boundary face - face id is the patch-local face id
561 values[i] = field.boundaryField()[patchi][facei];
562 }
563 else
564 {
565 // Internal face
566 values[i] = 0.5*(field[own[facei]] + field[nei[facei]]);
567 }
568 }
569
570 // No need to flip values - all boundary faces point outwards
571
572 return tvalues;
573}
574
575
576template<class Type>
578Foam::functionObjects::fieldValues::surfaceFieldValue::filterField
579(
580 const GeometricField<Type, fvsPatchField, surfaceMesh>& field
581) const
582{
583 auto tvalues = tmp<Field<Type>>::New(faceId_.size());
584 auto& values = tvalues.ref();
585
586 forAll(values, i)
587 {
588 const label facei = faceId_[i];
589 const label patchi = facePatchId_[i];
590
591 if (patchi >= 0)
592 {
593 values[i] = field.boundaryField()[patchi][facei];
594 }
595 else
596 {
597 values[i] = field[facei];
598 }
599 }
600
601 if (debug)
602 {
603 Pout<< "field " << field.name() << " oriented: "
604 << field.is_oriented() << endl;
605 }
606
607 if (field.is_oriented())
608 {
609 forAll(values, i)
610 {
611 if (faceFlip_[i])
612 {
613 values[i] *= -1;
614 }
615 }
616 }
617
618 return tvalues;
619}
620
621
622// ************************************************************************* //
#define Log
Definition PDRblock.C:28
label n
IOdictionary propsDict(dictIO)
Info<< nl;Info<< "Write faMesh in vtk format:"<< nl;{ vtk::uindirectPatchWriter writer(aMesh.patch(), fileName(aMesh.time().globalPath()/vtkBaseFileName));writer.writeGeometry();globalIndex procAddr(aMesh.nFaces());labelList cellIDs;if(UPstream::master()) { cellIDs.resize(procAddr.totalSize());for(const labelRange &range :procAddr.ranges()) { auto slice=cellIDs.slice(range);slice=identity(range);} } writer.beginCellData(4);writer.writeProcIDs();writer.write("cellID", cellIDs);writer.write("area", aMesh.S().field());writer.write("normal", aMesh.faceAreaNormals());writer.beginPointData(1);writer.write("normal", aMesh.pointAreaNormals());Info<< " "<< writer.output().name()<< nl;}{ vtk::lineWriter writer(aMesh.points(), aMesh.edges(), fileName(aMesh.time().globalPath()/(vtkBaseFileName+"-edges")));writer.writeGeometry();writer.beginCellData(4);writer.writeProcIDs();{ Field< scalar > fld(faMeshTools::flattenEdgeField(aMesh.magLe(), true))
vtk::lineWriter writer(edgeCentres, edgeList::null(), fileName(aMesh.time().globalPath()/(vtkBaseFileName+"-edgesCentres")))
A class for managing temporary objects.
Definition tmp.H:75
rDeltaTY field()
#define FatalErrorInFunction
Report an error message using Foam::FatalError.
Definition error.H:600
word outputName("finiteArea-edges.obj")
const pointField & points
return returnReduce(nRefine-oldNRefine, sumOp< label >())
#define WarningInFunction
Report a warning using Foam::Warning.
List< T > values(const HashTable< T, Key, Hash > &tbl, const bool doSort=false)
List of values from HashTable, optionally sorted.
Definition HashOps.H:164
bool returnReduceOr(const bool value, const int communicator=UPstream::worldComm)
Perform logical (or) MPI Allreduce on a copy. Uses UPstream::reduceOr.
Type gSum(const FieldField< Field, Type > &f)
List< label > labelList
A List of labels.
Definition List.H:62
dimensionedSymmTensor sqr(const dimensionedVector &dv)
void component(FieldField< Field, typename FieldField< Field, Type >::cmptType > &sf, const FieldField< Field, Type > &f, const direction d)
label & setComponent(label &val, const direction) noexcept
Non-const access to integer-type (has no components).
Definition label.H:160
Field< scalar > scalarField
Specialisation of Field<T> for scalar.
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition Ostream.H:519
dimensionedScalar sqrt(const dimensionedScalar &ds)
dimensioned< typename typeOfMag< Type >::type > mag(const dimensioned< Type > &dt)
errorManip< error > abort(error &err)
Definition errorManip.H:139
Type gMin(const FieldField< Field, Type > &f)
void cmptMag(FieldField< Field, Type > &cf, const FieldField< Field, Type > &f)
prefixOSstream Pout
OSstream wrapped stdout (std::cout) with parallel prefix.
errorManipArg< error, int > exit(error &err, const int errNo=1)
Definition errorManip.H:125
Type gMax(const FieldField< Field, Type > &f)
constexpr char nl
The newline '\n' character (0x0a).
Definition Ostream.H:50
constexpr char tab
The tab '\t' character(0x09).
Definition Ostream.H:49
Fields (face and point) for polySurface.
#define forAll(list, i)
Loop across all elements in list.
Definition stdFoam.H:299
Foam::surfaceFields.