Hermes2D  2.0
l2_proj_based_selector.cpp
1 #include "global.h"
2 #include "matrix.h"
3 #include "solution.h"
4 #include "shapeset/shapeset_l2_all.h"
5 #include "element_to_refine.h"
6 #include "l2_proj_based_selector.h"
7 namespace Hermes
8 {
9  namespace Hermes2D
10  {
11  namespace RefinementSelectors
12  {
13  template<typename Scalar>
14  const int L2ProjBasedSelector<Scalar>::H2DRS_MAX_L2_ORDER = H2DRS_MAX_ORDER;
15 
16  template<typename Scalar>
17  L2ProjBasedSelector<Scalar>::L2ProjBasedSelector(CandList cand_list, double conv_exp, int max_order, L2Shapeset* user_shapeset)
18  : ProjBasedSelector<Scalar>(cand_list, conv_exp, max_order, user_shapeset == NULL ? new L2Shapeset() : user_shapeset, typename OptimumSelector<Scalar>::Range(1, 1), typename OptimumSelector<Scalar>::Range(0, H2DRS_MAX_L2_ORDER)), user_shapeset(user_shapeset == NULL ? false : true)
19  {
20  if(user_shapeset != NULL)
21  {
22  this->warn("Warning: The user shapeset provided for the selector has to have a correct copy constructor implemented.");
23  this->warn("Warning: The functionality for cloning user shapeset is to be implemented yet.");
24  }
25  }
26 
27  template<typename Scalar>
29  {
30  if(!this->user_shapeset)
31  delete this->shapeset;
32  }
33 
34  template<typename Scalar>
36  {
37  L2ProjBasedSelector<Scalar>* newSelector = new L2ProjBasedSelector(this->cand_list, this->conv_exp, this->max_order, (L2Shapeset*)this->shapeset);
38  newSelector->set_error_weights(this->error_weight_h, this->error_weight_p, this->error_weight_aniso);
39  newSelector->isAClone = true;
40  return newSelector;
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 = (20 - element->iro_cache)/2 - 2; // default
49  else
50  this->current_max_order = std::min(this->current_max_order, (20 - element->iro_cache)/2 - 2); // user specified
51  this->current_min_order = 0;
52  }
53 
54  template<typename Scalar>
55  void L2ProjBasedSelector<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_L2FE_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_L2FE_VALUE][k] = this->shapeset->get_fn_value(inx_shape, ref_x, ref_y, 0, mode);
88  }
89  }
90 
91  //move to the next transformation
92  if(inx_trf == H2D_TRF_IDENTITY)
93  done = true;
94  else
95  {
96  inx_trf++;
97  if(inx_trf >= num_noni_trfs) //if all transformations were processed, move to the identity transformation
98  inx_trf = H2D_TRF_IDENTITY;
99  }
100  }
101  if(!done)
102  throw Exceptions::Exception("All transformation processed but identity transformation not found.");
103  }
104 
105  template<typename Scalar>
106  void L2ProjBasedSelector<Scalar>::create_candidates(Element* e, int quad_order, int max_ha_quad_order, int max_p_quad_order)
107  {
108  int order_h = H2D_GET_H_ORDER(quad_order), order_v = H2D_GET_V_ORDER(quad_order);
109  int max_p_order_h = H2D_GET_H_ORDER(max_p_quad_order), max_p_order_v = H2D_GET_V_ORDER(max_p_quad_order);
110  int max_ha_order_h = H2D_GET_H_ORDER(max_ha_quad_order), max_ha_order_v = H2D_GET_V_ORDER(max_ha_quad_order);
111  bool tri = e->is_triangle();
112 
113  //clear list of candidates
114  this->candidates.clear();
115  if(this->candidates.capacity() < H2DRS_ASSUMED_MAX_CANDS)
116  this->candidates.reserve(H2DRS_ASSUMED_MAX_CANDS);
117 
118  //generate all P-candidates (start from intention of generating all possible candidates
119  //and restrict it according to the given adapt-type)
120  bool iso_p = false;
121  int start_quad_order = quad_order;
122  int last_quad_order = H2D_MAKE_QUAD_ORDER(std::min(max_p_order_h, order_h + H2DRS_MAX_ORDER_INC), std::min(max_p_order_v, order_v + H2DRS_MAX_ORDER_INC));
123  switch(this->cand_list)
124  {
125  case H2D_H_ISO:
126  case H2D_H_ANISO: last_quad_order = start_quad_order; break; //no P-candidates except the original candidate
127  case H2D_P_ISO:
128  case H2D_HP_ISO:
129  case H2D_HP_ANISO_H: iso_p = true; break; //iso change of orders
130  }
131  this->append_candidates_split(quad_order, last_quad_order, H2D_REFINEMENT_P, tri || iso_p);
132 
133  //generate all H-candidates
134  iso_p = false;
135  int start_order_h = std::max(this->current_min_order, (order_h + 1) / 2), start_order_v = std::max(this->current_min_order, (order_v + 1) / 2);
136  start_quad_order = H2D_MAKE_QUAD_ORDER(start_order_h, start_order_v);
137  last_quad_order = H2D_MAKE_QUAD_ORDER(std::min(max_ha_order_h, start_order_h + H2DRS_MAX_ORDER_INC), std::min(max_ha_order_v, start_order_v + H2DRS_MAX_ORDER_INC));
138  switch(this->cand_list)
139  {
140  case H2D_H_ISO:
141  case H2D_H_ANISO:
142  last_quad_order = start_quad_order = quad_order; break; //no only one candidate will be created
143  case H2D_P_ISO:
144  case H2D_P_ANISO: last_quad_order = -1; break; //no H-candidate will be generated
145  case H2D_HP_ISO:
146  case H2D_HP_ANISO_H: iso_p = true; break; //iso change of orders
147  }
148  this->append_candidates_split(start_quad_order, last_quad_order, H2D_REFINEMENT_H, tri || iso_p);
149 
150  //generate all ANISO-candidates
151  if(!tri && e->iro_cache < 8
152  && (this->cand_list == H2D_H_ANISO || this->cand_list == H2D_HP_ANISO_H || this->cand_list == H2D_HP_ANISO))
153  {
154  iso_p = false;
155  int start_quad_order_hz = H2D_MAKE_QUAD_ORDER(order_h, std::max(this->current_min_order, (order_v + 1) / 2));
156  int last_quad_order_hz = H2D_MAKE_QUAD_ORDER(std::min(max_ha_order_h, order_h + H2DRS_MAX_ORDER_INC), std::min(order_v, H2D_GET_V_ORDER(start_quad_order) + H2DRS_MAX_ORDER_INC));
157  int start_quad_order_vt = H2D_MAKE_QUAD_ORDER(std::max(this->current_min_order, (order_h + 1) / 2), order_v);
158  int last_quad_order_vt = H2D_MAKE_QUAD_ORDER(std::min(order_h, H2D_GET_H_ORDER(start_quad_order) + H2DRS_MAX_ORDER_INC), std::min(max_ha_order_v, order_v + H2DRS_MAX_ORDER_INC));
159  switch(this->cand_list)
160  {
161  case H2D_H_ANISO:
162  last_quad_order_hz = start_quad_order_hz = quad_order;
163  last_quad_order_vt = start_quad_order_vt = quad_order;
164  break; //only one candidate will be created
165  case H2D_HP_ANISO_H: iso_p = true; break; //iso change of orders
166  }
167  if(iso_p) { //make orders uniform: take mininmum order since nonuniformity is caused by different handling of orders along directions
168  int order = std::min(H2D_GET_H_ORDER(start_quad_order_hz), H2D_GET_V_ORDER(start_quad_order_hz));
169  start_quad_order_hz = H2D_MAKE_QUAD_ORDER(order, order);
170  order = std::min(H2D_GET_H_ORDER(start_quad_order_vt), H2D_GET_V_ORDER(start_quad_order_vt));
171  start_quad_order_vt = H2D_MAKE_QUAD_ORDER(order, order);
172 
173  order = std::min(H2D_GET_H_ORDER(last_quad_order_hz), H2D_GET_V_ORDER(last_quad_order_hz));
174  last_quad_order_hz = H2D_MAKE_QUAD_ORDER(order, order);
175  order = std::min(H2D_GET_H_ORDER(last_quad_order_vt), H2D_GET_V_ORDER(last_quad_order_vt));
176  last_quad_order_vt = H2D_MAKE_QUAD_ORDER(order, order);
177  }
178  this->append_candidates_split(start_quad_order_hz, last_quad_order_hz, H2D_REFINEMENT_ANISO_H, iso_p);
179  this->append_candidates_split(start_quad_order_vt, last_quad_order_vt, H2D_REFINEMENT_ANISO_V, iso_p);
180  }
181  }
182 
183  template<typename Scalar>
184  void L2ProjBasedSelector<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)
185  {
186  //calculate values
187  precalc_shapes(gip_points, num_gip_points, trfs, num_noni_trfs, shapes, max_shape_inx, svals, mode);
188 
189  //calculate orthonormal basis
190  const int num_shapes = (int)shapes.size();
191  for(int i = 0; i < num_shapes; i++)
192  {
193  const int inx_shape_i = shapes[i].inx;
194 
195  //orthogonalize
196  for(int j = 0; j < i; j++)
197  {
198  const int inx_shape_j = shapes[j].inx;
199 
200  //calculate product of non-transformed functions
201  double product = 0.0;
202  for(int k = 0; k < num_gip_points; k++)
203  {
204  double sum = 0.0;
205  sum += svals[H2D_TRF_IDENTITY][inx_shape_i][H2D_L2FE_VALUE][k] * svals[H2D_TRF_IDENTITY][inx_shape_j][H2D_L2FE_VALUE][k];
206  product += gip_points[k][H2D_GIP2D_W] * sum;
207  }
208 
209  //for all transformations
210  int inx_trf = 0;
211  bool done = false;
212  while (!done && inx_trf < H2D_TRF_NUM)
213  {
214  //for all integration points
215  for(int k = 0; k < num_gip_points; k++)
216  {
217  svals[inx_trf][inx_shape_i][H2D_L2FE_VALUE][k] -= product * svals[inx_trf][inx_shape_j][H2D_L2FE_VALUE][k];
218  }
219 
220  //move to the next transformation
221  if(inx_trf == H2D_TRF_IDENTITY)
222  done = true;
223  else
224  {
225  inx_trf++;
226  if(inx_trf >= num_noni_trfs) //if all transformations were processed, move to the identity transformation
227  inx_trf = H2D_TRF_IDENTITY;
228  }
229  }
230  //identity transformation has to be the last transformation
231  if(!done)
232  throw Exceptions::Exception("All transformation processed but identity transformation not found.");
233  }
234 
235  //normalize
236  //calculate norm
237  double norm_squared = 0.0;
238  for(int k = 0; k < num_gip_points; k++)
239  {
240  double sum = 0.0;
241  sum += sqr(svals[H2D_TRF_IDENTITY][inx_shape_i][H2D_L2FE_VALUE][k]);
242  norm_squared += gip_points[k][H2D_GIP2D_W] * sum;
243  }
244  double norm = sqrt(norm_squared);
245  if(!finite(1/norm))
246  throw Exceptions::Exception("Norm (%g) is almost zero.", norm);
247 
248  //for all transformations: normalize
249  int inx_trf = 0;
250  bool done = false;
251  while (!done && inx_trf < H2D_TRF_NUM)
252  {
253  //for all integration points
254  for(int k = 0; k < num_gip_points; k++)
255  {
256  svals[inx_trf][inx_shape_i][H2D_L2FE_VALUE][k] /= norm;
257  }
258 
259  //move to the next transformation
260  if(inx_trf == H2D_TRF_IDENTITY)
261  done = true;
262  else
263  {
264  inx_trf++;
265  if(inx_trf >= num_noni_trfs) //if all transformations were processed, move to the identity transformation
266  inx_trf = H2D_TRF_IDENTITY;
267  }
268  }
269  //identity transformation has to be the last transformation
270  if(!done)
271  throw Exceptions::Exception("All transformation processed but identity transformation not found.");
272  }
273  }
274 
275  template<typename Scalar>
276  Scalar** L2ProjBasedSelector<Scalar>::precalc_ref_solution(int inx_son, Solution<Scalar>* rsln, Element* element, int intr_gip_order)
277  {
278  //fill with values
279  Scalar** rvals_son = precalc_rvals[inx_son];
280  rvals_son[H2D_L2FE_VALUE] = rsln->get_fn_values(0);
281 
282  return rvals_son;
283  }
284 
285  template<typename Scalar>
286  double** L2ProjBasedSelector<Scalar>::build_projection_matrix(double3* gip_points, int num_gip_points,
287  const int* shape_inx, const int num_shapes, ElementMode2D mode)
288  {
289  //allocate
290  double** matrix = new_matrix<double>(num_shapes, num_shapes);
291 
292  //calculate products
293  int inx_row = 0;
294  for(int i = 0; i < num_shapes; i++, inx_row += num_shapes)
295  {
296  double* matrix_row = matrix[i];
297  int shape0_inx = shape_inx[i];
298  for(int k = 0; k < num_shapes; k++)
299  {
300  int shape1_inx = shape_inx[k];
301 
302  double value = 0.0;
303  for(int j = 0; j < num_gip_points; j++)
304  {
305  double gip_x = gip_points[j][H2D_GIP2D_X], gip_y = gip_points[j][H2D_GIP2D_Y];
306  double value0 = this->shapeset->get_value(H2D_FEI_VALUE, shape0_inx, gip_x, gip_y, 0, mode);
307  double value1 = this->shapeset->get_value(H2D_FEI_VALUE, shape1_inx, gip_x, gip_y, 0, mode);
308 
309  value += gip_points[j][H2D_GIP2D_W] * (value0*value1);
310  }
311 
312  matrix_row[k] = value;
313  }
314  }
315 
316  return matrix;
317  }
318 
319  template<typename Scalar>
321  {
322  Scalar total_value = 0;
323  for(int gip_inx = 0; gip_inx < sub_gip.num_gip_points; gip_inx++)
324  {
325  //get location and transform it
326  double3 &gip_pt = sub_gip.gip_points[gip_inx];
327 
328  //get value of a shape function
329  double shape_value = sub_shape.svals[H2D_L2FE_VALUE][gip_inx];
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  //double shape_valueA = shapeset->get_fn_value(sub_shape.inx, ref_x, ref_y, 0);
335  //error_if(std::abs(shape_value - shape_valueA) > 1E-14, "A0");
337 
338  //get value of ref. solution
339  Scalar ref_value;
340  ref_value = sub_gip.rvals[H2D_L2FE_VALUE][gip_inx];
341 
342  //evaluate a right-hand value
343  Scalar value = (shape_value * ref_value);
344 
345  total_value += gip_pt[H2D_GIP2D_W] * value;
346  }
347  return total_value;
348  }
349 
350  template<typename Scalar>
352  {
353  double total_error_squared = 0;
354  for(int gip_inx = 0; gip_inx < sub_gip.num_gip_points; gip_inx++)
355  {
356  //get location and transform it
357  double3 &gip_pt = sub_gip.gip_points[gip_inx];
358 
359  //calculate value of projected solution
360  Scalar proj_value = 0;
361  for(int i = 0; i < elem_proj.num_shapes; i++)
362  {
363  int shape_inx = elem_proj.shape_inxs[i];
364  proj_value += elem_proj.shape_coeffs[i] * elem_proj.svals[shape_inx][H2D_L2FE_VALUE][gip_inx];
365  }
366 
367  //get value of ref. solution
368  Scalar ref_value = sub_gip.rvals[H2D_L2FE_VALUE][gip_inx];
369 
370  //evaluate error
371  double error_squared = sqr(proj_value - ref_value);
372 
373  total_error_squared += gip_pt[H2D_GIP2D_W] * error_squared;
374  }
375  return total_error_squared;
376  }
377  template class HERMES_API L2ProjBasedSelector<double>;
378  template class HERMES_API L2ProjBasedSelector<std::complex<double> >;
379  }
380  }
381 }