Hermes2D  2.0
neighbor.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 "neighbor.h"
17 #include <algorithm>
18 
19 namespace Hermes
20 {
21  namespace Hermes2D
22  {
23  template<typename Scalar>
25  supported_shapes(NULL),
26  mesh(mesh),
27  central_transformations(LightArray<Transformations*>(4)),
28  neighbor_transformations(LightArray<Transformations*>(4)),
29  central_el(el),
30  neighb_el(NULL),
31  quad(&g_quad_2d_std)
32  {
33  if(central_el == NULL || central_el->active != 1)
34  throw Exceptions::Exception("You must pass an active element to the NeighborSearch constructor.");
35  neighbors.reserve(2);
36  neighbor_edges.reserve(2);
37 
38  ignore_errors = false;
39  n_neighbors = 0;
40  neighborhood_type = H2D_DG_NOT_INITIALIZED;
41  original_central_el_transform = 0;
42  }
43 
44  template<typename Scalar>
46  supported_shapes(NULL),
47  mesh(ns.mesh),
48  central_transformations(LightArray<Transformations*>(4)),
49  neighbor_transformations(LightArray<Transformations*>(4)),
50  central_el(ns.central_el),
51  neighb_el(NULL),
52  neighbor_edge(ns.neighbor_edge),
53  active_segment(ns.active_segment)
54  {
55  neighbors.reserve(2);
56  neighbor_edges.reserve(2);
57 
58  for(unsigned int j = 0; j < ns.central_transformations.get_size(); j++)
59  if(ns.central_transformations.present(j))
60  {
61  // Copy current array of transformations into new memory location.
62  Transformations *tmp = new Transformations(ns.central_transformations.get(j));
63  this->central_transformations.add(tmp, j);
64  }
65  for(unsigned int j = 0; j < ns.neighbor_transformations.get_size(); j++)
66  if(ns.neighbor_transformations.present(j))
67  {
68  // Copy current array of transformations into new memory location.
69  Transformations *tmp = new Transformations(ns.neighbor_transformations.get(j));
70  this->neighbor_transformations.add(tmp, j);
71  }
72 
73  if(central_el == NULL || central_el->active != 1)
74  throw Exceptions::Exception("You must pass an active element to the NeighborSearch constructor.");
75 
76  for(unsigned int i = 0; i < ns.neighbors.size(); i++)
77  this->neighbors.push_back(ns.neighbors[i]);
78  for(unsigned int i = 0; i < ns.neighbor_edges.size(); i++)
79  this->neighbor_edges.push_back(ns.neighbor_edges[i]);
80 
82  n_neighbors = ns.n_neighbors;
83  neighborhood_type = ns.neighborhood_type;
84  original_central_el_transform = ns.original_central_el_transform;
85  quad = (&g_quad_2d_std);
86  active_edge = ns.active_edge;
87  }
88 
89  template<typename Scalar>
91  {
92  neighbor_edges.clear();
93  neighbors.clear();
94  clear_supported_shapes();
95 
96  for(unsigned int i = 0; i < central_transformations.get_size(); i++)
97  if(this->central_transformations.present(i))
98  delete this->central_transformations.get(i);
99  for(unsigned int i = 0; i < neighbor_transformations.get_size(); i++)
100  if(this->neighbor_transformations.present(i))
101  delete this->neighbor_transformations.get(i);
102  }
103 
104  template<typename Scalar>
106  {
107  return n_neighbors;
108  }
109 
110  template<typename Scalar>
111  const Hermes::vector<Element*>* NeighborSearch<Scalar>::get_neighbors() const
112  {
113  return &neighbors;
114  }
115 
116  template<typename Scalar>
118  {
119  if(supported_shapes != NULL) delete supported_shapes; supported_shapes = NULL;
120  }
121 
122  template<typename Scalar>
124  {
125  this->ignore_errors = value;
126  }
127 
128  template<typename Scalar>
130  {
131  // Reset transformations.
132  for(unsigned int i = 0; i < n_neighbors; i++)
133  {
134  if(this->central_transformations.present(i))
135  this->central_transformations.get(i)->reset();
136  if(this->neighbor_transformations.present(i))
137  this->neighbor_transformations.get(i)->reset();
138  }
139 
140  // Reset information about the neighborhood's active state.
141  active_segment = 0;
142  active_edge = 0;
143  neighb_el = NULL;
144  neighbor_edge.local_num_of_edge = 0;
145 
146  // Clear vectors with neighbor elements and their edge info for the active edge.
147  neighbor_edges.clear();
148  neighbors.clear();
149  n_neighbors = 0;
150 
151  neighborhood_type = H2D_DG_NOT_INITIALIZED;
152  }
153 
154  template<typename Scalar>
156  {
157  reset_neighb_info();
158  active_edge = edge;
159 
160  //debug_log("central element: %d", central_el->id);
161  if(central_el->en[active_edge]->bnd == 0)
162  {
163  neighb_el = central_el->get_neighbor(active_edge);
164 
165  // First case : The neighboring element is of the same size as the central one.
166  if(neighb_el != NULL)
167  {
168  //debug_log("active neighbor el: %d", neighb_el->id);
169 
170  // Get local number of the edge used by the neighbor.
171  for (unsigned int j = 0; j < neighb_el->get_nvert(); j++)
172  if(central_el->en[active_edge] == neighb_el->en[j])
173  {
174  neighbor_edge.local_num_of_edge = j;
175  break;
176  }
177 
178  NeighborEdgeInfo local_edge_info;
179  local_edge_info.local_num_of_edge = neighbor_edge.local_num_of_edge;
180 
181  // Query the orientation of the neighbor edge relative to the central el.
182  int p1 = central_el->vn[active_edge]->id;
183  int p2 = central_el->vn[(active_edge + 1) % central_el->get_nvert()]->id;
184  local_edge_info.orientation = neighbor_edge_orientation(p1, p2, 0);
185 
186  neighbor_edges.push_back(local_edge_info);
187 
188  // There is only one neighbor in this case.
189  n_neighbors = 1;
190  neighbors.push_back(neighb_el);
191 
192  // No need for transformation, since the neighboring element is of the same size.
193  neighborhood_type = H2D_DG_NO_TRANSF;
194  }
195  else
196  {
197  // Peek the vertex in the middle of the active edge (if there is none, vertex will be NULL).
198  Node* vertex = mesh->peek_vertex_node(central_el->en[active_edge]->p1, central_el->en[active_edge]->p2);
199 
200  // Endpoints of the active edge.
201  int orig_vertex_id[2];
202  orig_vertex_id[0] = central_el->vn[active_edge]->id;
203  orig_vertex_id[1] = central_el->vn[(active_edge + 1) % central_el->get_nvert()]->id;
204 
205  if(vertex == NULL)
206  {
207  neighborhood_type = H2D_DG_GO_UP;
208 
209  Element* parent = central_el->parent;
210 
211  // Array of middle-point vertices of the intermediate parent edges that we climb up to the correct parent element.
212  Node** par_mid_vertices = new Node*[Transformations::max_level];
213  // Number of visited intermediate parents.
214  int n_parents = 0;
215 
216  for (unsigned int j = 0; j < (unsigned) Transformations::max_level; j++)
217  par_mid_vertices[j] = NULL;
218 
219  find_act_elem_up(parent, orig_vertex_id, par_mid_vertices, n_parents);
220 
221  delete [] par_mid_vertices;
222  }
223  else
224  {
225  neighborhood_type = H2D_DG_GO_DOWN;
226 
227  int sons[Transformations::max_level]; // array of virtual sons of the central el. visited on the way down to the neighbor
228  int n_sons = 0; // number of used transformations
229 
230  // Start the search by going down to the first son.
231  find_act_elem_down( vertex, orig_vertex_id, sons, n_sons + 1);
232 
233  //debug_log("number of neighbors on the way down: %d ", n_neighbors);
234  }
235  }
236  }
237  else
238  if(!ignore_errors)
239  throw Hermes::Exceptions::Exception("The given edge isn't inner");
240  }
241 
242  template<typename Scalar>
244  {
245  Hermes::vector<unsigned int> transformations = get_transforms(original_central_el_transform);
246  // Inter-element edge.
247  if(is_inter_edge(edge, transformations))
248  {
249  set_active_edge(edge);
250  update_according_to_sub_idx(transformations);
251  return true;
252  }
253  // Intra-element edge.
254  else
255  {
256  neighb_el = central_el;
257 
258  neighbor_transformations.add(new Transformations(transformations), 0);
259 
260  neighbor_edge.local_num_of_edge = active_edge = edge;
261  NeighborEdgeInfo local_edge_info;
262  local_edge_info.local_num_of_edge = neighbor_edge.local_num_of_edge;
263  // The "opposite" view of the same edge has the same orientation.
264  local_edge_info.orientation = 0;
265  neighbor_edges.push_back(local_edge_info);
266 
267  n_neighbors = 1;
268  neighbors.push_back(neighb_el);
269  neighborhood_type = H2D_DG_NO_TRANSF;
270  return false;
271  }
272  }
273 
274  template<typename Scalar>
275  Hermes::vector<unsigned int> NeighborSearch<Scalar>::get_transforms(uint64_t sub_idx) const
276  {
277  Hermes::vector<unsigned int> transformations_backwards;
278  while (sub_idx > 0)
279  {
280  transformations_backwards.push_back((sub_idx - 1) & 7);
281  sub_idx = (sub_idx - 1) >> 3;
282  }
283  Hermes::vector<unsigned int> transformations;
284  for(unsigned int i = 0; i < transformations_backwards.size(); i++)
285  transformations.push_back(transformations_backwards[transformations_backwards.size() - 1 - i]);
286 
287  return transformations;
288  }
289 
290  template<typename Scalar>
291  bool NeighborSearch<Scalar>::is_inter_edge(const int& edge, const Hermes::vector<unsigned int>& transformations) const
292  {
293  // No subelements => of course this edge is an inter-element one.
294  if(transformations.size() == 0)
295  return true;
296 
297  // Triangles.
298  for(unsigned int i = 0; i < transformations.size(); i++)
299  if(central_el->get_mode() == HERMES_MODE_TRIANGLE)
300  {
301  if((edge == 0 && (transformations[i] == 2 || transformations[i] == 3)) ||
302  (edge == 1 && (transformations[i] == 0 || transformations[i] == 3)) ||
303  (edge == 2 && (transformations[i] == 1 || transformations[i] == 3)))
304  return false;
305  }
306  // Quads.
307  else
308  {
309  if((edge == 0 && (transformations[i] == 2 || transformations[i] == 3 || transformations[i] == 5)) ||
310  (edge == 1 && (transformations[i] == 0 || transformations[i] == 3 || transformations[i] == 6)) ||
311  (edge == 2 && (transformations[i] == 0 || transformations[i] == 1 || transformations[i] == 4)) ||
312  (edge == 3 && (transformations[i] == 1 || transformations[i] == 2 || transformations[i] == 7)))
313  return false;
314  }
315  return true;
316  }
317 
318  template<typename Scalar>
319  void NeighborSearch<Scalar>::update_according_to_sub_idx(const Hermes::vector<unsigned int>& transformations)
320  {
321  if(neighborhood_type == H2D_DG_NO_TRANSF || neighborhood_type == H2D_DG_GO_UP)
322  {
323  if(!neighbor_transformations.present(0)) // in case of neighborhood_type == H2D_DG_NO_TRANSF
324  neighbor_transformations.add(new Transformations, 0);
325  Transformations *tr = neighbor_transformations.get(0);
326 
327  for(unsigned int i = 0; i < transformations.size(); i++)
328  // Triangles.
329  if(central_el->get_mode() == HERMES_MODE_TRIANGLE)
330  if((active_edge == 0 && transformations[i] == 0) ||
331  (active_edge == 1 && transformations[i] == 1) ||
332  (active_edge == 2 && transformations[i] == 2))
333  tr->transf[tr->num_levels++] = (!neighbor_edge.orientation ? neighbor_edge.local_num_of_edge : (neighbor_edge.local_num_of_edge + 1) % 3);
334  else
335  tr->transf[tr->num_levels++] = (neighbor_edges[0].orientation ? neighbor_edge.local_num_of_edge : (neighbor_edge.local_num_of_edge + 1) % 3);
336  // Quads.
337  else
338  if((active_edge == 0 && (transformations[i] == 0 || transformations[i] == 6)) ||
339  (active_edge == 1 && (transformations[i] == 1 || transformations[i] == 4)) ||
340  (active_edge == 2 && (transformations[i] == 2 || transformations[i] == 7)) ||
341  (active_edge == 3 && (transformations[i] == 3 || transformations[i] == 5)))
342  tr->transf[tr->num_levels++] = (!neighbor_edge.orientation ? neighbor_edge.local_num_of_edge : (neighbor_edge.local_num_of_edge + 1) % 4);
343  else if((active_edge == 0 && (transformations[i] == 1 || transformations[i] == 7)) ||
344  (active_edge == 1 && (transformations[i] == 2 || transformations[i] == 5)) ||
345  (active_edge == 2 && (transformations[i] == 3 || transformations[i] == 6)) ||
346  (active_edge == 3 && (transformations[i] == 0 || transformations[i] == 4)))
347  tr->transf[tr->num_levels++] = (neighbor_edge.orientation ? neighbor_edge.local_num_of_edge : (neighbor_edge.local_num_of_edge + 1) % 4);
348  }
349  else handle_sub_idx_way_down(transformations);
350  }
351 
352  template<typename Scalar>
353  void NeighborSearch<Scalar>::handle_sub_idx_way_down(const Hermes::vector<unsigned int>& transformations)
354  {
355  Hermes::vector<unsigned int> neighbors_to_be_deleted;
356  Hermes::vector<unsigned int> neighbors_not_to_be_deleted;
357 
358  Hermes::vector<unsigned int> updated_transformations;
359  for(int i = 0; i < transformations.size(); i++)
360  {
361  if(! ((active_edge == 0 && transformations[i] == 4) || (active_edge == 1 && transformations[i] == 7) || (active_edge == 2 && transformations[i] == 5) || (active_edge == 3 && transformations[i] == 6)) )
362  {
363  if(active_edge == 0 && transformations[i] == 6)
364  updated_transformations.push_back(0);
365  else if(active_edge == 0 && transformations[i] == 7)
366  updated_transformations.push_back(1);
367  else if(active_edge == 1 && transformations[i] == 4)
368  updated_transformations.push_back(1);
369  else if(active_edge == 1 && transformations[i] == 5)
370  updated_transformations.push_back(2);
371  else if(active_edge == 2 && transformations[i] == 6)
372  updated_transformations.push_back(3);
373  else if(active_edge == 2 && transformations[i] == 7)
374  updated_transformations.push_back(2);
375  else if(active_edge == 3 && transformations[i] == 4)
376  updated_transformations.push_back(0);
377  else if(active_edge == 3 && transformations[i] == 5)
378  updated_transformations.push_back(3);
379  else
380  updated_transformations.push_back(transformations[i]);
381  }
382  }
383 
384  // We basically identify the neighbors that are not compliant with the current sub-element mapping on the central element.
385  for(unsigned int neighbor_i = 0; neighbor_i < n_neighbors; neighbor_i++)
386  {
387  bool deleted = false;
388 
389  Transformations* current_transforms = central_transformations.get(neighbor_i);
390 
391  for(unsigned int level = 0; level < std::min((unsigned int)updated_transformations.size(), current_transforms->num_levels); level++)
392  {
393  // If the found neighbor is not a neighbor of this subelement.
394  if(!compatible_transformations(current_transforms->transf[level], updated_transformations[level], active_edge))
395  {
396  deleted = true;
397  break;
398  }
399  }
400 
401  /*
402  // If there were more sub-element transformation from the assembling than from the neighbor search.
403  if(!deleted)
404  {
405  if((unsigned int)updated_transformations.size() > current_transforms->num_levels)
406  {
407  for(unsigned int level = current_transforms->num_levels; level < (unsigned int)updated_transformations.size(); level++)
408  {
409  // If the found neighbor is not a neighbor of this subelement.
410  if(!compatible_transformations(current_transforms->transf[current_transforms->num_levels - 1], updated_transformations[level], active_edge))
411  {
412  deleted = true;
413  break;
414  }
415  }
416  }
417  }
418  */
419  if(deleted)
420  neighbors_to_be_deleted.push_back(neighbor_i);
421  else
422  neighbors_not_to_be_deleted.push_back(neighbor_i);
423  }
424 
425  // Now we truly delete (in the reverse order) the neighbors.
426  if(neighbors_to_be_deleted.size() > 0)
427  for(unsigned int neighbors_to_be_deleted_i = neighbors_to_be_deleted.size(); neighbors_to_be_deleted_i >= 1; neighbors_to_be_deleted_i--)
428  delete_neighbor(neighbors_to_be_deleted[neighbors_to_be_deleted_i - 1]);
429  }
430 
431  template<typename Scalar>
432  bool NeighborSearch<Scalar>::compatible_transformations(unsigned int a, unsigned int b, int edge) const
433  {
434  if(a == b)
435  return true;
436  if(edge == 0)
437  {
438  if((a == 0 && (b == 6 || b == 4)) ||
439  (a == 1 && (b == 7 || b == 4)))
440  return true;
441  else
442  return false;
443  }
444  if(edge == 1)
445  {
446  if((a == 1 && (b == 4 || b == 7)) ||
447  (a == 2 && (b == 5 || b == 7)))
448  return true;
449  else
450  return false;
451  }
452  if(edge == 2)
453  {
454  if((a == 2 && (b == 7 || b == 5)) ||
455  (a == 3 && (b == 6 || b == 5)))
456  return true;
457  else
458  return false;
459  }
460  if(edge == 3)
461  {
462  if((a == 3 && (b == 5 || b == 6)) ||
463  (a == 0 && (b == 4 || b == 6)))
464  return true;
465  else
466  return false;
467  }
468  return false;
469  }
470 
471  template<typename Scalar>
473  {
474  if(neighborhood_type != H2D_DG_GO_DOWN)
475  return;
476  // Obtain the transformations sequence.
477  Hermes::vector<unsigned int> transformations = get_transforms(original_central_el_transform);
478 
479  Hermes::vector<unsigned int> updated_transformations;
480  for(int i = 0; i < transformations.size(); i++)
481  {
482  if(! ((active_edge == 0 && transformations[i] == 4) || (active_edge == 1 && transformations[i] == 7) || (active_edge == 2 && transformations[i] == 5) || (active_edge == 3 && transformations[i] == 6)) )
483  {
484  if(active_edge == 0 && transformations[i] == 6)
485  updated_transformations.push_back(0);
486  else if(active_edge == 0 && transformations[i] == 7)
487  updated_transformations.push_back(1);
488  else if(active_edge == 1 && transformations[i] == 4)
489  updated_transformations.push_back(1);
490  else if(active_edge == 1 && transformations[i] == 5)
491  updated_transformations.push_back(2);
492  else if(active_edge == 2 && transformations[i] == 6)
493  updated_transformations.push_back(3);
494  else if(active_edge == 2 && transformations[i] == 7)
495  updated_transformations.push_back(2);
496  else if(active_edge == 3 && transformations[i] == 4)
497  updated_transformations.push_back(0);
498  else if(active_edge == 3 && transformations[i] == 5)
499  updated_transformations.push_back(3);
500  else
501  updated_transformations.push_back(transformations[i]);
502  }
503  }
504 
505  // Test for active element.
506  if(updated_transformations.size() == 0)
507  return;
508 
509  for(unsigned int i = 0; i < n_neighbors; i++)
510  {
511  // Find the index where the additional subelement mapping (on top of the initial one from assembling) starts.
512  unsigned int j = 0;
513  // Note that we do not have to test if central_transformations is empty or how long it is, because it has to be
514  // longer than transformations (and that is tested).
515  // Also the function compatible_transformations() does not have to be used, as now the array central_transformations
516  // has been adjusted so that it contains the array transformations.
517  while(central_transformations.get(i)->transf[j] == updated_transformations[j])
518  if(++j > updated_transformations.size() - 1)
519  break;
520  if(j > central_transformations.get(i)->num_levels)
521  j = central_transformations.get(i)->num_levels;
522 
523  for(unsigned int level = central_transformations.get(i)->num_levels; level < updated_transformations.size(); level++)
524  {
525  if(!neighbor_transformations.present(i))
526  neighbor_transformations.add(new Transformations, i);
527 
528  Transformations* neighbor_transforms = neighbor_transformations.get(i);
529 
530  // Triangles.
531  if(central_el->get_mode() == HERMES_MODE_TRIANGLE)
532  if((active_edge == 0 && updated_transformations[level] == 0) ||
533  (active_edge == 1 && updated_transformations[level] == 1) ||
534  (active_edge == 2 && updated_transformations[level] == 2))
535  neighbor_transforms->transf[neighbor_transforms->num_levels++] = (!neighbor_edge.orientation ? neighbor_edge.local_num_of_edge : (neighbor_edge.local_num_of_edge + 1) % 3);
536  else
537  neighbor_transforms->transf[neighbor_transforms->num_levels++] = (neighbor_edge.orientation ? neighbor_edge.local_num_of_edge : (neighbor_edge.local_num_of_edge + 1) % 3);
538  // Quads.
539  else
540  if((active_edge == 0 && (updated_transformations[level] == 0 || updated_transformations[level] == 6)) ||
541  (active_edge == 1 && (updated_transformations[level] == 1 || updated_transformations[level] == 4)) ||
542  (active_edge == 2 && (updated_transformations[level] == 2 || updated_transformations[level] == 7)) ||
543  (active_edge == 3 && (updated_transformations[level] == 3 || updated_transformations[level] == 5)))
544  neighbor_transforms->transf[neighbor_transforms->num_levels++] = (!neighbor_edge.orientation ? neighbor_edge.local_num_of_edge : (neighbor_edge.local_num_of_edge + 1) % 4);
545  else if((active_edge == 0 && (updated_transformations[level] == 1 || updated_transformations[level] == 7)) ||
546  (active_edge == 1 && (updated_transformations[level] == 2 || updated_transformations[level] == 5)) ||
547  (active_edge == 2 && (updated_transformations[level] == 3 || updated_transformations[level] == 6)) ||
548  (active_edge == 3 && (updated_transformations[level] == 0 || updated_transformations[level] == 4)))
549  neighbor_transforms->transf[neighbor_transforms->num_levels++] = (neighbor_edge.orientation ? neighbor_edge.local_num_of_edge : (neighbor_edge.local_num_of_edge + 1) % 4);
550  }
551 
552  central_transformations.get(i)->strip_initial_transformations(j);
553  }
554  }
555 
556  template<typename Scalar>
558  {
559  // Create a new clear array for the remaining transformations.
560  unsigned int shifted_trfs[max_level];
561  memset(shifted_trfs, 0, max_level * sizeof(unsigned int));
562  // Move the old one to the new one.
563  for(unsigned int k = number_of_stripped; k < num_levels; k++)
564  shifted_trfs[k - number_of_stripped] = transf[k];
565  // Point to the new one.
566  memcpy(transf, shifted_trfs, max_level*sizeof(unsigned int));
567  // We also have to store the information about length of the transformation array for this neighbor.
568  num_levels -= number_of_stripped;
569  }
570 
571  template<typename Scalar>
572  void NeighborSearch<Scalar>::delete_neighbor(unsigned int position)
573  {
574  for(unsigned int i = position; i < n_neighbors - 1; i++)
575  central_transformations.get(i)->copy_from(central_transformations.get(i + 1));
576 
577  if(central_transformations.present(n_neighbors - 1)) // may not be true when position == n_neighbors - 1
578  central_transformations.get(n_neighbors - 1)->reset();
579 
580  for(unsigned int i = position; i < n_neighbors - 1; i++)
581  {
582  if(neighbor_transformations.present(i + 1))
583  {
584  if(!neighbor_transformations.present(i))
585  neighbor_transformations.add(new Transformations, i);
586 
587  neighbor_transformations.get(i)->copy_from(neighbor_transformations.get(i + 1));
588  }
589  }
590  if(neighbor_transformations.present(n_neighbors - 1)) // may not be true when position == n_neighbors - 1
591  neighbor_transformations.get(n_neighbors - 1)->reset();
592 
593  neighbor_edges.erase (neighbor_edges.begin() + position);
594  neighbors.erase (neighbors.begin() + position);
595  n_neighbors--;
596  }
597 
598  template<typename Scalar>
599  void NeighborSearch<Scalar>::find_act_elem_up( Element* elem, int* orig_vertex_id, Node** par_mid_vertices, int n_parents)
600  {
601  Node* edge = NULL;
602  Node* vertex = NULL;
603 
604  assert(n_parents <= (int)Transformations::max_level);
605 
606  // IDs of vertices bounding the current intermediate parent edge.
607  int p1 = elem->vn[active_edge]->id;
608  int p2 = elem->vn[(active_edge + 1) % elem->get_nvert()]->id;
609 
610  int id_of_par_orient_1 = p1;
611  int id_of_par_orient_2 = p2;
612 
613  // Find if p1 and p2 bound a used edge (used by the neighbor element).
614  edge = mesh->peek_edge_node(p1, p2);
615 
616  // Add the vertex in the middle of the parent edge to the array of intermediate parent vertices. This is for
617  // consequent transformation of functions on neighbor element.
618  vertex = mesh->peek_vertex_node(p1, p2);
619  if(vertex != NULL)
620  {
621  if(n_parents == 0)
622  par_mid_vertices[n_parents++] = vertex;
623  else
624  if(n_parents == Transformations::max_level - 1)
625  throw Hermes::Exceptions::Exception("Maximum number of intermediate parents exceeded in NeighborSearch<Scalar>::finding_act_elem_up");
626  else
627  if(par_mid_vertices[n_parents - 1]->id != vertex->id)
628  par_mid_vertices[n_parents++] = vertex;
629  }
630 
631  if((edge == NULL) || (central_el->en[active_edge]->id == edge->id))
632  {
633  // We have not yet found the parent of the central element completely adjacent to the neighbor.
634  find_act_elem_up(elem->parent, orig_vertex_id, par_mid_vertices, n_parents);
635  }
636  else
637  {
638  for (int i = 0; i < 2; i++)
639  {
640  // Get a pointer to the active neighbor element.
641  if((edge->elem[i] != NULL) && (edge->elem[i]->active == 1))
642  {
643  neighb_el = edge->elem[i]; //debug_log("way up neighbor: %d", neighb_el->id);
644 
645  // Get local number of the edge used by the neighbor.
646  neighbor_edge.local_num_of_edge = -1;
647  for(unsigned int j = 0; j < neighb_el->get_nvert(); j++)
648  if(neighb_el->en[j] == edge)
649  {
650  neighbor_edge.local_num_of_edge = j;
651  break;
652  }
653  if(neighbor_edge.local_num_of_edge == -1) throw Hermes::Exceptions::Exception("Neighbor edge wasn't found");
654 
655  Node* n = NULL;
656 
657  // Add to the array of neighbor_transformations one that transforms central el. to its parent completely
658  // adjacent to the single big neighbor.
659  assert(n_neighbors == 0);
660 
661  neighbor_transformations.add(new Transformations, n_neighbors);
662  Transformations *neighbor_transforms = neighbor_transformations.get(n_neighbors);
663 
664  neighbor_transforms->num_levels = n_parents;
665 
666  // Go back through the intermediate inactive parents down to the central element and stack corresponding
667  // neighbor_transformations into the array 'neighbor_transformations'.
668  for(int j = n_parents - 1; j > 0; j-- )
669  {
670  n = mesh->peek_vertex_node(par_mid_vertices[j]->id, p1);
671  if(n == NULL)
672  {
673  neighbor_transforms->transf[n_parents - j - 1] = neighbor_edge.local_num_of_edge;
674  p1 = par_mid_vertices[j]->id;
675  }
676  else
677  {
678  if(n->id == par_mid_vertices[j-1]->id)
679  {
680  neighbor_transforms->transf[n_parents - j - 1] = (neighbor_edge.local_num_of_edge + 1) % neighb_el->get_nvert();
681  p2 = par_mid_vertices[j]->id;
682  }
683  else
684  {
685  neighbor_transforms->transf[n_parents - j - 1] = neighbor_edge.local_num_of_edge;
686  p1 = par_mid_vertices[j]->id;
687  }
688  }
689  }
690 
691  // Final transformation to the central element itself.
692  if(orig_vertex_id[0] == par_mid_vertices[0]->id)
693  neighbor_transforms->transf[n_parents - 1] = neighbor_edge.local_num_of_edge;
694  else
695  neighbor_transforms->transf[n_parents - 1] = (neighbor_edge.local_num_of_edge + 1) % neighb_el->get_nvert();
696 
697  NeighborEdgeInfo local_edge_info;
698  local_edge_info.local_num_of_edge = neighbor_edge.local_num_of_edge;
699 
700  // Query the orientation of the neighbor edge relative to the central el.
701  local_edge_info.orientation = neighbor_edge_orientation(id_of_par_orient_1, id_of_par_orient_2, 0);
702 
703  neighbor_edges.push_back(local_edge_info);
704 
705  // There is only one neighbor, ...
706  n_neighbors = 1;
707 
708  // ...add it to the vector of neighbors.
709  neighbors.push_back(neighb_el);
710  }
711  }
712  }
713  }
714 
715  template<typename Scalar>
716  void NeighborSearch<Scalar>::find_act_elem_down( Node* vertex, int* bounding_verts_id, int* sons, unsigned int n_sons)
717  {
718  int mid_vert = vertex->id; // ID of vertex in between vertices from par_vertex_id.
719  int bnd_verts[2];
720  bnd_verts[0] = bounding_verts_id[0];
721  bnd_verts[1] = bounding_verts_id[1];
722 
723  assert(n_sons < (unsigned) Transformations::max_level);
724 
725  for (int i = 0; i < 2; i++)
726  {
727  sons[n_sons-1] = (active_edge + i) % central_el->get_nvert();
728 
729  // Try to get a pointer to the edge between the middle vertex and one of the vertices bounding the previously
730  // tested segment.
731  Node* edge = mesh->peek_edge_node(mid_vert, bnd_verts[i]);
732 
733  if(edge == NULL) // The edge is not used, i.e. there is no active element on either side.
734  {
735  // Get the middle vertex of this edge and try again on the segments into which this vertex splits the edge.
736  Node * n = mesh->peek_vertex_node(mid_vert, bnd_verts[i]);
737  if(n == NULL)
738  throw Hermes::Exceptions::Exception("wasn't able to find middle vertex");
739  else
740  {
741  // Make sure the next visited segment has the same orientation as the original central element's active edge.
742  if(i == 0)
743  bounding_verts_id[1] = mid_vert;
744  else
745  bounding_verts_id[0] = mid_vert;
746 
747  find_act_elem_down( n, bounding_verts_id, sons, n_sons + 1);
748 
749  bounding_verts_id[0] = bnd_verts[0];
750  bounding_verts_id[1] = bnd_verts[1];
751  }
752  }
753  else // We have found a used edge, the active neighbor we are looking for is on one of its sides.
754  {
755  for (int j = 0; j < 2; j++)
756  {
757  if((edge->elem[j] != NULL) && (edge->elem[j]->active == 1))
758  {
759  neighb_el = mesh->get_element(edge->elem[j]->id); //debug_log("way down neighbor: %d", edge->elem[j]->id);
760 
761  // Get local number of the edge used by the neighbor.
762  neighbor_edge.local_num_of_edge = -1;
763  for(unsigned int k = 0; k < neighb_el->get_nvert(); k++)
764  if(neighb_el->en[k] == edge)
765  {
766  neighbor_edge.local_num_of_edge = k;
767  break;
768  }
769 
770  if(neighbor_edge.local_num_of_edge == -1) throw Hermes::Exceptions::Exception("Neighbor edge wasn't found");
771 
772  //assert(!central_transformations.present(n_neighbors));
773 
774  central_transformations.add(new Transformations, n_neighbors);
775  Transformations *tr = central_transformations.get(n_neighbors);
776 
777  // Construct the transformation path to the current neighbor.
778  for(unsigned int k = 0; k < n_sons; k++)
779  tr->transf[k] = sons[k];
780  tr->num_levels = n_sons;
781 
782  NeighborEdgeInfo local_edge_info;
783  local_edge_info.local_num_of_edge = neighbor_edge.local_num_of_edge;
784  // Query the orientation of the neighbor edge relative to the central el.
785  local_edge_info.orientation = neighbor_edge_orientation(bnd_verts[0], bnd_verts[1], i);
786 
787  neighbor_edges.push_back(local_edge_info);
788 
789  // Append the new neighbor.
790  n_neighbors++;
791  neighbors.push_back(neighb_el);
792  }
793  }
794  }
795  }
796  }
797 
798  template<typename Scalar>
799  int NeighborSearch<Scalar>::neighbor_edge_orientation(int bounding_vert1, int bounding_vert2, int segment) const
800  {
801  if(segment == 0)
802  {
803  // neighbor edge goes from parent1 to middle vertex
804  if(neighb_el->vn[neighbor_edge.local_num_of_edge]->id != bounding_vert1)
805  return 1; // orientation reversed
806  }
807  else
808  {
809  // neighbor edge goes from middle vertex to parent2
810  if(neighb_el->vn[neighbor_edge.local_num_of_edge]->id == bounding_vert2)
811  return 1; // orientation reversed
812  }
813  return 0;
814  }
815 
816  template<typename Scalar>
817  NeighborSearch<Scalar>::ExtendedShapeset::ExtendedShapeset(const ExtendedShapeset & other)
818  {
819  this->central_al = new AsmList<Scalar>(*other.central_al);
820  this->cnt = other.cnt;
821  this->dof = other.dof;
822  this->neighbor_al = new AsmList<Scalar>(*other.neighbor_al);
823  this->combine_assembly_lists();
824  }
825 
826  template<typename Scalar>
828  {
829  ExtendedShapeset* new_supp_shapes = new ExtendedShapeset(this, al, space);
830 
831  return new_supp_shapes;
832  }
833 
834  template<typename Scalar>
836  {
837  if(supported_shapes != NULL)
838  delete supported_shapes;
839 
840  supported_shapes = new ExtendedShapeset(this, al, space);
841 
842  return new ExtendedShapeset(*supported_shapes);
843  }
844 
845  template<typename Scalar>
847  {
848  neighb_quad_order = quad->get_edge_points(neighbor_edge.local_num_of_edge, order, neighbors[active_segment]->get_mode());
849  central_quad_order = quad->get_edge_points(active_edge, order, central_el->get_mode());
850  }
851 
852  template<typename Scalar>
853  int NeighborSearch<Scalar>::get_quad_eo(bool on_neighbor) const
854  {
855  if(on_neighbor)
856  return neighb_quad_order;
857  else
858  return central_quad_order;
859  }
860 
861  template<typename Scalar>
863  {
864  return this->active_segment;
865  }
866 
867  template<typename Scalar>
869  {
870  if(index >= n_neighbors)
871  throw Hermes::Exceptions::Exception("NeighborSearch<Scalar>::set_active_segment() called with an incorrect index.");
872 
873  this->active_segment = index;
874  this->neighb_el = this->neighbors[index];
875  this->neighbor_edge = this->neighbor_edges[index];
876  }
877 
878  template<typename Scalar>
880  {
881  return this->neighb_el;
882  }
883 
884  template<typename Scalar>
886  {
887  return this->neighbor_edge;
888  }
889 
890  template<typename Scalar>
891  unsigned int NeighborSearch<Scalar>::get_central_n_trans(unsigned int index) const
892  {
893  if(this->central_transformations.present(index))
894  return this->central_transformations.get(index)->num_levels;
895  else
896  return 0;
897  }
898 
899  template<typename Scalar>
900  unsigned int NeighborSearch<Scalar>::get_central_transformations(unsigned int index_1, unsigned int index_2) const
901  {
902  if(!this->central_transformations.present(index_1))
903  throw Hermes::Exceptions::Exception("Out of bounds of central_transformations.");
904  if(index_2 >= (unsigned) Transformations::max_level)
905  throw Hermes::Exceptions::Exception("Trying to access transformation deeper than allowed.");
906 
907  return this->central_transformations.get(index_1)->transf[index_2];
908  }
909 
910  template<typename Scalar>
911  unsigned int NeighborSearch<Scalar>::get_neighbor_n_trans(unsigned int index) const
912  {
913  if(this->neighbor_transformations.present(index))
914  return this->neighbor_transformations.get(index)->num_levels;
915  else
916  return 0;
917  }
918 
919  template<typename Scalar>
920  unsigned int NeighborSearch<Scalar>::get_neighbor_transformations(unsigned int index_1, unsigned int index_2) const
921  {
922  if(!this->neighbor_transformations.present(index_1))
923  throw Hermes::Exceptions::Exception("Out of bounds of neighbor_transformations.");
924  if(index_2 >= (unsigned) Transformations::max_level)
925  throw Hermes::Exceptions::Exception("Trying to access transformation deeper than allowed.");
926 
927  return this->neighbor_transformations.get(index_1)->transf[index_2];
928  }
929 
930  template<typename Scalar>
932  {
933  Func<Scalar>* fn_central = init_fn(fu, get_quad_eo(false));
934 
935  uint64_t original_transform = fu->get_transform();
936 
937  // Change the active element of the function. Note that this also resets the transformations on the function.
938  fu->set_active_element(neighbors[active_segment]);
939 
940  if(neighbor_transformations.present(active_segment))
941  neighbor_transformations.get(active_segment)->apply_on(fu);
942 
943  Func<Scalar>* fn_neighbor = init_fn(fu, get_quad_eo(true));
944 
945  // Restore the original function.
946  fu->set_active_element(central_el);
947  fu->set_transform(original_transform);
948 
949  return new DiscontinuousFunc<Scalar>(fn_central, fn_neighbor, (neighbor_edge.orientation == 1));
950 
951  //NOTE: This function is not very efficient, since it sets the active elements and possibly pushes transformations
952  // for each mesh function in each cycle of the innermost assembly loop. This is neccessary because only in
953  // this innermost cycle (in function DiscreteProblem::eval_form), we know the quadrature order (dependent on
954  // the actual basis and test function), which is needed for creating the Func<Scalar> objects via init_fn.
955  // The reason for storing the central and neighbor values of any given function in these objects is that otherwise
956  // we would have to have one independent copy of the function for each of the neighboring elements. However, it
957  // could unify the way PrecalcShapesets and MeshFunctions are treated in NeighborSearch and maybe these additional
958  // deep memory copying, performed only after setting the active edge part (before the nested loops over basis and
959  // test functions), would be actually more efficient than this. This would require implementing copy for Filters.
960  }
961 
962  template<typename Scalar>
964  central_al(central_al)
965  {
967  space->get_boundary_assembly_list(neighborhood->neighb_el, neighborhood->neighbor_edge.local_num_of_edge, neighbor_al);
969  }
970 
971  template<typename Scalar>
973  {
974  assert(central_al != NULL && neighbor_al != NULL);
975  cnt = central_al->cnt + neighbor_al->cnt;
976  dof = new int[cnt];
977  memcpy(dof, central_al->dof, sizeof(int)*central_al->cnt);
978  memcpy(dof + central_al->cnt, neighbor_al->dof, sizeof(int)*neighbor_al->cnt);
979  }
980 
981  template<typename Scalar>
983  {
984  delete [] dof;
985  delete neighbor_al;
986  }
987 
988  template<typename Scalar>
990  {
991  delete central_al;
992  }
993 
994  template<typename Scalar>
996  {
997  delete [] this->dof;
998  space->get_boundary_assembly_list(neighborhood->neighb_el, neighborhood->neighbor_edge.local_num_of_edge, neighbor_al);
999  combine_assembly_lists();
1000  }
1001 
1002  template<typename Scalar>
1004  {
1005  return (index >= central_al->cnt);
1006  }
1007 
1008  template<typename Scalar>
1010  {
1011  memset(transf, 0, max_level * sizeof(int));
1012  }
1013 
1014  template<typename Scalar>
1015  NeighborSearch<Scalar>::Transformations::Transformations(const Transformations* t)
1016  {
1017  copy_from(t);
1018  }
1019 
1020  template<typename Scalar>
1021  NeighborSearch<Scalar>::Transformations::Transformations(const Hermes::vector<unsigned int>& t)
1022  {
1023  copy_from(t);
1024  }
1025 
1026  template<typename Scalar>
1027  void NeighborSearch<Scalar>::Transformations::copy_from(const Hermes::vector<unsigned int>& t)
1028  {
1029  num_levels = std::min<unsigned int>(t.size(), max_level);
1030  std::copy( t.begin(), t.begin() + num_levels, transf);
1031  }
1032 
1033  template<typename Scalar>
1034  void NeighborSearch<Scalar>::Transformations::copy_from(const Transformations* t)
1035  {
1036  num_levels = t->num_levels;
1037  memcpy(transf, t->transf, max_level * sizeof(unsigned int));
1038  }
1039 
1040  template<typename Scalar>
1041  void NeighborSearch<Scalar>::Transformations::copy_to(Hermes::vector<unsigned int>* t)
1042  {
1043  t->assign(transf, transf + num_levels);
1044  }
1045 
1046  template<typename Scalar>
1047  void NeighborSearch<Scalar>::Transformations::reset()
1048  {
1049  memset(transf, 0, num_levels * sizeof(unsigned int));
1050  num_levels = 0;
1051  }
1052 
1053  template<typename Scalar>
1054  void NeighborSearch<Scalar>::Transformations::apply_on(Transformable* tr) const
1055  {
1056  for(unsigned int i = 0; i < num_levels; i++)
1057  tr->push_transform(transf[i]);
1058  }
1059 
1060  template<typename Scalar>
1061  void NeighborSearch<Scalar>::Transformations::apply_on(const Hermes::vector<Transformable*>& tr) const
1062  {
1063  for(Hermes::vector<Transformable*>::const_iterator it = tr.begin(); it != tr.end(); ++it)
1064  for(unsigned int i = 0; i < num_levels; i++)
1065  (*it)->push_transform(transf[i]);
1066  }
1067 
1068  template class HERMES_API NeighborSearch<double>;
1069  template class HERMES_API NeighborSearch<std::complex<double> >;
1070  }
1071 }