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