Hermes2D  3.0
solution.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 
16 #include "exact_solution.h"
17 #include "forms.h"
18 #include "solution_h2d_xml.h"
19 #include "ogprojection.h"
20 #include "api2d.h"
21 #include "algebra/dense_matrix_operations.h"
22 #include "util/memory_handling.h"
23 
24 namespace Hermes
25 {
26  namespace Hermes2D
27  {
28  static double3* cheb_tab_tri[11];
29  static double3* cheb_tab_quad[11];
30  static unsigned char cheb_np_tri[11];
31  static unsigned char cheb_np_quad[11];
32 
33  static double3** cheb_tab[2] = { cheb_tab_tri, cheb_tab_quad };
34  static unsigned char* cheb_np[2] = { cheb_np_tri, cheb_np_quad };
35 
36  static class Quad2DCheb : public Quad2D
37  {
38  public:
39 
40  Quad2DCheb()
41  {
42  max_order[0] = max_order[1] = 10;
43  num_tables[0] = num_tables[1] = 11;
44  tables = cheb_tab;
45  np = cheb_np;
46 
47  tables[0][0] = tables[1][0] = nullptr;
48  np[0][0] = np[1][0] = 0;
49 
50  int i, j, k, n, m;
51  double3* pt;
52  for (int mode_i = 0; mode_i <= 1; mode_i++)
53  {
54  for (k = 0; k <= 10; k++)
55  {
56  np[mode_i][k] = n = mode_i ? sqr(k + 1) : (k + 1)*(k + 2) / 2;
57  tables[mode_i][k] = pt = malloc_with_check<double3>(n);
58 
59  for (i = k, m = 0; i >= 0; i--)
60  for (j = k; j >= (mode_i ? 0 : k - i); j--, m++) {
61  pt[m][0] = k ? cos(j * M_PI / k) : 1.0;
62  pt[m][1] = k ? cos(i * M_PI / k) : 1.0;
63  pt[m][2] = 1.0;
64  }
65  }
66  }
67  };
68 
69  ~Quad2DCheb()
70  {
71  for (int mode_i = 0; mode_i <= 1; mode_i++)
72  for (int k = 1; k <= 10; k++)
73  free_with_check(tables[mode_i][k]);
74  }
75 
76  virtual unsigned char get_id()
77  {
78  return 3;
79  };
80 
81  virtual void dummy_fn() {}
82  } g_quad_2d_cheb;
83 
84  template<typename Scalar>
85  void Solution<Scalar>::set_static_verbose_output(bool verbose)
86  {
87  Solution<Scalar>::static_verbose_output = verbose;
88  }
89 
90  template<typename Scalar>
91  bool Solution<Scalar>::static_verbose_output = false;
92 
93  template<typename Scalar>
95  {
96  transform = true;
97  sln_type = HERMES_UNDEF;
98  this->num_components = 0;
99 
100  mono_coeffs = nullptr;
101  elem_coeffs[0] = elem_coeffs[1] = nullptr;
102  elem_orders = nullptr;
103  dxdy_buffer = nullptr;
104  num_coeffs = num_elems = 0;
105  num_dofs = -1;
106 
107  this->set_quad_2d(&g_quad_2d_std);
108  }
109 
110  template<>
112  : MeshFunction<double>()
113  {
114  space_type = HERMES_INVALID_SPACE;
115  this->init();
116  }
117 
118  template<>
119  Solution<std::complex<double> >::Solution()
120  : MeshFunction<std::complex<double> >()
121  {
122  space_type = HERMES_INVALID_SPACE;
123  this->init();
124  }
125 
126  template<>
127  Solution<double>::Solution(MeshSharedPtr mesh) : MeshFunction<double>(mesh)
128  {
129  space_type = HERMES_INVALID_SPACE;
130  this->init();
131  this->mesh = mesh;
132  }
133 
134  template<>
135  Solution<std::complex<double> >::Solution(MeshSharedPtr mesh) : MeshFunction<std::complex<double> >(mesh)
136  {
137  space_type = HERMES_INVALID_SPACE;
138  this->init();
139  this->mesh = mesh;
140  }
141 
142  template<>
143  Solution<double>::Solution(SpaceSharedPtr<double> s, Vector<double>* coeff_vec) : MeshFunction<double>(s->get_mesh())
144  {
145  space_type = s->get_type();
146  this->init();
147  this->mesh = s->get_mesh();
148  Solution<double>::vector_to_solution(coeff_vec, s, this);
149  }
150 
151  template<>
152  Solution<std::complex<double> >::Solution(SpaceSharedPtr<std::complex<double> > s, Vector<std::complex<double> >* coeff_vec) : MeshFunction<std::complex<double> >(s->get_mesh())
153  {
154  space_type = s->get_type();
155  this->init();
156  this->mesh = s->get_mesh();
157  Solution<std::complex<double> >::vector_to_solution(coeff_vec, s, this);
158  }
159 
160  template<>
161  Solution<double>::Solution(SpaceSharedPtr<double> s, double* coeff_vec) : MeshFunction<double>(s->get_mesh())
162  {
163  space_type = s->get_type();
164  this->init();
165  this->mesh = s->get_mesh();
166  Solution<double>::vector_to_solution(coeff_vec, s, this);
167  }
168 
169  template<>
170  Solution<std::complex<double> >::Solution(SpaceSharedPtr<std::complex<double> > s, std::complex<double> * coeff_vec) : MeshFunction<std::complex<double> >(s->get_mesh())
171  {
172  space_type = s->get_type();
173  this->init();
174  this->mesh = s->get_mesh();
175  Solution<std::complex<double> >::vector_to_solution(coeff_vec, s, this);
176  }
177 
178  template<typename Scalar>
180  {
181  const Solution<Scalar>* solution = dynamic_cast<const Solution<Scalar>*>(sln);
182  if (solution == nullptr)
183  throw Exceptions::Exception("The instance is in fact not a Solution instance in copy().");
184 
185  if (solution->sln_type == HERMES_UNDEF)
186  throw Hermes::Exceptions::Exception("Solution being copied is uninitialized.");
187  free();
188 
189  this->mesh = solution->mesh;
190 
191  sln_type = solution->sln_type;
192  space_type = solution->get_space_type();
193  this->num_components = solution->num_components;
194  num_dofs = solution->num_dofs;
195 
196  if (solution->sln_type == HERMES_SLN) // standard solution: copy coefficient arrays
197  {
198  num_coeffs = solution->num_coeffs;
199  num_elems = solution->num_elems;
200  mono_coeffs = malloc_with_check<Solution<Scalar>, Scalar>(num_coeffs, this);
201  memcpy(mono_coeffs, solution->mono_coeffs, sizeof(Scalar)* num_coeffs);
202 
203  for (int l = 0; l < this->num_components; l++)
204  {
205  elem_coeffs[l] = malloc_with_check<Solution<Scalar>, int>(num_elems, this);
206  memcpy(elem_coeffs[l], solution->elem_coeffs[l], sizeof(int)* num_elems);
207  }
208 
209  elem_orders = malloc_with_check<Solution<Scalar>, int>(num_elems, this);
210  memcpy(elem_orders, solution->elem_orders, sizeof(int)* num_elems);
211  init_dxdy_buffer();
212  }
213  else // Const, exact handled differently.
214  throw Hermes::Exceptions::Exception("Undefined or exact solutions cannot be copied into an instance of Solution already coming from computation.");
215 
216  this->element = nullptr;
217  }
218 
219  template<typename Scalar>
221  {
222  Solution<Scalar>* sln = new Solution<Scalar>();
223  sln->copy(this);
224  return sln;
225  }
226 
227  template<typename Scalar>
229  {
230  free_with_check(mono_coeffs);
231  free_with_check(elem_orders);
232  free_with_check(dxdy_buffer);
233 
234  for (int i = 0; i < this->num_components; i++)
235  free_with_check(elem_coeffs[i]);
236 
237  space_type = HERMES_INVALID_SPACE;
238  }
239 
240  template<typename Scalar>
242  {
243  free();
244  }
245 
247  {
248  public:
249  // this is a set of LU-decomposed matrices shared by all Solutions
250  double** mat[2][11];
251  unsigned char* perm[2][11];
252 
253  mono_lu_init()
254  {
255  for (int m = 0; m <= 1; m++)
256  {
257  for (int i = 0; i <= 10; i++)
258  {
259  mat[m][i] = nullptr;
260  perm[m][i] = nullptr;
261  }
262  }
263  }
264 
265  ~mono_lu_init()
266  {
267  for (int m = 0; m <= 1; m++)
268  {
269  for (int i = 0; i <= 10; i++)
270  {
271  free_with_check(mat[m][i], true);
272  free_with_check(perm[m][i]);
273  }
274  }
275  }
276  }
277  mono_lu;
278 
279  template<typename Scalar>
280  double** Solution<Scalar>::calc_mono_matrix(int mode, unsigned char o)
281  {
282  if (mono_lu.mat[mode][o] == nullptr)
283  {
284  unsigned char i, j, m, row;
285  char k, l;
286  double x, y, xn, yn;
287  unsigned char n = this->mode ? sqr(o + 1) : (o + 1)*(o + 2) / 2;
288 
289  // loop through all chebyshev points
290  mono_lu.mat[mode][o] = new_matrix<double>(n, n);
291  for (k = o, row = 0; k >= 0; k--)
292  {
293  y = o ? cos(k * M_PI / o) : 1.0;
294  for (l = o; l >= (this->mode ? 0 : o - k); l--, row++)
295  {
296  x = o ? cos(l * M_PI / o) : 1.0;
297 
298  // each row of the matrix contains all the monomials x^i*y^j
299  for (i = 0, yn = 1.0, m = n - 1; i <= o; i++, yn *= y)
300  for (j = (this->mode ? 0 : i), xn = 1.0; j <= o; j++, xn *= x, m--)
301  mono_lu.mat[mode][o][row][m] = xn * yn;
302  }
303  }
304 
305  double d;
306  if (mono_lu.perm[mode][o] == nullptr)
307  mono_lu.perm[mode][o] = malloc_with_check<Solution<Scalar>, unsigned char>(n, this);
308  ludcmp(mono_lu.mat[mode][o], n, mono_lu.perm[mode][o], &d);
309  }
310 
311  return mono_lu.mat[mode][o];
312  }
313 
314  template<typename Scalar>
315  void Solution<Scalar>::set_coeff_vector(SpaceSharedPtr<Scalar> space, const Vector<Scalar>* vec, bool add_dir_lift, int start_index)
316  {
317  // Sanity check.
318  if (vec == nullptr)
319  throw Exceptions::NullException(2);
320 
321  space_type = space->get_type();
322  Scalar* coeffs = malloc_with_check<Solution<Scalar>, Scalar>(vec->get_size(), this);
323  vec->extract(coeffs);
324  this->set_coeff_vector(space, coeffs, add_dir_lift, start_index);
325  free_with_check(coeffs);
326  }
327 
328  template<typename Scalar>
330  const Scalar* coeff_vec, bool add_dir_lift, int start_index)
331  {
332  PrecalcShapeset pss(space->shapeset);
333 
334  if (Solution<Scalar>::static_verbose_output)
335  Hermes::Mixins::Loggable::Static::info("Solution: set_coeff_vector called.");
336 
337  // Sanity checks.
338  if (space->get_mesh() == nullptr)
339  throw Exceptions::Exception("Mesh == nullptr in Solution<Scalar>::set_coeff_vector().");
340  Helpers::check_for_null(space->get_mesh());
341  Helpers::check_for_null(coeff_vec);
342 
343  if (!space->is_up_to_date())
344  throw Exceptions::Exception("Provided 'space' is not up to date.");
345 
346  if (Solution<Scalar>::static_verbose_output)
347  Hermes::Mixins::Loggable::Static::info("Solution: set_coeff_vector - solution being freed.");
348 
349  this->free();
350 
351  this->space_type = space->get_type();
352  this->num_components = pss.get_num_components();
353  this->sln_type = HERMES_SLN;
354  this->mesh = space->get_mesh();
355 
356  // Allocate the coefficient arrays.
357  num_elems = this->mesh->get_max_element_id();
358  free_with_check(elem_orders);
359  elem_orders = calloc_with_check<Solution<Scalar>, int>(num_elems, this);
360  for (int l = 0; l < this->num_components; l++)
361  {
362  free_with_check(elem_coeffs[l]);
363  elem_coeffs[l] = calloc_with_check<Solution<Scalar>, int>(num_elems, this);
364  }
365 
366  // Obtain element orders, allocate mono_coeffs.
367  Element* e;
368  int o;
369  num_coeffs = 0;
370  for_all_active_elements(e, this->mesh)
371  {
372  this->mode = e->get_mode();
373  o = space->get_element_order(e->id);
374  o = std::max(H2D_GET_H_ORDER(o), H2D_GET_V_ORDER(o));
375  for (unsigned int k = 0; k < e->get_nvert(); k++)
376  {
377  int eo = space->get_edge_order(e, k);
378  if (eo > o)
379  o = eo;
380  }
381 
382  // Hcurl and Hdiv: actual order of functions is one higher than element order
383  if (space->shapeset->get_num_components() == 2)
384  if (o < space->shapeset->get_max_order())
385  o++;
386 
387  num_coeffs += this->mode ? sqr(o + 1) : (o + 1)*(o + 2) / 2;
388  elem_orders[e->id] = o;
389  }
390  num_coeffs *= this->num_components;
391  free_with_check(mono_coeffs);
392  mono_coeffs = malloc_with_check<Solution<Scalar>, Scalar>(num_coeffs, this);
393 
394  // Express the solution on elements as a linear combination of monomials.
395  Quad2D* quad = &g_quad_2d_cheb;
396  pss.set_quad_2d(quad);
397  Scalar* mono = mono_coeffs;
398  for_all_active_elements(e, this->mesh)
399  {
400  this->mode = e->get_mode();
401  o = elem_orders[e->id];
402  unsigned char np = quad->get_num_points(o, e->get_mode());
403 
404  AsmList<Scalar> al;
405  space->get_element_assembly_list(e, &al);
406  pss.set_active_element(e);
407 
408  for (int l = 0; l < this->num_components; l++)
409  {
410  // Obtain solution values for the current element.
411  Scalar* val = mono;
412  elem_coeffs[l][e->id] = (int)(mono - mono_coeffs);
413  memset(val, 0, sizeof(Scalar)*np);
414  for (unsigned int k = 0; k < al.cnt; k++)
415  {
416  pss.set_active_shape(al.idx[k]);
417  pss.set_quad_order(o, H2D_FN_VAL);
418  int dof = al.dof[k];
419  double dir_lift_coeff = add_dir_lift ? 1.0 : 0.0;
420  // By subtracting space->first_dof we make sure that it does not matter where the
421  // enumeration of dofs in the space starts. This ca be either zero or there can be some
422  // offset. By adding start_index we move to the desired section of coeff_vec.
423  Scalar coef = al.coef[k] * (dof >= 0 ? coeff_vec[dof - space->first_dof + start_index] : dir_lift_coeff);
424  const double* shape = pss.get_fn_values(l);
425  for (int i = 0; i < np; i++)
426  val[i] += shape[i] * coef;
427  }
428  mono += np;
429 
430  // solve for the monomial coefficients
431  calc_mono_matrix(this->mode, o);
432  lubksb(mono_lu.mat[this->mode][o], np, mono_lu.perm[this->mode][o], val);
433  }
434  }
435 
436  init_dxdy_buffer();
437  this->element = nullptr;
438  if (Solution<Scalar>::static_verbose_output)
439  Hermes::Mixins::Loggable::Static::info("Solution: set_coeff_vector - done.");
440  }
441 
442  template<typename Scalar>
443  void Solution<Scalar>::vector_to_solutions(const Scalar* solution_vector,
444  std::vector<SpaceSharedPtr<Scalar> > spaces, std::vector<MeshFunctionSharedPtr<Scalar> > solutions,
445  std::vector<bool> add_dir_lift, std::vector<int> start_indices)
446  {
447  Helpers::check_for_null(solution_vector);
448  Helpers::check_length(solutions, spaces);
449 
450  // If start indices are not given, calculate them using the dimension of each space.
451  std::vector<int> start_indices_new;
452  if (start_indices.empty())
453  {
454  int counter = 0;
455  for (unsigned char i = 0; i < spaces.size(); i++)
456  {
457  start_indices_new.push_back(counter);
458  counter += spaces[i]->get_num_dofs();
459  }
460  }
461  else
462  {
463  if (start_indices.size() != spaces.size()) throw Hermes::Exceptions::Exception("Mismatched start indices in vector_to_solutions().");
464  for (unsigned char i = 0; i < spaces.size(); i++)
465  {
466  start_indices_new.push_back(start_indices[i]);
467  }
468  }
469 
470  for (unsigned char i = 0; i < spaces.size(); i++)
471  {
472  if (Solution<Scalar>::static_verbose_output)
473  Hermes::Mixins::Loggable::Static::info("Vector to Solution: %d-th solution", i);
474 
475  if (add_dir_lift == std::vector<bool>())
476  Solution<Scalar>::vector_to_solution(solution_vector, spaces[i], solutions[i], true, start_indices_new[i]);
477  else
478  Solution<Scalar>::vector_to_solution(solution_vector, spaces[i], solutions[i], add_dir_lift[i], start_indices_new[i]);
479  }
480  }
481 
482  template<typename Scalar>
483  void Solution<Scalar>::vector_to_solution(const Scalar* solution_vector, SpaceSharedPtr<Scalar> space,
484  Solution<Scalar>* solution, bool add_dir_lift, int start_index)
485  {
486  Helpers::check_for_null(solution_vector);
487  solution->set_coeff_vector(space, solution_vector, add_dir_lift, start_index);
488  }
489 
490  template<typename Scalar>
491  void Solution<Scalar>::vector_to_solution(const Scalar* solution_vector, SpaceSharedPtr<Scalar> space,
492  MeshFunctionSharedPtr<Scalar> solution, bool add_dir_lift, int start_index)
493  {
494  Helpers::check_for_null(solution_vector);
495 
496  Solution<Scalar>* sln = dynamic_cast<Solution<Scalar>*>(solution.get());
497  if (sln == nullptr)
498  throw Exceptions::Exception("Passed solution is in fact not a Solution instance in vector_to_solution().");
499 
500  sln->set_coeff_vector(space, solution_vector, add_dir_lift, start_index);
501  }
502 
503  template<typename Scalar>
504  void Solution<Scalar>::vector_to_solutions(const Vector<Scalar>* solution_vector, std::vector<SpaceSharedPtr<Scalar> > spaces,
505  std::vector<MeshFunctionSharedPtr<Scalar> > solutions, std::vector<bool> add_dir_lift, std::vector<int> start_indices)
506  {
507  Helpers::check_for_null(solution_vector);
508  Helpers::check_length(solutions, spaces);
509 
510  // If start indices are not given, calculate them using the dimension of each space.
511  std::vector<int> start_indices_new;
512  if (start_indices.empty())
513  {
514  int counter = 0;
515  for (unsigned char i = 0; i < spaces.size(); i++)
516  {
517  start_indices_new.push_back(counter);
518  counter += spaces[i]->get_num_dofs();
519  }
520  }
521  else
522  {
523  if (start_indices.size() != spaces.size()) throw Hermes::Exceptions::Exception("Mismatched start indices in vector_to_solutions().");
524  for (unsigned char i = 0; i < spaces.size(); i++)
525  {
526  start_indices_new.push_back(start_indices[i]);
527  }
528  }
529 
530  for (unsigned char i = 0; i < spaces.size(); i++)
531  {
532  if (Solution<Scalar>::static_verbose_output)
533  Hermes::Mixins::Loggable::Static::info("Vector to Solution: %d-th solution", i);
534 
535  if (add_dir_lift == std::vector<bool>())
536  Solution<Scalar>::vector_to_solution(solution_vector, spaces[i], solutions[i], true, start_indices_new[i]);
537  else
538  Solution<Scalar>::vector_to_solution(solution_vector, spaces[i], solutions[i], add_dir_lift[i], start_indices_new[i]);
539  }
540  }
541 
542  template<typename Scalar>
543  void Solution<Scalar>::vector_to_solutions_common_dir_lift(const Vector<Scalar>* solution_vector, std::vector<SpaceSharedPtr<Scalar> > spaces,
544  std::vector<MeshFunctionSharedPtr<Scalar> > solutions, bool add_dir_lift)
545  {
546  Helpers::check_for_null(solution_vector);
547  Helpers::check_length(spaces, solutions);
548 
549  // If start indices are not given, calculate them using the dimension of each space.
550  std::vector<int> start_indices_new;
551  int counter = 0;
552  for (unsigned char i = 0; i < spaces.size(); i++)
553  {
554  start_indices_new.push_back(counter);
555  counter += spaces[i]->get_num_dofs();
556  }
557 
558  for (unsigned char i = 0; i < spaces.size(); i++)
559  {
560  if (Solution<Scalar>::static_verbose_output)
561  Hermes::Mixins::Loggable::Static::info("Vector to Solution: %d-th solution", i);
562 
563  Solution<Scalar>::vector_to_solution(solution_vector, spaces[i], solutions[i], add_dir_lift, start_indices_new[i]);
564  }
565  }
566 
567  template<typename Scalar>
568  void Solution<Scalar>::vector_to_solutions_common_dir_lift(const Scalar* solution_vector, std::vector<SpaceSharedPtr<Scalar> > spaces,
569  std::vector<MeshFunctionSharedPtr<Scalar> > solutions, bool add_dir_lift)
570  {
571  Helpers::check_for_null(solution_vector);
572  Helpers::check_length(solutions, spaces);
573 
574  // If start indices are not given, calculate them using the dimension of each space.
575  std::vector<int> start_indices_new;
576  int counter = 0;
577  for (unsigned char i = 0; i < spaces.size(); i++)
578  {
579  start_indices_new.push_back(counter);
580  counter += spaces[i]->get_num_dofs();
581  }
582 
583  for (unsigned char i = 0; i < spaces.size(); i++)
584  {
585  if (Solution<Scalar>::static_verbose_output)
586  Hermes::Mixins::Loggable::Static::info("Vector to Solution: %d-th solution", i);
587 
588  Solution<Scalar>::vector_to_solution(solution_vector, spaces[i], solutions[i], add_dir_lift, start_indices_new[i]);
589  }
590  }
591 
592  template<typename Scalar>
593  void Solution<Scalar>::vector_to_solution(const Vector<Scalar>* solution_vector, SpaceSharedPtr<Scalar> space,
594  MeshFunctionSharedPtr<Scalar> solution, bool add_dir_lift, int start_index)
595  {
596  // Sanity checks.
597  Helpers::check_for_null(solution_vector);
598 
599  Solution<Scalar>* sln = dynamic_cast<Solution<Scalar>*>(solution.get());
600  if (sln == nullptr)
601  throw Exceptions::Exception("Passed solution is in fact not a Solution instance in vector_to_solution().");
602 
603  sln->set_coeff_vector(space, solution_vector, add_dir_lift, start_index);
604  }
605 
606  template<typename Scalar>
608  {
609  space_type = space->get_type();
610  int ndof = space->get_num_dofs();
611  Scalar *temp = malloc_with_check<Solution<Scalar>, Scalar>(ndof, this);
612  memset(temp, 0, sizeof(Scalar)*ndof);
613  bool add_dir_lift = true;
614  int start_index = 0;
615  this->set_coeff_vector(space, temp, add_dir_lift, start_index);
616  free_with_check(temp);
617  }
618 
619  template<typename Scalar>
621  {
622  if (transform != enable)
623  this->invalidate_values();
624  transform = enable;
625  }
626 
627  template<typename Scalar>
629  {
630  Scalar* base_vector = malloc_with_check<Solution<Scalar>, Scalar>(target_space->get_num_dofs(), this);
631  Scalar* added_vector = malloc_with_check<Solution<Scalar>, Scalar>(target_space->get_num_dofs(), this);
632  OGProjection<Scalar>::project_global(target_space, this, base_vector);
633  OGProjection<Scalar>::project_global(target_space, other_mesh_function, added_vector);
634 
635  for (int i = 0; i < target_space->get_num_dofs(); i++)
636  base_vector[i] += added_vector[i];
637 
638  this->set_coeff_vector(target_space, base_vector, true, 0);
639  }
640 
641  template<typename Scalar>
642  void Solution<Scalar>::multiply(Scalar coef)
643  {
644  if (sln_type == HERMES_SLN)
645  {
646  for (int i = 0; i < num_coeffs; i++)
647  mono_coeffs[i] *= coef;
648  }
649  else if (sln_type == HERMES_EXACT)
650  dynamic_cast<ExactSolution<Scalar>*>(this)->exact_multiplicator *= coef;
651  else
652  throw Hermes::Exceptions::Exception("Uninitialized solution.");
653  }
654 
655  template<typename Scalar>
656  void Solution<Scalar>::make_dx_coeffs(int mode, int o, Scalar* mono, Scalar* result)
657  {
658  int i, j, k;
659  for (i = 0; i <= o; i++)
660  {
661  *result++ = 0.0;
662  k = mode ? o : i;
663  for (j = 0; j < k; j++)
664  *result++ = (Scalar)(k - j) * mono[j];
665  mono += k + 1;
666  }
667  }
668 
669  template<typename Scalar>
670  void Solution<Scalar>::make_dy_coeffs(int mode, int o, Scalar* mono, Scalar* result)
671  {
672  int i, j;
673  if (mode)
674  {
675  for (j = 0; j <= o; j++)
676  *result++ = 0.0;
677  for (i = 0; i < o; i++)
678  for (j = 0; j <= o; j++)
679  *result++ = (Scalar)(o - i) * (*mono++);
680  }
681  else {
682  for (i = 0; i <= o; i++)
683  {
684  *result++ = 0.0;
685  for (j = 0; j < i; j++)
686  *result++ = (Scalar)(o + 1 - i) * (*mono++);
687  }
688  }
689  }
690 
691  template<typename Scalar>
692  void Solution<Scalar>::init_dxdy_buffer()
693  {
694  free_with_check(dxdy_buffer);
695  dxdy_buffer = malloc_with_check<Solution<Scalar>, Scalar>(this->num_components * 5 * 121, this);
696  }
697 
698  template<typename Scalar>
700  {
702 
703  if (sln_type == HERMES_SLN)
704  {
705  int o = this->order = elem_orders[this->element->id];
706  int n = this->mode ? sqr(o + 1) : (o + 1)*(o + 2) / 2;
707 
708  for (int i = 0, m = 0; i < this->num_components; i++)
709  {
710  Scalar* mono = mono_coeffs + elem_coeffs[i][e->id];
711  dxdy_coeffs[i][0] = mono;
712 
713  make_dx_coeffs(this->mode, o, mono, dxdy_coeffs[i][1] = dxdy_buffer + m); m += n;
714  make_dy_coeffs(this->mode, o, mono, dxdy_coeffs[i][2] = dxdy_buffer + m); m += n;
715 #ifdef H2D_USE_SECOND_DERIVATIVES
716  make_dx_coeffs(this->mode, o, dxdy_coeffs[i][1], dxdy_coeffs[i][3] = dxdy_buffer + m); m += n;
717  make_dy_coeffs(this->mode, o, dxdy_coeffs[i][2], dxdy_coeffs[i][4] = dxdy_buffer + m); m += n;
718  make_dx_coeffs(this->mode, o, dxdy_coeffs[i][2], dxdy_coeffs[i][5] = dxdy_buffer + m); m += n;
719 #endif
720  }
721  }
722  else if (sln_type == HERMES_EXACT)
723  {
724  double x, y;
725  e->get_center(x, y);
726  this->order = (dynamic_cast<ExactSolution<Scalar>*>(this))->ord(x, y).get_order();
727  }
728  else
729  throw Hermes::Exceptions::Exception("Uninitialized solution.");
730  }
731 
732  template<typename Scalar>
733  static inline void set_vec_num(int n, Scalar* y, Scalar num)
734  {
735  for (int i = 0; i < n; i++)
736  y[i] = num;
737  }
738 
739  template<typename Scalar>
740  static inline void vec_x_vec_p_num(int n, Scalar* y, Scalar* x, Scalar num)
741  {
742  for (int i = 0; i < n; i++)
743  y[i] = y[i] * x[i] + num;
744  }
745 
746  template<typename Scalar>
747  static inline void vec_x_vec_p_vec(int n, Scalar* y, Scalar* x, Scalar* z)
748  {
749  for (int i = 0; i < n; i++)
750  y[i] = y[i] * x[i] + z[i];
751  }
752 
753  template<typename Scalar>
754  void Solution<Scalar>::transform_values(int order, int mask, int np)
755  {
756  double2x2 *mat, *m;
757  int i, mstep = 0;
758 
759  // H1 space, L2 space
760  if ((space_type == HERMES_H1_SPACE) || (space_type == HERMES_L2_SPACE))
761  {
762 #ifdef H2D_USE_SECOND_DERIVATIVES
763  if ((newmask & H2D_SECOND) == H2D_SECOND)
764  {
765  this->update_refmap();
766  mat = this->refmap.get_inv_ref_map(order);
767  double3x2 *mm, *mat2 = this->refmap.get_second_ref_map(order);
768  for (i = 0, m = mat, mm = mat2; i < np; i++, m++, mm++)
769  {
770  Scalar vx = this->values[0][1][i];
771  Scalar vy = this->values[0][2][i];
772  Scalar vxx = this->values[0][3][i];
773  Scalar vyy = this->values[0][4][i];
774  Scalar vxy = this->values[0][5][i];
775 
776  // dxx
777  this->values[0][3][i] = sqr((*m)[0][0])*vxx + 2 * (*m)[0][1] * (*m)[0][0] * vxy + sqr((*m)[0][1])*vyy + (*mm)[0][0] * vx + (*mm)[0][1] * vy;
778  // dyy
779  this->values[0][4][i] = sqr((*m)[1][0])*vxx + 2 * (*m)[1][1] * (*m)[1][0] * vxy + sqr((*m)[1][1])*vyy + (*mm)[2][0] * vx + (*mm)[2][1] * vy;
780  //dxy
781  this->values[0][5][i] = (*m)[0][0] * (*m)[1][0] * vxx + ((*m)[0][0] * (*m)[1][1] + (*m)[1][0] * (*m)[0][1])*vxy + (*m)[0][1] * (*m)[1][1] * vyy + (*mm)[1][0] * vx + (*mm)[1][1] * vy;
782  }
783  }
784 #endif
785  if ((mask & H2D_GRAD) == H2D_GRAD)
786  {
787  this->update_refmap();
788  mat = this->refmap.get_const_inv_ref_map();
789  if (!this->refmap.is_jacobian_const()) { mat = this->refmap.get_inv_ref_map(order); mstep = 1; }
790 
791  for (i = 0, m = mat; i < np; i++, m += mstep)
792  {
793  Scalar vx = this->values[0][1][i];
794  Scalar vy = this->values[0][2][i];
795  this->values[0][1][i] = (*m)[0][0] * vx + (*m)[0][1] * vy;
796  this->values[0][2][i] = (*m)[1][0] * vx + (*m)[1][1] * vy;
797  }
798  }
799  }
800 
801  // Hcurl space
802  else if (space_type == HERMES_HCURL_SPACE)
803  {
804  this->update_refmap();
805  mat = this->refmap.get_const_inv_ref_map();
806  if (!this->refmap.is_jacobian_const()) { mat = this->refmap.get_inv_ref_map(order); mstep = 1; }
807 
808  for (i = 0, m = mat; i < np; i++, m += mstep)
809  {
810  if ((mask & H2D_FN_VAL) == H2D_FN_VAL)
811  {
812  Scalar vx = this->values[0][0][i];
813  Scalar vy = this->values[1][0][i];
814  this->values[0][0][i] = (*m)[0][0] * vx + (*m)[0][1] * vy;
815  this->values[1][0][i] = (*m)[1][0] * vx + (*m)[1][1] * vy;
816  }
817  if ((mask & H2D_CURL) == H2D_CURL)
818  {
819  Scalar e0x = this->values[0][1][i], e0y = this->values[0][2][i];
820  Scalar e1x = this->values[1][1][i], e1y = this->values[1][2][i];
821  this->values[1][1][i] = (*m)[0][0] * ((*m)[1][0] * e0x + (*m)[1][1] * e1x) + (*m)[0][1] * ((*m)[1][0] * e0y + (*m)[1][1] * e1y);
822  this->values[0][2][i] = (*m)[1][0] * ((*m)[0][0] * e0x + (*m)[0][1] * e1x) + (*m)[1][1] * ((*m)[0][0] * e0y + (*m)[0][1] * e1y);
823  }
824  }
825  }
826 
827  // Hdiv space
828  else if (space_type == HERMES_HDIV_SPACE)
829  {
830  if ((mask & H2D_FN_VAL) == H2D_FN_VAL)
831  {
832  this->update_refmap();
833  mat = this->refmap.get_const_inv_ref_map();
834  if (!this->refmap.is_jacobian_const()) { mat = this->refmap.get_inv_ref_map(order); mstep = 1; }
835 
836  for (i = 0, m = mat; i < np; i++, m += mstep)
837  {
838  Scalar vx = this->values[0][0][i];
839  Scalar vy = this->values[1][0][i];
840  this->values[0][0][i] = (*m)[1][1] * vx - (*m)[1][0] * vy;
841  this->values[1][0][i] = -(*m)[0][1] * vx + (*m)[0][0] * vy;
842  }
843  }
844  }
845  }
846 
847  template<typename Scalar>
848  void Solution<Scalar>::precalculate(unsigned short order, unsigned short mask)
849  {
850  int i, j, k, l;
851  Quad2D* quad = this->quads[this->cur_quad];
852  unsigned char np = quad->get_num_points(order, this->mode);
853 
854  if (sln_type == HERMES_SLN)
855  {
856  // if we are required to transform vectors, we must precalculate both their components
857  if (transform)
858  {
859  // H1 space or L2 space
860  if (this->num_components == 1)
861  {
862  if ((mask & H2D_FN_DX_0) || (mask & H2D_FN_DY_0)) mask |= H2D_GRAD;
863 #ifdef H2D_USE_SECOND_DERIVATIVES
864  if ((mask & H2D_FN_DXX_0) || (mask & H2D_FN_DXY_0) || (mask & H2D_FN_DYY_0)) mask |= H2D_SECOND;
865 #endif
866  }
867  // Hcurl space
868  else if (space_type == HERMES_HCURL_SPACE)
869  {
870  if ((mask & H2D_FN_VAL_0) || (mask & H2D_FN_VAL_1)) mask |= H2D_FN_VAL;
871  if ((mask & H2D_FN_DX_1) || (mask & H2D_FN_DY_0)) mask |= H2D_CURL;
872  }
873  // Hdiv space
874  else
875  {
876  if ((mask & H2D_FN_VAL_0) || (mask & H2D_FN_VAL_1)) mask |= H2D_FN_VAL;
877  }
878  }
879 
880  // transform integration points by the current matrix
881  double3* pt = quad->get_points(order, this->element->get_mode());
882  for (i = 0; i < np; i++)
883  {
884  x[i] = pt[i][0] * this->ctm->m[0] + this->ctm->t[0];
885  y[i] = pt[i][1] * this->ctm->m[1] + this->ctm->t[1];
886  }
887 
888  // obtain the solution values, this is the core of the whole module
889  int o = elem_orders[this->element->id];
890  for (l = 0; l < this->num_components; l++)
891  {
892  for (k = 0; k < H2D_NUM_FUNCTION_VALUES; k++)
893  {
894  if (mask & this->idx2mask[k][l])
895  {
896  Scalar* result = this->values[l][k];
897 
898  // calculate the solution values using Horner's scheme
899  Scalar* mono = dxdy_coeffs[l][k];
900  for (i = 0; i <= o; i++)
901  {
902  set_vec_num(np, tx, *mono++);
903  for (j = 1; j <= (this->mode ? o : i); j++)
904  vec_x_vec_p_num(np, tx, x, *mono++);
905 
906  if (!i)
907  memcpy(result, tx, sizeof(Scalar)*np);
908  else
909  vec_x_vec_p_vec(np, result, y, tx);
910  }
911  }
912  }
913  }
914 
915  // transform gradient or vector solution, if required
916  if (transform)
917  transform_values(order, mask, np);
918  }
919  else if (sln_type == HERMES_EXACT)
920  {
921  if (mask & ~H2D_FN_DEFAULT)
922  throw Hermes::Exceptions::Exception("Cannot obtain second derivatives of an exact solution.");
923 
924  this->update_refmap();
925  double* x = this->refmap.get_phys_x(order);
926  double* y = this->refmap.get_phys_y(order);
927 
928  // evaluate the exact solution
929  if (this->num_components == 1)
930  {
931  // untransform values
932  if (!transform)
933  {
934  double2x2 *mat, *m;
935  int mstep = 0;
936  mat = this->refmap.get_const_inv_ref_map();
937  if (!this->refmap.is_jacobian_const()) { mat = this->refmap.get_inv_ref_map(order); mstep = 1; }
938 
939  for (i = 0, m = mat; i < np; i++, m += mstep)
940  {
941  double jac = (*m)[0][0] * (*m)[1][1] - (*m)[1][0] * (*m)[0][1];
942  Scalar val, dx = 0.0, dy = 0.0;
943  val = (static_cast<ExactSolutionScalar<Scalar>*>(this))->exact_function(x[i], y[i], dx, dy);
944  this->values[0][0][i] = val * (static_cast<ExactSolutionVector<Scalar>*>(this))->exact_multiplicator;
945  this->values[0][1][i] = ((*m)[1][1] * dx - (*m)[0][1] * dy) / jac * (static_cast<ExactSolutionVector<Scalar>*>(this))->exact_multiplicator;
946  this->values[0][2][i] = (-(*m)[1][0] * dx + (*m)[0][0] * dy) / jac * (static_cast<ExactSolutionVector<Scalar>*>(this))->exact_multiplicator;
947  }
948  }
949  else
950  {
951  for (i = 0; i < np; i++)
952  {
953  Scalar val, dx = 0.0, dy = 0.0;
954  val = (static_cast<ExactSolutionScalar<Scalar>*>(this))->exact_function(x[i], y[i], dx, dy);
955  this->values[0][0][i] = val * (static_cast<ExactSolutionVector<Scalar>*>(this))->exact_multiplicator;
956  this->values[0][1][i] = dx * (static_cast<ExactSolutionVector<Scalar>*>(this))->exact_multiplicator;
957  this->values[0][2][i] = dy * (static_cast<ExactSolutionVector<Scalar>*>(this))->exact_multiplicator;
958  }
959  }
960  }
961  else
962  {
963  for (i = 0; i < np; i++)
964  {
965  Scalar2<Scalar> dx(0.0, 0.0), dy(0.0, 0.0);
966  Scalar2<Scalar> val = (static_cast<ExactSolutionVector<Scalar>*>(this))->exact_function(x[i], y[i], dx, dy);
967  for (j = 0; j < 2; j++)
968  {
969  this->values[j][0][i] = val[j] * (static_cast<ExactSolutionVector<Scalar>*>(this))->exact_multiplicator;
970  this->values[j][1][i] = dx[j] * (static_cast<ExactSolutionVector<Scalar>*>(this))->exact_multiplicator;
971  this->values[j][2][i] = dy[j] * (static_cast<ExactSolutionVector<Scalar>*>(this))->exact_multiplicator;
972  }
973  }
974  }
975  }
976  else
977  {
978  throw Hermes::Exceptions::Exception("Cannot obtain values -- uninitialized solution. The solution was either "
979  "not calculated yet or you used the assignment operator which destroys "
980  "the solution on its right-hand side.");
981  }
982 
983  Function<Scalar>::precalculate(order, mask);
984  }
985 
986  template<>
987  void Solution<double>::save(const char* filename) const
988  {
989  // Check.
990  this->check();
991 
992  try
993  {
994  // Init XML.
995  // With counts, exactness.
996  XMLSolution::solution xmlsolution(this->num_components, this->num_elems, this->num_coeffs, 0, 0);
997 
998  // Space type.
999  xmlsolution.space().set(spaceTypeToString(this->get_space_type()));
1000 
1001  // Coefficients.
1002  for (unsigned int coeffs_i = 0; coeffs_i < this->num_coeffs; coeffs_i++)
1003  xmlsolution.mono_coeffs().push_back(XMLSolution::mono_coeffs(coeffs_i, mono_coeffs[coeffs_i]));
1004 
1005  // Orders.
1006  for (unsigned int elems_i = 0; elems_i < this->num_elems; elems_i++)
1007  xmlsolution.elem_orders().push_back(XMLSolution::elem_orders(elems_i, elem_orders[elems_i]));
1008 
1009  // Element offsets for each component.
1010  for (unsigned int component_i = 0; component_i < this->num_components; component_i++)
1011  {
1012  xmlsolution.component().push_back(XMLSolution::component());
1013  xmlsolution.component().back().component_number() = component_i;
1014  for (unsigned int elems_i = 0; elems_i < this->num_elems; elems_i++)
1015  xmlsolution.component().back().elem_coeffs().push_back(XMLSolution::elem_coeffs(elems_i, elem_coeffs[component_i][elems_i]));
1016  }
1017 
1018  // Write to disk.
1019  ::xml_schema::namespace_infomap namespace_info_map;
1020  std::ofstream out(filename);
1021  ::xml_schema::flags parsing_flags = ::xml_schema::flags::dont_pretty_print;
1022  XMLSolution::solution_(out, xmlsolution, namespace_info_map, "UTF-8", parsing_flags);
1023  out.close();
1024  }
1025  catch (const xml_schema::exception& e)
1026  {
1027  throw Hermes::Exceptions::SolutionSaveFailureException(e.what());
1028  }
1029  }
1030 
1031  template<>
1032  void Solution<std::complex<double> >::save(const char* filename) const
1033  {
1034  // Check.
1035  this->check();
1036 
1037  try
1038  {
1039  // Init XML.
1040  // With counts, exactness.
1041  XMLSolution::solution xmlsolution(this->num_components, this->num_elems, this->num_coeffs, 0, 0);
1042 
1043  // Space type.
1044  xmlsolution.space().set(spaceTypeToString(this->get_space_type()));
1045 
1046  // Coefficients - this is the only difference wrt. the real method.
1047  for (unsigned int coeffs_i = 0; coeffs_i < this->num_coeffs; coeffs_i++)
1048  {
1049  xmlsolution.mono_coeffs().push_back(XMLSolution::mono_coeffs(coeffs_i, mono_coeffs[coeffs_i].real()));
1050  xmlsolution.mono_coeffs().back().im() = mono_coeffs[coeffs_i].imag();
1051  }
1052 
1053  // Orders.
1054  for (unsigned int elems_i = 0; elems_i < this->num_elems; elems_i++)
1055  xmlsolution.elem_orders().push_back(XMLSolution::elem_orders(elems_i, elem_orders[elems_i]));
1056 
1057  // Element offsets for each component.
1058  for (unsigned int component_i = 0; component_i < this->num_components; component_i++)
1059  {
1060  xmlsolution.component().push_back(XMLSolution::component());
1061  xmlsolution.component().back().component_number() = component_i;
1062  for (unsigned int elems_i = 0; elems_i < this->num_elems; elems_i++)
1063  xmlsolution.component().back().elem_coeffs().push_back(XMLSolution::elem_coeffs(elems_i, elem_coeffs[component_i][elems_i]));
1064  }
1065 
1066  // Write to disk.
1067  ::xml_schema::namespace_infomap namespace_info_map;
1068  std::ofstream out(filename);
1069  ::xml_schema::flags parsing_flags = ::xml_schema::flags::dont_pretty_print;
1070  XMLSolution::solution_(out, xmlsolution, namespace_info_map, "UTF-8", parsing_flags);
1071  out.close();
1072  }
1073  catch (const xml_schema::exception& e)
1074  {
1075  throw Hermes::Exceptions::SolutionSaveFailureException(e.what());
1076  }
1077  }
1078 
1079 #ifdef WITH_BSON
1080  template<>
1081  void Solution<double>::save_bson(const char* filename) const
1082  {
1083  // Check.
1084  this->check();
1085 
1086  // Init bson
1087  bson bw;
1088  bson_init(&bw);
1089 
1090  // Space type.
1091  bson_append_string(&bw, "space", spaceTypeToString(this->get_space_type()));
1092 
1093  // Exactness.
1094  bson_append_bool(&bw, "exact", false);
1095 
1096  // Complexness for checking.
1097  bson_append_bool(&bw, "complex", false);
1098 
1099  // Counts.
1100  bson_append_int(&bw, "coeffs_count", this->num_coeffs);
1101  bson_append_int(&bw, "orders_count", this->num_elems);
1102  bson_append_int(&bw, "components_count", this->num_components);
1103 
1104  // Coefficients.
1105  bson_append_start_array(&bw, "coeffs");
1106  for (unsigned int coeffs_i = 0; coeffs_i < this->num_coeffs; coeffs_i++)
1107  bson_append_double(&bw, "c", mono_coeffs[coeffs_i]);
1108  bson_append_finish_array(&bw);
1109 
1110  // Orders.
1111  bson_append_start_array(&bw, "orders");
1112  for (unsigned int elems_i = 0; elems_i < this->num_elems; elems_i++)
1113  bson_append_int(&bw, "o", elem_orders[elems_i]);
1114  bson_append_finish_array(&bw);
1115 
1116  // Element offsets for each component.
1117  bson_append_start_array(&bw, "components");
1118  for (unsigned int component_i = 0; component_i < this->num_components; component_i++)
1119  {
1120  bson_append_start_array(&bw, "component");
1121  for (unsigned int elems_i = 0; elems_i < this->num_elems; elems_i++)
1122  bson_append_int(&bw, "c", elem_coeffs[component_i][elems_i]);
1123  bson_append_finish_array(&bw);
1124  }
1125  bson_append_finish_array(&bw);
1126 
1127  // Done.
1128  bson_finish(&bw);
1129 
1130  // Write to disk.
1131  FILE *fpw;
1132  fpw = fopen(filename, "wb");
1133  const char *dataw = (const char *)bson_data(&bw);
1134  fwrite(dataw, bson_size(&bw), 1, fpw);
1135  fclose(fpw);
1136 
1137  bson_destroy(&bw);
1138  }
1139 
1140  template<>
1141  void Solution<std::complex<double> >::save_bson(const char* filename) const
1142  {
1143  // Check.
1144  this->check();
1145 
1146  // Init bson
1147  bson bw;
1148  bson_init(&bw);
1149 
1150  // Space type.
1151  bson_append_string(&bw, "space", spaceTypeToString(this->get_space_type()));
1152 
1153  // Exactness.
1154  bson_append_bool(&bw, "exact", false);
1155 
1156  // Complexness for checking.
1157  bson_append_bool(&bw, "complex", true);
1158 
1159  // Counts.
1160  bson_append_int(&bw, "coeffs_count", this->num_coeffs);
1161  bson_append_int(&bw, "orders_count", this->num_elems);
1162  bson_append_int(&bw, "components_count", this->num_components);
1163 
1164  // Coefficients.
1165  bson_append_start_array(&bw, "coeffs-real");
1166  for (unsigned int coeffs_i = 0; coeffs_i < this->num_coeffs; coeffs_i++)
1167  bson_append_double(&bw, "c", mono_coeffs[coeffs_i].real());
1168  bson_append_finish_array(&bw);
1169 
1170  bson_append_start_array(&bw, "coeffs-imag");
1171  for (unsigned int coeffs_i = 0; coeffs_i < this->num_coeffs; coeffs_i++)
1172  bson_append_double(&bw, "c", mono_coeffs[coeffs_i].imag());
1173  bson_append_finish_array(&bw);
1174 
1175  // Orders.
1176  bson_append_start_array(&bw, "orders");
1177  for (unsigned int elems_i = 0; elems_i < this->num_elems; elems_i++)
1178  bson_append_int(&bw, "o", elem_orders[elems_i]);
1179  bson_append_finish_array(&bw);
1180 
1181  // Element offsets for each component.
1182  bson_append_start_array(&bw, "components");
1183  for (unsigned int component_i = 0; component_i < this->num_components; component_i++)
1184  {
1185  bson_append_start_array(&bw, "component");
1186  for (unsigned int elems_i = 0; elems_i < this->num_elems; elems_i++)
1187  bson_append_int(&bw, "c", elem_coeffs[component_i][elems_i]);
1188  bson_append_finish_array(&bw);
1189  }
1190  bson_append_finish_array(&bw);
1191 
1192  // Done.
1193  bson_finish(&bw);
1194 
1195  // Write to disk.
1196  FILE *fpw;
1197  fpw = fopen(filename, "wb");
1198  const char *dataw = (const char *)bson_data(&bw);
1199  fwrite(dataw, bson_size(&bw), 1, fpw);
1200  fclose(fpw);
1201 
1202  bson_destroy(&bw);
1203  }
1204 #endif
1205 
1206  template<>
1207  void Solution<double>::load_exact_solution(int number_of_components, SpaceSharedPtr<double> space, bool complexness,
1208  double x_real, double y_real, double x_complex, double y_complex)
1209  {
1210  switch (number_of_components)
1211  {
1212  case 1:
1213  if (!complexness)
1214  {
1215  double* coeff_vec = malloc_with_check<double>(space->get_num_dofs());
1216  MeshFunctionSharedPtr<double> sln(new ConstantSolution<double>(this->mesh, x_real));
1217  OGProjection<double>::project_global(space, sln, coeff_vec);
1218  this->set_coeff_vector(space, coeff_vec, true, 0);
1219  sln_type = HERMES_SLN;
1220  }
1221  else
1222  throw Hermes::Exceptions::SolutionLoadFailureException("Mismatched real - complex exact solutions.");
1223  break;
1224  case 2:
1225  if (!complexness)
1226  {
1227  double* coeff_vec = malloc_with_check<double>(space->get_num_dofs());
1228  MeshFunctionSharedPtr<double> sln(new ConstantSolutionVector<double>(this->mesh, x_real, y_real));
1229  OGProjection<double>::project_global(space, sln, coeff_vec);
1230  this->set_coeff_vector(space, coeff_vec, true, 0);
1231  this->sln_type = HERMES_SLN;
1232  }
1233  else
1234  throw Hermes::Exceptions::SolutionLoadFailureException("Mismatched real - complex exact solutions.");
1235  break;
1236  }
1237  }
1238 
1239  template<>
1240  void Solution<std::complex<double> >::load_exact_solution(int number_of_components, SpaceSharedPtr<std::complex<double> > space, bool complexness,
1241  double x_real, double y_real, double x_complex, double y_complex)
1242  {
1243  switch (number_of_components)
1244  {
1245  case 1:
1246  if (complexness)
1247  {
1248  std::complex<double>* coeff_vec = malloc_with_check<std::complex<double> >(space->get_num_dofs());
1249  MeshFunctionSharedPtr<std::complex<double> > sln(new ConstantSolution<std::complex<double> >(this->mesh, std::complex<double>(x_real, x_complex)));
1250  OGProjection<std::complex<double> >::project_global(space, sln, coeff_vec);
1251  this->set_coeff_vector(space, coeff_vec, true, 0);
1252  sln_type = HERMES_SLN;
1253  }
1254  else
1255  throw Hermes::Exceptions::SolutionLoadFailureException("Mismatched real - complex exact solutions.");
1256  break;
1257  case 2:
1258  if (complexness == 1)
1259  {
1260  std::complex<double>* coeff_vec = malloc_with_check<std::complex<double> >(space->get_num_dofs());
1261  MeshFunctionSharedPtr<std::complex<double> > sln(new ConstantSolutionVector<std::complex<double> >(this->mesh, std::complex<double>(x_real, x_complex), std::complex<double>(y_real, y_complex)));
1262  OGProjection<std::complex<double> >::project_global(space, sln, coeff_vec);
1263  this->set_coeff_vector(space, coeff_vec, true, 0);
1264  sln_type = HERMES_SLN;
1265  }
1266  else
1267  throw Hermes::Exceptions::SolutionLoadFailureException("Mismatched real - complex exact solutions.");
1268  break;
1269  }
1270  }
1271 
1272  template<>
1273  void Solution<double>::load(const char* filename, SpaceSharedPtr<double> space)
1274  {
1275  free();
1276  this->mesh = space->get_mesh();
1277  this->space_type = space->get_type();
1278 
1279  try
1280  {
1281  ::xml_schema::flags parsing_flags = 0;
1282  if (!this->validate)
1283  parsing_flags = xml_schema::flags::dont_validate;
1284 
1285  std::auto_ptr<XMLSolution::solution> parsed_xml_solution(XMLSolution::solution_(filename, parsing_flags));
1286  sln_type = parsed_xml_solution->exact() == 0 ? HERMES_SLN : HERMES_EXACT;
1287 
1288  if (parsed_xml_solution->ncmp() != space->get_shapeset()->get_num_components())
1289  throw Exceptions::Exception("Mismatched space / saved solution.");
1290 
1291  if (sln_type == HERMES_EXACT)
1292  this->load_exact_solution(parsed_xml_solution->ncmp(), space, parsed_xml_solution->exactC(), parsed_xml_solution->exactCXR().get(), parsed_xml_solution->exactCYR().get(), parsed_xml_solution->exactCXC().get(), parsed_xml_solution->exactCYC().get());
1293  else
1294  {
1295  this->check_space_type_compliance(parsed_xml_solution->space().get().c_str());
1296 
1297  this->num_coeffs = parsed_xml_solution->nc();
1298  this->num_elems = parsed_xml_solution->nel();
1299  this->num_components = parsed_xml_solution->ncmp();
1300 
1301  this->mono_coeffs = malloc_with_check<Solution<double>, double>(num_coeffs, this);
1302  memset(this->mono_coeffs, 0, this->num_coeffs*sizeof(double));
1303 
1304  for (unsigned int component_i = 0; component_i < num_components; component_i++)
1305  elem_coeffs[component_i] = malloc_with_check<Solution<double>, int>(num_elems, this);
1306 
1307  this->elem_orders = malloc_with_check<Solution<double>, int>(num_elems, this);
1308 
1309  for (unsigned int coeffs_i = 0; coeffs_i < num_coeffs; coeffs_i++)
1310  this->mono_coeffs[parsed_xml_solution->mono_coeffs().at(coeffs_i).id()] = parsed_xml_solution->mono_coeffs().at(coeffs_i).re();
1311 
1312  for (unsigned int elems_i = 0; elems_i < num_elems; elems_i++)
1313  this->elem_orders[parsed_xml_solution->elem_orders().at(elems_i).id()] = parsed_xml_solution->elem_orders().at(elems_i).ord();
1314 
1315  for (unsigned int component_i = 0; component_i < this->num_components; component_i++)
1316  for (unsigned int elems_i = 0; elems_i < num_elems; elems_i++)
1317  this->elem_coeffs[component_i][parsed_xml_solution->component().at(component_i).elem_coeffs().at(elems_i).id()] = parsed_xml_solution->component().at(component_i).elem_coeffs().at(elems_i).c();
1318  }
1319  init_dxdy_buffer();
1320  }
1321  catch (const xml_schema::exception& e)
1322  {
1323  throw Hermes::Exceptions::SolutionLoadFailureException(e.what());
1324  }
1325  }
1326 
1327  template<>
1328  void Solution<std::complex<double> >::load(const char* filename, SpaceSharedPtr<std::complex<double> > space)
1329  {
1330  free();
1331  sln_type = HERMES_SLN;
1332  this->mesh = space->get_mesh();
1333  this->space_type = space->get_type();
1334 
1335  try
1336  {
1337  ::xml_schema::flags parsing_flags = 0;
1338  if (!this->validate)
1339  parsing_flags = xml_schema::flags::dont_validate;
1340 
1341  std::auto_ptr<XMLSolution::solution> parsed_xml_solution(XMLSolution::solution_(filename, parsing_flags));
1342  sln_type = parsed_xml_solution->exact() == 0 ? HERMES_SLN : HERMES_EXACT;
1343 
1344  if (parsed_xml_solution->ncmp() != space->get_shapeset()->get_num_components())
1345  throw Exceptions::Exception("Mismatched space / saved solution.");
1346 
1347  if (sln_type == HERMES_EXACT)
1348  this->load_exact_solution(parsed_xml_solution->ncmp(), space, parsed_xml_solution->exactC(), parsed_xml_solution->exactCXR().get(), parsed_xml_solution->exactCYR().get(), parsed_xml_solution->exactCXC().get(), parsed_xml_solution->exactCYC().get());
1349  else
1350  {
1351  this->check_space_type_compliance(parsed_xml_solution->space().get().c_str());
1352 
1353  ::xml_schema::flags parsing_flags = 0;
1354  if (!this->validate)
1355  parsing_flags = xml_schema::flags::dont_validate;
1356 
1357  std::auto_ptr<XMLSolution::solution> parsed_xml_solution(XMLSolution::solution_(filename, parsing_flags));
1358 
1359  this->num_coeffs = parsed_xml_solution->nc();
1360  this->num_elems = parsed_xml_solution->nel();
1361  this->num_components = parsed_xml_solution->ncmp();
1362 
1363  this->mono_coeffs = malloc_with_check<Solution<std::complex<double> >, std::complex<double> >(num_coeffs, this);
1364  memset(this->mono_coeffs, 0, this->num_coeffs*sizeof(std::complex<double>));
1365 
1366  for (unsigned int component_i = 0; component_i < num_components; component_i++)
1367  elem_coeffs[component_i] = malloc_with_check<Solution<std::complex<double> >, int>(num_elems, this);
1368 
1369  this->elem_orders = malloc_with_check<Solution<std::complex<double> >, int>(num_elems, this);
1370 
1371  for (unsigned int coeffs_i = 0; coeffs_i < num_coeffs; coeffs_i++)
1372  this->mono_coeffs[parsed_xml_solution->mono_coeffs().at(coeffs_i).id()] = std::complex<double>(parsed_xml_solution->mono_coeffs().at(coeffs_i).re(), parsed_xml_solution->mono_coeffs().at(coeffs_i).im().get());
1373 
1374  for (unsigned int elems_i = 0; elems_i < num_elems; elems_i++)
1375  this->elem_orders[parsed_xml_solution->elem_orders().at(elems_i).id()] = parsed_xml_solution->elem_orders().at(elems_i).ord();
1376 
1377  for (unsigned int component_i = 0; component_i < this->num_components; component_i++)
1378  for (unsigned int elems_i = 0; elems_i < num_elems; elems_i++)
1379  this->elem_coeffs[component_i][parsed_xml_solution->component().at(component_i).elem_coeffs().at(elems_i).id()] = parsed_xml_solution->component().at(component_i).elem_coeffs().at(elems_i).c();
1380  }
1381 
1382  init_dxdy_buffer();
1383  }
1384  catch (const xml_schema::exception& e)
1385  {
1386  throw Hermes::Exceptions::SolutionLoadFailureException(e.what());
1387  }
1388  }
1389 
1390 #ifdef WITH_BSON
1391  template<>
1392  void Solution<double>::load_bson(const char* filename, SpaceSharedPtr<double> space)
1393  {
1394  free();
1395  this->mesh = space->get_mesh();
1396  this->space_type = space->get_type();
1397 
1398  FILE *fpr;
1399  fpr = fopen(filename, "rb");
1400 
1401  // file size:
1402  fseek(fpr, 0, SEEK_END);
1403  int size = ftell(fpr);
1404  rewind(fpr);
1405 
1406  // allocate memory to contain the whole file:
1407  char *datar = malloc_with_check<char>(size);
1408  fread(datar, size, 1, fpr);
1409  fclose(fpr);
1410 
1411  bson br;
1412  bson_init_finished_data(&br, datar, 0);
1413  // bson_print(&br);
1414 
1415  bson sub;
1416  bson_iterator it;
1417 
1418  bson_iterator it_exact;
1419  bson_find(&it_exact, &br, "exact");
1420  sln_type = bson_iterator_bool(&it_exact) ? HERMES_EXACT : HERMES_SLN;
1421 
1422  bson_iterator it_complex;
1423  bson_find(&it_complex, &br, "complex");
1424  bool is_complex = bson_iterator_bool(&it_complex);
1425 
1426  bson_iterator it_components;
1427  bson_find(&it_components, &br, "components_count");
1428  if (bson_iterator_int(&it_components) != space->get_shapeset()->get_num_components())
1429  throw Exceptions::Exception("Mismatched space / saved solution.");
1430  else
1431  this->num_components = bson_iterator_int(&it_components);
1432 
1433  if (sln_type == HERMES_EXACT)
1434  {
1435  std::vector<double> values;
1436  // values
1437  bson_find(&it, &br, "values");
1438  bson_iterator_subobject_init(&it, &sub, 0);
1439  bson_iterator_init(&it, &sub);
1440  while (bson_iterator_next(&it))
1441  values.push_back(bson_iterator_double(&it));
1442  this->load_exact_solution(this->num_components, space, is_complex, values[0], values[1], values[2], values[3]);
1443  }
1444  else
1445  {
1446  // space
1447  bson_iterator it_sp;
1448  bson_find(&it_sp, &br, "space");
1449  const char *sp = bson_iterator_string(&it_sp);
1450 
1451  this->check_space_type_compliance(sp);
1452 
1453  bson_iterator it_coeffs, it_orders;
1454  bson_find(&it_coeffs, &br, "coeffs_count");
1455  bson_find(&it_orders, &br, "orders_count");
1456 
1457  this->num_coeffs = bson_iterator_int(&it_coeffs);
1458  this->num_elems = bson_iterator_int(&it_orders);
1459 
1460  this->mono_coeffs = malloc_with_check<double>(num_coeffs);
1461 
1462  for (unsigned int component_i = 0; component_i < num_components; component_i++)
1463  this->elem_coeffs[component_i] = malloc_with_check<int>(num_elems);
1464 
1465  this->elem_orders = malloc_with_check<int>(num_elems);
1466 
1467  // coeffs
1468  bson_find(&it_coeffs, &br, "coeffs");
1469  bson_iterator_subobject_init(&it_coeffs, &sub, 0);
1470  bson_iterator_init(&it, &sub);
1471  int index_coeff = 0;
1472  while (bson_iterator_next(&it))
1473  this->mono_coeffs[index_coeff++] = bson_iterator_double(&it);
1474 
1475  // elem order
1476  bson_find(&it_orders, &br, "orders");
1477  bson_iterator_subobject_init(&it_orders, &sub, 0);
1478  bson_iterator_init(&it, &sub);
1479  int index_order = 0;
1480  while (bson_iterator_next(&it))
1481  this->elem_orders[index_order++] = bson_iterator_int(&it);
1482 
1483  //
1484  bson_find(&it_components, &br, "components");
1485  bson_iterator_subobject_init(&it_components, &sub, 0);
1486  bson_iterator_init(&it, &sub);
1487  int index_comp = 0;
1488  while (bson_iterator_next(&it))
1489  {
1490  bson sub_coeffs;
1491  bson_iterator_subobject_init(&it, &sub_coeffs, 0);
1492  bson_iterator it_coeffs;
1493  bson_iterator_init(&it_coeffs, &sub_coeffs);
1494 
1495  int index_coeff = 0;
1496  while (bson_iterator_next(&it_coeffs))
1497  this->elem_coeffs[index_comp][index_coeff++] = bson_iterator_int(&it_coeffs);
1498 
1499  index_comp++;
1500  }
1501  }
1502 
1503  bson_destroy(&br);
1504  free_with_check(datar);
1505 
1506  init_dxdy_buffer();
1507  }
1508 
1509  template<>
1510  void Solution<std::complex<double> >::load_bson(const char* filename, SpaceSharedPtr<std::complex<double> > space)
1511  {
1512  free();
1513  this->mesh = space->get_mesh();
1514  this->space_type = space->get_type();
1515 
1516  FILE *fpr;
1517  fpr = fopen(filename, "rb");
1518 
1519  // file size:
1520  fseek(fpr, 0, SEEK_END);
1521  int size = ftell(fpr);
1522  rewind(fpr);
1523 
1524  // allocate memory to contain the whole file:
1525  char *datar = malloc_with_check<char>(size);
1526  fread(datar, size, 1, fpr);
1527  fclose(fpr);
1528 
1529  bson br;
1530  bson_init_finished_data(&br, datar, 0);
1531  // bson_print(&br);
1532 
1533  bson sub;
1534  bson_iterator it;
1535 
1536  bson_iterator it_exact;
1537  bson_find(&it_exact, &br, "exact");
1538  sln_type = bson_iterator_bool(&it_exact) ? HERMES_EXACT : HERMES_SLN;
1539 
1540  bson_iterator it_complex;
1541  bson_find(&it_complex, &br, "complex");
1542  bool is_complex = bson_iterator_bool(&it_complex);
1543 
1544  bson_iterator it_components;
1545  bson_find(&it_components, &br, "components_count");
1546  if (bson_iterator_int(&it_components) != space->get_shapeset()->get_num_components())
1547  throw Exceptions::Exception("Mismatched space / saved solution.");
1548  else
1549  this->num_components = bson_iterator_int(&it_components);
1550 
1551  if (sln_type == HERMES_EXACT)
1552  {
1553  std::vector<double> values;
1554  // values
1555  bson_find(&it, &br, "values");
1556  bson_iterator_subobject_init(&it, &sub, 0);
1557  bson_iterator_init(&it, &sub);
1558  while (bson_iterator_next(&it))
1559  values.push_back(bson_iterator_double(&it));
1560  this->load_exact_solution(this->num_components, space, is_complex, values[0], values[1], values[2], values[3]);
1561  }
1562  else
1563  {
1564  // space
1565  bson_iterator it_sp;
1566  bson_find(&it_sp, &br, "space");
1567  const char *sp = bson_iterator_string(&it_sp);
1568 
1569  this->check_space_type_compliance(sp);
1570 
1571  bson_iterator it_coeffs, it_coeffs_real, it_coeffs_imag, it_orders;
1572  bson_find(&it_coeffs, &br, "coeffs_count");
1573  bson_find(&it_orders, &br, "orders_count");
1574 
1575  this->num_coeffs = bson_iterator_int(&it_coeffs);
1576  this->num_elems = bson_iterator_int(&it_orders);
1577 
1578  this->mono_coeffs = malloc_with_check<std::complex<double> >(num_coeffs);
1579 
1580  for (unsigned int component_i = 0; component_i < num_components; component_i++)
1581  this->elem_coeffs[component_i] = malloc_with_check<int>(num_elems);
1582 
1583  this->elem_orders = malloc_with_check<int>(num_elems);
1584 
1585  // coeffs.
1586  std::vector<double> real_coeffs, imag_coeffs;
1587  bson_find(&it_coeffs_real, &br, "coeffs-real");
1588  bson_iterator_subobject_init(&it_coeffs_real, &sub, 0);
1589  bson_iterator_init(&it, &sub);
1590  while (bson_iterator_next(&it))
1591  real_coeffs.push_back(bson_iterator_double(&it));
1592 
1593  bson_find(&it_coeffs_imag, &br, "coeffs-imag");
1594  bson_iterator_subobject_init(&it_coeffs_imag, &sub, 0);
1595  bson_iterator_init(&it, &sub);
1596  while (bson_iterator_next(&it))
1597  imag_coeffs.push_back(bson_iterator_double(&it));
1598 
1599  for (unsigned short i = 0; i < imag_coeffs.size(); i++)
1600  this->mono_coeffs[i] = std::complex<double>(real_coeffs[i], imag_coeffs[i]);
1601 
1602  // elem order
1603  bson_find(&it_orders, &br, "orders");
1604  bson_iterator_subobject_init(&it_orders, &sub, 0);
1605  bson_iterator_init(&it, &sub);
1606  int index_order = 0;
1607  while (bson_iterator_next(&it))
1608  this->elem_orders[index_order++] = bson_iterator_int(&it);
1609 
1610  //
1611  bson_find(&it_components, &br, "components");
1612  bson_iterator_subobject_init(&it_components, &sub, 0);
1613  bson_iterator_init(&it, &sub);
1614  int index_comp = 0;
1615  while (bson_iterator_next(&it))
1616  {
1617  bson sub_coeffs;
1618  bson_iterator_subobject_init(&it, &sub_coeffs, 0);
1619  bson_iterator it_coeffs;
1620  bson_iterator_init(&it_coeffs, &sub_coeffs);
1621 
1622  int index_coeff = 0;
1623  while (bson_iterator_next(&it_coeffs))
1624  this->elem_coeffs[index_comp][index_coeff++] = bson_iterator_int(&it_coeffs);
1625 
1626  index_comp++;
1627  }
1628  }
1629 
1630  bson_destroy(&br);
1631  free_with_check(datar);
1632 
1633  init_dxdy_buffer();
1634  }
1635 #endif
1636 
1637  template<typename Scalar>
1639  {
1640  bool okay = MeshFunction<Scalar>::isOkay();
1641 
1642  okay = (this->sln_type == HERMES_EXACT || this->get_space_type() != HERMES_INVALID_SPACE) && okay;
1643 
1644  if (sln_type == HERMES_UNDEF)
1645  {
1646  okay = false;
1647  throw Exceptions::Exception("Uninitialized space type.");
1648  }
1649 
1650  return okay;
1651  }
1652 
1653  template<typename Scalar>
1654  void Solution<Scalar>::check_space_type_compliance(const char* space_type_to_check) const
1655  {
1656  if (!strcmp(space_type_to_check, "h1"))
1657  if (this->space_type != HERMES_H1_SPACE)
1658  throw Exceptions::Exception("Space types not compliant in Solution::load().");
1659 
1660  if (!strcmp(space_type_to_check, "l2"))
1661  if (this->space_type != HERMES_L2_SPACE)
1662  throw Exceptions::Exception("Space types not compliant in Solution::load().");
1663 
1664  if (!strcmp(space_type_to_check, "hcurl"))
1665  if (this->space_type != HERMES_HCURL_SPACE)
1666  throw Exceptions::Exception("Space types not compliant in Solution::load().");
1667 
1668  if (!strcmp(space_type_to_check, "hdiv"))
1669  if (this->space_type != HERMES_HDIV_SPACE)
1670  throw Exceptions::Exception("Space types not compliant in Solution::load().");
1671 
1672  if (!strcmp(space_type_to_check, "l2-markerwise"))
1673  if (this->space_type != HERMES_L2_MARKERWISE_CONST_SPACE)
1674  throw Exceptions::Exception("Space types not compliant in Solution::load().");
1675  }
1676 
1677  template<typename Scalar>
1678  Scalar Solution<Scalar>::get_ref_value(Element* e, double xi1, double xi2, int component, int item)
1679  {
1680  Helpers::check_for_null(e);
1681  set_active_element(e);
1682 
1683  int o = elem_orders[e->id];
1684  Scalar* mono = dxdy_coeffs[component][item];
1685  Scalar result = 0.0;
1686  int k = 0;
1687  for (int i = 0; i <= o; i++)
1688  {
1689  Scalar row = mono[k++];
1690  for (int j = 0; j < (this->mode ? o : i); j++)
1691  row = row * xi1 + mono[k++];
1692  result = result * xi2 + row;
1693  }
1694 
1695  this->invalidate_values();
1696  return result;
1697  }
1698 
1699  template<typename Scalar>
1700  Scalar Solution<Scalar>::get_ref_value_transformed(Element* e, double xi1, double xi2, int a, int b)
1701  {
1702  Helpers::check_for_null(e);
1703 
1704  if (this->sln_type != HERMES_SLN)
1705  throw Exceptions::Exception("Solution::get_ref_value_transformed only works for solutions wrt. FE space, project if you want to use the method for exact solutions.");
1706 
1707  set_active_element(e);
1708 
1709  if (this->num_components == 1)
1710  {
1711  if (b == 0)
1712  return get_ref_value(e, xi1, xi2, a, b);
1713  if (b == 1 || b == 2)
1714  {
1715  double2x2 m;
1716  double xx, yy;
1717  this->refmap.inv_ref_map_at_point(xi1, xi2, xx, yy, m);
1718  Scalar dx = get_ref_value(e, xi1, xi2, a, 1);
1719  Scalar dy = get_ref_value(e, xi1, xi2, a, 2);
1720  // H2D_FN_DX
1721  if (b == 1) return m[0][0] * dx + m[0][1] * dy;
1722  // H2D_FN_DY
1723  if (b == 2) return m[1][0] * dx + m[1][1] * dy;
1724  }
1725 #ifdef H2D_USE_SECOND_DERIVATIVES
1726  else
1727  {
1728  double2x2 mat;
1729  double3x2 mat2;
1730  double xx, yy;
1731 
1732  this->refmap.inv_ref_map_at_point(xi1, xi2, xx, yy, mat);
1733 
1734  Scalar vx = get_ref_value(e, xi1, xi2, a, 1);
1735  Scalar vy = get_ref_value(e, xi1, xi2, a, 2);
1736  Scalar vxx = get_ref_value(e, xi1, xi2, a, 3);
1737  Scalar vyy = get_ref_value(e, xi1, xi2, a, 4);
1738  Scalar vxy = get_ref_value(e, xi1, xi2, a, 5);
1739  this->refmap.second_ref_map_at_point(xi1, xi2, xx, yy, mat2);
1740  if (b == 3)
1741  // dxx
1742  return sqr(mat[0][0])*vxx + 2 * mat[0][1] * mat[0][0] * vxy + sqr(mat[0][1])*vyy + mat2[0][0] * vx + mat2[0][1] * vy;
1743  if (b == 4)
1744  // dyy
1745  return sqr(mat[1][0])*vxx + 2 * mat[1][1] * mat[1][0] * vxy + sqr(mat[1][1])*vyy + mat2[2][0] * vx + mat2[2][1] * vy;
1746  if (b == 5)
1747  //dxy
1748  return mat[0][0] * mat[1][0] * vxx + (mat[0][0] * mat[1][1] + mat[1][0] * mat[0][1])*vxy + mat[0][1] * mat[1][1] * vyy + mat2[1][0] * vx + mat2[1][1] * vy;
1749  }
1750 #else
1751  throw Exceptions::Exception("Hermes not built with second derivatives support. Consult the macro H2D_USE_SECOND_DERIVATIVES.");
1752 #endif
1753  }
1754  else // vector solution
1755  {
1756  if (b == 0)
1757  {
1758  double2x2 m;
1759  double xx, yy;
1760  this->refmap.inv_ref_map_at_point(xi1, xi2, xx, yy, m);
1761  Scalar vx = get_ref_value(e, xi1, xi2, 0, 0);
1762  Scalar vy = get_ref_value(e, xi1, xi2, 1, 0);
1763  // H2D_FN_VAL_0
1764  if (a == 0) return m[0][0] * vx + m[0][1] * vy;
1765  // H2D_FN_VAL_1
1766  if (a == 1) return m[1][0] * vx + m[1][1] * vy;
1767  }
1768  else
1769  throw Hermes::Exceptions::Exception("Getting derivatives of the vector solution: Not implemented yet.");
1770  }
1771 
1772  throw Hermes::Exceptions::Exception("Internal error: reached end of non-void function");
1773  return 0.;
1774  }
1775 
1776  template<typename Scalar>
1778  {
1779  set_active_element(e);
1780 
1781  double x_ref, y_ref;
1782  double x_dummy, y_dummy;
1783 
1784  this->get_refmap()->untransform(e, x, y, x_ref, y_ref);
1785 
1786  Scalar** toReturn = malloc_with_check<Solution<Scalar>, Scalar*>(2, this);
1787  double2x2 mat;
1788  this->refmap.inv_ref_map_at_point(x_ref, y_ref, x_dummy, y_dummy, mat);
1789  if (this->num_components == 1)
1790  {
1791  toReturn[0] = malloc_with_check<Solution<Scalar>, Scalar>(6, this);
1792 
1793  int o = elem_orders[e->id];
1794 
1795  Scalar result[H2D_NUM_FUNCTION_VALUES];
1796  for (int item = 0; item < H2D_NUM_FUNCTION_VALUES; item++)
1797  {
1798  Scalar* mono = dxdy_coeffs[0][item];
1799  Scalar result_local = 0.0;
1800  int k = 0;
1801  for (int i = 0; i <= o; i++)
1802  {
1803  Scalar row = mono[k++];
1804  for (int j = 0; j < (this->mode ? o : i); j++)
1805  row = row * x_ref + mono[k++];
1806  result[item] = result_local * y_ref + row;
1807  }
1808  }
1809 
1810  toReturn[0][0] = result[0];
1811  toReturn[0][1] = mat[0][0] * result[1] + mat[0][1] * result[2];
1812  toReturn[0][2] = mat[1][0] * result[1] + mat[1][1] * result[2];
1813 #ifdef H2D_USE_SECOND_DERIVATIVES
1814  double3x2 mat2;
1815  this->refmap.second_ref_map_at_point(x_ref, y_ref, x_dummy, y_dummy, mat2);
1816 
1817  toReturn[0][3] = sqr(mat[0][0])*result[3] + 2 * mat[0][1] * mat[0][0] * result[5] + sqr(mat[0][1])*result[4] + mat2[0][0] * result[1] + mat2[0][1] * result[2];
1818  toReturn[0][4] = sqr(mat[1][0])*result[3] + 2 * mat[1][1] * mat[1][0] * result[5] + sqr(mat[1][1])*result[4] + mat2[2][0] * result[1] + mat2[2][1] * result[2];
1819  toReturn[0][5] = mat[0][0] * mat[1][0] * result[3] + (mat[0][0] * mat[1][1] + mat[1][0] * mat[0][1])*result[5] + mat[0][1] * mat[1][1] * result[4] + mat2[1][0] * result[1] + mat2[1][1] * result[2];
1820 #endif
1821  }
1822  else // vector solution
1823  {
1824  toReturn[0] = malloc_with_check<Solution<Scalar>, Scalar>(1, this);
1825 
1826  Scalar vx = get_ref_value(e, x_ref, y_ref, 0, 0);
1827  Scalar vy = get_ref_value(e, x_ref, y_ref, 1, 0);
1828  toReturn[0][0] = mat[0][0] * vx + mat[0][1] * vy;
1829  toReturn[1][0] = mat[1][0] * vx + mat[1][1] * vy;
1830  }
1831 
1832  this->invalidate_values();
1833  return toReturn;
1834  }
1835 
1836  template<typename Scalar>
1837  Func<Scalar>* Solution<Scalar>::get_pt_value(double x, double y, bool use_MeshHashGrid, Element* e)
1838  {
1839  double xi1, xi2;
1840 
1841  Func<Scalar>* toReturn = new Func<Scalar>(1, this->num_components);
1842 
1843  if (sln_type == HERMES_EXACT)
1844  {
1845  if (this->num_components == 1)
1846  {
1847  Scalar val, dx = 0.0, dy = 0.0;
1848  val = (static_cast<ExactSolutionScalar<Scalar>*>(this))->exact_function(x, y, dx, dy);
1849  toReturn->val[0] = val * (static_cast<ExactSolutionScalar<Scalar>*>(this))->exact_multiplicator;
1850  toReturn->dx[0] = dx * (static_cast<ExactSolutionScalar<Scalar>*>(this))->exact_multiplicator;
1851  toReturn->dy[0] = dy * (static_cast<ExactSolutionScalar<Scalar>*>(this))->exact_multiplicator;
1852  }
1853  else
1854  {
1855  Scalar2<Scalar> dx(0.0, 0.0), dy(0.0, 0.0);
1856  Scalar2<Scalar> val = (static_cast<ExactSolutionVector<Scalar>*>(this))->exact_function(x, y, dx, dy);
1857  toReturn->val0[0] = val[0] * (static_cast<ExactSolutionScalar<Scalar>*>(this))->exact_multiplicator;
1858  toReturn->val1[0] = val[1] * (static_cast<ExactSolutionScalar<Scalar>*>(this))->exact_multiplicator;
1859  }
1860 #ifdef H2D_USE_SECOND_DERIVATIVES
1861  this->warn("Cannot obtain second derivatives of an exact solution.");
1862 #endif
1863  return toReturn;
1864  }
1865  else if (sln_type == HERMES_UNDEF)
1866  {
1867  throw Hermes::Exceptions::Exception("Cannot obtain values -- uninitialized solution. The solution was either "
1868  "not calculated yet or you used the assignment operator which destroys "
1869  "the solution on its right-hand side.");
1870  return nullptr;
1871  }
1872  else // HERMES_SLN
1873  {
1874  if (e == nullptr)
1875  e = RefMap::element_on_physical_coordinates(use_MeshHashGrid, this->mesh, x, y, &xi1, &xi2);
1876  else
1877  RefMap::untransform(e, x, y, xi1, xi2);
1878 
1879  if (e != nullptr)
1880  {
1881  if (this->num_components == 1)
1882  {
1883  toReturn->val[0] = get_ref_value(e, xi1, xi2, 0, 0);
1884 
1885  double2x2 m;
1886  double xx, yy;
1887  this->refmap.inv_ref_map_at_point(xi1, xi2, xx, yy, m);
1888  Scalar dx = get_ref_value(e, xi1, xi2, 0, 1);
1889  Scalar dy = get_ref_value(e, xi1, xi2, 0, 2);
1890  toReturn->dx[0] = m[0][0] * dx + m[0][1] * dy;
1891  toReturn->dy[0] = m[1][0] * dx + m[1][1] * dy;
1892 
1893 #ifdef H2D_USE_SECOND_DERIVATIVES
1894  toReturn->laplace = malloc_with_check(1, this);
1895  double2x2 mat;
1896  double3x2 mat2;
1897 
1898  this->refmap.inv_ref_map_at_point(xi1, xi2, xx, yy, mat);
1899  this->refmap.second_ref_map_at_point(xi1, xi2, xx, yy, mat2);
1900 
1901  Scalar vxx = get_ref_value(e, xi1, xi2, 0, 3);
1902  Scalar vyy = get_ref_value(e, xi1, xi2, 0, 4);
1903  Scalar vxy = get_ref_value(e, xi1, xi2, 0, 5);
1904  // dxx
1905  Scalar dxx = sqr(mat[0][0])*vxx + 2 * mat[0][1] * mat[0][0] * vxy + sqr(mat[0][1])*vyy + mat2[0][0] * dx + mat2[0][1] * dy;
1906  // dyy
1907  Scalar dyy = sqr(mat[1][0])*vxx + 2 * mat[1][1] * mat[1][0] * vxy + sqr(mat[1][1])*vyy + mat2[2][0] * dx + mat2[2][1] * dy;
1908  toReturn->laplace[0] = dxx + dyy;
1909 #endif
1910  }
1911  else // vector solution
1912  {
1913  double2x2 m;
1914  double xx, yy;
1915  this->refmap.inv_ref_map_at_point(xi1, xi2, xx, yy, m);
1916  Scalar vx = get_ref_value(e, xi1, xi2, 0, 0);
1917  Scalar vy = get_ref_value(e, xi1, xi2, 1, 0);
1918  toReturn->val0[0] = m[0][0] * vx + m[0][1] * vy;
1919  toReturn->val1[0] = m[1][0] * vx + m[1][1] * vy;
1920  Hermes::Mixins::Loggable::Static::warn("Derivatives of vector functions not implemented yet.");
1921  }
1922  return toReturn;
1923  }
1924 
1925  this->warn("Point (%g, %g) does not lie in any element.", x, y);
1926  return nullptr;
1927  }
1928  }
1929 
1930  template class HERMES_API Solution < double > ;
1931  template class HERMES_API Solution < std::complex<double> > ;
1932  }
1933 }
Definition: adapt.h:24
int id
element id number
Definition: element.h:112
virtual void copy(const MeshFunction< Scalar > *sln)
Copy from sln to this instance.
Definition: solution.cpp:179
::xsd::cxx::tree::flags flags
Parsing and serialization flags.
Stores one element of a mesh.
Definition: element.h:107
Caches precalculated shape function values.
Definition: precalc.h:32
virtual void set_active_element(Element *e)
virtual void free()
Frees all precalculated tables.
Definition: solution.cpp:228
Class corresponding to the mono_coeffs schema type.
Scalar * mono_coeffs
Monomial coefficient array.
Definition: solution.h:157
void load_exact_solution(int number_of_components, SpaceSharedPtr< double > space, bool complexness, double x_real, double y_real, double x_complex, double y_complex)
Special internal method for loading exact solutions.
void set_dirichlet_lift(SpaceSharedPtr< Scalar > space)
Sets solution equal to Dirichlet lift only, solution vector = 0.
Definition: solution.cpp:607
Class corresponding to the component schema type.
Represents a function defined on a mesh.
Definition: mesh_function.h:56
int * elem_coeffs[H2D_MAX_SOLUTION_COMPONENTS]
array of pointers into mono_coeffs
Definition: solution.h:183
::xsd::cxx::tree::exception< char > exception
Root of the C++/Tree exception hierarchy.
Used to pass the instances of Space around.
Definition: space.h:34
::std::auto_ptr< ::XMLSolution::solution > solution_(const ::std::string &uri,::xml_schema::flags f=0, const ::xml_schema::properties &p=::xml_schema::properties())
Parse a URI or a local file.
Class corresponding to the elem_orders schema type.
virtual void precalculate(unsigned short order, unsigned short mask)
precalculates the current function at the current integration points.
Definition: function.cpp:109
Class corresponding to the solution schema type.
virtual MeshFunction< Scalar > * clone() const
Definition: solution.cpp:220
virtual void set_active_element(Element *e)
Internal.
Definition: solution.cpp:699
const int H2D_FN_DEFAULT
default precalculation mask
Definition: function.h:57
static void vector_to_solutions(const Scalar *solution_vector, std::vector< SpaceSharedPtr< Scalar > > spaces, std::vector< MeshFunctionSharedPtr< Scalar > > solutions, std::vector< bool > add_dir_lift=std::vector< bool >(), std::vector< int > start_indices=std::vector< int >())
Passes solution components calculated from solution vector as Solutions.
Definition: solution.cpp:443
virtual void set_coeff_vector(SpaceSharedPtr< Scalar > space, const Vector< Scalar > *vec, bool add_dir_lift, int start_index)
Converts a coefficient vector into a Solution.
Definition: solution.cpp:315
#define H2D_GET_H_ORDER(encoded_order)
Macros for combining quad horizontal and vertical encoded_orders.
Definition: global.h:98
::xsd::cxx::xml::dom::namespace_infomap< char > namespace_infomap
Namespace serialization information map.
virtual void save(const char *filename) const
Represents an exact solution of a PDE.
void get_center(double &x, double &y)
Returns the center of gravity.
Definition: element.cpp:237
virtual void add(MeshFunctionSharedPtr< Scalar > &other_mesh_function, SpaceSharedPtr< Scalar > target_space)
Definition: solution.cpp:628
void enable_transform(bool enable=true)
Definition: solution.cpp:620
const int H2D_FN_VAL
Both components are usually requested together...
Definition: function.h:53
Generated from solution_h2d_xml.xsd.
virtual void init()
Internal.
Definition: solution.cpp:94
unsigned char num_components
Number of vector components.
Definition: function.h:218
virtual void precalculate(unsigned short order, unsigned short mask)
precalculates the current function at the current integration points.
Definition: solution.cpp:848
void load(const char *filename, SpaceSharedPtr< double > space)
virtual void multiply(Scalar coef)
Multiplies the function represented by this class by the given coefficient.
Definition: solution.cpp:642
Class corresponding to the elem_coeffs schema type.
Represents the solution of a PDE.
Definition: api2d.h:35
static void project_global(SpaceSharedPtr< Scalar > space, MatrixFormVol< Scalar > *custom_projection_jacobian, VectorFormVol< Scalar > *custom_projection_residual, Scalar *target_vec)
This method allows to specify your own OG-projection form.