MeshChecker.cpp
1 /*---------------------------------------------------------------------------*\
2  *
3  * mimmo
4  *
5  * Copyright (C) 2015-2021 OPTIMAD engineering Srl
6  *
7  * -------------------------------------------------------------------------
8  * License
9  * This file is part of mimmo.
10  *
11  * mimmo is free software: you can redistribute it and/or modify it
12  * under the terms of the GNU Lesser General Public License v3 (LGPL)
13  * as published by the Free Software Foundation.
14  *
15  * mimmo is distributed in the hope that it will be useful, but WITHOUT
16  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
17  * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
18  * License for more details.
19  *
20  * You should have received a copy of the GNU Lesser General Public License
21  * along with mimmo. If not, see <http://www.gnu.org/licenses/>.
22  *
23  \ *---------------------------------------------------------------------------*/
24 
25 #include <MeshChecker.hpp>
26 #include <bitpit_common.hpp>
27 
28 namespace mimmo{
29 
34 {
35  m_name = "mimmo.MeshChecker";
36  setDefault();
37 }
38 
43 MeshChecker::MeshChecker(const bitpit::Config::Section & rootXML){
44 
45  m_name = "mimmo.MeshChecker";
46  setDefault();
47 
48  std::string fallback_name = "ClassNONE";
49  std::string input = rootXML.get("ClassName", fallback_name);
50  input = bitpit::utils::string::trim(input);
51  if(input == "mimmo.MeshChecker"){
52  absorbSectionXML(rootXML);
53  }else{
55  };
56 }
57 
62 
67  m_minVolume = other.m_minVolume;
68  m_maxVolume = other.m_maxVolume;
80  m_isGood = other.m_isGood;
83 };
84 
89  swap(other);
90  return *this;
91 }
92 
97 void
99 {
100  std::swap(m_minVolume, x.m_minVolume);
101  std::swap(m_maxVolume, x.m_maxVolume);
102  std::swap(m_maxSkewness, x.m_maxSkewness);
103  std::swap(m_maxSkewnessBoundary, x.m_maxSkewnessBoundary);
104  std::swap(m_minFaceValidity, x.m_minFaceValidity);
105  std::swap(m_maxFaceValidity, x.m_maxFaceValidity);
106  std::swap(m_minVolumeChange, x.m_minVolumeChange);
107  std::swap(m_minVolumeTol, x.m_minVolumeTol);
108  std::swap(m_maxVolumeTol, x.m_maxVolumeTol);
109  std::swap(m_maxSkewnessTol, x.m_maxSkewnessTol);
110  std::swap(m_maxSkewnessBoundaryTol, x.m_maxSkewnessBoundaryTol);
111  std::swap(m_minFaceValidityTol, x.m_minFaceValidityTol);
112  std::swap(m_minVolumeChangeTol, x.m_minVolumeChangeTol);
113  std::swap(m_isGood, x.m_isGood);
114  std::swap(m_qualityStatus, x.m_qualityStatus);
115  std::swap(m_printResumeFile, x.m_printResumeFile);
116 }
117 
121 void
123 {
124  m_minVolume = 1.e+18;
125  m_maxVolume = 0.;
126  m_maxSkewness = 0.;
128  m_minFaceValidity = 1.;
129  m_maxFaceValidity = 0.;
130  m_minVolumeChange = 1.;
131  m_minVolumeTol = 1.0e-14;
132  m_maxVolumeTol = 1.0e+10;
133  m_maxSkewnessTol = 85. * BITPIT_PI / 180.;
135  m_minFaceValidityTol = 0.5;
136  m_minVolumeChangeTol = 1.0e-05;
137  m_isGood = false;
138  m_qualityStatus = CMeshOutput::NOTRUN;
139  m_printResumeFile = false;
140  m_volumes.clear();
141 }
142 
146 void
148 {
149  if (getGeometry() == nullptr){
150  throw std::runtime_error (m_name + " : nullptr pointer to linked geometry");
151  }
152  if (getGeometry()->isEmpty()){
153  (*m_log)<<"WARNING: "<<m_name<< " : empty geometry found in execution"<<std::endl;
154  }
155 
156  m_volume = std::unique_ptr<MimmoObject>(new MimmoObject(getGeometry()->getType()));
157  m_volumechange = std::unique_ptr<MimmoObject>(new MimmoObject(getGeometry()->getType()));
158  m_skewness = std::unique_ptr<MimmoObject>(new MimmoObject(getGeometry()->getType()));
159  m_facevalidity =std::unique_ptr<MimmoObject>(new MimmoObject(getGeometry()->getType()));
160 
162  m_isGood = ( m_qualityStatus == CMeshOutput::GOOD );
163 
164  if(m_printResumeFile){
165  printResumeFile();
166  }
167  //Clear auxiliary variables
168  clear();
169 
170 }
171 
174 void
176  bool built = true;
177  built = (built && createPortIn<MimmoSharedPointer<MimmoObject>, MeshChecker>(this, &MeshChecker::setGeometry, M_GEOM, true));
178  built = (built && createPortOut<bool, MeshChecker>(this, &mimmo::MeshChecker::isGood, M_VALUEB));
179  built = (built && createPortOut<int, MeshChecker>(this, &mimmo::MeshChecker::getQualityStatusInt, M_VALUEI));
180  m_arePortsBuilt = built;
181 };
182 
188  if(geo){
190  //Clear auxiliary variables
191  clear();
192  }
193 }
194 
198 void
200 {
201  m_minVolumeTol = tol;
202 }
203 
207 void
209 {
210  m_maxVolumeTol = tol;
211 }
212 
216 void
218 {
219  m_maxSkewnessTol = tol / 180. * BITPIT_PI;
220 }
221 
225 void
227 {
228  m_maxSkewnessBoundaryTol = tol / 180. * BITPIT_PI;
229 }
230 
234 void
236 {
237  m_minFaceValidityTol = tol;
238 }
239 
243 void
245 {
246  m_minVolumeChangeTol = tol;
247 }
248 
252 void
254 {
255  m_printResumeFile = flag;
256 }
257 
258 
262 bool
264 {
265  return int(m_isGood);
266 }
267 
273 {
274  return m_qualityStatus;
275 }
276 
280 int
282 {
283  return static_cast<int>(m_qualityStatus);
284 }
285 
286 
292 {
293  CMeshOutput check = CMeshOutput::NOTRUN;
294 
295  (*m_log) << bitpit::log::priority(bitpit::log::NORMAL);
296  (*m_log) << bitpit::log::context("mimmo");
297 
298  try{
299  checkVolume();
300  checkSkewness();
302  }catch(std::exception & e){
303  (*m_log)<<m_name<<" : FAILED to calculate quality indicators. Check NOT RUN"<< std::endl;
304  return check;
305  }
306 
307  check = CMeshOutput::GOOD;
308 #if MIMMO_ENABLE_MPI
309  MPI_Barrier(m_communicator);
310 #endif
312  check = CMeshOutput::MAXIMUMVOLUME;
313  (*m_log)<<m_name<<" : FAILED maximum cell volume check, found value : "<< m_maxVolume << std::endl;
314  }
315  else{
316  (*m_log)<<m_name<<" : maximum cell volume check PASSED with value : "<< m_maxVolume << std::endl;
317  }
318 
319 #if MIMMO_ENABLE_MPI
320  MPI_Barrier(m_communicator);
321 #endif
323  check = CMeshOutput::MINIMUMVOLUME;
324  (*m_log)<<m_name<<" : FAILED minimum cell volume check, found value : "<< m_minVolume << std::endl;
325  }
326  else{
327  (*m_log)<<m_name<<" : minimum cell volume check PASSED with value : "<< m_minVolume << std::endl;
328  }
329 
330 #if MIMMO_ENABLE_MPI
331  MPI_Barrier(m_communicator);
332 #endif
334  check = CMeshOutput::SKEWNESS;
335  (*m_log)<<m_name<<" : FAILED cell skewness, found value [deg] : "<< m_maxSkewness / BITPIT_PI * 180. << std::endl;
336  }
337  else{
338  (*m_log)<<m_name<<" : cell skewness PASSED with value [deg] : "<< m_maxSkewness / BITPIT_PI * 180. << std::endl;
339  }
340 
341 #if MIMMO_ENABLE_MPI
342  MPI_Barrier(m_communicator);
343 #endif
345  check = CMeshOutput::BOUNDARYSKEWNESS;
346  (*m_log)<<m_name<<" : FAILED boundary skewness, found value [deg] : "<< m_maxSkewnessBoundary / BITPIT_PI * 180. << std::endl;
347  }
348  else{
349  (*m_log)<<m_name<<" : boundary skewness PASSED with value [deg] : "<< m_maxSkewnessBoundary / BITPIT_PI * 180. << std::endl;
350  }
351 
352 #if MIMMO_ENABLE_MPI
353  MPI_Barrier(m_communicator);
354 #endif
356  check = CMeshOutput::VOLUMECHANGERATIO;
357  (*m_log)<<m_name<<" : FAILED cell volume change check, found value : "<< m_minVolumeChange << std::endl;
358  }
359  else{
360  (*m_log)<<m_name<<" : cell volume change check PASSED with value : "<< m_minVolumeChange << std::endl;
361  }
362 
363 #if MIMMO_ENABLE_MPI
364  MPI_Barrier(m_communicator);
365 #endif
367  check = CMeshOutput::FACEVALIDITY;
368  (*m_log)<<m_name<<" : FAILED cell face validity check, found value : "<< m_minFaceValidity << std::endl;
369  }
370  else{
371  (*m_log)<<m_name<<" : cell face validity check PASSED with value : "<< m_minFaceValidity << std::endl;
372  }
373 
374 #if MIMMO_ENABLE_MPI
375  MPI_Barrier(m_communicator);
376 #endif
377  if (check == CMeshOutput::GOOD){
378  (*m_log)<< m_name << " : ALL checks PASSED " << std::endl;
379  }
380 
381  (*m_log) << bitpit::log::priority(bitpit::log::DEBUG);
382 
383 
384  return check;
385 }
386 
390 bool
392 {
393 
394  m_volumes.clear();
396  getGeometry()->updateAdjacencies();
397 
398  livector1D mvolcells;
399  livector1D mvolchangecells;
400 
401  for (auto it = getGeometry()->getPatch()->internalCellBegin(); it!= getGeometry()->getPatch()->internalCellEnd(); ++it){
402  long id = it.getId();
403  double vol = m_volumes[id];
404 
405  m_minVolume = std::min(m_minVolume, vol);
406  if (vol < m_minVolumeTol){
407  mvolcells.push_back(id);
408  }
409 
410  m_maxVolume = std::max(m_maxVolume, vol);
411  if (vol > m_maxVolumeTol){
412  mvolcells.push_back(id);
413  }
414 
415  double ratio = 1.;
416  int nneigh = it->getAdjacencyCount();
417  long* neighs = it->getAdjacencies();
418  for (int i=0; i<nneigh; i++){
419  long neigh = neighs[i];
420  if (neigh > -1)
421  ratio = std::min(ratio, vol/m_volumes[neigh]);
422  }
423  m_minVolumeChange = std::min(m_minVolumeChange, ratio);
424 
425  if (ratio < m_minVolumeChangeTol){
426  mvolchangecells.push_back(id);
427  }
428  }
429 
430  bool passed = ( mvolcells.empty() && mvolchangecells.empty() );
431  if (!passed){
432 
433  bitpit::PiercedVector<bitpit::Vertex> &vertices = getGeometry()->getVertices();
434  bitpit::PiercedVector<bitpit::Cell> &cells = getGeometry()->getCells();
435  bitpit::PiercedVector<bitpit::Vertex> &localVolumeVerts = m_volume->getVertices();
436  bitpit::PiercedVector<bitpit::Vertex> &localVolumeChangeVerts = m_volumechange->getVertices();
437 
438  for(long idCell : mvolcells){
439  bitpit::Cell & cell = cells.at(idCell);
440  bitpit::ConstProxyVector<long> connIds = cell.getVertexIds();
441 
442  for(long idV : connIds){
443  if(!localVolumeVerts.exists(idV)){
444  m_volume->addVertex(vertices.at(idV), idV);
445  }
446  }
447  m_volume->addCell(cell, idCell);
448  }
449 
450  for(long idCell : mvolchangecells){
451  bitpit::Cell & cell = cells.at(idCell);
452  bitpit::ConstProxyVector<long> connIds = cell.getVertexIds();
453 
454  for(long idV : connIds){
455  if(!localVolumeChangeVerts.exists(idV)){
456  m_volumechange->addVertex(vertices.at(idV), idV);
457  }
458  }
459  m_volumechange->addCell(cell, idCell);
460  }
461  }
462 
463 #if MIMMO_ENABLE_MPI
464  MPI_Allreduce(MPI_IN_PLACE, &passed, 1, MPI_C_BOOL, MPI_LAND, m_communicator);
465  MPI_Allreduce(MPI_IN_PLACE, &m_minVolumeChange, 1, MPI_DOUBLE, MPI_MIN, m_communicator);
466  MPI_Allreduce(MPI_IN_PLACE, &m_maxVolume, 1, MPI_DOUBLE, MPI_MAX, m_communicator);
467  MPI_Allreduce(MPI_IN_PLACE, &m_minVolume, 1, MPI_DOUBLE, MPI_MIN, m_communicator);
468 
469 #endif
470 
471  return passed;
472 }
473 
477 bool
479 {
480  if (getGeometry()->getType() != 2){
481  (*m_log)<<m_name<<" : skewness check active only for volume mesh -> check disabled" << std::endl;
482  return true;
483  }
484 
485  getGeometry()->updateInterfaces();
486 
487  livector1D listInterfaces;
488  livector1D listBoundInterfaces;
489  for (bitpit::Interface & interface : getGeometry()->getInterfaces()){
490  if (!interface.isBorder()){
491  std::array<double,3> centroidsVector = getGeometry()->evalCellCentroid(interface.getNeigh()) - getGeometry()->evalCellCentroid(interface.getOwner());
492  std::array<double,3> normal = static_cast<bitpit::VolUnstructured*>(getGeometry()->getPatch())->evalInterfaceNormal(interface.getId());
493  double angle = std::acos(dotProduct(centroidsVector,normal) / (norm2(centroidsVector)*norm2(normal)));
494  m_maxSkewness = std::max(m_maxSkewness, angle);
495  if (angle > m_maxSkewnessTol){
496  listInterfaces.push_back(interface.getId());
497  }
498  }else{
499  std::array<double,3> centroidsVector = getGeometry()->evalInterfaceCentroid(interface.getId()) -getGeometry()->evalCellCentroid(interface.getOwner());
500  std::array<double,3> normal = static_cast<bitpit::VolUnstructured*>(getGeometry()->getPatch())->evalInterfaceNormal(interface.getId());
501  double angle = std::acos(dotProduct(centroidsVector,normal) / (norm2(centroidsVector)*norm2(normal)));
502  m_maxSkewnessBoundary = std::max(m_maxSkewnessBoundary, angle);
503  if (angle > m_maxSkewnessBoundaryTol){
504  listBoundInterfaces.push_back(interface.getId());
505  }
506  }
507  }
508 
509  bool passed = ( listInterfaces.empty() && listBoundInterfaces.empty() );
510 
511  if (!passed){
512 
513  bitpit::PiercedVector<bitpit::Interface> & interfaces = getGeometry()->getInterfaces();
514  bitpit::PiercedVector<bitpit::Cell> & cells = getGeometry()->getCells();
515  bitpit::PiercedVector<bitpit::Vertex> & vertices = getGeometry()->getVertices();
516 
517  bitpit::PiercedVector<bitpit::Vertex> & skewVerts = m_skewness->getVertices();
518  bitpit::PiercedVector<bitpit::Cell> & skewCells = m_skewness->getCells();
519 
520  for( long idI : listInterfaces){
521  long idOwner = interfaces.at(idI).getOwner();
522  long idNeigh = interfaces.at(idI).getNeigh();
523  bitpit::Cell & cellOwner = cells.at(idOwner);
524  bitpit::Cell & cellNeigh = cells.at(idNeigh);
525 
526  //push the cell if it is not ghost and if it's not already inside m_skewness
527  if(cellOwner.isInterior() && !skewCells.exists(idOwner)){
528  bitpit::ConstProxyVector<long> vIds = cellOwner.getVertexIds();
529  for(long idV: vIds){
530  if(!skewVerts.exists(idV)){
531  m_skewness->addVertex(vertices.at(idV), idV);
532  }
533  }
534  m_skewness->addCell(cellOwner, idOwner);
535  }
536 
537  //push the cell if it is not ghost and if it's not already inside m_skewness
538  if(cellNeigh.isInterior() && !skewCells.exists(idNeigh)){
539  bitpit::ConstProxyVector<long> vIds = cellNeigh.getVertexIds();
540  for(long idV: vIds){
541  if(!skewVerts.exists(idV)){
542  m_skewness->addVertex(vertices.at(idV), idV);
543  }
544  }
545  m_skewness->addCell(cellNeigh, idNeigh);
546  }
547  }
548  } // end of if passed.
549 
550 #if MIMMO_ENABLE_MPI
551  MPI_Allreduce(MPI_IN_PLACE, &passed, 1, MPI_C_BOOL, MPI_LAND, m_communicator);
552  MPI_Allreduce(MPI_IN_PLACE, &m_maxSkewness, 1, MPI_DOUBLE, MPI_MAX, m_communicator);
553  MPI_Allreduce(MPI_IN_PLACE, &m_maxSkewnessBoundary, 1, MPI_DOUBLE, MPI_MAX, m_communicator);
554 #endif
555 
556  return passed;
557 }
558 
562 bool
564 {
565 
566  if (getGeometry()->getType() != 2){
567  (*m_log)<<m_name<<" : face validity check active only for volume mesh -> check disabled" << std::endl;
568  return true;
569  }
570 
571 
572  getGeometry()->updateInterfaces();
573 
574  //Prepare two structure areaGood and sumArea
575  std::unordered_map<long, double> sumArea;
576  std::unordered_map<long, double> areaGood;
577  for (bitpit::Cell & cell : getGeometry()->getCells()){
578  sumArea[cell.getId()] = 0.0;
579  areaGood[cell.getId()] = 0.0;
580  }
581  for (bitpit::Interface & interface : getGeometry()->getInterfaces()){
582  int n=1;
583  if (!interface.isBorder())
584  n=2;
585  for (int i=0; i<n; i++){
586  long idcell = interface.getOwnerNeigh()[i];
587  long idinter = interface.getId();
588  std::array<double,3> centroid = getGeometry()->getPatch()->evalCellCentroid(idcell);
589  std::array<double,3> centerinterface = getGeometry()->getPatch()->evalInterfaceCentroid(idinter);
590  std::array<double,3> normal = static_cast<bitpit::VolUnstructured*>(getGeometry()->getPatch())->evalInterfaceNormal(idinter);
591  if (i==1){
592  normal = -1.*normal;
593  }
594  double product = dotProduct((centerinterface-centroid),normal);
595  double area = static_cast<bitpit::VolUnstructured*>(getGeometry()->getPatch())->evalInterfaceArea(idinter);
596  if (product > 0.0){
597  areaGood[idcell] = areaGood[idcell] + area;
598  }
599  sumArea[idcell] = sumArea[idcell] + area;
600  }
601  }
602 
603  // save the sick elements in a list.
604  livector1D listSickCell;
605 
606  for (auto it = getGeometry()->getPatch()->internalCellBegin(); it!=getGeometry()->getPatch()->internalCellEnd(); ++it){
607  long idcell = it.getId();
608  double area = areaGood[idcell] / sumArea[idcell];
609  m_minFaceValidity = std::min(m_minFaceValidity, area);
610  if (area < m_minFaceValidityTol){
611  listSickCell.push_back(idcell);
612  }
613  }
614  //create the boolean
615  bool passed = listSickCell.empty();
616 
617  // fill the structure.
618  if (!passed){
619  bitpit::PiercedVector<bitpit::Vertex> & vertices = getGeometry()->getVertices();
620  bitpit::PiercedVector<bitpit::Cell> & cells = getGeometry()->getCells();
621 
622  bitpit::PiercedVector<bitpit::Vertex> & fvalVerts = m_facevalidity->getVertices();
623 
624  for(long idCell : listSickCell){
625  bitpit::Cell & cell = cells.at(idCell);
626  bitpit::ConstProxyVector<long> connIds = cell.getVertexIds();
627 
628  for(long idV : connIds){
629  if(!fvalVerts.exists(idV)){
630  m_facevalidity->addVertex(vertices.at(idV), idV);
631  }
632  }
633  m_facevalidity->addCell(cell, idCell);
634  }
635  }
636 
637 #if MIMMO_ENABLE_MPI
638  MPI_Allreduce(MPI_IN_PLACE, &passed, 1, MPI_C_BOOL, MPI_LAND, m_communicator);
639  MPI_Allreduce(MPI_IN_PLACE, &m_minFaceValidity, 1, MPI_DOUBLE, MPI_MIN, m_communicator);
640 #endif
641 
642  return passed;
643 }
644 
645 
649 void
651 {
653  for (bitpit::Cell & cell : getGeometry()->getCells()){
654  long id = cell.getId();
655  m_volumes[id] = getGeometry()->evalCellVolume(id);
656  }
657 }
658 
662 void
664  m_volumes.clear();
665 }
666 
670 void
672  if (getGeometry() == nullptr) return;
673  if(m_qualityStatus == CMeshOutput::NOTRUN ) return;
674 
675  bool volumeEmpty = m_volume->isEmpty();
676  bool volchangeEmpty = m_volumechange->isEmpty();
677  bool skewEmpty = m_skewness->isEmpty();
678  bool fvalEmpty = m_facevalidity->isEmpty();
679 
680 #if MIMMO_ENABLE_MPI
681  MPI_Allreduce(MPI_IN_PLACE, &volumeEmpty, 1, MPI_C_BOOL, MPI_LAND, m_communicator);
682  MPI_Allreduce(MPI_IN_PLACE, &volchangeEmpty, 1, MPI_C_BOOL, MPI_LAND, m_communicator);
683  MPI_Allreduce(MPI_IN_PLACE, &skewEmpty, 1, MPI_C_BOOL, MPI_LAND, m_communicator);
684  MPI_Allreduce(MPI_IN_PLACE, &fvalEmpty, 1, MPI_C_BOOL, MPI_LAND, m_communicator);
685 #endif
686 
687  if (!volumeEmpty){
688  m_volume->cleanPatchInfo();
689  m_volume->update();
690  m_volume->getPatch()->getVTK().setDirectory(m_outputPlot+"/");
691  m_volume->getPatch()->getVTK().setName(m_name+std::to_string(getId())+".volume");
692  m_volume->getPatch()->write();
693  }
694  if (!volchangeEmpty){
695  m_volumechange->cleanPatchInfo();
696  m_volumechange->update();
697  m_volumechange->getPatch()->getVTK().setDirectory(m_outputPlot+"/");
698  m_volumechange->getPatch()->getVTK().setName(m_name+std::to_string(getId())+".volume.ratio");
699  m_volumechange->getPatch()->write();
700  }
701  if (!skewEmpty){
702  m_skewness->cleanPatchInfo();
703  m_skewness->update();
704  m_skewness->getPatch()->getVTK().setDirectory(m_outputPlot+"/");
705  m_skewness->getPatch()->getVTK().setName(m_name+std::to_string(getId())+".skewness");
706  m_skewness->getPatch()->write();
707  }
708  if (!fvalEmpty){
709  m_facevalidity->cleanPatchInfo();
710  m_facevalidity->update();
711  m_facevalidity->getPatch()->getVTK().setDirectory(m_outputPlot+"/");
712  m_facevalidity->getPatch()->getVTK().setName(m_name+std::to_string(getId())+".face.validity");
713  m_facevalidity->getPatch()->write();
714  }
715 }
716 
722 void
723 MeshChecker::absorbSectionXML(const bitpit::Config::Section & slotXML, std::string name){
724 
725  BITPIT_UNUSED(name);
726 
727  BaseManipulation::absorbSectionXML(slotXML, name);
728 
729  //TODO XML SECTIONS
730 
731  if(slotXML.hasOption("MinVolTOL")){
732  std::string input = slotXML.get("MinVolTOL");
733  input = bitpit::utils::string::trim(input);
734  double val = 1.0E-14;
735  if(!input.empty()){
736  std::stringstream ss(input);
737  ss>>val;
738  }
740  }
741  if(slotXML.hasOption("MaxVolTOL")){
742  std::string input = slotXML.get("MaxVolTOL");
743  input = bitpit::utils::string::trim(input);
744  double val = 1.0E10;
745  if(!input.empty()){
746  std::stringstream ss(input);
747  ss>>val;
748  }
750  }
751 
752  if(slotXML.hasOption("MaxSkewTOL")){
753  std::string input = slotXML.get("MaxSkewTOL");
754  input = bitpit::utils::string::trim(input);
755  double val = 85.0*BITPIT_PI/180;
756  if(!input.empty()){
757  std::stringstream ss(input);
758  ss>>val;
759  }
761  }
762 
763  if(slotXML.hasOption("MaxBoundarySkewTOL")){
764  std::string input = slotXML.get("MaxBoundarySkewTOL");
765  input = bitpit::utils::string::trim(input);
766  double val = 85.0*BITPIT_PI/180;
767  if(!input.empty()){
768  std::stringstream ss(input);
769  ss>>val;
770  }
772  }
773 
774  if(slotXML.hasOption("MinFaceValidityTOL")){
775  std::string input = slotXML.get("MinFaceValidityTOL");
776  input = bitpit::utils::string::trim(input);
777  double val = 0.5;
778  if(!input.empty()){
779  std::stringstream ss(input);
780  ss>>val;
781  }
783  }
784  if(slotXML.hasOption("MinVolChangeTOL")){
785  std::string input = slotXML.get("MinVolChangeTOL");
786  input = bitpit::utils::string::trim(input);
787  double val = 1.0E-5;
788  if(!input.empty()){
789  std::stringstream ss(input);
790  ss>>val;
791  }
793  }
794  if(slotXML.hasOption("ResumeFile")){
795  std::string input = slotXML.get("ResumeFile");
796  input = bitpit::utils::string::trim(input);
797  bool val = false;
798  if(!input.empty()){
799  std::stringstream ss(input);
800  ss>>val;
801  }
802  setPrintResumeFile(val);
803  }
804 
805 };
806 
812 void
813 MeshChecker::flushSectionXML(bitpit::Config::Section & slotXML, std::string name){
814 
815  BITPIT_UNUSED(name);
816 
817  BaseManipulation::flushSectionXML(slotXML, name);
818 
819  {
820  std::stringstream ss;
821  ss << std::scientific<<std::setprecision(12)<<m_minVolumeTol;
822  slotXML.set("MinVolTOL", ss.str());
823  }
824 
825  {
826  std::stringstream ss;
827  ss << std::scientific<<std::setprecision(12)<<m_maxVolumeTol;
828  slotXML.set("MaxVolTOL", ss.str());
829  }
830  {
831  std::stringstream ss;
832  ss << std::scientific<<std::setprecision(12)<<m_maxSkewnessTol;
833  slotXML.set("MaxSkewTOL", ss.str());
834  }
835 
836  {
837  std::stringstream ss;
838  ss << std::scientific<<std::setprecision(12)<<m_maxSkewnessBoundaryTol;
839  slotXML.set("MaxBoundarySkewTOL", ss.str());
840  }
841  {
842  std::stringstream ss;
843  ss << std::scientific<<std::setprecision(12)<<m_minFaceValidityTol;
844  slotXML.set("MinFaceValidityTOL", ss.str());
845  }
846 
847  {
848  std::stringstream ss;
849  ss << std::scientific<<std::setprecision(12)<<m_minVolumeChangeTol;
850  slotXML.set("MinVolChangeTOL", ss.str());
851  }
852 
853  slotXML.set("ResumeFile", std::to_string(int(m_printResumeFile)));
854 };
855 
860 
861  long countVolumeCells = m_volume->getNCells();
862  long countVolumeChangeCells = m_volumechange->getNCells();
863  long countSkewCells = m_skewness->getNCells();
864  long countFValCells = m_facevalidity->getNCells();
865 
866 #if MIMMO_ENABLE_MPI
867  MPI_Allreduce(MPI_IN_PLACE, &countVolumeCells,1, MPI_LONG, MPI_SUM, m_communicator);
868  MPI_Allreduce(MPI_IN_PLACE, &countVolumeChangeCells,1, MPI_LONG, MPI_SUM, m_communicator);
869  MPI_Allreduce(MPI_IN_PLACE, &countSkewCells,1, MPI_LONG, MPI_SUM, m_communicator);
870  MPI_Allreduce(MPI_IN_PLACE, &countFValCells,1, MPI_LONG, MPI_SUM, m_communicator);
871 
872  if(m_rank == 0)
873 #endif
874  {
875  std::string dir = m_outputPlot + "/";
876  std::string name = m_name +std::to_string(getId())+"_ResumeFile.dat";
877  std::string file = dir + name;
878  std::ofstream out;
879  out.open(file);
880  if(out.is_open()){
881 
882  out<<"#mimmo MeshChecker Resume File"<<std::endl;
883  out<<std::endl;
884  out<<std::endl;
885  out<<"#Sick Cells Count: "<<std::endl;
886  out<<std::endl;
887  out<<"VOLUME : "<<countVolumeCells<<std::endl;
888  out<<"VOLUMECHANGE : "<<countVolumeChangeCells<<std::endl;
889  out<<"SKEWNESS : "<<countSkewCells<<std::endl;
890  out<<"FACEVALIDITY : "<<countFValCells<<std::endl;
891 
892  out<<std::endl;
893  out<<std::endl;
894  out<<"#Found indicators values vs Thresholds: "<<std::endl;
895  out<<std::endl;
896  out<<std::scientific<<"MinVol Threshold : "<< m_minVolumeTol <<" , MinVol found : "<<m_minVolume<<std::endl;
897  out<<std::scientific<<"MaxVol Threshold : "<< m_maxVolumeTol <<" , MaxVol found : "<<m_maxVolume<<std::endl;
898  out<<std::scientific<<"MinVolChange Threshold : "<< m_minVolumeChangeTol <<" , MinVolChange found : "<<m_minVolumeChange<<std::endl;
899  out<<std::scientific<<"MaxSkewness Threshold : "<< m_maxSkewnessTol <<" , MaxSkewness found : "<<m_maxSkewness<<std::endl;
900  out<<std::scientific<<"MaxBndSkewness Threshold : "<< m_maxSkewnessBoundaryTol <<" , MaxBndSkewness found : "<<m_maxSkewnessBoundary <<std::endl;
901  out<<std::scientific<<"MinFaceVal Threshold : "<< m_minFaceValidityTol <<" , MinFaceVal found : "<<m_minFaceValidity <<std::endl;
902 
903  out.close();
904  }else{
905  throw std::runtime_error("MeshChecker cannot open ResumeFile to write.");
906  }
907 
908  }
909 #if MIMMO_ENABLE_MPI
910  MPI_Barrier(m_communicator);
911 #endif
912 
913 }
914 
915 
916 
917 }
void setMinimumFaceValidityTolerance(double tol)
MimmoObject is the basic geometry container for mimmo library.
#define M_GEOM
CMeshOutput getQualityStatus()
std::unique_ptr< MimmoObject > m_volumechange
CMeshOutput checkMeshQuality()
void setMaximumVolumeTolerance(double tol)
double m_maxSkewnessBoundary
virtual void absorbSectionXML(const bitpit::Config::Section &slotXML, std::string name="")
MimmoPiercedVector< double > m_volumes
#define M_VALUEI
std::vector< long > livector1D
void setMaximumBoundarySkewnessTolerance(double tol)
void setMinimumVolumeChangeTolerance(double tol)
std::unique_ptr< MimmoObject > m_skewness
void warningXML(bitpit::Logger *log, std::string name)
double m_maxSkewnessBoundaryTol
MeshChecker is the class to evaluate the quality of a volume mesh.
Definition: MeshChecker.hpp:87
void setGeometry(MimmoSharedPointer< MimmoObject > obj)
BaseManipulation is the base class of any manipulation object of the library.
std::unique_ptr< MimmoObject > m_facevalidity
virtual void flushSectionXML(bitpit::Config::Section &slotXML, std::string name="")
void setMaximumSkewnessTolerance(double tol)
virtual void absorbSectionXML(const bitpit::Config::Section &slotXML, std::string name="")
std::unique_ptr< MimmoObject > m_volume
MeshChecker & operator=(MeshChecker other)
Definition: MeshChecker.cpp:88
CMeshOutput m_qualityStatus
void initialize(MimmoSharedPointer< MimmoObject >, MPVLocation, const mpv_t &)
virtual void flushSectionXML(bitpit::Config::Section &slotXML, std::string name="")
virtual ~MeshChecker()
Definition: MeshChecker.cpp:61
void setMinimumVolumeTolerance(double tol)
void setGeometry(MimmoSharedPointer< MimmoObject > geometry)
void swap(MeshChecker &x) noexcept
Definition: MeshChecker.cpp:98
MimmoSharedPointer is a custom implementation of shared pointer.
MimmoSharedPointer< MimmoObject > getGeometry()
void setPrintResumeFile(bool flag)
#define M_VALUEB