mapFields.C
Go to the documentation of this file.
1 /*---------------------------------------------------------------------------*\
2  ========= |
3  \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
4  \\ / O peration | Website: https://openfoam.org
5  \\ / A nd | Copyright (C) 2011-2019 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 Application
25  mapFields
26 
27 Description
28  Maps volume fields from one mesh to another, reading and
29  interpolating all fields present in the time directory of both cases.
30  Parallel and non-parallel cases are handled without the need to reconstruct
31  them first.
32 
33 \*---------------------------------------------------------------------------*/
34 
35 #include "fvCFD.H"
36 #include "meshToMesh0.H"
37 #include "processorFvPatch.H"
38 #include "MapMeshes.H"
39 
40 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
41 
42 void mapConsistentMesh
43 (
44  const fvMesh& meshSource,
45  const fvMesh& meshTarget,
46  const meshToMesh0::order& mapOrder,
47  const bool subtract
48 )
49 {
50  if (subtract)
51  {
52  MapConsistentMesh<minusEqOp>
53  (
54  meshSource,
55  meshTarget,
56  mapOrder
57  );
58  }
59  else
60  {
61  MapConsistentMesh<eqOp>
62  (
63  meshSource,
64  meshTarget,
65  mapOrder
66  );
67  }
68 }
69 
70 
71 void mapSubMesh
72 (
73  const fvMesh& meshSource,
74  const fvMesh& meshTarget,
75  const HashTable<word>& patchMap,
76  const wordList& cuttingPatches,
77  const meshToMesh0::order& mapOrder,
78  const bool subtract
79 )
80 {
81  if (subtract)
82  {
83  MapSubMesh<minusEqOp>
84  (
85  meshSource,
86  meshTarget,
87  patchMap,
88  cuttingPatches,
89  mapOrder
90  );
91  }
92  else
93  {
94  MapSubMesh<eqOp>
95  (
96  meshSource,
97  meshTarget,
98  patchMap,
99  cuttingPatches,
100  mapOrder
101  );
102  }
103 }
104 
105 
106 void mapConsistentSubMesh
107 (
108  const fvMesh& meshSource,
109  const fvMesh& meshTarget,
110  const meshToMesh0::order& mapOrder,
111  const bool subtract
112 )
113 {
114  if (subtract)
115  {
116  MapConsistentSubMesh<minusEqOp>
117  (
118  meshSource,
119  meshTarget,
120  mapOrder
121  );
122  }
123  else
124  {
125  MapConsistentSubMesh<eqOp>
126  (
127  meshSource,
128  meshTarget,
129  mapOrder
130  );
131  }
132 }
133 
134 
135 wordList addProcessorPatches
136 (
137  const fvMesh& meshTarget,
138  const wordList& cuttingPatches
139 )
140 {
141  // Add the processor patches to the cutting list
142  HashTable<label> cuttingPatchTable;
143  forAll(cuttingPatches, i)
144  {
145  cuttingPatchTable.insert(cuttingPatches[i], i);
146  }
147 
148  forAll(meshTarget.boundary(), patchi)
149  {
150  if (isA<processorFvPatch>(meshTarget.boundary()[patchi]))
151  {
152  if
153  (
154  !cuttingPatchTable.found
155  (
156  meshTarget.boundaryMesh()[patchi].name()
157  )
158  )
159  {
160  cuttingPatchTable.insert
161  (
162  meshTarget.boundaryMesh()[patchi].name(),
163  -1
164  );
165  }
166  }
167  }
168 
169  return cuttingPatchTable.toc();
170 }
171 
172 
173 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
174 
175 int main(int argc, char *argv[])
176 {
177  argList::addNote
178  (
179  "map volume fields from one mesh to another"
180  );
181  argList::noParallel();
182  argList::validArgs.append("sourceCase");
183 
184  argList::addOption
185  (
186  "sourceTime",
187  "scalar|'latestTime'",
188  "specify the source time"
189  );
190  argList::addOption
191  (
192  "sourceRegion",
193  "word",
194  "specify the source region"
195  );
196  argList::addOption
197  (
198  "targetRegion",
199  "word",
200  "specify the target region"
201  );
202  argList::addBoolOption
203  (
204  "parallelSource",
205  "the source is decomposed"
206  );
207  argList::addBoolOption
208  (
209  "parallelTarget",
210  "the target is decomposed"
211  );
212  argList::addBoolOption
213  (
214  "consistent",
215  "source and target geometry and boundary conditions identical"
216  );
217  argList::addOption
218  (
219  "mapMethod",
220  "word",
221  "specify the mapping method"
222  );
223  argList::addBoolOption
224  (
225  "subtract",
226  "subtract mapped source from target"
227  );
228 
229  argList args(argc, argv);
230 
231  if (!args.check())
232  {
233  FatalError.exit();
234  }
235 
236  fileName rootDirTarget(args.rootPath());
237  fileName caseDirTarget(args.globalCaseName());
238 
239  fileName casePath = args[1];
240  const fileName rootDirSource = casePath.path().toAbsolute();
241  const fileName caseDirSource = casePath.name();
242 
243  Info<< "Source: " << rootDirSource << " " << caseDirSource << endl;
244  word sourceRegion = fvMesh::defaultRegion;
245  if (args.optionFound("sourceRegion"))
246  {
247  sourceRegion = args["sourceRegion"];
248  Info<< "Source region: " << sourceRegion << endl;
249  }
250 
251  Info<< "Target: " << rootDirTarget << " " << caseDirTarget << endl;
252  word targetRegion = fvMesh::defaultRegion;
253  if (args.optionFound("targetRegion"))
254  {
255  targetRegion = args["targetRegion"];
256  Info<< "Target region: " << targetRegion << endl;
257  }
258 
259  const bool parallelSource = args.optionFound("parallelSource");
260  const bool parallelTarget = args.optionFound("parallelTarget");
261  const bool consistent = args.optionFound("consistent");
262 
263  meshToMesh0::order mapOrder = meshToMesh0::INTERPOLATE;
264  if (args.optionFound("mapMethod"))
265  {
266  const word mapMethod(args["mapMethod"]);
267  if (mapMethod == "mapNearest")
268  {
269  mapOrder = meshToMesh0::MAP;
270  }
271  else if (mapMethod == "interpolate")
272  {
273  mapOrder = meshToMesh0::INTERPOLATE;
274  }
275  else if (mapMethod == "cellPointInterpolate")
276  {
277  mapOrder = meshToMesh0::CELL_POINT_INTERPOLATE;
278  }
279  else
280  {
282  << "Unknown mapMethod " << mapMethod << ". Valid options are: "
283  << "mapNearest, interpolate and cellPointInterpolate"
284  << exit(FatalError);
285  }
286 
287  Info<< "Mapping method: " << mapMethod << endl;
288  }
289 
290  const bool subtract = args.optionFound("subtract");
291  if (subtract)
292  {
293  Info<< "Subtracting mapped source field from target" << endl;
294  }
295 
296 
297  #include "createTimes.H"
298 
299  HashTable<word> patchMap;
300  wordList cuttingPatches;
301 
302  if (!consistent)
303  {
304  IOdictionary mapFieldsDict
305  (
306  IOobject
307  (
308  "mapFieldsDict",
309  runTimeTarget.system(),
311  IOobject::MUST_READ_IF_MODIFIED,
312  IOobject::NO_WRITE,
313  false
314  )
315  );
316 
317  mapFieldsDict.lookup("patchMap") >> patchMap;
318  mapFieldsDict.lookup("cuttingPatches") >> cuttingPatches;
319  }
320 
321  if (parallelSource && !parallelTarget)
322  {
323  IOdictionary decompositionDict
324  (
325  IOobject
326  (
327  "decomposeParDict",
328  runTimeSource.system(),
330  IOobject::MUST_READ_IF_MODIFIED,
331  IOobject::NO_WRITE
332  )
333  );
334 
335  const int nProcs(decompositionDict.lookup<int>("numberOfSubdomains"));
336 
337  Info<< "Create target mesh\n" << endl;
338 
339  fvMesh meshTarget
340  (
341  IOobject
342  (
343  targetRegion,
344  runTimeTarget.timeName(),
346  )
347  );
348 
349  Info<< "Target mesh size: " << meshTarget.nCells() << endl;
350 
351  for (int proci=0; proci<nProcs; proci++)
352  {
353  Info<< nl << "Source processor " << proci << endl;
354 
355  Time runTimeSource
356  (
357  Time::controlDictName,
358  rootDirSource,
359  caseDirSource/fileName(word("processor") + name(proci))
360  );
361 
362  #include "setTimeIndex.H"
363 
364  fvMesh meshSource
365  (
366  IOobject
367  (
368  sourceRegion,
369  runTimeSource.timeName(),
371  )
372  );
373 
374  Info<< "mesh size: " << meshSource.nCells() << endl;
375 
376  if (consistent)
377  {
378  mapConsistentSubMesh
379  (
380  meshSource,
381  meshTarget,
382  mapOrder,
383  subtract
384  );
385  }
386  else
387  {
388  mapSubMesh
389  (
390  meshSource,
391  meshTarget,
392  patchMap,
393  cuttingPatches,
394  mapOrder,
395  subtract
396  );
397  }
398  }
399  }
400  else if (!parallelSource && parallelTarget)
401  {
402  IOdictionary decompositionDict
403  (
404  IOobject
405  (
406  "decomposeParDict",
407  runTimeTarget.system(),
409  IOobject::MUST_READ_IF_MODIFIED,
410  IOobject::NO_WRITE
411  )
412  );
413 
414  const int nProcs(decompositionDict.lookup<int>("numberOfSubdomains"));
415 
416  Info<< "Create source mesh\n" << endl;
417 
418  #include "setTimeIndex.H"
419 
420  fvMesh meshSource
421  (
422  IOobject
423  (
424  sourceRegion,
425  runTimeSource.timeName(),
427  )
428  );
429 
430  Info<< "Source mesh size: " << meshSource.nCells() << endl;
431 
432  for (int proci=0; proci<nProcs; proci++)
433  {
434  Info<< nl << "Target processor " << proci << endl;
435 
436  Time runTimeTarget
437  (
438  Time::controlDictName,
439  rootDirTarget,
440  caseDirTarget/fileName(word("processor") + name(proci))
441  );
442 
443  fvMesh meshTarget
444  (
445  IOobject
446  (
447  targetRegion,
448  runTimeTarget.timeName(),
450  )
451  );
452 
453  Info<< "mesh size: " << meshTarget.nCells() << endl;
454 
455  if (consistent)
456  {
457  mapConsistentSubMesh
458  (
459  meshSource,
460  meshTarget,
461  mapOrder,
462  subtract
463  );
464  }
465  else
466  {
467  mapSubMesh
468  (
469  meshSource,
470  meshTarget,
471  patchMap,
472  addProcessorPatches(meshTarget, cuttingPatches),
473  mapOrder,
474  subtract
475  );
476  }
477  }
478  }
479  else if (parallelSource && parallelTarget)
480  {
481  IOdictionary decompositionDictSource
482  (
483  IOobject
484  (
485  "decomposeParDict",
486  runTimeSource.system(),
488  IOobject::MUST_READ_IF_MODIFIED,
489  IOobject::NO_WRITE
490  )
491  );
492 
493  const int nProcsSource
494  (
495  decompositionDictSource.lookup<int>("numberOfSubdomains")
496  );
497 
498 
499  IOdictionary decompositionDictTarget
500  (
501  IOobject
502  (
503  "decomposeParDict",
504  runTimeTarget.system(),
506  IOobject::MUST_READ_IF_MODIFIED,
507  IOobject::NO_WRITE
508  )
509  );
510 
511  const int nProcsTarget
512  (
513  decompositionDictTarget.lookup<int>("numberOfSubdomains")
514  );
515 
516  List<boundBox> bbsTarget(nProcsTarget);
517  List<bool> bbsTargetSet(nProcsTarget, false);
518 
519  for (int procISource=0; procISource<nProcsSource; procISource++)
520  {
521  Info<< nl << "Source processor " << procISource << endl;
522 
523  Time runTimeSource
524  (
525  Time::controlDictName,
526  rootDirSource,
527  caseDirSource/fileName(word("processor") + name(procISource))
528  );
529 
530  #include "setTimeIndex.H"
531 
532  fvMesh meshSource
533  (
534  IOobject
535  (
536  sourceRegion,
537  runTimeSource.timeName(),
539  )
540  );
541 
542  Info<< "mesh size: " << meshSource.nCells() << endl;
543 
544  boundBox bbSource(meshSource.bounds());
545 
546  for (int procITarget=0; procITarget<nProcsTarget; procITarget++)
547  {
548  if
549  (
550  !bbsTargetSet[procITarget]
551  || (
552  bbsTargetSet[procITarget]
553  && bbsTarget[procITarget].overlaps(bbSource)
554  )
555  )
556  {
557  Info<< nl << "Target processor " << procITarget << endl;
558 
559  Time runTimeTarget
560  (
561  Time::controlDictName,
562  rootDirTarget,
563  caseDirTarget/fileName(word("processor")
564  + name(procITarget))
565  );
566 
567  fvMesh meshTarget
568  (
569  IOobject
570  (
571  targetRegion,
572  runTimeTarget.timeName(),
574  )
575  );
576 
577  Info<< "mesh size: " << meshTarget.nCells() << endl;
578 
579  bbsTarget[procITarget] = meshTarget.bounds();
580  bbsTargetSet[procITarget] = true;
581 
582  if (bbsTarget[procITarget].overlaps(bbSource))
583  {
584  if (consistent)
585  {
586  mapConsistentSubMesh
587  (
588  meshSource,
589  meshTarget,
590  mapOrder,
591  subtract
592  );
593  }
594  else
595  {
596  mapSubMesh
597  (
598  meshSource,
599  meshTarget,
600  patchMap,
601  addProcessorPatches(meshTarget, cuttingPatches),
602  mapOrder,
603  subtract
604  );
605  }
606  }
607  }
608  }
609  }
610  }
611  else
612  {
613  #include "setTimeIndex.H"
614 
615  Info<< "Create meshes\n" << endl;
616 
617  fvMesh meshSource
618  (
619  IOobject
620  (
621  sourceRegion,
622  runTimeSource.timeName(),
624  )
625  );
626 
627  fvMesh meshTarget
628  (
629  IOobject
630  (
631  targetRegion,
632  runTimeTarget.timeName(),
634  )
635  );
636 
637  Info<< "Source mesh size: " << meshSource.nCells() << tab
638  << "Target mesh size: " << meshTarget.nCells() << nl << endl;
639 
640  if (consistent)
641  {
642  mapConsistentMesh(meshSource, meshTarget, mapOrder, subtract);
643  }
644  else
645  {
646  mapSubMesh
647  (
648  meshSource,
649  meshTarget,
650  patchMap,
651  cuttingPatches,
652  mapOrder,
653  subtract
654  );
655  }
656  }
657 
658  Info<< "\nEnd\n" << endl;
659 
660  return 0;
661 }
662 
663 
664 // ************************************************************************* //
#define forAll(list, i)
Loop across all elements in list.
Definition: UList.H:434
errorManipArg< error, int > exit(error &err, const int errNo=1)
Definition: errorManip.H:124
const fileName & globalCaseName() const
Return case name.
Definition: argListI.H:54
static const char tab
Definition: Ostream.H:259
error FatalError
#define FatalErrorInFunction
Report an error message using Foam::FatalError.
Definition: error.H:323
const fileName & rootPath() const
Return root path.
Definition: argListI.H:42
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:251
bool optionFound(const word &opt) const
Return true if the named option is found.
Definition: argListI.H:114
Time runTimeTarget(Time::controlDictName, args)
void exit(const int errNo=1)
Exit : can be called for any error to exit program.
Definition: error.C:168
Time runTimeSource(Time::controlDictName, argsSrc)
word name() const
Return file name (part beyond last /)
Definition: fileName.C:195
fileName & toAbsolute()
Convert from relative to absolute.
Definition: fileName.C:79
static const char nl
Definition: Ostream.H:260
word name(const complex &)
Return a string representation of a complex.
Definition: complex.C:47
fileName path() const
Return the path to the caseName.
Definition: argListI.H:66
List< word > wordList
A List of words.
Definition: fileName.H:54
label patchi
messageStream Info
bool check(bool checkArgs=true, bool checkOpts=true) const
Check argument list.
Definition: argList.C:1371
Foam::argList args(argc, argv)