MimmoObject.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 "MimmoObject.hpp"
25 #include "MimmoNamespace.hpp"
26 #include "SkdTreeUtils.hpp"
27 #if MIMMO_ENABLE_MPI
28 #include "communications.hpp"
29 #endif
30 #include <Operators.hpp>
31 #include <set>
32 #include <cassert>
33 
34 namespace mimmo{
35 
36 #if MIMMO_ENABLE_MPI
37 
42  bitpit::SurfUnstructured(communicator){}
43 
49 MimmoSurfUnstructured::MimmoSurfUnstructured(int dimension, MPI_Comm communicator):
50  bitpit::SurfUnstructured(dimension, 3, communicator){}
51 
58 MimmoSurfUnstructured::MimmoSurfUnstructured(int id, int dimension, MPI_Comm communicator):
59  bitpit::SurfUnstructured(id, dimension, 3, communicator){}
60 
66 MimmoSurfUnstructured::MimmoSurfUnstructured(std::istream & stream, MPI_Comm communicator):
67  bitpit::SurfUnstructured(stream, communicator){}
68 
69 #else
70 
74  bitpit::SurfUnstructured(){}
75 
81  bitpit::SurfUnstructured(dimension, 3){}
82 
89  bitpit::SurfUnstructured(id, dimension, 3){}
90 
96  bitpit::SurfUnstructured(stream){}
97 
98 #endif
99 
104 
109 std::unique_ptr<bitpit::PatchKernel>
111  return bitpit::SurfUnstructured::clone();
112 }
113 
114 
115 #if MIMMO_ENABLE_MPI
116 
121 MimmoVolUnstructured::MimmoVolUnstructured(MPI_Comm communicator):
122  bitpit::VolUnstructured(3, communicator){}
123 
129 MimmoVolUnstructured::MimmoVolUnstructured(int dimension, MPI_Comm communicator):
130  bitpit::VolUnstructured(dimension, communicator){}
131 
138 MimmoVolUnstructured::MimmoVolUnstructured(int id, int dimension, MPI_Comm communicator):
139  bitpit::VolUnstructured(id, dimension, communicator){}
140 
141 #else
142 
147  bitpit::VolUnstructured(3){}
148 
154  bitpit::VolUnstructured(dimension){}
155 
162  bitpit::VolUnstructured(id, dimension){}
163 #endif
164 
169 
174 std::unique_ptr<bitpit::PatchKernel>
176  return bitpit::VolUnstructured::clone();
177 }
178 
179 
180 #if MIMMO_ENABLE_MPI
181 
185 MimmoPointCloud::MimmoPointCloud(MPI_Comm communicator):
186  bitpit::SurfUnstructured(2, 3, communicator){}
187 
193 MimmoPointCloud::MimmoPointCloud(int id, MPI_Comm communicator):
194  bitpit::SurfUnstructured(id, 2, 3, communicator){}
195 
196 #else
197 
200 MimmoPointCloud::MimmoPointCloud():bitpit::SurfUnstructured(2, 3){}
201 
206 MimmoPointCloud::MimmoPointCloud(int id):bitpit::SurfUnstructured(id, 2, 3){}
207 #endif
208 
213 
218 std::unique_ptr<bitpit::PatchKernel>
220  return bitpit::SurfUnstructured::clone();
221 }
222 
223 
235 MimmoObject::MimmoObject(int type, bool isParallel):m_patch(nullptr),m_extpatch(nullptr){
236 
237  // Initialize parallel data
238  m_isParallel = isParallel && MIMMO_ENABLE_MPI;
239 #if MIMMO_ENABLE_MPI
240  initializeMPI();
241  MPI_Comm_dup(MPI_COMM_WORLD, &m_communicator);
242  initializeCommunicator(m_isParallel);
243 #else
244  m_rank = 0;
245  m_nprocs = 1;
246 #endif
247 
248  //initialize the logger
250 
251  m_type = std::max(type,1);
252  switch(m_type){
253  case 1:
254 #if MIMMO_ENABLE_MPI
255  m_patch = std::move(std::unique_ptr<bitpit::PatchKernel>(new MimmoSurfUnstructured(2, getCommunicator())));
256 #else
257  m_patch = std::move(std::unique_ptr<bitpit::PatchKernel>(new MimmoSurfUnstructured(2)));
258 #endif
259  m_skdTree = std::move(std::unique_ptr<bitpit::PatchSkdTree>(new bitpit::SurfaceSkdTree(dynamic_cast<bitpit::SurfaceKernel*>(m_patch.get()))));
260  m_kdTree = std::move(std::unique_ptr<bitpit::KdTree<3,bitpit::Vertex,long> >(new bitpit::KdTree<3,bitpit::Vertex, long>()));
261  break;
262  case 2:
263 #if MIMMO_ENABLE_MPI
264  m_patch = std::move(std::unique_ptr<bitpit::PatchKernel>(new MimmoVolUnstructured(3, getCommunicator())));
265 #else
266  m_patch = std::move(std::unique_ptr<bitpit::PatchKernel>(new MimmoVolUnstructured(3)));
267 #endif
268  m_skdTree = std::move(std::unique_ptr<bitpit::PatchSkdTree>(new bitpit::VolumeSkdTree(dynamic_cast<bitpit::VolumeKernel*>(m_patch.get()))));
269  m_kdTree = std::move(std::unique_ptr<bitpit::KdTree<3,bitpit::Vertex,long> >(new bitpit::KdTree<3,bitpit::Vertex, long>()));
270  break;
271  case 3:
272 #if MIMMO_ENABLE_MPI
273  m_patch = std::move(std::unique_ptr<bitpit::PatchKernel>(new MimmoPointCloud(getCommunicator())));
274 #else
275  m_patch = std::move(std::unique_ptr<bitpit::PatchKernel>(new MimmoPointCloud()));
276 #endif
277  m_kdTree = std::move(std::unique_ptr<bitpit::KdTree<3,bitpit::Vertex,long> >(new bitpit::KdTree<3,bitpit::Vertex, long>()));
278  break;
279  case 4:
280 #if MIMMO_ENABLE_MPI
281  m_patch = std::move(std::unique_ptr<bitpit::PatchKernel>(new MimmoSurfUnstructured(1, getCommunicator())));
282 #else
283  m_patch = std::move(std::unique_ptr<bitpit::PatchKernel>(new MimmoSurfUnstructured(1)));
284 #endif
285  m_skdTree = std::move(std::unique_ptr<bitpit::PatchSkdTree>(new bitpit::SurfaceSkdTree(dynamic_cast<bitpit::SurfaceKernel*>(m_patch.get()))));
286  m_kdTree = std::move(std::unique_ptr<bitpit::KdTree<3,bitpit::Vertex,long> >(new bitpit::KdTree<3,bitpit::Vertex, long>()));
287  break;
288  default:
289  (*m_log)<<"Error MimmoObject: unrecognized data structure type in class construction."<<std::endl;
290  throw std::runtime_error ("MimmoObject : unrecognized mesh type in class construction");
291  break;
292  }
293 
294  m_internalPatch = true;
295 
296  // Set skdTreeSync and kdTreeSync to none
299 
300  // Set skdTreeSync to unsupported for point cloud
301  if (m_type == 3){
303  }
304 
305  // Set AdjSync and IntSync to none
308 
309  m_patchInfo.setPatch(m_patch.get());
310  m_patchInfo.update();
314 
315  setTolerance(1.0e-06);
316 }
317 
351 MimmoObject::MimmoObject(int type, dvecarr3E & vertex, livector2D * connectivity, bool isParallel):m_patch(nullptr),m_extpatch(nullptr){
352 
353  // Initialize parallel data
354  m_isParallel = isParallel && MIMMO_ENABLE_MPI;
355 #if MIMMO_ENABLE_MPI
356  initializeMPI();
357  initializeCommunicator(m_isParallel);
358 #else
359  m_rank = 0;
360  m_nprocs = 1;
361 #endif
362  //initialize the logger.
364 
365  m_type = std::max(type,1);
366  switch(m_type){
367  case 1:
368 #if MIMMO_ENABLE_MPI
369  m_patch = std::move(std::unique_ptr<bitpit::PatchKernel>(new MimmoSurfUnstructured(2, getCommunicator())));
370 #else
371  m_patch = std::move(std::unique_ptr<bitpit::PatchKernel>(new MimmoSurfUnstructured(2)));
372 #endif
373  m_skdTree = std::move(std::unique_ptr<bitpit::PatchSkdTree>(new bitpit::SurfaceSkdTree(dynamic_cast<bitpit::SurfaceKernel*>(m_patch.get()))));
374  m_kdTree = std::move(std::unique_ptr<bitpit::KdTree<3,bitpit::Vertex,long> >(new bitpit::KdTree<3,bitpit::Vertex, long>()));
375  break;
376  case 2:
377 #if MIMMO_ENABLE_MPI
378  m_patch = std::move(std::unique_ptr<bitpit::PatchKernel>(new MimmoVolUnstructured(3, getCommunicator())));
379 #else
380  m_patch = std::move(std::unique_ptr<bitpit::PatchKernel>(new MimmoVolUnstructured(3)));
381 #endif
382  m_skdTree = std::move(std::unique_ptr<bitpit::PatchSkdTree>(new bitpit::VolumeSkdTree(dynamic_cast<bitpit::VolumeKernel*>(m_patch.get()))));
383  m_kdTree = std::move(std::unique_ptr<bitpit::KdTree<3,bitpit::Vertex,long> >(new bitpit::KdTree<3,bitpit::Vertex, long>()));
384  break;
385  case 3:
386 #if MIMMO_ENABLE_MPI
387  m_patch = std::move(std::unique_ptr<bitpit::PatchKernel>(new MimmoPointCloud(getCommunicator())));
388 #else
389  m_patch = std::move(std::unique_ptr<bitpit::PatchKernel>(new MimmoPointCloud()));
390 #endif
391  m_kdTree = std::move(std::unique_ptr<bitpit::KdTree<3,bitpit::Vertex,long> >(new bitpit::KdTree<3,bitpit::Vertex, long>()));
392  break;
393  case 4:
394 #if MIMMO_ENABLE_MPI
395  m_patch = std::move(std::unique_ptr<bitpit::PatchKernel>(new MimmoSurfUnstructured(1, getCommunicator())));
396 #else
397  m_patch = std::move(std::unique_ptr<bitpit::PatchKernel>(new MimmoSurfUnstructured(1)));
398 #endif
399  m_skdTree = std::move(std::unique_ptr<bitpit::PatchSkdTree>(new bitpit::SurfaceSkdTree(dynamic_cast<bitpit::SurfaceKernel*>(m_patch.get()))));
400  m_kdTree = std::move(std::unique_ptr<bitpit::KdTree<3,bitpit::Vertex,long> >(new bitpit::KdTree<3,bitpit::Vertex, long>()));
401  break;
402  default:
403  (*m_log)<<"Error MimmoObject: unrecognized data structure type in class construction."<<std::endl;
404  throw std::runtime_error ("MimmoObject : unrecognized mesh type in class construction");
405  break;
406  }
407 
408  m_internalPatch = true;
409 
410  // Set skdTreeSync and kdTreeSync to none
413 
414  // Set skdTreeSync to unsupported for point cloud
415  if (m_type != 3){
417  }
418 
419  // Set AdjSync and IntSync to none
422 
423  bitpit::ElementType eltype;
424  std::size_t sizeVert = vertex.size();
425 
426  m_patch->reserveVertices(sizeVert);
427 
428  for(const auto & vv : vertex) addVertex(vv);
429 
430  m_log->setPriority(bitpit::log::Priority::DEBUG);
431 
432  livector1D temp;
433  std::size_t sizeCell = connectivity->size();
434  m_patch->reserveCells(sizeCell);
435  for(auto const & cc : *connectivity){
436  eltype = desumeElement(cc);
437  if(eltype != bitpit::ElementType::UNDEFINED){
438  addConnectedCell(cc, eltype); //if MPI, is adding cell with rank =-1, that is is using local m_rank.
439  }else{
440  (*m_log)<<"warning: in MimmoObject custom constructor. Undefined cell type detected and skipped."<<std::endl;
441  }
442  }
443 
444  m_pidsType.insert(0);
445  m_pidsTypeWNames.insert(std::make_pair(0,""));
446 
447  m_log->setPriority(bitpit::log::Priority::NORMAL);
448 
449  m_patchInfo.setPatch(m_patch.get());
450  m_patchInfo.update();
454 
455  setTolerance(1.0e-06);
456 
457 };
458 
469 MimmoObject::MimmoObject(int type, bitpit::PatchKernel* geometry):m_patch(nullptr),m_extpatch(nullptr){
470 
471  m_type = std::max(type,1);
472  if (m_type > 4 || geometry == nullptr){
473  throw std::runtime_error ("MimmoObject : unrecognized mesh type or nullptr argument in class construction");
474  }
475 
476  m_internalPatch = false;
477  m_extpatch = geometry;
478 
479  // Initialize parallel data
480  m_isParallel = false;
481 #if MIMMO_ENABLE_MPI
482  m_isParallel = geometry->getCommunicator() != MPI_COMM_NULL;
483  initializeMPI();
484  initializeCommunicator(m_isParallel);
485 #else
486  m_rank = 0;
487  m_nprocs = 1;
488 #endif
489 
491 
492  //check among elements if they are coherent with the type currently hold by the linked mesh.
493  std::unordered_set<int> mapEle = elementsMap(*geometry);
494  switch(m_type){
495  case 1:
496  if( mapEle.count((int)bitpit::ElementType::VERTEX) > 0 ||
497  mapEle.count((int)bitpit::ElementType::LINE) > 0 ||
498  mapEle.count((int)bitpit::ElementType::TETRA) > 0 ||
499  mapEle.count((int)bitpit::ElementType::HEXAHEDRON) > 0 ||
500  mapEle.count((int)bitpit::ElementType::VOXEL) > 0 ||
501  mapEle.count((int)bitpit::ElementType::WEDGE) > 0 ||
502  mapEle.count((int)bitpit::ElementType::PYRAMID) > 0 ||
503  mapEle.count((int)bitpit::ElementType::POLYHEDRON) > 0 ||
504  mapEle.count((int)bitpit::ElementType::UNDEFINED) > 0 )
505  {
506  (*m_log)<<"Error MimmoObject: unsupported Elements for required type in linked mesh."<<std::endl;
507  throw std::runtime_error ("MimmoObject :unsupported Elements for required type in linked mesh.");
508  }
509  m_skdTree = std::move(std::unique_ptr<bitpit::PatchSkdTree>(new bitpit::SurfaceSkdTree(dynamic_cast<bitpit::SurfaceKernel*>(geometry))));
510  m_kdTree = std::move(std::unique_ptr<bitpit::KdTree<3,bitpit::Vertex,long> >(new bitpit::KdTree<3,bitpit::Vertex, long>()));
511  break;
512  case 2:
513  if( mapEle.count((int)bitpit::ElementType::VERTEX) > 0 ||
514  mapEle.count((int)bitpit::ElementType::LINE) > 0 ||
515  mapEle.count((int)bitpit::ElementType::TRIANGLE) > 0 ||
516  mapEle.count((int)bitpit::ElementType::QUAD) > 0 ||
517  mapEle.count((int)bitpit::ElementType::PIXEL) > 0 ||
518  mapEle.count((int)bitpit::ElementType::POLYGON) > 0 ||
519  mapEle.count((int)bitpit::ElementType::UNDEFINED) > 0 )
520  {
521  (*m_log)<<"Error MimmoObject: unsupported Elements for required type in linked mesh."<<std::endl;
522  throw std::runtime_error ("MimmoObject :unsupported Elements for required type in linked mesh.");
523  }
524  m_skdTree = std::move(std::unique_ptr<bitpit::PatchSkdTree>(new bitpit::VolumeSkdTree(dynamic_cast<bitpit::VolumeKernel*>(geometry))));
525  m_kdTree = std::move(std::unique_ptr<bitpit::KdTree<3,bitpit::Vertex,long> >(new bitpit::KdTree<3,bitpit::Vertex, long>()));
526  break;
527  case 3:
528  if( mapEle.count((int)bitpit::ElementType::LINE) > 0 ||
529  mapEle.count((int)bitpit::ElementType::TRIANGLE) > 0 ||
530  mapEle.count((int)bitpit::ElementType::QUAD) > 0 ||
531  mapEle.count((int)bitpit::ElementType::PIXEL) > 0 ||
532  mapEle.count((int)bitpit::ElementType::POLYGON) > 0 ||
533  mapEle.count((int)bitpit::ElementType::TETRA) > 0 ||
534  mapEle.count((int)bitpit::ElementType::HEXAHEDRON) > 0 ||
535  mapEle.count((int)bitpit::ElementType::VOXEL) > 0 ||
536  mapEle.count((int)bitpit::ElementType::WEDGE) > 0 ||
537  mapEle.count((int)bitpit::ElementType::PYRAMID) > 0 ||
538  mapEle.count((int)bitpit::ElementType::POLYHEDRON) > 0 ||
539  mapEle.count((int)bitpit::ElementType::UNDEFINED) > 0 )
540  {
541  (*m_log)<<"Error MimmoObject: unsupported elements for required type in linked mesh."<<std::endl;
542  throw std::runtime_error ("MimmoObject :unsupported elements for required type in linked mesh.");
543  }
544  m_kdTree = std::move(std::unique_ptr<bitpit::KdTree<3,bitpit::Vertex,long> >(new bitpit::KdTree<3,bitpit::Vertex, long>()));
545  break;
546  case 4:
547  if( mapEle.count((int)bitpit::ElementType::VERTEX) > 0 ||
548  mapEle.count((int)bitpit::ElementType::TRIANGLE) > 0 ||
549  mapEle.count((int)bitpit::ElementType::QUAD) > 0 ||
550  mapEle.count((int)bitpit::ElementType::PIXEL) > 0 ||
551  mapEle.count((int)bitpit::ElementType::POLYGON) > 0 ||
552  mapEle.count((int)bitpit::ElementType::TETRA) > 0 ||
553  mapEle.count((int)bitpit::ElementType::HEXAHEDRON) > 0 ||
554  mapEle.count((int)bitpit::ElementType::VOXEL) > 0 ||
555  mapEle.count((int)bitpit::ElementType::WEDGE) > 0 ||
556  mapEle.count((int)bitpit::ElementType::PYRAMID) > 0 ||
557  mapEle.count((int)bitpit::ElementType::POLYHEDRON) > 0 ||
558  mapEle.count((int)bitpit::ElementType::UNDEFINED) > 0 )
559  {
560  (*m_log)<<"Error MimmoObject: unsupported elements for required type in linked mesh."<<std::endl;
561  throw std::runtime_error ("MimmoObject :unsupported elements for required type in linked mesh.");
562  }
563  m_skdTree = std::move(std::unique_ptr<bitpit::PatchSkdTree>(new bitpit::SurfaceSkdTree(dynamic_cast<bitpit::SurfaceKernel*>(geometry))));
564  m_kdTree = std::move(std::unique_ptr<bitpit::KdTree<3,bitpit::Vertex,long> >(new bitpit::KdTree<3,bitpit::Vertex, long>()));
565  break;
566  default:
567  //never been reached
568  break;
569  }
570 
571  // Set skdTreeSync and kdTreeSync to none
574 
575  // Set skdTreeSync to unsupported for point cloud
576  if (m_type == 3){
578  }
579 
580  // Check if adjacencies and interfaces are built.(Patch called it BuildStrategy -- NONE is unbuilt)
581  if (geometry->getAdjacenciesBuildStrategy() == bitpit::PatchKernel::AdjacenciesBuildStrategy::ADJACENCIES_NONE){
583  }
584  else{
585  // Set to UNSYNC to safeness
587  }
588 
589  if (geometry->getInterfacesBuildStrategy() == bitpit::PatchKernel::InterfacesBuildStrategy::INTERFACES_NONE){
591  }
592  else{
593  // Set to UNSYNC to safeness
595  }
596 
597  //recover cell PID
598  for(const auto &cell : getPatch()->getCells()){
599  auto PID = cell.getPID();
600  m_pidsType.insert((long)PID);
601  m_pidsTypeWNames.insert(std::make_pair( (long)PID , "") );
602  }
603 
604  m_patchInfo.setPatch(m_extpatch);
605  m_patchInfo.update();
609 
610  setTolerance(1.0e-06);
611 
612 }
613 
625 MimmoObject::MimmoObject(int type, std::unique_ptr<bitpit::PatchKernel> & geometry):m_patch(nullptr),m_extpatch(nullptr){
626 
627  if (!geometry){
628  throw std::runtime_error ("MimmoObject : nullptr argument in class construction");
629  }
630 
631  m_internalPatch = true;
632  m_patch = std::move(geometry);
633 
634  // Initialize parallel data
635  m_isParallel = false;
636 #if MIMMO_ENABLE_MPI
637  m_isParallel = getPatch()->getCommunicator() != MPI_COMM_NULL;
638  initializeMPI();
639  initializeCommunicator(m_isParallel);
640 #else
641  m_rank = 0;
642  m_nprocs = 1;
643 #endif
644 
645  //check among elements if they are coherent with the type currently hold by the linked mesh.
646  m_type = std::max(type,1);
647  std::unordered_set<int> mapEle = elementsMap(*(getPatch()));
648  switch(m_type){
649  case 1:
650  if(mapEle.count((int)bitpit::ElementType::VERTEX) > 0 ||
651  mapEle.count((int)bitpit::ElementType::LINE) > 0 ||
652  mapEle.count((int)bitpit::ElementType::TETRA) > 0 ||
653  mapEle.count((int)bitpit::ElementType::HEXAHEDRON) > 0 ||
654  mapEle.count((int)bitpit::ElementType::VOXEL) > 0 ||
655  mapEle.count((int)bitpit::ElementType::WEDGE) > 0 ||
656  mapEle.count((int)bitpit::ElementType::PYRAMID) > 0 ||
657  mapEle.count((int)bitpit::ElementType::POLYHEDRON) > 0 ||
658  mapEle.count((int)bitpit::ElementType::UNDEFINED) > 0 )
659  {
660  (*m_log)<<"Error MimmoObject: unsupported Elements for required type in linked mesh."<<std::endl;
661  throw std::runtime_error ("MimmoObject :unsupported Elements for required type in linked mesh.");
662  }
663  m_skdTree = std::move(std::unique_ptr<bitpit::PatchSkdTree>(new bitpit::SurfaceSkdTree(dynamic_cast<bitpit::SurfaceKernel*>(getPatch()))));
664  m_kdTree = std::move(std::unique_ptr<bitpit::KdTree<3,bitpit::Vertex,long> >(new bitpit::KdTree<3,bitpit::Vertex, long>()));
665  break;
666  case 2:
667  if( mapEle.count((int)bitpit::ElementType::VERTEX) > 0 ||
668  mapEle.count((int)bitpit::ElementType::LINE) > 0 ||
669  mapEle.count((int)bitpit::ElementType::TRIANGLE) > 0 ||
670  mapEle.count((int)bitpit::ElementType::QUAD) > 0 ||
671  mapEle.count((int)bitpit::ElementType::PIXEL) > 0 ||
672  mapEle.count((int)bitpit::ElementType::POLYGON) > 0 ||
673  mapEle.count((int)bitpit::ElementType::UNDEFINED) > 0 )
674  {
675  (*m_log)<<"Error MimmoObject: unsupported Elements for required type in linked mesh."<<std::endl;
676  throw std::runtime_error ("MimmoObject :unsupported Elements for required type in linked mesh.");
677  }
678  m_skdTree = std::move(std::unique_ptr<bitpit::PatchSkdTree>(new bitpit::VolumeSkdTree(dynamic_cast<bitpit::VolumeKernel*>(getPatch()))));
679  m_kdTree = std::move(std::unique_ptr<bitpit::KdTree<3,bitpit::Vertex,long> >(new bitpit::KdTree<3,bitpit::Vertex, long>()));
680  break;
681  case 3:
682  if( mapEle.count((int)bitpit::ElementType::LINE) > 0 ||
683  mapEle.count((int)bitpit::ElementType::TRIANGLE) > 0 ||
684  mapEle.count((int)bitpit::ElementType::QUAD) > 0 ||
685  mapEle.count((int)bitpit::ElementType::PIXEL) > 0 ||
686  mapEle.count((int)bitpit::ElementType::POLYGON) > 0 ||
687  mapEle.count((int)bitpit::ElementType::TETRA) > 0 ||
688  mapEle.count((int)bitpit::ElementType::HEXAHEDRON) > 0 ||
689  mapEle.count((int)bitpit::ElementType::VOXEL) > 0 ||
690  mapEle.count((int)bitpit::ElementType::WEDGE) > 0 ||
691  mapEle.count((int)bitpit::ElementType::PYRAMID) > 0 ||
692  mapEle.count((int)bitpit::ElementType::POLYHEDRON) > 0 ||
693  mapEle.count((int)bitpit::ElementType::UNDEFINED) > 0 )
694  {
695  (*m_log)<<"Error MimmoObject: unsupported elements for required type in linked mesh."<<std::endl;
696  throw std::runtime_error ("MimmoObject :unsupported elements for required type in linked mesh.");
697  } m_kdTree = std::move(std::unique_ptr<bitpit::KdTree<3,bitpit::Vertex,long> >(new bitpit::KdTree<3,bitpit::Vertex, long>()));
698  break;
699  case 4:
700  if( mapEle.count((int)bitpit::ElementType::VERTEX) > 0 ||
701  mapEle.count((int)bitpit::ElementType::TRIANGLE) > 0 ||
702  mapEle.count((int)bitpit::ElementType::QUAD) > 0 ||
703  mapEle.count((int)bitpit::ElementType::PIXEL) > 0 ||
704  mapEle.count((int)bitpit::ElementType::POLYGON) > 0 ||
705  mapEle.count((int)bitpit::ElementType::TETRA) > 0 ||
706  mapEle.count((int)bitpit::ElementType::HEXAHEDRON) > 0 ||
707  mapEle.count((int)bitpit::ElementType::VOXEL) > 0 ||
708  mapEle.count((int)bitpit::ElementType::WEDGE) > 0 ||
709  mapEle.count((int)bitpit::ElementType::PYRAMID) > 0 ||
710  mapEle.count((int)bitpit::ElementType::POLYHEDRON) > 0 ||
711  mapEle.count((int)bitpit::ElementType::UNDEFINED) > 0 )
712  {
713  (*m_log)<<"Error MimmoObject: unsupported elements for required type in linked mesh."<<std::endl;
714  throw std::runtime_error ("MimmoObject :unsupported elements for required type in linked mesh.");
715  }
716  m_skdTree = std::move(std::unique_ptr<bitpit::PatchSkdTree>(new bitpit::SurfaceSkdTree(dynamic_cast<bitpit::SurfaceKernel*>(getPatch()))));
717  m_kdTree = std::move(std::unique_ptr<bitpit::KdTree<3,bitpit::Vertex,long> >(new bitpit::KdTree<3,bitpit::Vertex, long>()));
718  break;
719  default:
720  throw std::runtime_error ("MimmoObject : unrecognized mesh type in class construction");
721  break;
722  }
723 
725 
726  // Set skdTreeSync and kdTreeSync to none
729 
730  // Set skdTreeSync to unsupported for point cloud
731  if (m_type == 3){
733  }
734 
735  // Check if adjacencies and interfaces are built.(Patch called it BuildStrategy -- NONE is unbuilt)
736  if (getPatch()->getAdjacenciesBuildStrategy() == bitpit::PatchKernel::AdjacenciesBuildStrategy::ADJACENCIES_NONE){
738  }
739  else{
740  // Set to UNSYNC to safeness
742  }
743 
744  if (getPatch()->getInterfacesBuildStrategy() == bitpit::PatchKernel::InterfacesBuildStrategy::INTERFACES_NONE){
746  }
747  else{
748  // Set to UNSYNC to safeness
750  }
751 
752  //recover cell PID
753  for(const auto &cell : getPatch()->getCells()){
754  auto PID = cell.getPID();
755  m_pidsType.insert((long)PID);
756  m_pidsTypeWNames.insert(std::make_pair( (long)PID , "") );
757  }
758 
759  m_patchInfo.setPatch(m_patch.get());
760  m_patchInfo.update();
764 
765  setTolerance(1.0e-06);
766 
767 }
768 
773 
782 
783  m_log = &bitpit::log::cout(MIMMO_LOG_FILE);
784 
785  m_isParallel = other.m_isParallel;
786 
787  m_extpatch = other.m_extpatch;
788  if(other.m_internalPatch){
789  m_extpatch = other.m_patch.get();
790  }
791  m_internalPatch = false;
792 
793  m_type = other.m_type;
794  m_pidsType = other.m_pidsType;
796  m_AdjSync = other.m_AdjSync;
797  m_IntSync = other.m_IntSync;
799 
800  m_patchInfo.setPatch(m_extpatch);
801  m_patchInfo.update();
803 
806 
807  //instantiate empty trees:
808  switch(m_type){
809  case 1:
810  m_skdTree = std::move(std::unique_ptr<bitpit::PatchSkdTree>(new bitpit::SurfaceSkdTree(dynamic_cast<bitpit::SurfaceKernel*>(m_extpatch))));
811  m_kdTree = std::move(std::unique_ptr<bitpit::KdTree<3,bitpit::Vertex,long> >(new bitpit::KdTree<3,bitpit::Vertex, long>()));
812  break;
813  case 2:
814  m_skdTree = std::move(std::unique_ptr<bitpit::PatchSkdTree>(new bitpit::VolumeSkdTree(dynamic_cast<bitpit::VolumeKernel*>(m_extpatch))));
815  m_kdTree = std::move(std::unique_ptr<bitpit::KdTree<3,bitpit::Vertex,long> >(new bitpit::KdTree<3,bitpit::Vertex, long>()));
816  break;
817  case 3:
818  m_kdTree = std::move(std::unique_ptr<bitpit::KdTree<3,bitpit::Vertex,long> >(new bitpit::KdTree<3,bitpit::Vertex, long>()));
819  break;
820  case 4:
821  m_skdTree = std::move(std::unique_ptr<bitpit::PatchSkdTree>(new bitpit::SurfaceSkdTree(dynamic_cast<bitpit::SurfaceKernel*>(m_extpatch))));
822  m_kdTree = std::move(std::unique_ptr<bitpit::KdTree<3,bitpit::Vertex,long> >(new bitpit::KdTree<3,bitpit::Vertex, long>()));
823  break;
824  default:
825  //never been reached
826  break;
827  }
828 
829 #if MIMMO_ENABLE_MPI
830  m_rank = other.m_rank;
831  m_nprocs = other.m_nprocs;
832  MPI_Comm_dup(other.m_communicator, &m_communicator);
833  m_nglobalvertices = other.m_nglobalvertices;
834  m_pointGhostExchangeInfoSync = SyncStatus::NONE;
835 #else
836  m_rank = 0;
837  m_nprocs=1;
838 #endif
839 
841 
842  m_tolerance = other.m_tolerance;
843 
844 };
845 
854 MimmoObject & MimmoObject::operator=(MimmoObject other){
855  swap(other);
856  return *this;
857 };
858 
863 void MimmoObject::swap(MimmoObject & x) noexcept
864 {
865  std::swap(m_patch, x.m_patch);
866  std::swap(m_extpatch, x.m_extpatch);
867  std::swap(m_internalPatch, x.m_internalPatch);
868  std::swap(m_type, x.m_type);
869  std::swap(m_pidsType, x.m_pidsType);
870  std::swap(m_pidsTypeWNames, x.m_pidsTypeWNames);
871  std::swap(m_AdjSync, x.m_AdjSync);
872  std::swap(m_IntSync, x.m_IntSync);
873  std::swap(m_skdTree, x.m_skdTree);
874  std::swap(m_kdTree, x.m_kdTree);
875  std::swap(m_skdTreeSync, x.m_skdTreeSync);
876  std::swap(m_kdTreeSync, x.m_kdTreeSync);
877  std::swap(m_boundingBoxSync, x.m_boundingBoxSync);
878 
879  m_patchInfo.setPatch(getPatch());
880  m_patchInfo.update();
881  m_infoSync = SyncStatus::SYNC;
882 
883 #if MIMMO_ENABLE_MPI
884  std::swap(m_isParallel, x.m_isParallel);
885  MPI_Comm dummy_communicator = MPI_COMM_NULL;
886  MPI_Comm_dup(m_communicator, &dummy_communicator);
887  MPI_Comm_dup(x.m_communicator, &m_communicator);
888  MPI_Comm_dup(dummy_communicator, &x.m_communicator);
889  MPI_Comm_free(&dummy_communicator);
890  std::swap(m_rank, x.m_rank);
891  std::swap(m_nprocs, x.m_nprocs);
892  std::swap(m_nglobalvertices, x.m_nglobalvertices);
893  m_pointGhostExchangeInfoSync = SyncStatus::NONE;
894 #endif
895  m_pointConnectivitySync = SyncStatus::NONE; //point connectivity is not copied
896 
897  std::swap(m_tolerance, x.m_tolerance);
898 
899 }
900 
904 void
906 
907  bool logexists = bitpit::log::manager().exists(MIMMO_LOG_FILE);
908 
909  if (!logexists){
910 #if MIMMO_ENABLE_MPI
911  // MPI variables have to be already initialized
912  bitpit::log::manager().initialize(bitpit::log::Mode::COMBINED, MIMMO_LOG_FILE, true, MIMMO_LOG_DIR, m_nprocs, m_rank);
913 #else
914  bitpit::log::manager().initialize(bitpit::log::Mode::COMBINED, MIMMO_LOG_FILE, true, MIMMO_LOG_DIR);
915 #endif
916  }
917  m_log = &bitpit::log::cout(MIMMO_LOG_FILE);
918  bitpit::log::setVisibility((*m_log), bitpit::log::Visibility::MASTER);
919  bitpit::log::setConsoleVerbosity((*m_log), bitpit::log::NORMAL);
920  bitpit::log::setFileVerbosity((*m_log), bitpit::log::NORMAL);
921 
922 }
923 
924 #if MIMMO_ENABLE_MPI
925 
928 void
929 MimmoObject::initializeMPI(){
930 
931  int initialized;
932  MPI_Initialized(&initialized);
933  if (!initialized)
934  MPI_Init(nullptr, nullptr);
935 
936 }
937 
942 void
943 MimmoObject::initializeCommunicator(bool isParallel){
944 
945  // If patch not yet set initialize the communicator with MPI_COMM_WORLD
946  // This will be used to initialize an internal patch
947  // Otherwise use a duplicate of the communicator of the patch
948  if (!getPatch()){
949 
950  if (isParallel){
951  MPI_Comm_dup(MPI_COMM_WORLD, &m_communicator);
952  MPI_Comm_rank(m_communicator, &m_rank);
953  MPI_Comm_size(m_communicator, &m_nprocs);
954  }else{
955  m_communicator = MPI_COMM_NULL;
956  m_rank = 0;
957  m_nprocs = 1;
958  }
959 
960  }else{
961 
962  // Recover communicator of the patch (always defined as parallel if I'm here)
963  MPI_Comm_dup(getPatch()->getCommunicator(), &m_communicator);
964  m_rank = getPatch()->getRank();
965  m_nprocs = getPatch()->getProcessorCount();
966 
967  }
968 
969  m_pointGhostExchangeInfoSync = SyncStatus::NONE;
970 
971 }
972 #endif
973 
977 bitpit::Logger&
979  return (*m_log);
980 }
981 
986 bool
988 
989  bool check = getNVertices() == 0;
990  check = check || (getNCells() == 0);
991 
992  return check;
993 };
994 
995 
1000 bool
1003 };
1004 
1010 int
1012  return m_type;
1013 };
1014 
1020 long
1022  const auto p = getPatch();
1023  return p->getVertexCount();
1024 };
1025 
1031 long
1033  const auto p = getPatch();
1034  return p->getCellCount();
1035 };
1036 
1042 long
1043 MimmoObject::getNVertices() const {
1044  const auto p = getPatch();
1045  return p->getVertexCount();
1046 };
1047 
1053 long
1054 MimmoObject::getNCells() const {
1055  const auto p = getPatch();
1056  return p->getCellCount();
1057 };
1058 
1063 long
1065  const auto p = getPatch();
1066  return p->getInternalCellCount();
1067 };
1068 
1073 long
1075 #if MIMMO_ENABLE_MPI
1076  if (!isDistributed())
1077 #endif
1078  return getNVertices();
1079 #if MIMMO_ENABLE_MPI
1080  return m_ninteriorvertices;
1081 #endif
1082 };
1083 
1084 #if MIMMO_ENABLE_MPI
1085 
1090 long
1091 MimmoObject::getNGlobalVertices(){
1092  if (!isParallel()){
1093  const auto p = getPatch();
1094  return p->getVertexCount();
1095  }
1096 
1097  return m_nglobalvertices;
1098 };
1099 
1105 long
1106 MimmoObject::getNGlobalCells() {
1107  if (!isParallel())
1108  return getNCells();
1109 
1110  return getPatchInfo()->getCellGlobalCount();
1111 };
1112 
1118 long
1119 MimmoObject::getPointGlobalCountOffset(){
1120  if (!isParallel())
1121  return 0;
1122 
1123  return m_globaloffset;
1124 };
1125 
1126 #endif
1127 
1135 dvecarr3E
1137  dvecarr3E result(getNVertices());
1138  int i = 0;
1139 
1140  auto pvert = getVertices();
1141 
1142  if (mapDataInv != nullptr){
1143  for (auto const & vertex : pvert){
1144  result[i] = vertex.getCoords();
1145  (*mapDataInv)[vertex.getId()] = i;
1146  ++i;
1147  }
1148  }
1149  else{
1150  for (auto const & vertex : pvert){
1151  result[i] = vertex.getCoords();
1152  ++i;
1153  }
1154  }
1155  return result;
1156 };
1157 
1164 const darray3E &
1166 {
1167  assert(getVertices().exists(i));
1168  return getPatch()->getVertexCoords(i);
1169 };
1170 
1176 bitpit::PiercedVector<bitpit::Vertex> &
1178  return getPatch()->getVertices();
1179 }
1180 
1186 const bitpit::PiercedVector<bitpit::Vertex> &
1187 MimmoObject::getVertices() const {
1188  const auto p = getPatch();
1189  return p->getVertices();
1190 }
1191 
1203 livector2D
1205 
1206  livector2D connecti(getNCells());
1207  int np, counter =0;
1208 
1209  for(auto const & cell : getCells()){
1210  np = cell.getConnectSize();
1211  const long * conn_ = cell.getConnect();
1212  connecti[counter].resize(np);
1213  bitpit::ElementType eltype = cell.getType();
1214 
1215  if(eltype == bitpit::ElementType::POLYGON){
1216  connecti[counter][0] = conn_[0];
1217  for (int i=1; i<np; ++i){
1218  connecti[counter][i] = mapDataInv[conn_[i]];
1219  }
1220  }else if(eltype == bitpit::ElementType::POLYHEDRON){
1221  connecti[counter][0] = conn_[0];
1222  for(int nF = 0; nF < conn_[0]-1; ++nF){
1223  int facePos = cell.getFaceStreamPosition(nF);
1224  int beginVertexPos = facePos + 1;
1225  int endVertexPos = facePos + 1 + conn_[facePos];
1226  connecti[counter][facePos] = conn_[facePos];
1227  for (int i=beginVertexPos; i<endVertexPos; ++i){
1228  connecti[counter][i] = mapDataInv[conn_[i]];
1229  }
1230  }
1231  }else{
1232  for (int i=0; i<np; ++i){
1233  connecti[counter][i] = mapDataInv[conn_[i]];
1234  }
1235  }
1236  ++counter;
1237  }
1238  return connecti;
1239 }
1240 
1249 livector2D
1251 
1252  livector2D connecti(getNCells());
1253  int np, counter =0;
1254 
1255  for(auto const & cell : getCells()){
1256  np = cell.getConnectSize();
1257  const long * conn_ = cell.getConnect();
1258  connecti[counter].resize(np);
1259  for (int i=0; i<np; ++i){
1260  connecti[counter][i] = conn_[i];
1261  }
1262  ++counter;
1263  }
1264 
1265  return connecti;
1266 };
1267 
1280 livector1D
1282  if (!(getCells().exists(i))) return livector1D(0);
1283 
1284  const bitpit::Cell & cell = getPatch()->getCell(i);
1285  int np = cell.getConnectSize();
1286  const long * conn_ = cell.getConnect();
1287  livector1D connecti(np);
1288 
1289  for (int j=0; j<np; j++){
1290  connecti[j] = conn_[j];
1291  }
1292  return connecti;
1293 };
1294 
1300 bitpit::PiercedVector<bitpit::Cell> &
1302  return getPatch()->getCells();
1303 }
1304 
1310 const bitpit::PiercedVector<bitpit::Cell> &
1311 MimmoObject::getCells() const{
1312  const auto p = getPatch();
1313  return p->getCells();
1314 }
1315 
1321 bitpit::PiercedVector<bitpit::Interface> &
1323  return getPatch()->getInterfaces();
1324 }
1325 
1331 const bitpit::PiercedVector<bitpit::Interface> &
1333  const auto p = getPatch();
1334  return p->getInterfaces();
1335 }
1336 
1344 livector1D
1345 MimmoObject::getCellsIds(bool internalsOnly){
1346 
1347  std::vector<long> ids;
1348 
1349 #if MIMMO_ENABLE_MPI
1350  //MPI version
1351  if(internalsOnly){
1352  ids.reserve(getPatch()->getInternalCellCount());
1353  for(bitpit::PatchKernel::CellIterator it = getPatch()->internalCellBegin(); it!= getPatch()->internalCellEnd(); ++it){
1354  ids.push_back(it.getId());
1355  }
1356  }else{
1357  ids = getPatch()->getCells().getIds();
1358  }
1359 #else
1360  //SERIAL version
1361  BITPIT_UNUSED(internalsOnly);
1362  ids = getPatch()->getCells().getIds();
1363 #endif
1364 
1365  return ids;
1366 };
1367 
1375 livector1D
1376 MimmoObject::getVerticesIds(bool internalsOnly){
1377 
1378  livector1D ids;
1379 
1380  if(internalsOnly){
1381  ids.reserve(getNInternalVertices());
1382  }
1383  else{
1384  ids.reserve(getNVertices());
1385  }
1386 
1387  for(const bitpit::Vertex & vertex : getVertices()){
1388  long vertexId = vertex.getId();
1389  if(!internalsOnly || isPointInterior(vertexId)){
1390  ids.push_back(vertexId);
1391  }
1392  }
1393 
1394  return ids;
1395 };
1396 
1397 
1401 bitpit::PatchKernel*
1403  if(!m_internalPatch) return m_extpatch;
1404  else return m_patch.get();
1405 };
1406 
1410 const bitpit::PatchKernel*
1411 MimmoObject::getPatch() const{
1412  if(!m_internalPatch) return m_extpatch;
1413  else return m_patch.get();
1414 };
1415 
1422 lilimap
1423 MimmoObject::getMapData(bool withghosts){
1424  lilimap mapData;
1425  lilimap mapDataInv = getMapDataInv(withghosts);
1426  for (auto const & vertex : getVertices()){
1427  long id = vertex.getId();
1428  if (mapDataInv.count(id))
1429  mapData[mapDataInv[id]] = id;
1430  }
1431  return mapData;
1432 };
1433 
1440 lilimap
1442 
1443  lilimap mapDataInv;
1444 #if MIMMO_ENABLE_MPI
1445  if (isDistributed()){
1446  for (auto val : m_pointConsecutiveId){
1447  if (!withghosts && !isPointInterior(val.first)){
1448  continue;
1449  }
1450  mapDataInv.insert(val);
1451  }
1452  return mapDataInv;
1453  }
1454 #else
1455  BITPIT_UNUSED(withghosts);
1456 #endif
1457  int i = 0;
1458  for (auto const & vertex : getVertices()){
1459  mapDataInv[vertex.getId()] = i;
1460  ++i;
1461  }
1462  return mapDataInv;
1463 };
1464 
1472 lilimap
1473 MimmoObject::getMapCell(bool withghosts){
1474  lilimap mapCell;
1475  for (auto const & cell : getCells()){
1476  long id = cell.getId();
1477  if (!withghosts && !cell.isInterior()){
1478  continue;
1479  }
1480  long i = getPatchInfo()->getCellConsecutiveId(id);
1481  mapCell[i] = id;
1482  }
1483  return mapCell;
1484 };
1485 
1493 lilimap
1495  lilimap mapCellInv = getPatchInfo()->getCellConsecutiveMap();
1496  if (!withghosts){
1497  std::vector<long> todelete;
1498  for (auto & val : mapCellInv){
1499  if (!getPatch()->getCell(val.second).isInterior()){
1500  todelete.push_back(val.first);
1501  }
1502  }
1503  for (int id : todelete){
1504  mapCellInv.erase(id);
1505  }
1506  }
1507  return mapCellInv;
1508 };
1509 
1514 std::unordered_set<long> &
1516  return m_pidsType;
1517 };
1518 
1523 std::unordered_map<long, std::string> &
1525  return m_pidsTypeWNames;
1526 };
1527 
1532 const std::unordered_set<long> &
1534  return m_pidsType;
1535 };
1536 
1541 const std::unordered_map<long, std::string> &
1543  return m_pidsTypeWNames;
1544 };
1545 
1551 livector1D
1553  if(m_pidsType.empty()) return livector1D(0);
1554  livector1D result(getNCells());
1555  int counter=0;
1556  for(auto const & cell : getCells()){
1557  result[counter] = (long)cell.getPID();
1558  ++counter;
1559  }
1560  return(result);
1561 };
1562 
1568 std::unordered_map<long,long>
1570  if(m_pidsType.empty()) return std::unordered_map<long,long>();
1571  std::unordered_map<long,long> result;
1572  for(auto const & cell : getCells()){
1573  result[cell.getId()] = (long) cell.getPID();
1574  }
1575  return(result);
1576 };
1577 
1582 SyncStatus
1584  return m_skdTreeSync;
1585 }
1586 
1591 SyncStatus
1593  return m_infoSync;
1594 }
1595 
1600 SyncStatus
1602  return m_boundingBoxSync;
1603 }
1604 
1608 bitpit::PatchSkdTree*
1610  return m_skdTree.get();
1611 }
1612 
1616 bitpit::PatchNumberingInfo*
1618  return &m_patchInfo;
1619 }
1620 
1625 SyncStatus
1627  return m_kdTreeSync;
1628 }
1629 
1633 bitpit::KdTree<3, bitpit::Vertex, long >*
1635  return m_kdTree.get();
1636 }
1637 
1643 bool
1645 {
1646 #if MIMMO_ENABLE_MPI
1647  return getPatch()->getVertex(id).isInterior();
1648 #else
1649  BITPIT_UNUSED(id);
1650  return true;
1651 #endif
1652 }
1653 
1658 double
1660  return m_tolerance;
1661 }
1662 
1669 {
1670  return m_rank;
1671 }
1672 
1679 {
1680  return m_nprocs;
1681 }
1682 
1683 
1684 #if MIMMO_ENABLE_MPI
1685 
1691 const MPI_Comm & MimmoObject::getCommunicator() const
1692 {
1693  return m_communicator;
1694 }
1695 
1702 const std::unordered_map<int, std::vector<long>> & MimmoObject::getPointGhostExchangeTargets() const
1703 {
1704  return getPatch()->getGhostVertexExchangeTargets();
1705 }
1706 
1713 const std::unordered_map<int, std::vector<long>> & MimmoObject::getPointGhostExchangeSources() const
1714 {
1715  return getPatch()->getGhostVertexExchangeSources();
1716 }
1717 
1718 
1723 SyncStatus
1724 MimmoObject::getPointGhostExchangeInfoSyncStatus()
1725 {
1726  MPI_Barrier(m_communicator);
1727  MPI_Allreduce(MPI_IN_PLACE, &m_pointGhostExchangeInfoSync, 1, MPI_LONG, MPI_MIN, m_communicator);
1728  return m_pointGhostExchangeInfoSync;
1729 }
1730 
1735 void MimmoObject::updatePointGhostExchangeInfo()
1736 {
1737 
1738  //Update n interior vertices
1739  m_ninteriorvertices = 0;
1740  for (long vertexId : getVerticesIds()){
1741  if (isPointInterior(vertexId)){
1742  m_ninteriorvertices++;
1743  }
1744  }
1745 
1746  //Update n global vertices
1747  m_nglobalvertices = 0;
1748  MPI_Allreduce(&m_ninteriorvertices, &m_nglobalvertices, 1, MPI_LONG, MPI_SUM, m_communicator);
1749 
1750  //Update n interior vertices for procs
1751  m_rankinteriorvertices.clear();
1752  m_rankinteriorvertices.resize(m_nprocs);
1753  m_rankinteriorvertices[m_rank] = m_ninteriorvertices;
1754  long rankinteriorvertices = m_rankinteriorvertices[m_rank];
1755  MPI_Allgather(&rankinteriorvertices, 1, MPI_LONG, m_rankinteriorvertices.data(), 1, MPI_LONG, m_communicator);
1756 
1757  //Update global offset
1758  m_globaloffset = 0;
1759  for (int i=0; i<m_rank; i++){
1760  m_globaloffset += m_rankinteriorvertices[i];
1761  }
1762 
1763  //---
1764  //Create consecutive map for vertices and fill locals
1765  //---
1766  m_pointConsecutiveId.clear();
1767  long consecutiveId = m_globaloffset;
1768  //Insert owned vertices
1769  for (const long & id : getVerticesIds()){
1770  if (isPointInterior(id)){
1771  m_pointConsecutiveId[id] = consecutiveId;
1772  consecutiveId++;
1773  }
1774  }
1775 
1776 
1777  //---
1778  //Communicate consecutive ids for ghost points
1779  //---
1780  {
1781  size_t exchangeDataSize = sizeof(consecutiveId);
1782  std::unique_ptr<bitpit::DataCommunicator> dataCommunicator;
1783  dataCommunicator = std::unique_ptr<bitpit::DataCommunicator>(new bitpit::DataCommunicator(getCommunicator()));
1784 
1785  // Set and start the sends
1786  for (const auto entry : getPointGhostExchangeSources()) {
1787  const int rank = entry.first;
1788  auto &list = entry.second;
1789  dataCommunicator->setSend(rank, list.size() * exchangeDataSize);
1790  bitpit::SendBuffer &buffer = dataCommunicator->getSendBuffer(rank);
1791  for (long id : list) {
1792  if (m_pointConsecutiveId.count(id)){
1793  buffer << m_pointConsecutiveId.at(id);
1794  }else{
1795  buffer << long(-1);
1796  }
1797  }
1798  dataCommunicator->startSend(rank);
1799  }
1800 
1801  // Discover & start all the receives
1802  dataCommunicator->discoverRecvs();
1803  dataCommunicator->startAllRecvs();
1804 
1805  // Receive the consecutive ids of the ghosts
1806  int nCompletedRecvs = 0;
1807  while (nCompletedRecvs < dataCommunicator->getRecvCount()) {
1808  int rank = dataCommunicator->waitAnyRecv();
1809  const auto &list = getPointGhostExchangeTargets().at(rank);
1810  bitpit::RecvBuffer &buffer = dataCommunicator->getRecvBuffer(rank);
1811  for (long id : list) {
1812  buffer >> consecutiveId;
1813  if (consecutiveId > -1){
1814  m_pointConsecutiveId[id] = consecutiveId;
1815  }
1816  }
1817  ++nCompletedRecvs;
1818  }
1819  // Wait for the sends to finish
1820  dataCommunicator->waitAllSends();
1821  }
1822 
1823  // Exchange info are now updated
1824  m_pointGhostExchangeInfoSync = SyncStatus::SYNC;
1825 }
1826 
1831 void MimmoObject::resetPointGhostExchangeInfo()
1832 {
1833  //Update n interior vertices
1834  m_ninteriorvertices = 0;
1835 
1836  //Update n global vertices
1837  m_nglobalvertices = 0;
1838 
1839  //Update n interior vertices for procs
1840  m_rankinteriorvertices.clear();
1841 
1842  //Update global offset
1843  m_globaloffset = 0;
1844 
1845  //Reset consecutive map for vertices
1846  m_pointConsecutiveId.clear();
1847 
1848  if(m_pointGhostExchangeInfoSync == SyncStatus::SYNC){
1849  m_pointGhostExchangeInfoSync = SyncStatus::UNSYNC;
1850  }
1851 }
1852 
1858 SyncStatus
1859 MimmoObject::cleanParallelSkdTreeSync(){
1860 
1861  MPI_Allreduce(MPI_IN_PLACE, &m_skdTreeSync, 1, MPI_LONG, MPI_MIN, m_communicator);
1862 
1864  cleanSkdTree();
1865  }
1866 
1867  return m_skdTreeSync;
1868 }
1869 
1875 SyncStatus
1876 MimmoObject::cleanParallelKdTreeSync(){
1877 
1878  MPI_Allreduce(MPI_IN_PLACE, &m_kdTreeSync, 1, MPI_LONG, MPI_MIN, m_communicator);
1879 
1881  cleanKdTree();
1882  }
1883 
1884  return (m_kdTreeSync);
1885 }
1892 SyncStatus
1893 MimmoObject::cleanParallelAdjacenciesSync(){
1894 
1895  // Reduce by using the minimum sync status
1896  MPI_Allreduce(MPI_IN_PLACE, &m_AdjSync, 1, MPI_LONG, MPI_MIN, m_communicator);
1897 
1898  //if status is none destroy adjacencies
1899  if(m_AdjSync == SyncStatus::NONE){
1901  }
1902 
1903  return (m_AdjSync);
1904 }
1905 
1912 SyncStatus
1913 MimmoObject::cleanParallelInterfacesSync(){
1914 
1915  // Reduce by using the minimum sync status
1916  MPI_Allreduce(MPI_IN_PLACE, &m_IntSync, 1, MPI_LONG, MPI_MIN, m_communicator);
1917 
1918  //if status is none destroy interfaces
1919  if(m_IntSync == SyncStatus::NONE){
1921  }
1922 
1923  return (m_IntSync);
1924 }
1925 
1932 SyncStatus
1933 MimmoObject::cleanParallelPointConnectivitySync(){
1934 
1935  // Reduce by using the minimum sync status
1936  MPI_Allreduce(MPI_IN_PLACE, &m_pointConnectivitySync, 1, MPI_LONG, MPI_MIN, m_communicator);
1937 
1938  //if status is not sync destroy
1941  }
1942 
1943  return (m_pointConnectivitySync);
1944 }
1951 SyncStatus
1952 MimmoObject::cleanParallelInfoSync(){
1953 
1954  // Reduce by using the minimum sync status
1955  MPI_Allreduce(MPI_IN_PLACE, &m_infoSync, 1, MPI_LONG, MPI_MIN, m_communicator);
1956 
1957  //if status is not sync destroy
1959  m_patchInfo.reset();
1960  }
1961 
1962  return (m_infoSync);
1963 }
1970 SyncStatus
1971 MimmoObject::cleanParallelBoundingBoxSync(){
1972 
1973  // Reduce by using the minimum sync status
1974  MPI_Allreduce(MPI_IN_PLACE, &m_boundingBoxSync, 1, MPI_LONG, MPI_MIN, m_communicator);
1975 
1976  //if status is not sync destroy
1978 // getPatch()->clearBoundingBox();
1979  }
1980 
1981  return (m_boundingBoxSync);
1982 }
1983 
1990 SyncStatus
1991 MimmoObject::cleanParallelPointGhostExchangeInfoSync(){
1992 
1993  // Reduce by using the minimum sync status
1994  MPI_Allreduce(MPI_IN_PLACE, &m_pointGhostExchangeInfoSync, 1, MPI_LONG, MPI_MIN, m_communicator);
1995 
1996  //if status is not sync destroy
1997  if(m_pointGhostExchangeInfoSync != SyncStatus::SYNC){
1998  resetPointGhostExchangeInfo();
1999  }
2000 
2001  return (m_pointGhostExchangeInfoSync);
2002 }
2003 
2009 void
2010 MimmoObject::cleanAllParallelSync(){
2011  cleanParallelSkdTreeSync();
2012  cleanParallelKdTreeSync();
2013  cleanParallelAdjacenciesSync();
2014  cleanParallelInterfacesSync();
2015  cleanParallelPointConnectivitySync();
2016  cleanParallelInfoSync();
2017  cleanParallelBoundingBoxSync();
2018  cleanParallelPointGhostExchangeInfoSync();
2019 }
2020 
2025 bool
2026 MimmoObject::isDistributed()
2027 {
2028  if (getPatch() == nullptr){
2029  return false;
2030  }
2031 
2032  return getPatch()->isDistributed();
2033 }
2034 
2041 void MimmoObject::deleteOrphanGhostCells(){
2042 
2043  //build temporarely adjacencies to get orphans.
2044  bool checkResetAdjacencies = false;
2045  if(m_AdjSync != SyncStatus::SYNC){
2047  checkResetAdjacencies = true;
2048  }
2049  std::vector<long> markToDelete;
2050 
2051  //Track orphan ghosts, that is ghost cells which have no neighbour cell marked as internal.
2052  bitpit::PiercedVector<bitpit::Cell> & patchCells = getCells();
2053  for(auto it = getPatch()->ghostCellBegin(); it != getPatch()->ghostCellEnd(); ++it){
2054  std::vector<long> neighs = getPatch()->findCellNeighs(it.getId());
2055  bool check = false;
2056  std::vector<long>::iterator itN = neighs.begin();
2057  while(itN != neighs.end() && !check){
2058  check = check || patchCells[*itN].isInterior();
2059  ++itN;
2060  }
2061 
2062  //if check is still false, send this ghost cell to deletion
2063  if(!check){
2064  markToDelete.push_back(it.getId());
2065  }
2066  }
2067 
2068  //clean marked ghosts;
2069  if(!markToDelete.empty()){
2070  getPatch()->deleteCells(markToDelete);
2071  }
2072  //erase temporarely adjacencies
2073  if(checkResetAdjacencies){
2075  }
2076 
2077 }
2078 
2079 #endif
2080 
2085 bool
2087 {
2088  if (getPatch() == nullptr){
2089  return false;
2090  }
2091 
2092  return m_isParallel;
2093 }
2094 
2100 void
2102 {
2103  m_tolerance = std::max(1.0e-15, tol);
2104  getPatch()->setTol(m_tolerance);
2105 }
2106 
2107 
2119 long
2120 MimmoObject::addVertex(const darray3E & vertex, const long idtag){
2121 
2122  if(idtag != bitpit::Vertex::NULL_ID && getVertices().exists(idtag)) return bitpit::Vertex::NULL_ID;
2123 
2124  bitpit::PatchKernel::VertexIterator it;
2125  auto patch = getPatch();
2126  if(idtag == bitpit::Vertex::NULL_ID){
2127  it = patch->addVertex(vertex);
2128  }else{
2129  it = patch->addVertex(vertex, idtag);
2130  }
2131 
2132  long id = it->getId();
2133 
2137 #if MIMMO_ENABLE_MPI
2138  m_pointGhostExchangeInfoSync = std::min(m_pointGhostExchangeInfoSync, SyncStatus::UNSYNC);
2139 #endif
2141  return id;
2142 };
2143 
2155 long
2156 MimmoObject::addVertex(const bitpit::Vertex & vertex, const long idtag){
2157 
2158  if(idtag != bitpit::Vertex::NULL_ID && getVertices().exists(idtag)) return bitpit::Vertex::NULL_ID;
2159 
2160  bitpit::PatchKernel::VertexIterator it;
2161  auto patch = getPatch();
2162  if(idtag == bitpit::Vertex::NULL_ID){
2163  it = patch->addVertex(vertex);
2164  }else{
2165  it = patch->addVertex(vertex, idtag);
2166  }
2167 
2168  long id = it->getId();
2169 
2173 #if MIMMO_ENABLE_MPI
2174  m_pointGhostExchangeInfoSync = std::min(m_pointGhostExchangeInfoSync, SyncStatus::UNSYNC);
2175 #endif
2177  return id;
2178 };
2179 
2180 
2187 bool
2188 MimmoObject::modifyVertex(const darray3E & vertex, const long & id){
2189 
2190  if(!(getVertices().exists(id))) return false;
2191  bitpit::Vertex &vert = getPatch()->getVertex(id);
2192  vert.setCoords(vertex);
2197 #if MIMMO_ENABLE_MPI
2198  m_pointGhostExchangeInfoSync = std::min(m_pointGhostExchangeInfoSync, SyncStatus::UNSYNC);
2199 #endif
2200  return true;
2201 };
2202 
2208 long
2209 MimmoObject::addConnectedCell(const livector1D & conn, bitpit::ElementType type, int rank){
2210  return addConnectedCell(conn, type, 0, bitpit::Cell::NULL_ID, rank);
2211 };
2212 
2218 long
2219 MimmoObject::addConnectedCell(const livector1D & conn, bitpit::ElementType type, long idtag, int rank){
2220  return addConnectedCell(conn, type, 0, idtag, rank);
2221 };
2222 
2248 long
2249 MimmoObject::addConnectedCell(const livector1D & conn, bitpit::ElementType type, long PID, long idtag, int rank){
2250 
2251 #if MIMMO_ENABLE_MPI==0
2252  BITPIT_UNUSED(rank);
2253 #endif
2254 
2255  if (conn.empty()) return bitpit::Cell::NULL_ID;
2256  if(idtag != bitpit::Cell::NULL_ID && getCells().exists(idtag)) return bitpit::Cell::NULL_ID;
2257 
2258  if(!checkCellConnCoherence(type, conn)) return bitpit::Cell::NULL_ID;
2259 
2260  auto patch = getPatch();
2261 
2262  bitpit::PatchKernel::CellIterator it;
2263  long checkedID;
2264 #if MIMMO_ENABLE_MPI
2265  if(rank < 0) rank = m_rank;
2266  it = patch->addCell(type, conn, rank, idtag);
2267 #else
2268  it = patch->addCell(type, conn, idtag);
2269 #endif
2270  checkedID = it->getId();
2271 
2272  setPIDCell(checkedID, PID);
2273 
2275  m_AdjSync = std::min(m_AdjSync, SyncStatus::UNSYNC);
2276  m_IntSync = std::min(m_IntSync, SyncStatus::UNSYNC);
2278 #if MIMMO_ENABLE_MPI
2279  m_pointGhostExchangeInfoSync = std::min(m_pointGhostExchangeInfoSync, SyncStatus::UNSYNC);
2280 #endif
2282  return checkedID;
2283 };
2284 
2290 long
2291 MimmoObject::addCell(bitpit::Cell & cell, int rank){
2292  return addCell(cell, bitpit::Cell::NULL_ID, rank);
2293 }
2294 
2310 long
2311 MimmoObject::addCell(bitpit::Cell & cell, const long idtag, int rank){
2312 #if MIMMO_ENABLE_MPI==0
2313  BITPIT_UNUSED(rank);
2314 #endif
2315 
2316  if(idtag != bitpit::Cell::NULL_ID && getCells().exists(idtag)) return bitpit::Cell::NULL_ID;
2317  auto patch = getPatch();
2318 
2319  //patchkernel methods addCell(const & Cell... ) copy everything from the target cell, adjacencies and interfaces included.
2320  //and move them into the new patch.
2321  // But pay attention these information are useless for you, since you considered interfaces and
2322  // adjacencies invalidated every time you add a cell.
2323  //So practically keep using an add cell method passing connectivity, type, PID and rank.
2324 
2325  int connectSize = cell.getConnectSize();
2326  long *conn = cell.getConnect();
2327  std::unique_ptr<long[]> connectStorage = std::unique_ptr<long[]>(new long[connectSize]);
2328  std::copy(conn, conn+connectSize, connectStorage.get());
2329  bitpit::PatchKernel::CellIterator itcell;
2330 #if MIMMO_ENABLE_MPI==1
2331  if(rank < 0) rank = m_rank;
2332  itcell = patch->addCell(cell.getType(), std::move(connectStorage), rank, idtag);
2333 #else
2334  itcell = patch->addCell(cell.getType(), std::move(connectStorage), idtag);
2335 #endif
2336 
2337  long checkedID = itcell->getId();
2338 
2339  setPIDCell(checkedID, cell.getPID());
2340 
2342  m_AdjSync = std::min(m_AdjSync, SyncStatus::UNSYNC);
2343  m_IntSync = std::min(m_IntSync, SyncStatus::UNSYNC);
2345 #if MIMMO_ENABLE_MPI
2346  m_pointGhostExchangeInfoSync = std::min(m_pointGhostExchangeInfoSync, SyncStatus::UNSYNC);
2347 #endif
2349  return checkedID;
2350 };
2351 
2358 void
2360  if((int)pids.size() != getNCells()) return;
2361 
2362  m_pidsType.clear();
2363  m_pidsTypeWNames.clear();
2364  int counter = 0;
2365  for(auto & cell: getCells()){
2366  m_pidsType.insert(pids[counter]);
2367  cell.setPID(pids[counter]);
2368  ++counter;
2369  }
2370 
2371  for(const auto & pid : m_pidsType){
2372  m_pidsTypeWNames.insert(std::make_pair( pid, ""));
2373  }
2374 };
2375 
2382 void
2383 MimmoObject::setPID(std::unordered_map<long, long> pidsMap){
2384  if(getNCells() == 0) return;
2385 
2386  m_pidsType.clear();
2387  m_pidsTypeWNames.clear();
2388  auto & cells = getCells();
2389  for(auto const & val: pidsMap){
2390  if(cells.exists(val.first)){
2391  cells[val.first].setPID(val.second);
2392  m_pidsType.insert(val.second);
2393  }
2394  }
2395 
2396  for(const auto & pid : m_pidsType){
2397  m_pidsTypeWNames.insert(std::make_pair( pid, ""));
2398  }
2399 
2400 };
2401 
2407 void
2408 MimmoObject::setPIDCell(long id, long pid){
2409  auto & cells = getCells();
2410  if(cells.exists(id)){
2411  cells[id].setPID((int)pid);
2412  m_pidsType.insert(pid);
2413  m_pidsTypeWNames.insert(std::make_pair( pid, "") );
2414  }
2415 };
2416 
2424 bool
2425 MimmoObject::setPIDName(long pid, const std::string & name){
2426  if(! bool(m_pidsTypeWNames.count(pid))) return false;
2427  m_pidsTypeWNames[pid] = name;
2428  return true;
2429 }
2430 
2436 void
2438  m_pidsType.clear();
2439  std::unordered_map<long, std::string> copynames = m_pidsTypeWNames;
2440  m_pidsTypeWNames.clear();
2441  for(const bitpit::Cell & cell : getCells()){
2442  m_pidsType.insert( (long)cell.getPID() );
2443  }
2444  std::string work;
2445  for(const auto & pid : m_pidsType){
2446  if (copynames.count(pid) > 0){
2447  work = copynames[pid];
2448  }else{
2449  work = "";
2450  }
2451  m_pidsTypeWNames.insert(std::make_pair( pid, work));
2452  }
2453 };
2454 
2464 
2465  //first step clone the internal bitpit patch.
2466  std::unique_ptr<bitpit::PatchKernel> clonedPatch = getPatch()->clone();
2467 
2468  //build the cloned mimmoObject using the custom constructor
2469  MimmoSharedPointer<MimmoObject> result (new MimmoObject(m_type, clonedPatch));
2470 
2471  //--> this constructor checks adjacencies and interfaces, initialize parallel
2472  // and update the infoSync (cell parallel structures also)
2473  //now what missing here?
2474  // 1) MimmoObject sync'ed PID structured and get eventually local PID names.
2475  result->resyncPID();
2476  for(auto & touple: m_pidsTypeWNames){
2477  result->setPIDName(touple.first, touple.second);
2478  }
2479 
2480 // result->update();
2481 
2482  // 2) check if trees are built here locally and force build to result eventually;
2483  if(m_kdTreeSync == SyncStatus::SYNC) result->buildKdTree();
2484  if(m_skdTreeSync == SyncStatus::SYNC) result->buildSkdTree();
2485 
2486 //
2487 #if MIMMO_ENABLE_MPI
2488  //rank, nprocs and communicator managed inside initializeParallel call of the MimmoObject constructor
2489  //3) check if PointGhost are synchronized, if they are, update point ghost of result
2490  if(m_pointGhostExchangeInfoSync == SyncStatus::SYNC) result->updatePointGhostExchangeInfo();
2491 #endif
2492 
2493  //4) check if pointConnectivity is built here locally, if it is, force build to result.
2494  if(m_pointConnectivitySync == SyncStatus::SYNC) result->buildPointConnectivity();
2495 
2496  return result;
2497 };
2498 
2506 bool
2508  auto patch = getPatch();
2509  int nvold = patch->getVertexCount();
2510  patch->deleteCoincidentVertices();
2511  bool checkSync = (nvold == patch->getVertexCount());
2512 
2513 #if MIMMO_ENABLE_MPI
2514  // Delete orphan ghosts cells
2515  deleteOrphanGhostCells();
2516  bool checkCleanOrphan = (getPatch()->countOrphanVertices() == 0);
2517  if(!checkCleanOrphan){
2518  getPatch()->deleteOrphanVertices();
2519  }
2520  checkSync = checkSync && checkCleanOrphan;
2521  MPI_Allreduce(MPI_IN_PLACE, &checkSync,1, MPI_C_BOOL, MPI_LAND, m_communicator);
2522 #endif
2523 
2524  if(!checkSync) setUnsyncAll();
2525 
2526 return !checkSync;
2527 
2528 }
2538 void
2541  m_IntSync = std::min(m_IntSync, SyncStatus::UNSYNC);
2546 #if MIMMO_ENABLE_MPI
2547  m_pointGhostExchangeInfoSync = std::min(m_pointGhostExchangeInfoSync, SyncStatus::UNSYNC);
2548 #endif
2549  cleanPointConnectivity(); //forcefully destroy point connectivity.
2550 };
2551 
2558  if(getType() == 3) return livector1D(0);
2559 
2560  livector1D result;
2561  std::unordered_set<long int> ordV;
2562  bitpit::PiercedVector<bitpit::Cell> & cells = getCells();
2563  ordV.reserve(getPatch()->getVertexCount());
2564  //get conn from each cell of the list
2565  for(const long & id : cellList){
2566  if(cells.exists(id)){
2567  bitpit::ConstProxyVector<long> ids = cells.at(id).getVertexIds();
2568  for(const long & val: ids){
2569  ordV.insert(val);
2570  }
2571  }
2572  }
2573  result.reserve(ordV.size());
2574  result.insert(result.end(), ordV.begin(), ordV.end());
2575  return result;
2576 }
2577 
2586  if(getType() == 3) return livector1D(0);
2587 
2588  updateInterfaces();
2589  livector1D result;
2590  std::unordered_set<long int> ordV;
2591  auto patch = getPatch();
2592  ordV.reserve(patch->getInterfaceCount());
2593 
2594  if (all){
2595  bitpit::PiercedVector<bitpit::Cell> & cells = getCells();
2596  //get conn from each cell of the list
2597  for(const auto id : cellList){
2598  if(cells.exists(id)){
2599  bitpit::Cell & cell = cells.at(id);
2600  long * interf =cell.getInterfaces();
2601  int nIloc = cell.getInterfaceCount();
2602  for(int i=0; i<nIloc; ++i){
2603  if(interf[i] < 0) continue;
2604  ordV.insert(interf[i]);
2605  }
2606  }
2607  }
2608  }
2609  else{
2610  std::unordered_set<long> targetCells(cellList.begin(), cellList.end());
2611  for(const auto & interf : getInterfaces()){
2612  long idowner = interf.getOwner();
2613  long idneigh = interf.getNeigh();
2614  if (targetCells.count(idowner) && (targetCells.count(idneigh) || idneigh == bitpit::Element::NULL_ID)){
2615  ordV.insert(interf.getId());
2616  }
2617  }
2618  }
2619  result.reserve(ordV.size());
2620  result.insert(result.end(), ordV.begin(), ordV.end());
2621  return result;
2622 }
2623 
2624 
2634  if(getType() == 3) return livector1D(0);
2635 
2636  livector1D result;
2637  std::unordered_set<long int> ordV, ordC;
2638  ordV.insert(vertexList.begin(), vertexList.end());
2639  ordC.reserve(getPatch()->getCellCount());
2640  //get conn from each cell of the list
2641  for(auto it = getPatch()->cellBegin(); it != getPatch()->cellEnd(); ++it){
2642  bitpit::ConstProxyVector<long> vIds= it->getVertexIds();
2643  bool check = false;
2644  for(const auto & id : vIds){
2645  check = (ordV.count(id) > 0);
2646  if(!check && strict) {
2647  break ;
2648  }
2649  if(check && !strict) {
2650  break ;
2651  }
2652  }
2653  if(check) ordC.insert(it.getId());
2654  }
2655  result.reserve(ordC.size());
2656  result.insert(result.end(), ordC.begin(), ordC.end());
2657  return result;
2658 }
2659 
2676 livector1D MimmoObject::getInterfaceFromVertexList(const livector1D & vertexList, bool strict, bool border){
2677  if(getType() == 3) return livector1D(0);
2678 
2679  updateInterfaces();
2680 
2681  livector1D result;
2682  std::unordered_set<long int> ordV, ordI;
2683  ordV.insert(vertexList.begin(), vertexList.end());
2684  ordI.reserve(getPatch()->getInterfaceCount());
2685  //get conn from each cell of the list
2686  for(auto it = getPatch()->interfaceBegin(); it != getPatch()->interfaceEnd(); ++it){
2687  if(border && !it->isBorder()) continue;
2688  bitpit::ConstProxyVector<long> vIds= it->getVertexIds();
2689  bool check = false;
2690  for(const auto & id : vIds){
2691  check = (ordV.count(id) > 0);
2692  if(!check && strict) {
2693  break ;
2694  }
2695  if(check && !strict) {
2696  break ;
2697  }
2698  }
2699  if(check) ordI.insert(it.getId());
2700  }
2701 
2702  result.reserve(ordI.size());
2703  result.insert(result.end(), ordI.begin(), ordI.end());
2704  return result;
2705 }
2706 
2707 
2718 std::unordered_map<long, std::set<int> >
2720 
2721  std::unordered_map<long, std::set<int> > result;
2722  if(m_type ==3) return result;
2723 
2724 #if MIMMO_ENABLE_MPI == 0 //serial part only
2725  BITPIT_UNUSED(ghost);
2726 #endif
2727  if(getAdjacenciesSyncStatus() != SyncStatus::SYNC) updateAdjacencies(); //forcing adjacencies building
2728  update();
2729 
2730  //loop on internal cells
2731  int size;
2732  for (bitpit::PatchKernel::CellIterator it = getPatch()->internalCellBegin(); it != getPatch()->internalCellEnd(); ++it){
2733  size= it->getFaceCount();
2734  for(int face=0; face<size; ++face){
2735  if(it->isFaceBorder(face)){
2736  result[it.getId()].insert(face);
2737  }//endif
2738  }// end loop on face
2739  }
2740 
2741 #if MIMMO_ENABLE_MPI
2742  //here, if you want ghost face physical borders, you need to do a communication
2743  // from local rank to neighbour ranks: send borderfaces of local rank internal sources,
2744  //and recover border faces on local ghosts from other ranks.
2745 
2746  if(ghost){
2747 
2748  size_t dataSize = sizeof(int);
2749  std::unique_ptr<bitpit::DataCommunicator> dataCommunicator(new bitpit::DataCommunicator(getCommunicator()));
2750 
2751  // Set and start the sends
2752  for (const auto & entry : getPatch()->getGhostCellExchangeSources()) {
2753  const int rank = entry.first;
2754  auto &list = entry.second;
2755  // Recover number of vertices
2756  int dataCount(0);
2757  for (long cellId : list){
2758  if(result.count(cellId) > 0) {
2759  dataCount += int(result[cellId].size());
2760  }
2761  }
2762 
2763  dataCommunicator->setSend(rank, ( dataCount * dataSize + int(list.size()) * dataSize ) );
2764  bitpit::SendBuffer &buffer = dataCommunicator->getSendBuffer(rank);
2765  // Fill the buffer with borderfaces information on sources.
2766  for (long cellId : list){
2767  if(result.count(cellId) > 0){
2768  buffer<<int(result[cellId].size());
2769  for(int face : result[cellId]){
2770  buffer<<face;
2771  }
2772  }else{
2773  buffer<<int(0);
2774  }
2775  }
2776  dataCommunicator->startSend(rank);
2777  }
2778 
2779  // Discover & start all the receives
2780  dataCommunicator->discoverRecvs();
2781  dataCommunicator->startAllRecvs();
2782 
2783  // Receive ghosts data from owners on other ranks
2784  int nCompletedRecvs = 0;
2785 
2786  while (nCompletedRecvs < dataCommunicator->getRecvCount()) {
2787  int rank = dataCommunicator->waitAnyRecv();
2788  const auto &list = getPatch()->getGhostCellExchangeTargets(rank);
2789  bitpit::RecvBuffer &buffer = dataCommunicator->getRecvBuffer(rank);
2790  // visit the list, all cellId in the list is a ghost for my local rank.
2791  //Collect all face information they had.
2792  int nface, face;
2793  for (long cellId : list){
2794  buffer >> nface;
2795  for(int i=0; i<nface; ++i){
2796  buffer >> face;
2797  result[cellId].insert(face);
2798  }
2799  }
2800  ++nCompletedRecvs;
2801  }
2802  // Wait for the sends to finish
2803  dataCommunicator->waitAllSends();
2804 
2805  } //end of if ghost
2806 
2807  //all ghost face borders are already appended to result
2808 #endif
2809 
2810  return result;
2811 };
2812 
2813 
2820 livector1D
2821 MimmoObject::extractBoundaryCellID(std::unordered_map<long, std::set<int> > & map){
2822  livector1D result;
2823  result.reserve(map.size());
2824  for(auto & touple: map){
2825  result.push_back(touple.first);
2826  }
2827  return result;
2828 };
2829 
2836 livector1D
2838  std::unordered_map<long, std::set<int> > map = extractBoundaryFaceCellID(ghost);
2839  return extractBoundaryCellID(map);
2840 };
2841 
2848 livector1D
2849 MimmoObject::extractBoundaryVertexID(std::unordered_map<long, std::set<int> > &map){
2850 
2851  std::unordered_set<long> container;
2852  container.reserve(getPatch()->getVertexCount());
2853 
2854  for (auto & touple : map){
2855  bitpit::Cell & cell = getPatch()->getCell(touple.first);
2856  for(int face : touple.second){
2857  bitpit::ConstProxyVector<long> list = cell.getFaceVertexIds(face);
2858  for(long id : list ){
2859  container.insert(id);
2860  }
2861  }// end loop on face
2862  }
2863 
2864  livector1D result;
2865  result.reserve(container.size());
2866  result.insert(result.end(), container.begin(), container.end());
2867 
2868  return result;
2869 };
2870 
2877 livector1D
2879  std::unordered_map<long, std::set<int> > map = extractBoundaryFaceCellID(ghost);
2880  return extractBoundaryVertexID(map);
2881 };
2882 
2889 livector1D
2890 MimmoObject::extractBoundaryInterfaceID(std::unordered_map<long, std::set<int> > &map){
2891 
2892  updateInterfaces();
2893 
2894  std::unordered_set<long> container;
2895  container.reserve(getPatch()->getInterfaceCount());
2896 
2897  for(auto & tuple : map){
2898  long * interfCellList = getPatch()->getCell(tuple.first).getInterfaces();
2899  for(int face : tuple.second){
2900  container.insert(interfCellList[face]);
2901  }
2902  }
2903 
2904  livector1D result;
2905  result.reserve(container.size());
2906  result.insert(result.end(), container.begin(), container.end());
2907 
2908  return result;
2909 };
2910 
2917 livector1D
2919  std::unordered_map<long, std::set<int> > map = extractBoundaryFaceCellID(ghost);
2920  return extractBoundaryInterfaceID(map);
2921 };
2922 
2935 
2936  bool destroyBulkInterface = (getInterfacesSyncStatus() == SyncStatus::NONE);
2937  updateInterfaces();
2938 
2939  livector1D boundaryInterfaces, boundaryVertices;
2940  {
2941  std::unordered_map<long, std::set<int>> map = extractBoundaryFaceCellID(true);
2942 
2943  boundaryVertices = extractBoundaryVertexID(map);
2944  boundaryInterfaces = extractBoundaryInterfaceID(map);
2945  }
2946 
2947  //fill new boundary
2948  //instantiate mesh
2949  int type = int(getType() == 2) + 4*int(getType() == 1) + 3*int(getType() == 4);
2951 
2952  //get intefaces from current mesh
2953  bitpit::PiercedVector<bitpit::Interface> & bulkInterf = getInterfaces();
2954 
2955  //fill vertices
2956  for(const auto & idV: boundaryVertices){
2957  boundary->addVertex(getVertexCoords(idV),idV);
2958  }
2959 
2960  int rank;
2961  long PID;
2962  long * conn = nullptr;
2963  for(long idI: boundaryInterfaces){
2964  bitpit::Interface & bInt = bulkInterf[idI];
2965  rank = -1;
2966  conn = bInt.getConnect();
2967 
2968 #if MIMMO_ENABLE_MPI
2969  rank = getPatch()->getCellRank(bInt.getOwner());
2970 #endif
2971  PID = getPatch()->getCell(bInt.getOwner()).getPID();
2972  boundary->addConnectedCell(livector1D(conn, conn+bInt.getConnectSize()), bInt.getType(), PID, idI, rank);
2973  }
2974 
2975  //check and release bulk Interfaces
2976  if(destroyBulkInterface) {
2978  }
2979 
2980 
2981 
2982  //get a self consistent distributed representation of boundary
2983  // some ghost interfaces may result isolated check and clean it
2984 #if MIMMO_ENABLE_MPI
2985  boundary->deleteOrphanGhostCells();
2986 #endif
2987 
2988  if(boundary->getPatch()->countOrphanVertices() > 0){
2989  boundary->getPatch()->deleteOrphanVertices();
2990  }
2991 
2992  boundary->getPatch()->squeezeVertices();
2993  boundary->getPatch()->squeezeCells();
2994 
2995  boundary->update();
2996 
2997  return boundary;
2998 }
2999 
3000 
3010 std::unordered_map<long, std::set<int> >
3012 
3013  std::unordered_map<long, std::set<int> > result;
3014  if(m_type ==3) return result;
3015 
3017  //loop on internal cells
3018  int size;
3019  for (bitpit::PatchKernel::CellIterator it = getPatch()->cellBegin(); it != getPatch()->cellEnd(); ++it){
3020  size= it->getFaceCount();
3021  for(int face=0; face<size; ++face){
3022  if(it->isFaceBorder(face)){
3023  result[it.getId()].insert(face);
3024  }//endif
3025  }// end loop on face
3026  }
3027 
3028  return result;
3029 };
3030 
3031 
3042 livector1D
3043 MimmoObject::getBorderCells(std::unordered_map<long, std::set<int> > & map){
3044  livector1D result;
3045  result.reserve(map.size());
3046  for(auto & touple: map){
3047  result.push_back(touple.first);
3048  }
3049  return result;
3050 };
3051 
3061 livector1D
3063  std::unordered_map<long, std::set<int> > map = getBorderFaceCells();
3064  return getBorderCells(map);
3065 };
3066 
3077 livector1D
3078 MimmoObject::getBorderVertices(std::unordered_map<long, std::set<int> > &map){
3079 
3080  std::unordered_set<long> container;
3081  container.reserve(getPatch()->getVertexCount());
3082 
3083  for (auto & touple : map){
3084  bitpit::Cell & cell = getPatch()->getCell(touple.first);
3085  for(int face : touple.second){
3086  bitpit::ConstProxyVector<long> list = cell.getFaceVertexIds(face);
3087  for(long id : list ){
3088  container.insert(id);
3089  }
3090  }// end loop on face
3091  }
3092 
3093  livector1D result;
3094  result.reserve(container.size());
3095  result.insert(result.end(), container.begin(), container.end());
3096 
3097  return result;
3098 };
3099 
3109 livector1D
3111  std::unordered_map<long, std::set<int> > map = getBorderFaceCells();
3112  return getBorderVertices(map);
3113 };
3114 
3115 
3122 livector1D MimmoObject::extractPIDCells(long flag, bool squeeze){
3123 
3124  if(m_pidsType.count(flag) < 1) return livector1D(0);
3125 
3126  livector1D result(getNCells());
3127  int counter = 0;
3128  for(auto const & cell : getCells()){
3129  if ( cell.getPID() == flag) {
3130  result[counter] = cell.getId();
3131  ++counter;
3132  }
3133  }
3134  result.resize(counter);
3135  if (squeeze)
3136  result.shrink_to_fit();
3137  return result;
3138 };
3139 
3147  livector1D result;
3148  result.reserve(getNCells());
3149  for(auto && id : flag){
3150  livector1D partial = extractPIDCells(id);
3151  result.insert(result.end(),partial.begin(), partial.end());
3152  }
3153  if (squeeze)
3154  result.shrink_to_fit();
3155  return(result);
3156 };
3157 
3162 std::map<long, livector1D>
3164 
3165  std::map<long, livector1D> result;
3166  if (m_pidsType.empty()){
3167  return result;
3168  }
3169  int totCells = getNCells();
3170  int reserveSize = int(totCells*1.3)/int(m_pidsType.size()); //euristic to not overestimate the reserve on vectors.
3171  for(const long & entry: m_pidsType) {
3172  result[entry].reserve(reserveSize);
3173  }
3174 
3175  for(bitpit::PatchKernel::CellIterator it = getPatch()->cellBegin(); it!= getPatch()->cellEnd(); ++it){
3176  result[it->getPID()].push_back(it.getId());
3177  }
3178  for(std::pair<const long, livector1D> & entry: result){
3179  entry.second.shrink_to_fit();
3180  }
3181 
3182  return result;
3183 };
3184 
3192 bool MimmoObject::checkCellConnCoherence(const bitpit::ElementType & type, const livector1D & list){
3193 
3194  switch(type){
3195  case bitpit::ElementType::VERTEX:
3196  return (list.size() == 1);
3197  break;
3198  case bitpit::ElementType::LINE:
3199  return (list.size() == 2);
3200  break;
3201  case bitpit::ElementType::TRIANGLE:
3202  return (list.size() == 3);
3203  break;
3204  case bitpit::ElementType::PIXEL:
3205  return (list.size() == 4);
3206  break;
3207  case bitpit::ElementType::QUAD:
3208  return (list.size() == 4);
3209  break;
3210  case bitpit::ElementType::POLYGON:
3211  if(list.size() < 3) return false;
3212  return(list.size() == std::size_t(list[0]+1));
3213  break;
3214  case bitpit::ElementType::TETRA:
3215  return (list.size() == 4);
3216  break;
3217  case bitpit::ElementType::VOXEL:
3218  return (list.size() == 8);
3219  break;
3220  case bitpit::ElementType::HEXAHEDRON:
3221  return (list.size() == 8);
3222  break;
3223  case bitpit::ElementType::WEDGE:
3224  return (list.size() == 6);
3225  break;
3226  case bitpit::ElementType::PYRAMID:
3227  return (list.size() == 5);
3228  break;
3229  case bitpit::ElementType::POLYHEDRON:
3230  if(list.size() < 9) return false;
3231  {
3232  //check if the record is a polyhedron
3233  long nFaces = list[0];
3234  std::size_t pos = 1;
3235  long countFaces = 0;
3236  while(pos < list.size() && countFaces<nFaces){
3237  countFaces++;
3238  pos += list[pos]+1;
3239  }
3240  return (pos == list.size() && countFaces == nFaces);
3241  }
3242  break;
3243  default:
3244  assert(false && "reached uncovered case");
3245  break;
3246  }
3247  return false;
3248 };
3249 
3256 void MimmoObject::getBoundingBox(std::array<double,3> & pmin, std::array<double,3> & pmax, bool global){
3257  getPatch()->getBoundingBox(global, pmin, pmax);
3258 }
3259 
3265 void MimmoObject::buildSkdTree(std::size_t value){
3266  if(!isSkdTreeSupported()) return;
3267 
3269  m_skdTree->clear();
3270  m_skdTree->build(value);
3272  }
3273  return;
3274 }
3275 
3281  if( getNVertices() == 0) return;
3282  long label;
3283 
3285  cleanKdTree();
3286  //TODO Why : + m_kdTree->MAXSTK ?
3287  m_kdTree->nodes.resize(getNVertices() + m_kdTree->MAXSTK);
3288 
3289  for(auto & val : getVertices()){
3290  label = val.getId();
3291  m_kdTree->insert(&val, label);
3292  }
3294  }
3295  return;
3296 }
3297 
3302  m_kdTree->n_nodes = 0;
3303  m_kdTree->nodes.clear();
3306  }
3307 }
3308 
3313  if (isSkdTreeSupported()){
3314  m_skdTree->clear();
3317  }
3318  }
3319 }
3320 
3325  if (m_internalPatch)
3326  m_patchInfo.setPatch(m_patch.get());
3327  else
3328  m_patchInfo.setPatch(m_extpatch);
3329  m_patchInfo.update();
3331 }
3332 
3337  m_patchInfo.reset();
3340  }
3341 }
3342 
3343 
3351  }
3352 }
3353 
3360 {
3361 
3362 #if MIMMO_ENABLE_MPI
3363  // Communicate sync status of all the structures
3364  if (isParallel()){
3365  cleanAllParallelSync();
3366  }
3367 #endif
3368 
3369  // Status variable
3370  SyncStatus status;
3371 
3372  // Update adjacencies
3373  bool resetAdjacencies = false;
3374  status = m_AdjSync;
3375  if (status == SyncStatus::UNSYNC){
3377  }
3378 #if MIMMO_ENABLE_MPI
3379  else if (status == SyncStatus::NONE){
3380  // The adjacencies are needed in parallel case to update the patch in bitpit
3381  resetAdjacencies = true;
3383  }
3384 #endif
3385 
3386  // Update interfaces
3387  status = m_IntSync;
3388  if (status == SyncStatus::UNSYNC){
3389  updateInterfaces();
3390  }
3391 
3392 
3393  // UPDATE PATCH
3394  getPatch()->update();
3395 
3396 
3397  // Update trees
3398  status = m_skdTreeSync;
3399  if (status == SyncStatus::UNSYNC){
3400  buildSkdTree();
3401  }
3402  status = m_kdTreeSync;
3403  if (status == SyncStatus::UNSYNC){
3404  buildKdTree();
3405  }
3406 
3407  // Update patch info
3408  status = m_infoSync;
3409  if (status == SyncStatus::UNSYNC){
3410  buildPatchInfo();
3411  }
3412 
3413  // Update patch bounding box (//TODO when ready use automatic update in bitpit patch)
3414  status = m_boundingBoxSync;
3415  if (status != SyncStatus::SYNC){
3416  getPatch()->updateBoundingBox(true);
3418  }
3419 
3420  // Update point connectivity
3421  status = getPointConnectivitySyncStatus();
3422  if (status == SyncStatus::UNSYNC){
3424  }
3425 
3426 #if MIMMO_ENABLE_MPI
3427  // Always update/build point ghost exchange information
3428  status = m_pointGhostExchangeInfoSync;
3429  if (status != SyncStatus::SYNC){
3430  updatePointGhostExchangeInfo();
3431  }
3432 
3433  // Reset structures if needed. This can happen only in MPI
3434  if (resetAdjacencies){
3436  }
3437 #else
3438  BITPIT_UNUSED(resetAdjacencies);
3439 #endif
3440 }
3441 
3447 
3448  //check if you are synchronized with patch
3449  if (getPatch()->getAdjacenciesBuildStrategy() == bitpit::PatchKernel::AdjacenciesBuildStrategy::ADJACENCIES_NONE){
3451  }
3452 
3453  return m_AdjSync;
3454 };
3455 
3461 
3462  //check if you are synchronized with patch
3463  if (getPatch()->getInterfacesBuildStrategy() == bitpit::PatchKernel::InterfacesBuildStrategy::INTERFACES_NONE){
3465  }
3466 
3467  return m_IntSync;
3468 };
3469 
3476 
3478  bool check = true;
3479 
3480  auto itp = getCells().cbegin();
3481  auto itend = getCells().cend();
3482  while(itp != itend && check){
3483 
3484  if (itp->isInterior()){
3485  int faces = itp->getFaceCount();
3486  for(int face=0; face<faces; ++face){
3487  // Check if it is a border face
3488  check = check && (!itp->isFaceBorder(face));
3489  }
3490  itp++;
3491  }
3492  }
3493 
3494 #if MIMMO_ENABLE_MPI
3495  MPI_Allreduce(MPI_IN_PLACE, &check, 1, MPI_C_BOOL, MPI_LAND, m_communicator);
3496 #endif
3497 
3498  return check;
3499 };
3500 
3501 
3507 //TODO PARALLEL VERSION (CURRENTLY USED ONLY IN CLOSEDCURVEINTERPOLATOR OF MIMIC)
3510 
3511  livector2D result;
3512  livector1D globalcellids = getCells().getIds();
3513  std::unordered_set<long> checked;
3514  bool outcycle = true;
3515 
3516  while(outcycle){
3517 
3518  livector1D stack, save;
3519 
3520  auto it = globalcellids.begin();
3521  bool found = false;
3522  long idstart = -1;
3523  while(!found && it != globalcellids.end()){
3524  if(checked.count(*it) == 0){
3525  idstart = *it;
3526  found = true;
3527  }
3528  ++it;
3529  }
3530 
3531  checked.insert(idstart);
3532  stack.push_back(idstart);
3533 
3534  while(!stack.empty()){
3535 
3536  long target = stack.back();
3537  stack.pop_back();
3538  save.push_back(target);
3539 
3540  //get the number of faces.
3541  const bitpit::Cell & cell = getPatch()->getCells().at(target);
3542  int facecount = cell.getFaceCount();
3543  for(int i=0; i<facecount; ++i){
3544 
3545  // Find face neighbours
3546  int neighscount = cell.getAdjacencyCount(i);
3547  const long * neighs = cell.getAdjacencies(i);
3548  bool found = false;
3549  int ineigh = 0;
3550  while(!found && ineigh < neighscount){
3551  long neighId = neighs[ineigh];
3552  if(checked.count(neighId) == 0){
3553  stack.push_back(neighId);
3554  checked.insert(neighId);
3555  found = true;
3556  }
3557  ++ineigh;
3558  }
3559  }
3560  }
3561  result.push_back(save);
3562  outcycle = (checked.size() < globalcellids.size());
3563  }
3564 
3565  return result;
3566 }
3567 
3572 
3573  switch(m_AdjSync){
3575  return;
3576  break;
3577  case SyncStatus::NONE:
3578  getPatch()->initializeAdjacencies();
3579  break;
3580  case SyncStatus::UNSYNC:
3581  getPatch()->updateAdjacencies();
3582  break;
3583  case SyncStatus::SYNC:
3584  return;
3585  break;
3586  default:
3587  return;
3588  break;
3589  }
3591 
3592 };
3593 
3601 
3602  if(m_AdjSync != SyncStatus::SYNC){
3604  }
3605 
3606  switch(m_IntSync){
3608  return;
3609  break;
3610  case SyncStatus::NONE:
3611  getPatch()->initializeInterfaces();
3612  break;
3613  case SyncStatus::UNSYNC:
3614  getPatch()->updateInterfaces();
3615  break;
3616  case SyncStatus::SYNC:
3617  return;
3618  break;
3619  default:
3620  return;
3621  break;
3622  }
3624 
3625 };
3626 
3631  getPatch()->destroyAdjacencies();
3633 };
3634 
3639  getPatch()->destroyInterfaces(); // is the same as getPatch()->destroyInterfaces
3641 
3642 };
3643 
3648  getPatch()->reset();
3651  cleanSkdTree();
3653  cleanKdTree();
3655  m_patchInfo.reset();
3658 #if MIMMO_ENABLE_MPI
3659  resetPointGhostExchangeInfo();
3660  m_pointGhostExchangeInfoSync = SyncStatus::NONE;
3661 #endif
3664 };
3665 
3675 //TODO To review in order to implement new derived classes MimmoSurfUnstructured and MimmoVolUnstructured
3676 bitpit::ElementType MimmoObject::desumeElement(const livector1D & locConn){
3677  bitpit::ElementType result = bitpit::ElementType::UNDEFINED;
3678 
3679  std::size_t sizeConn = locConn.size();
3680  switch(m_type){
3681  case 1:
3682  if(sizeConn == 3) result = bitpit::ElementType::TRIANGLE;
3683  if(sizeConn == 4) result = bitpit::ElementType::QUAD;
3684  if(sizeConn > 4 && sizeConn == std::size_t(locConn[0]+1)) result= bitpit::ElementType::POLYGON;
3685  break;
3686  case 2:
3687  if(sizeConn == 4) result = bitpit::ElementType::TETRA;
3688  if(sizeConn == 8) result = bitpit::ElementType::HEXAHEDRON;
3689  if(sizeConn == 5) result = bitpit::ElementType::PYRAMID;
3690  if(sizeConn == 6) result = bitpit::ElementType::WEDGE;
3691  if(sizeConn > 8 ){
3692  //check if the record is a polyhedron
3693  long nFaces = locConn[0];
3694  std::size_t pos = 1;
3695  long countFaces = 0;
3696  while(pos < sizeConn && countFaces<nFaces){
3697  countFaces++;
3698  pos += locConn[pos]+1;
3699  }
3700  if(pos == sizeConn && countFaces == nFaces){
3701  result= bitpit::ElementType::POLYHEDRON;
3702  }
3703  }
3704  break;
3705  case 3:
3706  if(sizeConn == 1) result = bitpit::ElementType::VERTEX;
3707  break;
3708  case 4:
3709  if(sizeConn == 2) result = bitpit::ElementType::LINE;
3710  break;
3711  default :
3712  assert(false && "reached uncovered case");
3713  break;
3714  }
3715 
3716  return result;
3717 };
3718 
3724 void MimmoObject::reset(int type, bool isParallel){
3725 
3726  m_log = &bitpit::log::cout(MIMMO_LOG_FILE);
3727 
3728  // Reset patch
3729  resetPatch();
3730 
3731  m_patch = nullptr;
3732  m_extpatch = nullptr;
3733 
3734  // Initialize parallel data
3735  m_isParallel = isParallel && MIMMO_ENABLE_MPI;
3736 #if MIMMO_ENABLE_MPI
3737  initializeMPI();
3738  initializeCommunicator(m_isParallel);
3739 #else
3740  m_rank = 0;
3741  m_nprocs = 1;
3742 #endif
3743 
3744  m_type = std::max(0, type);
3745  if (m_type > 4){
3746  m_type = 1;
3747  }
3748 
3749  switch(m_type){
3750  case 1:
3751 #if MIMMO_ENABLE_MPI
3752  m_patch = std::move(std::unique_ptr<bitpit::PatchKernel>(new MimmoSurfUnstructured(2, getCommunicator())));
3753 #else
3754  m_patch = std::move(std::unique_ptr<bitpit::PatchKernel>(new MimmoSurfUnstructured(2)));
3755 #endif
3756  m_skdTree = std::move(std::unique_ptr<bitpit::PatchSkdTree>(new bitpit::SurfaceSkdTree(dynamic_cast<bitpit::SurfaceKernel*>(m_patch.get()))));
3757  m_kdTree = std::move(std::unique_ptr<bitpit::KdTree<3,bitpit::Vertex,long> >(new bitpit::KdTree<3,bitpit::Vertex, long>()));
3758  break;
3759  case 2:
3760 #if MIMMO_ENABLE_MPI
3761  m_patch = std::move(std::unique_ptr<bitpit::PatchKernel>(new MimmoVolUnstructured(3, getCommunicator())));
3762 #else
3763  m_patch = std::move(std::unique_ptr<bitpit::PatchKernel>(new MimmoVolUnstructured(3)));
3764 #endif
3765  m_skdTree = std::move(std::unique_ptr<bitpit::PatchSkdTree>(new bitpit::VolumeSkdTree(dynamic_cast<bitpit::VolumeKernel*>(m_patch.get()))));
3766  m_kdTree = std::move(std::unique_ptr<bitpit::KdTree<3,bitpit::Vertex,long> >(new bitpit::KdTree<3,bitpit::Vertex, long>()));
3767  break;
3768  case 3:
3769 #if MIMMO_ENABLE_MPI
3770  m_patch = std::move(std::unique_ptr<bitpit::PatchKernel>(new MimmoPointCloud(getCommunicator())));
3771 #else
3772  m_patch = std::move(std::unique_ptr<bitpit::PatchKernel>(new MimmoPointCloud()));
3773 #endif
3774  m_kdTree = std::move(std::unique_ptr<bitpit::KdTree<3,bitpit::Vertex,long> >(new bitpit::KdTree<3,bitpit::Vertex, long>()));
3775  break;
3776  case 4:
3777 #if MIMMO_ENABLE_MPI
3778  m_patch = std::move(std::unique_ptr<bitpit::PatchKernel>(new MimmoSurfUnstructured(1, getCommunicator())));
3779 #else
3780  m_patch = std::move(std::unique_ptr<bitpit::PatchKernel>(new MimmoSurfUnstructured(1)));
3781 #endif
3782  m_skdTree = std::move(std::unique_ptr<bitpit::PatchSkdTree>(new bitpit::SurfaceSkdTree(dynamic_cast<bitpit::SurfaceKernel*>(m_patch.get()))));
3783  m_kdTree = std::move(std::unique_ptr<bitpit::KdTree<3,bitpit::Vertex,long> >(new bitpit::KdTree<3,bitpit::Vertex, long>()));
3784  break;
3785  default:
3786  //never been reached
3787  break;
3788  }
3789 
3790  m_internalPatch = true;
3791 
3792  // Set skdTreeSync and kdTreeSync to none
3795 
3796  // Set skdTreeSync to unsupported for point cloud
3797  if (m_type == 3){
3799  }
3800 
3801  // Set AdjSync and IntSync to none
3804 
3805  m_patchInfo.setPatch(m_patch.get());
3809 }
3810 
3818 void MimmoObject::dump(std::ostream & stream){
3819 
3820  //scan pids inside your patch to be sure everything it's in order.
3821  resyncPID();
3822  //reverse pid and pidnames in vector structures.
3823  auto mapPid = getPIDTypeListWNames() ;
3824  std::vector<long> pid(mapPid.size());
3825  std::vector<std::string> sspid(mapPid.size());
3826  int counter = 0;
3827  for(const auto & touple : mapPid){
3828  pid[counter] = touple.first;
3829  sspid[counter] = touple.second;
3830  ++counter;
3831  }
3832  //write comparison variables
3833  bitpit::utils::binary::write(stream,m_type);
3834 #if MIMMO_ENABLE_MPI
3835  bitpit::utils::binary::write(stream,m_nprocs);
3836 #endif
3837  //write other variables
3838  bitpit::utils::binary::write(stream,pid);
3839  bitpit::utils::binary::write(stream,sspid);
3840  bitpit::utils::binary::write(stream,m_AdjSync);
3841  bitpit::utils::binary::write(stream,m_IntSync);
3842  bitpit::utils::binary::write(stream,m_pointConnectivitySync);
3843 
3844  //write the patch
3845  getPatch()->dump(stream);
3846 }
3847 
3857 void MimmoObject::restore(std::istream & stream){
3858  //check comparisons
3859  int type;
3860  bitpit::utils::binary::read(stream,type);
3861 #if MIMMO_ENABLE_MPI
3862  int nprocs;
3863  bitpit::utils::binary::read(stream,nprocs);
3864  if(nprocs != m_nprocs){
3865  throw std::runtime_error("Error during MimmoObject::restore : uncoherent procs number between contents and container");
3866  }
3867 #endif
3868 
3869  //clean up and reset current object to ist virgin state
3870  // Reset to a parallel geometry if communicator is different from MPI_COMM_NULL
3871  bool isparallel = false;
3872 #if MIMMO_ENABLE_MPI
3873  isparallel = m_communicator != MPI_COMM_NULL;
3874 #endif
3875  reset(type, isparallel);
3876  //absorb the other data
3877  std::vector<long> pid;
3878  std::vector<std::string> sspid;
3879 
3880  bitpit::utils::binary::read(stream,pid);
3881  bitpit::utils::binary::read(stream,sspid);
3882  bitpit::utils::binary::read(stream,m_AdjSync);
3883  bitpit::utils::binary::read(stream,m_IntSync);
3884  bitpit::utils::binary::read(stream,m_pointConnectivitySync);
3885 
3886  getPatch()->restore(stream);
3887 
3888  //m_patchInfo has already the pointer to the patch set during reset(type)
3889  //update it.
3890  m_patchInfo.update();
3892 
3893  getPatch()->updateBoundingBox();
3895 
3896  //rebuild the point ghost exchange information.
3897 #if MIMMO_ENABLE_MPI
3898  updatePointGhostExchangeInfo();
3899 #endif
3900 
3901  //check point connectivity, if true build it, otherwise leave it as reset put it, i.e. false.
3903  this->buildPointConnectivity();
3904  }
3905 
3906  //uncompact and rewrite PID stuff
3907  int count = 0;
3908  for (long pp : pid){
3909  m_pidsType.insert(pp);
3910  m_pidsTypeWNames.insert( std::make_pair( pp, sspid[count]));
3911  ++count;
3912  }
3913 
3914  //that's all folks.
3915 }
3916 
3925 void
3926 MimmoObject::evalCellVolumes(bitpit::PiercedVector<double> & volumes){
3927 
3928  if(getPatch() == nullptr) return;
3929  if(isEmpty()) return ;
3930 
3931  switch (getType()){
3932  case 1:
3933  case 4:
3934  {
3935  bitpit::SurfaceKernel * p = static_cast<bitpit::SurfaceKernel *>(getPatch());
3936  for (const auto & cell: getCells()){
3937  volumes.insert(cell.getId(), p->evalCellArea(cell.getId()));
3938  }
3939  }
3940  break;
3941  case 2:
3942  {
3943  bitpit::VolumeKernel * p = static_cast<bitpit::VolumeKernel *>(getPatch());
3944  for (const auto & cell: getCells()){
3945  volumes.insert(cell.getId(), p->evalCellVolume(cell.getId()));
3946  }
3947  }
3948  break;
3949  default:
3950  //leave map empty
3951  break;
3952  }
3953 }
3954 
3965 void
3966 MimmoObject::evalCellAspectRatio(bitpit::PiercedVector<double> & ARs){
3967 
3968  if(getPatch() == nullptr) return;
3969  if(isEmpty()) return;
3970 
3971  switch (getType()){
3972  case 1:
3973  {
3974  bitpit::SurfaceKernel * p = static_cast<bitpit::SurfaceKernel *>(getPatch());
3975  int edge;
3976  for (const auto & cell: getCells()){
3977  ARs[cell.getId()] = p->evalAspectRatio(cell.getId(), edge);
3978  }
3979  }
3980  break;
3981  case 2:
3982  { //Following the example of OpenFoam, the AR index is calculated as
3983  // the ratio S between total surface and hydraulic surface of an equilater
3984  // cylinder (h=2*r) of the same volume, that is S_hyd = 1/6.0 * (V^(2/3)).
3985  updateInterfaces();
3986  bitpit::VolUnstructured * p = static_cast<bitpit::VolUnstructured *>(getPatch());
3987 
3988  //calculate interface area
3989  std::unordered_map<long, double> interfaceAreas;
3990  for (const auto & interf: getInterfaces()){
3991  interfaceAreas[interf.getId()] = p->evalInterfaceArea(interf.getId());
3992  }
3993 
3994  double Svalue = 0.0;
3995  double sumArea;
3996  int size;
3997  for (const auto & cell: getCells()){
3998 
3999  sumArea = 0.0;
4000 
4001  size = cell.getInterfaceCount();
4002  const long * conInt = cell.getInterfaces();
4003 
4004  for(int i=0; i<size; ++i){
4005  sumArea += interfaceAreas[conInt[i]];
4006  }
4007 
4008  double vol = p->evalCellVolume(cell.getId());
4009  if(vol <= std::numeric_limits<double>::min()){
4010  Svalue = std::numeric_limits<double>::max();
4011  }else{
4012  Svalue = sumArea/(6.0*std::pow(vol, 2.0/3.0));
4013  }
4014 
4015  ARs.insert(cell.getId(), Svalue);
4016  }
4017 
4018  }
4019  break;
4020  default:
4021  //leave map empty
4022  break;
4023  }
4024 }
4025 
4031 double
4033  switch (getType()){
4034  case 1:
4035  case 4:
4036  return static_cast<bitpit::SurfaceKernel *>(getPatch())->evalCellArea(id);
4037  break;
4038  case 2:
4039  return static_cast<bitpit::VolumeKernel *>(getPatch())->evalCellVolume(id);
4040  break;
4041  default:
4042  return 0.0;
4043  break;
4044  }
4045 }
4046 
4054 double
4056  int edge;
4057  switch (getType()){
4058  case 1:
4059  return static_cast<bitpit::SurfaceKernel *>(getPatch())->evalAspectRatio(id, edge);
4060  break;
4061  case 2:
4062  {
4063  //Following the example of OpenFoam, the AR index is calculated as
4064  // the ratio S between total surface and hydraulic surface of an equilater
4065  // cylinder (h=2*r) of the same volume, that is S_hyd = 1/6.0 * (V^(2/3)).
4066  updateInterfaces();
4067  bitpit::VolUnstructured * p = static_cast<bitpit::VolUnstructured *>(getPatch());
4068 
4069  double sumArea = 0.0;
4070  int size = p->getCell(id).getInterfaceCount();
4071  const long * conInt = p->getCell(id).getInterfaces();
4072  for(int i=0; i<size; ++i){
4073  sumArea += p->evalInterfaceArea(conInt[i]);
4074  }
4075 
4076  double vol = p->evalCellVolume(id);
4077  if(vol <= std::numeric_limits<double>::min()){
4078  return std::numeric_limits<double>::max();
4079  }else{
4080  return sumArea/(6.0*std::pow(vol, 2.0/3.0));
4081  }
4082  }
4083  break;
4084  default:
4085  return 0.0;
4086  break;
4087  }
4088 }
4089 
4095 std::unordered_set<int>
4096 MimmoObject::elementsMap(bitpit::PatchKernel & obj){
4097 
4098  std::unordered_set<int> result;
4099 
4100  for(const auto & cell : obj.getCells()){
4101  result.insert((int)cell.getType());
4102  }
4103  return result;
4104 };
4105 
4115 livector1D
4116 MimmoObject::getCellsNarrowBandToExtSurface(MimmoObject & surface, const double & maxdist, livector1D * seedlist){
4117  bitpit::PiercedVector<double> res = getCellsNarrowBandToExtSurfaceWDist(surface, maxdist, seedlist);
4118  return res.getIds();
4119 };
4120 
4130 bitpit::PiercedVector<double>
4131 MimmoObject::getCellsNarrowBandToExtSurfaceWDist(MimmoObject & surface, const double & maxdist, livector1D * seedlist){
4132 
4133  //TODO this propagation does not work properly in parallel. Please review it
4134  //using propagated distance on ghost.
4135  surface.updateAdjacencies();
4136 
4138  buildSkdTree();
4139 
4140  if (surface.getSkdTreeSyncStatus() != SyncStatus::SYNC)
4141  surface.buildSkdTree();
4142 
4143  bitpit::PiercedVector<double> result;
4144  if(surface.getType() != 1) return result;
4145  if(getType() == 3) return result;
4146 
4147  //use a stack-based search on face cell neighbors of some prescribed seed cells.
4148  //You need at least one cell to be near enough to surface
4149 
4150  //First step check seed list and precalculate distance. If dist >= maxdist
4151  //the seed candidate is out.
4152  int npoints(0);
4153  dvecarr3E points;
4154  dvector1D distances;
4155  livector1D surface_ids;
4156  livector1D candidates;
4157  double distance, maxdistance(maxdist);
4158  long id;
4159 
4160 
4161 
4162  if(seedlist){
4163  //check if seedlist contains valid cell ids for the current mesh/local rank partition.
4164  candidates.reserve(seedlist->size());
4165  bitpit::PiercedVector<bitpit::Cell> & cells = getCells();
4166  for(long id : *seedlist){
4167  if(cells.exists(id)) candidates.push_back(id);
4168  }
4169  candidates.shrink_to_fit();
4170  // Fill points array with seed list
4171  npoints = candidates.size();
4172  points.reserve(npoints);
4173  for(long idseed : candidates){
4174  points.emplace_back(getPatch()->evalCellCentroid(idseed));
4175  }
4176 
4177  } else {
4178 
4179  // Find the seeds by using all the cells of surface patch
4180  // Recover the seeds by selecting by patch the target cells
4181  // by using the surface input patch as selection patch.
4182  // Then check if the candidate cells are closer than maxdistance,
4183  // in this case insert in result as seeds
4184 
4185 
4186 #if MIMMO_ENABLE_MPI
4187  if (surface.isParallel()){
4188  candidates = skdTreeUtils::selectByGlobalPatch(surface.getSkdTree(), getSkdTree(), maxdistance);
4189  } else
4190 #endif
4191  {
4192  candidates = skdTreeUtils::selectByPatch(surface.getSkdTree(), getSkdTree(), maxdistance);
4193  }
4194 
4195  npoints = candidates.size();
4196  points.reserve(npoints);
4197  for(long idseed : candidates){
4198  points.emplace_back(getPatch()->evalCellCentroid(idseed));
4199  }
4200 
4201  } // end if seed list is null
4202 
4203 
4204  distances.resize(npoints, std::numeric_limits<double>::max());
4205  surface_ids.resize(npoints, bitpit::Cell::NULL_ID);
4206 
4207  // Compute distances from surface
4208 #if MIMMO_ENABLE_MPI
4209  if (surface.isParallel()){
4210  ivector1D surface_ranks(npoints, -1);
4211  skdTreeUtils::globalDistance(npoints, points.data(), surface.getSkdTree(), surface_ids.data(), surface_ranks.data(), distances.data(), maxdistance);
4212  } else
4213 #endif
4214  {
4215  skdTreeUtils::distance(npoints, points.data(), surface.getSkdTree(), surface_ids.data(), distances.data(), maxdistance);
4216  }
4217 
4218  // Fill seeds (directly in result) if distance < maxdistance
4219  for (int ipoint = 0; ipoint < npoints; ipoint++){
4220  distance = distances[ipoint];
4221  id = candidates[ipoint];
4222  if(distance < maxdist){
4223  result.insert(id, distance);
4224  }
4225  }
4226 
4227  // create the stack of neighbours with the seed i have.
4228  std::unordered_set<long> visited;
4229  livector1D stackNeighs, newStackNeighs;
4230  std::unordered_set<long> tt;
4231  for(auto it = result.begin(); it != result.end(); ++it){
4232  livector1D neighs = getPatch()->findCellNeighs(it.getId(), 1); //only face neighs.
4233  for(long id: neighs){
4234  if(!result.exists(id)) visited.insert(id);
4235  }
4236  }
4237  stackNeighs.insert(stackNeighs.end(), visited.begin(), visited.end());
4238 
4239  //add as visited also the id already in result;
4240  {
4241  livector1D temp = result.getIds();
4242  visited.insert(temp.begin(), temp.end());
4243  }
4244 
4245  // Search until the stack is empty.
4246  // In case of parallel and partitioned test the global stack size
4247  bool stackEmpty = stackNeighs.empty();
4248 #if MIMMO_ENABLE_MPI
4249  if (isParallel()){
4250  MPI_Allreduce(MPI_IN_PLACE, &stackEmpty, 1, MPI_C_BOOL, MPI_LAND, m_communicator);
4251  }
4252 #endif
4253  while(!stackEmpty){
4254 
4255  // use all stack neighs as candidates
4256  visited.insert(stackNeighs.begin(), stackNeighs.end());
4257 
4258  // evaluate their distances;
4259  npoints = stackNeighs.size();
4260  points.clear();
4261  points.reserve(npoints);
4262  distances.clear();
4263  distances.resize(npoints, std::numeric_limits<double>::max());
4264  surface_ids.clear();
4265  surface_ids.resize(npoints, bitpit::Cell::NULL_ID);
4266  for (long idtarget : stackNeighs){
4267  points.emplace_back(getPatch()->evalCellCentroid(idtarget));
4268  }
4269 
4270 #if MIMMO_ENABLE_MPI
4271  if (surface.isParallel()){
4272  ivector1D surface_ranks(npoints, -1);
4273  skdTreeUtils::globalDistance(npoints, points.data(), surface.getSkdTree(), surface_ids.data(), surface_ranks.data(), distances.data(), maxdistance);
4274  } else
4275 #endif
4276  {
4277  skdTreeUtils::distance(npoints, points.data(), surface.getSkdTree(), surface_ids.data(), distances.data(), maxdistance);
4278  }
4279 
4280  // Fill points inside narrow band in result and their neighbours in stack
4281  for (int ipoint = 0; ipoint < npoints; ipoint++){
4282  distance = distances[ipoint];
4283  id = stackNeighs[ipoint];
4284  if(distance < maxdist){
4285  result.insert(id, distance);
4286  livector1D neighs = getPatch()->findCellNeighs(id, 1); //only face neighs.
4287  for(long id : neighs){
4288  if(visited.count(id) < 1){
4289  visited.insert(id);
4290  newStackNeighs.push_back(id);
4291  }
4292  }
4293  }
4294  } // end loop on points
4295 
4296  // Empty stack by old targets and push the new stack neighs
4297  stackNeighs.swap(newStackNeighs);
4298  livector1D().swap(newStackNeighs);
4299 
4300  stackEmpty = stackNeighs.empty();
4301 #if MIMMO_ENABLE_MPI
4302  if (isParallel()){
4303  MPI_Allreduce(MPI_IN_PLACE, &stackEmpty, 1, MPI_C_BOOL, MPI_LAND, m_communicator);
4304  }
4305 #endif
4306 
4307  } // end while stack empty
4308  return result;
4309 
4310 };
4311 
4322 livector1D
4323 MimmoObject::getVerticesNarrowBandToExtSurface(MimmoObject & surface, const double & maxdist, livector1D * seedlist){
4324  bitpit::PiercedVector<double> res = getVerticesNarrowBandToExtSurfaceWDist(surface, maxdist, seedlist);
4325  return res.getIds();
4326 };
4327 
4338 bitpit::PiercedVector<double>
4339 MimmoObject::getVerticesNarrowBandToExtSurfaceWDist(MimmoObject & surface, const double & maxdist, livector1D * seedlist){
4340 
4341  //TODO this propagation does not work properly in parallel. Please review it
4342  //using propagated distance on ghost.
4343 
4344  bitpit::PiercedVector<double> result;
4345  if(surface.getType() != 1) return result;
4346 
4347  surface.updateAdjacencies();
4348 
4350  buildSkdTree();
4351 
4352  if (surface.getSkdTreeSyncStatus() != SyncStatus::SYNC)
4353  surface.buildSkdTree();
4354 
4357 
4358  //use a stack-based search on ring vertex neighbors of some prescribed seed vertex.
4359  //You need at least one vertex to be near enough to surface
4360 
4361  //First step check seed list and precalculate distance. If dist >= maxdist
4362  //the seed candidate is out.
4363  int npoints(0);
4364  dvecarr3E points;
4365  dvector1D distances;
4366  livector1D surface_ids;
4367  livector1D candidates;
4368  double distance, maxdistance(maxdist);
4369  long id;
4370 
4371  // Fill points candidates with seedlist or found candidates
4372  if(seedlist){
4373  //check if seedlist contains valid vertex ids for the current mesh/local rank partition.
4374  candidates.reserve(seedlist->size());
4375  bitpit::PiercedVector<bitpit::Vertex> & verts = getVertices();
4376  for(long id : *seedlist){
4377  if(verts.exists(id)) candidates.push_back(id);
4378  }
4379  candidates.shrink_to_fit();
4380  // Fill points array with seed list
4381  npoints = candidates.size();
4382  points.reserve(npoints);
4383  for(long idseed : candidates){
4384  points.emplace_back(getVertexCoords(idseed));
4385  }
4386 
4387  }else if(getType() != 3){
4388 
4389  // Find the seeds by using all the cells of surface patch
4390  // Recover the seeds by selecting by patch the target cells
4391  // by using the surface input patch as selection patch.
4392  // Then check if the candidate cells are closer than maxdistance,
4393  // in this case insert in result as seeds
4394 
4395  // Create cell candidates structure
4396  livector1D cell_candidates;
4397 #if MIMMO_ENABLE_MPI
4398  if (surface.isParallel()){
4399  cell_candidates = skdTreeUtils::selectByGlobalPatch(surface.getSkdTree(), getSkdTree(), maxdistance);
4400  } else
4401 #endif
4402  {
4403  cell_candidates = skdTreeUtils::selectByPatch(surface.getSkdTree(), getSkdTree(), maxdistance);
4404  }
4405 
4406  livector1D candidates = getVertexFromCellList(cell_candidates);
4407  // Fill points candidates with all the vertices of the found cells
4408  for(long idseed : candidates){
4409  points.emplace_back(getVertexCoords(idseed));
4410  }
4411 
4412  } // end if seed list is null
4413 
4414  distances.resize(npoints, std::numeric_limits<double>::max());
4415  surface_ids.resize(npoints, bitpit::Cell::NULL_ID);
4416  // Compute distances from surface
4417 #if MIMMO_ENABLE_MPI
4418  if (surface.isParallel()){
4419  ivector1D surface_ranks(npoints, -1);
4420  skdTreeUtils::globalDistance(npoints, points.data(), surface.getSkdTree(), surface_ids.data(), surface_ranks.data(), distances.data(), maxdistance);
4421  } else
4422 #endif
4423  {
4424  skdTreeUtils::distance(npoints, points.data(), surface.getSkdTree(), surface_ids.data(), distances.data(), maxdistance);
4425  }
4426 
4427  // Fill seed points (directly in result) if distance < maxdistance
4428  for (int ipoint = 0; ipoint < npoints; ipoint++){
4429  distance = distances[ipoint];
4430  id = candidates[ipoint];
4431  if(distance < maxdist){
4432  result.insert(id, distance);
4433  }
4434  }
4435 
4436  // create the stack of neighbours with the seed i have.
4437  std::unordered_set<long> visited;
4438  livector1D stackNeighs, newStackNeighs;
4439  std::unordered_set<long> tt;
4440  for(auto it = result.begin(); it != result.end(); ++it){
4441  std::unordered_set<long> neighs = getPointConnectivity(it.getId()); //only edge connected neighbours.
4442  for(long id: neighs){
4443  if(!result.exists(id)) visited.insert(id);
4444  }
4445  }
4446  stackNeighs.insert(stackNeighs.end(), visited.begin(), visited.end());
4447 
4448  //add as visited also the id already in result;
4449  {
4450  livector1D temp = result.getIds();
4451  visited.insert(temp.begin(), temp.end());
4452  }
4453 
4454  // Search until the stack is empty.
4455  // In case of parallel and partitioned test the global stack size
4456  bool stackEmpty = stackNeighs.empty();
4457 #if MIMMO_ENABLE_MPI
4458  if (isParallel()){
4459  MPI_Allreduce(MPI_IN_PLACE, &stackEmpty, 1, MPI_C_BOOL, MPI_LAND, m_communicator);
4460  }
4461 #endif
4462  while(!stackEmpty){
4463 
4464  // use all stack neighs as candidates
4465  visited.insert(stackNeighs.begin(), stackNeighs.end());
4466 
4467  // evaluate their distances;
4468  npoints = stackNeighs.size();
4469  points.clear();
4470  points.reserve(npoints);
4471  distances.clear();
4472  distances.resize(npoints, std::numeric_limits<double>::max());
4473  surface_ids.clear();
4474  surface_ids.resize(npoints, bitpit::Cell::NULL_ID);
4475  for (long idtarget : stackNeighs){
4476  points.emplace_back(getVertexCoords(idtarget));
4477  }
4478 
4479 #if MIMMO_ENABLE_MPI
4480  if (surface.isParallel()){
4481  ivector1D surface_ranks(npoints, -1);
4482  skdTreeUtils::globalDistance(npoints, points.data(), surface.getSkdTree(), surface_ids.data(), surface_ranks.data(), distances.data(), maxdistance);
4483  } else
4484 #endif
4485  {
4486  skdTreeUtils::distance(npoints, points.data(), surface.getSkdTree(), surface_ids.data(), distances.data(), maxdistance);
4487  }
4488 
4489  // Fill points inside narrow band in result and their neighbours in stack
4490  for (int ipoint = 0; ipoint < npoints; ipoint++){
4491  distance = distances[ipoint];
4492  id = stackNeighs[ipoint];
4493  if(distance < maxdist){
4494  result.insert(id, distance);
4495  std::unordered_set<long int> neighs = getPointConnectivity(id); //only edge connected
4496  for(long id : neighs){
4497  if(visited.count(id) < 1){
4498  visited.insert(id);
4499  newStackNeighs.push_back(id);
4500  }
4501  }
4502  }
4503  } // end loop on points
4504 
4505  // Empty stack by old targets and push the new stack neighs
4506  stackNeighs.swap(newStackNeighs);
4507  livector1D().swap(newStackNeighs);
4508 
4509  stackEmpty = stackNeighs.empty();
4510 #if MIMMO_ENABLE_MPI
4511  if (isParallel()){
4512  MPI_Allreduce(MPI_IN_PLACE, &stackEmpty, 1, MPI_C_BOOL, MPI_LAND, m_communicator);
4513  }
4514 #endif
4515 
4516  } // end while stack empty
4517 
4518  return result;
4519 
4520 };
4521 
4522 
4532 std::unordered_map<long,long> MimmoObject::getInverseConnectivity(){
4533 
4534  std::unordered_map<long,long> invConn ;
4535 
4536  long cellId;
4537  for(const auto &cell : getCells()){
4538  cellId = cell.getId();
4539  bitpit::ConstProxyVector<long> vList = cell.getVertexIds();
4540  for(const auto & idV : vList){
4541  invConn[idV] = cellId;
4542  }
4543  }
4544 
4545  return(invConn);
4546 };
4547 
4556 std::set<long> MimmoObject::findVertexVertexOneRing(const long & cellId, const long & vertexId){
4557 
4558  std::set<long> result;
4559  if( getType() == 3 ) return result;
4560 
4561  bitpit::PatchKernel * tri = getPatch();
4562  bitpit::Cell &cell = tri->getCell(cellId);
4563 
4564  if( !cell.isInterior() ) return result;
4565 
4566  int loc_target = cell.findVertex(vertexId);
4567  if(loc_target == bitpit::Vertex::NULL_ID) return result;
4568 
4569  livector1D list = tri->findCellVertexOneRing(cellId, loc_target);
4570 
4571  for(const auto & index : list){
4572  bitpit::ConstProxyVector<long> ids = tri->getCell(index).getVertexIds();
4573  result.insert(ids.begin(), ids.end());
4574  }
4575  result.erase(vertexId);
4576  return result;
4577 }
4578 
4584 std::array<double,3> MimmoObject::evalCellCentroid(const long & id){
4585  std::array<double,3> result = {{0.0,0.0,0.0}};
4586  if(getPatch()){
4587  result = getPatch()->evalCellCentroid(id);
4588  }
4589  return result;
4590 }
4591 
4597 std::array<double,3> MimmoObject::evalInterfaceCentroid(const long & id){
4598  std::array<double,3> result = {{0.0,0.0,0.0}};
4599  if(m_IntSync != SyncStatus::SYNC) return result;
4600 
4601  result = getPatch()->evalInterfaceCentroid(id);
4602 
4603  return result;
4604 }
4605 
4615 std::array<double,3> MimmoObject::evalInterfaceNormal(const long & id){
4616  std::array<double,3> result ({0.0,0.0,0.0});
4617  if(m_IntSync != SyncStatus::SYNC) return result;
4618 
4619  switch(m_type){
4620  case 1:
4621  {
4622  bitpit::Interface & interf = getInterfaces().at(id);
4623  std::array<double,3> enormal = static_cast<bitpit::SurfaceKernel*>(getPatch())->evalEdgeNormal(interf.getOwner(), interf.getOwnerFace());
4624  bitpit::ConstProxyVector<long> vv = interf.getVertexIds();
4625  result = crossProduct(getVertexCoords(vv[1]) - getVertexCoords(vv[0]), enormal);
4626  double normres = norm2(result);
4627  if(normres > std::numeric_limits<double>::min()){
4628  result /= normres;
4629  }
4630  }
4631  break;
4632 
4633  case 2:
4634  result = static_cast<bitpit::VolUnstructured*>(getPatch())->evalInterfaceNormal(id);
4635  break;
4636 
4637  default:
4638  //do nothing
4639  break;
4640  }
4641  return result;
4642 }
4643 
4653 double MimmoObject::evalInterfaceArea(const long & id){
4654  double result (0.0);
4655  if(m_IntSync != SyncStatus::SYNC) return result;
4656 
4657  switch(m_type){
4658  case 1:
4659  {
4660  bitpit::Interface & interf = getInterfaces().at(id);
4661  result = static_cast<bitpit::SurfaceKernel*>(getPatch())->evalEdgeLength(interf.getOwner(), interf.getOwnerFace());
4662  }
4663  break;
4664 
4665  case 2:
4666  result = static_cast<bitpit::VolUnstructured*>(getPatch())->evalInterfaceArea(id);
4667  break;
4668 
4669  default:
4670  //do nothing
4671  break;
4672  }
4673  return result;
4674 }
4675 
4680 void
4682 {
4684 
4685  //No point connectivity for point cloud
4686  if(getType() == 3) return;
4687 
4688  m_pointConnectivity.reserve(getNVertices());
4689 
4690  // Surface/volume mesh & 3d curve point connectivity
4691  if(getType() == 1 || getType() == 2 || getType() == 4){
4692 
4693  // Edge connectivity
4694  // All cells are considered, both interiors and ghosts
4695  std::set<std::pair<long,long> > edges;
4696  for (bitpit::Cell & cell : getCells()){
4697  int ne = 0;
4698  if (m_type == 1)
4699  ne = cell.getFaceCount();
4700  if (m_type == 2)
4701  ne = cell.getEdgeCount();
4702  if (m_type == 4)
4703  ne = 1;
4704 
4705  for (int i=0; i<ne; i++){
4706  bitpit::ConstProxyVector<long> ids;
4707  if (m_type == 1)
4708  ids = cell.getFaceVertexIds(i);
4709  if (m_type == 2)
4710  ids = cell.getEdgeVertexIds(i);
4711  if (m_type == 4)
4712  ids = cell.getVertexIds();
4713 
4714  // Edges have always two nodes
4715  long id1 = ids[0];
4716  long id2 = ids[1];
4717  std::pair<long,long> item;
4718  if (id1<id2)
4719  item=std::pair<long,long>(id1,id2);
4720  else
4721  item = std::pair<long,long>(id2,id1);
4722  if (!edges.count(item)){
4723  edges.insert(item);
4724  m_pointConnectivity[id1].insert(id2);
4725  m_pointConnectivity[id2].insert(id1);
4726  }
4727  }
4728  }
4729  }
4730  else{
4731  //No allowed type
4732  return;
4733  }
4734 
4736 }
4737 
4741 void
4743 {
4744  std::unordered_map<long, std::unordered_set<long> >().swap(m_pointConnectivity);
4745 
4748  };
4749 }
4750 
4756 std::unordered_set<long> &
4758 {
4759  assert(m_pointConnectivity.count(id) > 0 && "MimmoObject::not valid id in getPointConnectivity call");
4760  return m_pointConnectivity[id];
4761 }
4762 
4766 SyncStatus
4768  return m_pointConnectivitySync;
4769 }
4770 
4775 void
4777 
4778  if (m_type != 1){
4779  (*m_log)<<"Error MimmoObject: data structure type different from Surface in triangulate method"<<std::endl;
4780  throw std::runtime_error ("MimmoObject: data structure type different from Surface in triangulate method");
4781  }
4782 
4783  // In case of polygons (nVertices > 4) more nodes are added to the mesh.
4784  // In a distributed patch, new cells and nodes are added in all the partitions.
4785  // The connectivity order on two different partitions of the same cell (interior/ghost)
4786  // is supposed to be the same on each partition. This allows to add independently cells
4787  // on different partitions, even if working on the same physical cell.
4788  // The ghosts structures are updated at the end of the methods, by calling setPartitioned method.
4789  // Note. The node Ids on different partitions can be different and currently not tracked;
4790  // for this reason for now a serialization is forbidden after a refinement.
4791 
4792  // TODO INTRODUCE ADAPTING INFORMATION ON VERTICES AND CELLS WHEN USER INTERFACE IS READY IN BITPIT
4793 
4794  bitpit::PatchKernel * patch = getPatch();
4795 
4796  if (!isEmpty()){
4797 
4798  long maxID, newID, newVertID;
4799  const auto orderedCellID = getCells().getIds(true);
4800  maxID = orderedCellID[(int)orderedCellID.size()-1];
4801  newID = maxID+1;
4802  {
4803  const auto orderedVertID = getVertices().getIds(true);
4804  newVertID = orderedVertID[(int)orderedVertID.size()-1] +1;
4805  }
4806 
4807  bitpit::ElementType eletype;
4808  bitpit::ElementType eletri = bitpit::ElementType::TRIANGLE;
4809  livector1D connTriangle(3);
4810 
4811  for(const auto &idcell : orderedCellID){
4812 
4813  livector1D conn = getCellConnectivity(idcell);
4814  eletype = patch->getCell(idcell).getType();
4815  long pid = patch->getCell(idcell).getPID();
4816  int rank = -1;
4817 #if MIMMO_ENABLE_MPI
4818  rank = patch->getCellRank(idcell);
4819 #endif
4820  switch (eletype){
4821  case bitpit::ElementType::QUAD:
4822  case bitpit::ElementType::PIXEL:
4823  {
4824  patch->deleteCell(idcell);
4825  for(std::size_t i=0; i<2; ++i){
4826  connTriangle[0] = conn[0];
4827  connTriangle[1] = conn[i+1];
4828  connTriangle[2] = conn[i+2];
4829  addConnectedCell(connTriangle, eletri, pid, newID, rank);
4830  ++newID;
4831  }
4832  }
4833  break;
4834  case bitpit::ElementType::POLYGON:
4835  {
4836  std::size_t startIndex = 1;
4837  std::size_t nnewTri = conn.size() - startIndex;
4838  //calculate barycenter and add it as new vertex
4839  darray3E barycenter = patch->evalCellCentroid(idcell);
4840  addVertex(barycenter, newVertID);
4841  //delete current polygon
4842  patch->deleteCell(idcell);
4843  //insert new triangles from polygon subdivision
4844  for(std::size_t i=0; i<nnewTri; ++i){
4845  connTriangle[0] = newVertID;
4846  connTriangle[1] = conn[ startIndex + std::size_t( i % nnewTri) ];
4847  connTriangle[2] = conn[ startIndex + std::size_t( (i+1) % nnewTri ) ];
4848  addConnectedCell(connTriangle, eletri, pid, newID, rank);
4849  ++newID;
4850  }
4851  //increment label of vertices
4852  ++newVertID;
4853 
4854  }
4855  break;
4856  case bitpit::ElementType::TRIANGLE:
4857  //do nothing
4858  break;
4859  default:
4860  throw std::runtime_error("unrecognized cell type in 3D surface mesh of CGNSPidExtractor");
4861  break;
4862  }
4863  }
4864 
4865  // Unsync structures and update geometry
4870  m_AdjSync = std::min(m_AdjSync, SyncStatus::UNSYNC);
4871  m_IntSync = std::min(m_IntSync, SyncStatus::UNSYNC);
4872 #if MIMMO_ENABLE_MPI
4873  m_pointGhostExchangeInfoSync = std::min(m_pointGhostExchangeInfoSync, SyncStatus::UNSYNC);
4874 #endif
4875  } // end if patch is not empty
4876 
4877 #if MIMMO_ENABLE_MPI
4878  deleteOrphanGhostCells();
4879 #endif
4880 
4881  update();
4882 
4883 }
4884 
4898 void
4899 MimmoObject::degradeDegenerateElements(bitpit::PiercedVector<bitpit::Cell>* degradedDeletedCells,
4900  bitpit::PiercedVector<bitpit::Vertex>* collapsedVertices)
4901 {
4902  std::vector<long> toDelete;
4903  std::vector<bitpit::Cell> toInsert;
4904 
4905  // Reserve a tenth of the entire mesh for cells to be insert/delete
4906  toDelete.reserve(getNCells()/10);
4907  toInsert.reserve(getNCells()/10);
4908 
4909  std::unordered_map<long,long> vertexMap;
4910 
4911  bool fillCells = false;
4912  if (degradedDeletedCells){
4913  fillCells = true;
4914  degradedDeletedCells->clear();
4915  }
4916 
4917  bool fillVertices = false;
4918  if (collapsedVertices){
4919  fillVertices = true;
4920  collapsedVertices->clear();
4921  }
4922 
4923  // Loop on all cells to find the cell to be degraded or deleted
4924  // In parallel all the processes do the same things on local/ghost shared cells
4925  // The cells are degraded in the same manner and the cells/vertices delted
4926  // are the same.
4927  // Note. The new cells IDs can be different on different processes (local Id != ghost Id)
4928  for (bitpit::Cell & cell : getCells()){
4929 
4930  long cellId = cell.getId();
4931  bitpit::ElementType cellType = cell.getType();
4932  bitpit::ConstProxyVector<long> cellVertexIds = cell.getVertexIds();
4933  std::vector<long> cellConnectivity;
4934  std::vector<bitpit::Vertex> cellVertices;
4935  cellConnectivity.reserve(cellVertexIds.size());
4936  cellVertices.reserve(cellVertexIds.size());
4937  // Unique vertices cell connectivity
4938  for (long vertexId : cellVertexIds){
4939  bitpit::Vertex & candidateVertex = getPatch()->getVertex(vertexId);
4940  std::vector<bitpit::Vertex>::iterator it = std::find(cellVertices.begin(), cellVertices.end(), candidateVertex);
4941  if (it == cellVertices.end()){
4942  cellConnectivity.push_back(vertexId);
4943  cellVertices.emplace_back(candidateVertex);
4944  }
4945  else{
4946  //Collapse vertices
4947  vertexMap.insert({vertexId, it->getId()});
4948  if (fillVertices){
4949  collapsedVertices->insert(vertexId, candidateVertex);
4950  }
4951  }
4952  }
4953 
4954  bitpit::ElementType desumedType = desumeElement(cellConnectivity);
4955 
4956  if (desumedType != cellType){
4957  // If degenerate delete from geometry
4958  toDelete.push_back(cellId);
4959  if (desumedType != bitpit::ElementType::UNDEFINED){
4960  // If it can be degraded do it
4961  std::unique_ptr<long[]> connectStorage = std::unique_ptr<long[]>(new long[cellConnectivity.size()]);
4962  std::copy(cellConnectivity.begin(), cellConnectivity.end(), connectStorage.get());
4963  bitpit::Cell newCell(cellId, desumedType, std::move(connectStorage));
4964  newCell.setPID(cell.getPID());
4965  toInsert.push_back(newCell);
4966  }
4967  if (fillCells){
4968  degradedDeletedCells->insert(cellId, cell);
4969  }
4970  }
4971 
4972  } // end loop on cells
4973 
4974  // Delete degenerate cells
4975  getPatch()->deleteCells(toDelete);
4976 
4977  // Insert new degraded cells
4978  for (bitpit::Cell & cell : toInsert){
4979  addCell(cell, cell.getId());
4980  }
4981 
4982  // Collapse vertices
4983  if (!vertexMap.empty()) {
4984  // Renumber cell vertices
4985  for (bitpit::Cell &cell : getCells()) {
4986  cell.renumberVertices(vertexMap);
4987  }
4988  }
4989 
4990  // Unsync structures and update geometry if some cells deleted
4991  if (!toDelete.empty()){
4992  // Unsync structures and update geometry
4997  m_AdjSync = std::min(m_AdjSync, SyncStatus::UNSYNC);
4998  m_IntSync = std::min(m_IntSync, SyncStatus::UNSYNC);
4999 #if MIMMO_ENABLE_MPI
5000  m_pointGhostExchangeInfoSync = std::min(m_pointGhostExchangeInfoSync, SyncStatus::UNSYNC);
5001 #endif
5002 
5003  }
5004 
5005  update();
5006 
5007 }
5008 
5009 }
int getProcessorCount() const
livector2D getConnectivity()
std::vector< livector1D > livector2D
livector1D extractBoundaryVertexID(std::unordered_map< long, std::set< int > > &map)
SyncStatus m_AdjSync
std::unordered_map< long, std::set< int > > getBorderFaceCells()
std::vector< std::vector< long > > decomposeLoop()
std::set< long > findVertexVertexOneRing(const long &, const long &)
double evalInterfaceArea(const long &id)
SyncStatus
Define status of mimmo object structures like adjacencies, interfaces, etc.
bitpit::PiercedVector< bitpit::Vertex > & getVertices()
bitpit::PiercedVector< double > getCellsNarrowBandToExtSurfaceWDist(MimmoObject &surface, const double &maxdist, livector1D *seedList=nullptr)
SyncStatus m_boundingBoxSync
MimmoObject is the basic geometry container for mimmo library.
Custom derivation of bitpit::VolUnstructured class.
Definition: MimmoObject.hpp:73
SyncStatus m_pointConnectivitySync
bitpit::Logger * m_log
livector1D getBorderCells()
bitpit::PiercedVector< bitpit::Interface > & getInterfaces()
std::unordered_set< long > m_pidsType
SyncStatus getKdTreeSyncStatus()
dvecarr3E getVerticesCoords(lilimap *mapDataInv=nullptr)
std::vector< darray3E > dvecarr3E
bool setPIDName(long, const std::string &)
livector1D getVertexFromCellList(const livector1D &cellList)
void setPIDCell(long, long)
void swap(MimmoObject &) noexcept
void dump(std::ostream &stream)
MimmoObject(int type=1, bool isParallel=0)
std::vector< long > livector1D
long getNInternals() const
lilimap getMapCell(bool withghosts=true)
bool isPointInterior(long id)
long addConnectedCell(const livector1D &locConn, bitpit::ElementType type, int rank=-1)
livector1D getCellsIds(bool internalsOnly=false)
SyncStatus m_infoSync
livector1D getCellFromVertexList(const livector1D &vertList, bool strict=true)
std::unique_ptr< bitpit::PatchKernel > clone() const override
long addVertex(const darray3E &vertex, const long idtag=bitpit::Vertex::NULL_ID)
bitpit::PatchNumberingInfo * getPatchInfo()
livector1D extractBoundaryInterfaceID(std::unordered_map< long, std::set< int > > &map)
bitpit::PiercedVector< bitpit::Cell > & getCells()
void setTolerance(double tol)
bool modifyVertex(const darray3E &vertex, const long &id)
lilimap getMapCellInv(bool withghosts=true)
void setPID(livector1D)
SyncStatus getInfoSyncStatus()
std::unique_ptr< bitpit::PatchSkdTree > m_skdTree
livector2D getCompactConnectivity(lilimap &mapDataInv)
void evalCellAspectRatio(bitpit::PiercedVector< double > &)
std::unique_ptr< bitpit::KdTree< 3, bitpit::Vertex, long > > m_kdTree
livector1D getCellsNarrowBandToExtSurface(MimmoObject &surface, const double &maxdist, livector1D *seedList=nullptr)
std::unordered_map< long, long > getInverseConnectivity()
bitpit::PatchNumberingInfo m_patchInfo
SyncStatus getAdjacenciesSyncStatus()
livector1D extractPIDCells(long, bool squeeze=true)
bitpit::KdTree< 3, bitpit::Vertex, long > * getKdTree()
std::vector< int > ivector1D
livector1D getInterfaceFromVertexList(const livector1D &vertList, bool strict, bool border)
bitpit::ElementType desumeElement(const livector1D &)
std::unique_ptr< bitpit::PatchKernel > clone() const override
std::array< double, 3 > evalInterfaceNormal(const long &id)
std::vector< double > dvector1D
std::unordered_map< long, std::string > & getPIDTypeListWNames()
std::unordered_map< long, std::set< int > > extractBoundaryFaceCellID(bool ghost=false)
std::unordered_map< long int, long int > lilimap
Custom derivation of bitpit::SurfUnstructured class, for Point Cloud handling only.
Definition: MimmoObject.hpp:99
SyncStatus getInterfacesSyncStatus()
bitpit::PatchSkdTree * getSkdTree()
std::unordered_set< int > elementsMap(bitpit::PatchKernel &obj)
livector1D getBorderVertices()
void getBoundingBox(std::array< double, 3 > &pmin, std::array< double, 3 > &pmax, bool global=true)
bitpit::Logger & getLog()
std::array< double, 3 > evalCellCentroid(const long &id)
std::vector< long > selectByPatch(bitpit::PatchSkdTree *selection, bitpit::PatchSkdTree *target, double tol)
livector1D getInterfaceFromCellList(const livector1D &cellList, bool all=true)
void degradeDegenerateElements(bitpit::PiercedVector< bitpit::Cell > *degradedDeletedCells=nullptr, bitpit::PiercedVector< bitpit::Vertex > *collapsedVertices=nullptr)
void restore(std::istream &stream)
std::array< double, 3 > evalInterfaceCentroid(const long &id)
MimmoSharedPointer< MimmoObject > clone() const
std::unordered_map< long, std::string > m_pidsTypeWNames
void buildSkdTree(std::size_t value=1)
SyncStatus getBoundingBoxSyncStatus()
std::array< double, 3 > darray3E
livector1D getCompactPID()
std::unordered_set< long > & getPIDTypeList()
std::map< long, livector1D > extractPIDSubdivision()
livector1D getCellConnectivity(long id) const
SyncStatus getSkdTreeSyncStatus()
std::unordered_set< long > & getPointConnectivity(const long &id)
long addCell(bitpit::Cell &cell, int rank=-1)
livector1D getVerticesIds(bool internalsOnly=false)
void evalCellVolumes(bitpit::PiercedVector< double > &)
SyncStatus getPointConnectivitySyncStatus()
MimmoSharedPointer is a custom implementation of shared pointer.
std::unique_ptr< bitpit::PatchKernel > clone() const override
livector1D getVerticesNarrowBandToExtSurface(MimmoObject &surface, const double &maxdist, livector1D *seedList=nullptr)
lilimap getMapData(bool withghosts=false)
livector1D extractBoundaryCellID(bool ghost=false)
Custom derivation of bitpit::SurfUnstructured class.
Definition: MimmoObject.hpp:45
std::unordered_map< long, std::unordered_set< long > > m_pointConnectivity
MimmoSharedPointer< MimmoObject > extractBoundaryMesh()
std::unordered_map< long, long > getPID()
bitpit::PiercedVector< double > getVerticesNarrowBandToExtSurfaceWDist(MimmoObject &surface, const double &maxdist, livector1D *seedList=nullptr)
double distance(const std::array< double, 3 > *point, const bitpit::PatchSkdTree *tree, long &id, double r)
void reset(int type, bool isParallel=0)
double evalCellVolume(const long &id)
lilimap getMapDataInv(bool withghosts=true)
SyncStatus m_kdTreeSync
const darray3E & getVertexCoords(long i) const
SyncStatus m_IntSync
SyncStatus m_skdTreeSync
bitpit::PatchKernel * getPatch()