Loading...
Searching...
No Matches
POD_example_00005.cpp
1/*---------------------------------------------------------------------------*\
2 *
3 * bitpit
4 *
5 * Copyright (C) 2015-2023 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
41#include <array>
42#include <vector>
43#if BITPIT_ENABLE_MPI
44#include <mpi.h>
45#endif
46
47#include "pod.hpp"
48#include "pod_voloctree.hpp"
49#include "pod_kernel.hpp"
50#include "piercedStorage.hpp"
51
52using namespace bitpit;
53
54/*
55 * Build a PODField object with difference between two PODField objects.
56 *
57 * \param[in] field1, minuend PODField.
58 * \param[in] field2, subtrahend PODField.
59 * \param[in] listActIds, list of active ids of the mesh of field1 and field2.
60 * \param[out] errorField, PODField with the difference between field1 and field2.
61 */
62pod::PODField buildErrorField (pod::PODField &field1, pod::PODField &field2, const std::unordered_set<long> listActIds)
63{
64 pod::PODField errorField;
65 errorField.scalar = std::unique_ptr<pod::ScalarStorage>(new pod::ScalarStorage(2, &field1.mesh->getCells()));
66 errorField.vector = std::unique_ptr<pod::VectorStorage>(new pod::VectorStorage(1, &field1.mesh->getCells()));
67 errorField.scalar->fill(0.0);
68 errorField.vector->fill(std::array<double, 3>{{0.0, 0.0, 0.0}});
69 errorField.mask = std::unique_ptr<PiercedStorage<bool>>(new PiercedStorage<bool>(1, &field1.mesh->getCells()));
70 errorField.mask->fill(0.0);
71 errorField.setMesh(field1.mesh);
72 for (long id : listActIds) {
73 for (std::size_t isf = 0; isf < 2; ++isf) {
74 double field1s = field1.scalar->at(id, isf);
75 double field2s = field2.scalar->at(id, isf);
76 errorField.scalar->at(id, isf) += field1s-field2s;
77 }
78 std::array<double,3> field1sv = field1.vector->at(id,0);
79 std::array<double,3> field2sv = field2.vector->at(id,0);
80 errorField.vector->at(id, 0) += field1sv-field2sv;
81 errorField.mask->at(id) = 1;
82 }
83 return errorField;
84}
85
86/*
87 * Build a PODField object with the relative difference between two PODField objects.
88 *
89 * \param[in] field1, minuend PODField.
90 * \param[in] field2, subtrahend PODField.
91 * \param[in] pod, POD object over which the two fields have been defined.
92 * \param[in] norm_type, L2 or Linf
93 * \param[out] errorField, PODField with the difference between field1 and field2.
94 */
95pod::PODField buildRelErrorField (pod::PODField &field1, pod::PODField &field2, POD &pod, std::string norm_type )
96{
97 pod::PODField errorField;
98 errorField.scalar = std::unique_ptr<pod::ScalarStorage>(new pod::ScalarStorage(2, &field1.mesh->getCells()));
99 errorField.vector = std::unique_ptr<pod::VectorStorage>(new pod::VectorStorage(1, &field1.mesh->getCells()));
100 errorField.scalar->fill(0.0);
101 errorField.vector->fill(std::array<double, 3>{{0.0, 0.0, 0.0}});
102 errorField.mask = std::unique_ptr<PiercedStorage<bool>>(new PiercedStorage<bool>(1, &field1.mesh->getCells()));
103 errorField.mask->fill(0.0);
104 errorField.setMesh(field1.mesh);
105 std::vector<double> vec;
106 if (norm_type == "L2") {
107 vec = pod.fieldsl2norm(field1);
108 }
109 else if (norm_type == "Linf") {
110 vec = pod.fieldsMax(field1);
111 }
112 const std::unordered_set<long> & listActIds = pod.getListActiveIDs();
113 for (long id : listActIds) {
114 for (std::size_t isf = 0; isf < 2; ++isf) {
115 double field1s = field1.scalar->at(id, isf);
116 double field2s = field2.scalar->at(id, isf);
117 errorField.scalar->at(id, isf) += (field1s-field2s)/vec[isf];
118 }
119 std::array<double,3> field1sv = field1.vector->at(id,0);
120 std::array<double,3> field2sv = field2.vector->at(id,0);
121 errorField.vector->at(id, 0) += (field1sv-field2sv)/vec[2];
122 errorField.mask->at(id) = 1;
123 }
124 return errorField;
125}
126
127
128/*
129 * Print the L2 norm of each field of a PODField object.
130 *
131 * \param[in] field, PODField object.
132 * \param[in] pod, POD object defined on the same mesh.
133 * \param[in] field_name, string of the field name to display.
134 */
135void printL2norm (pod::PODField &field, POD &pod, std::string field_name)
136{
137 std::vector<double> vecL2 = pod.fieldsl2norm(field);
138 std::vector<std::string> scalarNames = pod.getScalarNames();
139 std::vector<std::array<std::string,3>> vectorNames= pod.getVectorNames();
140 int N = scalarNames.size();
141 for (int i=0; i<N; i++) {
142 std::cout << "L2 norm of " << field_name << " " << scalarNames[i] << " is "<< vecL2[i] << std::endl;
143 }
144 int M = vectorNames.size();
145 for (int i=N; i<N+M; i++) {
146 std::cout << "L2 norm of " << field_name << " " << vectorNames[i-N][0].substr(0,vectorNames[i-N][0].size()-2) << " is "<< vecL2[i] << std::endl;
147 }
148}
149
150/*
151 * Print the L infinity norm of each field of a PODField object.
152 *
153 * \param[in] field, PODField object.
154 * \param[in] pod, POD object defined on the same mesh.
155 * \param[in] field_name, string of the field name to display.
156 */
157void printLinfnorm (pod::PODField &field, POD &pod, std::string field_name)
158{
159 std::vector<double> vecLinf = pod.fieldsMax(field);
160 std::vector<std::string> scalarNames = pod.getScalarNames();
161 std::vector<std::array<std::string,3>> vectorNames= pod.getVectorNames();
162 int N = scalarNames.size();
163 for (int i=0; i<N; i++) {
164 std::cout << "L infinity norm of " << field_name << " " << scalarNames[i] << " is "<< vecLinf[i] << std::endl;
165 }
166 int M = vectorNames.size();
167 for (int i=N; i<N+M; i++) {
168 std::cout << "L infinity norm of " << field_name << " " << vectorNames[i-N][0].substr(0,vectorNames[i-N][0].size()-2) << " is "<< vecLinf[i] << std::endl;
169 }
170}
171
172/*
173 * Print a matrix.
174 *
175 * \param[in] mat, matrix of size M rows times N columns.
176 */
177void printMat (std::vector<std::vector<double>> mat)
178{
179 std::cout << "mat = " << std::endl;
180 size_t M = mat.size();
181 size_t N = mat[0].size();
182 for (size_t i=0; i<M; i++) {
183 for (size_t j=0; j<N; j++) {
184 if (j == 0) {
185 std::cout << "[ "<< mat[i][j] ;
186 }
187 else if (j==(N-1)) {
188 std::cout << " , " << mat[i][j] << " ]" << std::endl;
189 }
190 else {
191 std::cout << " , " << mat[i][j] ;
192 }
193 if (N==1) {
194 std::cout << " ]" << std::endl;
195 }
196 }
197 }
198}
199
203void run()
204{
206 POD pod;
207
209 for (int i=0; i<6; i++) {
210 pod.addSnapshot("./data", "test_set2."+std::to_string(i));
211 }
212
214 pod.setMeshType(POD::MeshType::VOLOCTREE);
215 pod.setStaticMesh(true);
216 pod.setErrorMode(POD::ErrorMode::SINGLE);
217 pod.setWriteMode(POD::WriteMode::DEBUG);
218 pod.setMemoryMode(POD::MemoryMode::MEMORY_NORMAL);
219 pod.setEnergyLevel(99.00);
220 pod.setUseMean(false);
221 pod.setDirectory("pod");
222 pod.setName("pod.test.solver");
223
225 pod.evalDecomposition();
226
228 const pod::SnapshotFile snap0 ("./data", "test_set2.0");
229 pod::PODField solution0;
230 pod.readSnapshot(snap0, solution0);
231 pod.write(solution0,"solution0");
232
234 std::vector<std::vector<double>> recostructionCoeffs = pod.projectField(solution0);
235 std::cout << "POD coefficients of the first snapshot " << std::endl;
236 printMat(recostructionCoeffs);
237 pod::PODField recon0;
238 pod.reconstructFields(recostructionCoeffs, recon0);
239 pod.write(recon0,"reconstruction0");
240
242 const std::unordered_set<long> & listActIds = pod.getListActiveIDs();
243 pod::PODField error0 = buildErrorField(solution0, recon0, listActIds);
244 pod::PODField error0relL2 = buildRelErrorField(solution0, recon0, pod, "L2");
245 pod::PODField error0relLinf = buildRelErrorField(solution0, recon0, pod, "Linf");
246 printL2norm(solution0,pod,"solution");
247 printLinfnorm(solution0,pod,"solution");
248 printL2norm(error0,pod,"reconstruction error");
249 printLinfnorm(error0,pod,"reconstruction error");
250 printL2norm(error0relL2,pod,"relative error");
251 printLinfnorm(error0relLinf,pod,"relative error");
252
254 POD pod2;
255 // Set pod2.
256 pod2.setWriteMode(POD::WriteMode::DEBUG);
257 pod2.setUseMean(false);
258 pod2.setDirectory("pod");
259 pod2.setName("pod.test.solver");
260 // restore modes.
261 pod2.restore();
262 std::cout << "the number of modes of pod 2 is " << pod2.getModeCount() << std::endl;
263 std::cout << "the number of modes of pod is " << pod.getModeCount() << std::endl;
264 // get modes from pod2.
265 const std::vector<pod::PODMode> &vec_pod_modes = pod2.getModes();
266 // get list of active ids from pod2
267 const std::unordered_set<long> & listActIds_2 = pod2.getListActiveIDs();
268 std::cout << "Number of active cells for pod2 object = ";
269 std::cout << listActIds_2.size() << std::endl;
270 // compare with list of active ids from pod1
271 std::cout << "Number of active cells for pod object = ";
272 std::cout << listActIds.size() << std::endl;
273
275 // get reconstruction coefficients used for the computation of recon0
276 double coeff11 = recostructionCoeffs[0][0];
277 double coeff12 = recostructionCoeffs[0][1];
278 double coeff21 = recostructionCoeffs[1][0];
279 double coeff22 = recostructionCoeffs[1][1];
280 double coeff31 = recostructionCoeffs[2][0];
281 double coeff32 = recostructionCoeffs[2][1];
282 double scalar1_diff = 0;
283 double scalar2_diff = 0;
284 double vector1_diff = 0;
285 for (long id : listActIds_2) {
286 double mode1 = vec_pod_modes[0].scalar->at(id, 0);
287 double mode2 = vec_pod_modes[1].scalar->at(id, 0);
288 scalar1_diff += coeff11*mode1+coeff12*mode2-recon0.scalar->at(id, 0);
289 mode1 = vec_pod_modes[0].scalar->at(id, 1);
290 mode2 = vec_pod_modes[1].scalar->at(id, 1);
291 scalar2_diff += coeff21*mode1+coeff22*mode2-recon0.scalar->at(id, 1);
292 std::array<double,3> mode1v = vec_pod_modes[0].vector->at(id, 0);
293 std::array<double,3> mode2v = vec_pod_modes[1].vector->at(id, 0);
294 std::array<double,3> diffv = recon0.vector->at(id, 0);
295 diffv -= coeff31*mode1v+coeff32*mode2v;
296 vector1_diff += std::sqrt( dotProduct((diffv),(diffv)));
297 }
298 std::cout << " " << std::endl;
299 std::cout << "The absolute error between the reconstruction and the linear combination of the restored modes is " << std::endl;
300 std::cout << scalar1_diff << " for the first scalar field, " << std::endl;
301 std::cout << scalar2_diff << " for the second scalar field, "<< std::endl;
302 std::cout << vector1_diff << " for the first vector field. "<< std::endl;
303}
304
308int main(int argc, char *argv[])
309{
310#if BITPIT_ENABLE_MPI
311 MPI_Init(&argc,&argv);
312#endif
313
315 try {
316 run();
317 } catch (const std::exception &exception) {
318 log::cout() << exception.what();
319 exit(1);
320 }
321
322#if BITPIT_ENABLE_MPI
323 MPI_Finalize();
324#endif
325
326}
The POD (Proper Orthogonal Decomposition) class provides an interface for defining POD object.
Definition pod.hpp:41
std::size_t getModeCount()
Definition pod.cpp:315
std::vector< std::array< std::string, 3 > > getVectorNames()
Definition pod.cpp:738
const std::vector< pod::PODMode > & getModes()
Definition pod.cpp:790
std::vector< double > fieldsMax(pod::PODField &snap)
Definition pod.cpp:2618
std::vector< std::string > getScalarNames()
Definition pod.cpp:728
const std::unordered_set< long int > & getListActiveIDs()
Definition pod.cpp:808
void setMeshType(MeshType type)
Definition pod.cpp:390
void setStaticMesh(bool flag)
Definition pod.cpp:483
std::vector< double > fieldsl2norm(pod::PODField &snap)
Definition pod.cpp:2577
void setMemoryMode(MemoryMode mode)
Definition pod.cpp:505
void write(const pod::PODField &snap, std::string file_name) const
Definition pod.cpp:3080
void setDirectory(const std::string &directory)
Definition pod.cpp:180
void readSnapshot(const pod::SnapshotFile &snap, pod::PODField &fieldr)
Definition pod.cpp:2150
void reconstructFields(pod::PODField &field, pod::PODField &recon)
Definition pod.cpp:1631
void setUseMean(bool flag)
Definition pod.cpp:493
std::vector< std::vector< double > > projectField(pod::PODField &field)
Definition pod.cpp:1764
void setWriteMode(WriteMode mode)
Definition pod.cpp:576
void restore()
Definition pod.cpp:864
void setEnergyLevel(double energy)
Definition pod.cpp:326
void setName(const std::string &name)
Definition pod.cpp:160
void setErrorMode(ErrorMode mode)
Definition pod.cpp:635
void evalDecomposition()
Definition pod.cpp:873
void addSnapshot(const std::string &directory, const std::string &name)
Definition pod.cpp:208
PiercedVector< Cell > & getCells()
T dotProduct(const std::array< T, d > &x, const std::array< T, d > &y)
Logger & cout(log::Level defaultSeverity, log::Visibility defaultVisibility)
Definition logger.cpp:1705
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 SnapFile structure is used to store the file names inside POD classes.
--- layout: doxygen_footer ---