Hermes2D  2.0
kelly_type_adapt.cpp
1 // This file is part of Hermes2D.
2 //
3 // Hermes2D is free software: you can redistribute it and/or modify
4 // it under the terms of the GNU General Public License as published by
5 // the Free Software Foundation, either version 2 of the License, or
6 // (at your option) any later version.
7 //
8 // Hermes2D is distributed in the hope that it will be useful,
9 // but WITHOUT ANY WARRANTY; without even the implied warranty of
10 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 // GNU General Public License for more details.
12 //
13 // You should have received a copy of the GNU General Public License
14 // along with Hermes2D. If not, see <http://www.gnu.org/licenses/>.
15 #include "kelly_type_adapt.h"
16 
17 namespace Hermes
18 {
19  namespace Hermes2D
20  {
21  static const int H2D_DG_INNER_EDGE_INT = -1234567;
22  static const std::string H2D_DG_INNER_EDGE = "-1234567";
23 
24  template<typename Scalar>
25  BasicKellyAdapt<Scalar>::ErrorEstimatorFormKelly::ErrorEstimatorFormKelly(int i, double const_by_laplacian) : KellyTypeAdapt<Scalar>::ErrorEstimatorForm(i, H2D_DG_INNER_EDGE), const_by_laplacian(const_by_laplacian)
26  {}
27 
28  template<typename Scalar>
30  {
31  this->set_area(H2D_DG_INNER_EDGE);
32  }
33 
34  template<typename Scalar>
36  bool ignore_visited_segments_,
37  Hermes::vector<const InterfaceEstimatorScalingFunction*> interface_scaling_fns_,
38  Hermes::vector<ProjNormType > norms_)
39  : Adapt<Scalar>(spaces_, norms_)
40  {
41  error_estimators_surf.reserve(this->num);
42  error_estimators_vol.reserve(this->num);
43 
44  if(interface_scaling_fns_.size() == 0)
45  {
46  interface_scaling_fns_.reserve(this->num);
47  for (int i = 0; i < this->num; i++)
48  interface_scaling_fns_.push_back(new ScaleByElementDiameter);
49  }
51  interface_scaling_fns = interface_scaling_fns_;
53  ignore_visited_segments = ignore_visited_segments_;
54 
55  element_markers_conversion = spaces_[0]->get_mesh()->element_markers_conversion;
56  boundary_markers_conversion = spaces_[0]->get_mesh()->boundary_markers_conversion;
57  }
58 
59  template<typename Scalar>
61  bool ignore_visited_segments_,
62  const InterfaceEstimatorScalingFunction* interface_scaling_fn_,
63  ProjNormType norm_)
64  : Adapt<Scalar>(space_, norm_)
65  {
66  if(interface_scaling_fn_ == NULL)
68  else
69  interface_scaling_fns.push_back(interface_scaling_fn_);
70 
72 
74  ignore_visited_segments = ignore_visited_segments_;
75 
76  element_markers_conversion = space_->get_mesh()->element_markers_conversion;
77  boundary_markers_conversion = space_->get_mesh()->boundary_markers_conversion;
78  }
79 
80  template<typename Scalar>
81  bool KellyTypeAdapt<Scalar>::adapt(double thr, int strat, int regularize, double to_be_processed)
82  {
83  Hermes::vector<RefinementSelectors::Selector<Scalar> *> refinement_selectors;
85  for (int i = 0; i < this->num; i++)
86  refinement_selectors.push_back(&selector);
87 
88  return Adapt<Scalar>::adapt(refinement_selectors, thr, strat, regularize, to_be_processed);
89  }
90 
91  template<typename Scalar>
93  {
94  if(form->i < 0 || form->i >= this->num)
95  throw Exceptions::ValueException("component number", form->i, 0, this->num);
96 
97  form->adapt = this;
98  this->error_estimators_vol.push_back(form);
99  }
100 
101  template<typename Scalar>
103  {
104  if(form->i < 0 || form->i >= this->num)
105  throw Exceptions::ValueException("component number", form->i, 0, this->num);
106 
107  form->adapt = this;
108  this->error_estimators_surf.push_back(form);
109  }
110 
111  template<typename Scalar>
113  Hermes::vector<double>* component_errors,
114  unsigned int error_flags)
115  {
116  if(slns.size() != this->num)
117  throw Hermes::Exceptions::LengthException(0, slns.size(), this->num);
118 
119  this->tick();
120 
121  for (int i = 0; i < this->num; i++)
122  {
123  this->sln[i] = slns[i];
124  this->sln[i]->set_quad_2d(&g_quad_2d_std);
125  }
126 
127  this->have_coarse_solutions = true;
128 
129  const Mesh** meshes = new const Mesh*[this->num];
130  Transformable** fns = new Transformable*[this->num];
131 
132  this->num_act_elems = 0;
133  for (int i = 0; i < this->num; i++)
134  {
135  meshes[i] = (this->sln[i]->get_mesh());
136  fns[i] = (this->sln[i]);
137 
138  this->num_act_elems += meshes[i]->get_num_active_elements();
139  int max = meshes[i]->get_max_element_id();
140 
141  if(this->errors[i] != NULL) delete [] this->errors[i];
142  this->errors[i] = new double[max];
143  memset(this->errors[i], 0, sizeof(double) * max);
144  }
145 
146  double total_norm = 0.0;
147 
148  bool calc_norm = false;
149  if((error_flags & this->HERMES_ELEMENT_ERROR_MASK) == HERMES_ELEMENT_ERROR_REL ||
150  (error_flags & this->HERMES_TOTAL_ERROR_MASK) == HERMES_TOTAL_ERROR_REL) calc_norm = true;
151 
152  double *norms = NULL;
153  if(calc_norm)
154  {
155  norms = new double[this->num];
156  memset(norms, 0, this->num * sizeof(double));
157  }
158 
159  double *errors_components = new double[this->num];
160  memset(errors_components, 0, this->num * sizeof(double));
161  this->errors_squared_sum = 0.0;
162  double total_error = 0.0;
163 
164  bool bnd[H2D_MAX_NUMBER_EDGES];
165  SurfPos surf_pos[H2D_MAX_NUMBER_EDGES];
166  Traverse::State *ee;
167  Traverse trav(true);
168 
169  // Reset the e->visited status of each element of each mesh (most likely it will be set to true from
170  // the latest assembling procedure).
171  if(ignore_visited_segments)
172  {
173  for (int i = 0; i < this->num; i++)
174  {
175  Element* e;
176  for_all_active_elements(e, meshes[i])
177  e->visited = false;
178  }
179  }
180 
181  // Begin the multimesh traversal.
182  trav.begin(this->num, meshes, fns);
183  while ((ee = trav.get_next_state()) != NULL)
184  {
185  bnd[0] = ee->bnd[0];
186  bnd[1] = ee->bnd[1];
187  bnd[2] = ee->bnd[2];
188  bnd[3] = ee->bnd[3];
189 
190  surf_pos[0].marker = ee->rep->en[0]->marker;
191  surf_pos[1].marker = ee->rep->en[1]->marker;
192  surf_pos[2].marker = ee->rep->en[2]->marker;
193  surf_pos[3].marker = ee->rep->en[3]->marker;
194 
195  surf_pos[0].surf_num = 0;
196  surf_pos[1].surf_num = 1;
197  surf_pos[2].surf_num = 2;
198  surf_pos[3].surf_num = 3;
199 
200  // Go through all solution components.
201  for (int i = 0; i < this->num; i++)
202  {
203  if(ee->e[i] == NULL)
204  continue;
205 
206  // Set maximum integration order for use in integrals, see limit_order()
207  update_limit_table(ee->e[i]->get_mode());
208 
209  RefMap *rm = this->sln[i]->get_refmap();
210 
211  double err = 0.0;
212 
213  // Go through all volumetric error estimators.
214  for (unsigned int iest = 0; iest < error_estimators_vol.size(); iest++)
215  {
216  // Skip current error estimator if it is assigned to a different component or geometric area
217  // different from that of the current active element.
218 
219  if(error_estimators_vol[iest]->i != i)
220  continue;
221 
222  if(error_estimators_vol[iest]->area != HERMES_ANY)
223  if(!element_markers_conversion.get_internal_marker(error_estimators_vol[iest]->area).valid || element_markers_conversion.get_internal_marker(error_estimators_vol[iest]->area).marker != ee->e[i]->marker)
224  continue;
225 
226  err += eval_volumetric_estimator(error_estimators_vol[iest], rm);
227  }
228 
229  // Go through all surface error estimators (includes both interface and boundary est's).
230  for (unsigned int iest = 0; iest < error_estimators_surf.size(); iest++)
231  {
232  if(error_estimators_surf[iest]->i != i)
233  continue;
234 
235  for (int isurf = 0; isurf < ee->e[i]->get_nvert(); isurf++)
236  {
237  if(bnd[isurf]) // Boundary
238  {
239  if(error_estimators_surf[iest]->area != HERMES_ANY)
240  {
241  if(!boundary_markers_conversion.get_internal_marker(error_estimators_surf[iest]->area).valid)
242  continue;
243  int imarker = boundary_markers_conversion.get_internal_marker(error_estimators_surf[iest]->area).marker;
244 
245  if(imarker == H2D_DG_INNER_EDGE_INT)
246  continue;
247  if(imarker != surf_pos[isurf].marker)
248  continue;
249  }
250 
251  err += eval_boundary_estimator(error_estimators_surf[iest], rm, &surf_pos[isurf]);
252  }
253  else // Interface
254  {
255  if(error_estimators_surf[iest]->area != H2D_DG_INNER_EDGE)
256  continue;
257 
258  // BEGIN COPY FROM DISCRETE_PROBLEM.CPP
259 
260  // 5 is for bits per page in the array.
261  LightArray<NeighborSearch<Scalar>*> neighbor_searches(5);
262  unsigned int num_neighbors = 0;
263  NeighborNode* root;
264  int ns_index;
265 
266  // Determine the minimum mesh seq in this stage.
267  unsigned int min_dg_mesh_seq = 0;
268  for(unsigned int j = 0; j < this->spaces.size(); j++)
269  if(this->spaces[j]->get_mesh()->get_seq() < min_dg_mesh_seq || j == 0)
270  min_dg_mesh_seq = this->spaces[j]->get_mesh()->get_seq();
271 
272  ns_index = meshes[i]->get_seq() - min_dg_mesh_seq; // = 0 for single mesh
273 
274  // Initialize the NeighborSearches.
275  this->dp.init_neighbors(neighbor_searches, ee, min_dg_mesh_seq);
276 
277  // Create a multimesh tree;
278  root = new NeighborNode(NULL, 0);
279  this->dp.build_multimesh_tree(root, neighbor_searches);
280 
281  // Update all NeighborSearches according to the multimesh tree.
282  // After this, all NeighborSearches in neighbor_searches should have the same count
283  // of neighbors and proper set of transformations
284  // for the central and the neighbor element(s) alike.
285  // Also check that every NeighborSearch has the same number of neighbor elements.
286  for(unsigned int j = 0; j < neighbor_searches.get_size(); j++)
287  {
288  if(neighbor_searches.present(j))
289  {
290  NeighborSearch<Scalar>* ns = neighbor_searches.get(j);
291  this->dp.update_neighbor_search(ns, root);
292  if(num_neighbors == 0)
293  num_neighbors = ns->n_neighbors;
294  if(ns->n_neighbors != num_neighbors)
295  throw Hermes::Exceptions::Exception("Num_neighbors of different NeighborSearches not matching in KellyTypeAdapt<Scalar>::calc_err_internal.");
296  }
297  }
298 
299  // Go through all segments of the currently processed interface (segmentation is caused
300  // by hanging nodes on the other side of the interface).
301  for (unsigned int neighbor = 0; neighbor < num_neighbors; neighbor++)
302  {
303  if(ignore_visited_segments)
304  {
305  bool processed = true;
306  for(unsigned int j = 0; j < neighbor_searches.get_size(); j++)
307  if(neighbor_searches.present(j))
308  if(!neighbor_searches.get(j)->neighbors.at(neighbor)->visited)
309  {
310  processed = false;
311  break;
312  }
313 
314  if(processed) continue;
315  }
316 
317  // We do not use cache_e and cache_jwt here.
318 
319  // Set the active segment in all NeighborSearches
320  for(unsigned int j = 0; j < neighbor_searches.get_size(); j++)
321  {
322  if(neighbor_searches.present(j))
323  {
324  neighbor_searches.get(j)->active_segment = neighbor;
325  neighbor_searches.get(j)->neighb_el = neighbor_searches.get(j)->neighbors[neighbor];
326  neighbor_searches.get(j)->neighbor_edge = neighbor_searches.get(j)->neighbor_edges[neighbor];
327  }
328  }
329 
330  // Push all the necessary transformations to all functions of this stage.
331  // The important thing is that the transformations to the current subelement are already there.
332  // Also store the current neighbor element and neighbor edge in neighb_el, neighbor_edge.
333  for(unsigned int fns_i = 0; fns_i < this->num; fns_i++)
334  {
335  NeighborSearch<Scalar> *ns = neighbor_searches.get(meshes[fns_i]->get_seq() - min_dg_mesh_seq);
336  if(ns->central_transformations.present(neighbor))
337  ns->central_transformations.get(neighbor)->apply_on(fns[fns_i]);
338  }
339 
340  // END COPY FROM DISCRETE_PROBLEM.CPP
341  rm->force_transform(this->sln[i]->get_transform(), this->sln[i]->get_ctm());
342 
343  // The estimate is multiplied by 0.5 in order to distribute the error equally onto
344  // the two neighboring elements.
345  double central_err = 0.5 * eval_interface_estimator(error_estimators_surf[iest],
346  rm, &surf_pos[isurf], neighbor_searches,
347  ns_index);
348  double neighb_err = central_err;
349 
350  // Scale the error estimate by the scaling function dependent on the element diameter
351  // (use the central element's diameter).
352  if(use_aposteriori_interface_scaling && interface_scaling_fns[i])
353  if(!element_markers_conversion.get_user_marker(ee->e[i]->marker).valid)
354  throw Hermes::Exceptions::Exception("Marker not valid.");
355  else
356  central_err *= interface_scaling_fns[i]->value(ee->e[i]->get_diameter(), element_markers_conversion.get_user_marker(ee->e[i]->marker).marker);
357 
358  // In the case this edge will be ignored when calculating the error for the element on
359  // the other side, add the now computed error to that element as well.
360  if(ignore_visited_segments)
361  {
362  Element *neighb = neighbor_searches.get(ns_index)->neighb_el;
363 
364  // Scale the error estimate by the scaling function dependent on the element diameter
365  // (use the diameter of the element on the other side).
366  if(use_aposteriori_interface_scaling && interface_scaling_fns[i])
367  if(!element_markers_conversion.get_user_marker(neighb->marker).valid)
368  throw Hermes::Exceptions::Exception("Marker not valid.");
369  else
370  neighb_err *= interface_scaling_fns[i]->value(neighb->get_diameter(), element_markers_conversion.get_user_marker(neighb->marker).marker);
371 
372  errors_components[i] += central_err + neighb_err;
373  total_error += central_err + neighb_err;
374  this->errors[i][ee->e[i]->id] += central_err;
375  this->errors[i][neighb->id] += neighb_err;
376  }
377  else
378  err += central_err;
379 
380  // BEGIN COPY FROM DISCRETE_PROBLEM.CPP
381 
382  // Clear the transformations from the RefMaps and all functions.
383  for(unsigned int fns_i = 0; fns_i < this->num; fns_i++)
384  fns[fns_i]->set_transform(neighbor_searches.get(meshes[fns_i]->get_seq() - min_dg_mesh_seq)->original_central_el_transform);
385 
386  rm->set_transform(neighbor_searches.get(ns_index)->original_central_el_transform);
387 
388  // END COPY FROM DISCRETE_PROBLEM.CPP
389  }
390 
391  // BEGIN COPY FROM DISCRETE_PROBLEM.CPP
392 
393  // Delete the multimesh tree;
394  delete root;
395 
396  // Delete the neighbor_searches array.
397  for(unsigned int j = 0; j < neighbor_searches.get_size(); j++)
398  if(neighbor_searches.present(j))
399  delete neighbor_searches.get(j);
400 
401  // END COPY FROM DISCRETE_PROBLEM.CPP
402  }
403  }
404  }
405 
406  if(calc_norm)
407  {
408  double nrm = eval_solution_norm(this->norm_form[i][i], rm, this->sln[i]);
409  norms[i] += nrm;
410  total_norm += nrm;
411  }
412 
413  errors_components[i] += err;
414  total_error += err;
415  this->errors[i][ee->e[i]->id] += err;
416 
417  ee->e[i]->visited = true;
418  }
419  }
420  trav.finish();
421 
422  // Store the calculation for each solution component separately.
423  if(component_errors != NULL)
424  {
425  component_errors->clear();
426  for (int i = 0; i < this->num; i++)
427  {
428  if((error_flags & this->HERMES_TOTAL_ERROR_MASK) == HERMES_TOTAL_ERROR_ABS)
429  component_errors->push_back(sqrt(errors_components[i]));
430  else if((error_flags & this->HERMES_TOTAL_ERROR_MASK) == HERMES_TOTAL_ERROR_REL)
431  component_errors->push_back(sqrt(errors_components[i]/norms[i]));
432  else
433  {
434  throw Hermes::Exceptions::Exception("Unknown total error type (0x%x).", error_flags & this->HERMES_TOTAL_ERROR_MASK);
435  return -1.0;
436  }
437  }
438  }
439 
440  this->tick();
441  this->error_time = this->accumulated();
442 
443  // Make the error relative if needed.
444  if((error_flags & this->HERMES_ELEMENT_ERROR_MASK) == HERMES_ELEMENT_ERROR_REL)
445  {
446  for (int i = 0; i < this->num; i++)
447  {
448  Element* e;
449  for_all_active_elements(e, meshes[i])
450  this->errors[i][e->id] /= norms[i];
451  }
452  }
453 
454  this->errors_squared_sum = total_error;
455 
456  // Element error mask is used here, because this variable is used in the adapt()
457  // function, where the processed error (sum of errors of processed element errors)
458  // is matched to this variable.
459  if((error_flags & this->HERMES_ELEMENT_ERROR_MASK) == HERMES_ELEMENT_ERROR_REL)
460  this->errors_squared_sum /= total_norm;
461 
462  // Prepare an ordered list of elements according to an error.
463  this->fill_regular_queue(meshes);
464  this->have_errors = true;
465 
466  if(calc_norm)
467  delete [] norms;
468  delete [] errors_components;
469 
470  // Return error value.
471  if((error_flags & this->HERMES_TOTAL_ERROR_MASK) == HERMES_TOTAL_ERROR_ABS)
472  return sqrt(total_error);
473  else if((error_flags & this->HERMES_TOTAL_ERROR_MASK) == HERMES_TOTAL_ERROR_REL)
474  return sqrt(total_error / total_norm);
475  else
476  {
477  throw Hermes::Exceptions::Exception("Unknown total error type (0x%x).", error_flags & this->HERMES_TOTAL_ERROR_MASK);
478  return -1.0;
479  }
480  }
481 
482  template<typename Scalar>
484  RefMap *rm, MeshFunction<Scalar>* sln)
485  {
486  // Determine the integration order.
487  int inc = (sln->get_num_components() == 2) ? 1 : 0;
488  Func<Hermes::Ord>* ou = init_fn_ord(sln->get_fn_order() + inc);
489 
490  double fake_wt = 1.0;
491  Geom<Hermes::Ord>* fake_e = init_geom_ord();
492  Hermes::Ord o = form->ord(1, &fake_wt, NULL, ou, ou, fake_e, NULL);
493  int order = rm->get_inv_ref_order();
494  order += o.get_order();
495 
496  Solution<Scalar>*sol = static_cast<Solution<Scalar>*>(sln);
497  if(sol && sol->get_type() == HERMES_EXACT)
498  limit_order_nowarn(order, rm->get_active_element()->get_mode());
499  else
500  limit_order(order, rm->get_active_element()->get_mode());
501 
502  ou->free_ord(); delete ou;
503  delete fake_e;
504 
505  // Evaluate the form.
506  Quad2D* quad = sln->get_quad_2d();
507  double3* pt = quad->get_points(order, sln->get_active_element()->get_mode());
508  int np = quad->get_num_points(order, sln->get_active_element()->get_mode());
509 
510  // Initialize geometry and jacobian*weights.
511  Geom<double>* e = init_geom_vol(rm, order);
512  double* jac = rm->get_jacobian(order);
513  double* jwt = new double[np];
514  for(int i = 0; i < np; i++)
515  jwt[i] = pt[i][2] * jac[i];
516 
517  // Function values.
518  Func<Scalar>* u = init_fn(sln, order);
519  Scalar res = form->value(np, jwt, NULL, u, u, e, NULL);
520 
521  e->free(); delete e;
522  delete [] jwt;
523  u->free_fn(); delete u;
524 
525  return std::abs(res);
526  }
527 
528  template<typename Scalar>
530  RefMap *rm)
531  {
532  // Determine the integration order.
533  int inc = (this->sln[err_est_form->i]->get_num_components() == 2) ? 1 : 0;
534 
535  Func<Hermes::Ord>** oi = new Func<Hermes::Ord>*[this->num];
536  for (int i = 0; i < this->num; i++)
537  oi[i] = init_fn_ord(this->sln[i]->get_fn_order() + inc);
538 
539  // Polynomial order of additional external functions.
540  Func<Hermes::Ord>** fake_ext_fn = new Func<Hermes::Ord>*[err_est_form->ext.size()];
541  for (int i = 0; i < err_est_form->ext.size(); i++)
542  fake_ext_fn[i] = init_fn_ord(err_est_form->ext[i]->get_fn_order());
543 
544  double fake_wt = 1.0;
545  Geom<Hermes::Ord>* fake_e = init_geom_ord();
546  Hermes::Ord o = err_est_form->ord(1, &fake_wt, oi, oi[err_est_form->i], fake_e, fake_ext_fn);
547  int order = rm->get_inv_ref_order();
548  order += o.get_order();
549 
550  limit_order(order, rm->get_active_element()->get_mode());
551 
552  // Clean up.
553  for (int i = 0; i < this->num; i++)
554  {
555  if(oi[i] != NULL)
556  {
557  oi[i]->free_ord();
558  delete oi[i];
559  }
560  }
561  delete [] oi;
562  delete fake_e;
563  for(int i = 0; i < err_est_form->ext.size(); i++)
564  fake_ext_fn[i]->free_ord();
565  delete [] fake_ext_fn;
566 
567  // eval the form
568  Quad2D* quad = this->sln[err_est_form->i]->get_quad_2d();
569  double3* pt = quad->get_points(order, rm->get_active_element()->get_mode());
570  int np = quad->get_num_points(order, rm->get_active_element()->get_mode());
571 
572  // Initialize geometry and jacobian*weights
573  Geom<double>* e = init_geom_vol(rm, order);
574  double* jac = rm->get_jacobian(order);
575  double* jwt = new double[np];
576  for(int i = 0; i < np; i++)
577  jwt[i] = pt[i][2] * jac[i];
578 
579  // Function values.
580  Func<Scalar>** ui = new Func<Scalar>*[this->num];
581 
582  for (int i = 0; i < this->num; i++)
583  ui[i] = init_fn(this->sln[i], order);
584 
585  Func<Scalar>** ext_fn = new Func<Scalar>*[err_est_form->ext.size()];
586  for (unsigned i = 0; i < err_est_form->ext.size(); i++)
587  {
588  if(err_est_form->ext[i] != NULL)
589  ext_fn[i] = init_fn(err_est_form->ext[i], order);
590  else
591  ext_fn[i] = NULL;
592  }
593 
594  Scalar res = volumetric_scaling_const * err_est_form->value(np, jwt, ui, ui[err_est_form->i], e, ext_fn);
595 
596  for (int i = 0; i < this->num; i++)
597  {
598  if(ui[i] != NULL)
599  {
600  ui[i]->free_fn();
601  delete ui[i];
602  }
603  }
604  delete [] ui;
605 
606  for(int i = 0; i < err_est_form->ext.size(); i++)
607  fake_ext_fn[i]->free_fn();
608  delete [] fake_ext_fn;
609 
610  e->free();
611  delete e;
612 
613  delete [] jwt;
614 
615  return std::abs(res);
616  }
617 
618  template<typename Scalar>
620  RefMap *rm, SurfPos* surf_pos)
621  {
622  // Determine the integration order.
623  int inc = (this->sln[err_est_form->i]->get_num_components() == 2) ? 1 : 0;
624  Func<Hermes::Ord>** oi = new Func<Hermes::Ord>*[this->num];
625  for (int i = 0; i < this->num; i++)
626  oi[i] = init_fn_ord(this->sln[i]->get_edge_fn_order(surf_pos->surf_num) + inc);
627 
628  // Polynomial order of additional external functions.
629  Func<Hermes::Ord>** fake_ext_fn = new Func<Hermes::Ord>*[err_est_form->ext.size()];
630  for (int i = 0; i < err_est_form->ext.size(); i++)
631  fake_ext_fn[i] = init_fn_ord(err_est_form->ext[i]->get_fn_order());
632 
633  double fake_wt = 1.0;
634  Geom<Hermes::Ord>* fake_e = init_geom_ord();
635  Hermes::Ord o = err_est_form->ord(1, &fake_wt, oi, oi[err_est_form->i], fake_e, fake_ext_fn);
636  int order = rm->get_inv_ref_order();
637  order += o.get_order();
638 
639  limit_order(order, rm->get_active_element()->get_mode());
640 
641  // Clean up.
642  for (int i = 0; i < this->num; i++)
643  if(oi[i] != NULL)
644  {
645  oi[i]->free_ord();
646  delete oi[i];
647  }
648 
649  delete [] oi;
650  delete fake_e;
651  for(int i = 0; i < err_est_form->ext.size(); i++)
652  fake_ext_fn[i]->free_ord();
653  delete [] fake_ext_fn;
654 
655  // Evaluate the form.
656  Quad2D* quad = this->sln[err_est_form->i]->get_quad_2d();
657  int eo = quad->get_edge_points(surf_pos->surf_num, order, rm->get_active_element()->get_mode());
658  double3* pt = quad->get_points(eo, rm->get_active_element()->get_mode());
659  int np = quad->get_num_points(eo, rm->get_active_element()->get_mode());
660 
661  // Initialize geometry and jacobian*weights.
662  double3* tan;
663  Geom<double>* e = init_geom_surf(rm, surf_pos->surf_num, surf_pos->marker, eo, tan);
664  double* jwt = new double[np];
665  for(int i = 0; i < np; i++)
666  jwt[i] = pt[i][2] * tan[i][2];
667 
668  // Function values
669  Func<Scalar>** ui = new Func<Scalar>*[this->num];
670  for (int i = 0; i < this->num; i++)
671  ui[i] = init_fn(this->sln[i], eo);
672 
673  Func<Scalar>** ext_fn = new Func<Scalar>*[err_est_form->ext.size()];
674  for (unsigned i = 0; i < err_est_form->ext.size(); i++)
675  {
676  if(err_est_form->ext[i] != NULL)
677  ext_fn[i] = init_fn(err_est_form->ext[i], order);
678  else
679  ext_fn[i] = NULL;
680  }
681 
682  Scalar res = boundary_scaling_const *
683  err_est_form->value(np, jwt, ui, ui[err_est_form->i], e, ext_fn);
684 
685  for (int i = 0; i < this->num; i++)
686  if(ui[i] != NULL)
687  {
688  ui[i]->free_fn();
689  delete ui[i];
690  }
691 
692  delete [] ui;
693  for(int i = 0; i < err_est_form->ext.size(); i++)
694  fake_ext_fn[i]->free_fn();
695  delete [] fake_ext_fn;
696 
697  e->free();
698  delete e;
699 
700  delete [] jwt;
701 
702  return std::abs(0.5*res); // Edges are parameterized from 0 to 1 while integration weights
703  // are defined in (-1, 1). Thus multiplying with 0.5 to correct
704  // the weights.
705  }
706 
707  template<typename Scalar>
708  double KellyTypeAdapt<Scalar>::eval_interface_estimator(typename KellyTypeAdapt<Scalar>::ErrorEstimatorForm* err_est_form,
709  RefMap *rm, SurfPos* surf_pos,
710  LightArray<NeighborSearch<Scalar>*>& neighbor_searches,
711  int neighbor_index)
712  {
713  NeighborSearch<Scalar>* nbs = neighbor_searches.get(neighbor_index);
714  Hermes::vector<MeshFunction<Scalar>*> slns;
715  for (int i = 0; i < this->num; i++)
716  slns.push_back(this->sln[i]);
717 
718  // Determine integration order.
719  Func<Hermes::Ord>** fake_ext_fns = new Func<Hermes::Ord>*[err_est_form->ext.size()];
720  for (unsigned int j = 0; j < err_est_form->ext.size(); j++)
721  {
722  int inc = (err_est_form->ext[j]->get_num_components() == 2) ? 1 : 0;
723  int central_order = err_est_form->ext[j]->get_edge_fn_order(neighbor_searches.get(err_est_form->ext[j]->get_mesh()->get_seq())->active_edge) + inc;
724  int neighbor_order = err_est_form->ext[j]->get_edge_fn_order(neighbor_searches.get(err_est_form->ext[j]->get_mesh()->get_seq())->neighbor_edge.local_num_of_edge) + inc;
725  fake_ext_fns[j] = new DiscontinuousFunc<Hermes::Ord>(init_fn_ord(central_order), init_fn_ord(neighbor_order));
726  }
727 
728  // Polynomial order of geometric attributes (eg. for multiplication of a solution with coordinates, normals, etc.).
729  Geom<Hermes::Ord>* fake_e = new InterfaceGeom<Hermes::Ord>(init_geom_ord(), nbs->neighb_el->marker, nbs->neighb_el->id, Hermes::Ord(nbs->neighb_el->get_diameter()));
730  double fake_wt = 1.0;
731  Hermes::Ord o = err_est_form->ord(1, &fake_wt, fake_ext_fns, fake_ext_fns[err_est_form->i], fake_e, NULL);
732 
733  int order = rm->get_inv_ref_order();
734  order += o.get_order();
735 
736  limit_order(order, rm->get_active_element()->get_mode());
737 
738  // Clean up.
739  for (int i = 0; i < this->num; i++)
740  {
741  fake_ext_fns[i]->free_ord();
742  delete fake_ext_fns[i];
743  }
744  delete [] fake_ext_fns;
745 
746  fake_e->free_ord();
747  delete fake_e;
748 
749  //delete fake_ext;
750 
751  Quad2D* quad = this->sln[err_est_form->i]->get_quad_2d();
752  int eo = quad->get_edge_points(surf_pos->surf_num, order, rm->get_active_element()->get_mode());
753  int np = quad->get_num_points(eo, rm->get_active_element()->get_mode());
754  double3* pt = quad->get_points(eo, rm->get_active_element()->get_mode());
755 
756  // Initialize geometry and jacobian*weights (do not use the NeighborSearch caching mechanism).
757  double3* tan;
758  double* jwt = new double[np];
759  for(int i = 0; i < np; i++)
760  jwt[i] = pt[i][2] * tan[i][2];
761 
762  Geom<double>* e = new InterfaceGeom<double>(init_geom_surf(rm, surf_pos->surf_num, surf_pos->marker, eo, tan),
763  nbs->neighb_el->marker,
764  nbs->neighb_el->id,
765  nbs->neighb_el->get_diameter());
766 
767  // Function values.
768  Func<Scalar>** ui = this->dp.init_ext_fns(slns, neighbor_searches, order, 0);
769 
770  Scalar res = interface_scaling_const *
771  err_est_form->value(np, jwt, ui, ui[err_est_form->i], e, NULL);
772 
773  if(ui != NULL)
774  {
775  for(unsigned int i = 0; i < slns.size(); i++)
776  ui[i]->free_fn();
777  delete [] ui;
778  }
779 
780  e->free();
781  delete e;
782 
783  delete [] jwt;
784 
785  return std::abs(0.5*res); // Edges are parameterized from 0 to 1 while integration weights
786  // are defined in (-1, 1). Thus multiplying with 0.5 to correct
787  // the weights.
788  }
789 
790  // #endif
791  template HERMES_API class KellyTypeAdapt<double>;
792  template HERMES_API class KellyTypeAdapt<std::complex<double> >;
793  template HERMES_API class BasicKellyAdapt<double>;
794  template HERMES_API class BasicKellyAdapt<std::complex<double> >;
795  }
796 }