ControlDeformExtSurface.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 #include "ControlDeformExtSurface.hpp"
25 #include "SkdTreeUtils.hpp"
26 #include <volcartesian.hpp>
27 #include <CG.hpp>
28 
29 namespace mimmo{
30 
35  m_name = "mimmo.ControlDeformExtSurface";
36  m_tolerance = 0.0;
37 
38  m_allowed.insert((FileType::_from_string("STL"))._to_integral());
39  m_allowed.insert((FileType::_from_string("SURFVTU"))._to_integral());
40  m_allowed.insert((FileType::_from_string("NAS"))._to_integral());
41 
42 };
43 
48 ControlDeformExtSurface::ControlDeformExtSurface(const bitpit::Config::Section & rootXML){
49 
50  m_name = "mimmo.ControlDeformExtSurface";
51  m_tolerance = 0.0;
52  m_allowed.insert((FileType::_from_string("STL"))._to_integral());
53  m_allowed.insert((FileType::_from_string("SURFVTU"))._to_integral());
54  m_allowed.insert((FileType::_from_string("NAS"))._to_integral());
55 
56  std::string fallback_name = "ClassNONE";
57  std::string input = rootXML.get("ClassName", fallback_name);
58  input = bitpit::utils::string::trim(input);
59  if(input == "mimmo.ControlDeformExtSurface"){
60  absorbSectionXML(rootXML);
61  }else{
63  };
64 }
65 
69 
74  m_allowed = other.m_allowed;
75  m_geoList = other.m_geoList;
76  m_geoFileList = other.m_geoFileList;
77  m_tolerance = other.m_tolerance;
78 };
79 
85  swap(other);
86  return(*this);
87 };
88 
94 {
95  std::swap(m_allowed, x.m_allowed);
96  std::swap(m_geoList, x.m_geoList);
97  std::swap(m_geoFileList, x.m_geoFileList);
98  std::swap(m_tolerance, x.m_tolerance);
99  m_violationField.swap(x.m_violationField);
100  m_defField.swap(x.m_defField);
102 }
105 void
107  bool built = true;
108 
109  built = (built && createPortIn<dmpvecarr3E*, ControlDeformExtSurface>(this, &mimmo::ControlDeformExtSurface::setDefField, M_GDISPLS));
110  built = (built && createPortIn<MimmoSharedPointer<MimmoObject>, ControlDeformExtSurface>(this, &mimmo::ControlDeformExtSurface::setGeometry, M_GEOM, true));
111  built = (built && createPortIn<MimmoSharedPointer<MimmoObject>, ControlDeformExtSurface>(this, &mimmo::ControlDeformExtSurface::addConstraint, M_GEOM2));
112 
113  built = (built && createPortOut<double, ControlDeformExtSurface>(this, &mimmo::ControlDeformExtSurface::getViolation, M_VALUED));
114  built = (built && createPortOut<dmpvector1D*, ControlDeformExtSurface>(this, &mimmo::ControlDeformExtSurface::getViolationField, M_SCALARFIELD));
115  m_arePortsBuilt = built;
116 };
117 
125 double
127 
128  double result = -1.0*std::numeric_limits<double>::max();
129  for(const auto & val : m_violationField){
130  result = std::fmax(result, val);
131  }
132 #if MIMMO_ENABLE_MPI
133  MPI_Allreduce(MPI_IN_PLACE, &result, 1, MPI_DOUBLE, MPI_MAX, m_communicator);
134 #endif
135  return result;
136 };
137 
146 dmpvector1D *
148  return &m_violationField;
149 };
150 
151 
159 double
161  return m_tolerance;
162 }
163 
171  return m_geoFileList;
172 }
173 
179 void
181  if(!field) return;
182  m_defField.clear();
183  m_defField = *field;
184 };
185 
190 void
192  if(target == nullptr) return;
193  if(target->getType() != 1){
194  (*m_log)<<"warning: ControlDeformExtSurface cannot support current geometry. It works only w/ 3D surface."<<std::endl;
195  return;
196  }
197  m_geometry = target;
198 
199 };
200 
208 void
210  m_tolerance = std::max(0.0, tol);
211 }
212 
219 void
221  if(constraint == nullptr) return;
222  if(constraint->getType() != 1){
223  (*m_log)<<"warning: ControlDeformExtSurface cannot support current constraint geometry. It works only w/ 3D surface."<<std::endl;
224  return;
225  }
226  m_geoList.insert(constraint);
227 };
228 
229 
230 
241 void
243  for(auto & val : files){
244  addConstraintFile(val.first, val.second);
245  }
246 };
247 
253 void
254 ControlDeformExtSurface::addConstraintFile(std::string file, int format){
255  if(m_allowed.count(format)>0){
256  m_geoFileList[file] = format;
257  }
258 };
259 
265 void ControlDeformExtSurface::addConstraintFile(std::string file, FileType format){
266  addConstraintFile(file,format._to_integral());
267 };
268 
273 void
275  if(m_geoFileList.count(file) >0) m_geoFileList.erase(file);
276 };
277 
281 void
283  m_geoFileList.clear();
284 };
285 
289 void
292  m_geoList.clear();
293  m_defField.clear();
294  m_violationField.clear();
295  m_tolerance = 0.0;
297 };
298 
302 void
304 
306  if(geo == nullptr){
307  (*m_log)<<"Error "+ m_name + " : null pointer to linked geometry found"<<std::endl;
308  throw std::runtime_error("Error "+m_name + " : null pointer to linked geometry found");
309 
310  }
311  if(geo->isEmpty()){
312  (*m_log)<<"Warning in " + m_name +" : empty linked geometry found"<<std::endl;
313  }
314 
315  bool check = m_defField.getGeometry() == geo;
316  check = check && m_defField.getDataLocation() == MPVLocation::POINT;
317  if(!check){
318  (*m_log)<<"Warning in "<<m_name<<": Unsuitable deformation field linked"<<std::endl;
319  }
320  m_defField.completeMissingData({{0.0,0.0,0.0}});
321 
322  m_violationField.clear();
323  m_violationField.initialize(geo, MPVLocation::POINT, -1.0E25);
324 
325  std::vector<long> pointIds = geo->getVerticesIds();
326  dvecarr3E points(pointIds.size());
327 
328  //adding deformation to points and calculate their local
329  //barycenter
330  int count = 0;
331  darray3E dbMin, dbMax;
332  dbMin.fill(std::numeric_limits<double>::max());
333  dbMax.fill(-1.0*std::numeric_limits<double>::max());
334  for (long id : pointIds){
335  pointIds[count] = id;
336  points[count] = geo->getVertexCoords(id) + m_defField[id];
337  for (int i=0; i<3; ++i){
338  dbMin[i] = std::min(dbMin[i], points[count][i]);
339  dbMax[i] = std::max(dbMax[i], points[count][i]);
340  }
341  ++count;
342  }
343  darray3E loc_dcenter = 0.5*(dbMin + dbMax);
344 
345 
346  //evaluate global AABB of geometry and save its center
347  darray3E pbMin, pbMax;
348  getGlobalBoundingBox(geo, pbMin, pbMax);
349  darray3E originalGlobalCenter = 0.5*(pbMin + pbMax);
350 
351  //put together constrained surfaces in a unique list
352  std::vector<MimmoSharedPointer<MimmoObject>> constraint_geos;
353  //from files first
354  readFileConstraints(constraint_geos);
355  // then add those directly linked with addConstraint method.
356  constraint_geos.insert(constraint_geos.end(), m_geoList.begin(), m_geoList.end());
357 
358  //check list size of constraints and rise a warning if the list is empty.
359  if(constraint_geos.empty()) {
360  (*m_log)<<"Warning in " + m_name +" : no valid constraint geometries are linked to the class. "<<std::endl;
361  }
362 
363  // start examining one by one all external constraints
364  darray3E bbMin, bbMax;
365 
366  for(MimmoSharedPointer<MimmoObject> localg : constraint_geos){
367 
368  //check constraint skdtree
369  localg->buildSkdTree();
370  //get the global bounding box of the constraint surface
371  getGlobalBoundingBox(localg, bbMin, bbMax);
372  //evaluate a guess of the search radius as distance using AABBs of the global
373  //target and the global constraint.
374  darray3E insMin, insMax;
375  double suppval(1.0E-08);
376  if(bitpit::CGElem::intersectBoxBox(pbMin,pbMax, bbMin, bbMax, insMin, insMax)){
377  suppval = std::max(1.0E-08, 0.5*norm2(insMax - insMin) );
378  }
379  double searchRadius = std::max( suppval, norm2(originalGlobalCenter - 0.5*(bbMin + bbMax)) );
380 
381  //calculate where the center of the global target is located w.r.t to constraint, to keep up the
382  //right sign for the distance.
383  double refsign = 1.0;
384  std::vector<double> distances;
385  distances.resize(1);
386  evaluateSignedDistance(std::vector<darray3E>(1,originalGlobalCenter), localg, searchRadius, distances);
387  if(distances[0] > 0.0) refsign *= -1.0;
388 
389  //Calculate now the real distances of the deformed points set.
390  distances.resize(points.size());
391  //evaluate a first guess of the search radius as distance using AABBs of the local
392  //point set and the global constraint.
393  suppval = 1.0E-08;
394  if(bitpit::CGElem::intersectBoxBox(dbMin,dbMax, bbMin, bbMax, insMin, insMax)){
395  suppval = std::max(1.0E-08, 0.5*norm2(insMax - insMin) );
396  }
397  searchRadius = std::max( suppval, norm2(loc_dcenter - 0.5*(bbMin + bbMax)) );
398 
399  evaluateSignedDistance(points, localg, searchRadius, distances);
400 
401  distances *= refsign;
402 
403  //push values directly in m_violationField.
404  count = 0;
405  for(long id : pointIds){
406  m_violationField[id] = std::max( m_violationField[id], (distances[count] + m_tolerance) );
407  ++count;
408  }
409 
410  }//end looping on constraint geometries.
411 
412  //write resume file.
413  writeLog();
414 
415 };
416 
422 void
423 ControlDeformExtSurface::absorbSectionXML(const bitpit::Config::Section & slotXML, std::string name){
424 
425  BITPIT_UNUSED(name);
426 
427  BaseManipulation::absorbSectionXML(slotXML, name);
428 
429  std::unordered_map<std::string, int > mapp;
430  if(slotXML.hasSection("Files")){
431 
432  const bitpit::Config::Section & filesXML = slotXML.getSection("Files");
433 
434  for(auto & subfile : filesXML.getSections()){
435  std::string path;
436  std::string tag, tolstring;
437 
438  if(subfile.second->hasOption("fullpath")) {
439  path = subfile.second->get("fullpath");
440  path = bitpit::utils::string::trim(path);
441  }
442  if(subfile.second->hasOption("tag")){
443  tag = subfile.second->get("tag");
444  tag = bitpit::utils::string::trim(tag);
445  //check tag;
446  auto maybe_tag = FileType::_from_string_nothrow(tag.c_str());
447  if(!maybe_tag) tag.clear();
448  else tag = maybe_tag->_to_string();
449  }
450  if(!path.empty() && !tag.empty()){
451  mapp[path] = int(FileType::_from_string(tag.c_str()));
452  }
453  }
454 
455  setConstraintFiles(mapp);
456 
457  }
458 
459  if(slotXML.hasOption("Tolerance")){
460  std::string input = slotXML.get("Tolerance");
461  input = bitpit::utils::string::trim(input);
462  double value = 0.0;
463  if(!input.empty()){
464  std::stringstream ss(input);
465  ss >> value;
466  }
467  setTolerance(value);
468  }
469 
470 };
471 
477 void
478 ControlDeformExtSurface::flushSectionXML(bitpit::Config::Section & slotXML, std::string name){
479 
480  BITPIT_UNUSED(name);
481 
482  BaseManipulation::flushSectionXML(slotXML, name);
483  bitpit::Config::Section & filesXML = slotXML.addSection("Files");
484 
485  int counter = 0;
486  for(auto & file : m_geoFileList){
487  std::string name = "file"+std::to_string(counter);
488  bitpit::Config::Section & local = filesXML.addSection(name);
489  local.set("fullpath", file.first);
490  std::string typetag = (FileType::_from_integral(file.second))._to_string();
491  local.set("tag", typetag);
492  ++counter;
493  }
494 
495  slotXML.set("Tolerance", std::to_string(m_tolerance));
496 
497 };
498 
506 void
507 ControlDeformExtSurface::readFileConstraints(std::vector<MimmoSharedPointer<MimmoObject> > & extFileGeos){
508 
509  extFileGeos.resize(m_geoFileList.size());
510 
511  int counter = 0;
512  std::unique_ptr<MimmoGeometry> geo (new MimmoGeometry(MimmoGeometry::IOMode::READ));
513 
514  for(auto & geoinfo : m_geoFileList){
515 
516  svector1D info = extractInfo(geoinfo.first);
517  geo->setDir(info[0]);
518  geo->setFilename(info[1]);
519  geo->setFileType(geoinfo.second);
520  geo->execute();
521 
522  MimmoSharedPointer<MimmoObject> locMesh = geo->getGeometry();
523  if (locMesh == nullptr) continue;
524 
525  extFileGeos[counter] = locMesh;
526 
527  extFileGeos[counter]->updateAdjacencies();
528  extFileGeos[counter]->buildSkdTree();
529 
530  ++counter;
531  }
532  extFileGeos.resize(counter);
533 };
534 
539 svector1D
540 ControlDeformExtSurface::extractInfo(std::string file){
541 
542  std::string root, name, tag,temp;
543  std::string key1=".", key2="/\\";
544 
545  std::size_t found = file.find_last_of(key2);
546  root = file.substr(0, found);
547  temp = file.substr(found+1);
548 
549  found = temp.find_last_of(key1);
550  name = temp.substr(0,found);
551  tag = temp.substr(found+1);
552 
553  svector1D result(3);
554  result[0] = root;
555  result[1] = name;
556  result[2] = tag;
557 
558  return result;
559 }
560 
573 void
574 ControlDeformExtSurface::evaluateSignedDistance(const std::vector<darray3E> &points, MimmoSharedPointer<MimmoObject> &geo,
575  double initRadius, std::vector<double> & distances)
576 {
577 
578  geo->buildSkdTree();
579 
580  double rate = 0.05;
581  int kmax = 1000;
582  int kiter = 0;
583  double sRadius(initRadius);
584  distances.resize(points.size());
585 
586  std::vector<darray3E> work = points;
587  std::unordered_map<std::size_t,std::size_t> mapPosIndex;
588  for(std::size_t i=0; i<points.size(); ++i){
589  mapPosIndex[i] = i;
590  }
591 
592  bool checkEmptyWork = work.empty();
593 #if MIMMO_ENABLE_MPI
594  MPI_Allreduce(MPI_IN_PLACE, &checkEmptyWork, 1, MPI_C_BOOL, MPI_LAND, m_communicator);
595 #endif
596 
597  while(!checkEmptyWork && kiter < kmax){
598 
599  std::vector<long> suppCellIds(work.size());
600  std::vector<double> distanceWork(work.size());
601  std::vector<darray3E> normals(work.size());
602 
603 #if MIMMO_ENABLE_MPI
604  std::vector<int> suppCellRanks(work.size());
605  skdTreeUtils::signedGlobalDistance(work.size(), work.data(), geo->getSkdTree(), suppCellIds.data(), suppCellRanks.data(), normals.data(), distanceWork.data(), sRadius, false);
606 #else
607  skdTreeUtils::signedDistance(work.size(), work.data(), geo->getSkdTree(), suppCellIds.data(), distanceWork.data(), normals.data(), sRadius);
608 #endif
609 
610  //get all points with distances not calculated.
611  std::vector<std::array<double,3>> failedPoints;
612  std::unordered_map<std::size_t, std::size_t> failedPosIndex;
613  failedPoints.reserve(work.size());
614  int count(0);
615  for(long & val : suppCellIds){
616  if(val == bitpit::Cell::NULL_ID){
617  failedPoints.push_back(work[count]);
618  failedPosIndex[failedPoints.size()-1] = mapPosIndex[count];
619  }else{
620  distances[mapPosIndex[count]] = distanceWork[count];
621  }
622  ++count;
623  }
624 
625  std::swap(failedPoints, work);
626  std::swap(failedPosIndex, mapPosIndex);
627 
628  //check work if empty
629  checkEmptyWork = work.empty();
630 #if MIMMO_ENABLE_MPI
631  MPI_Allreduce(MPI_IN_PLACE, &checkEmptyWork, 1, MPI_C_BOOL, MPI_LAND, m_communicator);
632 #endif
633  //increase search radius
634  sRadius *= (1.0 + rate);
635  //increase iteration
636  kiter++;
637  }
638 
639  //check for residual unchecked distances, and put them to -1.0E+25
640  // just to be manageable by visualizers like paraview.
641  for(auto & tuple : mapPosIndex){
642  distances[tuple.second] = -1.0E+25;
643  }
644 
645 }
646 
651 void
653 
654  m_defField.setName("Deformation Field");
655  m_violationField.setName("Violation Distance Field");
656  write(getGeometry(), m_defField, m_violationField);
657 
658 }
659 
663 void
664 ControlDeformExtSurface::writeLog(){
665 
666  double violationMax = getViolation();
667  std::size_t geoListSize = m_geoList.size();
668 
669 #if MIMMO_ENABLE_MPI
670  if(m_rank == 0){
671 #endif
672  std::string logname = m_name+std::to_string(getId())+"_violation.log";
673  std::ofstream log;
674  log.open(logname);
675  log<<"mimmo "<<m_name<<" resume file"<<std::endl;
676  log<<std::endl;
677  log<<std::endl;
678  log<<" violation value : " << violationMax << std::endl;
679  log<<std::endl;
680  log<<" directly linked constraints (number) : " << geoListSize << std::endl;
681  log<<std::endl;
682  log<<" additional constraints from files : " ;
683  for (auto ig : m_geoFileList){
684  log<< ig.first <<" "<<std::endl;
685  }
686  log.close();
687 
688 #if MIMMO_ENABLE_MPI
689  }
690  MPI_Barrier(m_communicator); // other ranks stalled here, waiting 0 to finish writing.
691  #endif
692 
693 }
694 
695 
703 void
704 ControlDeformExtSurface::getGlobalBoundingBox(MimmoSharedPointer<MimmoObject> & geo, darray3E & bMin, darray3E & bMax){
705  if(geo->getBoundingBoxSyncStatus() != mimmo::SyncStatus::SYNC){
706  geo->update();
707  }
708  geo->getBoundingBox(bMin, bMax, true);
709 }
710 
711 }//end mimmo namespace
#define M_GDISPLS
virtual void flushSectionXML(bitpit::Config::Section &slotXML, std::string name="")
#define M_GEOM
double signedDistance(const std::array< double, 3 > *point, const bitpit::PatchSkdTree *tree, long &id, std::array< double, 3 > &normal, double r)
const fileListWithType & getConstraintFiles() const
std::vector< std::string > svector1D
std::vector< darray3E > dvecarr3E
void setName(std::string name)
#define M_GEOM2
ControlDeformExtSurface is a class that check a deformation field, associated to a MimmoObject geomet...
bool completeMissingData(const mpv_t &defValue)
void warningXML(bitpit::Logger *log, std::string name)
BaseManipulation is the base class of any manipulation object of the library.
MimmoSharedPointer< MimmoObject > getGeometry() const
std::unordered_map< std::string, int > fileListWithType
void write(MimmoSharedPointer< MimmoObject > geometry)
virtual void absorbSectionXML(const bitpit::Config::Section &slotXML, std::string name="")
MimmoGeometry is an executable block class wrapping(linking or internally instantiating) a Mimmo Obje...
void initialize(MimmoSharedPointer< MimmoObject >, MPVLocation, const mpv_t &)
virtual void flushSectionXML(bitpit::Config::Section &slotXML, std::string name="")
MimmoSharedPointer< MimmoObject > m_geometry
#define M_VALUED
void addConstraintFile(std::string file, int format)
#define M_SCALARFIELD
std::array< double, 3 > darray3E
void addConstraint(MimmoSharedPointer< MimmoObject > constraint)
void setConstraintFiles(fileListWithType list)
MimmoSharedPointer< MimmoObject > getGeometry()
ControlDeformExtSurface & operator=(ControlDeformExtSurface other)
void swap(BaseManipulation &x) noexcept
void setGeometry(MimmoSharedPointer< MimmoObject > target)
virtual void absorbSectionXML(const bitpit::Config::Section &slotXML, std::string name="")
void swap(ControlDeformExtSurface &x) noexcept