Hermes2D  2.0
hcurl_proj_based_selector.cpp
1 #include "global.h"
2 #include "matrix.h"
3 #include "solution.h"
4 #include "shapeset/shapeset_hc_all.h"
5 #include "element_to_refine.h"
6 #include "hcurl_proj_based_selector.h"
7 namespace Hermes
8 {
9  namespace Hermes2D
10  {
11  namespace RefinementSelectors
12  {
13  template<typename Scalar>
14  const int HcurlProjBasedSelector<Scalar>::H2DRS_MAX_HCURL_ORDER = 6;
15 
16  template<typename Scalar>
17  HcurlProjBasedSelector<Scalar>::HcurlProjBasedSelector(CandList cand_list, double conv_exp, int max_order, HcurlShapeset* user_shapeset)
18  : ProjBasedSelector<Scalar>(cand_list, conv_exp, max_order, user_shapeset == NULL ? new HcurlShapeset() : user_shapeset, typename OptimumSelector<Scalar>::Range(), typename OptimumSelector<Scalar>::Range(0, H2DRS_MAX_HCURL_ORDER))
19  , precalc_rvals_curl(NULL)
20  {
21  if(user_shapeset != NULL)
22  {
23  this->warn("Warning: The user shapeset provided for the selector has to have a correct copy constructor implemented.");
24  this->warn("Warning: The functionality for cloning user shapeset is to be implemented yet.");
25  }
26  }
27 
28  template<typename Scalar>
30  {
31  HcurlProjBasedSelector* newSelector = new HcurlProjBasedSelector(this->cand_list, this->conv_exp, this->max_order);
32  newSelector->set_error_weights(this->error_weight_h, this->error_weight_p, this->error_weight_aniso);
33  newSelector->isAClone = true;
34  return newSelector;
35  }
36 
37  template<typename Scalar>
39  {
40  delete [] precalc_rvals_curl;
41  }
42 
43  template<typename Scalar>
45  {
46  this->current_max_order = this->max_order;
47  if(this->current_max_order == H2DRS_DEFAULT_ORDER)
48  this->current_max_order = std::min(H2DRS_MAX_HCURL_ORDER, (20 - element->iro_cache)/2 - 1); // default
49  else
50  this->current_max_order = std::min(this->max_order, (20 - element->iro_cache)/2 - 1); // user specified
51  this->current_min_order = 0;
52  }
53 
54  template<typename Scalar>
55  void HcurlProjBasedSelector<Scalar>::precalc_shapes(const double3* gip_points, const int num_gip_points, const Trf* trfs, const int num_noni_trfs, const Hermes::vector<typename OptimumSelector<Scalar>::ShapeInx>& shapes, const int max_shape_inx, typename ProjBasedSelector<Scalar>::TrfShape& svals, ElementMode2D mode)
56  {
57  //for all transformations
58  bool done = false;
59  int inx_trf = 0;
60  while (!done && inx_trf < H2D_TRF_NUM)
61  {
62  //prepare data for processing
63  const Trf& trf = trfs[inx_trf];
64  Hermes::vector<typename ProjBasedSelector<Scalar>::TrfShapeExp>& trf_svals = svals[inx_trf];
65 
66  //allocate
67  trf_svals.resize(max_shape_inx + 1);
68 
69  //for all shapes
70  const int num_shapes = (int)shapes.size();
71  for(int i = 0; i < num_shapes; i++)
72  {
73  int inx_shape = shapes[i].inx;
74  typename ProjBasedSelector<Scalar>::TrfShapeExp& shape_exp = trf_svals[inx_shape];
75 
76  //allocate
77  shape_exp.allocate(H2D_HCFE_NUM, num_gip_points);
78 
79  //for all GIP points
80  for(int k = 0; k < num_gip_points; k++)
81  {
82  //transform coordinates
83  double ref_x = gip_points[k][H2D_GIP2D_X] * trf.m[0] + trf.t[0];
84  double ref_y = gip_points[k][H2D_GIP2D_Y] * trf.m[1] + trf.t[1];
85 
86  //for all expansions: retrieve values
87  shape_exp[H2D_HCFE_VALUE0][k] = this->shapeset->get_fn_value(inx_shape, ref_x, ref_y, 0, mode);
88  shape_exp[H2D_HCFE_VALUE1][k] = this->shapeset->get_fn_value(inx_shape, ref_x, ref_y, 1, mode);
89  shape_exp[H2D_HCFE_CURL][k] = this->shapeset->get_dx_value(inx_shape, ref_x, ref_y, 1, mode) - this->shapeset->get_dy_value(inx_shape, ref_x, ref_y, 0, mode);
90  }
91  }
92 
93  //move to the next transformation
94  if(inx_trf == H2D_TRF_IDENTITY)
95  done = true;
96  else
97  {
98  inx_trf++;
99  if(inx_trf >= num_noni_trfs) //if all transformations were processed, move to the identity transformation
100  inx_trf = H2D_TRF_IDENTITY;
101  }
102  }
103  if(!done)
104  throw Exceptions::Exception("All transformation processed but identity transformation not found."); //identity transformation has to be the last transformation
105  }
106 
107  template<typename Scalar>
108  void HcurlProjBasedSelector<Scalar>::precalc_ortho_shapes(const double3* gip_points, const int num_gip_points, const Trf* trfs, const int num_noni_trfs, const Hermes::vector<typename OptimumSelector<Scalar>::ShapeInx>& shapes, const int max_shape_inx, typename ProjBasedSelector<Scalar>::TrfShape& svals, ElementMode2D mode)
109  {
110  //calculate values
111  precalc_shapes(gip_points, num_gip_points, trfs, num_noni_trfs, shapes, max_shape_inx, svals, mode);
112 
113  //calculate orthonormal basis
114  const int num_shapes = (int)shapes.size();
115  for(int i = 0; i < num_shapes; i++)
116  {
117  const int inx_shape_i = shapes[i].inx;
118 
119  //orthogonalize
120  for(int j = 0; j < i; j++)
121  {
122  const int inx_shape_j = shapes[j].inx;
123 
124  //calculate product of non-transformed functions
125  double product = 0.0;
126  for(int k = 0; k < num_gip_points; k++)
127  {
128  double sum = 0.0;
129  sum += svals[H2D_TRF_IDENTITY][inx_shape_i][H2D_HCFE_VALUE0][k] * svals[H2D_TRF_IDENTITY][inx_shape_j][H2D_HCFE_VALUE0][k];
130  sum += svals[H2D_TRF_IDENTITY][inx_shape_i][H2D_HCFE_VALUE1][k] * svals[H2D_TRF_IDENTITY][inx_shape_j][H2D_HCFE_VALUE1][k];
131  sum += svals[H2D_TRF_IDENTITY][inx_shape_i][H2D_HCFE_CURL][k] * svals[H2D_TRF_IDENTITY][inx_shape_j][H2D_HCFE_CURL][k];
132  product += gip_points[k][H2D_GIP2D_W] * sum;
133  }
134 
135  //for all transformations
136  int inx_trf = 0;
137  bool done = false;
138  while (!done && inx_trf < H2D_TRF_NUM)
139  {
140  //for all integration points
141  for(int k = 0; k < num_gip_points; k++)
142  {
143  svals[inx_trf][inx_shape_i][H2D_HCFE_VALUE0][k] -= product * svals[inx_trf][inx_shape_j][H2D_HCFE_VALUE0][k];
144  svals[inx_trf][inx_shape_i][H2D_HCFE_VALUE1][k] -= product * svals[inx_trf][inx_shape_j][H2D_HCFE_VALUE1][k];
145  svals[inx_trf][inx_shape_i][H2D_HCFE_CURL][k] -= product * svals[inx_trf][inx_shape_j][H2D_HCFE_CURL][k];
146  }
147 
148  //move to the next transformation
149  if(inx_trf == H2D_TRF_IDENTITY)
150  done = true;
151  else
152  {
153  inx_trf++;
154  if(inx_trf >= num_noni_trfs) //if all transformations were processed, move to the identity transformation
155  inx_trf = H2D_TRF_IDENTITY;
156  }
157  }
158  if(!done)
159  throw Exceptions::Exception("All transformation processed but identity transformation not found."); //identity transformation has to be the last transformation
160  }
161 
162  //normalize
163  //calculate norm
164  double norm_squared = 0.0;
165  for(int k = 0; k < num_gip_points; k++)
166  {
167  double sum = 0.0;
168  sum += sqr(svals[H2D_TRF_IDENTITY][inx_shape_i][H2D_HCFE_VALUE0][k]);
169  sum += sqr(svals[H2D_TRF_IDENTITY][inx_shape_i][H2D_HCFE_VALUE1][k]);
170  sum += sqr(svals[H2D_TRF_IDENTITY][inx_shape_i][H2D_HCFE_CURL][k]);
171  norm_squared += gip_points[k][H2D_GIP2D_W] * sum;
172  }
173  double norm = sqrt(norm_squared);
174  if(!finite(1/norm))
175  throw Exceptions::Exception("Norm (%g) is almost zero.", norm);
176 
177  //for all transformations: normalize
178  int inx_trf = 0;
179  bool done = false;
180  while (!done && inx_trf < H2D_TRF_NUM)
181  {
182  //for all integration points
183  for(int k = 0; k < num_gip_points; k++)
184  {
185  svals[inx_trf][inx_shape_i][H2D_HCFE_VALUE0][k] /= norm;
186  svals[inx_trf][inx_shape_i][H2D_HCFE_VALUE1][k] /= norm;
187  svals[inx_trf][inx_shape_i][H2D_HCFE_CURL][k] /= norm;
188  }
189 
190  //move to the next transformation
191  if(inx_trf == H2D_TRF_IDENTITY)
192  done = true;
193  else
194  {
195  inx_trf++;
196  if(inx_trf >= num_noni_trfs) //if all transformations were processed, move to the identity transformation
197  inx_trf = H2D_TRF_IDENTITY;
198  }
199  }
200  if(!done)
201  throw Exceptions::Exception("All transformation processed but identity transformation not found."); //identity transformation has to be the last transformation
202  }
203  }
204 
205  template<typename Scalar>
206  Scalar** HcurlProjBasedSelector<Scalar>::precalc_ref_solution(int inx_son, Solution<Scalar>* rsln, Element* element, int intr_gip_order)
207  {
208  const int num_gip = rsln->get_quad_2d()->get_num_points(intr_gip_order, rsln->get_active_element()->get_mode());
209 
210  //allocate space for Curl
211  if(precalc_rvals_curl == NULL)
212  precalc_rvals_curl = new_matrix<Scalar>(H2D_MAX_ELEMENT_SONS, num_gip);
213 
214  //prepre for curl
215  Scalar* curl = precalc_rvals_curl[inx_son];
216  Scalar* d1dx = rsln->get_dx_values(1);
217  Scalar* d0dy = rsln->get_dy_values(0);
218  for(int i = 0; i < num_gip; i++)
219  curl[i] = d1dx[i] - d0dy[i];
220 
221  //fill with values
222  Scalar** rvals_son = precalc_rvals[inx_son];
223  rvals_son[H2D_HCFE_VALUE0] = rsln->get_fn_values(0);
224  rvals_son[H2D_HCFE_VALUE1] = rsln->get_fn_values(1);
225  rvals_son[H2D_HCFE_CURL] = curl;
226 
227  return rvals_son;
228  }
229 
230  template<typename Scalar>
231  double** HcurlProjBasedSelector<Scalar>::build_projection_matrix(double3* gip_points, int num_gip_points,
232  const int* shape_inx, const int num_shapes, ElementMode2D mode)
233  {
234  //allocate
235  double** matrix = new_matrix<double>(num_shapes, num_shapes);
236 
237  //calculate products
238  int inx_row = 0;
239  for(int i = 0; i < num_shapes; i++, inx_row += num_shapes)
240  {
241  double* matrix_row = matrix[i];
242  int shape0_inx = shape_inx[i];
243  for(int k = 0; k < num_shapes; k++)
244  {
245  int shape1_inx = shape_inx[k];
246 
247  double value = 0.0;
248  for(int j = 0; j < num_gip_points; j++)
249  {
250  double gip_x = gip_points[j][H2D_GIP2D_X], gip_y = gip_points[j][H2D_GIP2D_Y];
251  double value0[2] = { this->shapeset->get_value(H2D_FEI_VALUE, shape0_inx, gip_x, gip_y, 0, mode), this->shapeset->get_value(H2D_FEI_VALUE, shape0_inx, gip_x, gip_y, 1, mode) };
252  double value1[2] = { this->shapeset->get_value(H2D_FEI_VALUE, shape1_inx, gip_x, gip_y, 0, mode), this->shapeset->get_value(H2D_FEI_VALUE, shape1_inx, gip_x, gip_y, 1, mode) };
253  double d1dx0 = this->shapeset->get_value(H2D_FEI_DX, shape0_inx, gip_x, gip_y, 1, mode);
254  double d1dx1 = this->shapeset->get_value(H2D_FEI_DX, shape1_inx, gip_x, gip_y, 1, mode);
255  double d0dy0 = this->shapeset->get_value(H2D_FEI_DY, shape0_inx, gip_x, gip_y, 0, mode);
256  double d0dy1 = this->shapeset->get_value(H2D_FEI_DY, shape1_inx, gip_x, gip_y, 0, mode);
257  double curl0 = d1dx0 - d0dy0;
258  double curl1 = d1dx1 - d0dy1;
259 
260  value += gip_points[j][H2D_GIP2D_W] * (value0[0]*value1[0] + value0[1]*value1[1] + curl0*curl1);
261  }
262 
263  matrix_row[k] = value;
264  }
265  }
266 
267  return matrix;
268  }
269 
270  template<typename Scalar>
272  {
273  double coef_curl = std::abs(sub_trf.coef_mx * sub_trf.coef_my);
274  Scalar total_value = 0;
275  for(int gip_inx = 0; gip_inx < sub_gip.num_gip_points; gip_inx++)
276  {
277  //get location and transform it
278  double3 &gip_pt = sub_gip.gip_points[gip_inx];
279 
280  //get value of a shape function
281  Scalar shape_value0 = sub_shape.svals[H2D_HCFE_VALUE0][gip_inx];
282  Scalar shape_value1 = sub_shape.svals[H2D_HCFE_VALUE1][gip_inx];
283  Scalar shape_curl = sub_shape.svals[H2D_HCFE_CURL][gip_inx];
284 
286  //double ref_x = gip_pt[H2D_GIP2D_X] * sub_trf.trf->m[0] + sub_trf.trf->t[0];
287  //double ref_y = gip_pt[H2D_GIP2D_Y] * sub_trf.trf->m[1] + sub_trf.trf->t[1];
288  //std::complex<double> shape_value0A = shapeset->get_fn_value(sub_shape.inx, ref_x, ref_y, 0);
289  //std::complex<double> shape_value1A = shapeset->get_fn_value(sub_shape.inx, ref_x, ref_y, 1);
290  //std::complex<double> shape_curlA = shapeset->get_dx_value(sub_shape.inx, ref_x, ref_y, 1) - shapeset->get_dy_value(sub_shape.inx, ref_x, ref_y, 0);
291  //error_if(std::abs(shape_value0 - shape_value0A) > 1E-15
292  // || std::abs(shape_value1 - shape_value1A) > 1E-15
293  // || std::abs(shape_curl - shape_curlA) > 1E-15, "A1");
295 
296  //get value of ref. solution
297  Scalar ref_value0 = sub_trf.coef_mx * sub_gip.rvals[H2D_HCFE_VALUE0][gip_inx];
298  Scalar ref_value1 = sub_trf.coef_my * sub_gip.rvals[H2D_HCFE_VALUE1][gip_inx];
299  Scalar ref_curl = coef_curl * sub_gip.rvals[H2D_HCFE_CURL][gip_inx]; //coef_curl * curl
300 
301  //evaluate a right-hand value
302  Scalar value = (shape_value0 * ref_value0)
303  + (shape_value1 * ref_value1)
304  + (shape_curl * ref_curl);
305 
306  total_value += gip_pt[H2D_GIP2D_W] * value;
307  }
308  return total_value;
309  }
310 
311  template<typename Scalar>
313  {
314  double total_error_squared = 0;
315  double coef_curl = std::abs(sub_trf.coef_mx * sub_trf.coef_my);
316  for(int gip_inx = 0; gip_inx < sub_gip.num_gip_points; gip_inx++)
317  {
318  //get location and transform it
319  double3 &gip_pt = sub_gip.gip_points[gip_inx];
320 
321  //calculate value of projected solution
322  Scalar proj_value0 = 0, proj_value1 = 0, proj_curl = 0;
323  for(int i = 0; i < elem_proj.num_shapes; i++)
324  {
325  int shape_inx = elem_proj.shape_inxs[i];
326  proj_value0 += elem_proj.shape_coeffs[i] * elem_proj.svals[shape_inx][H2D_HCFE_VALUE0][gip_inx];
327  proj_value1 += elem_proj.shape_coeffs[i] * elem_proj.svals[shape_inx][H2D_HCFE_VALUE1][gip_inx];
328  proj_curl += elem_proj.shape_coeffs[i] * elem_proj.svals[shape_inx][H2D_HCFE_CURL][gip_inx];
329  }
330 
332  //double ref_x = gip_pt[H2D_GIP2D_X] * sub_trf.trf->m[0] + sub_trf.trf->t[0];
333  //double ref_y = gip_pt[H2D_GIP2D_Y] * sub_trf.trf->m[1] + sub_trf.trf->t[1];
334  //std::complex<double> proj_value0A = 0, proj_value1A = 0, proj_curlA = 0;
335  //for(int i = 0; i < elem_proj.num_shapes; i++)
336  {
337  // int shape_inx = elem_proj.shape_inxs[i];
338  // proj_value0A += elem_proj.shape_coeffs[i] * shapeset->get_fn_value(shape_inx, ref_x, ref_y, 0);
339  // proj_value1A += elem_proj.shape_coeffs[i] * shapeset->get_fn_value(shape_inx, ref_x, ref_y, 1);
340  // proj_curlA += elem_proj.shape_coeffs[i] * (shapeset->get_dx_value(shape_inx, ref_x, ref_y, 1) - shapeset->get_dy_value(shape_inx, ref_x, ref_y, 0));
341  //}
342  //error_if(std::abs(proj_value0 - proj_value0A) > 1E-15
343  // || std::abs(proj_value1 - proj_value1A) > 1E-15
344  // || std::abs(proj_curl - proj_curlA) > 1E-15, "A1");
346 
347  //get value of ref. solution
348  Scalar ref_value0 = sub_trf.coef_mx * sub_gip.rvals[H2D_HCFE_VALUE0][gip_inx];
349  Scalar ref_value1 = sub_trf.coef_my * sub_gip.rvals[H2D_HCFE_VALUE1][gip_inx];
350  Scalar ref_curl = coef_curl * sub_gip.rvals[H2D_HCFE_CURL][gip_inx]; //coef_curl * curl
351 
352  //evaluate error
353  double error_squared = sqr(proj_value0 - ref_value0)
354  + sqr(proj_value1 - ref_value1)
355  + sqr(proj_curl - ref_curl);
356 
357  total_error_squared += gip_pt[H2D_GIP2D_W] * error_squared;
358  }
359  }
360  return total_error_squared;
361  }
362  template class HERMES_API HcurlProjBasedSelector<double>;
363  template class HERMES_API HcurlProjBasedSelector<std::complex<double> >;
364  }
365  }
366 }