Hermes2D  3.0
shapeset.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 "shapeset.h"
18 #include "matrix.h"
19 #include "algebra/dense_matrix_operations.h"
20 
22 
23 namespace Hermes
24 {
25  namespace Hermes2D
26  {
27  double* Shapeset::calculate_constrained_edge_combination(unsigned short order, unsigned short part, unsigned short ori, ElementMode2D mode)
28  {
29  /*
30  "ebias" is the order of the first edge function, this has to be subtracted
31  from the order to get a reasonable numbering of the edge functions, starting
32  from 0. For H1 ebias is 2 and for Hcurl it is 0.
33  */
34  assert((order - ebias) >= 0);
35  assert(part >= 0);
36 
37  unsigned short i, j, n;
38 
39  // determine the interval of the edge
40  for (n = 2; n <= part; n <<= 1)
41  part -= n;
42 
43  double n2 = 2.0 / n;
44  double hi = -((double)part * n2 - 1.0);
45  double lo = -((double)(part + 1) * n2 - 1.0);
46 
47  unsigned short idx[16];
48  ori = ori ? 0 : 1;
49  for (i = 0; i <= order; i++)
50  idx[i] = get_edge_index(0, ori, i, mode);
51 
52  // function values at the endpoints (for subtracting of the linear part in H1)
53  double c = 1.0;
54  double f_lo = 0.0, f_hi = 0.0;
55  if (ebias == 2)
56  {
57  f_lo = get_value(0, idx[order], lo, -1.0, 0, mode);
58  f_hi = get_value(0, idx[order], hi, -1.0, 0, mode);
59  }
60  else
61  {
62  // this is for H(curl), where we need to multiply the constrained function
63  // so that its vectors are not shortened and fit the large constraining fn.
64  c = (hi - lo) / 2.0;
65  }
66 
67  // fill the matrix of the linear system
68  n = order + 1 - ebias;
69  unsigned short space_type = this->get_space_type();
70  unsigned short component = (space_type == HERMES_HDIV_SPACE) ? 1 : 0;
71  double** a = new_matrix<double>(n, n);
72  double* b = malloc_with_check<double>(n);
73  for (i = 0; i < n; i++)
74  {
75  // chebyshev point
76  unsigned short o = (ebias == 0) ? order + 1 : order;
77  double p = cos((i + 1) * M_PI / o);
78  double r = (p + 1.0) * 0.5;
79  double s = 1.0 - r;
80 
81  // matrix row
82  for (j = 0; j < n; j++)
83  a[i][j] = get_value(0, idx[j + ebias], p, -1.0, component, mode);
84 
85  // rhs
86  b[i] = c * get_value(0, idx[order], lo*s + hi*r, -1.0, component, mode) - f_lo*s - f_hi*r;
87  }
88 
89  // solve the system
90  double d;
91  unsigned short* iperm = malloc_with_check<unsigned short>(n);
92  ludcmp(a, n, iperm, &d);
93  lubksb(a, n, iperm, b);
94 
95  // cleanup
96  free_with_check(iperm);
97  free_with_check(a, true);
98 
99  return b;
100  }
101 
102  double* Shapeset::get_constrained_edge_combination(unsigned short order, unsigned short part, unsigned short ori, unsigned short& nitems, ElementMode2D mode)
103  {
104  unsigned short index = 2 * ((max_order + 1 - ebias)*part + (order - ebias)) + ori;
105 
106  // allocate/reallocate the array if necessary
107  if (!this->comb_table)
108  {
109 #pragma omp critical
110  {
111  if (!this->comb_table)
112  {
113  table_size = 1024;
114  while (table_size <= index)
115  table_size *= 2;
116  comb_table = calloc_with_check<double*>(table_size, true);
117  }
118  }
119  }
120  else if (index >= table_size)
121  {
122 #pragma omp critical
123  {
124  // adjust table_size to accommodate the required depth
125  unsigned short old_size = table_size;
126  while (index >= table_size)
127  table_size *= 2;
128 
129  // reallocate the table
130  comb_table = realloc_with_check<double*>(comb_table, table_size);
131  memset(comb_table + old_size, 0, (table_size - old_size) * sizeof(double*));
132  }
133  }
134 
135  // do we have the required linear combination yet?
136  if (!comb_table[index])
137  {
138 #pragma omp critical
139  {
140  if (!comb_table[index])
141  {
142  // no, calculate it
143  comb_table[index] = calculate_constrained_edge_combination(order, part, ori, mode);
144  }
145  }
146  }
147 
148  nitems = order + 1 - ebias;
149  return comb_table[index];
150  }
151 
152  void Shapeset::free_constrained_edge_combinations()
153  {
154  if (comb_table)
155  {
156  for (int i = 0; i < table_size; i++)
157  free_with_check(comb_table[i]);
158 
159  free_with_check(comb_table, true);
160  }
161  }
162 
163  double Shapeset::get_constrained_value(int n, int index, double x, double y, unsigned short component, ElementMode2D mode)
164  {
165  index = -1 - index;
166 
167  unsigned short part = (unsigned)index >> 7;
168  unsigned short order = (index >> 3) & 15;
169  unsigned short edge = (index >> 1) & 3;
170  unsigned short ori = index & 1;
171 
172  unsigned short i, nc;
173  double sum, *comb = get_constrained_edge_combination(order, part, ori, nc, mode);
174 
175  sum = 0.0;
176  shape_fn_t* table = shape_table[n][mode][component];
177  for (i = 0; i < nc; i++)
178  sum += comb[i] * table[get_edge_index(edge, ori, i + ebias, mode)](x, y);
179 
180  return sum;
181  }
182 
183  Shapeset::~Shapeset() { free_constrained_edge_combinations(); }
184 
185  unsigned short Shapeset::get_max_order() const
186  {
187  return max_order;
188  }
189 
190  unsigned short Shapeset::get_min_order() const
191  {
192  return min_order;
193  }
194 
195  unsigned char Shapeset::get_num_components() const { return num_components; }
196 
197  short Shapeset::get_vertex_index(int vertex, ElementMode2D mode) const
198  {
199 #ifdef _DEBUG
200  if (mode == HERMES_MODE_TRIANGLE)
201  assert(vertex < 3);
202  else
203  assert(vertex < 4);
204 #endif
205  return vertex_indices[mode][vertex];
206  }
207 
208  short Shapeset::get_edge_index(unsigned char edge, unsigned short ori, unsigned short order, ElementMode2D mode) const
209  {
210 #ifdef _DEBUG
211  if (mode == HERMES_MODE_TRIANGLE)
212  assert(edge < 3);
213  else
214  assert(edge < 4);
215  assert(order >= 0 && order <= max_order);
216  assert(ori == 0 || ori == 1);
217 #endif
218  return edge_indices[mode][edge][2 * order + ori];
219  }
220 
221  short* Shapeset::get_bubble_indices(unsigned short order, ElementMode2D mode) const
222  {
223 #ifdef _DEBUG
224  assert(H2D_GET_H_ORDER(order) >= 0 && H2D_GET_H_ORDER(order) <= max_order);
225  assert(H2D_GET_V_ORDER(order) >= 0 && H2D_GET_V_ORDER(order) <= max_order);
226 #endif
227  unsigned short index = order;
228  if (mode == HERMES_MODE_QUAD) //tables of bubble indices are transposed
229  index = H2D_MAKE_QUAD_ORDER(H2D_GET_V_ORDER(order), H2D_GET_H_ORDER(order));
230  return bubble_indices[mode][index];
231  }
232 
233  unsigned short Shapeset::get_num_bubbles(unsigned short order, ElementMode2D mode) const
234  {
235 #ifdef _DEBUG
236  assert(H2D_GET_H_ORDER(order) >= 0 && H2D_GET_H_ORDER(order) <= max_order);
237  assert(H2D_GET_V_ORDER(order) >= 0 && H2D_GET_V_ORDER(order) <= max_order);
238 #endif
239  return bubble_count[mode][order];
240  }
241 
242  int Shapeset::get_constrained_edge_index(unsigned char edge, unsigned short order, unsigned short ori, unsigned short part, ElementMode2D mode) const
243  {
244 #ifdef _DEBUG
245  if (mode == HERMES_MODE_TRIANGLE)
246  assert(edge < 3);
247  else
248  assert(edge < 4);
249  assert(order >= 0 && order <= max_order);
250  assert(part >= 0);
251  assert(order <= H2D_ORDER_MASK);
252 #endif
253  return -1 - ((part << 7) + (order << 3) + (edge << 1) + ori);
254  }
255 
256  unsigned short Shapeset::get_order(int index, ElementMode2D mode) const
257  {
258  if (index >= 0) {
259  return index_to_order[mode][index];
260  }
261  else return ((-1 - index) >> 3) & 15;
262  }
263 
264  double Shapeset::get_value(int n, int index, double x, double y, unsigned short component, ElementMode2D mode)
265  {
266  if (index >= 0)
267  return shape_table[n][mode][component][index](x, y);
268  else
269  return get_constrained_value(n, index, x, y, component, mode);
270  }
271 
272  double Shapeset::get_fn_value(int index, double x, double y, unsigned short component, ElementMode2D mode)
273  {
274  if (index < 0)
275  return get_value(0, index, x, y, component, mode);
276  else
277  return shape_table[0][mode][component][index](x, y);
278  }
279  double Shapeset::get_dx_value(int index, double x, double y, unsigned short component, ElementMode2D mode)
280  {
281  if (index < 0)
282  return get_value(1, index, x, y, component, mode);
283  else
284  return shape_table[1][mode][component][index](x, y);
285  }
286  double Shapeset::get_dy_value(int index, double x, double y, unsigned short component, ElementMode2D mode)
287  {
288  if (index < 0)
289  return get_value(2, index, x, y, component, mode);
290  else
291  return shape_table[2][mode][component][index](x, y);
292  }
293 
294  double Shapeset::get_fn_value_0_tri(int index, double x, double y)
295  {
296  if (index < 0)
297  return get_value(0, index, x, y, 0, HERMES_MODE_TRIANGLE);
298  else
299  return shape_table[0][HERMES_MODE_TRIANGLE][0][index](x, y);
300  }
301  double Shapeset::get_dx_value_0_tri(int index, double x, double y)
302  {
303  if (index < 0)
304  return get_value(1, index, x, y, 0, HERMES_MODE_TRIANGLE);
305  else
306  return shape_table[1][HERMES_MODE_TRIANGLE][0][index](x, y);
307  }
308  double Shapeset::get_dy_value_0_tri(int index, double x, double y)
309  {
310  if (index < 0)
311  return get_value(2, index, x, y, 0, HERMES_MODE_TRIANGLE);
312  else
313  return shape_table[2][HERMES_MODE_TRIANGLE][0][index](x, y);
314  }
315 
316  double Shapeset::get_fn_value_0_quad(int index, double x, double y)
317  {
318  if (index < 0)
319  return get_value(0, index, x, y, 0, HERMES_MODE_QUAD);
320  else
321  return shape_table[0][HERMES_MODE_QUAD][0][index](x, y);
322  }
323  double Shapeset::get_dx_value_0_quad(int index, double x, double y)
324  {
325  if (index < 0)
326  return get_value(1, index, x, y, 0, HERMES_MODE_QUAD);
327  else
328  return shape_table[1][HERMES_MODE_QUAD][0][index](x, y);
329  }
330  double Shapeset::get_dy_value_0_quad(int index, double x, double y)
331  {
332  if (index < 0)
333  return get_value(2, index, x, y, 0, HERMES_MODE_QUAD);
334  else
335  return shape_table[2][HERMES_MODE_QUAD][0][index](x, y);
336  }
337 
338  double Shapeset::get_dxx_value(int index, double x, double y, unsigned short component, ElementMode2D mode)
339  {
340  if (index < 0)
341  return get_value(3, index, x, y, component, mode);
342  else
343  return shape_table[3][mode][component][index](x, y);
344  }
345  double Shapeset::get_dyy_value(int index, double x, double y, unsigned short component, ElementMode2D mode)
346  {
347  if (index < 0)
348  return get_value(4, index, x, y, component, mode);
349  else
350  return shape_table[4][mode][component][index](x, y);
351  }
352  double Shapeset::get_dxy_value(int index, double x, double y, unsigned short component, ElementMode2D mode)
353  {
354  if (index < 0)
355  return get_value(5, index, x, y, component, mode);
356  else
357  return shape_table[5][mode][component][index](x, y);
358  }
359 
360  double2* Shapeset::get_ref_vertex(int vertex, ElementMode2D mode)
361  {
362  return &ref_vert[mode][vertex];
363  }
364  }
365 }
Definition: adapt.h:24
Common definitions for Hermes2D.
#define H2D_GET_H_ORDER(encoded_order)
Macros for combining quad horizontal and vertical encoded_orders.
Definition: global.h:98