BELFEM 0.9.3
Berkeley Lab Finite Element Framework
Loading...
Searching...
No Matches
fn_FEM_recovery_inverse.hpp
Go to the documentation of this file.
1/*
2 * BELFEM -- The Berkeley Lab Finite Element Framework
3 * Copyright (c) 2026, The Regents of the University of California, through
4 * Lawrence Berkeley National Laboratory (subject to receipt of any required
5 * approvals from the U.S. Dept. of Energy). All rights reserved.
6 *
7 * Developers: Christian Messe, Gregory Giard
8 *
9 * See the top-level LICENSE file for the complete license and disclaimer.
10 */
11
12#ifndef BELFEM_FN_FEM_RECOVERY_INVERSE_HPP
13#define BELFEM_FN_FEM_RECOVERY_INVERSE_HPP
14
15#include <algorithm>
16#include <cmath>
17#include <limits>
18
19#include "typedefs.hpp"
20#include "assert.hpp"
21#include "cl_Vector.hpp"
22#include "cl_Matrix.hpp"
23#include "fn_dot.hpp"
24#include "fn_gesvd.hpp"
25
26namespace belfem
27{
28 namespace fem
29 {
58 inline bool
60 const Matrix< real > & aGram,
61 const real aMaxCondition,
62 Matrix< real > & aInverse,
63 real & aCondition,
64 Matrix< real > & aSchur,
65 Vector< real > & aCoupling,
66 Vector< real > & aSchurCoupling,
67 Matrix< real > & aSvdU,
68 Matrix< real > & aSvdVT,
69 Vector< real > & aSvdS,
70 Vector< real > & aSvdWork )
71 {
72 const uint tNumCoefficients = aGram.n_rows() ;
73 const uint tNumGradients = tNumCoefficients - 1 ;
74 const real tWeightSum = aGram( 0, 0 );
75
76 BELFEM_ASSERT( tNumCoefficients >= 2 && aGram.n_cols() == tNumCoefficients,
77 "recovery Gram matrix must be square with at least two coefficients" );
78 BELFEM_ASSERT( tWeightSum > 0.0, "recovery Gram matrix with patch weight %g", tWeightSum );
79 BELFEM_ASSERT( aMaxCondition > 0.0, "recovery truncation limit must be positive, is %g", aMaxCondition );
80 BELFEM_ASSERT( aSchur.n_rows() == tNumGradients && aSchur.n_cols() == tNumGradients
81 && aCoupling.length() == tNumGradients && aSchurCoupling.length() == tNumGradients
82 && aInverse.n_rows() == tNumCoefficients && aInverse.n_cols() == tNumCoefficients,
83 "recovery_block_inverse: scratch not sized for %u coefficients", tNumCoefficients );
84
85 for ( uint r=0; r<tNumGradients; ++r )
86 {
87 aCoupling( r ) = aGram( 0, r+1 ) / tWeightSum ;
88 }
89 for ( uint c=0; c<tNumGradients; ++c )
90 {
91 for ( uint r=0; r<tNumGradients; ++r )
92 {
93 aSchur( r, c ) = aGram( r+1, c+1 ) - aGram( r+1, 0 ) * aCoupling( c );
94 }
95 }
96
97 // the SVD of a symmetric positive semidefinite block is its eigen
98 // decomposition
99 gesvd( aSchur, aSvdS, aSvdU, aSvdVT, aSvdWork );
100
101 // an exactly singular S leaves round-off of the size of the
102 // subtracted terms, which a cut relative to S alone would invert
103 real tScale = 0.0 ;
104 for ( uint r=0; r<tNumGradients; ++r )
105 {
106 tScale = std::max( tScale, std::abs( aGram( r+1, r+1 ) ) );
107 }
108 const real tCut = std::max( aSvdS( 0 ) / aMaxCondition,
109 64.0 * std::numeric_limits< real >::epsilon() * tScale );
110
111 aCondition = aSvdS( tNumGradients - 1 ) > 0.0 ?
112 aSvdS( 0 ) / aSvdS( tNumGradients - 1 ) : BELFEM_REAL_MAX ;
113
114 bool tTruncated = false ;
115
116 aInverse.fill( 0.0 );
117 for ( uint j=0; j<tNumGradients; ++j )
118 {
119 if ( aSvdS( j ) <= tCut )
120 {
121 tTruncated = true ;
122 continue ;
123 }
124 for ( uint c=0; c<tNumGradients; ++c )
125 {
126 for ( uint r=0; r<tNumGradients; ++r )
127 {
128 aInverse( r+1, c+1 ) += aSvdVT( j, r ) * aSvdU( c, j ) / aSvdS( j );
129 }
130 }
131 }
132
133 for ( uint r=0; r<tNumGradients; ++r )
134 {
135 aSchurCoupling( r ) = 0.0 ;
136 for ( uint c=0; c<tNumGradients; ++c )
137 {
138 aSchurCoupling( r ) += aInverse( r+1, c+1 ) * aCoupling( c );
139 }
140 }
141 aInverse( 0, 0 ) = 1.0 / tWeightSum + dot( aCoupling, aSchurCoupling );
142 for ( uint r=0; r<tNumGradients; ++r )
143 {
144 aInverse( 0, r+1 ) = -aSchurCoupling( r );
145 aInverse( r+1, 0 ) = -aSchurCoupling( r );
146 }
147
148 return tTruncated ;
149 }
150 }
151}
152
153#endif //BELFEM_FN_FEM_RECOVERY_INVERSE_HPP
#define BELFEM_ASSERT(aCheck,...)
Definition assert.hpp:244
void fill(const T &aValue)
Definition cl_AR_Matrix.hpp:156
size_t n_rows() const
Definition cl_AR_Matrix.hpp:183
size_t n_cols() const
Definition cl_AR_Matrix.hpp:191
size_t length() const
get the length of the vector
Definition cl_AR_Vector.hpp:235
Inner products of vectors and matrices.
Singular value decomposition A = U * diag(S) * VT (LAPACK ?gesvd).
auto dot(const Vector< T > &aA, const Vector< T > &aB) -> decltype(arma::dot(aA.vector_data(), aB.vector_data()))
Scalar product of two vectors.
Definition fn_AR_dot.hpp:24
Definition cl_IFB_LINE3.hpp:21
bool recovery_block_inverse(const Matrix< real > &aGram, const real aMaxCondition, Matrix< real > &aInverse, real &aCondition, Matrix< real > &aSchur, Vector< real > &aCoupling, Vector< real > &aSchurCoupling, Matrix< real > &aSvdU, Matrix< real > &aSvdVT, Vector< real > &aSvdS, Vector< real > &aSvdWork)
Inverse of the Gram matrix of a patch-recovery fit whose basis is one in slot 0 at the node ( postpro...
Definition fn_FEM_recovery_inverse.hpp:59
USER GUIDES:
Definition cl_Capacitor.cpp:16
int_t gesvd(Matrix< T > &A, Vector< lapack::real_t< T > > &S, Matrix< T > &U, Matrix< T > &VT, Vector< lapack::real_t< T > > &Work, const char jobu='A', const char jobvt='A', const bool AbortOnError=true)
singular value decomposition A = U * diag( S ) * VT via LAPACK ?gesvd
Definition fn_gesvd.hpp:340
unsigned int uint
Definition typedefs.hpp:30
double real
Definition typedefs.hpp:36
#define BELFEM_REAL_MAX
Definition typedefs.hpp:80