Hermes2D  2.0
function.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 "function.h"
17 namespace Hermes
18 {
19  namespace Hermes2D
20  {
21  // Debug helpers.
22  template<typename Scalar>
23  void Function<Scalar>::check_params(int component, typename Function<Scalar>::Node* cur_node, int num_components)
24  {
25  if(component < 0 || component > num_components)
26  throw Hermes::Exceptions::Exception("Invalid component. You are probably using Scalar-valued shapeset for an Hcurl / Hdiv problem.");
27  if(cur_node == NULL)
28  throw Hermes::Exceptions::Exception("Invalid node. Did you call set_quad_order()?");
29  }
30 
31  // Debug helpers.
32  template<typename Scalar>
33  void Function<Scalar>::check_table(int component, typename Function<Scalar>::Node* cur_node, int n, const char* msg)
34  {
35  if(cur_node->values[component][n] == NULL)
36  throw Hermes::Exceptions::Exception("%s not precalculated for component %d. Did you call set_quad_order() with correct mask?", msg, component);
37  }
38 
39  template<typename Scalar>
41  : Transformable()
42  {
43  order = 0;
44  max_mem = total_mem = 0;
45  cur_node = NULL;
46  sub_tables = NULL;
47  nodes = NULL;
48  overflow_nodes = NULL;
49  memset(quads, 0, sizeof(quads));
50  }
51 
52  template<typename Scalar>
54  {
55  }
56 
57  template<typename Scalar>
59  {
60  return order;
61  }
62 
63  template<typename Scalar>
65  {
66  return order;
67  }
68 
69  template<typename Scalar>
71  {
72  return num_components;
73  }
74 
75  template<typename Scalar>
76  void Function<Scalar>::set_quad_order(unsigned int order, int mask)
77  {
78  if(nodes->present(order)) {
79  cur_node = nodes->get(order);
80  // If the mask has changed.
81  if((cur_node->mask & mask) != mask) {
82  precalculate(order, mask);
83  nodes->add(cur_node, order);
84  }
85  }
86  else {
87  // The value had not existed.
88  cur_node = NULL;
89  precalculate(order, mask);
90  nodes->add(cur_node, order);
91  }
92  }
93 
94  template<typename Scalar>
95  Scalar* Function<Scalar>::get_fn_values(int component)
96  {
97  check_params(component, cur_node, num_components); check_table(component, cur_node, 0, "Function values");
98  return cur_node->values[component][0];
99  }
100 
101  template<typename Scalar>
102  Scalar* Function<Scalar>::get_dx_values(int component)
103  {
104  check_params(component, cur_node, num_components); check_table(component, cur_node, 1, "DX values");
105  return cur_node->values[component][1];
106  }
107 
108  template<typename Scalar>
109  Scalar* Function<Scalar>::get_dy_values(int component)
110  {
111  check_params(component, cur_node, num_components); check_table(component, cur_node, 2, "DY values");
112  return cur_node->values[component][2];
113  }
114 
115  template<typename Scalar>
116  void Function<Scalar>::get_dx_dy_values(Scalar*& dx, Scalar*& dy, int component)
117  {
118  check_params(component, cur_node, num_components); check_table(component, cur_node, 1, "DX values"); check_table(component, cur_node, 2, "DY values");
119  dx = cur_node->values[component][1];
120  dy = cur_node->values[component][2];
121  }
122 
123  template<typename Scalar>
124  Scalar* Function<Scalar>::get_dxx_values(int component)
125  {
126  check_params(component, cur_node, num_components); check_table(component, cur_node, 3, "DXX values");
127  return cur_node->values[component][3];
128  }
129 
130  template<typename Scalar>
131  Scalar* Function<Scalar>::get_dyy_values(int component)
132  {
133  check_params(component, cur_node, num_components); check_table(component, cur_node, 4, "DYY values");
134  return cur_node->values[component][4];
135  }
136 
137  template<typename Scalar>
138  Scalar* Function<Scalar>::get_dxy_values(int component)
139  {
140  check_params(component, cur_node, num_components); check_table(component, cur_node, 5, "DXY values");
141  return cur_node->values[component][5];
142  }
143 
144  template<typename Scalar>
145  Scalar* Function<Scalar>::get_values(int a, int b)
146  {
147  return cur_node->values[a][b];
148  }
149 
150  template<typename Scalar>
152  {
153  int i;
154 
155  // check to see if we already have the quadrature
156  for (i = 0; i < 4; i++)
157  if(quads[i] == quad_2d)
158  {
159  cur_quad = i;
160  return;
161  }
162 
163  // if not, add the quadrature to a free slot
164  for (i = 0; i < 4; i++)
165  if(quads[i] == NULL)
166  {
167  quads[i] = quad_2d;
168  cur_quad = i;
169  return;
170  }
171 
172  throw Hermes::Exceptions::Exception("too many quadratures.");
173  }
174 
175  template<typename Scalar>
177  {
178  return quads[cur_quad];
179  }
180 
181  template<typename Scalar>
182  int Function<Scalar>::idx2mask[6][2] =
183  {
184  { H2D_FN_VAL_0, H2D_FN_VAL_1 }, { H2D_FN_DX_0, H2D_FN_DX_1 }, { H2D_FN_DY_0, H2D_FN_DY_1 },
185  { H2D_FN_DXX_0, H2D_FN_DXX_1 }, { H2D_FN_DYY_0, H2D_FN_DYY_1 }, { H2D_FN_DXY_0, H2D_FN_DXY_1 }
186  };
187 
188  template<typename Scalar>
189  typename Function<Scalar>::Node* Function<Scalar>::new_node(int mask, int num_points)
190  {
191  // get the number of tables
192  int nt = 0, m = mask;
193  if(num_components < 2) m &= H2D_FN_VAL_0 | H2D_FN_DX_0 | H2D_FN_DY_0 | H2D_FN_DXX_0 | H2D_FN_DYY_0 | H2D_FN_DXY_0;
194  while (m) { nt += m & 1; m >>= 1; }
195 
196  // allocate a node including its data part, init table pointers
197  int size = (sizeof(Node) - sizeof(Scalar)) + sizeof(Scalar) * num_points * nt; //Due to impl. reasons, the structure Node has non-zero length of data even though they can be zero.
198  Node* node = (Node*) malloc(size);
199  node->mask = mask;
200  node->size = size;
201  memset(node->values, 0, sizeof(node->values));
202  Scalar* data = node->data;
203  for (int j = 0; j < num_components; j++) {
204  for (int i = 0; i < 6; i++)
205  if(mask & idx2mask[i][j]) {
206  node->values[j][i] = data;
207  data += num_points;
208  }
209  }
210 
211  total_mem += size;
212  if(max_mem < total_mem) max_mem = total_mem;
213  return node;
214  }
215 
216  template<typename Scalar>
218  {
219  if(sub_idx > H2D_MAX_IDX)
220  handle_overflow_idx();
221  else {
222  if(sub_tables->find(sub_idx) == sub_tables->end())
223  sub_tables->insert(std::pair<uint64_t, LightArray<Node*>*>(sub_idx, new LightArray<Node*>));
224  nodes = sub_tables->find(sub_idx)->second;
225  }
226  }
227 
228  template<typename Scalar>
229  void Function<Scalar>::force_transform(uint64_t sub_idx, Trf* ctm)
230  {
231  this->sub_idx = sub_idx;
232  this->ctm = ctm;
233  update_nodes_ptr();
234  }
235 
236  template<typename Scalar>
238  {
239  if(node == NULL) throw Exceptions::NullException(1);
240  if(cur_node != NULL) {
241  total_mem -= cur_node->size;
242  ::free(cur_node);
243  }
244  cur_node = node;
245  }
246 
247  template class HERMES_API Function<double>;
248  template class HERMES_API Function<std::complex<double> >;
249  }
250 }