Hermes2D  3.0
precalc.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 "global.h"
17 #include "quad_all.h"
18 #include "precalc.h"
19 #include "mesh.h"
20 #include "shapeset/shapeset_h1_all.h"
21 #include "shapeset/shapeset_l2_all.h"
22 #include "shapeset/shapeset_hc_all.h"
23 #include "shapeset/shapeset_hd_all.h"
24 
25 namespace Hermes
26 {
27  namespace Hermes2D
28  {
30  {
31  if (shapeset == nullptr)
32  throw Exceptions::NullException(0);
33  this->shapeset = shapeset;
34  num_components = shapeset->get_num_components();
35  update_max_index();
36  set_quad_2d(&g_quad_2d_std);
37  }
38 
39  void PrecalcShapeset::update_max_index()
40  {
41  max_index[0] = shapeset->get_max_index(HERMES_MODE_TRIANGLE);
42  max_index[1] = shapeset->get_max_index(HERMES_MODE_QUAD);
43  }
44 
46  {
48  }
49 
51  {
52  // Update the Node table.
53  this->invalidate_values();
54 
55  this->index = index;
56  this->order = std::max(H2D_GET_H_ORDER(shapeset->get_order(index, element->get_mode())), H2D_GET_V_ORDER(shapeset->get_order(index, element->get_mode())));
57  }
58 
59  void PrecalcShapeset::precalculate(unsigned short order, unsigned short mask)
60  {
61  Function<double>::precalculate(order, mask);
62 
63  unsigned char np = this->quads[cur_quad]->get_num_points(order, this->element->get_mode());
64  double3* pt = this->quads[cur_quad]->get_points(order, this->element->get_mode());
65 
66  unsigned short j, k;
67 
68  ElementMode2D mode = element->get_mode();
69 
70  // Correction of points for sub-element mappings.
71  if (this->sub_idx != 0)
72  {
73  for (short i = 0; i < np; i++)
74  {
75  ref_points[i][0] = ctm->m[0] * pt[i][0] + ctm->t[0];
76  ref_points[i][1] = ctm->m[1] * pt[i][1] + ctm->t[1];
77  }
78 
79  for (j = 0; j < num_components; j++)
80  for (k = 0; k < H2D_NUM_FUNCTION_VALUES; k++)
81  if (mask & idx2mask[k][j])
82  for (short i = 0; i < np; i++)
83  this->values[j][k][i] = shapeset->get_value(k, index, ref_points[i][0], ref_points[i][1], j, mode);
84  }
85  else
86  {
87  if (this->num_components == 1)
88  {
89  if (mode == HERMES_MODE_TRIANGLE)
90  {
91  if (mask & idx2mask[0][0])
92  for (short i = 0; i < np; i++)
93  this->values[0][0][i] = shapeset->get_fn_value_0_tri(index, pt[i][0], pt[i][1]);
94  if (mask & idx2mask[1][0])
95  for (short i = 0; i < np; i++)
96  this->values[0][1][i] = shapeset->get_dx_value_0_tri(index, pt[i][0], pt[i][1]);
97  if (mask & idx2mask[2][0])
98  for (short i = 0; i < np; i++)
99  this->values[0][2][i] = shapeset->get_dy_value_0_tri(index, pt[i][0], pt[i][1]);
100  }
101  else
102  {
103  if (mask & idx2mask[0][0])
104  for (short i = 0; i < np; i++)
105  this->values[0][0][i] = shapeset->get_fn_value_0_quad(index, pt[i][0], pt[i][1]);
106  if (mask & idx2mask[1][0])
107  for (short i = 0; i < np; i++)
108  this->values[0][1][i] = shapeset->get_dx_value_0_quad(index, pt[i][0], pt[i][1]);
109  if (mask & idx2mask[2][0])
110  for (short i = 0; i < np; i++)
111  this->values[0][2][i] = shapeset->get_dy_value_0_quad(index, pt[i][0], pt[i][1]);
112  }
113  }
114  else
115  {
116  for (j = 0; j < num_components; j++)
117  for (k = 0; k < H2D_NUM_FUNCTION_VALUES; k++)
118  if (mask & idx2mask[k][j])
119  for (short i = 0; i < np; i++)
120  this->values[j][k][i] = shapeset->get_value(k, index, pt[i][0], pt[i][1], j, mode);
121  }
122  }
123  }
124 
126  {
127  }
128 
130  {
131  free();
132  }
133 
135  {
136  return index;
137  };
138 
140  {
141  return shapeset;
142  }
143 
145  {
146  return shapeset->get_space_type();
147  }
148 
149  unsigned short PrecalcShapeset::get_edge_fn_order(int edge)
150  {
151  return H2D_MAKE_EDGE_ORDER(element->get_mode(), edge, shapeset->get_order(index, element->get_mode()));
152  }
153 
154  // This is a technical thing - to be able to share the storage
155 #ifdef HERMES_FOR_AGROS
156  static PrecalcShapesetAssemblingStorage* PrecalcShapesetAssemblingTables[H2D_NUM_SHAPESETS] = { nullptr, nullptr };
157 #else
158  static PrecalcShapesetAssemblingStorage* PrecalcShapesetAssemblingTables[H2D_NUM_SHAPESETS] = { nullptr, nullptr, nullptr, nullptr, nullptr };
159 #endif
160 
161 #ifndef HERMES_FOR_AGROS
162  static PrecalcShapesetAssemblingInternal temp[H2D_NUM_SHAPESETS] = { PrecalcShapesetAssemblingInternal(new HcurlShapesetGradLeg), PrecalcShapesetAssemblingInternal(new HdivShapesetLegendre), PrecalcShapesetAssemblingInternal(new L2ShapesetLegendre), PrecalcShapesetAssemblingInternal(new L2ShapesetTaylor), PrecalcShapesetAssemblingInternal(new H1ShapesetJacobi) };
163 #endif
164 
165  PrecalcShapesetAssemblingInternal::PrecalcShapesetAssemblingInternal(Shapeset* shapeset) : PrecalcShapesetAssembling(shapeset)
166  {
167  }
168 
169  PrecalcShapesetAssemblingInternal::~PrecalcShapesetAssemblingInternal()
170  {
171  delete PrecalcShapesetAssemblingTables[(int)this->shapeset->get_id()];
172  delete this->shapeset;
173  }
174 
176  {
177  if (PrecalcShapesetAssemblingTables[(int)shapeset->get_id()])
178  {
179  this->storage = PrecalcShapesetAssemblingTables[(int)shapeset->get_id()];
180  this->storage->ref_count++;
181  }
182  if (!this->storage)
183  {
184 #pragma omp critical (pss_table_creation)
185  {
186  this->storage = new PrecalcShapesetAssemblingStorage(this->shapeset);
187  this->storage->ref_count++;
188  PrecalcShapesetAssemblingTables[(int)shapeset->get_id()] = storage;
189  }
190  }
191  }
192 
194  {
195  this->storage = other.storage;
196  this->storage->ref_count++;
197  }
198 
200  {
201  }
202 
203  const double* PrecalcShapesetAssembling::get_fn_values(int component) const
204  {
205  if (this->attempt_to_reuse(this->order))
206  return this->storage->PrecalculatedValues[this->element->get_mode()][0][this->order][this->index];
207  assert(this->values_valid);
208  return &values[component][0][0];
209  }
210 
211  const double* PrecalcShapesetAssembling::get_dx_values(int component) const
212  {
213  if (this->attempt_to_reuse(this->order))
214  return this->storage->PrecalculatedValues[this->element->get_mode()][1][this->order][this->index];
215  assert(this->values_valid);
216  return &values[component][1][0];
217  }
218 
219  const double* PrecalcShapesetAssembling::get_dy_values(int component) const
220  {
221  if (this->attempt_to_reuse(this->order))
222  return this->storage->PrecalculatedValues[this->element->get_mode()][2][this->order][this->index];
223  assert(this->values_valid);
224  return &values[component][2][0];
225  }
226 
227 #ifdef H2D_USE_SECOND_DERIVATIVES
228  const double* PrecalcShapesetAssembling::get_dxx_values(int component) const
229  {
230  assert(this->values_valid);
231  return &values[component][3][0];
232  }
233 
234  const double* PrecalcShapesetAssembling::get_dyy_values(int component) const
235  {
236  assert(this->values_valid);
237  return &values[component][4][0];
238  }
239 
240  const double* PrecalcShapesetAssembling::get_dxy_values(int component) const
241  {
242  assert(this->values_valid);
243  return &values[component][5][0];
244  }
245 #endif
246 
247  bool PrecalcShapesetAssembling::attempt_to_reuse(unsigned short order_) const
248  {
249  return (this->reuse_possible() && this->storage->PrecalculatedInfo[this->element->get_mode()][order_][this->index]);
250  }
251 
252  bool PrecalcShapesetAssembling::reuse_possible() const
253  {
254  return (this->index >= 0 && this->get_quad_2d()->get_id() == 1 && this->sub_idx == 0 && this->num_components == 1);
255  }
256 
257  const double* PrecalcShapesetAssembling::get_values(int component, unsigned short item) const
258  {
259  if (item == 0)
260  return this->get_fn_values(component);
261  else if (item == 1)
262  return this->get_dx_values(component);
263  else if (item == 2)
264  return this->get_dy_values(component);
265  else
266  return Function<double>::get_values(component, item);
267  }
268 
269  void PrecalcShapesetAssembling::precalculate(unsigned short order_, unsigned short mask)
270  {
271  if (this->attempt_to_reuse(order_))
272  return;
273  else
274  {
275  Function<double>::precalculate(order_, mask);
276 
277  unsigned char np = this->quads[cur_quad]->get_num_points(order_, this->element->get_mode());
278  double3* pt = this->quads[cur_quad]->get_points(order_, this->element->get_mode());
279 
280  unsigned short j, k;
281 
282  ElementMode2D mode = element->get_mode();
283 
284  if (this->num_components == 1)
285  {
286  if (this->reuse_possible())
287  {
288 #pragma omp critical (precalculatingPSS)
289  {
290  double* valuePointer;
291  if (mode == HERMES_MODE_TRIANGLE)
292  {
293  valuePointer = this->storage->PrecalculatedValues[HERMES_MODE_TRIANGLE][0][order_][index];
294  for (short i = 0; i < np; i++)
295  valuePointer[i] = shapeset->get_fn_value_0_tri(index, pt[i][0], pt[i][1]);
296 
297  valuePointer = this->storage->PrecalculatedValues[HERMES_MODE_TRIANGLE][1][order_][index];
298  for (short i = 0; i < np; i++)
299  valuePointer[i] = shapeset->get_dx_value_0_tri(index, pt[i][0], pt[i][1]);
300 
301  valuePointer = this->storage->PrecalculatedValues[HERMES_MODE_TRIANGLE][2][order_][index];
302  for (short i = 0; i < np; i++)
303  valuePointer[i] = shapeset->get_dy_value_0_tri(index, pt[i][0], pt[i][1]);
304 
305  this->storage->PrecalculatedInfo[HERMES_MODE_TRIANGLE][order_][index] = true;
306  }
307  else
308  {
309  valuePointer = this->storage->PrecalculatedValues[HERMES_MODE_QUAD][0][order_][index];
310  for (short i = 0; i < np; i++)
311  valuePointer[i] = shapeset->get_fn_value_0_quad(index, pt[i][0], pt[i][1]);
312 
313  valuePointer = this->storage->PrecalculatedValues[HERMES_MODE_QUAD][1][order_][index];
314  for (short i = 0; i < np; i++)
315  valuePointer[i] = shapeset->get_dx_value_0_quad(index, pt[i][0], pt[i][1]);
316 
317  valuePointer = this->storage->PrecalculatedValues[HERMES_MODE_QUAD][2][order_][index];
318  for (short i = 0; i < np; i++)
319  valuePointer[i] = shapeset->get_dy_value_0_quad(index, pt[i][0], pt[i][1]);
320 
321  this->storage->PrecalculatedInfo[HERMES_MODE_QUAD][order_][index] = true;
322  }
323  }
324  }
325  else
326  {
327  // Correction of points for sub-element mappings.
328  if (this->sub_idx != 0)
329  {
330  for (short i = 0; i < np; i++)
331  {
332  ref_points[i][0] = ctm->m[0] * pt[i][0] + ctm->t[0];
333  ref_points[i][1] = ctm->m[1] * pt[i][1] + ctm->t[1];
334  }
335 
336  for (k = 0; k < H2D_NUM_FUNCTION_VALUES; k++)
337  if (mask & idx2mask[k][0])
338  for (short i = 0; i < np; i++)
339  this->values[0][k][i] = shapeset->get_value(k, index, ref_points[i][0], ref_points[i][1], 0, mode);
340  }
341  else if (mode == HERMES_MODE_TRIANGLE)
342  {
343  if (mask & idx2mask[0][0])
344  for (short i = 0; i < np; i++)
345  this->values[0][0][i] = shapeset->get_fn_value_0_tri(index, pt[i][0], pt[i][1]);
346  if (mask & idx2mask[1][0])
347  for (short i = 0; i < np; i++)
348  this->values[0][1][i] = shapeset->get_dx_value_0_tri(index, pt[i][0], pt[i][1]);
349  if (mask & idx2mask[2][0])
350  for (short i = 0; i < np; i++)
351  this->values[0][2][i] = shapeset->get_dy_value_0_tri(index, pt[i][0], pt[i][1]);
352  }
353  else
354  {
355  if (mask & idx2mask[0][0])
356  for (short i = 0; i < np; i++)
357  this->values[0][0][i] = shapeset->get_fn_value_0_quad(index, pt[i][0], pt[i][1]);
358  if (mask & idx2mask[1][0])
359  for (short i = 0; i < np; i++)
360  this->values[0][1][i] = shapeset->get_dx_value_0_quad(index, pt[i][0], pt[i][1]);
361  if (mask & idx2mask[2][0])
362  for (short i = 0; i < np; i++)
363  this->values[0][2][i] = shapeset->get_dy_value_0_quad(index, pt[i][0], pt[i][1]);
364  }
365  }
366  }
367  else
368  {
369  // Correction of points for sub-element mappings.
370  if (this->sub_idx != 0)
371  {
372  for (short i = 0; i < np; i++)
373  {
374  ref_points[i][0] = ctm->m[0] * pt[i][0] + ctm->t[0];
375  ref_points[i][1] = ctm->m[1] * pt[i][1] + ctm->t[1];
376  }
377 
378  for (j = 0; j < num_components; j++)
379  for (k = 0; k < H2D_NUM_FUNCTION_VALUES; k++)
380  if (mask & idx2mask[k][j])
381  for (short i = 0; i < np; i++)
382  this->values[j][k][i] = shapeset->get_value(k, index, ref_points[i][0], ref_points[i][1], j, mode);
383  }
384  else
385  {
386  for (j = 0; j < num_components; j++)
387  for (k = 0; k < H2D_NUM_FUNCTION_VALUES; k++)
388  if (mask & idx2mask[k][j])
389  for (short i = 0; i < np; i++)
390  this->values[j][k][i] = shapeset->get_value(k, index, pt[i][0], pt[i][1], j, mode);
391  }
392  }
393  }
394  }
395 
396  PrecalcShapesetAssemblingStorage::PrecalcShapesetAssemblingStorage(Shapeset* shapeset) : shapeset_id(shapeset->get_id()), ref_count(0)
397  {
398  this->max_index[0] = shapeset->get_max_index(HERMES_MODE_TRIANGLE);
399  this->max_index[1] = shapeset->get_max_index(HERMES_MODE_QUAD);
400 
401  for (int i = 0; i < H2D_NUM_MODES; i++)
402  {
403  unsigned short g_max, np;
404  if (i == HERMES_MODE_TRIANGLE)
405  {
406  g_max = g_max_tri + 1 + 3 * g_max_tri + 3;
407  np = H2D_MAX_INTEGRATION_POINTS_COUNT_TRI;
408  }
409  else
410  {
411  g_max = g_max_quad + 1 + 4 * g_max_quad + 4;
412  np = H2D_MAX_INTEGRATION_POINTS_COUNT_QUAD;
413  }
414 
415  unsigned short local_base_size = this->max_index[i] + 1;
416 
417  this->PrecalculatedInfo[i] = malloc_with_check<bool*>(g_max);
418 
419  for (int j = 0; j < H2D_NUM_FUNCTION_VALUES; j++)
420  {
421  this->PrecalculatedValues[i][j] = malloc_with_check<double**>(g_max);
422 
423  for (int k = 0; k < g_max; k++)
424  {
425  this->PrecalculatedValues[i][j][k] = malloc_with_check<double*>(local_base_size);
426  if (j == 0)
427  this->PrecalculatedInfo[i][k] = calloc_with_check<bool>(local_base_size);
428 
429  for (int l = 0; l < local_base_size; l++)
430  this->PrecalculatedValues[i][j][k][l] = malloc_with_check<double>(np);
431  }
432  }
433  }
434  }
435 
436  PrecalcShapesetAssemblingStorage::~PrecalcShapesetAssemblingStorage()
437  {
438  for (int i = 0; i < H2D_NUM_MODES; i++)
439  {
440  unsigned short g_max;
441  if (i == HERMES_MODE_TRIANGLE)
442  g_max = g_max_tri + 1 + 3 * g_max_tri + 3;
443  else
444  g_max = g_max_quad + 1 + 4 * g_max_quad + 4;
445 
446  unsigned short local_base_size = this->max_index[i] + 1;
447 
448  for (int j = 0; j < H2D_NUM_FUNCTION_VALUES; j++)
449  {
450  for (int k = 0; k < g_max; k++)
451  {
452  for (int l = 0; l < local_base_size; l++)
453  free_with_check(this->PrecalculatedValues[i][j][k][l]);
454  free_with_check(this->PrecalculatedValues[i][j][k]);
455  if (j == 0)
456  free_with_check(this->PrecalculatedInfo[i][k]);
457  }
458 
459  free_with_check(this->PrecalculatedValues[i][j]);
460  free_with_check(this->PrecalculatedInfo[i][j]);
461  }
462  }
463  }
464  }
465 }
virtual ~PrecalcShapesetAssembling()
Destructor.
Definition: precalc.cpp:199
PrecalcShapeset variant for fast assembling.
Definition: precalc.h:109
Definition: adapt.h:24
Trf * ctm
Current sub-element transformation matrix.
double get_value(int n, int index, double x, double y, unsigned short component, ElementMode2D mode)
Definition: shapeset.cpp:264
double get_fn_value_0_quad(int index, double x, double y)
The most used calls are distinguished for optimization.
Definition: shapeset.cpp:316
virtual void free()
Frees all precalculated tables.
Definition: precalc.cpp:125
Caches precalculated shape function values.
Definition: precalc.h:32
const double * get_fn_values(int component=0) const
Returns function values.
Definition: precalc.cpp:203
SpaceType get_space_type() const
Returns type of space.
Definition: precalc.cpp:144
static int idx2mask[H2D_NUM_FUNCTION_VALUES][2]
Index to mask table.
Definition: function.h:231
const double * get_dx_values(int component=0) const
Returns the x partial derivative.
Definition: precalc.cpp:211
Quad2D * get_quad_2d() const
Returns the current quadrature points.
Common definitions for Hermes2D.
int get_active_shape() const
Returns the index of the active shape (can be negative if the shape is constrained).
Definition: precalc.cpp:134
virtual void precalculate(unsigned short order, unsigned short mask)
precalculates the current function at the current integration points.
Definition: function.cpp:109
double get_dx_value_0_quad(int index, double x, double y)
The most used calls are distinguished for optimization.
Definition: shapeset.cpp:323
virtual void precalculate(unsigned short order, unsigned short mask)
precalculates the current function at the current integration points.
Definition: precalc.cpp:59
#define H2D_NUM_MODES
Internal.
Definition: global.h:35
double values[H2D_MAX_SOLUTION_COMPONENTS][H2D_NUM_FUNCTION_VALUES][H2D_MAX_INTEGRATION_POINTS_COUNT]
The data.
Definition: function.h:203
double get_fn_value_0_tri(int index, double x, double y)
The most used calls are distinguished for optimization.
Definition: shapeset.cpp:294
#define H2D_GET_H_ORDER(encoded_order)
Macros for combining quad horizontal and vertical encoded_orders.
Definition: global.h:98
virtual SpaceType get_space_type() const =0
double2 t
The 2x2 diagonal transformation matrix.
Definition: transformable.h:32
virtual unsigned char get_id() const =0
Represents an arbitrary function defined on an element.
Definition: function.h:106
virtual unsigned short get_edge_fn_order(int edge)
Returns the polynomial order of the active shape function on given edge.
Definition: precalc.cpp:149
uint64_t sub_idx
Sub-element transformation index.
Should be exactly the same as is the count of enum ShapesetType.
Definition: shapeset.h:95
PrecalcShapesetAssembling common storage.
Definition: precalc.h:93
Element * element
The active element.
bool values_valid
Flag that the data are not 'dirty'.
Definition: function.h:205
virtual ~PrecalcShapeset()
Destructor.
Definition: precalc.cpp:129
double get_dy_value_0_tri(int index, double x, double y)
The most used calls are distinguished for optimization.
Definition: shapeset.cpp:308
unsigned char get_num_components() const
Returns 2 if this is a vector shapeset, 1 otherwise.
Definition: shapeset.cpp:195
PrecalcShapesetAssembling(Shapeset *shapeset)
Constructs a standard (master) precalculated shapeset class.
Definition: precalc.cpp:175
double get_dy_value_0_quad(int index, double x, double y)
The most used calls are distinguished for optimization.
Definition: shapeset.cpp:330
unsigned char num_components
Number of vector components.
Definition: function.h:218
virtual void set_quad_2d(Quad2D *quad_2d)
Selects the quadrature points in which the function will be evaluated.
Definition: function.cpp:79
double get_dx_value_0_tri(int index, double x, double y)
The most used calls are distinguished for optimization.
Definition: shapeset.cpp:301
virtual void set_quad_2d(Quad2D *quad_2d)
Selects the quadrature points in which the function will be evaluated.
Definition: precalc.cpp:45
Quad2D * quads[H2D_MAX_QUADRATURES]
List of available quadratures.
Definition: function.h:226
int cur_quad
Active quadrature (index into 'quads')
Definition: function.h:228
unsigned short get_order(int index, ElementMode2D mode) const
Definition: shapeset.cpp:256
PrecalcShapeset(Shapeset *shapeset)
Constructs a standard (master) precalculated shapeset class.
Definition: precalc.cpp:29
int order
Current function polynomial order.
Definition: function.h:215
const double * get_dy_values(int component=0) const
Returns the y partial derivative.
Definition: precalc.cpp:219
Shapeset * get_shapeset() const
Returns a pointer to the shapeset which is being precalculated.
Definition: precalc.cpp:139
double2 ref_points[H2D_MAX_INTEGRATION_POINTS_COUNT]
Transformed points to the reference domain, used by precalculate.
Definition: precalc.h:73
virtual unsigned short get_max_index(ElementMode2D mode) const =0
Returns the highest shape function index.
virtual void set_active_shape(int index)
Definition: precalc.cpp:50