1 #ifndef MOAB_SPECTRAL_HEX_HPP
2 #define MOAB_SPECTRAL_HEX_HPP
3
4 #include "moab/Matrix3.hpp"
5 #include "moab/CartVect.hpp"
6 #include "moab/FindPtFuncs.h"
7 #include <sstream>
8 #include <iomanip>
9 #include <iostream>
10
11 namespace moab
12 {
13
14 namespace element_utility
15 {
16
17 namespace
18 {
19 }
20
21 template < typename _Matrix >
22 class Spectral_hex_map
23 {
24 public:
25 typedef _Matrix Matrix;
26
27 private:
28 typedef Spectral_hex_map< Matrix > Self;
29
30 public:
31
32 Spectral_hex_map(){};
33 Spectral_hex_map( int order )
34 {
35 initialize_spectral_hex( order );
36 }
37
38 Spectral_hex_map( const Self& f ) {}
39
40 private:
41 void initialize_spectral_hex( int order )
42 {
43 if( _init && _n == order )
44 {
45 return;
46 }
47 if( _init && _n != order )
48 {
49 free_data();
50 }
51 _init = true;
52 _n = order;
53 for( int d = 0; d < 3; d++ )
54 {
55 lobatto_nodes( _z[d], _n );
56 lagrange_setup( &_ld[d], _z[d], _n );
57 }
58 opt_alloc_3( &_data, _ld );
59 std::size_t nf = _n * _n, ne = _n, nw = 2 * _n * _n + 3 * _n;
60 _odwork = tmalloc( real, 6 * nf + 9 * ne + nw );
61 }
62
63 void free_data()
64 {
65 for( int d = 0; d < 3; d++ )
66 {
67 free( _z[d] );
68 lagrange_free( &_ld[d] );
69 }
70 opt_free_3( &_data );
71 free( _odwork );
72 }
73
74 public:
75
76 template < typename Moab, typename Entity_handle, typename Points, typename Point >
77 std::pair< bool, Point > operator()( const Moab& ,
78 const Entity_handle& ,
79 const Points& v,
80 const Point& p,
81 const double tol = 1.e-6 )
82 {
83 Point result( 3, 0.0 );
84
89 bool point_found = solve_inverse( p, result, v, tol ) && is_contained( result, tol );
90 return std::make_pair( point_found, result );
91 }
92
93 private:
94 void set_gl_points( double* x, double* y, double* z )
95 {
96 _xyz[0] = x;
97 _xyz[1] = y;
98 _xyz[2] = z;
99 }
100 template < typename Point >
101 bool is_contained( const Point& p, const double tol ) const
102 {
103
104 return ( p[0] >= -1. - tol ) && ( p[0] <= 1. + tol ) && ( p[1] >= -1. - tol ) && ( p[1] <= 1. + tol ) &&
105 ( p[2] >= -1. - tol ) && ( p[2] <= 1. + tol );
106 }
107
108 template < typename Point, typename Points >
109 bool solve_inverse( const Point& x, Point& xi, const Points& points, const double tol = 1.e-6 )
110 {
111 const double error_tol_sqr = tol * tol;
112 Point delta( 3, 0.0 );
113 xi = delta;
114 evaluate( xi, points, delta );
115 vec_subtract( delta, x );
116 std::size_t num_iterations = 0;
117 #ifdef SPECTRAL_HEX_DEBUG
118 std::stringstream ss;
119 ss << "Point: ";
120 ss << x[0] << ", " << x[1] << ", " << x[2] << std::endl;
121 ss << "Hex: ";
122 for( int i = 0; i < 8; ++i )
123 {
124 ss << points[i][0] << ", " << points[i][1] << ", " << points[i][2] << std::endl;
125 }
126 ss << std::endl;
127 #endif
128 while( normsq( delta ) > error_tol_sqr )
129 {
130 #ifdef SPECTRAL_HEX_DEBUG
131 ss << "Iter #: " << num_iterations << " Err: " << sqrt( normsq( delta ) ) << " Iterate: ";
132 ss << xi[0] << ", " << xi[1] << ", " << xi[2] << std::endl;
133 #endif
134 if( ++num_iterations >= 5 )
135 {
136 return false;
137 }
138 Matrix J;
139 jacobian( xi, points, J );
140 double det = moab::Matrix::determinant3( J );
141 if( fabs( det ) < 1.e-10 )
142 {
143 #ifdef SPECTRAL_HEX_DEBUG
144 std::cerr << ss.str();
145 #endif
146 #ifndef SPECTRAL_HEX_DEBUG
147 std::cerr << x[0] << ", " << x[1] << ", " << x[2] << std::endl;
148 #endif
149 std::cerr << "inverse solve failure: det: " << det << std::endl;
150 exit( -1 );
151 }
152 vec_subtract( xi, moab::Matrix::inverse( J, 1.0 / det ) * delta );
153 evaluate( xi, points, delta );
154 vec_subtract( delta, x );
155 }
156 return true;
157 }
158
159 template < typename Point, typename Points >
160 Point& evaluate( const Point& p, const Points& , Point& f )
161 {
162 for( int d = 0; d < 3; ++d )
163 {
164 lagrange_0( &_ld[d], p[0] );
165 }
166 for( int d = 0; d < 3; ++d )
167 {
168 f[d] = tensor_i3( _ld[0].J, _ld[0].n, _ld[1].J, _ld[1].n, _ld[2].J, _ld[2].n, _xyz[d], _odwork );
169 }
170 return f;
171 }
172
173 template < typename Point, typename Field >
174 double evaluate_scalar_field( const Point& p, const Field& field ) const
175 {
176 int d;
177 for( d = 0; d < 3; d++ )
178 {
179 lagrange_0( &_ld[d], p[d] );
180 }
181 return tensor_i3( _ld[0].J, _ld[0].n, _ld[1].J, _ld[1].n, _ld[2].J, _ld[2].n, field, _odwork );
182 }
183 template < typename Points, typename Field >
184 double integrate_scalar_field( const Points& p, const Field& field ) const
185 {
186
187
188 _data.elx[0] = _xyz[0];
189 _data.elx[1] = _xyz[1];
190 _data.elx[2] = _xyz[2];
191 double xi[3];
192
193 double integral = 0.;
194
195 int index = 0;
196 for( int k = 0; k < _n; k++ )
197 {
198 xi[2] = _ld[2].z[k];
199
200 for( int j = 0; j < _n; j++ )
201 {
202 xi[1] = _ld[1].z[j];
203
204 for( int i = 0; i < _n; i++ )
205 {
206 xi[0] = _ld[0].z[i];
207
208 opt_vol_set_intp_3( (opt_data_3*)&_data, xi );
209 double wk = _ld[2].J[k];
210 double wj = _ld[1].J[j];
211 double wi = _ld[0].J[i];
212 Matrix3 J( 0. );
213 for( int n = 0; n < 8; n++ )
214 J( n / 3, n % 3 ) = _data.jac[n];
215 double bm = wk * wj * wi * J.determinant();
216 integral += bm * field[index++];
217
218 }
219 }
220 }
221
222 return integral;
223 }
224
225 template < typename Point, typename Points >
226 Matrix& jacobian( const Point& , const Points& , Matrix& J )
227 {
228 real x[3];
229 for( int i = 0; i < 3; ++i )
230 {
231 _data.elx[i] = _xyz[i];
232 }
233 opt_vol_set_intp_3( &_data, x );
234 for( int i = 0; i < 9; ++i )
235 {
236 J( i % 3, i / 3 ) = _data.jac[i];
237 }
238 return J;
239 }
240
241 private:
242 bool _init;
243 int _n;
244 real* _z[3];
245 lagrange_data _ld[3];
246 opt_data_3 _data;
247 real* _odwork;
248 real* _xyz[3];
249 };
250
251 }
252
253 }
254 #endif