parcelSelectionDetail.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) 2018-2019 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 "cloud.H"
29 #include "parcelSelectionDetail.H"
30 #include "scalarPredicates.H"
31 #include "labelField.H"
32 #include "scalarField.H"
33 #include "pointField.H"
34 #include "ListListOps.H"
35 
36 // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
37 
38 const Foam::Enum
39 <
41 >
43 ({
44  { actionType::ALL, "all" },
45  { actionType::CLEAR, "clear" },
46  { actionType::INVERT, "invert" },
47  { actionType::USE, "use" },
48  { actionType::ADD, "add" },
49  { actionType::SUBTRACT, "subtract" },
50  { actionType::SUBSET, "subset" },
51  { actionType::IGNORE, "ignore" },
52 });
53 
54 
55 const Foam::Enum
56 <
58 >
60 ({
61  { sourceType::FIELD, "field" },
62  { sourceType::STRIDE, "stride" },
63 });
64 
65 
66 const Foam::Enum
67 <
70 ({
71  { logicType::AND, "and" },
72  { logicType::OR, "or" },
73 });
74 
75 
76 // * * * * * * * * * * * * * * * Local Functions * * * * * * * * * * * * * * //
77 
78 namespace Foam
79 {
80  template<class Type, class Predicate, class AccessOp>
81  static void apply
82  (
83  bitSet& selection,
85  const Predicate& accept,
86  const UList<Type>& list,
87  const AccessOp& aop
88  )
89  {
90  using actionType = Detail::parcelSelection::actionType;
91 
92  const label len = selection.size();
93 
94  switch (action)
95  {
96  case actionType::ADD:
97  case actionType::USE:
98  {
99  if (actionType::USE == action)
100  {
101  // USE = CLEAR + ADD (ie, only use this selection)
102  selection = false;
103  }
104 
105  for (label parceli = 0; parceli < len; ++parceli)
106  {
107  if (accept(aop(list[parceli])))
108  {
109  selection.set(parceli);
110  }
111  }
112  }
113  break;
114 
115  case actionType::SUBTRACT:
116  {
117  for (label parceli = 0; parceli < len; ++parceli)
118  {
119  if (accept(aop(list[parceli])))
120  {
121  selection.unset(parceli);
122  }
123  }
124  }
125  break;
126 
127  case actionType::SUBSET:
128  {
129  for (const label parceli : selection)
130  {
131  if (!accept(aop(list[parceli])))
132  {
133  selection.unset(parceli);
134  }
135  }
136  }
137  break;
138 
139  default:
140  break;
141  }
142  }
144 } // End namespace Foam
145 
146 
147 // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
148 
150 (
151  const objectRegistry& obrTmp,
152  const bool log
153 )
154 {
155  if (parcelSelect_.empty())
156  {
157  parcelAddr_.clear();
158  return false;
159  }
160 
161  // Start with all parcels unselected
162 
163  // Number of parcels (locally)
164  const auto* pointsPtr = cloud::findIOPosition(obrTmp);
165  label nParcels = pointsPtr->size();
166 
167  parcelAddr_.reset();
168  parcelAddr_.resize(nParcels);
169 
170  reduce(nParcels, sumOp<label>());
171 
172  Log << "Applying parcel filtering to " << nParcels << " parcels" << nl;
173 
174  if (!nParcels)
175  {
176  parcelAddr_.clear();
177  return false;
178  }
179 
180  // The unary function type(s) for testing a scalar.
181  // Allocate 3 slots.
182  // 0 is the test
183  // 1,2 are for storage of composite tests (eg, and/or logic)
184  predicates::scalars tests(3);
185 
186  for (const entry& dEntry : parcelSelect_)
187  {
188  if (!dEntry.isDict())
189  {
191  << "Ignoring non-dictionary entry "
192  << dEntry << endl;
193  continue;
194  }
195 
196  const dictionary& dict = dEntry.dict();
197 
198  // A very limited number of sources (stride, field)
199  // and actions (all add subtract subset) so handle manually
200 
201  auto action = actionNames.get("action", dict);
202 
203  // These ones we do directly
204  switch (action)
205  {
206  case actionType::ALL:
207  Log << "- select all" << nl;
208  parcelAddr_ = true;
209  continue;
210  break;
211 
212  case actionType::CLEAR:
213  Log << "- clear" << nl;
214  parcelAddr_ = false;
215  continue;
216  break;
217 
218  case actionType::INVERT:
219  Log << "- invert" << nl;
220  parcelAddr_.flip();
221  continue;
222  break;
223 
224  case actionType::IGNORE:
225  continue;
226  break;
227 
228  default:
229  break;
230  }
231 
232  // The others need a source
233  // Need a source
234  const auto source = sourceNames.get("source", dict);
235 
236  switch (source)
237  {
238  case sourceType::STRIDE:
239  {
240  const label stride = dict.get<label>("stride");
241 
242  const labelField& ids =
243  obrTmp.lookupObject<labelField>("origId");
244 
245  Log << "- " << actionNames[action]
246  << " stride " << stride << nl;
247 
248  if (stride <= 0)
249  {
251  << nl
252  << "Ignoring bad value for stride=" << stride << nl
253  << endl;
254  }
255  else if (stride == 1)
256  {
257  // More efficient handling of stride 1, but should
258  // not really be using stride == 1.
259  switch (action)
260  {
261  case actionType::ADD:
262  parcelAddr_ = true;
263  break;
264 
265  case actionType::SUBTRACT:
266  parcelAddr_ = false;
267  break;
268 
269  default:
270  break;
271  }
272  }
273  else
274  {
275  // Using stride > 1
276  apply
277  (
278  parcelAddr_,
279  action,
280  [=](const label id) -> bool { return !(id % stride); },
281  ids,
282  accessOp<label>() // pass-through
283  );
284  }
285  }
286  break;
287 
288  case sourceType::FIELD:
289  {
290  const word fieldName(dict.get<word>("field"));
291 
292  const auto* labelFld =
293  obrTmp.findObject<labelField>(fieldName);
294 
295  const auto* scalarFld =
296  obrTmp.findObject<scalarField>(fieldName);
297 
298  const auto* vectorFld =
299  obrTmp.findObject<vectorField>(fieldName);
300 
301 
302  Log << "- " << actionNames[action] << " field " << fieldName;
303 
304  if (!labelFld && !scalarFld && !vectorFld)
305  {
307  << nl
308  << "No scalar/vector parcel field: " << fieldName
309  << " ignoring selection" << nl
310  << endl;
311  continue;
312  }
313 
314  const entry& e = dict.lookupEntry("accept", keyType::LITERAL);
315 
316  ITstream& is = e.stream();
317 
318  if (4 == is.size())
319  {
320  // 4 tokens:
321  // -> (op val)
322 
323  Tuple2<word,scalar> expr1(is);
324  e.checkITstream(is);
325 
326  tests.first() = predicates::scalars::operation(expr1);
327 
328  Log << " : " << expr1;
329  }
330  else if (9 == is.size())
331  {
332  // 9 tokens:
333  // -> (op val) and (op val)
334  // -> (op val) or (op val)
335 
336  Tuple2<word,scalar> expr1(is);
337  word logicName(is);
338  Tuple2<word,scalar> expr2(is);
339  e.checkITstream(is);
340 
341  logicType logic = logicNames[logicName];
342  tests[1] = predicates::scalars::operation(expr1);
343  tests[2] = predicates::scalars::operation(expr2);
344 
345  switch (logic)
346  {
347  case logicType::AND:
348  tests.first() =
349  predicates::scalars::andOp(tests[1], tests[2]);
350  break;
351 
352  case logicType::OR:
353  tests.first() =
354  predicates::scalars::orOp(tests[1], tests[2]);
355  break;
356  }
357 
358  Log << " : " << expr1 << ' ' << logicName << ' ' << expr2;
359  }
360  else
361  {
362  action = actionType::IGNORE;
363 
364  // Use the following to always provoke an error.
365  e.checkITstream(is);
366  }
367 
368  if (labelFld)
369  {
370  apply
371  (
372  parcelAddr_,
373  action,
374  tests.first(),
375  *labelFld,
376  accessOp<label>() // pass-through
377  );
378  }
379  else if (scalarFld)
380  {
381  apply
382  (
383  parcelAddr_,
384  action,
385  tests.first(),
386  *scalarFld,
387  accessOp<scalar>() // pass-through
388  );
389  }
390  else if (vectorFld)
391  {
392  apply
393  (
394  parcelAddr_,
395  action,
396  tests.first(),
397  *vectorFld,
398  [](const vector& val) -> scalar
399  {
400  return Foam::mag(val);
401  }
402  );
403  }
404 
405  Log << endl;
406  }
407  break;
408 
409  default:
410  break;
411  }
412  }
413 
414  return true;
415 }
416 
417 
418 // ************************************************************************* //
EnumType get(const word &enumName) const
The enumeration corresponding to the given name.
Definition: Enum.C:68
static const IOField< point > * findIOPosition(const objectRegistry &obr)
Locate the "position" IOField within object registry.
Definition: cloud.H:188
dictionary dict
Field< label > labelField
Specialisation of Field<T> for label.
Definition: labelField.H:48
const Type & lookupObject(const word &name, const bool recursive=false) const
Lookup and return const reference to the object of the given Type. Fatal if not found or the wrong ty...
void set(const bitSet &bitset)
Set specified bits from another bitset.
Definition: bitSetI.H:504
dimensionedScalar log(const dimensionedScalar &ds)
dimensioned< typename typeOfMag< Type >::type > mag(const dimensioned< Type > &dt)
constexpr char nl
The newline &#39;\n&#39; character (0x0a)
Definition: Ostream.H:50
void flip()
Invert all bits in the addressable region.
Definition: bitSetI.H:548
static void apply(bitSet &selection, const Detail::parcelSelection::actionType action, const Predicate &accept, const UList< Type > &list, const AccessOp &aop)
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:531
const Type * findObject(const word &name, const bool recursive=false) const
Return const pointer to the object of the given Type.
bitSet parcelAddr_
The filtered parcel addressing. Eg, for the current cloud.
void resize(const label numElem, const unsigned int val=0u)
Reset addressable list size, does not shrink the allocated size.
Definition: PackedListI.H:455
static const Enum< actionType > actionNames
Names for the actionType.
const dimensionedScalar e
Elementary charge.
Definition: createFields.H:11
bitSet & unset(const bitSet &other)
Unset (subtract) the bits specified in the other bitset, which is a set difference corresponds to the...
Definition: bitSetI.H:542
Field< scalar > scalarField
Specialisation of Field<T> for scalar.
sourceType
Enumeration defining the valid sources.
Vector< scalar > vector
Definition: vector.H:57
bool calculateFilter(const objectRegistry &obrTmp, const bool log=true)
Calculate parcel selection filter.
String literal.
Definition: keyType.H:82
actionType
Enumeration defining the valid selection actions.
void clear()
Clear the list, i.e. set addressable size to zero.
Definition: PackedListI.H:558
static unary orOp(const unary &test1, const unary &test2)
Combine unary tests as an OR operation.
static unary andOp(const unary &test1, const unary &test2)
Combine unary tests as an AND operation.
dictionary parcelSelect_
The filtered parcel addressing. Eg, for the current cloud.
static const Enum< sourceType > sourceNames
Names for the sourceType.
A bitSet stores bits (elements with only two states) in packed internal format and supports a variety...
Definition: bitSet.H:59
#define WarningInFunction
Report a warning using Foam::Warning.
Enum is a wrapper around a list of names/values that represent particular enumeration (or int) values...
Definition: error.H:64
#define Log
Definition: PDRblock.C:28
void reduce(const List< UPstream::commsStruct > &comms, T &value, const BinaryOp &bop, const int tag, const label comm)
Reduce inplace (cf. MPI Allreduce) using specified communication schedule.
static unary operation(const opType op, const scalar opVal, const scalar tol=VSMALL)
Standard comparison method by type.
Field< vector > vectorField
Specialisation of Field<T> for vector.
void reset()
Clear all bits but do not adjust the addressable size.
Definition: PackedListI.H:551
Registry of regIOobjects.
logicType
Enumeration defining and/or logic.
static const Enum< logicType > logicNames
Names for the logicType.
label size() const noexcept
Number of entries.
Definition: PackedList.H:371
Namespace for OpenFOAM.