Loading...
Searching...
No Matches
pod.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 <cassert>
26#include <sstream>
27#include <sys/types.h>
28#include <sys/stat.h>
29#include <typeinfo>
30#include <unordered_map>
31#include <unordered_set>
32
33#if BITPIT_ENABLE_MPI
34# include <mpi.h>
35#endif
36
37#include "bitpit_private_lapacke.hpp"
38#include "bitpit_voloctree.hpp"
39
40#include "pod.hpp"
41#include "pod_voloctree.hpp"
42
43namespace bitpit {
44
63# if BITPIT_ENABLE_MPI
67POD::POD(MPI_Comm comm)
68# else
70# endif
71: m_filter(1), m_sensorMask(1)
72{
73
74#if BITPIT_ENABLE_MPI
75 m_communicator = MPI_COMM_NULL;
76#endif
77
78 m_podkernel = nullptr;
79 m_meshType = MeshType::UNDEFINED;
80 m_staticMesh = true; //default static mesh TODO change it
81 m_useMean = true; //default use mean fields
82 m_toUpdate = false; //default, switched to true during set<...>
83 m_nSnapshots = 0;
84 m_nModes = std::numeric_limits<std::size_t>::max();
85 m_nFields = 0;
86 m_nScalarFields = 0;
87 m_nVectorFields = 0;
88 m_nReconstructionSnapshots = 0;
89 m_sizeInternal = 0;
90 m_errorThreshold = 0;
91 setEnergyLevel(100.);
92
93# if BITPIT_ENABLE_MPI
94 initializeCommunicator(comm);
95 MPI_Comm_size(m_communicator, &m_nProcs);
96 MPI_Comm_rank(m_communicator, &m_rank);
97#else
98 m_rank = 0;
99 m_nProcs = 1;
100#endif
101
102 m_memoryMode = MemoryMode::MEMORY_NORMAL;
103 m_runMode = RunMode::COMPUTE;
104 m_writeMode = WriteMode::DUMP;
105 m_reconstructionMode = ReconstructionMode::MINIMIZATION;
106 m_errorMode = ErrorMode::NONE;
107 m_expert = false;
108
109 m_directory = ".";
110 m_name = "pod";
111
112}
113
118{
119 clear();
120}
121
126{
127
128 m_meshType = MeshType::UNDEFINED;
129 m_staticMesh = true;
130 m_useMean = true;
131
132 m_correlationMatrices.clear();
133 m_modes.clear();
134 m_minimizationMatrices.clear();
135
136 m_database.clear();
137 m_reconstructionDatabase.clear();
138 m_leave1outOffDatabase.clear();
139 m_toUpdate = false;
140 m_nSnapshots = 0;
141 m_nScalarFields = 0;
142 m_nVectorFields = 0;
143 m_nModes = 0;
144 m_nReconstructionSnapshots = 0;
145
146 if (m_podkernel) {
147 m_podkernel->clearMapper();
148 }
149
150# if BITPIT_ENABLE_MPI
151 freeCommunicator();
152# endif
153}
154
160void POD::setName(const std::string &name)
161{
162 m_name = name;
163}
164
170const std::string & POD::getName()
171{
172 return m_name;
173}
174
180void POD::setDirectory(const std::string &directory)
181{
182 struct stat info;
183 if (stat(directory.c_str(), &info) != 0) {
184 throw std::runtime_error("The directory \"" + directory + "\" does not exists!");
185 } else if (!(info.st_mode & S_IFDIR)) {
186 throw std::runtime_error("The directory \"" + directory + "\" is not valid: a file with the same name was found!");
187 }
188
189 m_directory = directory + "/";
190}
191
197const std::string & POD::getDirectory()
198{
199 return m_directory;
200}
201
208void POD::addSnapshot(const std::string &directory, const std::string &name)
209{
210 pod::SnapshotFile file(directory, name);
211 addSnapshot(file);
212}
213
220{
221 m_database.push_back(file);
222 m_nSnapshots++;
223}
224
230void POD::setSnapshots(const std::vector<pod::SnapshotFile> &database)
231{
232 m_database = database;
233 m_nSnapshots = database.size();
234 m_toUpdate = true;
235}
236
243void POD::removeLeave1outSnapshot(const std::string &directory, const std::string &name)
244{
245 pod::SnapshotFile file(directory, name);
247}
248
255{
256 m_leave1outOffDatabase.push_back(file);
257}
258
263{
264 std::size_t nsoff=m_leave1outOffDatabase.size();
265 for (std::size_t i=0; i<m_nSnapshots; ++i){
266 std::string snapi=m_database[i].directory+"/"+m_database[i].name;
267 for (std::size_t j=0; j<nsoff; ++j){
268 std::string snapj=m_leave1outOffDatabase[j].directory+"/"+m_leave1outOffDatabase[j].name;
269 if (m_database[i].directory == m_leave1outOffDatabase[j].directory && m_database[i].name == m_leave1outOffDatabase[j].name)
270 m_listActiveIDsLeave1out.push_back(i);
271
272 }
273 }
274}
275
282void POD::addReconstructionSnapshot(const std::string &directory, const std::string &name)
283{
284 pod::SnapshotFile file(directory, name);
286}
287
294{
295 m_reconstructionDatabase.push_back(file);
296 m_nReconstructionSnapshots++;
297}
298
304void POD::setModeCount(std::size_t nmodes)
305{
306 m_nModes = nmodes;
307 m_toUpdate = true;
308}
309
315std::size_t POD::getModeCount()
316{
317 return m_nModes;
318}
319
326void POD::setEnergyLevel(double energy)
327{
328 m_energyLevel = energy - ENERGY_CHECK_TOLERANCE;
329}
330
337{
338 return m_energyLevel + ENERGY_CHECK_TOLERANCE;
339}
340
346void POD::setErrorThreshold(double threshold)
347{
348 m_errorThreshold = threshold;
349}
350
357{
358 return m_errorThreshold;
359}
360
367void POD::setTargetErrorFields(std::vector<std::string> &namesf, std::vector<std::array<std::string,3>> &namevf)
368{
369 std::map<std::string, std::size_t> fields;
370 std::size_t nsf= namesf.size();
371 std::size_t nvf= namevf.size();
372
373 for (std::size_t ifield=0; ifield<nsf; ++ifield)
374 fields[namesf[ifield]] = ifield;
375
376 for (std::size_t ifield=0; ifield<nvf; ++ifield){
377 for (std::size_t j=0; j<3; ++j)
378 fields[namevf[ifield][j]] = ifield*3+nsf+j;
379 }
380
381 m_nameTargetErrorFields = fields;
382}
383
391{
392 if (m_meshType != MeshType::UNDEFINED)
393 throw std::runtime_error ("POD mesh type already set. Change not allowed.");
394
395 m_meshType = type;
396
397 switch (type)
398 {
400#if BITPIT_ENABLE_MPI
401 m_podkernel = std::unique_ptr<PODKernel>(new PODVolOctree(m_communicator));
402#else
403 m_podkernel = std::unique_ptr<PODKernel>(new PODVolOctree());
404#endif
405 break;
406
407 default:
408 throw std::runtime_error ("POD mesh type not allowed.");
409 break;
410 }
411}
412
419void POD::setMesh(std::unique_ptr<VolumeKernel> &&mesh)
420{
421 if (m_meshType == MeshType::UNDEFINED)
422 throw std::runtime_error ("POD mesh type not set.");
423
424 const VolOctree* _octreecast_mesh = dynamic_cast<const VolOctree*>(mesh.get());
425 if (_octreecast_mesh){
426 if (m_meshType != MeshType::VOLOCTREE)
427 throw std::runtime_error ("POD mesh type not set to VolOctree.");
428 m_podkernel->setMesh(std::move(mesh));
429 }
430 else{
431 throw std::runtime_error ("POD mesh type not allowed.");
432 }
433}
434
443void POD::setMesh(const std::string &directory, const std::string &name)
444{
445 pod::SnapshotFile file(directory, name);
446 setMesh(file);
447}
448
457{
458 if (m_meshType == MeshType::UNDEFINED)
459 throw std::runtime_error ("POD mesh type not set.");
460
461 std::unique_ptr<VolumeKernel> mesh = m_podkernel->readMesh(file);
462 setMesh(std::move(mesh));
463}
464
471{
472 return m_meshType;
473}
474
483void POD::setStaticMesh(bool flag)
484{
485 m_staticMesh = flag;
486}
487
493void POD::setUseMean(bool flag)
494{
495 m_useMean = flag;
496}
497
506{
507 if (m_memoryMode == mode) {
508 return;
509 }
510
511 switch (mode) {
512
514
515 m_memoryMode = MemoryMode::MEMORY_NORMAL;
516 break;
517
519
520 m_memoryMode = MemoryMode::MEMORY_LIGHT;
521 m_modes.clear();
522 break;
523
524 }
525}
526
531{
532 return m_memoryMode;
533}
534
543{
544 if (m_runMode == mode) {
545 return;
546 }
547
548 switch (mode) {
549
550 case RunMode::COMPUTE:
551
552 m_runMode = RunMode::COMPUTE;
553 break;
554
555 case RunMode::RESTORE:
556
557 m_runMode = RunMode::RESTORE;
558 break;
559
560 }
561}
562
567{
568 return m_runMode;
569}
570
577{
578 if (m_writeMode == mode)
579 return;
580
581 m_writeMode = mode;
582}
583
588{
589 return m_writeMode;
590}
591
599{
600 if (m_reconstructionMode == mode)
601 return;
602
603 switch (mode) {
604
606
607 m_reconstructionMode = ReconstructionMode::MINIMIZATION;
608 break;
609
611
612 m_reconstructionMode = ReconstructionMode::PROJECTION;
613 break;
614
615 }
616}
617
624{
625 return m_reconstructionMode;
626}
627
636{
637 if (m_errorMode == mode)
638 return;
639
640 m_errorMode = mode;
641}
642
649{
650 return m_errorMode;
651}
652
660void POD::setExpert(bool mode)
661{
662 m_expert = mode;
663}
664
673{
674 m_sensorMask.unsetKernel();
675 m_sensorMask.setStaticKernel(&(m_podkernel->getMesh()->getCells()));
676
677 if (m_staticMesh || mesh == m_podkernel->getMesh()){
678
679 for (const Cell &cell : m_podkernel->getMesh()->getCells()) {
680 long id = cell.getId();
681 m_sensorMask[id] = mask[id];
682 }
683
684 }
685 else{
686
687 if (mesh == nullptr)
688 throw std::runtime_error ("POD: null mesh pointer passed to setSensorMask");
689
690 //If mapping dirty or not computed, compute mapping of input mesh on pod mesh
691 if (m_podkernel->isMapperDirty())
692 _computeMapper(mesh);
693
694 std::unordered_set<long> trueCells;
695 for (const Cell & cell : mesh->getCells()){
696 long id = cell.getId();
697 if (mask[id])
698 trueCells.insert(id);
699 }
700
701 //Map true cells
702 std::unordered_set<long> mappedCells = m_podkernel->mapCellsToPOD(&trueCells);
703
704 m_podkernel->mapBoolFieldToPOD(mask, mesh, &mappedCells, m_sensorMask);
705
706 }
707
708 fillListActiveIDs(m_sensorMask);
709 m_toUpdate = true;
710
711}
712
719{
720 return m_nSnapshots;
721}
722
728std::vector<std::string> POD::getScalarNames()
729{
730 return m_nameScalarFields;
731}
732
738std::vector<std::array<std::string,3>> POD::getVectorNames()
739{
740 return m_nameVectorFields;
741}
742
749std::vector<std::string> POD::getFieldsNames()
750{
751 std::vector<std::string> names;
752 for (const std::string &ss : m_nameScalarFields)
753 names.push_back(ss);
754 for (const std::array<std::string,3> &ssa : m_nameVectorFields){
755 for (const std::string &ss : ssa)
756 names.push_back(ss);
757 }
758
759 return names;
760}
761
768{
769 if (m_podkernel == nullptr)
770 throw std::runtime_error ("POD mesh not built");
771
772 return m_podkernel->getMesh();
773}
774
781{
782 return m_mean;
783}
784
790const std::vector<pod::PODMode> & POD::getModes()
791{
792 return m_modes;
793}
794
800std::vector<std::vector<double> > POD::getReconstructionCoeffs()
801{
802 return m_reconstructionCoeffs;
803}
804
808const std::unordered_set<long> & POD::getListActiveIDs()
809{
810 return m_listActiveIDs;
811}
812
817{
818 return m_sizeInternal;
819}
820
824std::unique_ptr<PODKernel> & POD::getKernel()
825{
826 return m_podkernel;
827}
828
837{
838 // Decomposition
839 if (m_runMode == RunMode::COMPUTE) {
840 log::cout() << "pod : evaluate decomposition ... " << std::endl;
842 } else if (m_runMode == RunMode::RESTORE) {
843 log::cout() << "pod : restore decomposition ... " << std::endl;
845 }
846
847 // Reconstruction
848 log::cout() << "pod : evaluate reconstruction ... " << std::endl;
850}
851
856{
857 // Dump decomposition
859}
860
865{
866 // Restore decomposition
868}
869
874{
875 // Evaluate mean field and mesh
876 log::cout() << "pod : computing mean field and pod mesh... " << std::endl;
877 evalMeanMesh();
878
879 // Initialize ID list
880 fillListActiveIDs(m_filter);
881
882 // Evaluate correlation matrices
883 log::cout() << "pod : computing correlation matrix... " << std::endl;
885
886 // Compute eigenvalues and eigenvectors
887 log::cout() << "pod : computing eigenvectors... " << std::endl;
888 evalEigen();
889
890 // Compute POD modes
891 log::cout() << "pod : computing pod modes... " << std::endl;
892 evalModes();
893
894 // Dump pod
895 if (m_writeMode != WriteMode::NONE) {
896 log::cout() << "pod : dumping... " << std::endl;
897 dump();
898 }
899}
900
905{
906 int dumpBlock = (m_nProcs > 1) ? m_rank : -1;
907
908 log::cout() << "Dumping POD ... " << std::endl;
909 // Dump the POD info (no reconstruction info)
910 std::string header = "pod";
911 OBinaryArchive binaryWriter(m_directory + m_name, ARCHIVE_VERSION, header, dumpBlock);
912 std::ostream &dataStream = binaryWriter.getStream();
913 utils::binary::write(dataStream, m_meshType);
914 utils::binary::write(dataStream, m_nModes);
915 utils::binary::write(dataStream, m_nSnapshots);
916 for (std::size_t i = 0; i < m_nSnapshots; ++i) {
917 utils::binary::write(dataStream, m_database[i].directory);
918 utils::binary::write(dataStream, m_database[i].name);
919 }
920 utils::binary::write(dataStream,m_staticMesh);
921 utils::binary::write(dataStream,m_memoryMode);
922 binaryWriter.close();
923
924 // Dump the modes, mean and meshPOD
925 if (m_memoryMode == MemoryMode::MEMORY_NORMAL) {
926 for (std::size_t ir = 0; ir < m_nModes; ++ir)
927 dumpMode(ir);
928
929 }
930
931 // Dumping mean as snapshot
932 if (m_useMean){
933 dumpMode(m_nModes);
934 }
935
936 // Dumping mask
937 {
938 std::string header = "podmask";
939 OBinaryArchive binaryWriter(m_directory + m_name + ".mask.data", ARCHIVE_VERSION, header, dumpBlock);
940 std::ostream &dataStream = binaryWriter.getStream();
941 m_sensorMask.dump(dataStream);
942 binaryWriter.close();
943 }
944
945 // Dumping mesh
946 {
947 std::string header = "podmesh";
948 OBinaryArchive binaryWriter(m_directory + m_name + ".mesh", ARCHIVE_VERSION, header, dumpBlock);
949 m_podkernel->getMesh()->dump(binaryWriter.getStream());
950 binaryWriter.close();
951 }
952
953 // Write debug info
954 if (m_writeMode == WriteMode::DEBUG) {
955 std::vector<std::string > datastring;
956 m_podkernel->getMesh()->getVTK().setDirectory(m_directory);
957 m_podkernel->getMesh()->getVTK().setName(m_name);
958
959 std::size_t nf=m_nModes;
960 if (m_useMean)
961 nf=nf+1;
962 std::vector<std::vector<std::vector<double>>> fields(nf, std::vector<std::vector<double>> (m_nScalarFields, std::vector<double>(m_podkernel->getMesh()->getInternalCellCount(), 0.0)));
963 std::vector<std::vector<std::vector<std::array<double,3>>>> fieldv(nf, std::vector<std::vector<std::array<double,3>>>(m_nVectorFields, std::vector<std::array<double,3>>(m_podkernel->getMesh()->getInternalCellCount(), {{0.0, 0.0, 0.0}})));
964
965 if (m_useMean){
966 for (std::size_t isf = 0; isf < m_nScalarFields; ++isf) {
967 int i = 0;
968 for (const Cell &cell : m_podkernel->getMesh()->getCells()) {
969 if (cell.isInterior()) {
970 long id = cell.getId();
971 fields[0][isf][i] = m_mean.scalar->at(id, isf);
972 ++i;
973 }
974 }
975 m_podkernel->getMesh()->getVTK().addData("scalarField" + std::to_string(isf) + "_mean", VTKFieldType::SCALAR, VTKLocation::CELL, fields[0][isf]);
976 datastring.push_back("scalarField" + std::to_string(isf) + "_mean");
977 }
978 for (std::size_t ivf = 0; ivf < m_nVectorFields; ++ivf) {
979 int i = 0;
980 for (const Cell &cell : m_podkernel->getMesh()->getCells()) {
981 if (cell.isInterior()) {
982 long id = cell.getId();
983 fieldv[0][ivf][i] = m_mean.vector->at(id, ivf);
984 ++i;
985 }
986 }
987 m_podkernel->getMesh()->getVTK().addData("vectorField"+std::to_string(ivf)+"_mean", VTKFieldType::VECTOR, VTKLocation::CELL, fieldv[0][ivf]);
988 datastring.push_back("vectorField"+std::to_string(ivf)+"_mean");
989 }
990 }
991 for (std::size_t ir = 0; ir < m_nModes; ++ir) {
992 if (m_memoryMode == MemoryMode::MEMORY_LIGHT)
993 readMode(ir);
994
995 std::size_t nir = ir;
996 if (m_useMean)
997 nir=ir+1;
998
999 for (std::size_t isf = 0; isf < m_nScalarFields; ++isf) {
1000 int i=0;
1001 for (const Cell &cell : m_podkernel->getMesh()->getCells()) {
1002 if (cell.isInterior()) {
1003 long id = cell.getId();
1004 fields[nir][isf][i] = m_modes[ir].scalar->at(id, isf);
1005 ++i;
1006 }
1007 }
1008 m_podkernel->getMesh()->getVTK().addData("scalarField"+std::to_string(isf)+"_podMode"+std::to_string(ir), VTKFieldType::SCALAR, VTKLocation::CELL, fields[nir][isf]);
1009 datastring.push_back("scalarField"+std::to_string(isf)+"_podMode"+std::to_string(ir));
1010 }
1011
1012 for (std::size_t ivf = 0; ivf < m_nVectorFields; ++ivf) {
1013 int i=0;
1014 for (const Cell &cell : m_podkernel->getMesh()->getCells()) {
1015 if (cell.isInterior()) {
1016 long id = cell.getId();
1017 fieldv[nir][ivf][i] = m_modes[ir].vector->at(id, ivf);
1018 ++i;
1019 }
1020 }
1021 m_podkernel->getMesh()->getVTK().addData("vectorField"+std::to_string(ivf)+"_podMode"+std::to_string(ir), VTKFieldType::VECTOR, VTKLocation::CELL, fieldv[nir][ivf]);
1022 datastring.push_back("vectorField"+std::to_string(ivf)+"_podMode"+std::to_string(ir));
1023 }
1024
1025 if (m_memoryMode == MemoryMode::MEMORY_LIGHT)
1026 m_modes[ir].clear();
1027 }
1028
1029 std::vector<uint8_t> mask(m_podkernel->getMesh()->getInternalCellCount(), 0);
1030 int i=0;
1031 for (const Cell &cell : m_podkernel->getMesh()->getCells()) {
1032 if (cell.isInterior()) {
1033 long id = cell.getId();
1034 mask[i] = m_filter[id];
1035 ++i;
1036 }
1037 }
1038
1039 m_podkernel->getMesh()->getVTK().addData("filter", VTKFieldType::SCALAR, VTKLocation::CELL, mask);
1040 datastring.push_back("filter");
1041 m_podkernel->getMesh()->write();
1042
1043 for (std::size_t is = 0; is < datastring.size(); ++is)
1044 m_podkernel->getMesh()->getVTK().removeData(datastring[is]);
1045 }
1046}
1047
1051void POD::restoreDecomposition()
1052{
1053 int dumpBlock = (m_nProcs > 1) ? m_rank : -1;
1054
1055 // Restore the POD info (no reconstruction info)
1056 log::cout() << "Restore POD ... " << std::endl;
1057
1058 std::string header = "pod";
1059 IBinaryArchive binaryReader(m_directory + m_name, dumpBlock);
1060 std::istream &dataStream = binaryReader.getStream();
1061 MeshType m_meshType_;
1062 utils::binary::read(dataStream, m_meshType_);
1063 setMeshType(m_meshType_);
1064 std::size_t nr_;
1065 utils::binary::read(dataStream, nr_);
1066 m_nModes = std::min(m_nModes, nr_);
1067 m_modes.resize(m_nModes);
1068 utils::binary::read(dataStream, m_nSnapshots);
1069 m_database.resize(m_nSnapshots);
1070 for (std::size_t i = 0; i < m_nSnapshots; ++i) {
1071 utils::binary::read(dataStream, m_database[i].directory);
1072 utils::binary::read(dataStream, m_database[i].name);
1073 }
1074 utils::binary::read(dataStream,m_staticMesh);
1075 utils::binary::read(dataStream,m_memoryMode);
1076 binaryReader.close();
1077
1078 // Restore mesh
1079 {
1080 pod::SnapshotFile podfile;
1081 podfile.directory = m_directory;
1082 podfile.name = m_name;
1083 m_podkernel->restoreMesh(podfile);
1084 }
1085
1086 // Restore the modes, mean and mesh
1087 {
1088 m_filter.unsetKernel();
1089 m_filter.setStaticKernel(&m_podkernel->getMesh()->getCells());
1090 m_sensorMask.unsetKernel();
1091 m_sensorMask.setStaticKernel(&m_podkernel->getMesh()->getCells());
1092
1093 if (m_memoryMode == MemoryMode::MEMORY_NORMAL) {
1094 for (std::size_t ir = 0; ir < m_nModes; ++ir) {
1095 readMode(ir);
1096 }
1097 }
1098 }
1099
1100 // Restore mean
1101 if (m_useMean){
1102 readMode(m_nModes);
1103 }
1104
1105 // Restore mask
1106 {
1107 IBinaryArchive binaryReader(m_directory + m_name + ".mask.data", dumpBlock);
1108 std::istream &dataStream = binaryReader.getStream();
1109 m_sensorMask.restore(dataStream);
1110 binaryReader.close();
1111 }
1112
1113 // Lestore ID list
1114 fillListActiveIDs(m_sensorMask);
1115 m_toUpdate = true;
1116}
1117
1121void POD::leave1out()
1122{
1123 setErrorMode(ErrorMode::COMBINED);
1124 setReconstructionMode(ReconstructionMode::PROJECTION);
1125 unsetLeave1outSnapshots();
1126
1127 // Evaluate mean field and mesh
1128 log::cout() << "pod : computing pod mesh... " << std::endl;
1129 evalMeanMesh();
1130
1131 // Initialize ID list
1132 fillListActiveIDs(m_filter);
1133
1134 // Evaluate correlation matrices
1135 log::cout() << "pod : computing correlation matrix... " << std::endl;
1136 evalCorrelation();
1137
1138 // Initialize error field
1139 initErrorMaps();
1140
1141 // Initialize help variables
1142 std::vector<std::vector<double>> h_correlationMatrices=m_correlationMatrices;
1143 std::vector<pod::SnapshotFile> h_database=m_database;
1144 std::size_t h_nSnapshots=m_nSnapshots;
1145 std::size_t nl1o=m_listActiveIDsLeave1out.size();
1146
1147 m_nSnapshots=h_nSnapshots-1;
1148
1149 for (std::size_t i=0; i<nl1o; ++i){
1150 std::size_t id = m_listActiveIDsLeave1out[i];
1151 log::cout() << ">> leave-1-out : removing snapshot " << m_database[id].directory+"/"+m_database[id].name<< std::endl;
1152
1153 m_reconstructionDatabase.clear();
1154 m_nReconstructionSnapshots = 0;
1155 addReconstructionSnapshot(m_database[id]);
1156 m_database.erase(m_database.begin()+id);
1157
1158 for (std::size_t ifield = 0; ifield<m_nFields; ++ifield){
1159 // get rid of id row
1160 m_correlationMatrices[ifield].erase(m_correlationMatrices[ifield].begin()+id*h_nSnapshots, m_correlationMatrices[ifield].begin()+id*h_nSnapshots+h_nSnapshots);
1161
1162 // get rid of id column
1163 std::size_t it=id;
1164 for (std::size_t j=0; j<m_nSnapshots; ++j){
1165 m_correlationMatrices[ifield].erase(m_correlationMatrices[ifield].begin()+it);
1166 it= it-1+h_nSnapshots;
1167 }
1168 }
1169
1170 // Compute eigenvalues and eigenvectors
1171 log::cout() << "pod : computing eigenvectors... " << std::endl;
1172 evalEigen();
1173
1174 // Compute POD modes
1175 log::cout() << "pod : computing pod modes... " << std::endl;
1176 evalModes();
1177
1178 // Evaluate reconstruction & compute error fields
1179 evalReconstruction();
1180
1181 // Reassignment for future usage
1182 m_correlationMatrices=h_correlationMatrices;
1183 m_database=h_database;
1184 m_toUpdate=true;
1185 }
1186
1187 //dump error
1188 if (m_writeMode != WriteMode::NONE){
1189 std::string ename = m_name + ".error";
1190 dumpField(ename, m_errorMap);
1191 }
1192 m_nSnapshots=h_nSnapshots;
1193}
1194
1200void POD::evalMeanMesh()
1201{
1202 if (m_database.empty())
1203 throw std::runtime_error ("POD database empty");
1204
1205 // If the mesh is static do nothing on mesh and compute mean fields directly
1206 _evalMeanMesh();
1207
1208 // Set mesh POD to write only internal cells
1209#if BITPIT_ENABLE_MPI
1210 m_podkernel->getMesh()->setVTKWriteTarget(PatchKernel::WriteTarget::WRITE_TARGET_CELLS_INTERNAL);
1211#else
1212 m_podkernel->getMesh()->setVTKWriteTarget(PatchKernel::WriteTarget::WRITE_TARGET_CELLS_ALL);
1213#endif
1214}
1215
1219void POD::_evalMeanMesh()
1220{
1221
1222 if (m_podkernel->getMesh() == nullptr){
1223
1224 //Read first mesh and use as meshPOD
1225 std::unique_ptr<VolumeKernel> readMesh = m_podkernel->readMesh(m_database[0]);
1226 m_podkernel->setMesh(std::move(readMesh));
1227
1228 //Dynamic mesh case
1229 if (!m_staticMesh){
1230 // Compute meshPOD (starting from inital mesh) and fill filter
1231 for (std::size_t i = 1; i < m_nSnapshots; ++i) {
1232 log::cout() << "pod : evaluation POD mesh - use snapshot " << i+1 << "/" << m_nSnapshots << std::endl;
1233 std::unique_ptr<VolumeKernel> readMesh = m_podkernel->readMesh(m_database[i]);
1234 m_podkernel->adaptMeshToMesh(m_podkernel->getMesh(), readMesh.get());
1235 m_podkernel->clearMapper();
1236 }
1237 }
1238 }
1239
1240 {
1241 // Read first snapshot to set n scalar and vector fields
1242 pod::PODField readf;
1243 readSnapshot(m_database[0], readf);
1244 }
1245
1246 //Compute cells volume
1247 m_podkernel->evalCellsVolume();
1248
1249 m_filter.unsetKernel();
1250 m_filter.setStaticKernel(&(m_podkernel->getMesh()->getCells()));
1251 m_filter.fill(true);
1252
1253
1254 if (m_useMean){
1255 m_mean.scalar = std::unique_ptr<pod::ScalarStorage>(new pod::ScalarStorage(m_nScalarFields, &m_podkernel->getMesh()->getCells()));
1256 m_mean.vector = std::unique_ptr<pod::VectorStorage>(new pod::VectorStorage(m_nVectorFields, &m_podkernel->getMesh()->getCells()));
1257 m_mean.scalar->fill(0.0);
1258 m_mean.vector->fill(std::array<double, 3>{{0.0, 0.0, 0.0}});
1259
1260 // Compute mean (starting from first snapshot) & filter+mask
1261 for (std::size_t i = 0; i < m_nSnapshots; ++i) {
1262 log::cout() << "pod : evaluation mean - use snapshot " << i+1 << "/" << m_nSnapshots << std::endl;
1263 pod::PODField readf;
1264 readSnapshot(m_database[i], readf);
1265 if (!m_staticMesh){
1266 //Compute mapping of read mesh on pod mesh
1267 _computeMapper(readf.mesh);
1268 readf = pod::PODField(m_podkernel->mapPODFieldToPOD(readf, nullptr));
1269 m_podkernel->clearMapper();
1270 }
1271
1272 for (const Cell &cell : m_podkernel->getMesh()->getCells()) {
1273 m_filter[cell.getId()] = (m_filter[cell.getId()]) && (readf.mask->at(cell.getId())); //N.B. mask == filter
1274 if (m_filter[cell.getId()]){
1275 for (std::size_t j = 0; j < m_nScalarFields; ++j)
1276 m_mean.scalar->at(cell.getId(),j) += readf.scalar->at(cell.getId(),j) / double(m_nSnapshots);
1277 for (std::size_t j = 0; j < m_nVectorFields; ++j)
1278 m_mean.vector->at(cell.getId(),j) += readf.vector->at(cell.getId(),j) / double(m_nSnapshots);
1279 }
1280 else{
1281 for (std::size_t j = 0; j < m_nScalarFields; ++j)
1282 m_mean.scalar->at(cell.getId(),j) = 0.0;
1283 for (std::size_t j = 0; j < m_nVectorFields; ++j)
1284 m_mean.vector->at(cell.getId(),j) = {{0.0, 0.0, 0.0}};
1285 }
1286 }
1287 }
1288 }
1289 else {
1290 // filter+mask
1291 for (std::size_t i = 0; i < m_nSnapshots; ++i) {
1292 pod::PODField readf;
1293 readSnapshot(m_database[i], readf);
1294 if (!m_staticMesh)
1295 {
1296 _computeMapper(readf.mesh);
1297 readf = pod::PODField(m_podkernel->mapPODFieldToPOD(readf, nullptr));
1298 m_podkernel->clearMapper();
1299 }
1300
1301 for (const Cell &cell : m_podkernel->getMesh()->getCells())
1302 m_filter[cell.getId()] = (m_filter[cell.getId()]) && (readf.mask->at(cell.getId())); //N.B. mask == filter
1303
1304 }
1305 }
1306
1307 setSensorMask(m_filter, m_podkernel->getMesh());
1308}
1309
1316void POD::fillListActiveIDs(const PiercedStorage<bool> &mask)
1317{
1318
1319 //NOTE!! NO GHOSTS IN ACTIVEIDS (*)
1320 m_listActiveIDs.clear();
1321 std::unordered_set<long> listGhost;
1322 for (const Cell &cell : m_podkernel->getMesh()->getCells()) {
1323 long id = cell.getId();
1324 //TODO reset to commented when solid/fluid field on ghosts is dumped
1325 //if (mask[id]) {
1326 if (mask[id] && cell.isInterior()) {
1327 if (cell.isInterior()) {
1328 m_listActiveIDs.insert(id);
1329 }else{
1330 listGhost.insert(id);
1331 }
1332 }
1333 }
1334
1335 m_sizeInternal = m_listActiveIDs.size();
1336
1337 // (*)
1338 //m_listActiveIDs.insert(listGhost.begin(), listGhost.end());
1339
1340}
1341
1345void POD::evalCorrelation()
1346{
1347 initCorrelation();
1348 for (std::size_t i = 0; i < m_nSnapshots; ++i){
1349 pod::PODField snapi;
1350 readSnapshot(m_database[i], snapi);
1351 if (!m_staticMesh){
1352 _computeMapper(snapi.mesh);
1353 snapi = pod::PODField(m_podkernel->mapPODFieldToPOD(snapi, nullptr));
1354 m_podkernel->clearMapper();
1355 }
1356
1357 if (m_useMean)
1358 diff(&snapi, m_mean);
1359
1360 for (std::size_t j = i; j < m_nSnapshots; ++j){
1361 log::cout() << "pod : evaluation " << i << "," << j << " term of correlation matrix " << std::endl;
1362 pod::PODField snapj;
1363 readSnapshot(m_database[j], snapj);
1364 if (!m_staticMesh){
1365 _computeMapper(snapj.mesh);
1366 snapj = pod::PODField(m_podkernel->mapPODFieldToPOD(snapj, nullptr));
1367 m_podkernel->clearMapper();
1368 }
1369
1370 if (m_useMean)
1371 diff(&snapj, m_mean);
1372
1373 evalCorrelationTerm(i, snapi, j, snapj);
1374
1375 }
1376 }
1377
1378# if BITPIT_ENABLE_MPI
1379 for (std::size_t i = 0; i < m_nFields; i++ )
1380 MPI_Allreduce(MPI_IN_PLACE, m_correlationMatrices[i].data(), m_nSnapshots*m_nSnapshots, MPI_DOUBLE, MPI_SUM, m_communicator);
1381# endif
1382
1383}
1384
1388void POD::initCorrelation()
1389{
1390 m_correlationMatrices.clear();
1391 m_correlationMatrices.resize(m_nFields,std::vector<double>(m_nSnapshots*m_nSnapshots, 0.0));
1392}
1393
1397void POD::initErrorMaps()
1398{
1399 m_errorMap.clear();
1400 m_errorMap.mesh = m_podkernel->getMesh();
1401 m_errorMap.scalar = std::unique_ptr<pod::ScalarStorage>(new pod::ScalarStorage(m_nScalarFields, &m_podkernel->getMesh()->getCells()));
1402 m_errorMap.vector = std::unique_ptr<pod::VectorStorage>(new pod::VectorStorage(m_nVectorFields, &m_podkernel->getMesh()->getCells()));
1403 m_errorMap.scalar->fill(0.0);
1404 m_errorMap.vector->fill(std::array<double, 3>{{0.0, 0.0, 0.0}});
1405 m_errorMap.mask = std::unique_ptr<PiercedStorage<bool>>(new PiercedStorage<bool>(1, &m_podkernel->getMesh()->getCells()));
1406 m_errorMap.mask->fill(0);
1407 for (long id : m_listActiveIDs)
1408 m_errorMap.mask->at(id)=1;
1409
1410}
1411
1415void POD::evalCorrelationTerm(int i, pod::PODField & snapi, int j, pod::PODField & snapj)
1416{
1417
1418 std::unordered_set<long>::iterator it;
1419 for (it = m_listActiveIDs.begin(); it != m_listActiveIDs.end(); ++it){
1420 long id = *it;
1421 std::size_t rawIndex = m_podkernel->getMesh()->getCells().getRawIndex(id);
1422 if (m_nScalarFields){
1423 double* datasi = snapi.scalar->rawData(rawIndex);
1424 double* datasj = snapj.scalar->rawData(rawIndex);
1425 for (std::size_t ifield = 0; ifield < m_nScalarFields; ++ifield){
1426 m_correlationMatrices[ifield][i*m_nSnapshots+j] += (*datasi)*(*datasj)*getRawCellVolume(rawIndex);
1427 datasi++;
1428 datasj++;
1429 }
1430 }
1431 if (m_nVectorFields){
1432 std::array<double,3>* datavi = snapi.vector->rawData(rawIndex);
1433 std::array<double,3>* datavj = snapj.vector->rawData(rawIndex);
1434 for (std::size_t ifield = m_nScalarFields; ifield < m_nFields; ++ifield){
1435 m_correlationMatrices[ifield][i*m_nSnapshots+j] += dotProduct((*datavi),(*datavj))*getRawCellVolume(rawIndex);
1436 datavi++;
1437 datavj++;
1438 }
1439 }
1440
1441 }
1442
1443}
1444
1449void POD::evalReconstruction()
1450{
1451 m_reconstructionCoeffs.clear();
1452 m_reconstructionCoeffs.resize(m_nFields, std::vector<double>(m_nModes,0.0));
1453
1454 for (std::size_t i = 0; i < m_nReconstructionSnapshots; ++i){
1455 pod::PODField snapi, reconi, erri;
1456 readSnapshot(m_reconstructionDatabase[i], snapi);
1457
1458 if (!m_staticMesh){
1459
1460 //Compute mapping of snapshot mesh on pod mesh
1461 _computeMapper(snapi.mesh);
1462
1463 // Map snapshot on pod mesh
1464 snapi = pod::PODField(m_podkernel->mapPODFieldToPOD(snapi, nullptr));
1465 m_podkernel->clearMapper();
1466
1467 }
1468
1469 reconstructFields(snapi, reconi);
1470 std::string rname = m_name + ".recon." + m_reconstructionDatabase[i].name;
1471
1472 if (m_writeMode != WriteMode::NONE && m_errorMode != ErrorMode::COMBINED)
1473 dumpField(rname, reconi);
1474
1475 if (m_errorMode != ErrorMode::COMBINED){
1476 // one coeff file for each reconstruction, each line is related to a field, each term is related to a mode
1477 std::ofstream outr(m_directory + m_name + ".recon.coeff."+ m_reconstructionDatabase[i].name +".dat", std::ofstream::out);
1478 for (std::size_t j = 0; j < m_nFields; ++j)
1479 outr << m_reconstructionCoeffs[j] << std::endl;
1480
1481 outr.close();
1482 }
1483 if (m_errorMode == ErrorMode::SINGLE){
1484 std::vector<double> enorm = fieldsl2norm(m_errorMap);
1485 std::string ename = m_name + ".error."+ m_reconstructionDatabase[i].name;
1486
1487 if (m_writeMode != WriteMode::NONE)
1488 dumpField(ename, m_errorMap);
1489
1490 // one coeff file for each reconstruction, each line is related to a field
1491 std::ofstream oute(m_directory + m_name + ".error.norm."+ m_reconstructionDatabase[i].name +".dat", std::ofstream::out);
1492 for (std::size_t j = 0; j < m_nFields; ++j)
1493 oute << enorm[j] << std::endl;
1494
1495 oute.close();
1496 }
1497 }
1498}
1499
1503void POD::evalErrorBoundingBox()
1504{
1505 setWriteMode(WriteMode::NONE);
1506 pod::SnapshotFile efile("./pod", m_name+".error");
1507 log::cout()<< "Reading error field ..."<< std::endl;
1508 log::cout()<< efile.directory+"/"+efile.name +"..."<< std::endl;
1509 pod::PODField error;
1510 readSnapshot(efile, error);
1511
1512 fillListActiveIDs(*error.mask);
1513
1514 std::vector<std::size_t> scalarIds, vectorIds;
1515 std::map<std::string, std::size_t> targetErrorFields = m_nameTargetErrorFields;
1516
1517 // Find scalar target fields
1518 std::size_t count=0;
1519 for (const std::string &val : m_nameScalarFields) {
1520 std::map<std::string, std::size_t>::iterator found = targetErrorFields.find(val);
1521 if (found != targetErrorFields.end()) {
1522 scalarIds.push_back(count);
1523 targetErrorFields.erase(found);
1524 }
1525 count++;
1526 }
1527
1528 // Find vector target fields
1529 for (const std::array<std::string,3> &valv : m_nameVectorFields) {
1530 std::size_t ic = 0;
1531 std::array<std::string,3> toerase;
1532 for (const std::string &val : valv) {
1533 std::map<std::string, std::size_t>::iterator found = targetErrorFields.find(val);
1534 if (found != targetErrorFields.end()) {
1535 toerase[ic] = val;
1536 ic++;
1537 }
1538
1539 if (ic == 3) {
1540 vectorIds.push_back(count);
1541 for (std::size_t i = 0; i < 3; ++i)
1542 targetErrorFields.erase(toerase[i]);
1543 }
1544 }
1545 count++;
1546 }
1547
1548 if (targetErrorFields.size() != 0) {
1549 std::string verror = " ";
1550 for (const auto &targetErrorField : targetErrorFields)
1551 verror += targetErrorField.first + " ";
1552
1553 throw std::runtime_error ("POD: fields not found in POD base or incomplete vector: " + verror);
1554 }
1555
1556 std::size_t nsf = scalarIds.size();
1557 std::size_t nvf = vectorIds.size();
1558
1559 std::vector<std::array<double, 3>> minBoxes, maxBoxes;
1560 minBoxes.resize(m_nFields, {{0.0, 0.0, 0.0}});
1561 maxBoxes.resize(m_nFields, {{0.0, 0.0, 0.0}});
1562
1563 std::unordered_set<long>::iterator it;
1564 for (it = m_listActiveIDs.begin(); it != m_listActiveIDs.end(); ++it) {
1565 long id = *it;
1566 std::array<double, 3> cellCentroid = error.mesh->evalCellCentroid(id);
1567 std::size_t rawIndex = m_podkernel->getMesh()->getCells().getRawIndex(id);
1568
1569 if (nsf) {
1570 double* datas = error.scalar->rawData(rawIndex);
1571 for (std::size_t i = 0; i < nsf; ++i){
1572 double* datasi = datas+scalarIds[i];
1573 if (*datasi >= m_errorThreshold){
1574 maxBoxes[scalarIds[i]]= max(cellCentroid,maxBoxes[scalarIds[i]]);
1575 minBoxes[scalarIds[i]]= min(cellCentroid,minBoxes[scalarIds[i]]);
1576 }
1577 }
1578 }
1579 if (nvf) {
1580 std::array<double,3>* datav = error.vector->rawData(rawIndex);
1581 for (std::size_t i = 0; i< nvf; ++i) {
1582 std::array<double,3>* datavi = datav+vectorIds[i];
1583 if (std::sqrt( dotProduct((*datavi),(*datavi)) ) >= m_errorThreshold){
1584 maxBoxes[vectorIds[i]]= max(cellCentroid,maxBoxes[vectorIds[i]]);
1585 minBoxes[vectorIds[i]]= min(cellCentroid,minBoxes[vectorIds[i]]);
1586 }
1587 }
1588 }
1589 }
1590
1591# if BITPIT_ENABLE_MPI
1592 MPI_Allreduce(MPI_IN_PLACE, reinterpret_cast<double *>(maxBoxes.data()), m_nFields*3, MPI_DOUBLE, MPI_MAX, m_communicator);
1593 MPI_Allreduce(MPI_IN_PLACE, reinterpret_cast<double *>(minBoxes.data()), m_nFields*3, MPI_DOUBLE, MPI_MIN, m_communicator);
1594# endif
1595
1596 log::cout()<< ">> Fields Bounding boxes " << std::endl;
1597 log::cout()<< "min: "<< minBoxes << std::endl;
1598 log::cout()<< "max: "<< maxBoxes << std::endl;
1599
1600 std::array<double, 3> minBox = {{0.0, 0.0, 0.0}};
1601 std::array<double, 3> maxBox = {{0.0, 0.0, 0.0}};
1602
1603 for (std::size_t i =0; i < m_nFields; ++i){
1604 maxBox=max(maxBoxes[i],maxBox);
1605 minBox=min(minBoxes[i],minBox);
1606 }
1607
1608 log::cout()<< ">> Bounding box " << std::endl;
1609 log::cout()<< "("<< minBox << ") ("<< maxBox << ")"<< std::endl;
1610
1611 bool runSolver;
1612#if BITPIT_ENABLE_MPI
1613 runSolver = (m_rank == 0);
1614#else
1615 runSolver = true;
1616#endif
1617 if (runSolver){
1618 std::ofstream outBB(m_directory + m_name + ".box.dat", std::ofstream::out);
1619 outBB << minBox << std::endl;
1620 outBB << maxBox << std::endl;
1621 outBB.close();
1622 }
1623
1624}
1625
1631void POD::reconstructFields(pod::PODField & field, pod::PODField & reconi)
1632{
1633
1634 //set the mesh of reconstructed field
1635 reconi.mesh = field.mesh;
1636 reconi.mask = std::unique_ptr<PiercedStorage<bool>>(new PiercedStorage<bool>(*field.mask));
1637 evalReconstructionCoeffs(field);
1638 buildFields(m_reconstructionCoeffs, reconi);
1639 if (m_errorMode != ErrorMode::NONE){
1640 if (m_errorMode == ErrorMode::SINGLE)
1641 initErrorMaps();
1642 buildErrorMaps(field,reconi);
1643 }
1644
1645}
1646
1652void POD::reconstructFields(const std::vector<std::vector<double>> &reconstructionCoeffs,
1653 pod::PODField & reconi)
1654{
1655 reconi.setMesh(m_podkernel->getMesh());
1656 buildFields(reconstructionCoeffs, reconi);
1657}
1658
1667void POD::reconstructFields(PiercedStorage<double> &fields, VolumeKernel *mesh,
1668 std::map<std::string, std::size_t> targetFields,
1669 const std::unordered_set<long> * targetCells)
1670{
1671 std::vector<std::size_t> podscalarIds;
1672 std::vector<std::size_t> podvectorIds;
1673
1674 std::vector<std::size_t> scalarIds;
1675 std::vector<std::array<std::size_t, 3>> vectorIds;
1676
1677 // Find scalar target fields
1678 std::size_t count = 0;
1679 for (const std::string &val : m_nameScalarFields) {
1680 std::map<std::string, std::size_t>::iterator found = targetFields.find(val);
1681 if (found != targetFields.end()) {
1682 std::size_t ind = found->second;
1683 podscalarIds.push_back(count);
1684 scalarIds.push_back(ind);
1685 targetFields.erase(found);
1686 count++;
1687 }
1688 }
1689
1690 // Find vector target fields
1691 count = 0;
1692 for (const std::array<std::string,3> &valv : m_nameVectorFields) {
1693 std::size_t ic = 0;
1694 std::array<std::size_t,3> vectorarr;
1695 std::array<std::string,3> toerase;
1696 for (const std::string &val : valv) {
1697 std::map<std::string, std::size_t>::iterator found = targetFields.find(val);
1698 if (found != targetFields.end()) {
1699 std::size_t ind = found->second;
1700 vectorarr[ic] = ind;
1701 toerase[ic] = val;
1702 ic++;
1703 }
1704
1705 if (ic == 3) {
1706 podvectorIds.push_back(count);
1707 vectorIds.push_back(vectorarr);
1708 for (std::size_t i = 0; i < 3; ++i)
1709 targetFields.erase(toerase[i]);
1710 }
1711 }
1712 count++;
1713 }
1714
1715 if (targetFields.size() != 0) {
1716 std::string verror = " ";
1717 for (const auto &targetField : targetFields)
1718 verror += targetField.first + " ";
1719
1720 throw std::runtime_error ("POD: fields not found in POD base or incomplete vector: " + verror);
1721 }
1722
1723
1724 if (m_staticMesh){
1725
1726 evalReconstructionCoeffs(fields, scalarIds, podscalarIds, vectorIds, podvectorIds);
1727
1728 buildFields(m_reconstructionCoeffs, fields, scalarIds, podscalarIds, vectorIds, podvectorIds, targetCells);
1729
1730 }
1731 else{
1732
1733 //If mapping not computed, compute mapping of input mesh on pod mesh
1734 if (m_podkernel->isMapperDirty())
1735 _computeMapper(mesh);
1736
1737 // Map data fields on pod mesh
1738 PiercedStorage<double> mappedFields = m_podkernel->mapFieldsToPOD(fields, mesh, &m_listActiveIDs, scalarIds, vectorIds);
1739
1740 evalReconstructionCoeffs(mappedFields, scalarIds, podscalarIds, vectorIds, podvectorIds);
1741
1742 //Map target cells
1743 std::unordered_set<long> mappedCells;
1744 std::unordered_set<long>* ptr_mappedCells = nullptr;
1745 if (targetCells){
1746 mappedCells = m_podkernel->mapCellsToPOD(targetCells);
1747 ptr_mappedCells = &mappedCells;
1748 }
1749
1750 buildFields(m_reconstructionCoeffs, mappedFields, scalarIds, podscalarIds, vectorIds, podvectorIds, ptr_mappedCells);
1751
1752 m_podkernel->mapFieldsFromPOD(fields, mesh, targetCells, mappedFields, scalarIds, vectorIds);
1753
1754 }
1755
1756}
1757
1764std::vector<std::vector<double>> POD::projectField(pod::PODField &field)
1765{
1766 std::vector<std::vector<double>> reconstructionCoeffs(m_nFields, std::vector<double>(m_nModes,0.0));
1767 if (m_useMean) {
1768 diff(&field, m_mean);
1769 }
1770
1771 // Outer cycle over the POD modes
1772 for (std::size_t ir = 0; ir < m_nModes; ++ir) {
1773 if (m_memoryMode == MemoryMode::MEMORY_LIGHT) {
1774 readMode(ir);
1775 }
1776
1777 // Outer cycle over active cells
1778 for (long id : m_listActiveIDs) {
1779 std::size_t rawIndex = field.mesh->getCells().getRawIndex(id);
1780
1781 // Inner cycle over scalar fields
1782 if (m_nScalarFields) {
1783 const double *modes = m_modes[ir].scalar->rawData(rawIndex);
1784 const double *data = field.scalar->rawData(rawIndex);
1785 for (std::size_t ifs = 0; ifs < m_nScalarFields; ++ifs) {
1786 reconstructionCoeffs[ifs][ir] += data[ifs] * modes[ifs] * getRawCellVolume(rawIndex);
1787 }
1788 }
1789
1790 // Inner cycle over vector fields
1791 if (m_nVectorFields) {
1792 const std::array<double,3> *modes = m_modes[ir].vector->rawData(rawIndex);
1793 const std::array<double,3> *data = field.vector->rawData(rawIndex);
1794 for (std::size_t ifv = 0; ifv < m_nVectorFields; ++ifv) {
1795 reconstructionCoeffs[ifv+m_nScalarFields][ir] += dotProduct(data[ifv], modes[ifv]) * getRawCellVolume(rawIndex);
1796 }
1797 }
1798 }
1799 }
1800
1801#if BITPIT_ENABLE_MPI
1802 for (std::size_t i = 0; i < m_nFields; ++i) {
1803 MPI_Allreduce(MPI_IN_PLACE, reconstructionCoeffs[i].data(), m_nModes, MPI_DOUBLE, MPI_SUM, m_communicator);
1804 }
1805#endif
1806
1807 if (m_useMean) {
1808 sum(&field, m_mean);
1809 }
1810
1811 return reconstructionCoeffs;
1812}
1813
1820void POD::buildErrorMaps(pod::PODField & snap, pod::PODField & recon)
1821{
1822 std::vector<double> norm = fieldsMax(snap);
1823
1824 for (long id : m_listActiveIDs){
1825 std::size_t rawIndex = m_podkernel->getMesh()->getCells().getRawIndex(id);
1826 if (m_nScalarFields){
1827 double* recons = recon.scalar->rawData(rawIndex);
1828 double* snaps = snap.scalar->rawData(rawIndex);
1829 double* errors = m_errorMap.scalar->rawData(rawIndex);
1830 for (std::size_t ifs = 0; ifs < m_nScalarFields; ++ifs){
1831 *errors=std::max(*errors, std::abs(*recons - *snaps)/norm[ifs]);
1832 errors++;
1833 recons++;
1834 snaps++;
1835 }
1836 }
1837 if (m_nVectorFields){
1838 std::array<double,3>* reconv = recon.vector->rawData(rawIndex);
1839 std::array<double,3>* snapv = snap.vector->rawData(rawIndex);
1840 std::array<double,3>* errorv = m_errorMap.vector->rawData(rawIndex);
1841 for (std::size_t ifv = 0; ifv < m_nVectorFields; ++ifv){
1842 for (std::size_t j=0; j<3; ++j)
1843 (*errorv)[j]=std::max((*errorv)[j], std::abs((*reconv)[j] - (*snapv)[j])/norm[ifv]);
1844
1845 errorv++;
1846 reconv++;
1847 snapv++;
1848 }
1849 }
1850 }
1851}
1852
1856void POD::initMinimization()
1857{
1858 m_minimizationMatrices.clear();
1859 m_minimizationMatrices.resize(m_nFields,std::vector<double>(m_nModes*m_nModes, 0.0));
1860}
1861
1865void POD::evalMinimizationMatrices()
1866{
1867 if (m_toUpdate){
1868 initMinimization();
1869
1870
1871 if (m_reconstructionMode == ReconstructionMode::PROJECTION){
1872 for (std::size_t ifield = 0; ifield < m_nFields; ++ifield){
1873 for (std::size_t ir = 0; ir < m_nModes; ++ir)
1874 m_minimizationMatrices[ifield][ir*m_nModes+ir] = 1.0;
1875 }
1876
1877 }else{
1878
1879 for (std::size_t ir = 0; ir < m_nModes; ++ir){
1880 if (m_memoryMode == MemoryMode::MEMORY_LIGHT)
1881 readMode(ir);
1882
1883 for (std::size_t jr = ir; jr < m_nModes; ++jr){
1884 if (m_memoryMode == MemoryMode::MEMORY_LIGHT)
1885 readMode(jr);
1886
1887 std::unordered_set<long>::iterator it;
1888 for (it = m_listActiveIDs.begin(); it != m_listActiveIDs.end(); ++it){
1889 long id = *it;
1890 std::size_t rawIndex = m_podkernel->getMesh()->getCells().getRawIndex(id);
1891 if (m_nScalarFields){
1892 double* datasi = m_modes[ir].scalar->rawData(rawIndex);
1893 double* datasj = m_modes[jr].scalar->rawData(rawIndex);
1894 for (std::size_t ifield = 0; ifield < m_nScalarFields; ++ifield){
1895 m_minimizationMatrices[ifield][ir*m_nModes+jr] += (*datasi)*(*datasj)*getRawCellVolume(rawIndex);
1896 datasi++;
1897 datasj++;
1898 }
1899
1900 if (ir != jr){
1901 for (std::size_t ifield = 0; ifield < m_nScalarFields; ++ifield){
1902 m_minimizationMatrices[ifield][jr*m_nModes+ir] = m_minimizationMatrices[ifield][ir*m_nModes+jr]; // sym: just in case...
1903 }
1904 }
1905 }
1906 if (m_nVectorFields){
1907 std::array<double,3>* datavi = m_modes[ir].vector->rawData(rawIndex);
1908 std::array<double,3>* datavj = m_modes[jr].vector->rawData(rawIndex);
1909 for (std::size_t ifield = m_nScalarFields; ifield < m_nFields; ++ifield){
1910 m_minimizationMatrices[ifield][ir*m_nModes+jr] += dotProduct((*datavi),(*datavj))*getRawCellVolume(rawIndex);
1911 datavi++;
1912 datavj++;
1913 }
1914
1915 if (ir != jr){
1916 for (std::size_t ifield = m_nScalarFields; ifield < m_nFields; ++ifield)
1917 m_minimizationMatrices[ifield][jr*m_nModes+ir] = m_minimizationMatrices[ifield][ir*m_nModes+jr]; // sym: just in case...
1918 }
1919 }
1920 }
1921 }
1922 }
1923
1924# if BITPIT_ENABLE_MPI
1925 for (std::size_t i = 0; i < m_nFields; i++ )
1926 MPI_Allreduce(MPI_IN_PLACE, m_minimizationMatrices[i].data(), m_nModes*m_nModes, MPI_DOUBLE, MPI_SUM, m_communicator);
1927# endif
1928 }
1929 m_toUpdate = false;
1930 }
1931
1932}
1933
1939void POD::solveMinimization(std::vector<std::vector<double> > & rhs)
1940{
1941 bool runSolver;
1942#if BITPIT_ENABLE_MPI
1943 runSolver = (m_rank == 0);
1944#else
1945 runSolver = true;
1946#endif
1947
1948 if (runSolver) {
1949 for (std::size_t i = 0; i < m_nFields; ++i) {
1950 std::vector<double> A(m_nModes * m_nModes);
1951 std::vector<int> ipiv(m_nModes);
1952
1953 for (std::size_t j = 0; j < m_nModes*m_nModes; ++j)
1954 A[j] = m_minimizationMatrices[i][j];
1955
1956 lapack_int info = LAPACKE_dgesv(LAPACK_COL_MAJOR, m_nModes, 1, A.data(), m_nModes, ipiv.data(), rhs[i].data(), m_nModes); //lapacke
1957 if (info != 0) {
1958 log::cout() << "WARNING! algorithm convergence info " << info << std::endl;
1959 throw std::runtime_error("Unable to solve minimization problem.");
1960 }
1961 }
1962 }
1963 else{
1964 for (std::size_t i = 0; i < m_nFields; ++i) {
1965 rhs[i] = std::vector<double>(m_nModes, 0.0);
1966 }
1967 }
1968}
1969
1973void POD::evalEigen()
1974{
1975 m_lambda.clear();
1976 m_lambda.resize(m_nFields,std::vector<double>(m_nSnapshots, 0.0));
1977
1978 m_podCoeffs.clear();
1979 m_podCoeffs.resize(m_nFields, std::vector<std::vector<double>>(m_nSnapshots, std::vector<double>(m_nSnapshots,0.0)));
1980
1981 bool runSolver;
1982#if BITPIT_ENABLE_MPI
1983 runSolver = (m_rank == 0);
1984#else
1985 runSolver = true;
1986#endif
1987
1988 if (runSolver) {
1989 int N = m_nSnapshots*m_nSnapshots;
1990 for (std::size_t i = 0; i < m_nFields; ++i) {
1991 std::vector<double> Marr(N);
1992 std::vector<double> alambda(m_nSnapshots);
1993 for (std::size_t j = 0; j < m_nSnapshots*m_nSnapshots; ++j)
1994 Marr[j/m_nSnapshots+j%m_nSnapshots*m_nSnapshots] = m_correlationMatrices[i][j];
1995
1996 lapack_int info = LAPACKE_dsyev(LAPACK_COL_MAJOR, 'V', 'U', m_nSnapshots, Marr.data(), m_nSnapshots, alambda.data()); //lapacke
1997 if (info != 0) {
1998 log::cout() << "WARNING! algorithm convergence info " << info << std::endl;
1999 throw std::runtime_error("Unable to solve minimization problem.");
2000 }
2001
2002 // Check number of modes with energy level
2003 checkModeCount(alambda.data(), i);
2004
2005 for (std::size_t n = 0; n < m_nSnapshots; ++n)
2006 m_lambda[i][n] = alambda[m_nSnapshots - n - 1];
2007
2008 for (std::size_t n = 0; n < m_nSnapshots; ++n) {
2009 for (std::size_t p = 0; p < m_nSnapshots; ++p)
2010 m_podCoeffs[i][p][n] = Marr[N - m_nSnapshots * (p + 1) + n] * std::sqrt(std::abs(m_lambda[i][p]));
2011 }
2012 }
2013 if (m_errorMode != ErrorMode::COMBINED){
2014 // one coeff file for each mode, each line is related to a field, each term is related to a snapshot
2015 for (std::size_t ir=0; ir<m_nModes; ++ir) {
2016 std::ofstream out(m_directory + m_name + ".coeff."+std::to_string(ir)+".dat", std::ofstream::out);
2017 for (std::size_t i = 0; i < m_nFields; ++i)
2018 out << m_podCoeffs[i][ir] << std::endl;
2019
2020 out.close();
2021 }
2022
2023 std::ofstream outl(m_directory + m_name + ".lambda.dat", std::ofstream::out);
2024 for (std::size_t i = 0; i < m_nFields; ++i)
2025 outl << m_lambda[i] << std::endl;
2026
2027 outl.close();
2028 }
2029 }
2030
2031#if BITPIT_ENABLE_MPI
2032 long bufferSize = m_nModes;
2033 MPI_Bcast(&bufferSize, 1, MPI_LONG, 0, m_communicator);
2034 m_nModes = bufferSize;
2035 for (std::size_t i = 0; i < m_nFields; ++i) {
2036 for (std::size_t p=0; p<m_nModes; ++p)
2037 MPI_Bcast(m_podCoeffs[i][p].data(), m_nSnapshots, MPI_DOUBLE, 0, m_communicator);
2038
2039 MPI_Bcast(m_lambda[i].data(), m_nSnapshots, MPI_DOUBLE, 0, m_communicator);
2040 }
2041#endif
2042}
2043
2050void POD::checkModeCount(double *alambda, std::size_t ifield)
2051{
2052 if (ifield == 0){
2053 _m_nr.clear();
2054 if (m_useMean)
2055 m_nModes = std::min(m_nModes, m_nSnapshots-1);
2056 else
2057 m_nModes = std::min(m_nModes, m_nSnapshots);
2058 }
2059
2060 std::size_t nr = 0;
2061 std::size_t hn = 0;
2062 if (!m_useMean)
2063 hn=1;
2064 double en = 0;
2065 double sumen = 0;
2066 std::vector<double> dlambda(m_nSnapshots);
2067
2068 for (std::size_t n=hn; n<m_nSnapshots; ++n){
2069 dlambda[n] = alambda[m_nSnapshots-n-1];
2070 sumen += std::abs(dlambda[n]);
2071 }
2072 while (nr < m_nModes && en < m_energyLevel){
2073 en += std::abs(dlambda[nr]) / sumen * 100;
2074 nr++;
2075 }
2076 _m_nr.push_back(nr);
2077 if (ifield == m_nFields-1)
2078 m_nModes = *(std::max_element(_m_nr.begin(), _m_nr.end()));
2079}
2080
2084void POD::evalModes()
2085{
2086 m_modes.resize(m_nModes);
2087 _evalModes();
2088}
2089
2093void POD::_evalModes()
2094{
2095 for (std::size_t ir = 0; ir < m_nModes; ++ir){
2096 m_modes[ir].scalar = std::unique_ptr<pod::ScalarStorage>(new pod::ScalarStorage(m_nScalarFields, &m_podkernel->getMesh()->getCells()));
2097 m_modes[ir].vector = std::unique_ptr<pod::VectorStorage>(new pod::VectorStorage(m_nVectorFields, &m_podkernel->getMesh()->getCells()));
2098 m_modes[ir].scalar->fill(0.0);
2099 m_modes[ir].vector->fill(std::array<double, 3>{{0.0, 0.0, 0.0}});
2100 }
2101
2102 for (std::size_t is = 0; is < m_nSnapshots; ++is){
2103 pod::PODField snapi;
2104 readSnapshot(m_database[is], snapi);
2105 if (!m_staticMesh){
2106 _computeMapper(snapi.mesh);
2107 snapi = pod::PODField(m_podkernel->mapPODFieldToPOD(snapi, nullptr));
2108 m_podkernel->clearMapper();
2109 }
2110
2111 if (m_useMean)
2112 diff(&snapi, m_mean);
2113
2114 for (std::size_t ir = 0; ir < m_nModes; ++ir){
2115 for (long id : m_listActiveIDs){
2116 std::size_t rawIndex = m_podkernel->getMesh()->getCells().getRawIndex(id);
2117 if (m_nScalarFields){
2118 double* modes = m_modes[ir].scalar->rawData(rawIndex);
2119 double* datas = snapi.scalar->rawData(rawIndex);
2120 for (std::size_t ifs = 0; ifs < m_nScalarFields; ++ifs){
2121 *modes = *modes + *datas*m_podCoeffs[ifs][ir][is] / m_lambda[ifs][ir];
2122 modes++;
2123 datas++;
2124 }
2125 }
2126 if (m_nVectorFields){
2127 std::array<double, 3>* modev = m_modes[ir].vector->rawData(rawIndex);
2128 std::array<double, 3>* datav = snapi.vector->rawData(rawIndex);
2129 for (std::size_t ifv = 0; ifv < m_nVectorFields; ++ifv){
2130 *modev = *modev + *datav*m_podCoeffs[m_nScalarFields+ifv][ir][is] / m_lambda[m_nScalarFields+ifv][ir];
2131 modev++;
2132 datav++;
2133 }
2134 }
2135 }
2136 if (m_memoryMode == MemoryMode::MEMORY_LIGHT){
2137 dumpMode(ir);
2138 m_modes[ir].clear();
2139 }
2140 }
2141 }
2142}
2143
2150void POD::readSnapshot(const pod::SnapshotFile & snap, pod::PODField & fieldr)
2151{
2152
2153 int dumpBlock = (m_nProcs > 1) ? m_rank : -1;
2154
2155 std::string filename = std::string(snap.directory) + "/" + std::string(snap.name) + ".data";
2156 IBinaryArchive binaryReader(filename, dumpBlock);
2157 std::istream &dataStream = binaryReader.getStream();
2158
2159 //Set mesh field
2160 if (m_staticMesh){
2161 fieldr.setMesh(m_podkernel->getMesh());
2162 }
2163 else{
2164 //Read and set the mesh
2165 fieldr.setMesh(m_podkernel->readMesh(snap));
2166 }
2167 VolumeKernel * mesh = fieldr.mesh;
2168
2169 // Restore solved cells
2170 fieldr.mask = std::unique_ptr<PiercedStorage<bool>>(new PiercedStorage<bool>(1, &mesh->getCells()));
2171 fieldr.mask->restore(dataStream);
2172
2173 // For each snapshot the global number of fields are read & updated again .
2174
2175 // Restore scalar fields
2176 utils::binary::read(dataStream, m_nScalarFields);
2177 m_nameScalarFields.resize(m_nScalarFields);
2178 for (std::size_t i = 0; i < m_nScalarFields; ++i)
2179 utils::binary::read(dataStream, m_nameScalarFields[i]);
2180
2181 if (m_nScalarFields) {
2182 fieldr.scalar = std::unique_ptr<pod::ScalarStorage>(new pod::ScalarStorage(m_nScalarFields, &mesh->getCells()));
2183 fieldr.scalar->restore(dataStream);
2184 }
2185
2186 // Restore vector fields
2187 utils::binary::read(dataStream, m_nVectorFields);
2188 m_nFields = m_nScalarFields + m_nVectorFields;
2189 m_nameVectorFields.resize(m_nVectorFields);
2190 for (std::size_t i = 0; i < m_nVectorFields; ++i)
2191 utils::binary::read(dataStream, m_nameVectorFields[i]);
2192
2193 if (m_nVectorFields) {
2194 fieldr.vector = std::unique_ptr<pod::VectorStorage>(new pod::VectorStorage(m_nVectorFields, &mesh->getCells()));
2195 fieldr.vector->restore(dataStream);
2196 }
2197 binaryReader.close();
2198
2199 // Write vtk with field in DEBUG mode
2200 if (m_writeMode == WriteMode::DEBUG) {
2201 std::vector<std::string > datastring;
2202 mesh->getVTK().setDirectory(m_directory);
2203 mesh->getVTK().setName(m_name + "." + snap.name);
2204 std::vector<uint8_t> mask(mesh->getCellCount());
2205 std::vector<std::vector<double>> fields(m_nScalarFields, std::vector<double>(mesh->getCellCount()));
2206 std::vector<std::vector<std::array<double,3>>> fieldv(m_nVectorFields, std::vector<std::array<double,3>>(mesh->getCellCount()));
2207
2208 int i=0;
2209 for (const Cell &cell : mesh->getCells()) {
2210 long id = cell.getId();
2211 mask[i] = uint8_t(fieldr.mask->at(id));
2212 ++i;
2213 }
2214 mesh->getVTK().addData("mask", VTKFieldType::SCALAR, VTKLocation::CELL, mask);
2215 datastring.push_back("mask");
2216
2217 for (std::size_t isf = 0; isf < m_nScalarFields; ++isf) {
2218 int i = 0;
2219 for (const Cell &cell : mesh->getCells()) {
2220 long id = cell.getId();
2221 fields[isf][i] = fieldr.scalar->at(id, isf);
2222 ++i;
2223 }
2224 mesh->getVTK().addData(m_nameScalarFields[isf], VTKFieldType::SCALAR, VTKLocation::CELL, fields[isf]);
2225 datastring.push_back(m_nameScalarFields[isf]);
2226 }
2227
2228 for (std::size_t ivf = 0; ivf < m_nVectorFields; ++ivf) {
2229 int i = 0;
2230 for (const Cell &cell : mesh->getCells()) {
2231 long id = cell.getId();
2232 fieldv[ivf][i] = fieldr.vector->at(id, ivf);
2233 ++i;
2234 }
2235 std::string vname= m_nameVectorFields[ivf][0].substr(0,m_nameVectorFields[ivf][0].size()-2);
2236 mesh->getVTK().addData(vname, VTKFieldType::VECTOR, VTKLocation::CELL, fieldv[ivf]);
2237 datastring.push_back(vname);
2238 }
2239
2240 // Set temporary write all cells if meshPOD
2241 if (mesh == m_podkernel->getMesh())
2242 mesh->setVTKWriteTarget(PatchKernel::WriteTarget::WRITE_TARGET_CELLS_ALL);
2243
2244 mesh->write();
2245
2246 for (std::size_t is=0; is < datastring.size(); ++is)
2247 mesh->getVTK().removeData(datastring[is]);
2248 }
2249
2250 // Reset temporary write internal cells only if meshPOD
2251 if (mesh == m_podkernel->getMesh()){
2252#if BITPIT_ENABLE_MPI
2253 mesh->setVTKWriteTarget(PatchKernel::WriteTarget::WRITE_TARGET_CELLS_INTERNAL);
2254#else
2255 mesh->setVTKWriteTarget(PatchKernel::WriteTarget::WRITE_TARGET_CELLS_ALL);
2256#endif
2257 }
2258}
2259
2265void POD::readMode(std::size_t ir)
2266{
2267 if (!m_podkernel->getMesh())
2268 throw std::runtime_error ("POD: POD mesh not initialized before read a POD mode");
2269
2270 if (ir > m_nModes)
2271 throw std::runtime_error ("POD: mode index > number of POD modes during read");
2272
2273 int dumpBlock = (m_nProcs > 1) ? m_rank : -1;
2274
2275 if (ir == m_nModes){
2276 // Read mean
2277 std::string filename = m_directory + m_name + ".mean"+".data";
2278 IBinaryArchive binaryReader(filename, dumpBlock);
2279 std::istream &dataStream = binaryReader.getStream();
2280
2281 // Restore solved cells (read for each POD mode)
2282 m_filter.restore(dataStream);
2283
2284 // For each mode/mean the global number of fields are read & updated again .
2285
2286 // Restore scalar fields
2287 utils::binary::read(dataStream, m_nScalarFields);
2288 m_nameScalarFields.resize(m_nScalarFields);
2289 for (std::size_t i = 0; i < m_nScalarFields; ++i)
2290 utils::binary::read(dataStream, m_nameScalarFields[i]);
2291
2292 if (m_nScalarFields) {
2293 m_mean.scalar = std::unique_ptr<pod::ScalarStorage>(new pod::ScalarStorage(m_nScalarFields, &m_podkernel->getMesh()->getCells()));
2294 m_mean.scalar->restore(dataStream);
2295 }
2296
2297 // Restore vector fields
2298 utils::binary::read(dataStream, m_nVectorFields);
2299 m_nameVectorFields.resize(m_nVectorFields);
2300 m_nFields = m_nScalarFields + m_nVectorFields;
2301 for (std::size_t i = 0; i < m_nVectorFields; ++i)
2302 utils::binary::read(dataStream, m_nameVectorFields[i]);
2303
2304 if (m_nVectorFields) {
2305 m_mean.vector = std::unique_ptr<pod::VectorStorage>(new pod::VectorStorage(m_nVectorFields, &m_podkernel->getMesh()->getCells()));
2306 m_mean.vector->restore(dataStream);
2307 }
2308 binaryReader.close();
2309 }
2310 else{
2311 // Read mode
2312 m_modes[ir].clear();
2313
2314 std::string filename = m_directory + m_name + ".mode."+std::to_string(ir)+".data";
2315 IBinaryArchive binaryReader(filename, dumpBlock);
2316 std::istream &dataStream = binaryReader.getStream();
2317
2318 // Restore solved cells (read for each POD mode)
2319 m_filter.restore(dataStream);
2320
2321 // For each mode/mean the global number of fields are read & updated again .
2322
2323 // Restore scalar fields
2324 utils::binary::read(dataStream, m_nScalarFields);
2325 m_nameScalarFields.resize(m_nScalarFields);
2326 for (std::size_t i = 0; i < m_nScalarFields; ++i)
2327 utils::binary::read(dataStream, m_nameScalarFields[i]);
2328
2329 if (m_nScalarFields) {
2330 m_modes[ir].scalar = std::unique_ptr<pod::ScalarStorage>(new pod::ScalarStorage(m_nScalarFields, &m_podkernel->getMesh()->getCells()));
2331 m_modes[ir].scalar->restore(dataStream);
2332 }
2333
2334 // Restore vector fields
2335 utils::binary::read(dataStream, m_nVectorFields);
2336 m_nFields = m_nScalarFields + m_nVectorFields;
2337 m_nameVectorFields.resize(m_nVectorFields);
2338 for (std::size_t i = 0; i < m_nVectorFields; ++i)
2339 utils::binary::read(dataStream, m_nameVectorFields[i]);
2340
2341 if (m_nVectorFields) {
2342 m_modes[ir].vector = std::unique_ptr<pod::VectorStorage>(new pod::VectorStorage(m_nVectorFields, &m_podkernel->getMesh()->getCells()));
2343 m_modes[ir].vector->restore(dataStream);
2344 }
2345 binaryReader.close();
2346 }
2347}
2348
2354double POD::getCellVolume(long id)
2355{
2356 return m_podkernel->getCellVolume(id);
2357}
2358
2364double POD::getRawCellVolume(long rawIndex)
2365{
2366 return m_podkernel->getRawCellVolume(rawIndex);
2367}
2368
2374void POD::dumpMode(std::size_t ir)
2375{
2376 if (ir > m_nModes)
2377 throw std::runtime_error ("POD: mode index > number of pod modes during write");
2378
2379 int dumpBlock = (m_nProcs > 1) ? m_rank : -1;
2380
2381 if (ir == m_nModes) {
2382 // Dumping mean as snapshot
2383 std::string header = "podmean." + std::to_string(ir);
2384 OBinaryArchive binaryWriter(m_directory + m_name + ".mean"+".data", ARCHIVE_VERSION, header, dumpBlock);
2385 std::ostream &dataStream = binaryWriter.getStream();
2386 m_filter.dump(dataStream);
2387 utils::binary::write(dataStream,std::size_t(m_nScalarFields));
2388 if (m_nScalarFields) {
2389 for (std::size_t i = 0; i < m_nScalarFields; ++i)
2390 utils::binary::write(dataStream, m_nameScalarFields[i]);
2391 m_mean.scalar->dump(dataStream);
2392 }
2393
2394 utils::binary::write(dataStream,std::size_t(m_nVectorFields));
2395 if (m_nVectorFields) {
2396 for (std::size_t i = 0; i < m_nVectorFields; ++i)
2397 utils::binary::write(dataStream, m_nameVectorFields[i]);
2398 m_mean.vector->dump(dataStream);
2399 }
2400 binaryWriter.close();
2401
2402 } else{
2403 // Dumping modes as snapshots
2404 std::string header = "podmode." + std::to_string(ir);
2405 OBinaryArchive binaryWriter(m_directory + m_name + ".mode."+std::to_string(ir)+".data", ARCHIVE_VERSION, header, dumpBlock);
2406 std::ostream &dataStream = binaryWriter.getStream();
2407 m_filter.dump(dataStream);
2408 utils::binary::write(dataStream,std::size_t(m_nScalarFields));
2409 if (m_nScalarFields) {
2410 for (std::size_t i = 0; i < m_nScalarFields; ++i)
2411 utils::binary::write(dataStream, m_nameScalarFields[i]);
2412
2413 m_modes[ir].scalar->dump(dataStream);
2414 }
2415
2416 utils::binary::write(dataStream,std::size_t(m_nVectorFields));
2417 if (m_nVectorFields) {
2418 for (std::size_t i = 0; i < m_nVectorFields; ++i)
2419 utils::binary::write(dataStream, m_nameVectorFields[i]);
2420
2421 m_modes[ir].vector->dump(dataStream);
2422 }
2423 binaryWriter.close();
2424 }
2425}
2426
2433void POD::dumpField(const std::string &name, const pod::PODField &field) const
2434{
2435 log::cout() << "Dumping snapshot ... " << std::endl;
2436
2437 int dumpBlock = (m_nProcs > 1) ? m_rank : -1;
2438
2439 // Dump field data
2440 {
2441 std::string header = name;
2442 OBinaryArchive binaryWriter(m_directory + name + ".data", ARCHIVE_VERSION, header, dumpBlock);
2443 std::ostream &dataStream = binaryWriter.getStream();
2444 m_filter.dump(dataStream);
2445 utils::binary::write(dataStream,std::size_t(m_nScalarFields));
2446 if (m_nScalarFields) {
2447 for (std::size_t i = 0; i < m_nScalarFields; ++i) {
2448 utils::binary::write(dataStream, m_nameScalarFields[i]);
2449 }
2450 field.scalar->dump(dataStream);
2451 }
2452
2453 utils::binary::write(dataStream,std::size_t(m_nVectorFields));
2454 if (m_nVectorFields) {
2455 for (std::size_t i = 0; i < m_nVectorFields; ++i) {
2456 utils::binary::write(dataStream, m_nameVectorFields[i]);
2457 }
2458 field.vector->dump(dataStream);
2459 }
2460 binaryWriter.close();
2461 }
2462
2463 // Dumping mesh
2464 {
2465 std::string header = name;// + "mesh";
2466 OBinaryArchive binaryWriter(m_directory + name + ".mesh", ARCHIVE_VERSION, header, dumpBlock);
2467 std::ostream &dataStream = binaryWriter.getStream();
2468 field.mesh->dump(dataStream);
2469 binaryWriter.close();
2470 }
2471
2472 // Write VTK file
2473 if (m_writeMode == WriteMode::DEBUG) {
2474 write(field, name);
2475 }
2476}
2477
2484void POD::diff(pod::PODField* _a, const pod::PODMode& b)
2485{
2486 pod::PODField& a = *_a;
2487 std::size_t nsf = 0;
2488 if (m_nScalarFields){
2489 nsf = a.scalar->getFieldCount();
2490 if (nsf != b.scalar->getFieldCount())
2491 throw std::runtime_error ("POD: different field count");
2492 }
2493
2494 std::size_t nvf = 0;
2495 if (m_nVectorFields){
2496 nvf = a.vector->getFieldCount();
2497 if (nvf != b.vector->getFieldCount())
2498 throw std::runtime_error ("POD: different field count");
2499 }
2500
2501 if (nsf){
2502 for (long id : a.scalar->getKernel()->getIds()){
2503 std::size_t rawIndex = m_podkernel->getMesh()->getCells().getRawIndex(id);
2504 double* datasa = a.scalar->rawData(rawIndex);
2505 double* datasb = b.scalar->rawData(rawIndex);
2506 for (std::size_t i = 0; i < nsf; ++i){
2507 *datasa = *datasa - *datasb;
2508 datasa++;
2509 datasb++;
2510 }
2511 }
2512 }
2513 if (nvf){
2514 for (long id : a.scalar->getKernel()->getIds()){
2515 std::size_t rawIndex = m_podkernel->getMesh()->getCells().getRawIndex(id);
2516 std::array<double,3>* datava = a.vector->rawData(rawIndex);
2517 std::array<double,3>* datavb = b.vector->rawData(rawIndex);
2518 for (std::size_t i = 0; i < nvf; ++i)
2519 *datava = *datava - *datavb;
2520 datava++;
2521 datavb++;
2522 }
2523 }
2524}
2525
2532void POD::sum(pod::PODField* _a, const pod::PODMode& b)
2533{
2534 pod::PODField& a = *_a;
2535 std::size_t nsf = 0;
2536 if (m_nScalarFields){
2537 nsf = a.scalar->getFieldCount();
2538 if (nsf != b.scalar->getFieldCount())
2539 throw std::runtime_error ("POD: different field count");
2540 }
2541
2542 std::size_t nvf = 0;
2543 if (m_nVectorFields){
2544 nvf = a.vector->getFieldCount();
2545 if (nvf != b.vector->getFieldCount())
2546 throw std::runtime_error ("POD: different field count");
2547 }
2548
2549 if (nsf){
2550 for (long id : a.scalar->getKernel()->getIds()){
2551 std::size_t rawIndex = m_podkernel->getMesh()->getCells().getRawIndex(id);
2552 double *dataa = a.scalar->rawData(rawIndex);
2553 const double *datab = b.scalar->rawData(rawIndex);
2554 for (std::size_t i = 0; i < nsf; ++i){
2555 dataa[i] += datab[i];
2556 }
2557 }
2558 }
2559 if (nvf){
2560 for (long id : a.scalar->getKernel()->getIds()){
2561 std::size_t rawIndex = m_podkernel->getMesh()->getCells().getRawIndex(id);
2562 std::array<double,3> *dataa = a.vector->rawData(rawIndex);
2563 const std::array<double,3> *datab = b.vector->rawData(rawIndex);
2564 for (std::size_t i = 0; i < nvf; ++i) {
2565 dataa[i] += datab[i];
2566 }
2567 }
2568 }
2569}
2570
2577std::vector<double> POD::fieldsl2norm(pod::PODField & snap)
2578{
2579 std::vector<double> norm;
2580 norm.resize(m_nFields,0.0);
2581
2582 std::unordered_set<long>::iterator it;
2583 for (it = m_listActiveIDs.begin(); it != m_listActiveIDs.end(); ++it){
2584 long id = *it;
2585 std::size_t rawIndex = m_podkernel->getMesh()->getCells().getRawIndex(id);
2586 if (m_nScalarFields){
2587 double* datas = snap.scalar->rawData(rawIndex);
2588 for (std::size_t ifield = 0; ifield < m_nScalarFields; ++ifield){
2589 norm[ifield] += (*datas)*(*datas)*snap.mesh->evalCellVolume(id);
2590 datas++;
2591 }
2592 }
2593 if (m_nVectorFields){
2594 std::array<double,3>* datav = snap.vector->rawData(rawIndex);
2595 for (std::size_t ifield = m_nScalarFields; ifield < m_nFields; ++ifield){
2596 norm[ifield] += dotProduct((*datav),(*datav))*snap.mesh->evalCellVolume(id);
2597 datav++;
2598 }
2599 }
2600 }
2601
2602# if BITPIT_ENABLE_MPI
2603 MPI_Allreduce(MPI_IN_PLACE, norm.data(), m_nFields, MPI_DOUBLE, MPI_SUM, m_communicator);
2604# endif
2605
2606 for (std::size_t ifield = 0; ifield < m_nFields; ++ifield)
2607 norm[ifield]=std::sqrt(norm[ifield]);
2608
2609 return norm;
2610}
2611
2618std::vector<double> POD::fieldsMax(pod::PODField & snap)
2619{
2620 std::vector<double> max;
2621 max.resize(m_nFields,0.0);
2622 for (long id : m_listActiveIDs) {
2623 std::size_t rawIndex = snap.mesh->getCells().getRawIndex(id);
2624
2625 if (m_nScalarFields){
2626 const double *data = snap.scalar->rawData(rawIndex);
2627 for (std::size_t i = 0; i < m_nScalarFields; ++i){
2628 double fieldData = data[i];
2629 max[i] = std::max(max[i], std::abs(fieldData));
2630 }
2631 }
2632 if (m_nVectorFields){
2633 const std::array<double,3> *data = snap.vector->rawData(rawIndex);
2634 for (std::size_t i = m_nScalarFields; i < m_nFields; ++i){
2635 const std::array<double,3> &fieldData = data[i - m_nScalarFields];
2636 max[i] = std::max(max[i], std::sqrt(dotProduct(fieldData, fieldData)));
2637 }
2638 }
2639 }
2640
2641# if BITPIT_ENABLE_MPI
2642 MPI_Allreduce(MPI_IN_PLACE, max.data(), m_nFields, MPI_DOUBLE, MPI_MAX, m_communicator);
2643# endif
2644
2645 return max;
2646}
2647
2648#if BITPIT_ENABLE_MPI
2654void POD::initializeCommunicator(MPI_Comm communicator)
2655{
2656 // Communication can be set just once
2657 if (isCommunicatorSet())
2658 throw std::runtime_error ("POD communicator can be set just once");
2659
2660 // The communicator has to be valid
2661 if (communicator == MPI_COMM_NULL)
2662 throw std::runtime_error ("POD communicator is not valid");
2663
2664 // Create a copy of the user-specified communicator
2665 //
2666 // No library routine should use MPI_COMM_WORLD as the communicator;
2667 // instead, a duplicate of a user-specified communicator should always
2668 // be used.
2669 MPI_Comm_dup(communicator, &m_communicator);
2670}
2671
2676MPI_Comm POD::getCommunicator() const
2677{
2678 return m_communicator;
2679}
2680
2687bool POD::isCommunicatorSet() const
2688{
2689
2690 return (getCommunicator() != MPI_COMM_NULL);
2691}
2692
2696void POD::freeCommunicator()
2697{
2698 if (!isCommunicatorSet())
2699 return;
2700
2701 int finalizedCalled;
2702 MPI_Finalized(&finalizedCalled);
2703 if (finalizedCalled)
2704 return;
2705
2706 MPI_Comm_free(&m_communicator);
2707}
2708#endif
2709
2715void POD::evalReconstructionCoeffs(pod::PODField & field)
2716{
2717 evalMinimizationMatrices();
2718
2719 // Evaluate RHS
2720 m_reconstructionCoeffs = projectField(field);
2721
2722 // Solve minimization
2723 solveMinimization(m_reconstructionCoeffs);
2724}
2725
2735void POD::evalReconstructionCoeffs(PiercedStorage<double> &fields,
2736 const std::vector<std::size_t> &scalarIds, const std::vector<std::size_t> & podscalarIds,
2737 const std::vector<std::array<std::size_t, 3>> & vectorIds, const std::vector<std::size_t> & podvectorIds)
2738{
2739 std::size_t nsf = scalarIds.size();
2740 std::size_t nvf = vectorIds.size();
2741
2742 // Difference field - m_mean
2743 diff(fields, m_mean, scalarIds, podscalarIds, vectorIds, podvectorIds, &m_listActiveIDs);
2744
2745 m_reconstructionCoeffs.clear();
2746 m_reconstructionCoeffs.resize(m_nFields, std::vector<double>(m_nModes, 0.0));
2747
2748 // Evaluate minimization matrices
2749 evalMinimizationMatrices();
2750
2751 // Evaluate RHS
2752 for (std::size_t ir = 0; ir < m_nModes; ++ir) {
2753 if (m_memoryMode == MemoryMode::MEMORY_LIGHT)
2754 readMode(ir);
2755
2756 std::unordered_set<long>::iterator it;
2757 for (it = m_listActiveIDs.begin(); it != m_listActiveIDs.end(); ++it) {
2758 long id = *it;
2759 std::size_t rawIndex = m_podkernel->getMesh()->getCells().getRawIndex(id);
2760 double *datag = fields.rawData(rawIndex);
2761 if (nsf) {
2762 double *modes = m_modes[ir].scalar->rawData(rawIndex);
2763 for (std::size_t ifield = 0; ifield < nsf; ++ifield) {
2764 double *modesi = modes + podscalarIds[ifield];
2765 double *datagi = datag + scalarIds[ifield];
2766 m_reconstructionCoeffs[ifield][ir] += (*datagi)*(*modesi)*getRawCellVolume(rawIndex);
2767 }
2768 }
2769 if (nvf) {
2770 std::array<double,3>* modev = m_modes[ir].vector->rawData(rawIndex);
2771 for (std::size_t ifield = 0; ifield < nvf; ++ifield) {
2772 std::array<double,3>* modevi = modev + podvectorIds[ifield];
2773 for (std::size_t j = 0; j < 3; ++j) {
2774 double *datagi = datag + vectorIds[ifield][j];
2775 m_reconstructionCoeffs[m_nScalarFields+ifield][ir] += ((*datagi)*(*modevi)[j])*getRawCellVolume(rawIndex);
2776 }
2777 }
2778 }
2779 }
2780 }
2781
2782#if BITPIT_ENABLE_MPI
2783 for (std::size_t i = 0; i < m_nFields; ++i)
2784 MPI_Allreduce(MPI_IN_PLACE, m_reconstructionCoeffs[i].data(), m_nModes, MPI_DOUBLE, MPI_SUM, m_communicator);
2785#endif
2786
2787 // Solve
2788 solveMinimization(m_reconstructionCoeffs);
2789
2790 // Sum field and mean
2791 sum(fields, m_mean, scalarIds, podscalarIds, vectorIds, podvectorIds, &m_listActiveIDs);
2792}
2793
2801void POD::buildFields(const std::vector<std::vector<double>> &reconstructionCoeffs, pod::PODField &recon)
2802{
2803 // set up of the PODField members: scalar, vector
2804 recon.scalar = std::unique_ptr<pod::ScalarStorage>(new pod::ScalarStorage(m_nScalarFields, &m_podkernel->getMesh()->getCells()));
2805 recon.vector = std::unique_ptr<pod::VectorStorage>(new pod::VectorStorage(m_nVectorFields, &m_podkernel->getMesh()->getCells()));
2806 recon.scalar->fill(0.0);
2807 recon.vector->fill(std::array<double, 3>{{0.0, 0.0, 0.0}});
2808
2809 // Outer cycle over modes
2810 for (std::size_t ir = 0; ir < m_nModes; ++ir) {
2811 if (m_memoryMode == MemoryMode::MEMORY_LIGHT) {
2812 readMode(ir);
2813 }
2814
2815 // Outer cycle over cells
2816 for (long id : m_listActiveIDs) {
2817 std::size_t rawIndex = recon.mesh->getCells().getRawIndex(id);
2818
2819 // Inner cycle over scalar fields
2820 if (m_nScalarFields) {
2821 const double *modes = m_modes[ir].scalar->rawData(rawIndex);
2822 for (std::size_t isf = 0; isf < m_nScalarFields; ++isf) {
2823 recon.scalar->at(id, isf) += modes[isf] * reconstructionCoeffs[isf][ir];
2824 }
2825 }
2826
2827 // Inner cycle over vector fields
2828 if (m_nVectorFields) {
2829 const std::array<double,3> *modes = m_modes[ir].vector->rawData(rawIndex);
2830 for (std::size_t ifv = 0; ifv < m_nVectorFields; ++ifv) {
2831 recon.vector->at(id, ifv) += modes[ifv] * reconstructionCoeffs[m_nScalarFields+ifv][ir];
2832 }
2833 }
2834 }
2835
2836 if (m_memoryMode == MemoryMode::MEMORY_LIGHT) {
2837 m_modes[ir].clear();
2838 }
2839 }
2840
2841 if (m_useMean) {
2842 sum(&recon, m_mean);
2843 }
2844}
2845
2859void POD::buildFields(const std::vector<std::vector<double>> &reconstructionCoeffs, PiercedStorage<double> &fields,
2860 const std::vector<std::size_t> &scalarIds, const std::vector<std::size_t> &podscalarIds,
2861 const std::vector<std::array<std::size_t, 3>> &vectorIds, const std::vector<std::size_t> &podvectorIds,
2862 const std::unordered_set<long> *targetCells)
2863{
2864 std::size_t nsf = scalarIds.size();
2865 std::size_t nvf = vectorIds.size();
2866 if (nsf == 0 && nvf == 0) {
2867 return;
2868 }
2869
2870 std::unordered_set<long> targetCellsStorage;
2871 if (!targetCells) {
2872 for (const Cell &cell : m_podkernel->getMesh()->getCells()) {
2873 targetCellsStorage.insert(cell.getId());
2874 }
2875 targetCells = &targetCellsStorage;
2876 }
2877
2878 // Initialization of fields
2879 for (const long id : *targetCells) {
2880 std::size_t rawIndex = m_podkernel->getMesh()->getCells().getRawIndex(id);
2881 double *recon = fields.rawData(rawIndex);
2882 for (std::size_t ifs = 0; ifs < m_nScalarFields; ++ifs) {
2883 double *reconsi = recon + scalarIds[ifs];
2884 (*reconsi) = 0.;
2885 }
2886 for (std::size_t ifv = 0; ifv < m_nVectorFields; ++ifv) {
2887 for (std::size_t j = 0; j < 3; ++j) {
2888 double *reconvi = recon + vectorIds[ifv][j];
2889 (*reconvi) = 0.;
2890 }
2891 }
2892 }
2893
2894 // Reconstruction of fields
2895 for (std::size_t ir = 0; ir < m_nModes; ++ir) {
2896 if (m_memoryMode == MemoryMode::MEMORY_LIGHT) {
2897 readMode(ir);
2898 }
2899
2900 for (const long id : *targetCells) {
2901 std::size_t rawIndex = m_podkernel->getMesh()->getCells().getRawIndex(id);
2902 double *recon = fields.rawData(rawIndex);
2903
2904 if (m_nScalarFields > 0) {
2905 const double *modes = m_modes[ir].scalar->rawData(rawIndex);
2906 for (std::size_t ifs = 0; ifs < m_nScalarFields; ++ifs) {
2907 double *reconsi = recon + scalarIds[ifs];
2908 const double *modesi = modes + podscalarIds[ifs];
2909 (*reconsi) += (*modesi) * reconstructionCoeffs[ifs][ir];
2910 }
2911 }
2912
2913 if (m_nVectorFields > 0) {
2914 const std::array<double,3> *modev = m_modes[ir].vector->rawData(rawIndex);
2915 for (std::size_t ifv = 0; ifv < m_nVectorFields; ++ifv) {
2916 const std::array<double,3> * modevi = modev + podvectorIds[ifv];
2917 for (std::size_t j = 0; j < 3; ++j) {
2918 double *reconvi = recon + vectorIds[ifv][j];
2919 (*reconvi) += (*modevi)[j] * reconstructionCoeffs[m_nScalarFields + ifv][ir];
2920 }
2921 }
2922 }
2923 }
2924
2925 if (m_memoryMode == MemoryMode::MEMORY_LIGHT) {
2926 m_modes[ir].clear();
2927 }
2928 }
2929
2930 // Sum field and mean
2931 sum(fields, m_mean, scalarIds, podscalarIds, vectorIds, podvectorIds, targetCells);
2932}
2933
2939void POD::computeMapper(const VolumeKernel * mesh)
2940{
2941 if (!m_expert)
2942 throw std::runtime_error("POD: compute mapper can be called only in expert mode");
2943 _computeMapper(mesh);
2944}
2945
2952void POD::adaptionAlter(const std::vector<adaption::Info> & info)
2953{
2954 if (!m_expert)
2955 throw std::runtime_error("POD: update mapper can be called only in expert mode");
2956 _adaptionAlter(info);
2957}
2958
2963void POD::_computeMapper(const VolumeKernel * mesh)
2964{
2965 m_podkernel->computeMapper(mesh);
2966 m_podkernel->setMapperDirty(!m_expert);
2967}
2968
2974void POD::adaptionPrepare(const std::vector<adaption::Info> & info)
2975{
2976 m_podkernel->adaptionPrepare(info);
2977}
2978
2984void POD::_adaptionAlter(const std::vector<adaption::Info> & info)
2985{
2986 m_podkernel->adaptionAlter(info);
2987}
2988
2993void POD::adaptionCleanUp(const std::vector<adaption::Info> & info)
2994{
2995 m_podkernel->adaptionCleanUp(info);
2996}
2997
3004void POD::diff(PiercedStorage<double> &fields, const pod::PODMode &mode,
3005 const std::vector<std::size_t> &scalarIds, const std::vector<std::size_t> &podscalarIds,
3006 const std::vector<std::array<std::size_t, 3>> &vectorIds, const std::vector<std::size_t> &podvectorIds,
3007 const std::unordered_set<long> *targetCells)
3008{
3009 if (targetCells){
3010
3011 std::size_t nsf = scalarIds.size();
3012 std::size_t nvf = vectorIds.size();
3013
3014 for (long id : *targetCells) {
3015 std::size_t rawIndex = m_podkernel->getMesh()->getCells().getRawIndex(id);
3016 double *datag = fields.rawData(rawIndex);
3017 double *datams = mode.scalar->rawData(rawIndex);
3018 for (std::size_t i = 0; i < nsf; ++i) {
3019 double *datagi = datag + scalarIds[i];
3020 double *datamsi = datams + podscalarIds[i];
3021 (*datagi) -= (*datamsi);
3022 }
3023 std::array<double,3>* datamv = mode.vector->rawData(rawIndex);
3024 for (std::size_t i = 0; i < nvf; ++i) {
3025 std::array<double,3>* datamvi = datamv + podvectorIds[i];
3026 for (std::size_t j = 0; j < 3; ++j) {
3027 double *datagi = datag + vectorIds[i][j];
3028 (*datagi) -= (*datamvi)[j];
3029 }
3030 }
3031 }
3032
3033 }
3034}
3035
3042void POD::sum(PiercedStorage<double> &fields, const pod::PODMode &mode,
3043 const std::vector<std::size_t> &scalarIds, const std::vector<std::size_t> &podscalarIds,
3044 const std::vector<std::array<std::size_t, 3>> &vectorIds, const std::vector<std::size_t> &podvectorIds,
3045 const std::unordered_set<long> *targetCells)
3046{
3047 if (targetCells){
3048
3049 std::size_t nsf = scalarIds.size();
3050 std::size_t nvf = vectorIds.size();
3051
3052 for (long id : *targetCells) {
3053 std::size_t rawIndex = m_podkernel->getMesh()->getCells().getRawIndex(id);
3054 double *datag = fields.rawData(rawIndex);
3055 double *datams = mode.scalar->rawData(rawIndex);
3056 for (std::size_t i = 0; i < nsf; ++i) {
3057 double *datagi = datag + scalarIds[i];
3058 double *datamsi = datams + podscalarIds[i];
3059 (*datagi) += (*datamsi);
3060 }
3061 std::array<double,3>* datamv = mode.vector->rawData(rawIndex);
3062 for (std::size_t i = 0; i < nvf; ++i) {
3063 std::array<double,3>* datamvi = datamv + podvectorIds[i];
3064 for (std::size_t j = 0; j < 3; ++j) {
3065 double *datagi = datag + vectorIds[i][j];
3066 (*datagi) += (*datamvi)[j];
3067 }
3068 }
3069 }
3070
3071 }
3072}
3073
3080void POD::write(const pod::PODField &field, std::string file_name) const
3081{
3082 log::cout() << "Writing snapshot ... " << std::endl;
3083
3084 // Set directory to write the VTK file.
3085 m_podkernel->getMesh()->getVTK().setDirectory(m_directory);
3086
3087 // Set up empty string to store fields name
3088 std::vector<std::string > datastring;
3089 field.mesh->getVTK().setName(file_name);
3090
3091 // Set up matrix and vectors to populate the VTK file
3092 std::vector<std::vector<double>> fields(m_nScalarFields, std::vector<double>(field.mesh->getInternalCellCount(), 0.0));
3093 std::vector<std::vector<std::array<double,3>>> fieldv(m_nVectorFields, std::vector<std::array<double,3>>(field.mesh->getInternalCellCount(), {{0.0, 0.0, 0.0}}));
3094 std::vector<uint8_t> field_mask(field.mesh->getInternalCellCount(), 0);
3095
3096 // Populate the scalar fields matrix
3097 for (std::size_t isf = 0; isf < m_nScalarFields; ++isf) {
3098 int i=0;
3099 for (const Cell &cell : field.mesh->getCells()) {
3100 if (cell.isInterior()){
3101 long id = cell.getId();
3102 fields[isf][i] = field.scalar->at(id, isf);
3103 ++i;
3104 }
3105 }
3106 // Add data to the VTK file and name them using the corresponding fields name of the pod object
3107 field.mesh->getVTK().addData(m_nameScalarFields[isf], VTKFieldType::SCALAR, VTKLocation::CELL, fields[isf]);
3108 datastring.push_back(m_nameScalarFields[isf]);
3109 }
3110
3111 // Populate the vector fields matrix
3112 for (std::size_t ivf = 0; ivf < m_nVectorFields; ++ivf) {
3113 int i=0;
3114 for (const Cell &cell : field.mesh->getCells()) {
3115 if (cell.isInterior()) {
3116 long id = cell.getId();
3117 fieldv[ivf][i] = field.vector->at(id, ivf);
3118 ++i;
3119 }
3120 }
3121 std::string vname= m_nameVectorFields[ivf][0].substr(0,m_nameVectorFields[ivf][0].size()-2);
3122 // add data to the VTK file and name them using the corresponding fields name of the pod object
3123 field.mesh->getVTK().addData(vname, VTKFieldType::VECTOR, VTKLocation::CELL, fieldv[ivf]);
3124 datastring.push_back(vname);
3125 }
3126
3127 // Populate the mask vector
3128 int j = 0;
3129 for (const Cell &cell : field.mesh->getCells()) {
3130 if (cell.isInterior()) {
3131 long id = cell.getId();
3132 field_mask[j] = m_filter[id];
3133 ++j;
3134 }
3135 }
3136 field.mesh->getVTK().addData("filter", VTKFieldType::SCALAR, VTKLocation::CELL, field_mask);
3137 datastring.push_back("filter");
3138
3139 // Write the VTK file
3140 field.mesh->write();
3141
3142 // Remove the data from the VTK member of the input PODField mesh
3143 for (std::size_t is=0; is < datastring.size(); ++is) {
3144 field.mesh->getVTK().removeData(datastring[is]);
3145 }
3146}
3147
3154void POD::write(int mode_index, std::string file_name)
3155{
3156 log::cout() << "Writing mode ... " << std::endl;
3157
3158 // Set up mesh
3159 VolumeKernel* mode_mesh;
3160 mode_mesh = m_podkernel->getMesh();
3161 mode_mesh->getVTK().setName(file_name);
3162
3163 // Set up empty string to store fields name
3164 std::vector<std::string> datastring;
3165
3166 // set up matrix and vectors to populate the VTK file
3167 std::vector<std::vector<double>> fields(m_nScalarFields, std::vector<double>(mode_mesh->getInternalCellCount(), 0.0));
3168 std::vector<std::vector<std::array<double,3>>> fieldv(m_nVectorFields, std::vector<std::array<double,3>>(mode_mesh->getInternalCellCount(), {{0.0, 0.0, 0.0}}));
3169 std::vector<uint8_t> mask(mode_mesh->getInternalCellCount(), 0);
3170
3171 // Populate the scalar fields matrix
3172 for (std::size_t isf = 0; isf < m_nScalarFields; ++isf) {
3173 int i=0;
3174 for (const Cell &cell : mode_mesh->getCells()) {
3175 if (cell.isInterior()){
3176 long id = cell.getId();
3177 fields[isf][i] = m_modes[mode_index].scalar->at(id, isf);
3178 ++i;
3179 }
3180 }
3181 // add data to the VTK file and name them using the corresponding fields name of the pod object
3182 mode_mesh->getVTK().addData(m_nameScalarFields[isf], VTKFieldType::SCALAR, VTKLocation::CELL, fields[isf]);
3183 datastring.push_back(m_nameScalarFields[isf]);
3184 }
3185
3186 // Populate the vector fields matrix
3187 for (std::size_t ivf = 0; ivf < m_nVectorFields; ++ivf) {
3188 int i=0;
3189 for (const Cell &cell : mode_mesh->getCells()) {
3190 if (cell.isInterior()) {
3191 long id = cell.getId();
3192 fieldv[ivf][i] = m_modes[mode_index].vector->at(id, ivf);
3193 ++i;
3194 }
3195 }
3196 std::string vname= m_nameVectorFields[ivf][0].substr(0,m_nameVectorFields[ivf][0].size()-2);
3197 // add data to the VTK file and name them using the corresponding fields name of the pod object
3198 mode_mesh->getVTK().addData(vname, VTKFieldType::VECTOR, VTKLocation::CELL, fieldv[ivf]);
3199 datastring.push_back(vname);
3200 }
3201
3202 // Populate the mask vector
3203 int j=0;
3204 for (const Cell &cell : mode_mesh->getCells()) {
3205 if (cell.isInterior()) {
3206 long id = cell.getId();
3207 mask[j] = m_filter[id];
3208 ++j;
3209 }
3210 }
3211 mode_mesh->getVTK().addData("mask", VTKFieldType::SCALAR, VTKLocation::CELL, mask);
3212 datastring.push_back("mask");
3213
3214 // Write the VTK file
3215 mode_mesh->write();
3216
3217 // Remove the data from the VTK member of the input PODField mesh
3218 for (std::size_t is=0; is < datastring.size(); ++is) {
3219 mode_mesh->getVTK().removeData(datastring[is]);
3220 }
3221}
3222
3223}
The Cell class defines the cells.
Definition cell.hpp:42
Input binary archive.
std::istream & getStream()
Output binary archive.
std::ostream & getStream()
The PODVolOctree is the specialized class of PODKernel for VolOctree meshes.
void setErrorThreshold(double threshold)
Definition pod.cpp:346
std::size_t getModeCount()
Definition pod.cpp:315
void fillListActiveIDs(const PiercedStorage< bool > &bfield)
Definition pod.cpp:1316
void clear()
Definition pod.cpp:125
void run()
Definition pod.cpp:836
std::vector< std::array< std::string, 3 > > getVectorNames()
Definition pod.cpp:738
std::size_t getSnapshotCount()
Definition pod.cpp:718
void evalReconstruction()
Definition pod.cpp:1449
void evalCorrelation()
Definition pod.cpp:1345
void unsetLeave1outSnapshots()
Definition pod.cpp:262
const std::string & getDirectory()
Definition pod.cpp:197
const std::vector< pod::PODMode > & getModes()
Definition pod.cpp:790
void setRunMode(RunMode mode)
Definition pod.cpp:542
const VolumeKernel * getMesh()
Definition pod.cpp:767
std::unique_ptr< PODKernel > & getKernel()
Definition pod.cpp:824
std::vector< std::string > getScalarNames()
Definition pod.cpp:728
const std::unordered_set< long int > & getListActiveIDs()
Definition pod.cpp:808
void setTargetErrorFields(std::vector< std::string > &namesf, std::vector< std::array< std::string, 3 > > &namevf)
Definition pod.cpp:367
void setMeshType(MeshType type)
Definition pod.cpp:390
void setStaticMesh(bool flag)
Definition pod.cpp:483
void setSensorMask(const PiercedStorage< bool > &mask, VolumeKernel *mesh=nullptr)
Definition pod.cpp:672
WriteMode
Output Write Mode of the POD object. It defines the amount of information written by the POD object.
Definition pod.hpp:67
void setMemoryMode(MemoryMode mode)
Definition pod.cpp:505
double getErrorThreshold()
Definition pod.cpp:356
void setDirectory(const std::string &directory)
Definition pod.cpp:180
double getEnergyLevel()
Definition pod.cpp:336
const std::string & getName()
Definition pod.cpp:170
RunMode getRunMode()
Definition pod.cpp:566
POD(MPI_Comm comm=MPI_COMM_WORLD)
Definition pod.cpp:67
void restoreDecomposition()
Definition pod.cpp:1051
ReconstructionMode getReconstructionMode()
Definition pod.cpp:623
void dump()
Definition pod.cpp:855
std::vector< std::string > getFieldsNames()
Definition pod.cpp:749
MemoryMode getMemoryMode()
Definition pod.cpp:530
void setExpert(bool mode=true)
Definition pod.cpp:660
void setUseMean(bool flag)
Definition pod.cpp:493
void addReconstructionSnapshot(const std::string &directory, const std::string &name)
Definition pod.cpp:282
void removeLeave1outSnapshot(const std::string &directory, const std::string &name)
Definition pod.cpp:243
void evalModes()
Definition pod.cpp:2084
MeshType
Type of the Mesh used to compute the POD basis.
Definition pod.hpp:96
ReconstructionMode
Mode of Reconstruction of fields by using the POD basis.
Definition pod.hpp:77
MeshType getMeshType()
Definition pod.cpp:470
const pod::PODMode & getMean()
Definition pod.cpp:780
MemoryMode
Memory Mode of the POD object. It defines the use of the memory resources.
Definition pod.hpp:49
void setSnapshots(const std::vector< pod::SnapshotFile > &database)
Definition pod.cpp:230
void setWriteMode(WriteMode mode)
Definition pod.cpp:576
ErrorMode getErrorMode()
Definition pod.cpp:648
std::size_t getListIDInternalCount()
Definition pod.cpp:816
void setReconstructionMode(ReconstructionMode mode)
Definition pod.cpp:598
ErrorMode
Mode of Error evaluation of a reconstructed fields by the POD basis.
Definition pod.hpp:86
void dumpDecomposition()
Definition pod.cpp:904
void restore()
Definition pod.cpp:864
void setEnergyLevel(double energy)
Definition pod.cpp:326
void setModeCount(std::size_t nmodes)
Definition pod.cpp:304
void setName(const std::string &name)
Definition pod.cpp:160
WriteMode getWriteMode()
Definition pod.cpp:587
void setErrorMode(ErrorMode mode)
Definition pod.cpp:635
void evalDecomposition()
Definition pod.cpp:873
void setMesh(const std::string &directory, const std::string &name)
Definition pod.cpp:443
void evalMeanMesh()
Definition pod.cpp:1200
void evalEigen()
Definition pod.cpp:1973
std::vector< std::vector< double > > getReconstructionCoeffs()
Definition pod.cpp:800
void addSnapshot(const std::string &directory, const std::string &name)
Definition pod.cpp:208
RunMode
Run Mode of the POD object. It defines if the POD basis has to be computed or restored.
Definition pod.hpp:58
PiercedVector< Cell > & getCells()
VTKUnstructuredGrid & getVTK()
void setVTKWriteTarget(WriteTarget targetCells)
virtual long getCellCount() const
bool dump(std::ostream &stream)
void write(VTKWriteMode mode=VTKWriteMode::DEFAULT)
long getInternalCellCount() const
void setStaticKernel(const PiercedKernel< id_t > *kernel)
void unsetKernel(bool release=true)
Metafunction for generating a pierced storage.
__PS_POINTER__ rawData(std::size_t pos, std::size_t offset=0)
void dump(std::ostream &stream) const
void setDirectory(const std::string &)
Definition VTK.cpp:129
VTKField & addData(VTKField &&field)
Definition VTK.cpp:281
void removeData(const std::string &)
Definition VTK.cpp:330
void setName(const std::string &)
Definition VTK.cpp:119
The VolOctree defines a Octree patch.
Definition voloctree.hpp:37
The VolumeKernel class provides an interface for defining volume patches.
void sum(const std::array< T, d > &x, T1 &s)
double norm(const std::array< T, d > &x, int p)
T dotProduct(const std::array< T, d > &x, const std::array< T, d > &y)
std::array< T, d > max(const std::array< T, d > &x, const std::array< T, d > &y)
std::array< T, d > min(const std::array< T, d > &x, const std::array< T, d > &y)
void write(std::ostream &stream, const std::vector< bool > &container)
Logger & cout(log::Level defaultSeverity, log::Visibility defaultVisibility)
Definition logger.cpp:1705
Logger & info(log::Visibility defaultVisibility)
Definition logger.cpp:1847
The PODfield structure is used to store the fields inside POD classes.
std::unique_ptr< pod::ScalarStorage > scalar
std::unique_ptr< PiercedStorage< bool > > mask
std::unique_ptr< pod::VectorStorage > vector
void setMesh(VolumeKernel *lmesh)
VolumeKernel * mesh
The PODMode structure is used to store the modes inside pod classes.
std::unique_ptr< pod::VectorStorage > vector
std::unique_ptr< pod::ScalarStorage > scalar
The SnapFile structure is used to store the file names inside POD classes.
--- layout: doxygen_footer ---