Loading...
Searching...
No Matches
surfunstructured.cpp
1/*---------------------------------------------------------------------------*\
2 *
3 * bitpit
4 *
5 * Copyright (C) 2015-2021 OPTIMAD engineering Srl
6 *
7 * -------------------------------------------------------------------------
8 * License
9 * This file is part of bitpit.
10 *
11 * bitpit 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 * bitpit 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 bitpit. If not, see <http://www.gnu.org/licenses/>.
22 *
23\*---------------------------------------------------------------------------*/
24
25#include "bitpit_common.hpp"
26#include "bitpit_IO.hpp"
27
28#include "surfunstructured.hpp"
29
30namespace bitpit {
31
42#if BITPIT_ENABLE_MPI==1
55SurfUnstructured::SurfUnstructured(MPI_Comm communicator, std::size_t haloSize)
56 : SurfaceKernel(communicator, haloSize, ADAPTION_MANUAL, PARTITIONING_ENABLED)
57#else
62 : SurfaceKernel(ADAPTION_MANUAL)
63#endif
64{
65}
66
67#if BITPIT_ENABLE_MPI==1
81SurfUnstructured::SurfUnstructured(int dimension, MPI_Comm communicator, std::size_t haloSize)
82 : SurfUnstructured(PatchManager::AUTOMATIC_ID, dimension, communicator, haloSize)
83#else
90 : SurfUnstructured(PatchManager::AUTOMATIC_ID, dimension)
91#endif
92{
93}
94
95#if BITPIT_ENABLE_MPI==1
110SurfUnstructured::SurfUnstructured(int id, int dimension, MPI_Comm communicator, std::size_t haloSize)
111 : SurfaceKernel(id, dimension, communicator, haloSize, ADAPTION_MANUAL, PARTITIONING_ENABLED)
112#else
119SurfUnstructured::SurfUnstructured(int id, int dimension)
120 : SurfaceKernel(id, dimension, ADAPTION_MANUAL)
121#endif
122{
123}
124
125#if BITPIT_ENABLE_MPI==1
138SurfUnstructured::SurfUnstructured(std::istream &stream, MPI_Comm communicator, std::size_t haloSize)
139 : SurfaceKernel(communicator, haloSize, ADAPTION_MANUAL, PARTITIONING_ENABLED)
140#else
146SurfUnstructured::SurfUnstructured(std::istream &stream)
147 : SurfaceKernel(ADAPTION_MANUAL)
148#endif
149{
150 // Restore the patch
151 restore(stream);
152}
153
159std::unique_ptr<PatchKernel> SurfUnstructured::clone() const
160{
161 return std::unique_ptr<SurfUnstructured>(new SurfUnstructured(*this));
162}
163
170{
171 const int DUMP_VERSION = 5;
172
173 return DUMP_VERSION;
174}
175
181void SurfUnstructured::_dump(std::ostream &stream) const
182{
183 // Save the vertices
184 dumpVertices(stream);
185
186 // Save the cells
187 dumpCells(stream);
188
189 // Save the interfaces
190 dumpInterfaces(stream);
191}
192
198void SurfUnstructured::_restore(std::istream &stream)
199{
200 // Restore the vertices
201 restoreVertices(stream);
202
203 // Restore the cells
204 restoreCells(stream);
205
206 // Restore the interfaces
207 restoreInterfaces(stream);
208}
209
223long SurfUnstructured::locatePoint(const std::array<double, 3> &point) const
224{
225 BITPIT_UNUSED(point);
226
227 throw std::runtime_error ("The function 'locatePoint' is not implemented yet");
228
229 return Cell::NULL_ID;
230}
231
232//TODO: Aggiungere un metodo in SurfUnstructured per aggiungere piĆ¹ vertici.
241{
242 // ====================================================================== //
243 // VARIABLES DECLARATION //
244 // ====================================================================== //
245
246 // Local variables
247 bool check;
248 int n_faces, n_adj;
249 long id;
250 const long *adjacencies;
251
252 // Counters
253 int i, j;
254 VertexIterator v_, ve_ = vertexEnd();
255 CellIterator c_, ce_ = cellEnd();
256
257 // ====================================================================== //
258 // INITIALIZE DATA STRUCTURE //
259 // ====================================================================== //
260 net.reserveCells(net.getCellCount() + countFaces());
262
263 // ====================================================================== //
264 // ADD VERTEX TO net //
265 // ====================================================================== //
266 for (v_ = vertexBegin(); v_ != ve_; ++v_) {
267 net.addVertex(v_->getCoords(), v_->getId());
268 } //next v_
269
270 // ====================================================================== //
271 // ADD EDGES //
272 // ====================================================================== //
273 for (c_ = cellBegin(); c_ != ce_; ++c_) {
274 id = c_->getId();
275 n_faces = c_->getFaceCount();
276 ConstProxyVector<long> cellVertexIds = c_->getVertexIds();
277 for (i = 0; i < n_faces; ++i) {
278 check = true;
279 n_adj = c_->getAdjacencyCount(i);
280 adjacencies = c_->getAdjacencies(i);
281 for (j = 0; j < n_adj; ++j) {
282 check = check && (id > adjacencies[j]);
283 } //next j
284 if (check) {
285 // Get edge type
286 ElementType edgeType = c_->getFaceType(i);
287
288 // Get edge connect
289 ConstProxyVector<long> faceConnect = c_->getFaceConnect(i);
290 int faceConnectSize = faceConnect.size();
291
292 std::unique_ptr<long[]> edgeConnect = std::unique_ptr<long[]>(new long[faceConnectSize]);
293 for (int k = 0; k < faceConnectSize; ++k) {
294 edgeConnect[k] = faceConnect[k];
295 }
296
297 // Add edge
298 net.addCell(edgeType, std::move(edgeConnect));
299 }
300 } //next i
301 } //next c_
302
303 return;
304}
305
306//TODO: normals??
307//TODO: error flag on output
308//TODO: import a specified solid (ascii format only)
329int SurfUnstructured::importSTL(const std::string &filename,
330 int PIDOffset, bool PIDSquash)
331{
332 return importSTL(filename, STLReader::FormatUnknown, false, PIDOffset, PIDSquash);
333}
334
358int SurfUnstructured::importSTL(const std::string &filename, bool isBinary,
359 int PIDOffset, bool PIDSquash,
360 std::unordered_map<int, std::string> *PIDNames)
361{
362 STLReader::Format format;
363 if (isBinary) {
364 format = STLReader::FormatBinary;
365 } else {
366 format = STLReader::FormatASCII;
367 }
368
369 return importSTL(filename, format, false, PIDOffset, PIDSquash, PIDNames);
370}
371
405int SurfUnstructured::importSTL(const std::string &filename, STLReader::Format format,
406 bool joinFacets, int PIDOffset, bool PIDSquash,
407 std::unordered_map<int, std::string> *PIDNames)
408{
409 int readerError;
410
411 // Initialize reader
412 STLReader reader(filename, format);
413 if (format == STLReader::FormatUnknown) {
414 format = reader.getFormat();
415 }
416
417 // Begin reding the STL file
418 readerError = reader.readBegin();
419 if (readerError != 0) {
420 return readerError;
421 }
422
423 // Initialize cache needed for joinin the facets
424 //
425 // The cache will contain the ids of the vertices that have been added
426 // to the patch. It uses a special comparator that allows to compare
427 // the coordinates of a candidate vertex with the coordinates of the
428 // vertices in the cache.
429 std::array<double, 3> *candidateVertexCoords;
430 Vertex::Less vertexLess(10 * std::numeric_limits<double>::epsilon());
431
432 auto vertexCoordsLess = [this, &vertexLess, &candidateVertexCoords](const long &id_1, const long &id_2)
433 {
434 const std::array<double, 3> &coords_1 = (id_1 >= 0) ? this->getVertex(id_1).getCoords() : *candidateVertexCoords;
435 const std::array<double, 3> &coords_2 = (id_2 >= 0) ? this->getVertex(id_2).getCoords() : *candidateVertexCoords;
436
437 return vertexLess(coords_1, coords_2);
438 };
439
440 std::set<long, decltype(vertexCoordsLess)> vertexCache(vertexCoordsLess);
441
442 // Read all the solids in the STL file
443 int pid = PIDOffset;
444
445 ElementType facetType = ElementType::TRIANGLE;
446 const int nFacetVertices = ReferenceElementInfo::getInfo(ElementType::TRIANGLE).nVertices;
447
448 while (true) {
449 // Read header
450 std::size_t nFacets;
451 std::string name;
452 readerError = reader.readHeader(&name, &nFacets);
453 if (readerError != 0) {
454 if (readerError == -2) {
455 break;
456 } else {
457 return readerError;
458 }
459 }
460
461 // Generate patch cells from STL facets
462 reserveCells(getCellCount() + nFacets);
463
464 std::size_t nEstimatedVertices;
465 if (joinFacets) {
466 // The number of facets and the number of vertices of a triangulation
467 // are related by the inequality nFacets <= 2 * nVertices - 4, where
468 // the equality holds for a closed triangulation. To limit memory usage
469 // we estimate the number of vertices assuming a closed triangulation
470 // (this gives us the minimum number of nodes the triangulation could
471 // possibly have).
472 nEstimatedVertices = static_cast<std::size_t>(0.5 * nFacets) + 2;
473 } else {
474 nEstimatedVertices = nFacetVertices * nFacets;
475 }
476 reserveVertices(getVertexCount() + nEstimatedVertices);
477
478 vertexCache.clear();
479
480 for (std::size_t n = 0; n < nFacets; ++n) {
481 // Read facet data
482 std::array<Vertex, 3> faceVertices;
483 std::array<double, 3> facetNormal;
484 readerError = reader.readFacet(&(faceVertices[0].getCoords()), &(faceVertices[1].getCoords()), &(faceVertices[2].getCoords()), &facetNormal);
485 if (readerError != 0) {
486 return readerError;
487 }
488
489 // Add vertices
490 std::unique_ptr<long[]> connectStorage = std::unique_ptr<long[]>(new long[nFacetVertices]);
491 if (joinFacets) {
492 for (int i = 0; i < nFacetVertices; ++i) {
493 // The candidate vertex is set equal to the face vertex
494 // that needs to be added, then the cache is checked: if
495 // a vertex with the same coordinates is already in the
496 // cache, the vertex will not be added and the existing
497 // one will be used.
498 //
499 // The cache contains the ids of the vertices that have
500 // been added. It uses a special comparator that allows
501 // to compare the candidate vertex with the ones in the
502 // cache, in order to do that the null vertex should be
503 // passed to the find function.
504 candidateVertexCoords = &(faceVertices[i].getCoords());
505
506 long vertexId;
507 auto vertexCacheItr = vertexCache.find(Vertex::NULL_ID);
508 if (vertexCacheItr == vertexCache.end()) {
509 VertexIterator vertexItr = addVertex(*candidateVertexCoords);
510 vertexId = vertexItr.getId();
511 vertexCache.insert(vertexId);
512 } else {
513 vertexId = *vertexCacheItr;
514 }
515 connectStorage[i] = vertexId;
516 }
517 } else {
518 for (int i = 0; i < nFacetVertices; ++i) {
519 VertexIterator vertexItr = addVertex(faceVertices[i].getCoords());
520 long vertexId = vertexItr.getId();
521 connectStorage[i] = vertexId;
522 }
523 }
524
525 // Add cell
526 CellIterator cellIterator = addCell(facetType, std::move(connectStorage));
527 cellIterator->setPID(pid);
528 }
529
530 // Read footer
531 readerError = reader.readFooter(name);
532 if (readerError != 0) {
533 return readerError;
534 }
535
536 // Assign PID name
537 if (!PIDSquash) {
538 if (PIDNames && !name.empty()) {
539 PIDNames->insert({{pid, name}});
540 }
541 ++pid;
542 }
543
544 // Multi-body STL files are supported only in ASCII mode
545 if (format == STLReader::FormatBinary) {
546 break;
547 }
548 }
549
550 // End reading
551 readerError = reader.readEnd();
552 if (readerError != 0) {
553 return readerError;
554 }
555
556 return 0;
557}
558
569int SurfUnstructured::exportSTL(const std::string &filename, bool isBinary)
570{
571 return exportSTLSingle(filename, isBinary);
572}
573
587int SurfUnstructured::exportSTL(const std::string &filename, bool isBinary, bool isMulti,
588 std::unordered_map<int, std::string> *PIDNames)
589{
590 int flag = 0;
591 if (isMulti) {
592 flag = exportSTLMulti(filename, PIDNames);
593 } else {
594 flag = exportSTLSingle(filename, isBinary);
595 }
596
597 return flag;
598}
599
600//TODO: normals??
601//TODO: error flag on output
602//TODO: conversion of quad into tria
612int SurfUnstructured::exportSTLSingle(const std::string &filename, bool isBinary)
613{
614 int writerError;
615
616 // Initialize writer
617 STLReader::Format format;
618 if (isBinary) {
619 format = STLReader::FormatBinary;
620 } else {
621 format = STLReader::FormatASCII;
622 }
623
624 STLWriter writer(filename, format);
625
626 // Solid name
627 //
628 // An empty solid name will be used.
629 const std::string name = "";
630
631 // Detect if this is the master writer
632 bool isMasterWriter;
633#if BITPIT_ENABLE_MPI==1
634 if (isPartitioned()) {
635 isMasterWriter = (getRank() == 0);
636 } else {
637#else
638 {
639#endif
640 isMasterWriter = true;
641 }
642
643 // Detect if the file will be written incrementally
644 bool incrementalWrite;
645#if BITPIT_ENABLE_MPI==1
646 incrementalWrite = true;
647#else
648 incrementalWrite = false;
649#endif
650
651 // Count the number of facets
652 long nFacets = getInternalCellCount();
653#if BITPIT_ENABLE_MPI==1
654 if (isPartitioned()) {
655 MPI_Allreduce(MPI_IN_PLACE, &nFacets, 1, MPI_LONG, MPI_SUM, getCommunicator());
656 }
657#endif
658
659 // Write header
660 if (isMasterWriter) {
661 // Begin writing
662 writerError = writer.writeBegin(STLWriter::WriteOverwrite, incrementalWrite);
663 if (writerError != 0) {
664 writer.writeEnd();
665
666 return writerError;
667 }
668
669 // Write header section
670 writerError = writer.writeHeader(name, nFacets);
671 if (writerError != 0) {
672 writer.writeEnd();
673
674 return writerError;
675 }
676
677#if BITPIT_ENABLE_MPI==1
678 // Close the file to let other process write into it
679 writerError = writer.writeEnd();
680 if (writerError != 0) {
681 return writerError;
682 }
683#endif
684 }
685
686 // Write facet data
687#if BITPIT_ENABLE_MPI==1
688 int nRanks = getProcessorCount();
689 for (int i = 0; i < nRanks; ++i) {
690 if (i == getRank()) {
691 // Begin writing
692 writerError = writer.writeBegin(STLWriter::WriteAppend, incrementalWrite);
693 if (writerError != 0) {
694 writer.writeEnd();
695 return writerError;
696 }
697
698#else
699 {
700#endif
701 // Write facet section
704 for (CellConstIterator cellItr = cellBegin; cellItr != cellEnd; ++cellItr) {
705 // Get cell
706 const Cell &cell = *cellItr;
707
708 // Get vertex coordinates
709 ConstProxyVector<long> cellVertexIds = cell.getVertexIds();
710 assert(cellVertexIds.size() == 3);
711
712 const std::array<double, 3> &coords_0 = getVertex(cellVertexIds[0]).getCoords();
713 const std::array<double, 3> &coords_1 = getVertex(cellVertexIds[1]).getCoords();
714 const std::array<double, 3> &coords_2 = getVertex(cellVertexIds[2]).getCoords();
715
716 // Evaluate normal
717 const std::array<double, 3> normal = evalFacetNormal(cell.getId());
718
719 // Write data
720 writerError = writer.writeFacet(coords_0, coords_1, coords_2, normal);
721 if (writerError != 0) {
722 writer.writeEnd();
723 return writerError;
724 }
725 }
726
727#if BITPIT_ENABLE_MPI==1
728 // Close the file to let other process write into it
729 writerError = writer.writeEnd();
730 if (writerError != 0) {
731 return writerError;
732 }
733 }
734
735 if (isPartitioned()) {
736 MPI_Barrier(getCommunicator());
737 }
738#endif
739 }
740
741 // Write footer
742 if (isMasterWriter) {
743#if BITPIT_ENABLE_MPI==1
744 // Begin writning
745 //
746 // The file was previously closed to let other process write into it.
747 writerError = writer.writeBegin(STLWriter::WriteAppend, incrementalWrite);
748 if (writerError != 0) {
749 writer.writeEnd();
750 return writerError;
751 }
752#endif
753
754 // Write footer section
755 writerError = writer.writeFooter(name);
756 if (writerError != 0) {
757 writer.writeEnd();
758
759 return writerError;
760 }
761
762 // End writing
763 writerError = writer.writeEnd();
764 if (writerError != 0) {
765 return writerError;
766 }
767 }
768
769 return 0;
770}
771
782int SurfUnstructured::exportSTLMulti(const std::string &filename, std::unordered_map<int, std::string> *PIDNames)
783{
784 int writerError;
785
786 // Initialize writer
787 STLWriter writer(filename, STLReader::FormatASCII);
788
789 // Detect if this is the master writer
790 bool isMasterWriter;
791#if BITPIT_ENABLE_MPI==1
792 if (isPartitioned()) {
793 isMasterWriter = (getRank() == 0);
794 } else {
795#else
796 {
797#endif
798 isMasterWriter = true;
799 }
800
801 // Detect if the file will be written incrementally
802 bool incrementalWrite = true;
803
804#if BITPIT_ENABLE_MPI==1
805 // Count number of ranks
806 int nRanks = getProcessorCount();
807#endif
808
809 // Get the global list of PID
810 std::set<int> cellPIDs;
811#if BITPIT_ENABLE_MPI==1
812 if (isPartitioned()) {
813 std::set<int> internalPIDs = getInternalCellPIDs();
814 std::vector<int> localPIDs(internalPIDs.begin(), internalPIDs.end());
815 int nLocalPids = localPIDs.size();
816
817 std::vector<int> gatherPIDCount(nRanks);
818 MPI_Allgather(&nLocalPids, 1, MPI_INT, gatherPIDCount.data(), 1, MPI_INT, getCommunicator());
819
820 std::vector<int> gatherPIDDispls(nRanks, 0);
821 for (int i = 1; i < nRanks; ++i) {
822 gatherPIDDispls[i] = gatherPIDDispls[i - 1] + gatherPIDCount[i - 1];
823 }
824
825 int gatherPIDsSize = gatherPIDDispls.back() + gatherPIDCount.back();
826
827 std::vector<int> globalPIDs(gatherPIDsSize);
828 MPI_Allgatherv(localPIDs.data(), nLocalPids, MPI_INT, globalPIDs.data(),
829 gatherPIDCount.data(), gatherPIDDispls.data(), MPI_INT, getCommunicator());
830
831 cellPIDs = std::set<int>(globalPIDs.begin(), globalPIDs.end());
832 } else {
833#else
834 {
835#endif
836 cellPIDs = getInternalCellPIDs();
837 }
838
839 // Export cells
840 bool firstPID = true;
841 for (int pid : cellPIDs) {
842 // Cells associated with the PID
843 std::vector<long> cells = getInternalCellsByPID(pid);
844
845 // Count the number of facets
846 long nFacets = cells.size();
847#if BITPIT_ENABLE_MPI==1
848 if (isPartitioned()) {
849 MPI_Allreduce(MPI_IN_PLACE, &nFacets, 1, MPI_LONG, MPI_SUM, getCommunicator());
850 }
851#endif
852
853 // Solid name
854 std::string name;
855 if (PIDNames && PIDNames->count(pid) > 0) {
856 name = PIDNames->at(pid);
857 } else {
858 name = std::to_string(pid);
859 }
860
861 // Write header
862 if (isMasterWriter) {
863 // Begin writing
864 STLWriter::WriteMode writeMode;
865 if (firstPID) {
866 writeMode = STLWriter::WriteOverwrite;
867 } else {
868 writeMode = STLWriter::WriteAppend;
869 }
870
871 writerError = writer.writeBegin(writeMode, incrementalWrite);
872 if (writerError != 0) {
873 writer.writeEnd();
874
875 return writerError;
876 }
877
878 // Write header section
879 writerError = writer.writeHeader(name, nFacets);
880 if (writerError != 0) {
881 writer.writeEnd();
882
883 return writerError;
884 }
885
886#if BITPIT_ENABLE_MPI==1
887 // Close the file to let other process write into it
888 writerError = writer.writeEnd();
889 if (writerError != 0) {
890 return writerError;
891 }
892#endif
893 }
894
895 // Write facet data
896#if BITPIT_ENABLE_MPI==1
897 for (int i = 0; i < nRanks; ++i) {
898 if (i == getRank()) {
899 // Begin writing
900 writerError = writer.writeBegin(STLWriter::WriteAppend, incrementalWrite);
901 if (writerError != 0) {
902 writer.writeEnd();
903 return writerError;
904 }
905
906#else
907 {
908#endif
909 // Write facet section
910 for (long cellId : cells) {
911 // Get cell
912 const Cell &cell = getCell(cellId);
913
914 // Get vertex coordinates
915 ConstProxyVector<long> cellVertexIds = cell.getVertexIds();
916 assert(cellVertexIds.size() == 3);
917
918 const std::array<double, 3> &coords_0 = getVertex(cellVertexIds[0]).getCoords();
919 const std::array<double, 3> &coords_1 = getVertex(cellVertexIds[1]).getCoords();
920 const std::array<double, 3> &coords_2 = getVertex(cellVertexIds[2]).getCoords();
921
922 // Evaluate normal
923 const std::array<double, 3> normal = evalFacetNormal(cell.getId());
924
925 // Write data
926 writerError = writer.writeFacet(coords_0, coords_1, coords_2, normal);
927 if (writerError != 0) {
928 writer.writeEnd();
929 return writerError;
930 }
931 }
932
933 #if BITPIT_ENABLE_MPI==1
934 // Close the file to let other process write into it
935 writerError = writer.writeEnd();
936 if (writerError != 0) {
937 return writerError;
938 }
939 }
940
941 if (isPartitioned()) {
942 MPI_Barrier(getCommunicator());
943 }
944#endif
945 }
946
947 // Write footer
948 if (isMasterWriter) {
949#if BITPIT_ENABLE_MPI==1
950 // Begin writing
951 //
952 // The file was previously closed to let other process write into it.
953 writerError = writer.writeBegin(STLWriter::WriteAppend, incrementalWrite);
954 if (writerError != 0) {
955 writer.writeEnd();
956 return writerError;
957 }
958#endif
959
960 // Write footer section
961 writerError = writer.writeFooter(name);
962 if (writerError != 0) {
963 writer.writeEnd();
964
965 return writerError;
966 }
967
968 // End writing
969 writerError = writer.writeEnd();
970 if (writerError != 0) {
971 return writerError;
972 }
973 }
974
975 // The first PID has been written
976 firstPID = false;
977 }
978
979 return 0;
980}
981
999int SurfUnstructured::importDGF(const std::string &filename, int PIDOffset, bool PIDSquash)
1000{
1001 return importDGF(filename, false, PIDOffset, PIDSquash);
1002}
1003
1029int SurfUnstructured::importDGF(const std::string &filename, bool joinFacets, int PIDOffset, bool PIDSquash)
1030{
1031 // ====================================================================== //
1032 // VARIABLES DECLARATION //
1033 // ====================================================================== //
1034
1035 // Local variables
1036 DGFObj dgf_in(filename);
1037 int nV = 0, nS = 0;
1038 std::vector<std::array<double, 3>> vertex_list;
1039 std::vector<std::vector<int>> simplex_list;
1040 std::vector<int> simplex_PID;
1041 std::vector<long> vertex_map;
1042 std::vector<long> connect;
1043
1044 // Counters
1045 std::vector<std::vector<int>>::iterator c_, ce_;
1046 std::vector<int>::iterator i_, ie_;
1047 std::vector<long>::iterator j_, je_;
1048
1049 // ====================================================================== //
1050 // IMPORT DATA //
1051 // ====================================================================== //
1052
1053 // Read vertices and cells from DGF file
1054 dgf_in.load(nV, nS, vertex_list, simplex_list, simplex_PID);
1055
1056 // Add vertices
1057 vertex_map.resize(nV);
1058 if (joinFacets) {
1059 // Vertices added to the patch are also added into a cache. Before
1060 // inserting a new vertex, the cache is checked: if a vertex with the
1061 // same coordinates is already in the cache, the new vertex will not
1062 // be added and the existing one will be used.
1063 //
1064 // The cache contains the position of the vertices in the list of
1065 // vertices read from the DGF file.
1066 Vertex::Less vertexLess(10 * std::numeric_limits<double>::epsilon());
1067
1068 auto vertexCoordsLess = [&vertexLess, &vertex_list](const int &i, const int &j)
1069 {
1070 return vertexLess(vertex_list[i], vertex_list[j]);
1071 };
1072
1073 std::set<int, decltype(vertexCoordsLess)> vertexCache(vertexCoordsLess);
1074
1075 for (int i = 0; i < nV; ++i) {
1076 long vertexId;
1077 auto vertexCacheItr = vertexCache.find(i);
1078 if (vertexCacheItr == vertexCache.end()) {
1079 VertexIterator vertexItr = addVertex(vertex_list[i]);
1080 vertexId = vertexItr.getId();
1081 vertexCache.insert(i);
1082 } else {
1083 vertexId = vertex_map[*vertexCacheItr];
1084 }
1085 vertex_map[i] = vertexId;
1086 }
1087 } else {
1088 for (int i = 0; i < nV; ++i) {
1089 VertexIterator vertexItr = addVertex(vertex_list[i]);
1090 long vertexId = vertexItr.getId();
1091 vertex_map[i] = vertexId;
1092 }
1093 }
1094
1095 // Update connectivity infos
1096 ce_ = simplex_list.end();
1097 for (c_ = simplex_list.begin(); c_ != ce_; ++c_) {
1098 ie_ = c_->end();
1099 for (i_ = c_->begin(); i_ != ie_; ++i_) {
1100 *i_ = vertex_map[*i_];
1101 } //next i_
1102 } //next c_
1103
1104 // Add cells
1105 int k;
1106 for (c_ = simplex_list.begin(), k = 0; c_ != ce_; ++c_, ++k) {
1107 // Create cell
1108 i_ = c_->begin();
1109 connect.resize(c_->size(), Vertex::NULL_ID);
1110 je_ = connect.end();
1111 for (j_ = connect.begin(); j_ != je_; ++j_) {
1112 *j_ = *i_;
1113 ++i_;
1114 } //next j_
1115 CellIterator cellIterator = addCell(getDGFFacetType(c_->size()), connect);
1116
1117 // Set cell PID
1118 int cellPID = PIDOffset;
1119 if (!PIDSquash) {
1120 cellPID += simplex_PID[k];
1121 }
1122
1123 cellIterator->setPID(cellPID);
1124 } //next c_
1125
1126 return 0;
1127}
1128
1136int SurfUnstructured::exportDGF(const std::string &filename)
1137{
1138 // ====================================================================== //
1139 // VARIABLES DECLARATION //
1140 // ====================================================================== //
1141
1142 // Local variables
1143 DGFObj dgf_in(filename);
1144 int nV = getVertexCount(), nS = getCellCount();
1145 int v, nv;
1146 long vcount, ccount, idx;
1147 std::vector<std::array<double, 3>> vertex_list(nV);
1148 std::vector<std::vector<int>> simplex_list(nS);
1149 std::unordered_map<long, long> vertex_map;
1150
1151 // Counters
1152 VertexIterator v_, ve_;
1153 CellIterator c_, ce_;
1154
1155 // ====================================================================== //
1156 // EXPORT DATA //
1157 // ====================================================================== //
1158
1159 // Create vertex list
1160 ve_ = vertexEnd();
1161 vcount = 0;
1162 for (v_ = vertexBegin(); v_ != ve_; ++v_) {
1163 idx = v_->getId();
1164 vertex_list[vcount] = v_->getCoords();
1165 vertex_map[idx] = vcount;
1166 ++vcount;
1167 } //next v_
1168
1169 // Add cells
1170 ce_ = cellEnd();
1171 ccount = 0;
1172 for (c_ = cellBegin(); c_ != ce_; ++c_) {
1173 ConstProxyVector<long> cellVertexIds = c_->getVertexIds();
1174 nv = cellVertexIds.size();
1175 simplex_list[ccount].resize(nv);
1176 for (v = 0; v < nv; ++v) {
1177 simplex_list[ccount][v] = vertex_map[cellVertexIds[v]];
1178 } //next v
1179 ++ccount;
1180 } //next c_
1181
1182 // Read vertices and cells from DGF file
1183 dgf_in.save(nV, nS, vertex_list, simplex_list);
1184
1185 return 0;
1186}
1187
1196{
1197 switch(nFacetVertices) {
1198
1199 case 1:
1200 return ElementType::VERTEX;
1201
1202 case 2:
1203 return ElementType::LINE;
1204
1205 case 3:
1206 return ElementType::TRIANGLE;
1207
1208 case 4:
1209 return ElementType::QUAD;
1210
1211 default:
1212 return ElementType::UNDEFINED;
1213
1214 }
1215}
1216
1217}
The Cell class defines the cells.
Definition cell.hpp:42
Interface to DGF I/O function.
Definition DGF.hpp:78
void save(int &, int &, std::vector< std::vector< double > > &, std::vector< std::vector< int > > &)
Definition DGF.cpp:676
void load(int &, int &, std::vector< std::vector< double > > &, std::vector< std::vector< int > > &)
Definition DGF.cpp:516
long getId() const
Definition element.cpp:510
static ConstProxyVector< long > getVertexIds(ElementType type, const long *connectivity)
Definition element.cpp:1193
The LineUnstructured class defines an unstructured line tasselation.
VertexIterator vertexEnd()
CellIterator cellBegin()
void dumpInterfaces(std::ostream &stream) const
CellConstIterator internalCellConstEnd() const
std::vector< long > getInternalCellsByPID(int pid)
void dumpVertices(std::ostream &stream) const
void dumpCells(std::ostream &stream) const
CellConstIterator internalCellConstBegin() const
VertexIterator vertexBegin()
virtual long getVertexCount() const
void restoreCells(std::istream &stream)
VertexIterator addVertex(const Vertex &source, long id=Vertex::NULL_ID)
Cell & getCell(long id)
CellIterator addCell(const Cell &source, long id=Element::NULL_ID)
CellIterator cellEnd()
void restoreVertices(std::istream &stream)
const MPI_Comm & getCommunicator() const
void restore(std::istream &stream, bool reregister=false)
Vertex & getVertex(long id)
std::set< int > getInternalCellPIDs()
void restoreInterfaces(std::istream &stream)
virtual long getCellCount() const
long getInternalCellCount() const
bool reserveCells(size_t nCells)
bool reserveVertices(size_t nVertices)
The PatchManager oversee the handling of the patches.
id_t getId(const id_t &fallback=-1) const noexcept
Iterator for the class PiercedStorage.
Metafunction for generating a list of elements that can be either stored in an external vectror or,...
std::size_t size() const
static BITPIT_PUBLIC_API const ReferenceElementInfo & getInfo(ElementType type)
Format getFormat() const
Definition STL.cpp:111
Class for reading ASCII and binary STL files.
Definition STL.hpp:83
int readFacet(std::array< double, 3 > *V0, std::array< double, 3 > *V1, std::array< double, 3 > *V2, std::array< double, 3 > *N)
Definition STL.cpp:942
int readBegin()
Definition STL.cpp:714
int readFooter()
Definition STL.cpp:896
int readHeader(std::string *name, std::size_t *nT)
Definition STL.cpp:845
Class for writing ASCII and binary STL files.
Definition STL.hpp:156
int writeFacet(const std::array< double, 3 > &V0, const std::array< double, 3 > &V1, const std::array< double, 3 > &V2, const std::array< double, 3 > &N)
Definition STL.cpp:1542
int writeFooter(const std::string &name)
Definition STL.cpp:1515
int writeHeader(const std::string &name, std::size_t nT)
Definition STL.cpp:1491
int writeBegin(WriteMode writeMode, bool partialWrite=false)
Definition STL.cpp:1362
The SurfUnstructured class defines an unstructured surface triangulation.
void _dump(std::ostream &stream) const override
int importDGF(const std::string &filename, int PIDOffset=0, bool PIDSquash=false)
SurfUnstructured(MPI_Comm communicator, std::size_t haloSize=1)
void extractEdgeNetwork(LineUnstructured &net)
int exportSTL(const std::string &filename, bool isBinary)
long locatePoint(const std::array< double, 3 > &point) const override
std::unique_ptr< PatchKernel > clone() const override
int _getDumpVersion() const override
int importSTL(const std::string &filename, int PIDOffset=0, bool PIDSquash=false)
void _restore(std::istream &stream) override
int exportSTLSingle(const std::string &name, bool isBinary)
static ElementType getDGFFacetType(int nFacetVertices)
int exportSTLMulti(const std::string &name, std::unordered_map< int, std::string > *PIDNames=nullptr)
int exportDGF(const std::string &filename)
The SurfaceKernel class provides an interface for defining surface patches.
virtual std::array< double, 3 > evalFacetNormal(long, const std::array< double, 3 > &orientation={{0., 0., 1.}}) const
std::array< double, 3 > & getCoords()
Definition vertex.cpp:246
#define BITPIT_UNUSED(variable)
Definition compiler.hpp:63
--- layout: doxygen_footer ---