triSurfaceLoader.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) 2017-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 "triSurfaceLoader.H"
29 #include "fileNameList.H"
30 #include "Time.H"
31 #include "OSspecific.H"
32 
33 // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
34 
35 const Foam::Enum
36 <
38 >
40 ({
41  { loadingOption::SINGLE_REGION, "single" },
42  { loadingOption::FILE_REGION, "file" },
43  { loadingOption::OFFSET_REGION, "offset" },
44  { loadingOption::MERGE_REGION, "merge" },
45 });
46 
47 
48 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
49 
50 Foam::triSurfaceLoader::triSurfaceLoader(const fileName& directory)
51 :
52  directory_(directory),
53  available_(),
54  selected_()
55 {
56  readDir();
57 }
58 
59 
60 Foam::triSurfaceLoader::triSurfaceLoader(const Time& runTime)
61 :
62  directory_(runTime.constantPath()/"triSurface"),
63  available_(),
64  selected_()
65 {
66  readDir();
67 }
68 
69 
70 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
71 
73 {
74  fileNameList files = Foam::readDir(directory_, fileName::FILE);
75 
76  // Will be using triSurface
77  //
78  // - filter according to what is supported
79  //
80  // Transform from fileName to word and eliminate duplicates
81  // (eg, files with/without .gz)
82  wordHashSet names(2*files.size());
83 
84  for (const fileName& f : files)
85  {
87  {
88  names.insert(f.name());
89  }
90  }
91  available_ = names.sortedToc();
92 
93  return available_.size();
94 }
95 
96 
98 {
99  selected_ = available_;
100  return selected_.size();
101 }
102 
103 
104 Foam::label Foam::triSurfaceLoader::select(const word& name)
105 {
106  if (available_.found(name))
107  {
108  selected_.resize(1);
109  selected_.first() = name;
110  }
111  else
112  {
113  selected_.clear();
114  }
115 
116  return selected_.size();
117 }
118 
119 
120 Foam::label Foam::triSurfaceLoader::select(const wordRe& mat)
121 {
122  if (mat.isPattern())
123  {
124  labelList foundIds = findStrings(mat, available_);
125  Foam::sort(foundIds);
126  selected_ = wordList(available_, foundIds);
127  }
128  else if (available_.found(static_cast<const word&>(mat)))
129  {
130  selected_.resize(1);
131  selected_.first() = mat;
132  }
133  else
134  {
136  << "Specified the surfaces " << mat << nl
137  << " - but could not find it"
139  }
140 
141  return selected_.size();
142 }
143 
144 
145 Foam::label Foam::triSurfaceLoader::select(const UList<wordRe>& matcher)
146 {
147  // Need to be more careful when select.
148  // - preserve same order as the input matcher itself
149  // - avoid duplicate selections
150  // - flag explicitly named files as missing.
151  // (Eg, foo.stl must exist, but "foo.*\.stl" is optional)
152 
153  // Track which files have already been selected
154  DynamicList<label> foundIds(available_.size());
155  labelHashSet hashedFound(2*available_.size());
156 
157  DynamicList<word> missing(matcher.size());
158  wordHashSet hashedMissing(2*matcher.size());
159 
160  // Exact matches must exist
161  for (const wordRe& mat : matcher)
162  {
163  if (mat.isPattern())
164  {
165  labelList indices = findStrings(mat, available_);
166  Foam::sort(indices);
167 
168  for (const label idx : indices)
169  {
170  if (hashedFound.insert(idx))
171  {
172  foundIds.append(idx);
173  }
174  }
175  }
176  else
177  {
178  const word& plain = mat;
179  const label idx = available_.find(plain);
180 
181  if (idx >= 0)
182  {
183  if (hashedFound.insert(idx))
184  {
185  foundIds.append(idx);
186  }
187  }
188  else if (hashedMissing.insert(plain))
189  {
190  missing.append(plain);
191  }
192  }
193  }
194 
195  if (missing.size())
196  {
198  << "Specified the surfaces " << flatOutput(matcher) << nl
199  << " - but could not find " << flatOutput(missing)
200  << exit(FatalError);
201  }
203  selected_ = wordList(available_, foundIds);
204  return selected_.size();
205 }
206 
207 
209 (
210  const enum loadingOption opt,
211  const scalar scaleFactor
212 ) const
213 {
215 
216  if (selected_.empty())
217  {
218  return output;
219  }
220  else if (selected_.size() == 1)
221  {
222  // Use scaling (if any)
223  output.reset(new triSurface(directory_/selected_[0], scaleFactor));
224 
225  triSurface& surf = output();
226 
227  if
228  (
229  opt == loadingOption::SINGLE_REGION
230  || opt == loadingOption::FILE_REGION
231  )
232  {
233  for (labelledTri& f : surf)
234  {
235  f.region() = 0;
236  }
237 
238  if (surf.patches().size())
239  {
240  surf.patches().resize(1);
241  }
242  else
243  {
244  surf.patches().append
245  (
246  geometricSurfacePatch(selected_[0].lessExt(), 0)
247  );
248  }
249  }
250 
251  return output;
252  }
253 
254 
255  List<labelledTri> faces;
257 
258  Map<label> oldToNew;
259  HashTable<label> patchNameLookup;
260  DynamicList<geometricSurfacePatch> patches(16*selected_.size());
261 
262  forAll(selected_, surfi)
263  {
264  List<labelledTri> addfaces;
265  pointField addpoints;
266 
267  triSurface addsurf(directory_/selected_[surfi]);
268 
269  addsurf.swapFaces(addfaces);
270  addsurf.swapPoints(addpoints);
271 
272  // Offset the points for all additional surfaces
273  if (surfi)
274  {
275  const label ptoff = points.size();
276 
277  for (labelledTri& f : addfaces)
278  {
279  forAll(f, fi)
280  {
281  f[fi] += ptoff;
282  }
283  }
284  }
285 
286  switch (opt)
287  {
288  case loadingOption::SINGLE_REGION:
289  {
290  for (labelledTri& f : addfaces)
291  {
292  f.region() = 0;
293  }
294 
295  if (patches.empty() && !addsurf.patches().empty())
296  {
297  patches.append(addsurf.patches().first());
298  }
299 
300  break;
301  }
302 
303  case loadingOption::FILE_REGION:
304  {
305  for (labelledTri& f : addfaces)
306  {
307  f.region() = surfi;
308  }
309 
310  // Use surface name for region
312  (
313  geometricSurfacePatch(selected_[surfi].lessExt(), surfi)
314  );
315 
316  break;
317  }
318 
319  case loadingOption::OFFSET_REGION:
320  {
321  // Collect all patches, preserving names.
322  // This will be horrible for output, but is good if we rely
323  // on the names for defining baffles.
324 
325  // region offset
326  const label regoff = patches.size();
327  patches.append(addsurf.patches());
328 
329  if (surfi)
330  {
331  for (labelledTri& f : addfaces)
332  {
333  f.region() += regoff;
334  }
335  }
336  break;
337  }
338 
339  case loadingOption::MERGE_REGION:
340  {
341  // Merge by name
342  geometricSurfacePatchList& addpatches = addsurf.patches();
343 
344  // Build lookup tables with name->id and localId -> mergedId
345  oldToNew.clear();
346  forAll(addpatches, patchi)
347  {
348  geometricSurfacePatch& p = addpatches[patchi];
349  const word& patchName = p.name();
350 
351  label patchId = patches.size();
352  if (patchNameLookup.insert(patchName, patchId))
353  {
354  p.index() = patchId;
355  patches.append(p);
356  }
357  else
358  {
359  patchId = patchNameLookup[patchName];
360  }
361 
362  oldToNew.insert(patchi, patchId);
363  }
364 
365  if (surfi)
366  {
367  // Relabel regions accordingly
368  for (labelledTri& f : addfaces)
369  {
370  f.region() = oldToNew[f.region()];
371  }
372  }
373  break;
374  }
375  }
376 
377  if (surfi)
378  {
379  faces.append(addfaces);
380  points.append(addpoints);
381  }
382  else
383  {
384  faces.transfer(addfaces);
385  points.transfer(addpoints);
386  }
387  }
388 
389  // Apply scaling (if any)
390  if (scaleFactor > VSMALL)
391  {
392  points *= scaleFactor;
393  }
394 
395  output.reset(new triSurface(faces, patches, points, true));
396 
397  return output;
398 }
399 
400 
401 // ************************************************************************* //
label patchId(-1)
void size(const label n)
Older name for setAddressableSize.
Definition: UList.H:116
label select(const word &name)
Populates &#39;selected&#39; with a subset of the available files.
List< word > names(const UPtrList< T > &list, const UnaryMatchPredicate &matcher)
List of names generated by calling name() for each list item and filtered for matches.
A class for handling file names.
Definition: fileName.H:72
errorManipArg< error, int > exit(error &err, const int errNo=1)
Definition: errorManip.H:125
void resize(const label len)
Adjust allocated size of list.
Definition: ListI.H:160
void transfer(List< T > &list)
Transfer the contents of the argument List into this list and annul the argument list.
Definition: List.C:326
error FatalError
Error stream (stdout output on all processes), with additional &#39;FOAM FATAL ERROR&#39; header text and sta...
#define FatalErrorInFunction
Report an error message using Foam::FatalError.
Definition: error.H:598
void append(const T &val)
Append an element at the end of the list.
Definition: List.H:517
const word & name() const noexcept
Return the object name.
Definition: IOobjectI.H:195
constexpr char nl
The newline &#39;\n&#39; character (0x0a)
Definition: Ostream.H:50
engineTime & runTime
autoPtr< triSurface > load(const enum loadingOption opt=loadingOption::OFFSET_REGION, const scalar scaleFactor=-1) const
Load a single file, or load and combine multiple selected files.
Class to control time during OpenFOAM simulations that is also the top-level objectRegistry.
Definition: Time.H:69
label readDir()
Read directory and populate the &#39;available&#39; files.
#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
Functions used by OpenFOAM that are specific to POSIX compliant operating systems and need to be repl...
vectorField pointField
pointField is a vectorField.
Definition: pointFieldFwd.H:38
word name(const expressions::valueTypeCode typeCode)
A word representation of a valueTypeCode. Empty for expressions::valueTypeCode::INVALID.
Definition: exprTraits.C:127
const pointField & points
void clear()
Clear the list, i.e. set size to zero.
Definition: ListI.H:137
A class for handling words, derived from Foam::string.
Definition: word.H:63
void sort(UList< T > &list)
Sort the list.
Definition: UList.C:296
A regular file.
Definition: fileName.H:84
label size() const noexcept
The number of entries in the list.
Definition: UPtrListI.H:106
HashSet< word, Hash< word > > wordHashSet
A HashSet of words, uses string hasher.
Definition: HashSet.H:73
List< geometricSurfacePatch > geometricSurfacePatchList
List of geometricSurfacePatch.
labelList f(nPoints)
bool empty() const noexcept
True if the list is empty (ie, size() is zero)
Definition: UPtrListI.H:99
List< word > wordList
List of word.
Definition: fileName.H:59
void append(autoPtr< T > &ptr)
Move append an element to the end of the list.
Definition: PtrList.H:344
Enum is a wrapper around a list of names/values that represent particular enumeration (or int) values...
Definition: error.H:64
const polyBoundaryMesh & patches
loadingOption
The file loading options for triSurfaceLoader.
static Ostream & output(Ostream &os, const IntRange< T > &range)
Definition: IntRanges.C:44
static bool canRead(const fileName &name, bool verbose=false)
Can we read this file format?
Definition: triSurfaceIO.C:92
List< label > labelList
A List of labels.
Definition: List.H:62
volScalarField & p
static const Enum< loadingOption > loadingOptionNames
The loading enumeration names.
fileNameList readDir(const fileName &directory, const fileName::Type type=fileName::Type::FILE, const bool filtergz=true, const bool followLink=true)
Read a directory and return the entries as a fileName List.
Definition: POSIX.C:963
labelList findStrings(const regExp &matcher, const UList< StringType > &input, const bool invert=false)
Return list indices for strings matching the regular expression.
Definition: stringListOps.H:92
label selectAll()
Populates &#39;selected&#39; with all available files.
FlatOutput::OutputAdaptor< Container, Delimiters > flatOutput(const Container &obj, Delimiters delim)
Global flatOutput() function with specified output delimiters.
Definition: FlatOutput.H:225