RefineGeometry.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 "RefineGeometry.hpp"
26 #if MIMMO_ENABLE_MPI
27 #include "mimmo_parallel.hpp"
28 #endif
29 
30 namespace mimmo{
31 
36  m_name = "mimmo.RefineGeometry";
37  m_type = RefineType(1);
38  m_steps = 0;
39  m_refinements = 1;
40 }
41 
46 RefineGeometry::RefineGeometry(const bitpit::Config::Section & rootXML){
47 
48  std::string fallback_name = "ClassNONE";
49  std::string input_name = rootXML.get("ClassName", fallback_name);
50  input_name = bitpit::utils::string::trim(input_name);
51 
52  m_name = "mimmo.RefineGeometry";
53  m_type = RefineType(1);
54  m_steps = 0;
55  m_refinements = 1;
56 
57  if(input_name == "mimmo.RefineGeometry"){
58  absorbSectionXML(rootXML);
59  }else{
61  };
62 }
63 
68 
73  m_type = other.m_type;
74  m_steps = other.m_steps;
76 };
77 
82  swap(other);
83  return *this;
84 };
85 
86 
92 {
93  std::swap(m_type,x.m_type);
94  std::swap(m_steps,x.m_steps);
95  std::swap(m_refinements,x.m_refinements);
97 };
98 
99 
103 void
105  bool built = true;
106  built = (built && createPortIn<mimmo::MimmoSharedPointer<MimmoObject>, RefineGeometry>(this, &BaseManipulation::setGeometry, M_GEOM, true));
107  built = (built && createPortOut<mimmo::MimmoSharedPointer<MimmoObject>, RefineGeometry>(this, &BaseManipulation::getGeometry, M_GEOM));
108  m_arePortsBuilt = built;
109 }
110 
117  return m_type;
118 }
119 
125 void
127  if (type != RefineType::TERNARY && type != RefineType::REDGREEN)
128  throw std::runtime_error(m_name + " : refinement method not allowed");
129  m_type = type;
130 };
131 
136 void
138  if (type != 0 && type != 1)
139  throw std::runtime_error(m_name + " : refinement method not allowed");
140 
141  m_type = RefineType(type);
142 };
143 
149 void
151  m_refinements = std::max(0, steps);
152 };
153 
159 void
161  m_steps = std::max(0, steps);
162 };
163 
167 void
170 };
171 
172 
176 void
178 
179  if(getGeometry() == nullptr){
180  (*m_log)<<m_name + " : no geometry to refine found"<<std::endl;
181  return;
182  }
183 
184  if (getGeometry()->getType() != 1){
185  (*m_log)<<m_name + " : data structure type different from Surface "<<std::endl;
186  throw std::runtime_error (m_name + " : data structure type different from Surface");
187  }
188 
190  bool check = checkTriangulation();
191  if(!check){
192  (*m_log)<<m_name + " : detected not regular triangulated surface, no redgreen refinement can be performed. Returning. "<<std::endl;
193  return;
194  }
195  }
196 
197  // Initialize active cells with all geometry cells
198  for (int i=0; i<m_refinements; i++){
199  m_activecells = getGeometry()->getCellsIds();
200 
201  if (m_type == RefineType::TERNARY){
202  ternaryRefine();
203  }
204  else if (m_type == RefineType::REDGREEN){
205  redgreenRefine();
206  }
207  }
208  if (m_steps>0){
209  smoothing();
210  }
211 }
212 
218 void RefineGeometry::absorbSectionXML(const bitpit::Config::Section & slotXML, std::string name){
219 
220  BITPIT_UNUSED(name);
221 
222  std::string input;
223 
224  if(slotXML.hasOption("RefineType")){
225  std::string input = slotXML.get("RefineType");
226  input = bitpit::utils::string::trim(input);
227  int value = 1;
228  if(!input.empty()){
229  std::stringstream ss(input);
230  ss >> value;
231  }
232  setRefineType(value);
233  }
234 
235  if(slotXML.hasOption("RefineSteps")){
236  std::string input = slotXML.get("RefineSteps");
237  input = bitpit::utils::string::trim(input);
238  int value = 0;
239  if(!input.empty()){
240  std::stringstream ss(input);
241  ss >> value;
242  }
243  setRefineSteps(value);
244  }
245 
246  if(slotXML.hasOption("SmoothingSteps")){
247  std::string input = slotXML.get("SmoothingSteps");
248  input = bitpit::utils::string::trim(input);
249  int value = 0;
250  if(!input.empty()){
251  std::stringstream ss(input);
252  ss >> value;
253  }
254  setSmoothingSteps(value);
255  }
256 
257  BaseManipulation::absorbSectionXML(slotXML, name);
258 
259 };
260 
266 void RefineGeometry::flushSectionXML(bitpit::Config::Section & slotXML, std::string name){
267 
268  BaseManipulation::flushSectionXML(slotXML, name);
269  slotXML.set("RefineType", std::to_string(int(m_type)));
270  slotXML.set("RefineSteps", std::to_string(m_refinements));
271  slotXML.set("SmoothingSteps", std::to_string(m_steps));
272 
273 };
274 
278 void
280  write(getGeometry());
281 }
282 
287 void
289 {
290  //TERNARY REFINEMENT
291 
292  // Ternary refinement force the geometry to be a triangulation by placing a new vertex
293  // on the mean point of each cell (the cells have to be convex).
294 
295  // It works in parallel, supposing the cell refined in the same manner
296  // if local or ghost on the owner process or on the near process.
297  // The ids are not maintained unique between all the processes
298 #if MIMMO_ENABLE_MPI
299  if (m_nprocs > 1){
300  (*m_log)<< "WARNING " <<m_name <<" : uniqueness of cell/vertex ids among processes is not maintained during parallel geometry refinement."<<std::endl;
301  }
302 #endif
303 
305  std::unordered_set<long> newCells;
306  std::unordered_set<long> toDelete;
307 
308  for(const long cellId : m_activecells){
309 
310  // Eval centroid
311  std::array<double,3> centroid = getGeometry()->evalCellCentroid(cellId);
312 
313  // Build perimeter structure with the vertices of the cell and then a triangulation refinement
314  // will be performed by placing the centroid as new vertex
315  std::vector<bitpit::Vertex> perimeter;
316  for (const long & id : getGeometry()->getPatch()->getCell(cellId).getVertexIds()){
317  perimeter.emplace_back(getGeometry()->getPatch()->getVertex(id));
318  }
319 
320  // Refine cell
321  std::vector<long> generatedCells = ternaryRefineCell(cellId, perimeter, centroid);
322 
323 
324  if (!generatedCells.empty()){
325 
326  //Add cell to todelete and refined structure
327  toDelete.insert(cellId);
328 
329  // Add vertices and cell to coarse patch
330  if (coarsepatch != nullptr)
331  {
332  bitpit::Cell & cell = getGeometry()->getPatch()->getCell(cellId);
333  coarsepatch->addCell(cell, cellId);
334  for (long vertexId : cell.getVertexIds()){
335  bitpit::Vertex vertex = getGeometry()->getPatch()->getVertex(vertexId);
336  coarsepatch->addVertex(vertex, vertexId);
337  }
338  }
339 
340  // Add entry to refine-coarse mapping and newCells structure
341  for (long newCellId : generatedCells){
342  if (mapping != nullptr)
343  mapping->insert({newCellId, cellId});
344  newCells.insert(newCellId);
345  }
346 
347  } // end if generated cells is not empty
348 
349  } // end loop on cells
350 
351 
352 
353  //Delete cells and clean geometries
354  {
355  getGeometry()->getPatch()->deleteCells(livector1D(toDelete.begin(), toDelete.end()));
356  getGeometry()->setUnsyncAll();
357 
358 #if MIMMO_ENABLE_MPI
359  // Update adjacencies
360  getGeometry()->updateAdjacencies();
361 
362  // Delete orphan ghosts
363  getGeometry()->deleteOrphanGhostCells();
364  getGeometry()->getPatch()->deleteOrphanVertices();
365 #endif
366 
367  // Update coarse patch
368  getGeometry()->update();
369  if (coarsepatch != nullptr){
370  coarsepatch->update();
371  }
372  }
373 
374  // Add vertices and cells to refine patch
375  if (refinepatch != nullptr){
376  for (long newcellId : newCells){
377  bitpit::Cell & cell = getGeometry()->getPatch()->getCell(newcellId);
378  refinepatch->addCell(cell, newcellId);
379  for (long vertexId : cell.getVertexIds()){
380  const bitpit::Vertex & vertex = getGeometry()->getPatch()->getVertex(vertexId);
381  refinepatch->addVertex(vertex, vertexId);
382  }
383  }
384 
385 #if MIMMO_ENABLE_MPI
386  // update adjacencies refine patch
387  refinepatch->update();
388 
389  // Delete orphan ghosts
390  refinepatch->deleteOrphanGhostCells();
391  refinepatch->getPatch()->deleteOrphanVertices();
392 #endif
393 
394  // update refine patch
395  refinepatch->update();
396  }
397 
398 }
399 
400 
411 std::vector<long>
412 RefineGeometry::ternaryRefineCell(const long & cellId, const std::vector<bitpit::Vertex> & vertices, const std::array<double,3> & center)
413 {
414 
415  long newVertID;
416 
417  std::vector<long> newCellIDs;
418 
419  bitpit::ElementType eletri = bitpit::ElementType::TRIANGLE;
420  livector1D connTriangle(3);
421 
422  // Take a cell copy, after the emplace back of the refined cells the reference can be changed
423  const bitpit::Cell & cell = getGeometry()->getPatch()->getCell(cellId);
424 
425  long pid = cell.getPID();
426  int rank = -1;
427 
428  //Number of new triangles is the number of the perimetral vertices
429  std::size_t nnewTri = vertices.size();
430  newCellIDs.reserve(nnewTri);
431 
432  // Add barycenter and new vertices (check for old vertices)
433  newVertID = getGeometry()->addVertex(center);
434 
435  //insert new triangles from polygon subdivision
436  for(std::size_t i=0; i<nnewTri; ++i){
437  connTriangle[0] = newVertID;
438  connTriangle[1] = vertices[ std::size_t( i % nnewTri) ].getId();
439  connTriangle[2] = vertices[ std::size_t( (i+1) % nnewTri ) ].getId();
440 #if MIMMO_ENABLE_MPI
441  // Recover cell rank
442  rank = getGeometry()->getPatch()->getCellRank(cellId);
443 #endif
444  newCellIDs.push_back(getGeometry()->addConnectedCell(connTriangle, eletri, pid, bitpit::Cell::NULL_ID, rank));
445  }
446 
447  return newCellIDs;
448 
449 }
450 
460 void
462 {
463 
464  //REDGREEN REFINEMENT
465  // It works in parallel, supposing the cell refined in the same manner
466  // if local or ghost on the owner process or on the near process.
467  // The ids are not maintained unique between all the processes
468 #if MIMMO_ENABLE_MPI
469  if (m_nprocs > 1){
470  (*m_log)<< "WARNING " <<m_name <<" : uniqueness of cell/vertex ids among processes is not maintained during parallel geometry refinement."<<std::endl;
471  }
472 #endif
473 
475  std::unordered_set<long> newCells;
476  std::unordered_set<long> toDelete;
477 
478  // Initialize tag Red, Green structure (0=no refinement, 1=green, 2=red) to 0 for all the cells
479  std::unordered_map<long, int> refinementTag;
480  for(const long cellId : geometry->getCellsIds()){
481  refinementTag[cellId] = 0;
482  }
483 
484  // Create container for edges to be splitted by using only red elements (green are included automatically)
485  // In order to be unique the interface id of the patch is used
486  std::set<long> edges; //edge defined as interface index
487 
488  // Create a map edge id -> new vertex id
489  std::unordered_map<long,long> edgeVertexId;
490 
491  // Create map green cells -> index edge to be splitted
492  std::unordered_map<long,int> greenSplitFaceIndex;
493 
494  {
495  // Build adjacencies and interfaces if not built
496  geometry->updateAdjacencies();
497  geometry->updateInterfaces();
498 
499  // Set active cells as reds and initialize new reds stack
500  std::deque<long> newreds;
501  for(const long cellId : m_activecells){
502  refinementTag[cellId] = 2;
503  newreds.push_back(cellId);
504  }
505 
506 #if MIMMO_ENABLE_MPI
507  // In case of distributed mesh initialize data
508  // of newreds boolean to update new reds that are
509  // ghosts for other ranks
510  MimmoPiercedVector<bool> isnewred;
511  isnewred.initialize(geometry, MPVLocation::CELL, false);
512 
513  // Instantiate refinement tags container used only for communications
514  MimmoPiercedVector<int> refinementTagCommunicated;
515 
516  // Instantiate green split face container used only for communications
517  MimmoPiercedVector<int> greenSplitFaceIndexCommunicated;
518 
519  // Fill initial sources and targets values
520  for (auto & source_tuple : geometry->getPatch()->getGhostCellExchangeSources()){
521  //int rank = source_tuple.first;
522  for (long id : source_tuple.second){
523  if (!refinementTagCommunicated.exists(id)){
524  refinementTagCommunicated.insert(id,-1);
525  greenSplitFaceIndexCommunicated.insert(id,-1);
526  }
527  }
528  }
529  for (auto & target_tuple : geometry->getPatch()->getGhostCellExchangeTargets()){
530  //int rank = target_tuple.first;
531  for (long id : target_tuple.second){
532  // Initialize targets (ghosts) to -1
533  if (!refinementTagCommunicated.exists(id)){
534  refinementTagCommunicated.insert(id, -1);
535  greenSplitFaceIndexCommunicated.insert(id, -1);
536  }
537  }
538  }
539 
540 #endif
541 
542  // If active cells are all the cells, propagate red-green refinement
543  // even if all the cells are reds, in order to build edges structure
544  bool check = newreds.empty();
545 
546 #if MIMMO_ENABLE_MPI
547  // While global newreds stack is not empty. See below for details on local new reds.
548  // Initialized to false to enter always in while loop at least one time
549  bool global_check = false;
550 
551  while (!global_check){
552 #endif
553 
554  // While newreds stack is not empty:
555  // - serch neighbors of newreds elements
556  // - check in tag map if each neighbor currently it's no,green or red element
557  // - if 0-> promote to green (1), if green->promote to red (2) and insert in newreds, if red->skip neighbour
558  while (!check){
559 
560  long redId = newreds.front();
561  newreds.pop_front();
562 
563  bitpit::Cell & redCell = geometry->getPatch()->getCell(redId);
564 
565  //Only for triangles!!!
566  if (redCell.getType() == bitpit::ElementType::TRIANGLE){
567 
568  for (int iface = 0; iface < 3; iface++){
569 
570  if (!redCell.isFaceBorder(iface)){
571 
572  // Find face neighbours (only one in conform case)
573  int neighscount = redCell.getAdjacencyCount(iface);
574  const long * neighs = redCell.getAdjacencies(iface);
575 
576  for (int ineigh = 0; ineigh < neighscount; ineigh++){
577 
578  long neighId = neighs[ineigh];
579 
580  // Increase tag (at the end the red elements have a tag >=2)
581  refinementTag[neighId]++;
582 
583  // Insert edge between current red and neighbor
584  // The edges structure is a set, so each edge will be not duplicated
585  // Recover interface
586  long interfaceId = geometry->getPatch()->getCell(redId).getInterface(iface);
587  bitpit::Interface & interface = geometry->getPatch()->getInterface(interfaceId);
588  edges.insert(interfaceId);
589 
590  if (refinementTag[neighId] > 2){
591  continue;
592  } // if neigh already red
593 
594 
595  if (refinementTag[neighId] == 2){
596 
597  // Push neigh to new reds
598  newreds.push_back(neighId);
599 
600  // Destroy green entry with splitting edge index
601  greenSplitFaceIndex.erase(neighId);
602 
603  } // If is neigh is new red
604  else if (refinementTag[neighId] == 1){
605 
606  // Get if neighbor is owner of neigh
607  bool isOwner = (interface.getOwner() == neighId);
608 
609  // Recover splitting face index of the neighbor
610  int splitface;
611  if (isOwner){
612  splitface = interface.getOwnerFace();
613  }
614  else{
615  splitface = interface.getNeighFace();
616  }
617  greenSplitFaceIndex[neighId] = splitface;
618 
619  } // Else if neigh is green
620  } // end loop on neighs
621  } // end if not border face
622  else{
623 
624  // If border face the edge is to be refined
625  // Recover border interface
626  long interfaceId = redCell.getInterface(iface);
627  edges.insert(interfaceId);
628 
629  }// end if border face
630 
631  }// End loop on face
632 
633  } // if triangle
634 
635  check = newreds.empty();
636 
637  } // end while stack
638 
639 #if MIMMO_ENABLE_MPI
640  // In case of not partitioned patch use local check
641  global_check = check;
642 
643  if (geometry->isParallel()){
644 
645  // Update ghost refinement tags
646  // The if needed insert new edges and put new reds in stack
647  // Fill with sources and targets values
648  for (auto & source_tuple : geometry->getPatch()->getGhostCellExchangeSources()){
649  //int rank = source_tuple.first;
650  for (long id : source_tuple.second){
651  refinementTagCommunicated.at(id) = refinementTag.at(id);
652  if (greenSplitFaceIndex.count(id)){
653  greenSplitFaceIndexCommunicated.at(id) = greenSplitFaceIndex.at(id);
654  }
655  else{
656  greenSplitFaceIndexCommunicated.at(id) = -1;
657  }
658  }
659  }
660  for (auto & target_tuple : geometry->getPatch()->getGhostCellExchangeTargets()){
661  //int rank = target_tuple.first;
662  for (long id : target_tuple.second){
663  // Initialize targets (ghosts) to -1
664  refinementTagCommunicated.at(id) = -1;
665  greenSplitFaceIndexCommunicated.at(id) = -1;
666  }
667  }
668 
669  // Communicate tag and face index
670  refinementTagCommunicated.communicateData();
671  greenSplitFaceIndexCommunicated.communicateData();
672 
673  // Update refinement tags if different from communicated
674  for (auto ghostIt = geometry->getPatch()->ghostCellConstBegin(); ghostIt != geometry->getPatch()->ghostCellConstEnd(); ghostIt++){
675  long ghostId = ghostIt->getId();
676 
677  // Maximum communicated tag to 2
678  refinementTagCommunicated[ghostId] = std::min(2, refinementTagCommunicated[ghostId]);
679 
680  // If communicated tag is different from local one update it if greater
681  if (refinementTagCommunicated[ghostId] > refinementTag[ghostId]){
682  refinementTag[ghostId] = refinementTagCommunicated[ghostId];
683 
684  if (refinementTag[ghostId] == 1){
685  // If green refinement insert splitFaceIndex
686  greenSplitFaceIndex[ghostId] = greenSplitFaceIndexCommunicated[ghostId];
687  }
688  else if (refinementTag[ghostId] >= 2){
689  // Push ghost to new reds
690  newreds.push_back(ghostId);
691  // Destroy green entry with splitting edge index
692  greenSplitFaceIndex.erase(ghostId);
693  }
694  }
695  } // end ghost iteration
696 
697  // Update global stack check
698  global_check = newreds.empty();
699  MPI_Allreduce(MPI_IN_PLACE, &global_check, 1, MPI_C_BOOL, MPI_LAND, m_communicator);
700  }
701 
702  } // end while global stack
703 #endif
704 
705  } // Scope to destroy temporary containers
706 
707  // Insert new vertices
708  for (long interfaceId : edges){
709  // Recover vertices
710  bitpit::ConstProxyVector<long> vertexIds = geometry->getPatch()->getInterface(interfaceId).getVertexIds();
711  std::array<double,3> newCoordinates({0.,0.,0.});
712  for (long vertexId : vertexIds){
713  newCoordinates += geometry->getVertexCoords(vertexId);
714  }
715  newCoordinates /= double(vertexIds.size());
716  long newVertexId = geometry->addVertex(newCoordinates);
717  edgeVertexId[interfaceId] = newVertexId;
718  }
719 
720  // Refine red and green cells
721  for (auto & tupletag : refinementTag){
722 
723  long cellId = tupletag.first;
724  int tag = std::min(2, tupletag.second);
725 
726  if (tag <= 0)
727  continue;
728 
729  // Generated cells structure
730  std::vector<long> generatedCells;
731 
732  if (tag == 2){
733 
734  // Take reference to cell before refinement
735  bitpit::Cell & cell = geometry->getPatch()->getCell(cellId);
736 
737  // Red refinement
738  // Recover new vertices
739  std::vector<long> newCellVertexIds(cell.getFaceCount());
740  for (int iface=0; iface<cell.getFaceCount(); iface++){
741  long interfaceId = cell.getInterface(iface);
742  newCellVertexIds[iface] = edgeVertexId.at(interfaceId);
743  }
744  // Cell refinement
745  generatedCells = redRefineCell(cellId, newCellVertexIds);
746  }
747  else if (tag == 1){
748 
749  // Take reference to cell before refinement
750  bitpit::Cell & cell = geometry->getPatch()->getCell(cellId);
751 
752  // Green refinement
753  // Recover new vertex and splitted face index
754  int splitFaceIndex = greenSplitFaceIndex.at(cellId);
755  long interfaceId = cell.getInterface(splitFaceIndex);
756  long newCellVertexId = edgeVertexId.at(interfaceId);
757  // Cell refinement
758  generatedCells = greenRefineCell(cellId, newCellVertexId, splitFaceIndex);
759  }
760 
761  if (!generatedCells.empty()){
762 
763  //Add cell to todelete structure
764  toDelete.insert(cellId);
765 
766  // Add vertices and cell to coarse patch
767  if (coarsepatch != nullptr)
768  {
769  // Take reference to cell after refinement
770  // The original cell is still inside the cells structure but the new cells
771  // are already insert, so the reference has to be locally taken.
772  bitpit::Cell & cell = geometry->getPatch()->getCell(cellId);
773 
774  coarsepatch->addCell(cell, cellId);
775  for (long vertexId : cell.getVertexIds()){
776  bitpit::Vertex & vertex = geometry->getPatch()->getVertex(vertexId);
777  coarsepatch->addVertex(vertex, vertexId);
778  }
779  }
780 
781  // Add entry to refine-coarse mapping and newCells structure
782  for (long newCellId : generatedCells){
783  if (mapping != nullptr){
784  mapping->insert({newCellId, cellId});
785  }
786  newCells.insert(newCellId);
787  }
788 
789  } // end if generated cells is not empty
790 
791  } // end loop on refinement tag
792 
793  //Delete cells and clean geometries
794  {
795  // Destroy interfaces
796  getGeometry()->destroyInterfaces();
797 
798  // Delete original cells
799  getGeometry()->getPatch()->deleteCells(livector1D(toDelete.begin(), toDelete.end()));
800 
801  // Set all sync status of mimmo to unsync/none
802  getGeometry()->setUnsyncAll();
803 
804  // Add vertices and cells to refine patch
805  if (refinepatch != nullptr){
806  for (long newcellId : newCells){
807  bitpit::Cell & cell = getGeometry()->getPatch()->getCell(newcellId);
808  refinepatch->addCell(cell, newcellId);
809  for (long vertexId : cell.getVertexIds()){
810  bitpit::Vertex & vertex = getGeometry()->getPatch()->getVertex(vertexId);
811  refinepatch->addVertex(vertex, vertexId);
812  }
813  }
814  }
815 #if MIMMO_ENABLE_MPI
816  // Delete orphan ghosts
817  getGeometry()->deleteOrphanGhostCells();
818  getGeometry()->getPatch()->deleteOrphanVertices();
819 #endif
820  // Update geometry
821  getGeometry()->update();
822 
823  // Update coarse patch
824  if (coarsepatch != nullptr){
825  coarsepatch->update();
826  }
827 
828  // Update refine patch
829  if (refinepatch != nullptr){
830 #if MIMMO_ENABLE_MPI
831  // Delete orphan ghosts
832  refinepatch->deleteOrphanGhostCells();
833  refinepatch->getPatch()->deleteOrphanVertices();
834 #endif
835  // Update refine patch
836  refinepatch->update();
837  }
838 
839  } // end scope
840 
841 }
842 
849 std::vector<long>
850 RefineGeometry::redRefineCell(const long & cellId, const std::vector<long> & newVertexIds)
851 {
852 
853  std::vector<long> newCellIDs;
854 
855  bitpit::ElementType eletype;
856  bitpit::ElementType eletri = bitpit::ElementType::TRIANGLE;
857  livector1D connTriangle(3);
858 
859  // Take a cell copy, after the emplace back of the refined cells the reference can be changed
860  bitpit::Cell cell = getGeometry()->getPatch()->getCell(cellId);
861 
862  eletype = cell.getType();
863  //Only for triangles
864  if (eletype != eletri){
865  (*m_log)<<m_name + " : red refinement allowd only for triangles. Skip element."<<std::endl;
866  return newCellIDs;
867  }
868 
869  long pid = cell.getPID();
870  int rank = -1;
871 #if MIMMO_ENABLE_MPI
872  // Recover cell rank
873  rank = getGeometry()->getPatch()->getCellRank(cellId);
874 #endif
875 
876  //Number of new triangles is 4
877  std::size_t sizeEle = 3;
878  newCellIDs.reserve(sizeEle+1);
879 
880  //insert new triangles from red subdivision
881  // Insert internal one
882  // newVertexIds are supposed ordered as indices of faces (0,1,2)
883  connTriangle[0] = newVertexIds[0];
884  connTriangle[1] = newVertexIds[1];
885  connTriangle[2] = newVertexIds[2];
886  newCellIDs.push_back(getGeometry()->addConnectedCell(connTriangle, eletri, pid, bitpit::Cell::NULL_ID, rank));
887 
888  // Insert three vertex related triangles
889  // Note. start from refined triangle placed on vertex index 1 of coarse triangle
890  for(std::size_t i=0; i<sizeEle; ++i){
891  connTriangle[0] = cell.getVertexId( int( (i+1) % sizeEle) );
892  connTriangle[1] = newVertexIds[ std::size_t( (i+1) % sizeEle) ];
893  connTriangle[2] = newVertexIds[ std::size_t( (i) % sizeEle ) ];
894  newCellIDs.emplace_back(getGeometry()->addConnectedCell(connTriangle, eletri, pid, bitpit::Cell::NULL_ID, rank));
895  }
896 
897  return newCellIDs;
898 }
899 
907 std::vector<long>
908 RefineGeometry::greenRefineCell(const long & cellId, const long newVertexId, int splitEdgeIndex)
909 {
910 
911  std::vector<long> newCellIDs;
912 
913  bitpit::ElementType eletype;
914  bitpit::ElementType eletri = bitpit::ElementType::TRIANGLE;
915  livector1D connTriangle(3);
916 
917  // Take a cell copy, after the emplace back of the refined cells the reference can be changed
918  bitpit::Cell cell = getGeometry()->getPatch()->getCell(cellId);
919 
920  eletype = cell.getType();
921  //Only for triangles
922  if (eletype != eletri){
923  (*m_log)<<m_name + " : red refinement allowd only for triangles. Skip element."<<std::endl;
924  return newCellIDs;
925  }
926 
927  long pid = cell.getPID();
928  int rank = -1;
929 #if MIMMO_ENABLE_MPI
930  // Recover cell rank
931  rank = getGeometry()->getPatch()->getCellRank(cellId);
932 #endif
933 
934  //Number of new triangles is 2
935  std::size_t sizeEle = 3;
936  newCellIDs.reserve(sizeEle-1);
937 
938  // Insert three vertex related triangles
939  // Note. start from refined triangle placed on vertex index 1 of coarse triangle
940  for(std::size_t i=0; i<sizeEle-1; ++i){
941  connTriangle[0] = newVertexId;
942  connTriangle[1] = cell.getVertexId( int( (splitEdgeIndex+1+i) % sizeEle) );
943  connTriangle[2] = cell.getVertexId( int( (splitEdgeIndex+2+i) % sizeEle) );
944  newCellIDs.emplace_back(getGeometry()->addConnectedCell(connTriangle, eletri, pid, bitpit::Cell::NULL_ID, rank));
945  }
946 
947  return newCellIDs;
948 
949 }
950 
951 
958 void
959 RefineGeometry::smoothing(std::set<long> * constrainedVertices)
960 {
961 
963 
964  // Force build the needed structures
965  if(geometry->getAdjacenciesSyncStatus() != mimmo::SyncStatus::SYNC)
966  geometry->updateAdjacencies();
967 
968  if(geometry->getInterfacesSyncStatus() != mimmo::SyncStatus::SYNC)
969  geometry->updateInterfaces();
970 
971  if(geometry->getInfoSyncStatus() != mimmo::SyncStatus::SYNC)
972  geometry->buildPatchInfo();
973 
974  if(geometry->getPointConnectivitySyncStatus() != mimmo::SyncStatus::SYNC)
975  geometry->buildPointConnectivity();
976 
977 #if MIMMO_ENABLE_MPI
978 
979  if(geometry->getPointGhostExchangeInfoSyncStatus() != mimmo::SyncStatus::SYNC)
980  geometry->updatePointGhostExchangeInfo();
981 
982  // Instantiate new coordinates container used only for communications
983  MimmoPiercedVector<std::array<double,3>> newCoordinatesCommunicated(geometry, MPVLocation::POINT);
984 
985  // Fill initial sources and targets values
986  for (auto source_tuple : geometry->getPointGhostExchangeSources()){
987  //int rank = source_tuple.first;
988  for (long id : source_tuple.second){
989  if (!newCoordinatesCommunicated.exists(id)){
990  newCoordinatesCommunicated.insert(id, std::array<double,3>({{0.,0.,0.}}));
991  }
992  }
993  }
994  for (auto target_tuple : geometry->getPointGhostExchangeTargets()){
995  //int rank = target_tuple.first;
996  for (long id : target_tuple.second){
997  if (!newCoordinatesCommunicated.exists(id)){
998  newCoordinatesCommunicated.insert(id, std::array<double,3>({{0.,0.,0.}}));
999  }
1000  }
1001  }
1002 
1003 #endif
1004 
1005 
1006  double lambda = 0.6;
1007  double kappa = -0.603*lambda;
1008 
1009  for (int istep=0; istep < m_steps; istep++){
1010 
1011  {
1012  // First sub-step (positive) of laplacian smoothing
1013  std::unordered_map<long, std::array<double,3>> newcoordinates;
1014  std::unordered_set<long> pointconnectivity;
1015  std::array<double,3> newcoords, oldcoords, neighcoords;
1016  double weight, sumweights;
1017  newcoordinates.reserve(geometry->getNVertices());
1018  //compute new coordinates
1019 // for (long id : geometry->getVertices().getIds()){
1020  for (const bitpit::Vertex & vert : geometry->getVertices()){
1021  long id = vert.getId();
1022  // If ghost vertex do nothing
1023  if (geometry->isPointInterior(id)){
1024 
1025  oldcoords = geometry->getVertexCoords(id);
1026  newcoords = std::array<double,3>{{0.,0.,0.}};
1027 
1028  // If constrained vertex do nothing
1029  if (constrainedVertices == nullptr || !constrainedVertices->count(id)){
1030  pointconnectivity = geometry->getPointConnectivity(id);
1031  sumweights = 0.;
1032  for (long idneigh : pointconnectivity){
1033  neighcoords = geometry->getVertexCoords(idneigh);
1034  std::array<double,3> distancevector = (neighcoords-oldcoords);
1035  weight = 1.;
1036  sumweights += weight;
1037  newcoords += lambda*weight*distancevector;
1038  }
1039  if (sumweights > 0.)
1040  newcoords /= sumweights;
1041  }
1042 
1043  newcoords += oldcoords;
1044  newcoordinates[id] = newcoords;
1045  }
1046 
1047  }
1048 
1049 #if MIMMO_ENABLE_MPI
1050  //Communicate newcoordinates
1051  if (geometry->isParallel()){
1052 
1053  // Update ghost new coordinates
1054 
1055  // Fill with sources and targets values
1056  for (auto source_tuple : geometry->getPointGhostExchangeSources()){
1057  //int rank = source_tuple.first;
1058  for (long id : source_tuple.second){
1059  newCoordinatesCommunicated.at(id) = newcoordinates.at(id);
1060  }
1061  }
1062 
1063  // Communicate new coordinates
1064  newCoordinatesCommunicated.communicateData();
1065 
1066  // Update coordinates of ghost vertices with communicated ones
1067  for (auto target_tuple : geometry->getPointGhostExchangeTargets()){
1068  //int rank = target_tuple.first;
1069  for (long id : target_tuple.second){
1070  newcoordinates[id] = newCoordinatesCommunicated.at(id);
1071  } // end id
1072  } // end tuple
1073 
1074  } // end if geometry is parallel
1075 #endif
1076 
1077  //Set new coordinates
1078 // for (long id : geometry->getVertices().getIds()){
1079  for (const bitpit::Vertex & vert : geometry->getVertices()){
1080  long id = vert.getId();
1081  geometry->modifyVertex(newcoordinates[id], id);
1082  }
1083 
1084  //Update geometry
1085  geometry->update();
1086 
1087  }
1088 
1089  {
1090  //Second sub-step (negative) of laplacian anti-smoothing
1091  std::unordered_map<long, std::array<double,3>> newcoordinates;
1092  std::unordered_set<long> pointconnectivity;
1093  std::array<double,3> newcoords, oldcoords, neighcoords;
1094  double weight, sumweights;
1095  newcoordinates.reserve(geometry->getNVertices());
1096  //compute new coordinates
1097 // for (long id : geometry->getVertices().getIds()){
1098  for (const bitpit::Vertex & vert : geometry->getVertices()){
1099  long id = vert.getId();
1100  oldcoords = geometry->getVertexCoords(id);
1101  newcoords = std::array<double,3>{{0.,0.,0.}};
1102 
1103  // If constrained vertex do nothing
1104  if (constrainedVertices != nullptr && !constrainedVertices->count(id)){
1105  pointconnectivity = geometry->getPointConnectivity(id);
1106  sumweights = 0.;
1107  for (long idneigh : pointconnectivity){
1108  neighcoords = geometry->getVertexCoords(idneigh);
1109  weight = 1.0;
1110  sumweights += weight;
1111  newcoords += kappa*weight*(neighcoords-oldcoords);
1112  }
1113  if (sumweights > 0.)
1114  newcoords /= sumweights;
1115  }
1116 
1117  newcoords += oldcoords;
1118  newcoordinates[id] = newcoords;
1119  }
1120 
1121 #if MIMMO_ENABLE_MPI
1122  //Communicate newcoordinates
1123  if (geometry->isParallel()){
1124 
1125  // Update ghost new coordinates
1126  // The if needed insert new edges and put new reds in stack
1127 
1128  // Fill with sources and targets values
1129  for (auto source_tuple : geometry->getPointGhostExchangeSources()){
1130  //int rank = source_tuple.first;
1131  for (long id : source_tuple.second){
1132  newCoordinatesCommunicated.at(id) = newcoordinates.at(id);
1133  }
1134  }
1135 
1136  // Communicate new coordinates
1137  newCoordinatesCommunicated.communicateData();
1138 
1139  // Update coordinates of ghost vertices with communicated ones
1140  for (auto target_tuple : geometry->getPointGhostExchangeTargets()){
1141  for (long id : target_tuple.second){
1142  newcoordinates.at(id) = newCoordinatesCommunicated.at(id);
1143  } // end id iteration
1144  } // end tuple iteration
1145 
1146  } // end if geometry is parallel
1147 #endif
1148 
1149  //Set new coordinates
1150 // for (long id : geometry->getVertices().getIds()){
1151  for (const bitpit::Vertex & vert : geometry->getVertices()){
1152  long id = vert.getId();
1153  geometry->modifyVertex(newcoordinates[id], id);
1154  }
1155 
1156  //Update geometry
1157  geometry->update();
1158 
1159  } // end second sub step
1160 
1161 
1162  } // end step iteration
1163 
1164 }
1165 
1170 bool
1172  // Check if the m_geometry is a regular triangulation
1173  bool check = true;
1174  for (const bitpit::Cell & cell : getGeometry()->getCells()){
1175  check = check && (cell.getType() == bitpit::ElementType::TRIANGLE);
1176  }
1177 #if MIMMO_ENABLE_MPI
1178  MPI_Allreduce(MPI_IN_PLACE, &check, 1, MPI_C_BOOL, MPI_LAND, m_communicator);
1179 #endif
1180 
1181  return check;
1182 }
1183 
1184 }
#define M_GEOM
std::vector< long > ternaryRefineCell(const long &cellId, const std::vector< bitpit::Vertex > &vertices, const std::array< double, 3 > &center)
void setSmoothingSteps(int steps)
RefineType
Methods available for refining globally a (surface) geometry.
virtual void flushSectionXML(bitpit::Config::Section &slotXML, std::string name="")
std::vector< long > livector1D
std::vector< long > m_activecells
void warningXML(bitpit::Logger *log, std::string name)
void swap(RefineGeometry &x) noexcept
virtual void absorbSectionXML(const bitpit::Config::Section &slotXML, std::string name="")
BaseManipulation is the base class of any manipulation object of the library.
MimmoPiercedVector is the basic data container for mimmo library.
void write(MimmoSharedPointer< MimmoObject > geometry)
void setRefineType(RefineType type)
virtual void absorbSectionXML(const bitpit::Config::Section &slotXML, std::string name="")
void setRefineSteps(int steps)
std::vector< long > redRefineCell(const long &cellId, const std::vector< long > &newVertexIds)
void initialize(MimmoSharedPointer< MimmoObject >, MPVLocation, const mpv_t &)
virtual void flushSectionXML(bitpit::Config::Section &slotXML, std::string name="")
std::vector< long > greenRefineCell(const long &cellId, const long newVertexId, int iface)
RefineGeometry is an executable block class capable of refine a surface geometry.
void redgreenRefine(std::unordered_map< long, long > *mapping=nullptr, mimmo::MimmoSharedPointer< MimmoObject > coarsepatch=nullptr, mimmo::MimmoSharedPointer< MimmoObject > refinepatch=nullptr)
void setGeometry(MimmoSharedPointer< MimmoObject > geometry)
RefineGeometry & operator=(RefineGeometry other)
MimmoSharedPointer is a custom implementation of shared pointer.
MimmoSharedPointer< MimmoObject > getGeometry()
void smoothing(std::set< long > *constrainedVertices=nullptr)
void swap(BaseManipulation &x) noexcept
void ternaryRefine(std::unordered_map< long, long > *mapping=nullptr, mimmo::MimmoSharedPointer< MimmoObject > coarsepatch=nullptr, mimmo::MimmoSharedPointer< MimmoObject > refinepatch=nullptr)