cellCutPlot.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) 2022-2026 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 "cellCutPlot.H"
27 #include "cutPolyIntegral.H"
28 #include "generatedCellZone.H"
29 #include "OSspecific.H"
30 #include "setWriter.H"
31 #include "SubField.H"
32 #include "volFields.H"
33 #include "writeFile.H"
34 
35 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
36 
37 namespace Foam
38 {
39 namespace cellCutPlot
40 {
41 
42 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
43 
44 //- Allocate and return a pair of fields
45 template<class Type>
47 {
48  return
50  (
51  new Pair<Field<Type>>(Field<Type>(size), Field<Type>(size))
52  );
53 }
54 
55 
56 //- Allocate and return a pair of a pair of fields
57 template<class Type>
59 {
60  return
62  (
64  (
67  )
68  );
69 }
70 
71 
72 //- Base class for classes which manage incomplete sets of face data
73 class faceData
74 {
75 protected:
76 
77  const cellList& cells_;
78 
80 
82 
83  const faceList& faces_;
84 
86 
88 
90 
92 
94 
96 
98 
99  inline label activeCuti(const label cuti) const
100  {
101  return cuti % faceis_.size();
102  }
103 
104 public:
105 
107  (
108  const polyMesh& mesh,
109  const label nActiveCuts,
110  const scalarField& pointXs,
111  const scalarField& cutXs
112  )
113  :
114  cells_(mesh.cells()),
116  cellVolumes_(mesh.cellVolumes()),
117  faces_(mesh.faces()),
118  faceAreas_(mesh.faceAreas()),
119  faceCentres_(mesh.faceCentres()),
120  points_(mesh.points()),
121  pointXs_(pointXs),
122  cutXs_(cutXs),
123  faceis_(nActiveCuts),
124  haveFaces_(nActiveCuts)
125  {
126  forAll(faceis_, i)
127  {
128  faceis_.set(i, new DynamicList<label>(mesh.nFaces()));
129  haveFaces_.set(i, new boolList(mesh.nFaces(), false));
130  }
131  }
132 
133  void clear(const label cuti)
134  {
136  (
137  haveFaces_[activeCuti(cuti)],
138  faceis_[activeCuti(cuti)]
139  ) = false;
140 
141  faceis_[activeCuti(cuti)].clear();
142  }
143 };
144 
145 
146 //- Class to manage face cut data
148 :
149  public faceData
150 {
151 private:
152 
153  PtrList<List<List<labelPair>>> faceCuts_;
154 
155  PtrList<Pair<vectorField>> faceCutAreas_;
156 
157 public:
158 
160  (
161  const polyMesh& mesh,
162  const label nActiveCuts,
163  const scalarField& pointXs,
164  const scalarField& cutXs
165  )
166  :
167  faceData(mesh, nActiveCuts, pointXs, cutXs),
168  faceCuts_(nActiveCuts),
169  faceCutAreas_(nActiveCuts)
170  {
171  forAll(faceis_, i)
172  {
173  faceCuts_.set(i, new List<List<labelPair>>(mesh.nFaces()));
174  faceCutAreas_.set(i, fieldPairPtr<vector>(mesh.nFaces()));
175  }
176  }
177 
178  void cache(const label celli, const label cuti)
179  {
180  forAll(cells_[celli], cellFacei)
181  {
182  const label facei = cells_[celli][cellFacei];
183 
184  if (haveFaces_[activeCuti(cuti)][facei]) continue;
185 
186  faceis_[activeCuti(cuti)].append(facei);
187 
188  haveFaces_[activeCuti(cuti)][facei] = true;
189 
190  faceCuts_[activeCuti(cuti)][facei] =
192  (
193  faces_[facei],
194  pointXs_,
195  cutXs_[cuti]
196  );
197 
198  for (label sidei = 0; sidei <= 1; ++ sidei)
199  {
200  faceCutAreas_[activeCuti(cuti)][sidei][facei] =
202  (
203  faces_[facei],
204  faceAreas_[facei],
205  faceCuts_[activeCuti(cuti)][facei],
206  points_,
207  pointXs_,
208  cutXs_[cuti],
209  sidei == 0
210  );
211  }
212  }
213  }
214 
215  const List<List<labelPair>>& faceCuts(const label cuti) const
216  {
217  return faceCuts_[activeCuti(cuti)];
218  }
219 
220  const Pair<vectorField>& faceCutAreas(const label cuti) const
221  {
222  return faceCutAreas_[activeCuti(cuti)];
223  }
224 };
225 
226 
227 //- Class to manage face basis function data
229 :
230  public faceData
231 {
232 private:
233 
234  const faceCutData& fcd_;
235 
236  PtrList<Pair<scalarField>> pointFs_;
237 
238  PtrList<Pair<scalarField>> faceFs_;
239 
240  PtrList<Pair<Pair<scalarField>>> faceCutFs_;
241 
242 
243 public:
244 
246  (
247  const faceCutData& fcd,
248  const polyMesh& mesh,
249  const label nActiveCuts,
250  const scalarField& pointXs,
251  const scalarField& cutXs
252  )
253  :
254  faceData(mesh, nActiveCuts, pointXs, cutXs),
255  fcd_(fcd),
256  pointFs_(nActiveCuts),
257  faceFs_(nActiveCuts),
258  faceCutFs_(nActiveCuts)
259  {
260  forAll(faceis_, i)
261  {
262  pointFs_.set(i, fieldPairPtr<scalar>(mesh.nPoints()));
263  faceFs_.set(i, fieldPairPtr<scalar>(mesh.nFaces()));
264  faceCutFs_.set(i, fieldPairPairPtr<scalar>(mesh.nFaces()));
265  }
266  }
267 
268  void cache(const label celli, const label cuti)
269  {
270  forAll(cells_[celli], cellFacei)
271  {
272  const label facei = cells_[celli][cellFacei];
273 
274  if (haveFaces_[activeCuti(cuti)][facei]) continue;
275 
276  faceis_[activeCuti(cuti)].append(facei);
277 
278  haveFaces_[activeCuti(cuti)][facei] = true;
279 
280  forAll(faces_[facei], facePointi)
281  {
282  const label pointi = faces_[facei][facePointi];
283 
284  if (cuti > 0)
285  {
286  pointFs_[activeCuti(cuti)][0][pointi] =
287  (pointXs_[pointi] - cutXs_[cuti - 1])
288  /(cutXs_[cuti] - cutXs_[cuti - 1]);
289  }
290 
291  if (cuti < cutXs_.size() - 1)
292  {
293  pointFs_[activeCuti(cuti)][1][pointi] =
294  (cutXs_[cuti + 1] - pointXs_[pointi])
295  /(cutXs_[cuti + 1] - cutXs_[cuti]);
296  }
297  }
298 
299  for
300  (
301  label fi = (cuti > 0 ? 0 : 1);
302  fi <= (cuti < cutXs_.size() - 1 ? 1 : 0);
303  fi ++
304  )
305  {
306  faceFs_[activeCuti(cuti)][fi][facei] =
308  (
309  faces_[facei],
310  points_,
311  pointFs_[activeCuti(cuti)][fi]
312  ).second();
313  }
314 
315  for
316  (
317  label fi = (cuti > 0 ? 0 : 1);
318  fi <= (cuti < cutXs_.size() - 1 ? 1 : 0);
319  fi ++
320  )
321  {
322  for (label sidei = 0; sidei <= 1; ++ sidei)
323  {
324  const label cutj =
325  fi == 0 && sidei == 0 ? cuti - 1
326  : fi == 1 && sidei == 1 ? cuti + 1
327  : cuti;
328 
329  if (cutj < 0 || cutj > cutXs_.size() - 1) continue;
330 
331  Tuple2<vector, vector> integral =
333  (
334  faces_[facei],
335  faceAreas_[facei],
336  faceFs_[activeCuti(cuti)][fi][facei],
337  fcd_.faceCuts(cutj)[facei],
338  points_,
339  pointFs_[activeCuti(cuti)][fi],
340  pointXs_,
341  cutXs_[cutj],
342  sidei == 0
343  );
344 
345  const scalar magSqrArea = magSqr(integral.first());
346 
347  faceCutFs_[activeCuti(cuti)][fi][sidei][facei] =
348  magSqrArea > vSmall
349  ? integral.second() & integral.first()/magSqrArea
350  : faceFs_[activeCuti(cuti)][fi][facei];
351  }
352  }
353  }
354  }
355 
356  const Pair<scalarField>& pointFs(const label cuti) const
357  {
358  return pointFs_[activeCuti(cuti)];
359  }
360 
361  const Pair<scalarField>& faceFs(const label cuti) const
362  {
363  return faceFs_[activeCuti(cuti)];
364  }
365 
366  const Pair<Pair<scalarField>>& faceCutFs(const label cuti) const
367  {
368  return faceCutFs_[activeCuti(cuti)];
369  }
370 };
371 
372 
374 (
375  const polyMesh& mesh,
376  const generatedCellZone& zone,
377  const scalarField& pointXs,
378  const scalarField& zoneCellMinXs,
379  const scalarField& zoneCellMaxXs,
380  const labelList& zoneCellMinOrder,
381  const scalarField& cutXs,
382  const bool normalise
383 )
384 {
385  const cellList& cells = mesh.cells();
387  const scalarField& cellVolumes = mesh.cellVolumes();
388  const faceList& faces = mesh.faces();
389  const vectorField& faceAreas = mesh.faceAreas();
390  const pointField& faceCentres = mesh.faceCentres();
391  const pointField& points = mesh.points();
392 
393  // Determine the largest number of cuts spanned by a single cell, and
394  // therefore the number for which data must be simultaneously maintained
395  label nActiveCuts = 0;
396  {
397  label cuti = 0;
398  forAll(zoneCellMinOrder, zoneCellMinOrderi)
399  {
400  const label zoneCelli = zoneCellMinOrder[zoneCellMinOrderi];
401 
402  // Find the next relevant cut
403  while (zoneCellMinXs[zoneCelli] > cutXs[cuti + 1]) cuti ++;
404 
405  // Find the first irrelevant cut
406  label cutj = cuti;
407  while (zoneCellMaxXs[zoneCelli] > cutXs[cutj]) cutj ++;
408 
409  nActiveCuts = max(nActiveCuts, cutj - cuti);
410  }
411  }
412 
413  // Storage for face cut data
414  faceCutData fcd(mesh, nActiveCuts, pointXs, cutXs);
415 
416  // Generate weights for each cell in turn
417  DynamicList<weight> dynWeights(zone.nCells()*2);
418  label cuti = 0;
419  forAll(zoneCellMinOrder, zoneCellMinOrderi)
420  {
421  const label zoneCelli = zoneCellMinOrder[zoneCellMinOrderi];
422  const label celli = zone.celli(zoneCelli);
423 
424  // Find the next relevant cut and remove all data relating to
425  // cuts now behind the spans of the remaining cells
426  while
427  (
428  cuti < cutXs.size() - 1
429  && zoneCellMinXs[zoneCelli] > cutXs[cuti + 1]
430  )
431  {
432  fcd.clear(cuti);
433  cuti ++;
434  }
435 
436  // Loop over all relevant cuts
437  label cutj = cuti;
438  while
439  (
440  cutj < cutXs.size() - 1
441  && zoneCellMaxXs[zoneCelli] > cutXs[cutj]
442  )
443  {
444  // Compute the face data as necessary
445  fcd.cache(celli, cutj);
446  fcd.cache(celli, cutj + 1);
447 
448  // Add a new weight
449  dynWeights.append({celli, cutj, cellVolumes[celli]});
450 
451  // Left interval
452  if (zoneCellMinXs[zoneCelli] < cutXs[cutj])
453  {
454  dynWeights.last().value -=
456  (
457  cells[celli],
458  cAddrs[celli],
459  cellVolumes[celli],
461  (
462  cells[celli],
463  cAddrs[celli],
464  faces,
465  fcd.faceCuts(cutj),
466  pointXs,
467  cutXs[cutj]
468  ),
469  faces,
470  faceAreas,
471  faceCentres,
472  fcd.faceCutAreas(cutj)[0],
473  points,
474  pointXs,
475  cutXs[cutj],
476  true
477  );
478  }
479 
480  // Right interval
481  if (zoneCellMaxXs[zoneCelli] > cutXs[cutj + 1])
482  {
483  dynWeights.last().value -=
485  (
486  cells[celli],
487  cAddrs[celli],
488  cellVolumes[celli],
490  (
491  cells[celli],
492  cAddrs[celli],
493  faces,
494  fcd.faceCuts(cutj + 1),
495  pointXs,
496  cutXs[cutj + 1]
497  ),
498  faces,
499  faceAreas,
500  faceCentres,
501  fcd.faceCutAreas(cutj + 1)[1],
502  points,
503  pointXs,
504  cutXs[cutj + 1],
505  false
506  );
507  }
508 
509  cutj ++;
510  }
511  }
512 
513  // Transfer to non-dynamic storage
514  List<weight> weights;
515  weights.transfer(dynWeights);
516 
517  // Normalise, if requested
518  if (normalise)
519  {
520  scalarField cutWeightSums(cutXs.size() - 1, scalar(0));
521  forAll(weights, weighti)
522  {
523  cutWeightSums[weights[weighti].cuti] += weights[weighti].value;
524  }
525 
527  Pstream::listCombineScatter(cutWeightSums);
528 
529  forAll(weights, weighti)
530  {
531  weights[weighti].value /=
532  (cutWeightSums[weights[weighti].cuti] + vSmall);
533  }
534  }
535 
536  return weights;
537 }
538 
539 
541 (
542  const polyMesh& mesh,
543  const generatedCellZone& zone,
544  const scalarField& pointXs,
545  const scalarField& zoneCellMinXs,
546  const scalarField& zoneCellMaxXs,
547  const labelList& zoneCellMinOrder,
548  const scalarField& cutXs,
549  const bool normalise
550 )
551 {
552  const cellList& cells = mesh.cells();
554  const scalarField& cellVolumes = mesh.cellVolumes();
555  const faceList& faces = mesh.faces();
556  const vectorField& faceAreas = mesh.faceAreas();
557  const pointField& faceCentres = mesh.faceCentres();
558  const pointField& points = mesh.points();
559 
560  // Determine the largest number of cuts spanned by a single cell, and
561  // therefore the number for which data must be simultaneously maintained
562  label nActiveCuts = 0;
563  {
564  label cuti = 0;
565  forAll(zoneCellMinOrder, zoneCellMinOrderi)
566  {
567  const label zoneCelli = zoneCellMinOrder[zoneCellMinOrderi];
568 
569  // Find the next relevant cut
570  while (zoneCellMinXs[zoneCelli] > cutXs[cuti + 1])
571  {
572  cuti ++;
573  }
574 
575  // Find the first irrelevant cut
576  label cutj = cuti;
577  while (zoneCellMaxXs[zoneCelli] > cutXs[max(cutj - 1, 0)])
578  {
579  cutj ++;
580  }
581 
582  nActiveCuts = max(nActiveCuts, cutj - cuti + 1);
583  }
584  }
585 
586  // Storage for face cut and face functions data
587  faceCutData fcd(mesh, nActiveCuts, pointXs, cutXs);
588  faceFsData ffs(fcd, mesh, nActiveCuts, pointXs, cutXs);
589 
590  // Generate weights for each cell in turn
591  DynamicList<weight> dynWeights(zone.nCells()*2);
592  label cuti = 0;
593  forAll(zoneCellMinOrder, zoneCellMinOrderi)
594  {
595  const label zoneCelli = zoneCellMinOrder[zoneCellMinOrderi];
596  const label celli = zone.celli(zoneCelli);
597 
598  // Find the next relevant cut and remove all data relating to
599  // cuts now behind the spans of the remaining cells
600  while
601  (
602  cuti < cutXs.size()
603  && zoneCellMinXs[zoneCelli] > cutXs[cuti + 1]
604  )
605  {
606  if (cuti != 0) fcd.clear(cuti - 1);
607  ffs.clear(cuti);
608  cuti ++;
609  }
610 
611  // Loop over all relevant cuts
612  label cutj = cuti;
613  while
614  (
615  cutj < cutXs.size()
616  && zoneCellMaxXs[zoneCelli] > cutXs[max(cutj - 1, 0)]
617  )
618  {
619  // Compute the connected face data as necessary
620  if (cutj != 0) fcd.cache(celli, cutj - 1);
621  fcd.cache(celli, cutj);
622  if (cutj != cutXs.size() - 1) fcd.cache(celli, cutj + 1);
623  ffs.cache(celli, cutj);
624 
625  // Add a new weight
626  dynWeights.append({celli, cutj, 0});
627 
628  // Get the cell cuts for the middle cut. These will be used twice.
629  // The cuts for the left and right will only be used once and hence
630  // don't need to be stored. They are evaluated inline below.
631  const labelListList cCutsMid =
633  (
634  cells[celli],
635  cAddrs[celli],
636  faces,
637  fcd.faceCuts(cutj),
638  pointXs,
639  cutXs[cutj]
640  );
641 
642  // Left interval
643  if
644  (
645  cutj > 0
646  && zoneCellMinXs[zoneCelli] < cutXs[cutj]
647  )
648  {
649  const scalar cellVF =
651  (
652  cells[celli],
653  cAddrs[celli],
654  faceAreas,
655  faceCentres,
656  ffs.faceFs(cutj)[0]
657  ).second();
658 
659  // Add the whole cell's contribution
660  dynWeights.last().value += cellVF;
661 
662  // Cut off anything before the left point
663  if (zoneCellMinXs[zoneCelli] < cutXs[cutj - 1])
664  {
665  dynWeights.last().value -=
667  (
668  cells[celli],
669  cAddrs[celli],
670  cellVolumes[celli],
671  cellVF/cellVolumes[celli],
673  (
674  cells[celli],
675  cAddrs[celli],
676  faces,
677  fcd.faceCuts(cutj - 1),
678  pointXs,
679  cutXs[cutj - 1]
680  ),
681  faces,
682  faceAreas,
683  faceCentres,
684  ffs.faceFs(cutj)[0],
685  fcd.faceCutAreas(cutj - 1)[0],
686  ffs.faceCutFs(cutj)[0][0],
687  points,
688  ffs.pointFs(cutj)[0],
689  pointXs,
690  cutXs[cutj - 1],
691  true
692  ).second();
693  }
694 
695  // Cut off anything after the middle point
696  if (zoneCellMaxXs[zoneCelli] > cutXs[cutj])
697  {
698  dynWeights.last().value -=
700  (
701  cells[celli],
702  cAddrs[celli],
703  cellVolumes[celli],
704  cellVF/cellVolumes[celli],
705  cCutsMid,
706  faces,
707  faceAreas,
708  faceCentres,
709  ffs.faceFs(cutj)[0],
710  fcd.faceCutAreas(cutj)[1],
711  ffs.faceCutFs(cutj)[0][1],
712  points,
713  ffs.pointFs(cutj)[0],
714  pointXs,
715  cutXs[cutj],
716  false
717  ).second();
718  }
719  }
720 
721  // Right interval
722  if
723  (
724  cutj < cutXs.size() - 1
725  && zoneCellMaxXs[zoneCelli] > cutXs[cutj]
726  )
727  {
728  const scalar cellVF =
730  (
731  cells[celli],
732  cAddrs[celli],
733  faceAreas,
734  faceCentres,
735  ffs.faceFs(cutj)[1]
736  ).second();
737 
738  // Add the whole cell's contribution
739  dynWeights.last().value += cellVF;
740 
741  // Cut off anything before the middle point
742  if (zoneCellMinXs[zoneCelli] < cutXs[cutj])
743  {
744  dynWeights.last().value -=
746  (
747  cells[celli],
748  cAddrs[celli],
749  cellVolumes[celli],
750  cellVF/cellVolumes[celli],
751  cCutsMid,
752  faces,
753  faceAreas,
754  faceCentres,
755  ffs.faceFs(cutj)[1],
756  fcd.faceCutAreas(cutj)[0],
757  ffs.faceCutFs(cutj)[1][0],
758  points,
759  ffs.pointFs(cutj)[1],
760  pointXs,
761  cutXs[cutj],
762  true
763  ).second();
764  }
765 
766  // Cut off anything after the right point
767  if (zoneCellMaxXs[zoneCelli] > cutXs[cutj + 1])
768  {
769  dynWeights.last().value -=
771  (
772  cells[celli],
773  cAddrs[celli],
774  cellVolumes[celli],
775  cellVF/cellVolumes[celli],
777  (
778  cells[celli],
779  cAddrs[celli],
780  faces,
781  fcd.faceCuts(cutj + 1),
782  pointXs,
783  cutXs[cutj + 1]
784  ),
785  faces,
786  faceAreas,
787  faceCentres,
788  ffs.faceFs(cutj)[1],
789  fcd.faceCutAreas(cutj + 1)[1],
790  ffs.faceCutFs(cutj)[1][1],
791  points,
792  ffs.pointFs(cutj)[1],
793  pointXs,
794  cutXs[cutj + 1],
795  false
796  ).second();
797  }
798  }
799 
800  cutj ++;
801  }
802  }
803 
804  // Transfer to non-dynamic storage
805  List<weight> weights;
806  weights.transfer(dynWeights);
807 
808  // Normalise, if requested. Otherwise, double the weight values on the ends
809  // to account for the fact that these points only have half a basis function
810  // contributing to their sums.
811  if (normalise)
812  {
813  scalarField cutWeightSums(cutXs.size(), scalar(0));
814  forAll(weights, weighti)
815  {
816  cutWeightSums[weights[weighti].cuti] += weights[weighti].value;
817  }
818 
820  Pstream::listCombineScatter(cutWeightSums);
821 
822  forAll(weights, weighti)
823  {
824  weights[weighti].value /=
825  (cutWeightSums[weights[weighti].cuti] + vSmall);
826  }
827  }
828  else
829  {
830  forAll(weights, weighti)
831  {
832  if
833  (
834  weights[weighti].cuti == 0
835  || weights[weighti].cuti == cutXs.size() - 1
836  )
837  {
838  weights[weighti].value *= 2;
839  }
840  }
841  }
842 
843  return weights;
844 }
845 
846 
848 (
849  const polyMesh& mesh,
850  const generatedCellZone& zone,
851  const scalarField& pointXs,
852  const scalarField& cellMinXs,
853  const scalarField& cellMaxXs,
854  const labelList& cellMinOrder,
855  const scalarField& cutXs,
856  const bool interpolate,
857  const bool normalise
858 )
859 {
860  return
861  (
865  )
866  (
867  mesh,
868  zone,
869  pointXs,
870  cellMinXs,
871  cellMaxXs,
872  cellMinOrder,
873  cutXs,
874  normalise
875  );
876 }
877 
878 
879 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
880 
881 } // End namespace cellCutPlot
882 } // End namespace Foam
883 
884 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
885 
887 (
888  const polyMesh& mesh,
889  const generatedCellZone& zone,
890  const scalarField& pointXs,
891  const scalarField& cutXs,
892  const bool interpolate,
893  const bool normalise
894 )
895 {
896  const cellList& cells = mesh.cells();
897  const faceList& faces = mesh.faces();
898 
899  // Determine cell min and max coordinates
900  scalarField zoneCellMinXs(zone.nCells(), vGreat);
901  scalarField zoneCellMaxXs(zone.nCells(), -vGreat);
902  forAll(zoneCellMinXs, zoneCelli)
903  {
904  const label celli = zone.celli(zoneCelli);
905  forAll(cells[celli], cellFacei)
906  {
907  const label facei = cells[celli][cellFacei];
908  forAll(faces[facei], facePointi)
909  {
910  const label pointi = faces[facei][facePointi];
911  zoneCellMinXs[zoneCelli] =
912  min(zoneCellMinXs[zoneCelli], pointXs[pointi]);
913  zoneCellMaxXs[zoneCelli] =
914  max(zoneCellMaxXs[zoneCelli], pointXs[pointi]);
915  }
916  }
917  }
918 
919  // Create orderings of the cells based on their min and max coordinates
920  labelList zoneCellMinOrder(zone.nCells());
921  sortedOrder(zoneCellMinXs, zoneCellMinOrder);
922 
923  // Calculate and return the weights
924  return
926  (
927  mesh,
928  zone,
929  pointXs,
930  zoneCellMinXs,
931  zoneCellMaxXs,
932  zoneCellMinOrder,
933  cutXs,
934  interpolate,
935  normalise
936  );
937 }
938 
939 
941 (
942  const polyMesh& mesh,
943  const generatedCellZone& zone,
944  const scalarField& pointXs,
945  const bool interpolate,
946  const label nCuts,
947  const label nIter,
948  const bool debug,
949  const word& functionName,
950  const setWriter& functionFormatter
951 )
952 {
953  const cellList& cells = mesh.cells();
954  const faceList& faces = mesh.faces();
955 
956  const label nIntervals = interpolate ? nCuts : nCuts - 1;
957 
958  // Determine face min and max coordinates
959  scalarField zoneCellMinXs(zone.nCells(), vGreat);
960  scalarField zoneCellMaxXs(zone.nCells(), -vGreat);
961  forAll(zoneCellMinXs, zoneCelli)
962  {
963  const label celli = zone.celli(zoneCelli);
964  forAll(cells[celli], cellFacei)
965  {
966  const label facei = cells[celli][cellFacei];
967  forAll(faces[facei], facePointi)
968  {
969  const label pointi = faces[facei][facePointi];
970  zoneCellMinXs[zoneCelli] =
971  min(zoneCellMinXs[zoneCelli], pointXs[pointi]);
972  zoneCellMaxXs[zoneCelli] =
973  max(zoneCellMaxXs[zoneCelli], pointXs[pointi]);
974  }
975  }
976  }
977 
978  // Create orderings of the cells based on their min and max coordinates
979  labelList zoneCellMinOrder(zone.nCells());
980  sortedOrder(zoneCellMinXs, zoneCellMinOrder);
981 
982  // Assume equal spacing to begin with
983  scalar xMin = gMin(pointXs), xMax = gMax(pointXs);
984  xMin -= max(rootVSmall, 2*small*mag(xMin));
985  xMax += max(rootVSmall, 2*small*mag(xMax));
986  tmp<scalarField> tcutXs = xMin + linearSequence01(nCuts)*(xMax - xMin);
987  scalarField& cutXs = tcutXs.ref();
988  cutXs.first() = xMin;
989  cutXs.last() = xMax;
990 
991  // Names and fields for debug output of the counts, to observe the effect
992  // of iterative improvement of the spacing
994  #define DeclareTypeFieldValues(Type, nullArg) \
995  PtrList<Field<Type>> Type##FieldValues;
997  #undef DeclareTypeFieldValues
998 
999  // Iteratively optimise the spacing between the cut points to achieve an
1000  // approximately equal number of data points in each interval
1001  for (label iteri = 0; iteri < nIter + debug; ++ iteri)
1002  {
1003  // Determine the count of faces that contribute to each interval
1004  const List<weight> weights =
1005  calcWeights
1006  (
1007  mesh,
1008  zone,
1009  pointXs,
1010  zoneCellMinXs,
1011  zoneCellMaxXs,
1012  zoneCellMinOrder,
1013  cutXs,
1014  interpolate,
1015  false
1016  );
1017  const scalarField intervalCounts
1018  (
1020  );
1021 
1022  if (debug)
1023  {
1024  const label nFields0 = (2 + !interpolate)*iteri;
1025  const label nFields = (2 + !interpolate)*(iteri + 1);
1026 
1027  fieldNames.resize(nFields);
1028  #define ResizeTypeFieldValues(Type, nullArg) \
1029  Type##FieldValues.resize(nFields);
1031  #undef ResizeTypeFieldValues
1032 
1033  if (!interpolate)
1034  {
1035  const SubField<scalar> distance0s(cutXs, nIntervals);
1036  const SubField<scalar> distance1s(cutXs, nIntervals, 1);
1037 
1038  fieldNames[nFields0] = "distance-" + Foam::name(iteri);
1039  scalarFieldValues.set(nFields0, (distance0s + distance1s)/2);
1040 
1041  fieldNames[nFields0 + 1] = "thickness-" + Foam::name(iteri);
1042  scalarFieldValues.set(nFields0 + 1, distance1s - distance0s);
1043  }
1044  else
1045  {
1046  fieldNames[nFields0] = "distance-" + Foam::name(iteri);
1047  scalarFieldValues.set(nFields0, new scalarField(cutXs));
1048  }
1049 
1050  fieldNames[nFields - 1] = "count-" + Foam::name(iteri);
1051  scalarFieldValues.set(nFields - 1, new scalarField(intervalCounts));
1052 
1053  if (iteri == nIter) break;
1054  }
1055 
1056  // Do a cumulative sum of the interval counts across all cut points
1057  scalarField cutSumCounts(nCuts, 0);
1058  for (label cuti = 0; cuti < nCuts - 1; ++ cuti)
1059  {
1060  cutSumCounts[cuti + 1] =
1061  cutSumCounts[cuti]
1062  + (
1063  interpolate
1064  ? (intervalCounts[cuti + 1] + intervalCounts[cuti])/2
1065  : intervalCounts[cuti]
1066  );
1067  }
1068 
1069  // Compute the desired count in each interval
1070  const scalar intervalCount = cutSumCounts.last()/(nCuts - 1);
1071 
1072  // Compute the new spacing between the points
1073  scalarField cut0Xs(cutXs);
1074  cutXs = -vGreat;
1075  cutXs.first() = xMin;
1076  label cuti = 1;
1077  for (label cuti0 = 0; cuti0 < nCuts - 1; ++ cuti0)
1078  {
1079  while
1080  (
1081  cuti < nCuts
1082  && cutSumCounts[cuti0 + 1] > cuti*intervalCount
1083  )
1084  {
1085  const scalar f =
1086  (cuti*intervalCount - cutSumCounts[cuti0])
1087  /(cutSumCounts[cuti0 + 1] - cutSumCounts[cuti0]);
1088 
1089  cutXs[cuti] = (1 - f)*cut0Xs[cuti0] + f*cut0Xs[cuti0 + 1];
1090 
1091  cuti ++;
1092  }
1093  }
1094  cutXs.last() = xMax;
1095  }
1096 
1097  if (debug)
1098  {
1099  const fileName outputPath =
1100  mesh.time().globalPath()
1101  /functionObjects::writeFile::outputPrefix
1102  /(
1103  mesh.name() != polyMesh::defaultRegion
1104  ? mesh.name()
1105  : word()
1106  )
1107  /functionName
1108  /mesh.time().name();
1109 
1110  mkDir(outputPath);
1111 
1112  functionFormatter.write
1113  (
1114  outputPath,
1115  functionName + "_count",
1117  fieldNames
1118  #define TypeFieldValuesParameter(Type, nullArg) \
1119  , Type##FieldValues
1122  );
1123  }
1124 
1125  return tcutXs;
1126 }
1127 
1128 
1130 (
1131  const fvMesh& mesh,
1132  const List<cellCutPlot::weight>& weights,
1133  const word& functionName
1134 )
1135 {
1137  (
1138  IOobject
1139  (
1140  functionName + ":layers",
1141  mesh.time().name(),
1142  mesh
1143  ),
1144  mesh,
1145  dimensionedTensor(dimless, tensor::uniform(-1))
1146  );
1147 
1148  forAll(weights, weighti)
1149  {
1150  const weight& w = weights[weighti];
1151 
1152  layers[w.elementi] = tensor::zero;
1153  }
1154 
1155  forAll(weights, weighti)
1156  {
1157  const weight& w = weights[weighti];
1158 
1159  layers[w.elementi][w.cuti % tensor::nComponents] =
1160  w.value/mesh.cellVolumes()[w.elementi];
1161  }
1162 
1163  Info<< functionName << ": Writing " << layers.name() << endl;
1164 
1165  layers.write();
1166 }
1167 
1168 
1169 // ************************************************************************* //
Functions used by OpenFOAM that are specific to POSIX compliant operating systems and need to be repl...
#define forAll(list, i)
Loop across all elements in list.
Definition: UList.H:449
#define TypeFieldValuesParameter(Type, nullArg)
#define DeclareTypeFieldValues(Type, nullArg)
#define ResizeTypeFieldValues(Type, nullArg)
static cellEdgeAddressingList & New(const word &name, const polyMesh &mesh)
Construct and return the named DemandDrivenMeshObject.
Field with dimensions and associated with geometry type GeoMesh which is used to size the field and a...
DynamicList< T, SizeInc, SizeMult, SizeDiv > & append(const T &)
Append an element at the end of the list.
Definition: DynamicListI.H:296
Pre-declare SubField and related Field type.
Definition: Field.H:83
IOobject defines the attributes of an object for which implicit objectRegistry management is supporte...
Definition: IOobject.H:99
const word & name() const
Return name.
Definition: IOobject.H:307
void transfer(List< T > &)
Transfer the contents of the argument List into this list.
Definition: List.C:342
void resize(const label)
Alias for setSize(const label)
Definition: ListI.H:138
void size(const label)
Override size to be inconsistent with allocated storage.
Definition: ListI.H:164
An ordered pair of two objects of type <Type> with first() and second() elements.
Definition: Pair.H:67
static void listCombineGather(const List< commsStruct > &comms, List< T > &Value, const CombineOp &cop, const int tag, const label comm)
static void listCombineScatter(const List< commsStruct > &comms, List< T > &Value, const int tag, const label comm)
Scatter data. Reverse of combineGather.
A templated 1D list of pointers to objects of type <T>, where the size of the array is known and used...
Definition: PtrList.H:75
bool set(const label) const
Is element set.
Definition: PtrListI.H:62
Pre-declare related SubField type.
Definition: SubField.H:63
fileName globalPath() const
Return the global path.
Definition: TimePaths.H:132
A 2-tuple for storing two objects of different types.
Definition: Tuple2.H:66
const Type2 & second() const
Return second.
Definition: Tuple2.H:131
const Type1 & first() const
Return first.
Definition: Tuple2.H:119
A List with indirect addressing.
Definition: UIndirectList.H:61
T & last()
Return the last element of the list.
Definition: UListI.H:128
An auto-pointer similar to the STL auto_ptr but with automatic casting to a reference to the type and...
Definition: autoPtr.H:51
Class to manage face cut data.
Definition: cellCutPlot.C:150
const List< List< labelPair > > & faceCuts(const label cuti) const
Definition: cellCutPlot.C:215
void cache(const label celli, const label cuti)
Definition: cellCutPlot.C:178
const Pair< vectorField > & faceCutAreas(const label cuti) const
Definition: cellCutPlot.C:220
faceCutData(const polyMesh &mesh, const label nActiveCuts, const scalarField &pointXs, const scalarField &cutXs)
Definition: cellCutPlot.C:160
Base class for classes which manage incomplete sets of face data.
Definition: cellCutPlot.C:74
const scalarField & pointXs_
Definition: cellCutPlot.C:91
const pointField & points_
Definition: cellCutPlot.C:89
label activeCuti(const label cuti) const
Definition: cellCutPlot.C:99
PtrList< DynamicList< label > > faceis_
Definition: cellCutPlot.C:95
const faceList & faces_
Definition: cellCutPlot.C:83
faceData(const polyMesh &mesh, const label nActiveCuts, const scalarField &pointXs, const scalarField &cutXs)
Definition: cellCutPlot.C:107
void clear(const label cuti)
Definition: cellCutPlot.C:133
const pointField & faceCentres_
Definition: cellCutPlot.C:87
const cellEdgeAddressingList & cAddrs_
Definition: cellCutPlot.C:79
PtrList< boolList > haveFaces_
Definition: cellCutPlot.C:97
const scalarField & cellVolumes_
Definition: cellCutPlot.C:81
const cellList & cells_
Definition: cellCutPlot.C:77
const vectorField & faceAreas_
Definition: cellCutPlot.C:85
const scalarField & cutXs_
Definition: cellCutPlot.C:93
Class to manage face basis function data.
Definition: cellCutPlot.C:231
const Pair< Pair< scalarField > > & faceCutFs(const label cuti) const
Definition: cellCutPlot.C:366
const Pair< scalarField > & faceFs(const label cuti) const
Definition: cellCutPlot.C:361
const Pair< scalarField > & pointFs(const label cuti) const
Definition: cellCutPlot.C:356
void cache(const label celli, const label cuti)
Definition: cellCutPlot.C:268
faceFsData(const faceCutData &fcd, const polyMesh &mesh, const label nActiveCuts, const scalarField &pointXs, const scalarField &cutXs)
Definition: cellCutPlot.C:246
Holds list of sampling positions.
Definition: coordSet.H:51
Generic dimensioned Type class.
const word & name() const
Return const reference to name.
A class for handling file names.
Definition: fileName.H:82
A functionName is a word starting with '#'.
Definition: functionName.H:60
Mesh data needed to do the Finite Volume discretisation.
Definition: fvMesh.H:98
const Time & time() const
Return the top-level database.
Definition: fvMesh.H:433
const word & name() const
Return reference to name.
Definition: fvMesh.H:447
cellZone selection or generation class
label celli(const label i) const
Return the cell index corresponding to the cell set index.
label nCells() const
Return the number of cells in the set.
Mesh consisting of general polyhedral cells.
Definition: polyMesh.H:78
virtual const faceList & faces() const
Return raw faces.
Definition: polyMesh.C:1308
virtual const pointField & points() const
Return raw points.
Definition: polyMesh.C:1295
const vectorField & faceCentres() const
const scalarField & cellVolumes() const
label nPoints() const
const vectorField & faceAreas() const
const cellList & cells() const
label nFaces() const
virtual bool write(const bool write=true) const
Write using setting from DB.
Base class for writing coordinate sets with data.
Definition: setWriter.H:64
virtual void write(const fileName &outputDir, const fileName &setName, const coordSet &set, const wordList &valueSetNames #define TypeValueSetsConstArg(Type, nullArg)) const =0
Write a coordSet and associated data.
A class for managing temporary objects.
Definition: tmp.H:55
T & ref() const
Return non-const reference or generate a fatal error.
Definition: tmpI.H:197
A class for handling words, derived from string.
Definition: word.H:63
Foam::fvMesh mesh(Foam::IOobject(regionName, runTime.name(), runTime, Foam::IOobject::MUST_READ), false)
#define FOR_ALL_FIELD_TYPES(Macro,...)
Definition: fieldTypes.H:51
volScalarField scalarField(fieldObject, mesh)
static List< word > fieldNames
Definition: globalFoam.H:46
const pointField & points
const cellShapeList & cells
autoPtr< Pair< Field< Type > > > fieldPairPtr(const label size)
Allocate and return a pair of fields.
Definition: cellCutPlot.C:46
List< weight > calcWeights(const polyMesh &mesh, const generatedCellZone &zone, const scalarField &pointXs, const scalarField &cellMinXs, const scalarField &cellMaxXs, const labelList &cellMinOrder, const scalarField &cutXs, const bool interpolate, const bool normalise)
Definition: cellCutPlot.C:848
void writeLayers(const fvMesh &mesh, const List< cellCutPlot::weight > &weights, const word &functionName)
Write the layers as components of a tensor field for debugging.
Definition: cellCutPlot.C:1130
tmp< scalarField > calcCutXs(const polyMesh &mesh, const generatedCellZone &zone, const scalarField &pointXs, const bool interpolate, const label nCuts, const label nIter, const bool debug=false, const word &functionName=word::null, const setWriter &functionFormatter=NullObjectRef< setWriter >())
Compute and return evenly-spaced cut coordinates.
Definition: cellCutPlot.C:941
List< weight > calcInterpolatingWeights(const polyMesh &mesh, const generatedCellZone &zone, const scalarField &pointXs, const scalarField &zoneCellMinXs, const scalarField &zoneCellMaxXs, const labelList &zoneCellMinOrder, const scalarField &cutXs, const bool normalise)
Definition: cellCutPlot.C:541
List< weight > calcNonInterpolatingWeights(const polyMesh &mesh, const generatedCellZone &zone, const scalarField &pointXs, const scalarField &zoneCellMinXs, const scalarField &zoneCellMaxXs, const labelList &zoneCellMinOrder, const scalarField &cutXs, const bool normalise)
Definition: cellCutPlot.C:374
autoPtr< Pair< Pair< Field< Type > > > > fieldPairPairPtr(const label size)
Allocate and return a pair of a pair of fields.
Definition: cellCutPlot.C:58
tmp< Field< Type > > applyWeights(const label n, const List< cellCutPlot::weight > &weights, const Field< Type > &cellValues)
Construct plot values from cell values given a set of weights.
Tuple2< vector, std::tuple< AreaIntegralType< Types > ... > > faceCutAreaIntegral(const face &f, const vector &fArea, const std::tuple< Types ... > &fPsis, const List< labelPair > &fCuts, const pointField &ps, const std::tuple< const Field< Types > &... > &pPsis, const scalarField &pAlphas, const scalar isoAlpha, const bool below)
Compute the face-cut-area and face-cut-area-integral of the given properties.
vector faceCutArea(const face &f, const vector &fArea, const List< labelPair > &fCuts, const pointField &ps, const scalarField &pAlphas, const scalar isoAlpha, const bool below)
Compute the face-cut-area.
Tuple2< scalar, std::tuple< Types ... > > cellCutVolumeIntegral(const cell &c, const cellEdgeAddressing &cAddr, const scalar cVolume, const std::tuple< Types ... > &cPsis, const labelListList &cCuts, const faceUList &fs, const vectorField &fAreas, const pointField &fCentres, const std::tuple< const Field< Types > &... > &fPsis, const vectorField &fCutAreas, const std::tuple< const Field< Types > &... > &fCutPsis, const pointField &ps, const std::tuple< const Field< Types > &... > &pPsis, const scalarField &pAlphas, const scalar isoAlpha, const bool below)
Compute the cell-cut-volume and cell-cut-volume-integral.
Tuple2< scalar, std::tuple< Types ... > > cellVolumeIntegral(const cell &c, const cellEdgeAddressing &cAddr, const point &cPAvg, const std::tuple< Types ... > &cPsiAvgs, const vectorField &fAreas, const pointField &fCentres, const std::tuple< const Field< Types > &... > &fPsis)
Compute the cell-volume and cell-volume-integrals of the given properties.
Tuple2< vector, std::tuple< Types ... > > faceAreaAverage(const FaceValues< point > &fPs, const point &fPAvg, const std::tuple< FaceValues< Types > ... > &fPsis, const std::tuple< Types ... > &fPsiAvgs)
Compute the face-area and face-area-averages of the given properties.
List< labelPair > faceCuts(const face &f, const scalarField &pAlphas, const scalar isoAlpha)
Return the cuts for a given face. This returns a list of pairs of.
Definition: cutPoly.C:61
labelListList cellCuts(const cell &c, const cellEdgeAddressing &cAddr, const faceUList &fs, const List< List< labelPair >> &fCuts, const scalarField &pAlphas, const scalar isoAlpha)
Return the cuts for a given cell. This returns a list of lists of cell-edge.
Definition: cutPoly.C:121
scalar cellCutVolume(const cell &c, const cellEdgeAddressing &cAddr, const scalar cVolume, const labelListList &cCuts, const faceUList &fs, const vectorField &fAreas, const pointField &fCentres, const vectorField &fCutAreas, const pointField &ps, const scalarField &pAlphas, const scalar isoAlpha, const bool below)
Compute the cell-cut-volume.
const dimensionSet dimless
static tmp< SurfaceField< Type > > interpolate(const VolField< Type > &tvf, const surfaceScalarField &faceFlux, Istream &schemeData)
Interpolate field onto faces using scheme given by Istream.
Namespace for OpenFOAM.
Type gMin(const UList< Type > &f, const label comm)
List< label > labelList
A List of labels.
Definition: labelList.H:56
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
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:288
messageStream Info
List< bool > boolList
Bool container classes.
Definition: boolList.H:50
tmp< scalarField > linearSequence01(const label n)
Definition: scalarField.C:107
dimensioned< Type > min(const DimensionedField< Type, GeoMesh, PrimitiveField > &df)
Type gMax(const UList< Type > &f, const label comm)
word name(const LagrangianState state)
Return a string representation of a Lagrangian state enumeration.
tmp< DimensionedField< scalar, GeoMesh, Field > > mag(const DimensionedField< Type, GeoMesh, PrimitiveField > &df)
void sortedOrder(const UList< T > &, labelList &order)
Generate the (stable) sort order for the list.
quaternion normalise(const quaternion &q)
Return the normalised (unit) quaternion of the given quaternion.
Definition: quaternionI.H:603
tmp< DimensionedField< scalar, GeoMesh, Field > > magSqr(const DimensionedField< Type, GeoMesh, PrimitiveField > &df)
tmp< DimensionedField< TypeR, GeoMesh, Field > > New(const tmp< DimensionedField< TypeR, GeoMesh, Field >> &tdf1, const word &name, const dimensionSet &dimensions)
dimensioned< Type > max(const DimensionedField< Type, GeoMesh, PrimitiveField > &df)
labelList f(nPoints)
Structure containing the weight for a given mesh element and cut index.
Definition: cutPlot.H:51
const scalar xMin
Definition: createFields.H:29
mkDir(pdfPath)
const label nIntervals(pdfDictionary.lookup< label >("nIntervals"))
const scalar xMax
Definition: createFields.H:30