MappedFileFilterField.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) 2022 OpenCFD Ltd.
9 -------------------------------------------------------------------------------
10 License
11  This file is part of OpenFOAM.
12 
13  OpenFOAM is free software: you can redistribute it and/or modify it
14  under the terms of the GNU General Public License as published by
15  the Free Software Foundation, either version 3 of the License, or
16  (at your option) any later version.
17 
18  OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
19  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
20  FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
21  for more details.
22 
23  You should have received a copy of the GNU General Public License
24  along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
25 
26 \*---------------------------------------------------------------------------*/
27 
28 #include "MappedFileFilterField.H"
29 #include "oneField.H"
30 #include "MeshedSurfaces.H"
31 #include "MinMax.H"
32 #include "indexedOctree.H"
33 #include "treeDataPoint.H"
34 
35 // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
36 
37 namespace Foam
38 {
39 namespace PatchFunction1Types
40 {
41  defineTypeNameAndDebug(FilterField, 0);
42 }
43 }
44 
45 
46 const Foam::Enum
47 <
49 >
50 Foam::PatchFunction1Types::FilterField::RBF_typeNames_
51 {
52  { RBF_type::RBF_linear, "linear" },
53  { RBF_type::RBF_quadratic, "quadratic" },
54  { RBF_type::RBF_linear, "default" },
55 };
56 
57 
58 // * * * * * * * * * * * * * * * Local Functions * * * * * * * * * * * * * * //
59 
60 namespace Foam
61 {
62 
63 //- Linear basis function: 1 - (r/r0)
64 static inline scalar linearWeight
65 (
66  const point& p,
67  const point& p0,
68  const scalar radiusSqr
69 )
70 {
71  return (1 - ::sqrt(p.distSqr(p0) / radiusSqr));
72 }
73 
74 
75 //- Quadratic basis function: 1 - (r/r0)^2
76 static inline scalar quadraticWeight
77 (
78  const point& p,
79  const point& p0,
80  const scalar radiusSqr
81 )
82 {
83  return (1 - p.distSqr(p0) / radiusSqr);
84 }
85 
86 
87 //- Construct search tree for points
90 {
91  // Avoid bounding box error in case of 2D cases
92  treeBoundBox bb(points);
93  bb.grow(1e-4);
94 
96 
97  const int oldDebug = indexedOctreeBase::debug;
98 
99  if (debug & 2)
100  {
102  }
103 
105  (
107  bb, // overall search domain
108  points.size(), // maxLevel
109  16, // leafsize
110  1.0 // duplicity
111  );
112 
113  indexedOctreeBase::debug = oldDebug;
114 
115  if (debug & 2)
116  {
117  const auto& tree = treePtr();
118 
119  OFstream os("indexedOctree.obj");
120  tree.writeOBJ(os);
121  Info<< "=================" << endl;
122  Info<< "have " << tree.nodes().size() << " nodes" << nl;
123  Info<< "=================" << endl;
124  }
125 
126  return treePtr;
127 }
128 
129 } // End namespace Foam
130 
131 
132 // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
133 
134 template
135 <
136  class TreeType,
137  class RadiusSqrOp,
138  class BasisFunctionOp,
139  class PointWeightFieldType
140 >
141 void Foam::PatchFunction1Types::FilterField::buildWeightsImpl
142 (
143  const TreeType& tree,
144  const RadiusSqrOp& radiusSqrOp,
145  const BasisFunctionOp& basisFuncOp,
146  const PointWeightFieldType& pointWeightFld
147 )
148 {
149  tmp<pointField> tpoints = tree.shapes().centres();
150 
151  const auto& points = tpoints();
152 
153  const label nPoints = points.size();
154 
155  weights_.clear();
156  addressing_.clear();
157 
158  weights_.resize(nPoints);
159  addressing_.resize(nPoints);
160 
161  labelHashSet neighbours(2*128);
162 
163  // Catch degenerate case where weight/addressing not actually needed
164  bool usesNeighbours = false;
165 
166  for (label pointi = 0; pointi < nPoints; ++pointi)
167  {
168  const point& p0 = points[pointi];
169  auto& currAddr = addressing_[pointi];
170  auto& currWeight = weights_[pointi];
171 
172  // Search with local sphere
173  const scalar radiusSqr = radiusSqrOp(pointi);
174 
175  tree.findSphere(p0, radiusSqr, neighbours);
176 
177  // Paranoid, enforce identity weighting as a minimum
178  if (neighbours.size() < 2)
179  {
180  currAddr.resize(1, pointi);
181  currWeight.resize(1, scalar(1));
182  continue;
183  }
184 
185  usesNeighbours = true;
186 
187  currAddr = neighbours.sortedToc();
188  currWeight.resize_nocopy(currAddr.size());
189 
190  scalar sumWeight = 0;
191 
192  forAll(currAddr, i)
193  {
194  const point& p = points[currAddr[i]];
195 
196  currWeight[i] = basisFuncOp(p, p0, radiusSqr);
197 
198  // Eg, face area weighting.
199  // - cast required for oneField()
200  currWeight[i] *= static_cast<scalar>(pointWeightFld[i]);
201  sumWeight += currWeight[i];
202  }
203 
204  for (auto& w : currWeight)
205  {
206  w /= sumWeight;
207  }
208  }
209 
210  if (!usesNeighbours)
211  {
212  // No addressing/weighting required
213  reset();
214  }
215 
216  if (debug && !addressing_.empty())
217  {
218  labelMinMax limits(addressing_[0].size());
219 
220  label total = 0;
221 
222  for (const labelList& addr : addressing_)
223  {
224  const label n = addr.size();
225 
226  limits.add(n);
227  total += n;
228  }
229 
230  Pout<< "Weight neighbours: min=" << limits.min()
231  << " avg=" << (total / addressing_.size())
232  << " max=" << limits.max() << endl;
233  }
234 }
235 
236 
237 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
238 
240 (
241  const pointField& points,
242  const scalar radius,
243  const RBF_type interp
244 )
245 {
246  reset(points, radius, interp);
247 }
248 
249 
251 (
252  const meshedSurface& geom,
253  const scalar radius,
254  const bool relative,
255  const RBF_type interp
256 )
257 {
258  reset(geom, radius, relative, interp);
259 }
260 
261 
262 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
265 {
266  addressing_.clear();
267  weights_.clear();
268 }
269 
270 
272 (
273  const pointField& points,
274  const scalar radius,
275  const RBF_type interp
276 )
277 {
278  scalarField dummyWeights;
279 
280  if (debug)
281  {
282  Pout<< "Apply " << RBF_typeNames_[interp] << " filter,"
283  << " radius=" << radius << nl
284  << "Create tree..." << endl;
285  }
286 
288  = createTree(points);
289 
290  const scalar radiusSqr = sqr(radius);
291 
292  auto weightFunc = linearWeight;
293 
294  if (interp == RBF_type::RBF_quadratic)
295  {
296  weightFunc = quadraticWeight;
297  }
298 
299 
300  // Use (constant) absolute size
301  buildWeightsImpl
302  (
303  treePtr(),
304  [=](label index) -> scalar { return radiusSqr; },
305  weightFunc,
306  oneField()
307  );
308 }
309 
310 
312 (
313  const meshedSurface& geom,
314  const scalar radius,
315  const bool relative,
316  const RBF_type interp
317 )
318 {
319  if (!geom.nFaces())
320  {
321  // Received geometry without any faces eg, boundaryData
322  reset(geom.points(), radius, interp);
323  return;
324  }
325 
326  if (debug)
327  {
328  Pout<< "Apply " << RBF_typeNames_[interp] << " filter,"
329  << (relative ? " relative" : "") << " radius=" << radius << nl
330  << "Create tree..." << endl;
331  }
332 
334  = createTree(geom.faceCentres());
335 
336  const scalar radiusSqr = sqr(radius);
337 
338  auto weightFunc = linearWeight;
339 
340  if (interp == RBF_type::RBF_quadratic)
341  {
342  weightFunc = quadraticWeight;
343  }
344 
345 
346  if (relative)
347  {
348  // Use relative size
349  buildWeightsImpl
350  (
351  treePtr(),
352  [&](label index) -> scalar
353  {
354  return (radiusSqr * geom.sphere(index));
355  },
356  weightFunc,
357  geom.magSf()
358  );
359  }
360  else
361  {
362  // Use (constant) absolute size
363  buildWeightsImpl
364  (
365  treePtr(),
366  [=](label index) -> scalar { return radiusSqr; },
367  weightFunc,
368  geom.magSf()
369  );
370  }
371 }
372 
373 
374 // ************************************************************************* //
void size(const label n)
Older name for setAddressableSize.
Definition: UList.H:116
Holds (reference to) pointField. Encapsulation of data needed for octree searches. Used for searching for nearest point. No bounding boxes around points. Only overlaps and calcNearest are implemented, rest makes little sense.
Definition: treeDataPoint.H:58
void resize(const label len)
Adjust allocated size of list.
Definition: ListI.H:160
dimensionedSymmTensor sqr(const dimensionedVector &dv)
Output to file stream, using an OSstream.
Definition: OFstream.H:49
constexpr char nl
The newline &#39;\n&#39; character (0x0a)
Definition: Ostream.H:50
FilterField() noexcept=default
Default construct.
dimensionedScalar sqrt(const dimensionedScalar &ds)
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:531
tmp< DimensionedField< TypeR, GeoMesh > > New(const tmp< DimensionedField< TypeR, GeoMesh >> &tf1, const word &name, const dimensionSet &dimensions, const bool initCopy=false)
Global function forwards to reuseTmpDimensionedField::New.
defineTypeNameAndDebug(FilterField, 0)
#define forAll(list, i)
Loop across all elements in list.
Definition: stdFoam.H:421
HashSet< label, Hash< label > > labelHashSet
A HashSet of labels, uses label hasher.
Definition: HashSet.H:85
const dimensionedScalar e
Elementary charge.
Definition: createFields.H:11
const pointField & points
static autoPtr< indexedOctree< treeDataPoint > > createTree(const pointField &points)
Construct search tree for points.
void clear()
Clear the list, i.e. set size to zero.
Definition: ListI.H:137
const scalarField & magSf() const
Face area magnitudes.
label nPoints
const Field< point_type > & faceCentres() const
Return face centres for patch.
Tree tree(triangles.begin(), triangles.end())
MinMax< label > labelMinMax
A label min/max range.
Definition: MinMax.H:93
const Field< point_type > & points() const noexcept
Return reference to global points.
void reset()
Reset to unweighted (pass-through)
A Vector of values with scalar precision, where scalar is float/double depending on the compilation f...
int debug
Static debugging option.
OBJstream os(runTime.globalPath()/outputName)
static scalar quadraticWeight(const point &p, const point &p0, const scalar radiusSqr)
Quadratic basis function: 1 - (r/r0)^2.
A class representing the concept of a field of 1 used to avoid unnecessary manipulations for objects ...
Definition: oneField.H:47
vector point
Point is a vector.
Definition: point.H:37
Enum is a wrapper around a list of names/values that represent particular enumeration (or int) values...
Definition: error.H:64
scalar sphere(const label facei) const
The enclosing (bounding) sphere radius^2 for specified face.
Standard boundBox with extra functionality for use in octree.
Definition: treeBoundBox.H:90
messageStream Info
Information stream (stdout output on master, null elsewhere)
label n
Pointer management similar to std::unique_ptr, with some additional methods and type checking...
Definition: HashPtrTable.H:48
List< label > labelList
A List of labels.
Definition: List.H:62
volScalarField & p
static scalar linearWeight(const point &p, const point &p0, const scalar radiusSqr)
Linear basis function: 1 - (r/r0)
label nFaces() const noexcept
Number of faces in the patch.
void grow(const scalar delta)
Expand box by adjusting min/max by specified amount in each dimension.
Definition: boundBoxI.H:367
prefixOSstream Pout
OSstream wrapped stdout (std::cout) with parallel prefix.
const volScalarField & p0
Definition: EEqn.H:36
Namespace for OpenFOAM.
tmp< surfaceScalarField > relative(const tmp< surfaceScalarField > &tphi, const volVectorField &U)
Return the given absolute flux in relative form.
Definition: fvcMeshPhi.C:148