moab
|
00001 #include "moab/SpectralHex.hpp" 00002 #include "moab/Forward.hpp" 00003 00004 namespace moab 00005 { 00006 00007 // SpectralHex 00008 00009 // filescope for static member data that is cached 00010 int SpectralHex::_n; 00011 real *SpectralHex::_z[3]; 00012 lagrange_data SpectralHex::_ld[3]; 00013 opt_data_3 SpectralHex::_data; 00014 real * SpectralHex::_odwork; 00015 00016 bool SpectralHex::_init = false; 00017 00018 void SpectralHex::initFcn(const double *verts, const int nverts, double *&work) 00019 { 00020 if (_init && _n==order) 00021 return; 00022 if (_init && _n!=order) 00023 { 00024 // TODO: free data cached 00025 freedata(); 00026 } 00027 // compute stuff that depends only on order 00028 _init = true; 00029 _n = order; 00030 //triplicates! n is the same in all directions !!! 00031 for(int d=0; d<3; d++){ 00032 _z[d] = tmalloc(double, _n); 00033 lobatto_nodes(_z[d], _n); 00034 lagrange_setup(&_ld[d], _z[d], _n); 00035 } 00036 opt_alloc_3(&_data, _ld); 00037 00038 unsigned int nf = _n*_n, ne = _n, nw = 2*_n*_n + 3*_n; 00039 _odwork = tmalloc(double, 6*nf + 9*ne + nw); 00040 } 00041 void SpectralHex::freedata() 00042 { 00043 for(int d=0; d<3; d++){ 00044 free(_z[d]); 00045 lagrange_free(&_ld[d]); 00046 } 00047 opt_free_3(&_data); 00048 free(_odwork); 00049 } 00050 00051 void SpectralHex::set_gl_points( double * x, double * y, double *z) 00052 { 00053 _xyz[0] = x; 00054 _xyz[1] = y; 00055 _xyz[2] = z; 00056 } 00057 CartVect SpectralHex::evaluate( const CartVect& params ) const 00058 { 00059 //piece that we shouldn't want to cache 00060 int d=0; 00061 for(d=0; d<3; d++){ 00062 lagrange_0(&_ld[d], params[d]); 00063 } 00064 CartVect result; 00065 for (d=0; d<3; d++) 00066 { 00067 result[d] = tensor_i3(_ld[0].J,_ld[0].n, 00068 _ld[1].J,_ld[1].n, 00069 _ld[2].J,_ld[2].n, 00070 _xyz[d], // this is the "field" 00071 _odwork); 00072 } 00073 return result; 00074 } 00075 // replicate the functionality of hex_findpt 00076 bool SpectralHex::evaluate_reverse(CartVect const & xyz, CartVect ¶ms, double iter_tol, const double inside_tol, 00077 const CartVect &init) const 00078 { 00079 params = init; 00080 00081 //find nearest point 00082 double x_star[3]; 00083 xyz.get(x_star); 00084 00085 double r[3] = {0, 0, 0 }; // initial guess for parametric coords 00086 unsigned c = opt_no_constraints_3; 00087 double dist = opt_findpt_3(&_data, (const double **)_xyz, x_star, r, &c); 00088 // if it did not converge, get out with throw... 00089 if (dist > 0.9e+30) 00090 return false; 00091 //c tells us if we landed inside the element or exactly on a face, edge, or node 00092 // also, dist shows the distance to the computed point. 00093 //copy parametric coords back 00094 params = r; 00095 00096 return is_inside(params, inside_tol); 00097 } 00098 Matrix3 SpectralHex::jacobian(const CartVect& params) const 00099 { 00100 double x_i[3]; 00101 params.get(x_i); 00102 // set the positions of GL nodes, before evaluations 00103 _data.elx[0]=_xyz[0]; 00104 _data.elx[1]=_xyz[1]; 00105 _data.elx[2]=_xyz[2]; 00106 opt_vol_set_intp_3(&_data,x_i); 00107 Matrix3 J(0.); 00108 // it is organized differently 00109 J(0,0) = _data.jac[0]; // dx/dr 00110 J(0,1) = _data.jac[1]; // dx/ds 00111 J(0,2) = _data.jac[2]; // dx/dt 00112 J(1,0) = _data.jac[3]; // dy/dr 00113 J(1,1) = _data.jac[4]; // dy/ds 00114 J(1,2) = _data.jac[5]; // dy/dt 00115 J(2,0) = _data.jac[6]; // dz/dr 00116 J(2,1) = _data.jac[7]; // dz/ds 00117 J(2,2) = _data.jac[8]; // dz/dt 00118 return J; 00119 } 00120 void SpectralHex::evaluate_vector(const CartVect& params, const double *field, int num_tuples, double *eval) const 00121 { 00122 //piece that we shouldn't want to cache 00123 int d; 00124 for(d=0; d<3; d++){ 00125 lagrange_0(&_ld[d], params[d]); 00126 } 00127 00128 *eval = tensor_i3(_ld[0].J,_ld[0].n, 00129 _ld[1].J,_ld[1].n, 00130 _ld[2].J,_ld[2].n, 00131 field, 00132 _odwork); 00133 } 00134 void SpectralHex::integrate_vector(const double *field_values, int num_tuples, double *integral) const 00135 { 00136 // set the position of GL points 00137 // set the positions of GL nodes, before evaluations 00138 _data.elx[0]=_xyz[0]; 00139 _data.elx[1]=_xyz[1]; 00140 _data.elx[2]=_xyz[2]; 00141 double params[3]; 00142 //triple loop; the most inner loop is in r direction, then s, then t 00143 for (int l = 0; l < num_tuples; l++) integral[l] = 0.0; 00144 //double volume = 0; 00145 int index=0; // used fr the inner loop 00146 for (int k=0; k<_n; k++ ) 00147 { 00148 params[2]=_ld[2].z[k]; 00149 //double wk= _ld[2].w[k]; 00150 for (int j=0; j<_n; j++) 00151 { 00152 params[1]=_ld[1].z[j]; 00153 //double wj= _ld[1].w[j]; 00154 for (int i=0; i<_n; i++) 00155 { 00156 params[0]=_ld[0].z[i]; 00157 //double wi= _ld[0].w[i]; 00158 opt_vol_set_intp_3(&_data,params); 00159 double wk= _ld[2].J[k]; 00160 double wj= _ld[1].J[j]; 00161 double wi= _ld[0].J[i]; 00162 Matrix3 J(0.); 00163 // it is organized differently 00164 J(0,0) = _data.jac[0]; // dx/dr 00165 J(0,1) = _data.jac[1]; // dx/ds 00166 J(0,2) = _data.jac[2]; // dx/dt 00167 J(1,0) = _data.jac[3]; // dy/dr 00168 J(1,1) = _data.jac[4]; // dy/ds 00169 J(1,2) = _data.jac[5]; // dy/dt 00170 J(2,0) = _data.jac[6]; // dz/dr 00171 J(2,1) = _data.jac[7]; // dz/ds 00172 J(2,2) = _data.jac[8]; // dz/dt 00173 double bm = wk*wj*wi* J.determinant(); 00174 for (int l = 0; l < num_tuples; l++) 00175 integral[l]+= bm*field_values[num_tuples*index+l]; 00176 //volume +=bm; 00177 } 00178 } 00179 } 00180 //std::cout << "volume: " << volume << "\n"; 00181 } 00182 00183 int SpectralHex::insideFcn(const double *params, const int ndim, const double tol) 00184 { 00185 return EvalSet::inside(params, ndim, tol); 00186 } 00187 00188 // SpectralHex 00189 00190 } // namespace moab