1 #include "moab/LocalDiscretization/SpectralQuad.hpp"
2 #include "moab/Forward.hpp"
3 
4 namespace moab
5 {
6 
7   // filescope for static member data that is cached
8 int SpectralQuad::_n;
9 real *SpectralQuad::_z[2];
10 lagrange_data SpectralQuad::_ld[2];
11 opt_data_2 SpectralQuad::_data;
12 real * SpectralQuad::_odwork;
13 real * SpectralQuad::_glpoints;
14 bool SpectralQuad::_init = false;
15 
SpectralQuad()16 SpectralQuad::SpectralQuad() : Map(0)
17 {
18 }
19   // the preferred constructor takes pointers to GL blocked positions
SpectralQuad(int order,double * x,double * y,double * z)20 SpectralQuad::SpectralQuad(int order, double * x, double *y, double *z) : Map(0)
21 {
22   Init(order);
23   _xyz[0]=x; _xyz[1]=y; _xyz[2]=z;
24 }
SpectralQuad(int order)25 SpectralQuad::SpectralQuad(int order) : Map(4)
26 {
27   Init(order);
28   _xyz[0]=_xyz[1]=_xyz[2]=NULL;
29 }
~SpectralQuad()30 SpectralQuad::~SpectralQuad()
31 {
32   if (_init)
33     freedata();
34   _init=false;
35 }
Init(int order)36 void SpectralQuad::Init(int order)
37 {
38   if (_init && _n==order)
39     return;
40   if (_init && _n!=order)
41   {
42       // TODO: free data cached
43     freedata();
44   }
45     // compute stuff that depends only on order
46   _init = true;
47   _n = order;
48     //duplicates! n is the same in all directions !!!
49   for(int d=0; d<2; d++){
50     _z[d] = tmalloc(double, _n);
51     lobatto_nodes(_z[d], _n);
52     lagrange_setup(&_ld[d], _z[d], _n);
53   }
54   opt_alloc_2(&_data, _ld);
55 
56   unsigned int nf = _n*_n, ne = _n, nw = 2*_n*_n + 3*_n;
57   _odwork = tmalloc(double, 6*nf + 9*ne + nw);
58   _glpoints = tmalloc (double, 3*nf);
59 }
60 
freedata()61 void SpectralQuad::freedata()
62 {
63   for(int d=0; d<2; d++){
64     free(_z[d]);
65     lagrange_free(&_ld[d]);
66   }
67   opt_free_2(&_data);
68   free(_odwork);
69   free(_glpoints);
70 }
71 
set_gl_points(double * x,double * y,double * z)72 void SpectralQuad::set_gl_points( double * x, double * y, double *z)
73 {
74   _xyz[0] = x;
75   _xyz[1] = y;
76   _xyz[2] = z;
77 }
evalFcn(const double * params,const double * field,const int ndim,const int num_tuples,double * work,double * result)78 CartVect SpectralQuad::evalFcn(const double *params, const double *field, const int ndim, const int num_tuples,
79                                double *work, double *result)
80 {
81     //piece that we shouldn't want to cache
82   int d=0;
83   for(d=0; d<2; d++){
84     lagrange_0(&_ld[d], params[d]);
85   }
86   CartVect result;
87   for (d=0; d<3; d++)
88   {
89     result[d] = tensor_i2(_ld[0].J,_ld[0].n,
90                           _ld[1].J,_ld[1].n,
91                           _xyz[d],
92                           _odwork);
93   }
94   return result;
95 }
96   // replicate the functionality of hex_findpt
reverseEvalFcn(const double * posn,const double * verts,const int nverts,const int ndim,const double iter_tol,const double inside_tol,double * work,double * params,int * is_inside)97 bool SpectralQuad::reverseEvalFcn(const double *posn, const double *verts, const int nverts, const int ndim,
98                                   const double iter_tol, const double inside_tol, double *work,
99                                   double *params, int *is_inside)
100 {
101   params = init;
102 
103     //find nearest point
104   double x_star[3];
105   xyz.get(x_star);
106 
107   double r[2] = {0, 0 }; // initial guess for parametric coords
108   unsigned c = opt_no_constraints_3;
109   double dist = opt_findpt_2(&_data, (const double **)_xyz, x_star, r, &c);
110     // if it did not converge, get out with throw...
111   if (dist > 0.9e+30)
112   {
113     std::vector<CartVect> dummy;
114     throw Map::EvaluationError(CartVect(x_star), dummy);
115   }
116     //c tells us if we landed inside the element or exactly on a face, edge, or node
117     // also, dist shows the distance to the computed point.
118     //copy parametric coords back
119   params = r;
120 
121   return insideFcn(params, 2, inside_tol);
122 }
123 
124 
jacobian(const double * params,const double * verts,const int nverts,const int ndim,double * work,double * result)125 Matrix3  SpectralQuad::jacobian(const double *params, const double *verts, const int nverts, const int ndim,
126                                      double *work, double *result)
127 {
128     // not implemented
129   Matrix3 J(0.);
130   return J;
131 }
132 
133 
evaluate_vector(const CartVect & params,const double * field,int num_tuples,double * eval) const134 void SpectralQuad::evaluate_vector(const CartVect& params, const double *field, int num_tuples, double *eval) const
135 {
136     //piece that we shouldn't want to cache
137   int d;
138   for(d=0; d<2; d++){
139     lagrange_0(&_ld[d], params[d]);
140   }
141 
142   *eval = tensor_i2(_ld[0].J,_ld[0].n,
143                     _ld[1].J,_ld[1].n,
144                     field,
145                     _odwork);
146 }
integrate_vector(const double * field,const double * verts,const int nverts,const int ndim,const int num_tuples,double * work,double * result)147 void SpectralQuad:: integrate_vector(const double *field, const double *verts, const int nverts, const int ndim,
148                                       const int num_tuples, double *work, double *result)
149 {
150     // not implemented
151 }
152 
insideFcn(const double * params,const int ndim,const double tol)153 int SpectralQuad::insideFcn(const double *params, const int ndim, const double tol)
154 {
155   return EvalSet::inside(params, ndim, tol);
156 }
157 
158   // something we don't do for spectral hex; we do it here because
159   //       we do not store the position of gl points in a tag yet
compute_gl_positions()160 void SpectralQuad::compute_gl_positions()
161 {
162     // will need to use shape functions on a simple linear quad to compute gl points
163     // so we know the position of gl points in parametric space, we will just compute those
164     // from the 3d vertex position (corner nodes of the quad), using simple mapping
165   assert (this->vertex.size()==4);
166   static double corner_params[4][2]={ { -1., -1.},
167                                       {  1., -1.},
168                                       {  1.,  1.},
169                                       { -1.,  1.} };
170     // we will use the cached lobatto nodes in parametric space _z[d] (the same in both directions)
171   int indexGL=0;
172   int n2= _n*_n;
173   for (int i=0; i<_n; i++)
174   {
175     double csi=_z[0][i];
176     for (int j=0; j<_n; j++)
177     {
178       double eta = _z[1][j]; // we could really use the same _z[0] array of lobatto nodes
179       CartVect pos(0.0);
180       for (int k = 0; k < 4; k++) {
181         const double N_k = (1 + csi*corner_params[k][0])
182             * (1 + eta*corner_params[k][1]);
183         pos += N_k * vertex[k];
184       }
185       pos *= 0.25;// these are x, y, z of gl points; reorder them
186       _glpoints[indexGL] = pos[0]; // x
187       _glpoints[indexGL+n2] = pos[1]; // y
188       _glpoints[indexGL+2*n2] = pos[2]; // z
189       indexGL++;
190     }
191   }
192     // now, we can set the _xyz pointers to internal memory allocated to these!
193   _xyz[0] =  &(_glpoints[0]);
194   _xyz[1] =  &(_glpoints[n2]);
195   _xyz[2] =  &(_glpoints[2*n2]);
196 }
get_gl_points(double * & x,double * & y,double * & z,int & size)197 void SpectralQuad::get_gl_points( double *& x, double *& y, double *& z, int & size)
198 {
199   x=  (double *)_xyz[0] ;
200   y = (double *)_xyz[1] ;
201   z = (double *)_xyz[2] ;
202   size = _n*_n;
203 }
204 
205 } // namespace moab
206