AMIMethod.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) 2013-2014 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 
26 #include "AMIMethod.H"
27 #include "meshTools.H"
28 #include "mapDistribute.H"
29 #include "unitConversion.H"
30 
31 // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
32 
33 template<class SourcePatch, class TargetPatch>
35 {
36  if (debug && (!srcPatch_.size() || !tgtPatch_.size()))
37  {
38  Pout<< "AMI: Patches not on processor: Source faces = "
39  << srcPatch_.size() << ", target faces = " << tgtPatch_.size()
40  << endl;
41  }
42 
43 
44  if (conformal())
45  {
46  const scalar maxBoundsError = 0.05;
47 
48  // check bounds of source and target
49  boundBox bbSrc(srcPatch_.points(), srcPatch_.meshPoints(), true);
50  boundBox bbTgt(tgtPatch_.points(), tgtPatch_.meshPoints(), true);
51 
52  boundBox bbTgtInf(bbTgt);
53  bbTgtInf.inflate(maxBoundsError);
54 
55  if (!bbTgtInf.contains(bbSrc))
56  {
57  WarningIn("AMIMethod<SourcePatch, TargetPatch>::checkPatches()")
58  << "Source and target patch bounding boxes are not similar"
59  << nl
60  << " source box span : " << bbSrc.span() << nl
61  << " target box span : " << bbTgt.span() << nl
62  << " source box : " << bbSrc << nl
63  << " target box : " << bbTgt << nl
64  << " inflated target box : " << bbTgtInf << endl;
65  }
66  }
67 }
68 
69 
70 template<class SourcePatch, class TargetPatch>
72 (
73  labelListList& srcAddress,
74  scalarListList& srcWeights,
75  labelListList& tgtAddress,
76  scalarListList& tgtWeights,
77  label& srcFaceI,
78  label& tgtFaceI
79 )
80 {
81  checkPatches();
82 
83  // set initial sizes for weights and addressing - must be done even if
84  // returns false below
85  srcAddress.setSize(srcPatch_.size());
86  srcWeights.setSize(srcPatch_.size());
87  tgtAddress.setSize(tgtPatch_.size());
88  tgtWeights.setSize(tgtPatch_.size());
89 
90  // check that patch sizes are valid
91  if (!srcPatch_.size())
92  {
93  return false;
94  }
95  else if (!tgtPatch_.size())
96  {
97  WarningIn
98  (
99  "void Foam::AMIMethod<SourcePatch, TargetPatch>::initialise"
100  "("
101  "labelListList&, "
102  "scalarListList&, "
103  "labelListList&, "
104  "scalarListList&, "
105  "label&, "
106  "label&"
107  ")"
108  )
109  << srcPatch_.size() << " source faces but no target faces" << endl;
110 
111  return false;
112  }
113 
114  // reset the octree
115  resetTree();
116 
117  // find initial face match using brute force/octree search
118  if ((srcFaceI == -1) || (tgtFaceI == -1))
119  {
120  srcFaceI = 0;
121  tgtFaceI = 0;
122  bool foundFace = false;
123  forAll(srcPatch_, faceI)
124  {
125  tgtFaceI = findTargetFace(faceI);
126  if (tgtFaceI >= 0)
127  {
128  srcFaceI = faceI;
129  foundFace = true;
130  break;
131  }
132  }
133 
134  if (!foundFace)
135  {
136  if (requireMatch_)
137  {
139  (
140  "void Foam::AMIMethod<SourcePatch, TargetPatch>::initialise"
141  "("
142  "labelListList&, "
143  "scalarListList&, "
144  "labelListList&, "
145  "scalarListList&, "
146  "label&, "
147  "label&"
148  ")"
149  ) << "Unable to find initial target face"
150  << abort(FatalError);
151  }
152 
153  return false;
154  }
155  }
156 
157  if (debug)
158  {
159  Pout<< "AMI: initial target face = " << tgtFaceI << endl;
160  }
161 
162  return true;
163 }
164 
165 
166 template<class SourcePatch, class TargetPatch>
168 (
169  const scalar area,
170  const face& f1,
171  const face& f2,
172  const pointField& f1Points,
173  const pointField& f2Points
174 ) const
175 {
176  static label count = 1;
177 
178  const pointField f1pts = f1.points(f1Points);
179  const pointField f2pts = f2.points(f2Points);
180 
181  Pout<< "Face intersection area (" << count << "):" << nl
182  << " f1 face = " << f1 << nl
183  << " f1 pts = " << f1pts << nl
184  << " f2 face = " << f2 << nl
185  << " f2 pts = " << f2pts << nl
186  << " area = " << area
187  << endl;
188 
189  OFstream os("areas" + name(count) + ".obj");
190 
191  forAll(f1pts, i)
192  {
193  meshTools::writeOBJ(os, f1pts[i]);
194  }
195  os<< "l";
196  forAll(f1pts, i)
197  {
198  os<< " " << i + 1;
199  }
200  os<< " 1" << endl;
201 
202 
203  forAll(f2pts, i)
204  {
205  meshTools::writeOBJ(os, f2pts[i]);
206  }
207  os<< "l";
208  forAll(f2pts, i)
209  {
210  os<< " " << f1pts.size() + i + 1;
211  }
212  os<< " " << f1pts.size() + 1 << endl;
213 
214  count++;
215 }
216 
217 
218 template<class SourcePatch, class TargetPatch>
220 {
221  // Clear the old octree
222  treePtr_.clear();
223 
224  treeBoundBox bb(tgtPatch_.points());
225  bb.inflate(0.01);
226 
227  if (!treePtr_.valid())
228  {
229  treePtr_.reset
230  (
232  (
233  treeType
234  (
235  false,
236  tgtPatch_,
238  ),
239  bb, // overall search domain
240  8, // maxLevel
241  10, // leaf size
242  3.0 // duplicity
243  )
244  );
245  }
246 }
247 
248 
249 template<class SourcePatch, class TargetPatch>
251 (
252  const label srcFaceI
253 ) const
254 {
255  label targetFaceI = -1;
256 
257  const pointField& srcPts = srcPatch_.points();
258  const face& srcFace = srcPatch_[srcFaceI];
259  const point srcPt = srcFace.centre(srcPts);
260  const scalar srcFaceArea = srcMagSf_[srcFaceI];
261 
262  pointIndexHit sample = treePtr_->findNearest(srcPt, 10.0*srcFaceArea);
263 
264  if (sample.hit())
265  {
266  targetFaceI = sample.index();
267 
268  if (debug)
269  {
270  Pout<< "Source point = " << srcPt << ", Sample point = "
271  << sample.hitPoint() << ", Sample index = " << sample.index()
272  << endl;
273  }
274  }
275 
276  return targetFaceI;
277 }
278 
279 
280 template<class SourcePatch, class TargetPatch>
282 (
283  const label faceI,
284  const TargetPatch& patch,
285  const DynamicList<label>& visitedFaces,
286  DynamicList<label>& faceIDs
287 ) const
288 {
289  const labelList& nbrFaces = patch.faceFaces()[faceI];
290 
291  // filter out faces already visited from face neighbours
292  forAll(nbrFaces, i)
293  {
294  label nbrFaceI = nbrFaces[i];
295  bool valid = true;
296  forAll(visitedFaces, j)
297  {
298  if (nbrFaceI == visitedFaces[j])
299  {
300  valid = false;
301  break;
302  }
303  }
304 
305  if (valid)
306  {
307  forAll(faceIDs, j)
308  {
309  if (nbrFaceI == faceIDs[j])
310  {
311  valid = false;
312  break;
313  }
314  }
315  }
316 
317  // prevent addition of face if it is not on the same plane-ish
318  if (valid)
319  {
320  const vector& n1 = patch.faceNormals()[faceI];
321  const vector& n2 = patch.faceNormals()[nbrFaceI];
322 
323  scalar cosI = n1 & n2;
324 
325  if (cosI > Foam::cos(degToRad(89.0)))
326  {
327  faceIDs.append(nbrFaceI);
328  }
329  }
330  }
331 }
332 
333 
334 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
335 
336 template<class SourcePatch, class TargetPatch>
338 (
339  const SourcePatch& srcPatch,
340  const TargetPatch& tgtPatch,
341  const scalarField& srcMagSf,
342  const scalarField& tgtMagSf,
344  const bool reverseTarget,
345  const bool requireMatch
346 )
347 :
348  srcPatch_(srcPatch),
349  tgtPatch_(tgtPatch),
350  reverseTarget_(reverseTarget),
351  requireMatch_(requireMatch),
352  srcMagSf_(srcMagSf),
353  tgtMagSf_(tgtMagSf),
354  srcNonOverlap_(),
355  triMode_(triMode)
356 {}
357 
358 
359 // * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * //
360 
361 template<class SourcePatch, class TargetPatch>
363 {}
364 
365 
366 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
367 
368 template<class SourcePatch, class TargetPatch>
370 {
371  return true;
372 }
373 
374 
375 // ************************************************************************* //
Output to file stream.
Definition: OFstream.H:81
This class describes the interaction of (usually) a face and a point. It carries the info of a succes...
Definition: PointIndexHit.H:53
void appendNbrFaces(const label faceI, const TargetPatch &patch, const DynamicList< label > &visitedFaces, DynamicList< label > &faceIDs) const
Add faces neighbouring faceI to the ID list.
Definition: AMIMethod.C:282
word name(const complex &)
Return a string representation of a complex.
Definition: complex.C:47
Base class for Arbitrary Mesh Interface (AMI) methods.
Definition: AMIMethod.H:55
label findTargetFace(const label srcFaceI) const
Find face on target patch that overlaps source face.
Definition: AMIMethod.C:251
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
Standard boundBox + extra functionality for use in octree.
Definition: treeBoundBox.H:75
void size(const label)
Override size to be inconsistent with allocated storage.
Definition: ListI.H:76
DynamicList< T, SizeInc, SizeMult, SizeDiv > & append(const T &)
Append an element at the end of the list.
Definition: DynamicListI.H:310
bool hit() const
Is there a hit.
label index() const
Return index.
point centre(const pointField &) const
Centre point of face.
Definition: face.C:493
const Point & hitPoint() const
Return hit point.
A face is a list of labels corresponding to mesh vertices.
Definition: face.H:75
bool initialise(labelListList &srcAddress, scalarListList &srcWeights, labelListList &tgtAddress, scalarListList &tgtWeights, label &srcFaceI, label &tgtFaceI)
Initialise and return true if all ok.
Definition: AMIMethod.C:72
static const char nl
Definition: Ostream.H:260
void setSize(const label)
Reset size of List.
Definition: List.C:318
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:251
#define WarningIn(functionName)
Report a warning using Foam::Warning.
#define forAll(list, i)
Definition: UList.H:421
dimensionedScalar cos(const dimensionedScalar &ds)
void checkPatches() const
Check AMI patch coupling.
Definition: AMIMethod.C:34
Unit conversion functions.
Encapsulation of data needed to search on PrimitivePatches.
errorManip< error > abort(error &err)
Definition: errorManip.H:131
virtual ~AMIMethod()
Destructor.
Definition: AMIMethod.C:362
void writeIntersectionOBJ(const scalar area, const face &f1, const face &f2, const pointField &f1Points, const pointField &f2Points) const
Write triangle intersection to OBJ file.
Definition: AMIMethod.C:168
#define FatalErrorIn(functionName)
Report an error message using Foam::FatalError.
Definition: error.H:314
A bounding box defined in terms of the points at its extremities.
Definition: boundBox.H:55
Non-pointer based hierarchical recursive searching.
Definition: treeDataEdge.H:47
virtual bool conformal() const
Flag to indicate that interpolation patches are conformal.
Definition: AMIMethod.C:369
void resetTree()
Reset the octree for the target patch face search.
Definition: AMIMethod.C:219
error FatalError
pointField points(const pointField &) const
Return the points corresponding to this face.
Definition: faceI.H:80
scalar degToRad(const scalar deg)
Conversion from degrees to radians.
void inflate(const scalar s)
Inflate box by factor*mag(span) in all dimensions.
Definition: boundBox.C:210
void writeOBJ(Ostream &os, const point &pt)
Write obj representation of point.
Definition: meshTools.C:209
prefixOSstream Pout(cout,"Pout")
Definition: IOstreams.H:53