![]() |
Mesh Oriented datABase
(version 5.4.1)
Array-based unstructured mesh datastructure
|
00001 #include "moab/LocalDiscretization/SpectralQuad.hpp"
00002 #include "moab/Forward.hpp"
00003
00004 namespace moab
00005 {
00006
00007 // filescope for static member data that is cached
00008 int SpectralQuad::_n;
00009 real* SpectralQuad::_z[2];
00010 lagrange_data SpectralQuad::_ld[2];
00011 opt_data_2 SpectralQuad::_data;
00012 real* SpectralQuad::_odwork;
00013 real* SpectralQuad::_glpoints;
00014 bool SpectralQuad::_init = false;
00015
00016 SpectralQuad::SpectralQuad() : Map( 0 ) {}
00017 // the preferred constructor takes pointers to GL blocked positions
00018 SpectralQuad::SpectralQuad( int order, double* x, double* y, double* z ) : Map( 0 )
00019 {
00020 Init( order );
00021 _xyz[0] = x;
00022 _xyz[1] = y;
00023 _xyz[2] = z;
00024 }
00025 SpectralQuad::SpectralQuad( int order ) : Map( 4 )
00026 {
00027 Init( order );
00028 _xyz[0] = _xyz[1] = _xyz[2] = NULL;
00029 }
00030 SpectralQuad::~SpectralQuad()
00031 {
00032 if( _init ) freedata();
00033 _init = false;
00034 }
00035 void SpectralQuad::Init( int order )
00036 {
00037 if( _init && _n == order ) return;
00038 if( _init && _n != order )
00039 {
00040 // TODO: free data cached
00041 freedata();
00042 }
00043 // compute stuff that depends only on order
00044 _init = true;
00045 _n = order;
00046 // duplicates! n is the same in all directions !!!
00047 for( int d = 0; d < 2; d++ )
00048 {
00049 _z[d] = tmalloc( double, _n );
00050 lobatto_nodes( _z[d], _n );
00051 lagrange_setup( &_ld[d], _z[d], _n );
00052 }
00053 opt_alloc_2( &_data, _ld );
00054
00055 unsigned int nf = _n * _n, ne = _n, nw = 2 * _n * _n + 3 * _n;
00056 _odwork = tmalloc( double, 6 * nf + 9 * ne + nw );
00057 _glpoints = tmalloc( double, 3 * nf );
00058 }
00059
00060 void SpectralQuad::freedata()
00061 {
00062 for( int d = 0; d < 2; d++ )
00063 {
00064 free( _z[d] );
00065 lagrange_free( &_ld[d] );
00066 }
00067 opt_free_2( &_data );
00068 free( _odwork );
00069 free( _glpoints );
00070 }
00071
00072 void SpectralQuad::set_gl_points( double* x, double* y, double* z )
00073 {
00074 _xyz[0] = x;
00075 _xyz[1] = y;
00076 _xyz[2] = z;
00077 }
00078 CartVect SpectralQuad::evalFcn( const double* params,
00079 const double* field,
00080 const int ndim,
00081 const int num_tuples,
00082 double* work,
00083 double* result )
00084 {
00085 // piece that we shouldn't want to cache
00086 int d = 0;
00087 for( d = 0; d < 2; d++ )
00088 {
00089 lagrange_0( &_ld[d], params[d] );
00090 }
00091 CartVect result;
00092 for( d = 0; d < 3; d++ )
00093 {
00094 result[d] = tensor_i2( _ld[0].J, _ld[0].n, _ld[1].J, _ld[1].n, _xyz[d], _odwork );
00095 }
00096 return result;
00097 }
00098 // replicate the functionality of hex_findpt
00099 bool SpectralQuad::reverseEvalFcn( const double* posn,
00100 const double* verts,
00101 const int nverts,
00102 const int ndim,
00103 const double iter_tol,
00104 const double inside_tol,
00105 double* work,
00106 double* params,
00107 int* is_inside )
00108 {
00109 params = init;
00110
00111 // find nearest point
00112 double x_star[3];
00113 xyz.get( x_star );
00114
00115 double r[2] = { 0, 0 }; // initial guess for parametric coords
00116 unsigned c = opt_no_constraints_3;
00117 double dist = opt_findpt_2( &_data, (const double**)_xyz, x_star, r, &c );
00118 // if it did not converge, get out with throw...
00119 if( dist > 0.9e+30 )
00120 {
00121 std::vector< CartVect > dummy;
00122 throw Map::EvaluationError( CartVect( x_star ), dummy );
00123 }
00124 // c tells us if we landed inside the element or exactly on a face, edge, or node
00125 // also, dist shows the distance to the computed point.
00126 // copy parametric coords back
00127 params = r;
00128
00129 return insideFcn( params, 2, inside_tol );
00130 }
00131
00132 Matrix3 SpectralQuad::jacobian( const double* params,
00133 const double* verts,
00134 const int nverts,
00135 const int ndim,
00136 double* work,
00137 double* result )
00138 {
00139 // not implemented
00140 Matrix3 J( 0. );
00141 return J;
00142 }
00143
00144 void SpectralQuad::evaluate_vector( const CartVect& params, const double* field, int num_tuples, double* eval ) const
00145 {
00146 // piece that we shouldn't want to cache
00147 int d;
00148 for( d = 0; d < 2; d++ )
00149 {
00150 lagrange_0( &_ld[d], params[d] );
00151 }
00152
00153 *eval = tensor_i2( _ld[0].J, _ld[0].n, _ld[1].J, _ld[1].n, field, _odwork );
00154 }
00155 void SpectralQuad::integrate_vector( const double* field,
00156 const double* verts,
00157 const int nverts,
00158 const int ndim,
00159 const int num_tuples,
00160 double* work,
00161 double* result )
00162 {
00163 // not implemented
00164 }
00165
00166 int SpectralQuad::insideFcn( const double* params, const int ndim, const double tol )
00167 {
00168 return EvalSet::inside( params, ndim, tol );
00169 }
00170
00171 // something we don't do for spectral hex; we do it here because
00172 // we do not store the position of gl points in a tag yet
00173 void SpectralQuad::compute_gl_positions()
00174 {
00175 // will need to use shape functions on a simple linear quad to compute gl points
00176 // so we know the position of gl points in parametric space, we will just compute those
00177 // from the 3d vertex position (corner nodes of the quad), using simple mapping
00178 assert( this->vertex.size() == 4 );
00179 static double corner_params[4][2] = { { -1., -1. }, { 1., -1. }, { 1., 1. }, { -1., 1. } };
00180 // we will use the cached lobatto nodes in parametric space _z[d] (the same in both directions)
00181 int indexGL = 0;
00182 int n2 = _n * _n;
00183 for( int i = 0; i < _n; i++ )
00184 {
00185 double csi = _z[0][i];
00186 for( int j = 0; j < _n; j++ )
00187 {
00188 double eta = _z[1][j]; // we could really use the same _z[0] array of lobatto nodes
00189 CartVect pos( 0.0 );
00190 for( int k = 0; k < 4; k++ )
00191 {
00192 const double N_k = ( 1 + csi * corner_params[k][0] ) * ( 1 + eta * corner_params[k][1] );
00193 pos += N_k * vertex[k];
00194 }
00195 pos *= 0.25; // these are x, y, z of gl points; reorder them
00196 _glpoints[indexGL] = pos[0]; // x
00197 _glpoints[indexGL + n2] = pos[1]; // y
00198 _glpoints[indexGL + 2 * n2] = pos[2]; // z
00199 indexGL++;
00200 }
00201 }
00202 // now, we can set the _xyz pointers to internal memory allocated to these!
00203 _xyz[0] = &( _glpoints[0] );
00204 _xyz[1] = &( _glpoints[n2] );
00205 _xyz[2] = &( _glpoints[2 * n2] );
00206 }
00207 void SpectralQuad::get_gl_points( double*& x, double*& y, double*& z, int& size )
00208 {
00209 x = (double*)_xyz[0];
00210 y = (double*)_xyz[1];
00211 z = (double*)_xyz[2];
00212 size = _n * _n;
00213 }
00214
00215 } // namespace moab