Loading...
Searching...
No Matches
ITHACAnorm.C
Go to the documentation of this file.
1/*---------------------------------------------------------------------------*\
2 ██╗████████╗██╗ ██╗ █████╗ ██████╗ █████╗ ███████╗██╗ ██╗
3 ██║╚══██╔══╝██║ ██║██╔══██╗██╔════╝██╔══██╗ ██╔════╝██║ ██║
4 ██║ ██║ ███████║███████║██║ ███████║█████╗█████╗ ██║ ██║
5 ██║ ██║ ██╔══██║██╔══██║██║ ██╔══██║╚════╝██╔══╝ ╚██╗ ██╔╝
6 ██║ ██║ ██║ ██║██║ ██║╚██████╗██║ ██║ ██║ ╚████╔╝
7 ╚═╝ ╚═╝ ╚═╝ ╚═╝╚═╝ ╚═╝ ╚═════╝╚═╝ ╚═╝ ╚═╝ ╚═══╝
8
9 * In real Time Highly Advanced Computational Applications for Finite Volumes
10 * Copyright (C) 2017 by the ITHACA-FV authors
11-------------------------------------------------------------------------------
12
13License
14 This file is part of ITHACA-FV
15
16 ITHACA-FV is free software: you can redistribute it and/or modify
17 it under the terms of the GNU Lesser General Public License as published by
18 the Free Software Foundation, either version 3 of the License, or
19 (at your option) any later version.
20
21 ITHACA-FV is distributed in the hope that it will be useful,
22 but WITHOUT ANY WARRANTY; without even the implied warranty of
23 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
24 GNU Lesser General Public License for more details.
25
26 You should have received a copy of the GNU Lesser General Public License
27 along with ITHACA-FV. If not, see <http://www.gnu.org/licenses/>.
28\*---------------------------------------------------------------------------*/
29
30#include "ITHACAnorm.H"
31
34
35// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
36
37namespace ITHACAutilities
38{
39
40template<typename T>
41Eigen::MatrixXd dot_product_POD(PtrList<T>& v, PtrList<T>& w,
42 const word& hilbertSpacePOD,
43 const double& weightBC,
44 const word& patchBC,
45 const double& weightH1)
46{
47 Eigen::MatrixXd matrix_dot_product = Eigen::MatrixXd::Zero(v.size(),w.size());
48 if (hilbertSpacePOD == "L2")
49 {
50 matrix_dot_product = getMassMatrix(v,w);
51 }
52 else if (hilbertSpacePOD == "dL2"){
53 Eigen::VectorXd V = getMassMatrixFV(v[0]).array().pow(4.0/3.0);
54 V = V.array().inverse();
55 matrix_dot_product = getMassMatrix(v,w,V);
56 }
57 else
58 {
59 Info << "Error: hilbertSpacePOD " << hilbertSpacePOD << " is not valid." << endl;
60 Info << "NOT CODED YET : dot_product_POD is available for L2 only." << endl;
61 abort();
62 }
63 return matrix_dot_product;
64}
65// Specialization
66template Eigen::MatrixXd dot_product_POD(PtrList<volTensorField>& v, PtrList<volTensorField>& w,
67 const word& hilbertSpacePOD,
68 const double& weightBC,
69 const word& patchBC,
70 const double& weightH1);
71template Eigen::MatrixXd dot_product_POD(PtrList<volVectorField>& v, PtrList<volVectorField>& w,
72 const word& hilbertSpacePOD,
73 const double& weightBC,
74 const word& patchBC,
75 const double& weightH1);
76template Eigen::MatrixXd dot_product_POD(PtrList<volScalarField>& v, PtrList<volScalarField>& w,
77 const word& hilbertSpacePOD,
78 const double& weightBC,
79 const word& patchBC,
80 const double& weightH1);
81
82
83//Separation because dot product H1 can't be applied when using volTensorFields
84double dot_product_POD(const volScalarField& v, const volScalarField& w,
85 const word& hilbertSpacePOD,
86 const double& weightBC,
87 const word& patchBC,
88 const double& weightH1)
89{
90 double integral(0);
91 if (hilbertSpacePOD == "L2" || hilbertSpacePOD == "dL2")
92 {
93 integral = dot_product_L2(v,w);
94 }
95 else if (hilbertSpacePOD == "L2wBC")
96 {
97 integral = dot_product_L2wBC(v,w,weightBC, patchBC);
98 }
99 else if (hilbertSpacePOD == "H1")
100 {
101 integral = dot_product_H1(v,w);
102 }
103 else if (hilbertSpacePOD == "wH1")
104 {
105 integral = dot_product_H1(v,w,weightH1);
106 }
107 else
108 {
109 Info << "Error: hilbertSpacePOD " << hilbertSpacePOD << " is not valid." << endl;
110 Info << "dot_product_POD is available for L2, L2wBC, H1 and wH1 only." << endl;
111 abort();
112 }
113 return integral;
114}
115
116double dot_product_POD(const volVectorField& v, const volVectorField& w, const word& hilbertSpacePOD, const double& weightBC, const word& patchBC, const double& weightH1)
117{
118 double integral(0);
119 if (hilbertSpacePOD == "L2")
120 {
121 integral = dot_product_L2(v,w);
122 }
123 else if (hilbertSpacePOD == "L2wBC")
124 {
125 integral = dot_product_L2wBC(v,w,weightBC, patchBC);
126 }
127 else if (hilbertSpacePOD == "H1")
128 {
129 integral = dot_product_H1(v,w);
130 }
131 else if (hilbertSpacePOD == "wH1")
132 {
133 integral = dot_product_H1(v,w,weightH1);
134 }
135 else
136 {
137 Info << "Error: hilbertSpacePOD " << hilbertSpacePOD << " is not valid." << endl;
138 Info << "dot_product_POD is available for L2, L2wBC, H1 and wH1 only." << endl;
139 abort();
140 }
141 return integral;
142}
143
144double dot_product_POD(const volTensorField& v, const volTensorField& w,
145 const word& hilbertSpacePOD,
146 const double& weightBC,
147 const word& patchBC,
148 const double& weightH1)
149{
150 double integral(0);
151 if (hilbertSpacePOD == "L2")
152 {
153 integral = dot_product_L2(v,w);
154 }
155 else if (hilbertSpacePOD == "L2wBC")
156 {
157 integral = dot_product_L2wBC(v,w,weightBC, patchBC);
158 }
159 else if ((hilbertSpacePOD == "H1")||(hilbertSpacePOD == "wH1"))
160 {
161 Info << "Error : dot_product_POD cannot be computed between volTensorFields with the hilbertSpacePOD =" <<hilbertSpacePOD << " ." << endl;
162 abort();
163 }
164 else
165 {
166 Info << "Error: hilbertSpacePOD " << hilbertSpacePOD << " is not valid." << endl;
167 Info << "dot_product_POD is available for L2, L2wBC, H1 and wH1 only." << endl;
168 abort();
169 }
170 return integral;
171}
172
173template<typename T>
174double dot_product_H1(const T& v, const T& w, const double& weightH1)
175{
176 return ( dot_product_L2(v,w) + weightH1 * dot_product_L2(fvc::grad(v),fvc::grad(w)) );
177}
178// Specialization
179template double dot_product_H1(const volVectorField& v, const volVectorField& w, const double& weightH1);
180template double dot_product_H1(const volScalarField& v, const volScalarField& w, const double& weightH1);
181
182double dot_product_L2(const volVectorField& v, const volVectorField& w)
183{
184 return fvc::domainIntegrate(v & w).value();
185
186}
187
188double dot_product_L2(const volScalarField& v, const volScalarField& w)
189{
190 return fvc::domainIntegrate(v * w).value();
191}
192
193
194double dot_product_L2(const volTensorField& v, const volTensorField& w)
195{
196 return fvc::domainIntegrate(v && w).value();
197}
198
199//Dot product at a boundary patch
200double dot_product_patch(const Eigen::VectorXd& f1BC_i,const Eigen::VectorXd& f2BC_i, const scalarField& AreaFace, const int& d)
201{
202 double dot_prod_patch=0.;
203 double dx = 1.;
204 //Loop for the boundary cells
205 for (label k = 0; k < f1BC_i.size()/d; k++)
206 {
207 double productBC=0.;
208 //Loop for the coordinates separated in the Eigen::VectorXd
209 for (label i=0;i<d;i++)
210 {
211 productBC+=f1BC_i(k+i*f1BC_i.size()/d) * f2BC_i(k+i*f1BC_i.size()/d);
212 }
213 dot_prod_patch+=productBC* AreaFace[k] * dx;
214 }
215 return dot_prod_patch;
216}
217
218template<typename T>
219// Dot product at the boundary
220double dot_product_boundary(const T& v,const T& w, const word& patchBC)
221{
222 T f1 = v;
223 T f2 = w;
224 double dot_prod_boundary=0.;
225
226 int NBC = f1.boundaryField().size();
227 List<Eigen::VectorXd> f1BC = Foam2Eigen::field2EigenBC(f1);
228 List<Eigen::VectorXd> f2BC = Foam2Eigen::field2EigenBC(f2);
229
230 label ind = f1.mesh().boundaryMesh().findPatchID(patchBC);
231 //Dimension of the field to separate the coordinates after Eigen2Field
232 int d = dimensionField(f1);
233 //List of indexes of the considered boundary patches
234 List<label> l;
235
236 if (ind==-1)
237 {
238 for (label i=0;i<NBC;i++)
239 {
240 l.append(i);
241 }
242 }
243
244 else
245 {
246 l.append(ind);
247 }
248 //Loop for the boundary patches
249 for (label g = 0; g < l.size(); g++)
250 {
251 // Create a scalar field with area value
252 scalarField AreaFace = f1.mesh().magSf().boundaryField()[l[g]];
253 // Compute the dot product at each patch
254 dot_prod_boundary+=dot_product_patch(f1BC[l[g]],f2BC[l[g]],AreaFace,d);
255 }
256 return dot_prod_boundary;
257}
258template double dot_product_boundary(const volTensorField& v, const volTensorField& w, const word& patchBC);
259template double dot_product_boundary(const volVectorField& v, const volVectorField& w, const word& patchBC);
260template double dot_product_boundary(const volScalarField& v, const volScalarField& w, const word& patchBC);
261
262template<typename T>
263// Dot product L2wBC : uses dot_product_L2 at the interior and dot_product_boundary at the boundary with a weight weightBC
264double dot_product_L2wBC(const T& v, const T& w, const double& weightBC, const word& patchBC)
265{
266 double dot_prod;
267
268 //Compute the dot product at the boundary
269 double dp_boundary = dot_product_boundary(v,w,patchBC);
270
271 //Add the dot product at the boundary to the L2 one inside of the domain
272 dot_prod=dp_boundary*weightBC+dot_product_L2(v,w);
273 return dot_prod;
274}
275
276template double dot_product_L2wBC(const volTensorField& v, const volTensorField& w, const double& weightBC, const word& patchBC);
277template double dot_product_L2wBC(const volVectorField& v, const volVectorField& w, const double& weightBC, const word& patchBC);
278template double dot_product_L2wBC(const volScalarField& v, const volScalarField& w, const double& weightBC, const word& patchBC);
279
280template<typename T>
281double norm_L2wBC(const T& v, const double& weightBC, const word& patchBC)
282{
283 return std::sqrt(dot_product_L2wBC(v,v, weightBC, patchBC));
284}
285
286template double norm_L2wBC(const volTensorField& v, const double& weightBC, const word& patchBC);
287template double norm_L2wBC(const volVectorField& v, const double& weightBC, const word& patchBC);
288template double norm_L2wBC(const volScalarField& v, const double& weightBC, const word& patchBC);
289
290template<typename T>
291double norm_POD(const T& v, const word& hilbertSpacePOD, const double& weightBC, const word& patchBC, const double& weightH1)
292{
293 return std::sqrt(dot_product_POD(v,v, hilbertSpacePOD, weightBC, patchBC, weightH1));
294}
295// Specialization
296template double norm_POD(const volVectorField& v, const word& hilbertSpacePOD, const double& weightBC, const word& patchBC, const double& weightH1);
297template double norm_POD(const volScalarField& v, const word& hilbertSpacePOD, const double& weightBC, const word& patchBC, const double& weightH1);
298
299template<typename T>
300double L2Norm(const T v)
301{
302 return Foam::sqrt(dot_product_L2(v,v));
303}
304
305// Specialization
306template double L2Norm(const volTensorField& v);
307template double L2Norm(const volVectorField& v);
308template double L2Norm(const volScalarField& v);
309template double L2Norm(const volTensorField v);
310template double L2Norm(const volVectorField v);
311template double L2Norm(const volScalarField v);
312template double L2Norm(const tmp<volTensorField> v);
313template double L2Norm(const tmp<volVectorField> v);
314template double L2Norm(const tmp<volScalarField> v);
315
316
317template<>
318double LinfNorm(GeometricField<scalar, fvPatchField, volMesh>& field)
319{
320 double a;
321 a = Foam::max(Foam::sqrt(field.internalField() *
322 field.internalField())).value();
323 return a;
324}
325
326template<>
327double LinfNorm(GeometricField<vector, fvPatchField, volMesh>& field)
328{
329 double a;
330 Info << "LinfNorm(GeometricField<vector, fvPatchField, volMesh>& field) is still to be implemented"
331 << endl;
332 exit(12);
333 return a;
334}
335
336template<>
337double H1Seminorm(GeometricField<scalar, fvPatchField, volMesh>& field)
338{
339 double a;
340 a = Foam::sqrt(fvc::domainIntegrate(fvc::grad(field) & fvc::grad(
341 field)).value());
342 return a;
343}
344
345template<>
346double H1Seminorm(GeometricField<vector, fvPatchField, volMesh>& field)
347{
348 double a;
349 a = Foam::sqrt(fvc::domainIntegrate(fvc::grad(field)
350 && fvc::grad(field)).value());
351 return a;
352}
353
354template<class Type, template<class> class PatchField, class GeoMesh>
355double frobNorm(GeometricField<Type, PatchField, GeoMesh>& field)
356{
357 double norm(0);
358 Eigen::VectorXd vF = Foam2Eigen::field2Eigen(field);
359 norm = vF.norm();
360 return norm;
361}
362template double frobNorm(GeometricField<scalar, fvPatchField, volMesh>& field);
363template double frobNorm(GeometricField<scalar, fvsPatchField, surfaceMesh>& field);
364template double frobNorm(GeometricField<vector, fvPatchField, volMesh>& field);
365
366double L2normOnPatch(fvMesh& mesh, volScalarField& field,
367 word patch)
368{
369 double L2 = 0;
370 //Access the mesh information for the boundary
371 label patchID = mesh.boundaryMesh().findPatchID(patch);
372 const polyPatch& cPatch = mesh.boundaryMesh()[patchID];
373 //List of cells close to a boundary
374 const labelUList& faceCells = cPatch.faceCells();
375 forAll(cPatch, faceI)
376 {
377 //id of the owner cell having the face
378 label faceOwner = faceCells[faceI] ;
379 scalar faceArea = mesh.magSf().boundaryField()[patchID][faceI];
380 L2 += faceArea * field[faceOwner] * field[faceOwner];
381 }
382
383 return Foam::sqrt(L2);
384}
385
386double L2productOnPatch(fvMesh& mesh, List<scalar>& field1,
387 List<scalar>& field2, word patch)
388{
389 M_Assert(field1.size() == field2.size(),
390 "The two fields do not have the same size, code will abort");
391 double L2 = 0;
392 //Access the mesh information for the boundary
393 label patchID = mesh.boundaryMesh().findPatchID(patch);
394 const polyPatch& cPatch = mesh.boundaryMesh()[patchID];
395 M_Assert(field1.size() == cPatch.size(),
396 "The filds must have the same size of the patch, code will abort");
397 forAll(cPatch, faceI)
398 {
399 scalar faceArea = mesh.magSf().boundaryField()[patchID][faceI];
400 L2 += faceArea * field1[faceI] * field2[faceI];
401 }
402
403 return L2;
404}
405
406double LinfNormOnPatch(fvMesh& mesh, volScalarField& field,
407 word patch)
408{
409 double Linf = 0;
410 //Access the mesh information for the boundary
411 label patchID = mesh.boundaryMesh().findPatchID(patch);
412 const polyPatch& cPatch = mesh.boundaryMesh()[patchID];
413 //List of cells close to a boundary
414 const labelUList& faceCells = cPatch.faceCells();
415 forAll(cPatch, faceI)
416 {
417 label faceOwner = faceCells[faceI] ;
418
419 if (faceI == 0)
420 {
421 Linf = std::abs(field[faceOwner]);
422 }
423 else if (std::abs(field[faceOwner]) > Linf)
424 {
425 Linf = std::abs(field[faceOwner]);
426 }
427 }
428
429 return Linf;
430}
431
432double integralOnPatch(fvMesh& mesh, volScalarField& field,
433 word patch)
434{
435 double integral = 0;
436 //Access the mesh information for the boundary
437 label patchID = mesh.boundaryMesh().findPatchID(patch);
438 const polyPatch& cPatch = mesh.boundaryMesh()[patchID];
439 //List of cells close to a boundary
440 const labelUList& faceCells = cPatch.faceCells();
441 forAll(cPatch, faceI)
442 {
443 //id of the owner cell having the face
444 label faceOwner = faceCells[faceI] ;
445 scalar faceArea = mesh.magSf().boundaryField()[patchID][faceI];
446 integral += faceArea * field[faceOwner];
447 }
448
449 return integral;
450}
451
452double integralOnPatch(fvMesh& mesh, List<scalar> field,
453 word patch)
454{
455 double integral = 0;
456 //Access the mesh information for the boundary
457 label patchID = mesh.boundaryMesh().findPatchID(patch);
458 const polyPatch& cPatch = mesh.boundaryMesh()[patchID];
459 //List of cells close to a boundary
460 const labelUList& faceCells = cPatch.faceCells();
461 int patchSize = mesh.magSf().boundaryField()[patchID].size();
462 std::string message = "The input list (size = " + std::to_string(field.size())
463 + ") must have the same size of the patch mesh (size = "
464 + std::to_string(patchSize) + ")";
465 M_Assert( patchSize == field.size(), message.c_str());
466 forAll(cPatch, faceI)
467 {
468 //id of the owner cell having the face
469 label faceOwner = faceCells[faceI] ;
470 scalar faceArea = mesh.magSf().boundaryField()[patchID][faceI];
471 integral += faceArea * field[faceI];
472 }
473
474 return integral;
475}
476
477
478}
Header file of the ITHACAnorm file.
static List< Eigen::VectorXd > field2EigenBC(GeometricField< scalar, PatchField, GeoMesh > &field)
Convert an OpenFOAM scalar field to a List of Eigen Vectors, one for each boundary.
Definition Foam2Eigen.C:253
static Eigen::MatrixXd field2Eigen(GeometricField< Type, PatchField, GeoMesh > &field)
Convert a vector OpenFOAM field into an Eigen Vector.
Namespace to implement some useful assign operation of OF fields.
double norm_L2wBC(const T &v, const double &weightBC, const word &patchBC)
Compute the norm using the L2 dot product of v at the boundaries.
Definition ITHACAnorm.C:281
int dimensionField(const volTensorField &v)
Return the dimension of a volTensorField.
double LinfNormOnPatch(fvMesh &mesh, volScalarField &field, word patch)
Evaluate the Linf norm of a field on a boundary patch.
Definition ITHACAnorm.C:406
double dot_product_boundary(const T &v, const T &w, const word &patchBC)
Perform the L2 dot product of v and w at a given boundary.
Definition ITHACAnorm.C:220
Eigen::MatrixXd dot_product_POD(PtrList< T > &v, PtrList< T > &w, const word &hilbertSpacePOD, const double &weightBC, const word &patchBC, const double &weightH1)
Perform the dot product of two PtrList of type T.
Definition ITHACAnorm.C:41
double integralOnPatch(fvMesh &mesh, volScalarField &field, word patch)
Evaluate the integral on a patch.
Definition ITHACAnorm.C:432
double L2normOnPatch(fvMesh &mesh, volScalarField &field, word patch)
Evaluate the L2 norm of a field on a boundary patch.
Definition ITHACAnorm.C:366
double frobNorm(GeometricField< Type, PatchField, GeoMesh > &field)
Evaluate the Frobenius norm of a field.
Definition ITHACAnorm.C:355
Eigen::VectorXd getMassMatrixFV(GeometricField< Type, PatchField, GeoMesh > &snapshot)
Gets a vector containing the volumes of each cell of the mesh.
double dot_product_patch(const Eigen::VectorXd &f1BC_i, const Eigen::VectorXd &f2BC_i, const scalarField &AreaFace, const int &d)
Perform the L2 dot product of v and w at a given boundary patch.
Definition ITHACAnorm.C:200
double L2Norm(const T v)
Compute the L2 norm of v.
Definition ITHACAnorm.C:300
Eigen::MatrixXd getMassMatrix(PtrList< GeometricField< Type, PatchField, GeoMesh > > &modes, label Nmodes, bool consider_volumes)
Gets the mass matrix using the eigen routine.
double dot_product_L2(const volVectorField &v, const volVectorField &w)
Perform the L2 dot product of v and w.
Definition ITHACAnorm.C:182
double norm_POD(const T &v, const word &hilbertSpacePOD, const double &weightBC, const word &patchBC, const double &weightH1)
Compute the norm of v.
Definition ITHACAnorm.C:291
double dot_product_H1(const T &v, const T &w, const double &weightH1)
Perform the H1 dot product of v and w.
Definition ITHACAnorm.C:174
double L2productOnPatch(fvMesh &mesh, List< scalar > &field1, List< scalar > &field2, word patch)
Evaluate the L2 inner product between two scalarLists.
Definition ITHACAnorm.C:386
double dot_product_L2wBC(const T &v, const T &w, const double &weightBC, const word &patchBC)
Perform the L2 dot product of v and w at the boundaries.
Definition ITHACAnorm.C:264