CreateSeedsOnSurface.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 "CreateSeedsOnSurface.hpp"
26 #include "Lattice.hpp"
27 #include "SkdTreeUtils.hpp"
28 
29 #include <CG.hpp>
30 
31 #include <stdlib.h>
32 #include <time.h>
33 #include <set>
34 #include <random>
35 
36 namespace mimmo{
37 
42  m_name = "mimmo.CreateSeedsOnSurface";
43  m_nPoints = 0;
44  m_minDist = 0.0;
45  m_seed = {{0.0,0.0,0.0}};
46  m_engine = CSeedSurf::CARTESIANGRID;
47  m_seedbaricenter = false;
48  m_randomFixed = false;
49  m_randomSignature = 1;
50  m_bbox = std::unique_ptr<mimmo::OBBox> (new mimmo::OBBox());
51 };
52 
57 CreateSeedsOnSurface::CreateSeedsOnSurface(const bitpit::Config::Section & rootXML){
58 
59  m_name = "mimmo.CreateSeedsOnSurface";
60  m_nPoints = 0;
61  m_minDist = 0.0;
62  m_seed = {{0.0,0.0,0.0}};
63  m_engine = CSeedSurf::CARTESIANGRID;
64  m_seedbaricenter = false;
65  m_randomFixed = false;
66  m_randomSignature = 1;
67  m_bbox = std::unique_ptr<mimmo::OBBox> (new mimmo::OBBox());
68 
69  std::string fallback_name = "ClassNONE";
70  std::string input = rootXML.get("ClassName", fallback_name);
71  input = bitpit::utils::string::trim(input);
72  if(input == "mimmo.CreateSeedsOnSurface"){
73  absorbSectionXML(rootXML);
74  }else{
76  };
77 }
78 
83 
89  m_points = other.m_points;
90  m_nPoints = other.m_nPoints;
91  m_minDist = other.m_minDist;
92  m_seed = other.m_seed;
93  m_engine = other.m_engine;
94  m_seedbaricenter = other.m_seedbaricenter;
95  m_randomFixed = other.m_randomFixed;
96  m_randomSignature = other.m_randomSignature;
97  m_sensitivity = other.m_sensitivity;
98  m_bbox = std::unique_ptr<mimmo::OBBox>(new mimmo::OBBox(*(other.m_bbox.get())));
99 };
100 
106  swap(other);
107  return *this;
108 }
109 
115 {
116  std::swap(m_points, x.m_points);
117  std::swap(m_nPoints, x.m_nPoints);
118  std::swap(m_minDist, x.m_minDist);
119  std::swap(m_seed, x.m_seed);
120  std::swap(m_engine, x.m_engine);
121  std::swap(m_seedbaricenter, x.m_seedbaricenter);
122  std::swap(m_randomFixed, x.m_randomFixed);
123  std::swap(m_randomSignature, x.m_randomSignature);
124  std::swap(m_deads, x.m_deads);
125  m_sensitivity.swap(x.m_sensitivity);
126  std::swap(m_bbox, x.m_bbox);
127  std::swap(m_final_sensitivity, x.m_final_sensitivity);
128 
130 }
134 void
136 
137  bool built = true;
138 
139  //input
140  built = (built && createPortIn<MimmoSharedPointer<MimmoObject>, CreateSeedsOnSurface>(this, &mimmo::CreateSeedsOnSurface::setGeometry,M_GEOM, true));
141  built = (built && createPortIn<darray3E, CreateSeedsOnSurface>(this, &mimmo::CreateSeedsOnSurface::setSeed, M_POINT));
142  built = (built && createPortIn<dmpvector1D*, CreateSeedsOnSurface>(this, &mimmo::CreateSeedsOnSurface::setSensitivityMap, M_FILTER));
143 
144  //output
145  built = (built && createPortOut<dvecarr3E, CreateSeedsOnSurface>(this, &mimmo::CreateSeedsOnSurface::getPoints, M_COORDS));
146  built = (built && createPortOut<long, CreateSeedsOnSurface>(this, &mimmo::CreateSeedsOnSurface::getRandomSignature, M_VALUELI ));
147 
148  m_arePortsBuilt = built;
149 };
150 
155 int
157  return m_nPoints;
158 };
159 
164 dvecarr3E
166  return m_points;
167 };
168 
173 CSeedSurf
175  return m_engine;
176 };
177 
178 
183 int
185  return static_cast<int>(m_engine);
186 };
187 
194 darray3E
196  return m_seed;
197 }
198 
204 bool
206  return m_seedbaricenter;
207 };
208 
209 
214 double
216  return m_minDist;
217 }
218 
219 
225 bool
227  return m_randomFixed;
228 };
229 
236 long
238  return long(m_randomSignature);
239 }
240 
245 void
247  m_nPoints = std::max(val,0);
248 }
249 
254 void
256  m_engine = eng;
257 }
258 
263 void
265  if(eng <0 || eng >2) eng = 2;
266  setEngineENUM(static_cast<CSeedSurf>(eng));
267 }
268 
275 void
277  m_seed = seed;
278 }
279 
285 void
287  m_seedbaricenter = flag;
288 }
289 
296 void
298  if(geo == nullptr) return;
299  if(geo->getType() != 1) return;
300 
302  //using the following method to clear it up first any previous geometry retained in local bbox member
303  m_bbox->setGeometries(std::vector<MimmoSharedPointer<MimmoObject> >(1,geo));
304 }
305 
306 
315 void
317  m_randomFixed = fix;
318 }
319 
327 void
329  m_randomSignature = signature;
330 }
331 
338 void
340  if(!field) return;
341  m_sensitivity = *field;
342 }
343 
347 void
349  m_points.clear();
350  m_nPoints = 0;
351  m_minDist = 0.0;
352  m_seed = {{0.0,0.0,0.0}};
353  m_engine = CSeedSurf::CARTESIANGRID;
354  m_seedbaricenter = false;
355  m_randomFixed = false;
356  m_randomSignature =1;
357  m_deads.clear();
358  m_sensitivity.clear();
359  m_final_sensitivity.clear();
360 }
361 
365 void
367 
368  solve(false);
369 }
370 
375 void
377 
378  plotCloud(m_outputPlot, m_name + "Cloud", getId(), true );
379 }
380 
385 void
387 
388  if(getGeometry() == nullptr){
389  (*m_log)<<"Error in " + m_name + " : nullptr pointer to linked geometry found"<<std::endl;
390  throw std::runtime_error(m_name + "nullptr pointer to linked geometry found");
391  }
392 
393  if(getGeometry()->getInfoSyncStatus() != mimmo::SyncStatus::SYNC) getGeometry()->buildPatchInfo();
394 
395 #if MIMMO_ENABLE_MPI
396  int ncells = getGeometry()->getNGlobalCells();
397 #else
398  int ncells = getGeometry()->getNCells();
399 #endif
400  if(ncells == 0){
401  (*m_log)<<"Error in " + m_name + " : globally empty surface found, impossible to seed points "<<std::endl;
402  throw std::runtime_error(m_name + " : globally empty surface found, impossible to seed points ");
403  }
404  //clear the points
405  m_points.clear();
406  //evaluate the oriented bounding box of the 3D surface (geometry already provided to the box in setGeometry method)
407  m_bbox->setOBBStrategy(OBBStrategy::MINVOL);
408  m_bbox->execute();
409  if(m_seedbaricenter) m_seed = m_bbox->getOrigin();
410  //check and fix it up the sensitivity field attached
411  checkField();
412  normalizeField();
413 
414  //choose the engine and seed the points.
415  switch(m_engine){
416  case CSeedSurf::RANDOM :
417  solveRandom(debug);
418  break;
419 
420  case CSeedSurf::LEVELSET :
421  solveLSet(debug);
422  break;
423 
425  solveGrid(debug);
426  break;
427 
428  default: //never been reached
429  break;
430  }
431 };
432 
441 void
442 CreateSeedsOnSurface::solveLSet(bool debug){
443 
444 #if MIMMO_ENABLE_MPI
445  if(m_nprocs > 1){
446  //Levelset strategy not available in MPI multirank.
447  bitpit::log::Priority oldP = m_log->getPriority();
448  m_log->setPriority(bitpit::log::Priority::NORMAL);
449  (*m_log)<<"Warning in "<<m_name<<" : LevelSet option is not available in MPI version with np > 1. Switch to another engine."<<std::endl;
450  m_log->setPriority(oldP);
451  return;
452  }
453 #endif
454 
455  if(debug) (*m_log)<<m_name<<" : started LevelSet engine"<<std::endl;
456 
457  dvecarr3E initList;
458  m_deads.clear();
459  m_deads.reserve(m_nPoints);
460 
461  //understand if the class is a pure triangulation or not
462  MimmoSharedPointer<MimmoObject> workgeo;
463  dmpvector1D * worksensitivity = nullptr;
464  if(!checkTriangulation()){
465  workgeo = createTriangulation();
466  worksensitivity = &m_sensitivity_triangulated;
467  }else{
468  workgeo = getGeometry();
469  worksensitivity = &m_sensitivity;
470  }
471 
472  workgeo->updateAdjacencies();
473  workgeo->buildSkdTree();
474  bitpit::SurfUnstructured * tri = static_cast<bitpit::SurfUnstructured * >(workgeo->getPatch());
475 
476 
477  //find the nearest mesh vertex to the seed point, passing from the nearest cell
478  long candidateIdv = bitpit::Vertex::NULL_ID;
479  {
480  double distance = std::numeric_limits<double>::max();
481  long cellId = bitpit::Cell::NULL_ID;
482  darray3E pseed;
483  skdTreeUtils::projectPoint(1, &m_seed, workgeo->getSkdTree(), &pseed, &cellId, distance);
484 
485  if(cellId != bitpit::Cell::NULL_ID){
486  bitpit::ConstProxyVector<long> cellVids = tri->getCell(cellId).getVertexIds();
487  double mindist = std::numeric_limits<double>::max();
488  double wdist;
489  for(long idV : cellVids){
490  wdist = norm2(pseed - workgeo->getVertexCoords(idV));
491  if(wdist < mindist){
492  candidateIdv = idV;
493  mindist = wdist;
494  }
495  }
496  }
497  }
498 
499  if(candidateIdv != bitpit::Vertex::NULL_ID) m_deads.push_back(candidateIdv);
500 
501  int deadSize = m_deads.size();
502  if(debug) (*m_log)<<m_name<<" : projected seed point"<<std::endl;
503 
504  std::unordered_map<long,long> invConn = getInverseConn(*(workgeo->getPatch()));
505  if(debug) (*m_log)<<m_name<<" : created geometry inverse connectivity"<<std::endl;
506 
507  while(deadSize < m_nPoints && deadSize != 0){
508 
509  dmpvector1D field;
510  field.initialize(workgeo, MPVLocation::POINT, std::numeric_limits<double>::max());
511  for(const auto & dd : m_deads) field[dd] = 0.0;
512 
513  solveEikonal(1.0,1.0, *(workgeo->getPatch()), invConn, field);
514 
515  //modulate field with current working sensitivity field
516  auto itSE=worksensitivity->end();
517  for(auto itSX =worksensitivity->begin(); itSX != itSE; ++itSX){
518  field[itSX.getId()] *= *itSX;
519  }
520 
521  double maxField= 0.0;
522  long candMax =0;
523  auto itE=field.end();
524  for(auto itX =field.begin(); itX != itE; ++itX){
525  if(*itX > maxField){
526  maxField = *itX;
527  candMax = itX.getId();
528  }
529  }
530 
531  m_deads.push_back(candMax);
532 
533  deadSize = m_deads.size();
534  if(debug) (*m_log)<<m_name<<" : geodesic distance field for point "<<deadSize-1<<" found"<<std::endl;
535  }
536 
537  //store result in m_points.
538  m_points.clear();
539  m_final_sensitivity.clear();
540  m_points.reserve(deadSize);
541  m_final_sensitivity.reserve(deadSize);
542  for(const auto & val: m_deads){
543  m_points.push_back(tri->getVertexCoords(val));
544  m_final_sensitivity.push_back(worksensitivity->at(val));
545  }
546 
547  m_minDist = std::numeric_limits<double>::max();
548 
549  for(int i=0; i<deadSize; ++i){
550  for(int j=i+1; j<deadSize; ++j){
551  m_minDist = std::min(m_minDist,norm2(m_points[i] - m_points[j]));
552  }
553  }
554 
555  m_deads.clear();
556  m_sensitivity_triangulated.clear();
557  if(debug) (*m_log)<<m_name<<" : distribution of point successfully found w/ LevelSet engine "<<std::endl;
558 };
559 
567 void
568 CreateSeedsOnSurface::solveGrid(bool debug){
569 
570  //MPI version: all ranks do the same thing on indipendent but all-the-same list of m_points
571  if(debug) (*m_log)<<m_name<<" : started CartesianGrid engine"<<std::endl;
572 
573  //find a suitable dimension set for cartesian grid so that its vertices will
574  //represent an enough populated list of candidate points.
575  iarray3E dim = {{1,1,1}};
576  darray3E span = m_bbox->getSpan();
577  m_minDist = norm2(span)/2.0;
578  double perim = span[0]+span[1]+span[2];
579  {
580  for(int i=0; i<3; ++i){
581  dim[i] = std::max(dim[i], int(span[i]*m_nPoints/perim + 0.5));
582  }
583  }
584 
585  dim += iarray3E({{1,1,1}});
586 
587  //create a lattice on it
588  mimmo::Lattice * grid = new Lattice();
589  grid->setShape(mimmo::ShapeType::CUBE);
590  grid->setOrigin(m_bbox->getOrigin());
591  grid->setSpan(m_bbox->getSpan());
592  grid->setRefSystem(m_bbox->getAxes());
593  grid->setDimension(dim);
594 // grid->setPlotInExecution(true);
595 // grid->exec();
596  grid->execute();
597 
598  //get cell centroids
599  dvecarr3E centroids = grid->getGlobalCellCentroids();
600 
601  if(debug) (*m_log)<<m_name<<" : build volume cartesian grid wrapping 3D surface"<<std::endl;
602 
603  getGeometry()->buildSkdTree();
604 
605  //project centroids on surface. For MPI use shared list algorithm
606  dvecarr3E projCentroids(centroids.size());
607  dvector1D projSensitivity(centroids.size(), 1.0);
608  {
609  livector1D ids(centroids.size());
610 #if MIMMO_ENABLE_MPI
611  ivector1D ranks(centroids.size(),-1);
612  int currentRank = getRank();
613  skdTreeUtils::projectPointGlobal(int(centroids.size()), centroids.data(), getGeometry()->getSkdTree(), projCentroids.data(), ids.data(), ranks.data(), m_minDist, true); //called SHARED
614 #else
615  skdTreeUtils::projectPoint(int(centroids.size()), centroids.data(), getGeometry()->getSkdTree(), projCentroids.data(), ids.data(), m_minDist);
616 #endif
617  //get list of interpolated sensitivities on the proj points.
618  //Beware, MPI version will work only on proj points lying on a cell internal to rank, otherwise will leave
619  //sensitivity to the unitary default value.
620  int count(0);
621  for(darray3E & p : projCentroids){
622 #if MIMMO_ENABLE_MPI
623  if(currentRank == ranks[count])
624 #endif
625  {
626  bitpit::ConstProxyVector<long> cellVids = getGeometry()->getPatch()->getCell(ids[count]).getVertexIds();
627  dvecarr3E listv;
628  listv.reserve(cellVids.size());
629  for(long id: cellVids){
630  listv.push_back(getGeometry()->getVertexCoords(id));
631  }
632  dvector1D lambdas;
633  bitpit::CGElem::computeGeneralizedBarycentric(p, listv, lambdas);
634  projSensitivity[count] = 0;
635  int ccvids(0);
636  for(long id: cellVids){
637  projSensitivity[count] += lambdas[ccvids] * m_sensitivity[id];
638  ++ccvids;
639  }
640  }
641  ++count;
642  }
643 
644 #if MIMMO_ENABLE_MPI
645  //reduce properly list of sensitivities for multi ranks processing
646  MPI_Allreduce(MPI_IN_PLACE, projSensitivity.data(), int(projSensitivity.size()), MPI_DOUBLE, MPI_MIN, m_communicator);
647 #endif
648  }
649 
650  if(debug) (*m_log)<<m_name<<" : found grid cell centers in the narrow band of 3D surface and projected them on it "<<std::endl;
651 
652 
653  //SORT THE CURRENT POINT LIST FROM NEAREST TO FARTHEST from m_seed
654  //rearrange the list, putting the most nearest point to the seed on top
655  // and decimate points up to desired value.
656  {
657  std::vector<std::pair<double, int>> sortContainer;
658  sortContainer.reserve(projCentroids.size());
659  int cc(0);
660  for(darray3E & p : projCentroids){
661  sortContainer.push_back(std::make_pair(norm2(m_seed - p), cc));
662  ++cc;
663  }
664  std::sort(sortContainer.begin(), sortContainer.end());
665 
666  dvecarr3E tempP(projCentroids.size());
667  dvector1D tempS(projCentroids.size());
668  cc=0;
669  for(std::pair<double,int> & val : sortContainer){
670  tempP[cc] = projCentroids[val.second];
671  tempS[cc] = projSensitivity[val.second];
672  ++cc;
673  }
674  std::swap(projCentroids, tempP);
675  std::swap(projSensitivity, tempS);
676  }
677 
678  decimatePoints(projCentroids, projSensitivity);
679  if(debug) (*m_log)<<m_name<<" : candidates decimated "<<std::endl;
680 
681  //store results
682  std::swap(m_points, projCentroids);
683  std::swap(m_final_sensitivity, projSensitivity);
684  if(debug) (*m_log)<<m_name<<" : distribution of point successfully found w/ CartesianGrid engine "<<std::endl;
685 
686  delete grid;
687 };
688 
689 
695 void
696 CreateSeedsOnSurface::solveRandom(bool debug){
697 
698  if(debug) (*m_log)<<m_name<<" : started Random engine"<<std::endl;
699 
700  darray3E span = m_bbox->getSpan();
701  m_minDist = norm2(span)/ 2.0;
702  //fill the oriented bounding box of the figure randomly with max of 100 and 5*m_nPoints
703  dvecarr3E centroids;
704  {
705  dmatrix33E axes = m_bbox->getAxes();
706  darray3E minP = m_bbox->getOrigin();
707  for(int i=0; i<3; ++i) {minP += - 0.5*span[i]*axes[i];}
708 
709  if (!m_randomFixed){
710  m_randomSignature = uint32_t(time(nullptr));
711  }
712 #if MIMMO_ENABLE_MPI
713  MPI_Bcast(&m_randomSignature, 1, MPI_UINT32_T, 0, m_communicator);
714 #endif
715  std::mt19937 rgen; //based on marsenne-twister random number generator
716  rgen.seed(m_randomSignature);
717  double dist_rgen = double(rgen.max()-rgen.min());
718  double beg_rgen = double(rgen.min());
719 
720  int nTent = 5*m_nPoints;
721  centroids.resize(nTent, minP);
722 
723  for(int i = 0; i<nTent; ++i){
724  for(int j=0; j<3; ++j){
725  double valrand = (double(rgen())-beg_rgen)/dist_rgen;
726  centroids[i] += valrand * span[j]*axes[j];
727  }
728  }
729  }
730 
731  if(debug) (*m_log)<<m_name<<" : found random points"<<std::endl;
732  getGeometry()->buildSkdTree();
733 
734  //project centroids on surface. For MPI use shared list algorithm
735  dvecarr3E projCentroids(centroids.size());
736  dvector1D projSensitivity(centroids.size(), 1.0);
737  {
738  livector1D ids(centroids.size(), bitpit::Cell::NULL_ID);
739 #if MIMMO_ENABLE_MPI
740  ivector1D ranks(centroids.size(),-1);
741  int currentRank = getRank();
742  skdTreeUtils::projectPointGlobal(int(centroids.size()), centroids.data(), getGeometry()->getSkdTree(), projCentroids.data(), ids.data(), ranks.data(), m_minDist, true); //called SHARED
743 #else
744  skdTreeUtils::projectPoint(int(centroids.size()), centroids.data(), getGeometry()->getSkdTree(), projCentroids.data(), ids.data(), m_minDist);
745 #endif
746  //get list of interpolated sensitivities on the proj points.
747  //Beware, MPI version will work only on proj points lying on a cell internal to rank, otherwise will leave
748  //sensitivity to the unitary default value.
749  int count(0);
750  for(darray3E & p : projCentroids){
751 #if MIMMO_ENABLE_MPI
752  if(currentRank == ranks[count])
753 #endif
754  {
755  bitpit::ConstProxyVector<long> cellVids = getGeometry()->getPatch()->getCell(ids[count]).getVertexIds();
756  dvecarr3E listv;
757  listv.reserve(cellVids.size());
758  for(long id: cellVids){
759  listv.push_back(getGeometry()->getVertexCoords(id));
760  }
761  std::vector<double> lambdas;
762  bitpit::CGElem::computeGeneralizedBarycentric(p, listv, lambdas);
763  projSensitivity[count] = 0;
764  int ccvids(0);
765  for(long id: cellVids){
766  projSensitivity[count] += lambdas[ccvids] * m_sensitivity[id];
767  ++ccvids;
768  }
769  }
770  ++count;
771  }
772 
773 #if MIMMO_ENABLE_MPI
774  //reduce properly list of sensitivities for multi ranks processing
775  MPI_Allreduce(MPI_IN_PLACE, projSensitivity.data(), int(projSensitivity.size()), MPI_DOUBLE, MPI_MIN, m_communicator);
776 #endif
777  }
778 
779  if(debug) (*m_log)<<m_name<<" : projected points onto 3D surface "<<std::endl;
780 
781 
782  //SORT THE CURRENT POINT LIST FROM NEAREST TO FARTHEST from m_seed
783  //rearrange the list, putting the most nearest point to the seed on top
784  // and decimate points up to desired value.
785  {
786  std::vector<std::pair<double, int>> sortContainer;
787  sortContainer.reserve(projCentroids.size());
788  int cc(0);
789  for(darray3E & p : projCentroids){
790  sortContainer.push_back(std::make_pair(norm2(m_seed - p), cc));
791  ++cc;
792  }
793  std::sort(sortContainer.begin(), sortContainer.end());
794 
795  dvecarr3E tempP(projCentroids.size());
796  dvector1D tempS(projCentroids.size());
797  cc=0;
798  for(std::pair<double,int> & val : sortContainer){
799  tempP[cc] = projCentroids[val.second];
800  tempS[cc] = projSensitivity[val.second];
801  ++cc;
802  }
803  std::swap(projCentroids, tempP);
804  std::swap(projSensitivity, tempS);
805  }
806 
807  decimatePoints(projCentroids, projSensitivity);
808  if(debug) (*m_log)<<m_name<<" : candidates decimated "<<std::endl;
809 
810  //store results
811  std::swap(m_points, projCentroids);
812  std::swap(m_final_sensitivity, projSensitivity);
813  if(debug) (*m_log)<<m_name<<" : distribution of point successfully found w/ Random engine "<<std::endl;
814 };
815 
816 
824 void
825 CreateSeedsOnSurface::plotCloud(std::string dir, std::string file, int counter, bool binary){
826 
827  // m_points is shared collectively among ranks
828  if(m_points.empty()) return;
829 
830 #if MIMMO_ENABLE_MPI
831  //let master rank do the writing on file
832  if(m_rank == 0)
833 #endif
834  {
835 
836  bitpit::VTKFormat codex = bitpit::VTKFormat::ASCII;
837  if(binary){codex=bitpit::VTKFormat::APPENDED;}
838 
839  ivector1D conn(m_nPoints);
840  for(int i=0; i<m_nPoints; i++){
841  conn[i] = i;
842  }
843 
844  m_final_sensitivity.resize(m_nPoints, 1.0);
845  ivector1D labels(m_nPoints);
846  for(int i=0; i<m_nPoints; ++i){
847  labels[i] = i;
848  }
849 
850  bitpit::VTKUnstructuredGrid vtk(dir, file, bitpit::VTKElementType::VERTEX);
851  vtk.setGeomData( bitpit::VTKUnstructuredField::POINTS, m_points) ;
852  vtk.setGeomData( bitpit::VTKUnstructuredField::CONNECTIVITY, conn) ;
853  vtk.setDimensions( m_nPoints, m_nPoints);
854  vtk.addData("sensitivity", bitpit::VTKFieldType::SCALAR, bitpit::VTKLocation::POINT, m_final_sensitivity);
855  vtk.addData("labels", bitpit::VTKFieldType::SCALAR, bitpit::VTKLocation::POINT,labels);
856  vtk.setCodex(codex);
857  if(counter>=0){vtk.setCounter(counter);}
858 
859  vtk.write();
860  }
861 #if MIMMO_ENABLE_MPI
862  MPI_Barrier(m_communicator);
863 #endif
864 }
865 
875 void
876 CreateSeedsOnSurface::decimatePoints(dvecarr3E & list, dvector1D & sens){
877 
878  int listS = list.size();
879 
880  //reference all coordinate list to the seed candidate 0;
881  // modulate the coordinate of each point with its respective sensitivity.
882  dvecarr3E listRefer(listS);
883  for(int j=0; j<listS; ++j){
884  listRefer[j] = (list[j] - list[0])*sens[j];
885  }
886 
887  bitpit::KdTree<3,darray3E,long> kdT;
888  //build a kdtree of points
889  //TODO Why : + kdT.MAXSTK ?
890  kdT.nodes.resize(listS + kdT.MAXSTK);
891  long label=0;
892  for(auto & val : listRefer ){
893  kdT.insert(&val, label);
894  ++label;
895  }
896 
897  long candidate = 0; //starting seed;
898 
899  //use kdTree to search points within a radius of m_minDist from the seed.
900  // if no matches are found, choose randomly the next candidate
901  livector1D neighs, excl,effective;
902  std::set<long> visited;
903  std::map<double, long> chooseCand;
904  livector1D finalCandidates;
905 
906  finalCandidates.reserve(m_nPoints);
907  int candSize = finalCandidates.size();
908  while( candSize < m_nPoints){
909 
910  finalCandidates.push_back(candidate);
911  candSize++;
912  visited.insert(candidate);
913  excl.insert(excl.end(), visited.begin(), visited.end());
914  kdT.hNeighbors(&listRefer[candidate], m_minDist, &neighs, & excl );
915 
916  visited.insert(neighs.begin(), neighs.end());
917 
918  int sizeN = visited.size();
919  neighs.clear();
920  excl.clear();
921 
922 
923  while(sizeN == listS){
924  m_minDist *= 0.9;
925  visited.clear();
926  visited.insert(finalCandidates.begin(), finalCandidates.end());
927  for(const auto & ind : finalCandidates){
928  excl.insert(excl.end(), visited.begin(), visited.end());
929  kdT.hNeighbors(&listRefer[ind], m_minDist, &neighs, & excl );
930  visited.insert(neighs.begin(), neighs.end());
931  }
932  sizeN = visited.size();
933  excl.clear();
934  neighs.clear();
935  }
936 
937  effective.reserve(list.size() - visited.size());
938  for(int i=0; i< listS; ++i){
939  if( !visited.count(i) )
940  effective.push_back(i);
941  }
942 
943  for(const auto & ind : effective){
944  dvector1D norms(finalCandidates.size());
945  int countNorms=0;
946  for(const auto & indEx: finalCandidates){
947  norms[countNorms] = norm2(list[ind] - list[indEx]);
948  ++countNorms;
949  }
950 
951  double norm = 0.0, variance=0.0;
952  for(auto &val : norms) norm += val;
953  norm /= double(norms.size());
954  for(auto &val : norms) val = std::abs(val/norm - 1.0);
955  maxval(norms, variance);
956  norm /= std::pow((variance+1.0),2);
957 
958  chooseCand[norm] = ind;
959  }
960 
961  candidate = (chooseCand.rbegin())->second;
962 
963  effective.clear();
964  chooseCand.clear();
965  }
966 
967  dvecarr3E resultP(finalCandidates.size());
968  dvector1D resultS(finalCandidates.size());
969  int counter = 0;
970  for(long index : finalCandidates){
971  resultP[counter] = list[index];
972  resultS[counter] = sens[index];
973  ++counter;
974  }
975  std::swap(list, resultP);
976  std::swap(sens, resultS);
977 };
978 
979 
993 double
994 CreateSeedsOnSurface::updateEikonal(double g, double s, long tVert,long tCell, bitpit::PatchKernel &tri, std::unordered_map<long int, short int> &flag, dmpvector1D & field){
995 
996  BITPIT_UNUSED(s);
997 
998  livector1D oneRing;
999  long I, U, V, W;
1000 
1001  int k, m;
1002 
1003  int select = -1;
1004  double value(std::numeric_limits<double>::max());
1005  double dVU, dVW, dWU, dVP;
1006  std::array<double,3> eVU, eVW, eWU, eVP, P;
1007 
1008 
1009  double a, b, c, A, B, C, K, discr ;
1010  double phi_U, phi_W, phi_P;
1011  int discrType;
1012 
1013  double xi1, xi2;
1014  double tempVal1, tempVal2;
1015 
1016  //get current field value of the node;
1017  value = std::abs(field[tVert]);
1018 
1019  V = tVert;
1020 
1021  {
1022  // find 1-Ring cells around target node
1023  bitpit::Cell & targetCell = tri.getCell(tCell);
1024  int locVert = targetCell.findVertex(tVert);
1025  if(locVert == bitpit::Vertex::NULL_ID) return value;
1026  oneRing = tri.findCellVertexOneRing(tCell, locVert);
1027  }
1028 
1029  // Loop over cells in the 1-Ring --------------------------------------------------- //
1030  for (auto && oneIndex : oneRing) {
1031 
1032  // Cell data get id of vertex composing triangular cell
1033  I = oneIndex;
1034  bitpit::Cell & cellI = tri.getCell(I);
1035  long * connCellI = cellI.getConnect();
1036  k = cellI.findVertex(V);
1037  k = (k + 1) % cellI.getVertexCount();
1038  U = connCellI[k];
1039  m = (k + 1) % cellI.getVertexCount();
1040  W = connCellI[m];
1041 
1042  // discriminate case, according to flag vector of deads, alives and far-aways
1043  if ((flag[U] == 0) && (flag[W] == 0)) {
1044  select = 2;
1045  }
1046  else {
1047  if ((flag[U] == 0) || (flag[W] == 0)) {
1048  select = 1;
1049  if (flag[W] == 0) {
1050  U = W;
1051  }
1052  }
1053  else {
1054  select = 0;
1055  }
1056  }
1057 
1058  //Compute solution to the 2D Eikonal equation
1059  switch (select){
1060 
1061  case 1 : // with 1 dead node
1062  eVU = tri.getVertexCoords(V) - tri.getVertexCoords(U);
1063  dVU = norm2(eVU);
1064  value = std::min(value, std::abs(field[U]) + g*dVU);
1065  break;
1066 
1067  case 2 : // with 2 dead nodes
1068 
1069  eVW = tri.getVertexCoords(V) - tri.getVertexCoords(W);
1070  dVW = norm2(eVW);
1071  eVW = eVW/dVW;
1072  eVU = tri.getVertexCoords(V) - tri.getVertexCoords(U);
1073  dVU = norm2(eVU);
1074  eVU = eVU/dVU;
1075  eWU = tri.getVertexCoords(W) - tri.getVertexCoords(U);
1076  dWU = norm2(eWU);
1077  eWU = eWU/dWU;
1078 
1079  // Coeffs -------------------------------------------------------------------- //
1080  phi_U = std::abs(field[U]);
1081  phi_W = std::abs(field[W]);
1082  K = phi_W - phi_U;
1083  a = pow(dWU, 2);
1084  b = -dWU*dVU*dotProduct(eWU, eVU);
1085  c = pow(dVU, 2);
1086  A = a*(pow(K, 2) - a);
1087  B = b*(pow(K, 2) - a);
1088  C = (pow(K, 2)*c - pow(b, 2));
1089  discr = pow(B, 2) - A*C;
1090 
1091  // Find optimal solution ----------------------------------------------------- //
1092  discrType = (discr < -1.0e-12) + 2*(std::abs(A) > 1.0e-12) +3*((std::abs(A) < 1.0e-12) && (std::abs(A) >= 0.0)) -1;
1093 
1094  switch(discrType){
1095  case 1: //2 distinct solutions
1096  discr = std::abs(discr);
1097 
1098  xi1 = (-B - sqrt(discr))/A;
1099  xi2 = (-B + sqrt(discr))/A;
1100 
1101  // Restriction of solutions onto [0, 1]
1102  xi1 = std::min(1.0, std::max(0.0, xi1));
1103  xi2 = std::min(1.0, std::max(0.0, xi2));
1104 
1105  // Solution #1
1106  P = (1.0 - xi1) * tri.getVertexCoords(U) + xi1 * tri.getVertexCoords(W);
1107  eVP = tri.getVertexCoords(V) - P;
1108  dVP = norm2(eVP);
1109  eVP = eVP/dVP;
1110  phi_P = (1.0 - xi1) * phi_U + xi1 * phi_W;
1111  tempVal1 = phi_P + g * dVP;
1112 
1113  // Solution #2
1114  P = (1.0 - xi2) * tri.getVertexCoords(U) + xi2 * tri.getVertexCoords(W);
1115  eVP = tri.getVertexCoords(V) - P;
1116  dVP = norm2(eVP);
1117  eVP = eVP/dVP;
1118  phi_P = (1.0 - xi2) * phi_U + xi2 * phi_W;
1119  tempVal2 = phi_P + g * dVP;
1120 
1121  break;
1122 
1123  case 2: // coincident solutions
1124  discr = std::abs(discr);
1125 
1126  // Solution #1
1127  P = tri.getVertexCoords(U);
1128  eVP = tri.getVertexCoords(V) - P;
1129  dVP = norm2(eVP);
1130  eVP = eVP/dVP;
1131  phi_P = phi_U;
1132  tempVal1 = phi_P + g*dVP;
1133 
1134  // Solution #2
1135  P = tri.getVertexCoords(W);
1136  eVP = tri.getVertexCoords(V) - P;
1137  dVP = norm2(eVP);
1138  eVP = eVP/dVP;
1139  phi_P = phi_W;
1140  tempVal2 = phi_P + g*dVP;
1141 
1142  break;
1143 
1144  default: //no real solutions indeed
1145  tempVal1 = value;
1146  tempVal2 = value;
1147  break;
1148  }//end on switch discrType
1149 
1150  // Update solution for case 2:
1151  value = std::min(value, std::min(tempVal1, tempVal2));
1152  break;
1153 
1154  default: //doing really nothing. No dead nodes to hang out.
1155  break;
1156  }//end switch select
1157 
1158  } //loop on oneRing
1159 
1160  return(value);
1161 };
1162 
1174 void
1175 CreateSeedsOnSurface::solveEikonal(double g, double s,bitpit::PatchKernel &tri, std::unordered_map<long,long> & invConn, dmpvector1D & field ){
1176 
1177  // declare total size and support structure
1178  long N(tri.getVertexCount());
1179  std::unordered_map<long int, short int> active;
1180 
1181  std::unordered_map<long, int> vmap;
1182  int countV = 0;
1183  for(const auto & vert: tri.getVertices()){
1184  vmap[vert.getId()] = countV;
1185  ++countV;
1186  }
1187 
1188  { //FLAG DEAD/ALIVE/FAR-AWAY VERTICES
1189 
1190  long myId;
1191  bool check;
1192  std::set<long> neighs;
1193  std::set<long>::iterator it, itend;
1194 
1195  //set active vector size and mark its position with original geometry ids
1196  active.reserve(N);
1197  for ( const auto &vertex : tri.getVertices() ){
1198  myId = vertex.getId() ;
1199  active[myId] = 2 ;
1200  }
1201 
1202  //fill active vector
1203  for ( const auto &vertex : tri.getVertices() ){
1204  myId = vertex.getId();
1205 
1206  // Dead vertices
1207  if( isDeadFront(myId) ){
1208  active[myId] = 0;
1209 
1210  }else{
1211 
1212  //loop over neighbors
1213  check = false;
1214  neighs = findVertexVertexOneRing(tri,invConn[myId], myId);
1215  it = neighs.begin();
1216  itend = neighs.end();
1217  while(!check && it !=itend){
1218 
1219  check = s*field[*it] >= 0.0 && field[*it] < std::numeric_limits<double>::max();
1220  ++it;
1221  };
1222 
1223  active[myId] = 2 - (int) check;
1224  }
1225  }
1226  }
1227 
1228 
1229  { // Construct min heap data structure
1230  long m(0), I(0), myId, J ;
1231  double value ;
1232 
1233  std::set<long> neighs;
1234  std::set<long>::iterator it,itbeg, itend;
1235 
1236  std::vector<std::array<int,2>> map(N), *mapPtr = &map;
1237 
1238  bitpit::MinPQueue<double, long> heap(N, true, mapPtr);
1239 
1240  // Inserting alive vertices in the heap
1241 
1242  for(const auto & vertex : tri.getVertices()){
1243 
1244  myId = vertex.getId();
1245  if(active[myId] == 1) {
1246  //assign a value to your actual vertex
1247  value = updateEikonal(s, g, myId, invConn[myId], tri, active, field);
1248 
1249  //store it into heap
1250  map[m][0] = vmap[myId];
1251  map[vmap[myId]][1] = m;
1252 
1253  heap.keys[m] = value;
1254  heap.labels[m] = myId;
1255 
1256  //update counter
1257  ++m;
1258  }
1259  ++I;
1260  }//next vertex
1261 
1262  // Build min-heap
1263  heap.heap_size = m;
1264  heap.buildHeap();
1265 
1266 
1267  // FAST MARCHING //
1268  while (heap.heap_size > 0) {
1269 
1270  // Extract root from min-heap
1271  heap.extract(value, myId);
1272 
1273  // Update level set value
1274  //value = s*updateEikonal(s, g, myId, invConn[myId], active);
1275  field[myId] = value;
1276 
1277  // Update flag to dead;
1278  active[myId] = 0;
1279 
1280  //update neighbours
1281  neighs = findVertexVertexOneRing(tri, invConn[myId], myId);
1282  itbeg = neighs.begin();
1283  itend = neighs.end();
1284 
1285  for(it=itbeg; it != itend; ++it) {
1286  J = *it;
1287 
1288  if(active[J] == 1){
1289 
1290  //update local value;
1291  value = updateEikonal(s,g,J,invConn[J], tri, active, field);
1292 
1293  //update its value in the min-heap
1294  I = vmap[J];
1295  heap.modify( map[I][1],value,J );
1296 
1297  }else if( active[J] == 2){
1298 
1299  //update local value;
1300  value = updateEikonal(s,g,J, invConn[J],tri, active, field);
1301 
1302  //reflag vertex as alive vertex
1303  active[J] = 1;
1304  I = vmap[J];
1305 
1306  // Insert neighbor into the min heap
1307  map[heap.heap_size][0] = I ;
1308  map[I][1] = heap.heap_size;
1309 
1310  heap.insert(value, J);
1311  }
1312  }
1313  }//end while
1314  };
1315 };
1316 
1326 std::unordered_map<long,long>
1327 CreateSeedsOnSurface::getInverseConn(bitpit::PatchKernel & geo){
1328 
1329  std::unordered_map<long,long> invConn ;
1330 
1331  long cellId;
1332  for(const auto &cell : geo.getCells()){
1333  cellId = cell.getId();
1334  auto vList = cell.getVertexIds();
1335  for(const auto & idV : vList) invConn[idV] = cellId;
1336  }
1337 
1338  return(invConn);
1339 };
1340 
1346 bool CreateSeedsOnSurface::isDeadFront(const long int label){
1347 
1348  livector1D::iterator got = std::find(m_deads.begin(), m_deads.end(), label);
1349  if(got == m_deads.end()) return false;
1350  return true;
1351 }
1352 
1360 std::set<long>
1361 CreateSeedsOnSurface::findVertexVertexOneRing(bitpit::PatchKernel &geo, const long & cellId, const long & vertexId){
1362 
1363  std::set<long> result;
1364  bitpit::Cell &cell = geo.getCell(cellId);
1365 
1366  int loc_target = cell.findVertex(vertexId);
1367  if(loc_target == bitpit::Vertex::NULL_ID) return result;
1368 
1369  livector1D list = geo.findCellVertexOneRing(cellId, loc_target);
1370 
1371  for(const auto & index : list){
1372  bitpit::Cell & cell = geo.getCell(index);
1373  auto vList = cell.getVertexIds();
1374  for(const auto & idV : vList){
1375  result.insert(idV);
1376  }
1377  }
1378 
1379  result.erase(vertexId);
1380  return result;
1381 }
1382 
1388 void
1389 CreateSeedsOnSurface::absorbSectionXML(const bitpit::Config::Section & slotXML, std::string name ){
1390 
1391  BITPIT_UNUSED(name);
1392 
1393  BaseManipulation::absorbSectionXML(slotXML, name);
1394 
1395  if(slotXML.hasOption("NPoints")){
1396  std::string input = slotXML.get("NPoints");
1397  input = bitpit::utils::string::trim(input);
1398  int value = 0;
1399  if(!input.empty()){
1400  std::stringstream ss(input);
1401  ss >> value;
1402  value = std::max(value,0);
1403  }
1404  setNPoints(value);
1405  }
1406 
1407  if(slotXML.hasOption("Engine")){
1408  std::string input = slotXML.get("Engine");
1409  input = bitpit::utils::string::trim(input);
1410  int value = 2;
1411  if(!input.empty()){
1412  std::stringstream ss(input);
1413  ss >> value;
1414  value = std::min(std::max(value,0),2);
1415  }
1416  setEngine(value);
1417  }
1418 
1419 
1420  if(slotXML.hasOption("Seed")){
1421  std::string input = slotXML.get("Seed");
1422  input = bitpit::utils::string::trim(input);
1423  darray3E temp;
1424  temp.fill(0.0);
1425  if(!input.empty()){
1426  std::stringstream ss(input);
1427  ss >> temp[0]>>temp[1]>>temp[2];
1428  }
1429  setSeed(temp);
1430  }
1431 
1432  if(slotXML.hasOption("MassCenterAsSeed")){
1433  std::string input = slotXML.get("MassCenterAsSeed");
1434  input = bitpit::utils::string::trim(input);
1435  bool value = false;
1436  if(!input.empty()){
1437  std::stringstream ss(input);
1438  ss >> value;
1439  }
1440  setMassCenterAsSeed(value);
1441  }
1442 
1443  if(slotXML.hasOption("RandomFixed")){
1444  std::string input = slotXML.get("RandomFixed");
1445  input = bitpit::utils::string::trim(input);
1446  int value = -1;
1447  if(!input.empty()){
1448  std::stringstream ss(input);
1449  ss >> value;
1450  }
1451  setRandomFixed(value);
1452  }
1453 
1454 
1455 };
1456 
1462 void
1463 CreateSeedsOnSurface::flushSectionXML(bitpit::Config::Section & slotXML, std::string name){
1464 
1465  BITPIT_UNUSED(name);
1466 
1467  BaseManipulation::flushSectionXML(slotXML, name);
1468 
1469  if(m_nPoints != 0 ){
1470  slotXML.set("NPoints", std::to_string(m_nPoints));
1471  }
1472 
1473  int engint = getEngine();
1474  if(engint != 2 ){
1475  slotXML.set("Engine", std::to_string(engint));
1476  }
1477 
1478  darray3E seed = getSeed();
1479  if(norm2(seed) != 0.0 ){
1480 
1481  std::stringstream ss;
1482  ss<<std::scientific<<seed[0]<<'\t'<<seed[1]<<'\t'<<seed[2];
1483  slotXML.set("Seed", ss.str());
1484  }
1485 
1486  if(isSeedMassCenter() ){
1487  slotXML.set("MassCenterAsSeed", std::to_string(1));
1488  }
1489 
1490  long signat = getRandomSignature();
1491  if( signat != -1 && m_engine == mimmo::CSeedSurf::RANDOM){
1492  slotXML.set("RandomFixed", std::to_string(signat));
1493  }
1494 
1495 
1496 };
1497 
1507 
1508  if(getGeometry() == nullptr) return;
1509  dmpvector1D defaultField;
1510  defaultField.initialize(getGeometry(),MPVLocation::POINT, 1.0);
1511 
1512 // m_log->setPriority(bitpit::log::Verbosity::DEBUG);
1513  if(getGeometry() != m_sensitivity.getGeometry()){
1514  m_sensitivity = defaultField;
1515 // (*m_log)<<"warning in "<<m_name<<" : Not suitable data field connected. Reference geometry linked by the class and by MimmoPiercedvector field differs. Using default field"<<std::endl;
1516  }else if(m_sensitivity.getDataLocation() != MPVLocation::POINT){
1517  m_sensitivity = defaultField;
1518 // (*m_log)<<"warning in "<<m_name<<" : Wrong data field connected. Data Location of MimmoPiercedvector field is not referred geometry Vertex/Point. Using default field"<<std::endl;
1519  }else{
1520  if(!m_sensitivity.completeMissingData(0.0)){
1521  m_sensitivity = defaultField;
1522 // (*m_log)<<"warning in "<<m_name<<" : Not coherent data field connected. Data Ids of MimmoPiercedvector field are not aligned with geometry Vertex/Point field. Using default field"<<std::endl;
1523  }
1524  }
1525 // m_log->setPriority(bitpit::log::Verbosity::NORMAL);
1526 
1527 }
1528 
1529 
1535 
1536  double minSense=0.0,maxSense=0.0;
1537  minval(m_sensitivity.getRawDataAsVector(), minSense);
1538  maxval(m_sensitivity.getRawDataAsVector(), maxSense);
1539  double diff = maxSense - minSense;
1540 
1541 // m_log->setPriority(bitpit::log::Verbosity::DEBUG);
1542  if(std::isnan(minSense) || std::isnan(maxSense) || diff <= std::numeric_limits<double>::min()){
1543  (*m_log)<<"Warning in "<<m_name<<" : Not valid data of sensitivity field detected. Using default unitary field"<<std::endl;
1544  m_sensitivity.initialize(getGeometry(),MPVLocation::POINT, 1.0);
1545  }else{
1546  for(auto &val: m_sensitivity){
1547  val += -1.0*minSense;
1548  val /= diff;
1549  }
1550 
1551  }
1552 // m_log->setPriority(bitpit::log::Verbosity::NORMAL);
1553 }
1554 
1555 
1559 bool
1561  bool check = true;
1562  bitpit::PatchKernel::CellIterator it = getGeometry()->getPatch()->cellBegin();
1563  bitpit::PatchKernel::CellIterator itEnd = getGeometry()->getPatch()->cellEnd();
1564  while(check && it != itEnd){
1565  check = ( (*it).getType() == bitpit::ElementType::TRIANGLE );
1566  ++it;
1567  }
1568  return check;
1569 }
1570 
1577  //THIS METHOD IS MEANT TO WORK IN serial ONLY
1578  MimmoSharedPointer<MimmoObject> temp = getGeometry()->clone();
1579  m_sensitivity_triangulated = m_sensitivity;
1580  m_sensitivity_triangulated.setGeometry(temp);
1581  temp->triangulate();
1582 
1583  //check if some polygons splitted by triangulator added new vertices into the mesh.
1584  int nResidual = temp->getNVertices() - getGeometry()->getNVertices();
1585  if(nResidual > 0){
1586  m_sensitivity_triangulated.completeMissingData(0.0);
1587  livector1D missingIds;
1588  missingIds.reserve(nResidual);
1589  bitpit::PiercedVector<bitpit::Vertex> & originalPV = getGeometry()->getVertices();
1590  for(auto it=m_sensitivity_triangulated.begin(); it != m_sensitivity_triangulated.end(); ++it){
1591  if(!originalPV.exists(it.getId())) missingIds.push_back(it.getId());
1592  }
1593 
1594  temp->updateAdjacencies();
1595  std::unordered_map<long,long> invConn = getInverseConn(*(temp->getPatch()));
1596  darray3E pcoord;
1597  for(long id : missingIds){
1598  pcoord = temp->getVertexCoords(id);
1599  std::set<long> ring = findVertexVertexOneRing(*(temp->getPatch()), invConn[id], id);
1600  double wtot(0), w;
1601  for(long idR : ring){
1602  w = 1.0/norm2(pcoord - temp->getVertexCoords(idR));
1603  wtot += w;
1604  m_sensitivity_triangulated[id] += (w * m_sensitivity_triangulated[idR]);
1605  }
1606  m_sensitivity_triangulated[id] /= wtot;
1607  }
1608  }
1609  return temp;
1610 }
1611 
1612 }
MimmoSharedPointer< MimmoObject > createTriangulation()
std::array< int, 3 > iarray3E
CSeedSurf
Enum class for engine choice to set up initial points on a 3D surface.
#define M_GEOM
std::vector< darray3E > dvecarr3E
std::vector< long > livector1D
virtual void flushSectionXML(bitpit::Config::Section &slotXML, std::string name="")
bool completeMissingData(const mpv_t &defValue)
#define M_POINT
void warningXML(bitpit::Logger *log, std::string name)
void setRandomSignature(uint32_t signature)
BaseManipulation is the base class of any manipulation object of the library.
virtual void absorbSectionXML(const bitpit::Config::Section &slotXML, std::string name="")
MimmoSharedPointer< MimmoObject > getGeometry() const
void setSensitivityMap(dmpvector1D *field)
void swap(CreateSeedsOnSurface &x) noexcept
Oriented Bounding Box calculator.
Definition: OBBox.hpp:90
std::vector< int > ivector1D
virtual void absorbSectionXML(const bitpit::Config::Section &slotXML, std::string name="")
std::array< darray3E, 3 > dmatrix33E
std::vector< double > dvector1D
Distribute a raw list of points on a target 3D surface.
void initialize(MimmoSharedPointer< MimmoObject >, MPVLocation, const mpv_t &)
virtual void flushSectionXML(bitpit::Config::Section &slotXML, std::string name="")
mimmo::MimmoPiercedVector< double > dmpvector1D
void setGeometry(MimmoSharedPointer< MimmoObject > geo)
#define M_VALUELI
void plotCloud(std::string dir, std::string file, int counter, bool binary)
CreateSeedsOnSurface & operator=(CreateSeedsOnSurface other)
void setGeometry(MimmoSharedPointer< MimmoObject > geometry)
std::array< double, 3 > darray3E
darray3E projectPoint(const std::array< double, 3 > *point, const bitpit::PatchSkdTree *skdtree, double r)
std::vector< mpv_t > getRawDataAsVector(bool ordered=false)
void setGeometry(MimmoSharedPointer< MimmoObject >)
MimmoSharedPointer is a custom implementation of shared pointer.
MimmoSharedPointer< MimmoObject > getGeometry()
void swap(BaseManipulation &x) noexcept
double distance(const std::array< double, 3 > *point, const bitpit::PatchSkdTree *tree, long &id, double r)
#define M_COORDS
Structured 3D Cartesian Mesh.
Definition: Lattice.hpp:103
#define M_FILTER