SpecularPoints.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 "SpecularPoints.hpp"
25 #include "SkdTreeUtils.hpp"
26 
27 namespace mimmo{
28 
33  m_name = "mimmo.SpecularPoints";
34  m_plane.fill(0.0);
35  m_insideout = false;
36  m_force = true;
37  m_origin.fill(0.0);
38  m_normal.fill(0.0);
39  m_implicit = false;
40  m_scalar = nullptr;
41  m_vector = nullptr;
42 };
43 
48 SpecularPoints::SpecularPoints(const bitpit::Config::Section & rootXML){
49 
50  m_name = "mimmo.SpecularPoints";
51  m_plane.fill(0.0);
52  m_insideout = false;
53  m_force = true;
54  m_origin.fill(0.0);
55  m_normal.fill(0.0);
56  m_implicit = false;
57  m_scalar = nullptr;
58  m_vector = nullptr;
59 
60  std::string fallback_name = "ClassNONE";
61  std::string input = rootXML.get("ClassName", fallback_name);
62  input = bitpit::utils::string::trim(input);
63  if(input == "mimmo.SpecularPoints"){
64  absorbSectionXML(rootXML);
65  }else{
67  };
68 }
69 
73 
77  m_plane = other.m_plane;
78  m_scalar = other.m_scalar;
79  m_vector = other.m_vector;
80  m_insideout = other.m_insideout;
81  m_force = other.m_force;
82  m_origin = other.m_origin;
83  m_normal = other.m_normal;
84  m_implicit = other.m_implicit;
85  m_pc = other.m_pc;
86 };
87 
92  swap(other);
93  return *this;
94 }
95 
101 {
102  std::swap(m_plane, x.m_plane);
103  std::swap(m_scalar, x.m_scalar);
104  std::swap(m_vector, x.m_vector);
105  std::swap(m_insideout, x.m_insideout);
106  std::swap(m_force, x.m_force);
107  std::swap(m_origin, x.m_origin);
108  std::swap(m_normal, x.m_normal);
109  std::swap(m_implicit, x.m_implicit);
110  m_scalarMirrored.swap(x.m_scalarMirrored);
111  m_vectorMirrored.swap(x.m_vectorMirrored);
112  std::swap(m_pc,x.m_pc);
113 
115 }
118 void
120  bool built = true;
121 
122  built = (built && createPortIn<MimmoSharedPointer<MimmoObject>, SpecularPoints>(this,&mimmo::SpecularPoints::setPointCloud, M_GEOM2, true));
123  built = (built && createPortIn<dmpvecarr3E*, SpecularPoints>(this, &mimmo::SpecularPoints::setVectorData, M_VECTORFIELD));
124  built = (built && createPortIn<dmpvector1D*, SpecularPoints>(this, &mimmo::SpecularPoints::setScalarData, M_DATAFIELD));
125  built = (built && createPortIn<darray4E, SpecularPoints>(this, &mimmo::SpecularPoints::setPlane, M_PLANE));
126  built = (built && createPortIn<darray3E, SpecularPoints>(this, &mimmo::SpecularPoints::setOrigin, M_POINT));
127  built = (built && createPortIn<darray3E, SpecularPoints>(this, &mimmo::SpecularPoints::setNormal, M_AXIS));
128  built = (built && createPortIn<MimmoSharedPointer<MimmoObject>, SpecularPoints>(this, &mimmo::SpecularPoints::setGeometry, M_GEOM));
129 
130  built = (built && createPortOut<MimmoSharedPointer<MimmoObject>, SpecularPoints>(this, &mimmo::SpecularPoints::getMirroredPointCloud, M_GEOM));
131  built = (built && createPortOut<dmpvecarr3E*, SpecularPoints>(this, &mimmo::SpecularPoints::getMirroredVectorData, M_VECTORFIELD));
132  built = (built && createPortOut<dmpvector1D*, SpecularPoints>(this, &mimmo::SpecularPoints::getMirroredScalarData, M_SCALARFIELD));
133  m_arePortsBuilt = built;
134 };
135 
140 dmpvector1D *
142  return m_scalar;
143 };
144 
149 dmpvecarr3E *
151  return m_vector;
152 };
153 
158 dmpvector1D *
160  return &m_scalarMirrored;
161 };
162 
167 dmpvecarr3E *
169  return &m_vectorMirrored;
170 };
171 
172 
177 dvecarr3E
179 
180  dvecarr3E points;
181  if(m_patch != nullptr){
182  points.reserve(m_patch->getNVertices());
183  for(bitpit::Vertex & vert : m_patch->getVertices()){
184  points.push_back(vert.getCoords());
185  }
186  }
187  return points;
188 };
189 
196 
197  livector1D labels;
198  if(m_patch != nullptr){
199  labels.reserve(m_patch->getNVertices());
200  for(bitpit::Vertex & vert : m_patch->getVertices()){
201  labels.push_back(vert.getId());
202  }
203  }
204  return labels;
205 };
206 
212  return m_patch;
213 }
214 
219 darray4E
221  return m_plane;
222 };
223 
229 bool
231  return m_insideout;
232 }
233 
239 bool
241  return m_force;
242 }
243 
244 
249 void
251 
252  if(targetpatch == nullptr) return;
253  if(targetpatch->getType() !=3) return;
254  m_pc = targetpatch;
255 };
256 
257 
262 void
264  if(scalardata == nullptr) return;
265  if(scalardata->getDataLocation() != MPVLocation::POINT) return;
266  m_scalar = scalardata;
267 };
268 
273 void
275  if(vectordata == nullptr) return;
276  if(vectordata->getDataLocation() != MPVLocation::POINT) return;
277  m_vector = vectordata;
278 };
279 
284 void
286  m_plane = plane;
287  m_implicit = true;
288 };
289 
296 void
298 
299  double normx=norm2(normal);
300  if(normx > std::numeric_limits<double>::min()) normal /= normx;
301 
302  m_plane[0] = normal[0];
303  m_plane[1] = normal[1];
304  m_plane[2] = normal[2];
305  m_plane[3] = -1.0*dotProduct(origin, normal);
306 
307  m_implicit = true;
308 
309 };
310 
316 void
318  m_origin = origin;
319 };
320 
326 void
328  m_normal = normal;
329 };
330 
335 void
337  m_insideout = flag;
338 };
339 
345 void
347  m_force = flag;
348 }
349 
350 
354 void
356 
357  //check if there is a valid a point cloud
358  if (m_pc == nullptr){
359  (*m_log)<<"Error in "<<m_name << " : nullptr pointer to target point cloud"<<std::endl;
360  throw std::runtime_error (m_name + " : nullptr pointer to target point cloud");
361  }
362 
363  //clone it into the internal member m_cobj (mother class ProjPatchOnSurface)
364  m_cobj = m_pc->clone();
365  //initialize mirrored data;
366  m_scalarMirrored.clear();
367  m_vectorMirrored.clear();
368  m_scalarMirrored.initialize(m_cobj, MPVLocation::POINT, 0.);
369  m_scalarMirrored.setName("MirroredScalarData");
370  m_vectorMirrored.initialize(m_cobj, MPVLocation::POINT, {{0.0,0.0,0.0}});
371  m_vectorMirrored.setName("MirroredVectorData");
372 
373 
374  /* Check the plane stuff and if an implicit definition is not present it has to be computed
375  * by using origin and normal.
376  */
377  if (!m_implicit) setPlane(m_origin, m_normal);
378 
379  darray3E norm;
380  double offsetPlane;
381  for(int i=0; i<3; ++i) norm[i] = m_plane[i];
382  offsetPlane = m_plane[3];
383  double normPlane = norm2(norm);
384 
385  //if normal is 0 there is nothing to do
386  if(normPlane <= std::numeric_limits<double>::min()){
387  (*m_log)<< "Error: "<<m_name <<" : no valid plane normal found"<<std::endl;
388  m_patch = m_cobj;
389  return;
390  }
391 
392  //adjust the normal to be unitary in modulus
393  norm /= normPlane;
394 
395  //see if need to project the cloud on a surface geometry: set bool project as active.
396  bool project = false;
397  int cellcount(0);
398  if (getGeometry() != nullptr){
399  cellcount = getGeometry()->getNCells();
400 #if MIMMO_ENABLE_MPI
401  MPI_Allreduce(MPI_IN_PLACE, &cellcount, 1, MPI_INT, MPI_SUM, m_communicator);
402 #endif
403  project = (cellcount > 0);
404  }
405 
406 
407  //calculate a reasonable margin for defining the plane offset. This is
408  // done to distinguish quickly points which lies on plane or not.
409  double margin = 1.0E-12;
410  if(project){
411  double areaTot = 0.0;
412  bitpit::SurfaceKernel * tri = static_cast<bitpit::SurfaceKernel * >(getGeometry()->getPatch());
413  for(auto it = tri->internalCellBegin(); it != tri->internalCellEnd(); ++it ){
414  areaTot += tri->evalCellArea(it.getId());
415  }
416 #if MIMMO_ENABLE_MPI
417  MPI_Allreduce(MPI_IN_PLACE, &areaTot, 1, MPI_DOUBLE, MPI_SUM, m_communicator);
418 #endif
419  if(areaTot > std::numeric_limits<double>::min()) {
420  margin = 1.2*std::pow(areaTot/((double)cellcount),0.5);
421  }
422  }
423 
424  //take into account the right emiplane with insideout given by the User.
425  double sig = (1.0 - 2.0*((int)m_insideout));
426 
427  //before mirroring, evaluate starting offsets for labeling new vertices to be added.
428 
429  livector1D localVertIds = m_cobj->getVerticesIds();
430  int nPCvert = int(localVertIds.size());
431 
432  long offsetVertLabel(0);
433  if(!localVertIds.empty())
434  offsetVertLabel = *(std::max_element(localVertIds.begin(), localVertIds.end())) + 1;
435  long offsetCellLabel(0);
436  {
437  livector1D localCellIds = m_cobj->getCellsIds();
438  if(!localCellIds.empty())
439  offsetCellLabel = *(std::max_element(localCellIds.begin(), localCellIds.end())) + 1;
440  }
441 
442 
443 #if MIMMO_ENABLE_MPI
444  std::vector<int> rankPCSize (m_nprocs, 0);
445  rankPCSize[m_rank] = nPCvert;
446  MPI_Allreduce(MPI_IN_PLACE, &offsetVertLabel, 1, MPI_LONG, MPI_MAX, m_communicator);
447  MPI_Allreduce(MPI_IN_PLACE, &offsetCellLabel, 1, MPI_LONG, MPI_MAX, m_communicator);
448  MPI_Allreduce(MPI_IN_PLACE, rankPCSize.data(), m_nprocs, MPI_INT, MPI_MAX, m_communicator);
449 
450  for(int i=0; i<m_rank; ++i) {
451  offsetVertLabel += long(rankPCSize[i]);
452  offsetCellLabel += long(rankPCSize[i]);
453  }
454 #endif
455 
456  //copy data of scalar and vector (if any) into mirrored twin structures
457  //(that are already initialized to default 0 value) and reserve them
458  //for new vertices insertion
459  if(m_scalar){
460  for(long id: localVertIds){
461  if(m_scalar->exists(id)){
462  m_scalarMirrored[id] = m_scalar->at(id);
463  }
464  }
465  m_scalarMirrored.reserve(2*nPCvert);
466  }
467 
468  if(m_vector){
469  for(long id: localVertIds){
470  if(m_vector->exists(id)){
471  m_vectorMirrored[id] = m_vector->at(id);
472  }
473  }
474  m_vectorMirrored.reserve(2*nPCvert);
475  }
476 
477  m_cobj->getPatch()->reserveVertices(2*nPCvert);
478  m_cobj->getPatch()->reserveCells(2*nPCvert);
479 
480 
481  //FINALLY mirror the points, scalar and vector fields.
482  darray3E vert;
483  bitpit::ElementType type = bitpit::ElementType::VERTEX;
484  for (long id: localVertIds){
485  vert = m_cobj->getVertexCoords(id);
486  double distance = sig*(dotProduct(norm, vert) + offsetPlane);
487 
488  if(distance > margin || m_force){
489 
490  m_cobj->addVertex( (vert - 2.0*distance*sig*norm), offsetVertLabel);
491 #if MIMMO_ENABLE_MPI
492  m_cobj->addConnectedCell(std::vector<long>(1, offsetVertLabel), type, 0, offsetCellLabel, m_rank);
493 #else
494  m_cobj->addConnectedCell(std::vector<long>(1, offsetVertLabel), type, 0, offsetCellLabel);
495 #endif
496  m_scalarMirrored.insert(offsetVertLabel, m_scalarMirrored[id] );
497  m_vectorMirrored.insert(offsetVertLabel, (m_vectorMirrored[id] -2.0*dotProduct(m_vectorMirrored[id], sig*norm)*sig*norm) );
498 
499  ++offsetVertLabel;
500  ++offsetCellLabel;
501  }
502  }
503 
504  if(project){
505  //this chunk will project the original cloud onto the target surface
506  //m_cobj is filled up before.
507  m_workingOnTarget = true;
508  //final m_patch is m_cobj itself;
509  projection();
510  //for MPI version, this method already update the patch.
511  }else{
512  m_patch = m_cobj;
513  m_patch->cleanPatchInfo();
514  #if MIMMO_ENABLE_MPI
515  m_patch->resetPointGhostExchangeInfo();
516  #endif
517  m_patch->update();
518  }
519 
520  //squeeze stuff out
521  m_patch->getPatch()->squeezeVertices();
522  m_patch->getPatch()->squeezeCells();
523  m_scalarMirrored.shrinkToFit();
524  m_vectorMirrored.shrinkToFit();
525 
526  //evaluate kdtree if required by the class
527  if(m_patch){
528  if(m_buildKdTree) m_patch->buildKdTree();
529  }else{
530  (*m_log)<<m_name << " : failed mirroring Point Cloud"<<std::endl;
531  }
532 };
533 
537 void
540  m_scalar = nullptr;
541  m_vector = nullptr;
542  m_scalarMirrored.clear();
543  m_vectorMirrored.clear();
544  m_plane.fill(0.0);
545  m_insideout = false;
546 };
547 
553 void
554 SpecularPoints::absorbSectionXML(const bitpit::Config::Section & slotXML, std::string name){
555 
556  BITPIT_UNUSED(name);
557 
558  //start absorbing
560 
561  if(slotXML.hasOption("Force")){
562  std::string input = slotXML.get("Force");
563  input = bitpit::utils::string::trim(input);
564  bool value = false;
565  if(!input.empty()){
566  std::stringstream ss(input);
567  ss >> value;
568  }
569  setForce(value);
570  }
571 
572  if(slotXML.hasOption("InsideOut")){
573  std::string input = slotXML.get("InsideOut");
574  input = bitpit::utils::string::trim(input);
575  bool value = false;
576  if(!input.empty()){
577  std::stringstream ss(input);
578  ss >> value;
579  }
580  setInsideOut(value);
581  }
582 
583  if(slotXML.hasSection("Plane")){
584  const bitpit::Config::Section & planeXML = slotXML.getSection("Plane");
585 
586  std::string input1 = planeXML.get("Point");
587  std::string input2 = planeXML.get("Normal");
588  input1 = bitpit::utils::string::trim(input1);
589  input2 = bitpit::utils::string::trim(input2);
590 
591  darray3E temp1 = {{0.0,0.0,0.0}};
592  darray3E temp2 = {{0.0,0.0,0.0}};
593 
594  if(!input1.empty()){
595  std::stringstream ss(input1);
596  ss>>temp1[0]>>temp1[1]>>temp1[2];
597  }
598  if(!input2.empty()){
599  std::stringstream ss(input2);
600  ss>>temp2[0]>>temp2[1]>>temp2[2];
601  }
602 
603  setPlane(temp1, temp2);
604  };
605 };
606 
612 void
613 SpecularPoints::flushSectionXML(bitpit::Config::Section & slotXML, std::string name){
614 
615  BITPIT_UNUSED(name);
616 
618 
619  int value = m_force;
620  slotXML.set("Force", std::to_string(value));
621 
622  value = m_insideout;
623  slotXML.set("InsideOut", std::to_string(value));
624 
625 
626  {
627  darray4E org = getPlane();
628  darray3E normal;
629  darray3E point = {{0.0,0.0,0.0}};
630  int imax = -1;
631  double dum = 0.0;
632  for(int i=0; i<3; ++i) {
633  normal[i] =org[i];
634  if(abs(normal[i]) > dum) {
635  imax = i;
636  dum = abs(normal[i]);
637  }
638  }
639  if(imax != -1) point[imax] = -1.0*org[3]/normal[imax];
640 
641  std::stringstream ss1, ss2;
642  ss1<<std::scientific<<point[0]<<'\t'<<point[1]<<'\t'<<point[2];
643  ss2<<std::scientific<<normal[0]<<'\t'<<normal[1]<<'\t'<<normal[2];
644 
645  bitpit::Config::Section & planeXML = slotXML.addSection("Plane");
646  planeXML.set("Point",ss1.str());
647  planeXML.set("Normal",ss2.str());
648  }
649 
650 };
651 
656 void
658  write(m_patch, m_scalarMirrored, m_vectorMirrored);
659 };
660 
661 }
std::array< double, 4 > darray4E
void setInsideOut(bool flag)
void swap(SpecularPoints &x) noexcept
virtual void absorbSectionXML(const bitpit::Config::Section &slotXML, std::string name="")
#define M_DATAFIELD
#define M_GEOM
livector1D getMirroredLabels()
virtual void plotOptionalResults()
MimmoSharedPointer< MimmoObject > m_patch
void setGeometry(MimmoSharedPointer< MimmoObject > geo)
std::vector< darray3E > dvecarr3E
void setName(std::string name)
std::vector< long > livector1D
#define M_GEOM2
dmpvecarr3E * getMirroredVectorData()
#define M_POINT
void warningXML(bitpit::Logger *log, std::string name)
void flushSectionXML(bitpit::Config::Section &slotXML, std::string name="")
dmpvecarr3E * getOriginalVectorData()
#define M_VECTORFIELD
SpecularPoints is a class that mirrors a point cloud w.r.t. a reference plane, on a target surface ge...
void absorbSectionXML(const bitpit::Config::Section &slotXML, std::string name="")
void write(MimmoSharedPointer< MimmoObject > geometry)
dmpvector1D * getOriginalScalarData()
void setPlane(darray4E plane)
void setOrigin(darray3E origin)
void initialize(MimmoSharedPointer< MimmoObject >, MPVLocation, const mpv_t &)
#define M_PLANE
void setPointCloud(MimmoSharedPointer< MimmoObject > targetpatch)
Executable block class capable of projecting a surface patch, 3DCurve or PointCloud on a 3D surface,...
dvecarr3E getMirroredRawCoords()
MimmoSharedPointer< MimmoObject > getMirroredPointCloud()
MimmoSharedPointer< MimmoObject > m_cobj
SpecularPoints & operator=(SpecularPoints other)
void setVectorData(dmpvecarr3E *vdata)
#define M_SCALARFIELD
std::array< double, 3 > darray3E
#define M_AXIS
void setForce(bool flag)
MimmoSharedPointer is a custom implementation of shared pointer.
MimmoSharedPointer< MimmoObject > getGeometry()
virtual void flushSectionXML(bitpit::Config::Section &slotXML, std::string name="")
void setScalarData(dmpvector1D *data)
void setNormal(darray3E normal)
dmpvector1D * getMirroredScalarData()
void swap(ProjPatchOnSurface &x) noexcept