sample_point_container.cc
Go to the documentation of this file.
1 // LIC// ====================================================================
2 // LIC// This file forms part of oomph-lib, the object-oriented,
3 // LIC// multi-physics finite-element library, available
4 // LIC// at http://www.oomph-lib.org.
5 // LIC//
6 // LIC// Copyright (C) 2006-2024 Matthias Heil and Andrew Hazel
7 // LIC//
8 // LIC// This library is free software; you can redistribute it and/or
9 // LIC// modify it under the terms of the GNU Lesser General Public
10 // LIC// License as published by the Free Software Foundation; either
11 // LIC// version 2.1 of the License, or (at your option) any later version.
12 // LIC//
13 // LIC// This library is distributed in the hope that it will be useful,
14 // LIC// but WITHOUT ANY WARRANTY; without even the implied warranty of
15 // LIC// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 // LIC// Lesser General Public License for more details.
17 // LIC//
18 // LIC// You should have received a copy of the GNU Lesser General Public
19 // LIC// License along with this library; if not, write to the Free Software
20 // LIC// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
21 // LIC// 02110-1301 USA.
22 // LIC//
23 // LIC// The authors may be contacted at oomph-lib@maths.man.ac.uk.
24 // LIC//
25 // LIC//====================================================================
26 #include "sample_point_container.h"
27 
28 
29 namespace oomph
30 {
31  /// ///////////////////////////////////////////////////////////////////////////
32  /// ///////////////////////////////////////////////////////////////////////////
33  /// ///////////////////////////////////////////////////////////////////////////
34  // RefineableBin class
35  /// ///////////////////////////////////////////////////////////////////////////
36  /// ///////////////////////////////////////////////////////////////////////////
37  /// ///////////////////////////////////////////////////////////////////////////
38 
39  //==============================================================================
40  /// Destructor
41  //==============================================================================
43  {
44  if (Sub_bin_array_pt != 0)
45  {
46  delete Sub_bin_array_pt;
47  }
48  Sub_bin_array_pt = 0;
49 
50  if (Sample_point_pt != 0)
51  {
52  unsigned n = Sample_point_pt->size();
53  for (unsigned i = 0; i < n; i++)
54  {
55  delete (*Sample_point_pt)[i];
56  }
57  delete Sample_point_pt;
58  }
59  }
60 
61 
62  //==============================================================================
63  /// Compute total number of sample points recursively
64  //==============================================================================
66  const
67  {
68  unsigned count = 0;
69 
70  // Recurse?
71  if (Sub_bin_array_pt != 0)
72  {
73  count =
74  Sub_bin_array_pt->total_number_of_sample_points_computed_recursively();
75  }
76  else
77  {
78  if (Sample_point_pt != 0)
79  {
80  count = Sample_point_pt->size();
81  }
82  }
83  return count;
84  }
85 
86 
87  //==============================================================================
88  /// Function called for making a sub bin array in a given RefineableBin.
89  /// Pass the vector of min and max coordinates of the NEW bin array.
90  //==============================================================================
92  const Vector<std::pair<double, double>>& min_and_max_coordinates)
93  {
94  // Setup parameters for sub-bin
95  RefineableBinArrayParameters* ref_bin_array_parameters_pt =
96  new RefineableBinArrayParameters(Bin_array_pt->mesh_pt());
97 
98  // Pass coordinates and dimensions
99  ref_bin_array_parameters_pt->min_and_max_coordinates() =
100  min_and_max_coordinates;
101 
102  ref_bin_array_parameters_pt->dimensions_of_bin_array() =
103  Bin_array_pt->dimensions_of_bin_array();
104 
105  // Eulerian coordinates or zeta?
106  if (Bin_array_pt->use_eulerian_coordinates_during_setup())
107  {
108  ref_bin_array_parameters_pt
109  ->enable_use_eulerian_coordinates_during_setup();
110  }
111  else
112  {
113  ref_bin_array_parameters_pt
114  ->disable_use_eulerian_coordinates_during_setup();
115  }
116 
117 
118 #ifdef OOMPH_HAS_MPI
119 
120  // How do we handle halo elements?
121  if (Bin_array_pt->ignore_halo_elements_during_locate_zeta_search())
122  {
123  ref_bin_array_parameters_pt
124  ->enable_ignore_halo_elements_during_locate_zeta_search();
125  }
126  else
127  {
128  ref_bin_array_parameters_pt
129  ->disable_ignore_halo_elements_during_locate_zeta_search();
130  }
131 
132 #endif
133 
134  // "Measure of" number of sample points per element
135  ref_bin_array_parameters_pt->nsample_points_generated_per_element() =
136  Bin_array_pt->nsample_points_generated_per_element();
137 
138 
139  // Is it recursive?
140  if (Bin_array_pt->bin_array_is_recursive())
141  {
142  ref_bin_array_parameters_pt->enable_bin_array_is_recursive();
143  }
144  else
145  {
146  ref_bin_array_parameters_pt->disable_bin_array_is_recursive();
147  }
148 
149  // Depth
150  ref_bin_array_parameters_pt->depth() = Bin_array_pt->depth() + 1;
151 
152  // Max. depth
153  ref_bin_array_parameters_pt->max_depth() = Bin_array_pt->max_depth();
154 
155  // Max. number of sample points before it's subdivided
156  ref_bin_array_parameters_pt->max_number_of_sample_point_per_bin() =
157  Bin_array_pt->max_number_of_sample_point_per_bin();
158 
159  // Root bin array
160  ref_bin_array_parameters_pt->root_bin_array_pt() =
161  Bin_array_pt->root_bin_array_pt();
162 
163  // We first construct a new bin array, providing the right parameters
164  BinArrayParameters* bin_array_parameters_pt = ref_bin_array_parameters_pt;
165  Sub_bin_array_pt = new RefineableBinArray(bin_array_parameters_pt);
166  delete ref_bin_array_parameters_pt;
167 
168  // Fill it
169  Sub_bin_array_pt->fill_bin_array(*Sample_point_pt);
170 
171  // Now deleting Sample_point_pt, we no longer need it; note that
172  // sample points themselves stay alive!
173  delete Sample_point_pt;
174  Sample_point_pt = 0;
175  }
176 
177 
178  //============================================================================
179  /// Output bin; x,[y,[z]],n_sample_points.
180  //============================================================================
181  void RefineableBin::output(std::ofstream& outfile, const bool& don_t_recurse)
182  {
183  // Recurse?
184  if ((Sub_bin_array_pt != 0) && (!don_t_recurse))
185  {
186  Sub_bin_array_pt->output_bins(outfile);
187  }
188  else
189  {
190  unsigned n_lagr = Bin_array_pt->ndim_zeta();
191  Vector<std::pair<double, double>> min_and_max_coordinates(n_lagr);
192  get_bin_boundaries(min_and_max_coordinates);
193 
194  // How many sample points do we have in this bin?
195  unsigned n_sample_points = 0;
196  if (Sample_point_pt != 0)
197  {
198  n_sample_points = Sample_point_pt->size();
199  }
200 
201  switch (n_lagr)
202  {
203  case 1:
204  outfile << "ZONE I=2\n"
205  << min_and_max_coordinates[0].first << " " << n_sample_points
206  << std::endl
207  << min_and_max_coordinates[0].second << " " << n_sample_points
208  << std::endl;
209  break;
210 
211  case 2:
212 
213  outfile << "ZONE I=2, J=2\n"
214  << min_and_max_coordinates[0].first << " "
215  << min_and_max_coordinates[1].first << " " << n_sample_points
216  << "\n"
217 
218  << min_and_max_coordinates[0].second << " "
219  << min_and_max_coordinates[1].first << " " << n_sample_points
220  << "\n"
221 
222  << min_and_max_coordinates[0].first << " "
223  << min_and_max_coordinates[1].second << " " << n_sample_points
224  << "\n"
225 
226  << min_and_max_coordinates[0].second << " "
227  << min_and_max_coordinates[1].second << " " << n_sample_points
228  << "\n";
229  break;
230 
231  case 3:
232 
233 
234  outfile << "ZONE I=2, J=2, K=2\n"
235  << min_and_max_coordinates[0].first << " "
236  << min_and_max_coordinates[1].first << " "
237  << min_and_max_coordinates[2].first << " " << n_sample_points
238  << "\n"
239 
240  << min_and_max_coordinates[0].second << " "
241  << min_and_max_coordinates[1].first << " "
242  << min_and_max_coordinates[2].first << " " << n_sample_points
243  << "\n"
244 
245  << min_and_max_coordinates[0].first << " "
246  << min_and_max_coordinates[1].second << " "
247  << min_and_max_coordinates[2].first << " " << n_sample_points
248  << "\n"
249 
250  << min_and_max_coordinates[0].second << " "
251  << min_and_max_coordinates[1].second << " "
252  << min_and_max_coordinates[2].first << " " << n_sample_points
253  << "\n"
254 
255  << min_and_max_coordinates[0].first << " "
256  << min_and_max_coordinates[1].first << " "
257  << min_and_max_coordinates[2].second << " " << n_sample_points
258  << "\n"
259 
260  << min_and_max_coordinates[0].second << " "
261  << min_and_max_coordinates[1].first << " "
262  << min_and_max_coordinates[2].second << " " << n_sample_points
263  << "\n"
264 
265  << min_and_max_coordinates[0].first << " "
266  << min_and_max_coordinates[1].second << " "
267  << min_and_max_coordinates[2].second << " " << n_sample_points
268  << "\n"
269 
270  << min_and_max_coordinates[0].second << " "
271  << min_and_max_coordinates[1].second << " "
272  << min_and_max_coordinates[2].second << " " << n_sample_points
273  << "\n";
274 
275  break;
276 
277  default:
278 
279  oomph_info << "n_lagr=" << n_lagr << std::endl;
280  throw OomphLibError("Wrong dimension",
281  OOMPH_CURRENT_FUNCTION,
282  OOMPH_EXCEPTION_LOCATION);
283  }
284  }
285  }
286 
287 
288  //============================================================================
289  /// Output bin; x,[y,[z]]
290  //============================================================================
291  void RefineableBin::output_bin_vertices(std::ofstream& outfile)
292  {
293  // Recurse?
294  if (Sub_bin_array_pt != 0)
295  {
296  Sub_bin_array_pt->output_bin_vertices(outfile);
297  }
298  else
299  {
300  unsigned n_lagr = Bin_array_pt->ndim_zeta();
301  Vector<std::pair<double, double>> min_and_max_coordinates(n_lagr);
302  get_bin_boundaries(min_and_max_coordinates);
303 
304  switch (n_lagr)
305  {
306  case 1:
307  outfile << "ZONE I=2\n"
308  << min_and_max_coordinates[0].first << std::endl
309  << min_and_max_coordinates[0].second << std::endl;
310  break;
311 
312  case 2:
313 
314  outfile << "ZONE I=2, J=2\n"
315  << min_and_max_coordinates[0].first << " "
316  << min_and_max_coordinates[1].first << " "
317  << "\n"
318 
319  << min_and_max_coordinates[0].second << " "
320  << min_and_max_coordinates[1].first << " "
321  << "\n"
322 
323  << min_and_max_coordinates[0].first << " "
324  << min_and_max_coordinates[1].second << " "
325  << "\n"
326 
327  << min_and_max_coordinates[0].second << " "
328  << min_and_max_coordinates[1].second << " "
329  << "\n";
330  break;
331 
332  case 3:
333 
334 
335  outfile << "ZONE I=2, J=2, K=2\n"
336  << min_and_max_coordinates[0].first << " "
337  << min_and_max_coordinates[1].first << " "
338  << min_and_max_coordinates[2].first << " "
339  << "\n"
340 
341  << min_and_max_coordinates[0].second << " "
342  << min_and_max_coordinates[1].first << " "
343  << min_and_max_coordinates[2].first << " "
344  << "\n"
345 
346  << min_and_max_coordinates[0].first << " "
347  << min_and_max_coordinates[1].second << " "
348  << min_and_max_coordinates[2].first << " "
349  << "\n"
350 
351  << min_and_max_coordinates[0].second << " "
352  << min_and_max_coordinates[1].second << " "
353  << min_and_max_coordinates[2].first << " "
354  << "\n"
355 
356  << min_and_max_coordinates[0].first << " "
357  << min_and_max_coordinates[1].first << " "
358  << min_and_max_coordinates[2].second << " "
359  << "\n"
360 
361  << min_and_max_coordinates[0].second << " "
362  << min_and_max_coordinates[1].first << " "
363  << min_and_max_coordinates[2].second << " "
364  << "\n"
365 
366  << min_and_max_coordinates[0].first << " "
367  << min_and_max_coordinates[1].second << " "
368  << min_and_max_coordinates[2].second << " "
369  << "\n"
370 
371  << min_and_max_coordinates[0].second << " "
372  << min_and_max_coordinates[1].second << " "
373  << min_and_max_coordinates[2].second << " "
374  << "\n";
375 
376  break;
377 
378  default:
379 
380  oomph_info << "n_lagr=" << n_lagr << std::endl;
381  throw OomphLibError("Wrong dimension",
382  OOMPH_CURRENT_FUNCTION,
383  OOMPH_EXCEPTION_LOCATION);
384  }
385  }
386  }
387 
388 
389  //==============================================================================
390  /// Add a SamplePoint* to a RefineableBin object.
391  //==============================================================================
392  void RefineableBin::add_sample_point(SamplePoint* new_sample_point_pt,
393  const Vector<double>& zeta_coordinates)
394  {
395  // If the bin is a "leaf" (ie no sub bin array)
396  if (Sub_bin_array_pt == 0)
397  {
398  // if there is no Sample_point_pt create it
399  if (Sample_point_pt == 0)
400  {
401  Sample_point_pt = new Vector<SamplePoint*>;
402  }
403  this->Sample_point_pt->push_back(new_sample_point_pt);
404 
405  // If we are recursive (ie not at the maximum depth or not
406  // in fill bin by diffusion configuration) and if the number
407  // of elements there are in the RefineableBin is bigger than the maximum
408  // one
409  if ((Bin_array_pt->bin_array_is_recursive()) &&
410  (Sample_point_pt->size() >
411  Bin_array_pt->max_number_of_sample_point_per_bin()) &&
412  (Bin_array_pt->depth() < Bin_array_pt->max_depth()))
413  {
414  // Get min and max coordinates of current bin...
415  Vector<std::pair<double, double>> min_and_max_coordinates(
416  Bin_array_pt->ndim_zeta());
417  get_bin_boundaries(min_and_max_coordinates);
418 
419  // ...and use them as the boundaries for new sub-bin-array
420  // (this transfers all the new points into the new sub-bin-array
421  this->make_sub_bin_array(min_and_max_coordinates);
422  }
423  }
424  else // if the bin has a sub bin array
425  {
426  // we call the corresponding method of the sub bin array
427  this->Sub_bin_array_pt->add_sample_point(new_sample_point_pt,
428  zeta_coordinates);
429  }
430  }
431 
432 
433  //==============================================================================
434  /// Find sub-GeomObject (finite element) and the local coordinate
435  /// s within it that contains point with global coordinate zeta.
436  /// sub_geom_object_pt=0 if point can't be found.
437  //==============================================================================
438  void RefineableBin::locate_zeta(const Vector<double>& zeta,
439  GeomObject*& sub_geom_object_pt,
440  Vector<double>& s)
441  {
442  // Haven't found zeta yet!
443  sub_geom_object_pt = 0;
444 
445  // Descend?
446  if (Sub_bin_array_pt != 0)
447  {
448  Sub_bin_array_pt->locate_zeta(zeta, sub_geom_object_pt, s);
449  }
450  else
451  {
452  // Do we have to look into any sample points in this bin?
453  // NOTE: There's some slight potential for overlap/duplication
454  // because we always search through all the sample points in a bin
455  // (unless we find the required point in which case we stop).
456  bool do_it = true;
457  if (
458  Bin_array_pt->root_bin_array_pt()
459  ->total_number_of_sample_points_visited_during_locate_zeta_from_top_level() <
460  Bin_array_pt->root_bin_array_pt()
461  ->first_sample_point_to_actually_lookup_during_locate_zeta())
462  {
463  // oomph_info << "Not doing it (ref-bin) because counter less than
464  // first" << std::endl;
465  do_it = false;
466  }
467  if (
468  Bin_array_pt->root_bin_array_pt()
469  ->total_number_of_sample_points_visited_during_locate_zeta_from_top_level() >
470  Bin_array_pt->root_bin_array_pt()
471  ->last_sample_point_to_actually_lookup_during_locate_zeta())
472  {
473  // oomph_info << "Not doing it (ref-bin) because counter more than last"
474  // << std::endl;
475  do_it = false;
476  }
477  double max_search_radius =
478  Bin_array_pt->root_bin_array_pt()->max_search_radius();
479  bool dont_do_it_because_of_radius = false;
480  if (max_search_radius < DBL_MAX)
481  {
482  // Base "radius" of bin on centre of gravity
483  unsigned n = zeta.size();
484  double dist_squared = 0.0;
485  double cog = 0.0;
486  double aux = 0.0;
487  Vector<std::pair<double, double>> min_and_max_coordinates(n);
488  get_bin_boundaries(min_and_max_coordinates);
489  for (unsigned i = 0; i < n; i++)
490  {
491  cog = 0.5 * (min_and_max_coordinates[i].first +
492  min_and_max_coordinates[i].second);
493  aux = (cog - zeta[i]);
494  dist_squared += aux * aux;
495  }
496  if (dist_squared > max_search_radius * max_search_radius)
497  {
498  do_it = false;
499  dont_do_it_because_of_radius = true;
500  }
501  }
502 
503  if (!do_it)
504  {
505  if (!dont_do_it_because_of_radius)
506  {
507  // Skip all the sample points in this bin
508  Bin_array_pt->root_bin_array_pt()
509  ->total_number_of_sample_points_visited_during_locate_zeta_from_top_level() +=
510  Sample_point_pt->size();
511  }
512  return;
513  }
514 
515 
516  // Now search through (at most) all the sample points in this bin
517  unsigned n_sample_point = Sample_point_pt->size();
518  unsigned i = 0;
519  while ((i < n_sample_point) && (sub_geom_object_pt == 0))
520  {
521  // Get the corresponding finite element
522  FiniteElement* el_pt = Bin_array_pt->mesh_pt()->finite_element_pt(
523  (*Sample_point_pt)[i]->element_index_in_mesh());
524 
525 #ifdef OOMPH_HAS_MPI
526  // We only look at the sample point if it isn't halo
527  // if we are set up to ignore the halo elements
528  if ((Bin_array_pt->ignore_halo_elements_during_locate_zeta_search()) &&
529  (el_pt->is_halo()))
530  {
531  // Halo
532  }
533  else
534  {
535 #endif
536  // Provide initial guess for Newton search using local coordinate
537  // of sample point
538  bool use_equally_spaced_interior_sample_points =
540  unsigned j = (*Sample_point_pt)[i]->sample_point_index_in_element();
541  el_pt->get_s_plot(
542  j,
543  Bin_array_pt->nsample_points_generated_per_element(),
544  s,
545  use_equally_spaced_interior_sample_points);
546 
547 
548  // History of sample points visited
550  {
551  unsigned cached_dim_zeta = Bin_array_pt->ndim_zeta();
552  Vector<double> zeta_sample(cached_dim_zeta);
553  if (Bin_array_pt->use_eulerian_coordinates_during_setup())
554  {
555  el_pt->interpolated_x(s, zeta_sample);
556  }
557  else
558  {
559  el_pt->interpolated_zeta(s, zeta_sample);
560  }
561  double dist = 0.0;
562  for (unsigned ii = 0; ii < cached_dim_zeta; ii++)
563  {
564  BinArray::Visited_sample_points_file << zeta_sample[ii] << " ";
565  dist +=
566  (zeta[ii] - zeta_sample[ii]) * (zeta[ii] - zeta_sample[ii]);
567  }
569  << Bin_array_pt->root_bin_array_pt()
570  ->total_number_of_sample_points_visited_during_locate_zeta_from_top_level()
571  << " " << sqrt(dist) << std::endl;
572  }
573 
574 
575  // Bump counter
576  Bin_array_pt->root_bin_array_pt()
577  ->total_number_of_sample_points_visited_during_locate_zeta_from_top_level()++;
578 
579  bool use_coordinate_as_initial_guess = true;
580  el_pt->locate_zeta(
581  zeta, sub_geom_object_pt, s, use_coordinate_as_initial_guess);
582 
583  // Always fail? (Used for debugging, e.g. to trace out
584  // spiral path)
586  {
587  sub_geom_object_pt = 0;
588  }
589 
590 #ifdef OOMPH_HAS_MPI
591  }
592 #endif
593  // Next one please
594  i++;
595  }
596  }
597  }
598 
599  //==============================================================================
600  /// Boundaries of bin in each coordinate direction. *.first = min;
601  /// *.second = max.
602  //==============================================================================
604  Vector<std::pair<double, double>>& min_and_max_coordinates)
605  {
606  unsigned n_bin = Bin_index_in_bin_array;
607 
608  // temporary storage for the eulerian dim
609  unsigned current_dim = Bin_array_pt->ndim_zeta();
610  min_and_max_coordinates.resize(current_dim);
611  for (unsigned u = 0; u < current_dim; u++)
612  {
613  // The number of bins there are according to the u-th dimension
614  double nbin_in_dir = n_bin % Bin_array_pt->dimension_of_bin_array(u);
615  n_bin /= Bin_array_pt->dimension_of_bin_array(u);
616 
617  // The range between the maximum and minimum u-th coordinates of a bin
618  double range = (Bin_array_pt->min_and_max_coordinates(u).second -
619  Bin_array_pt->min_and_max_coordinates(u).first) /
620  double(Bin_array_pt->dimension_of_bin_array(u));
621 
622  // Now updating the minimum and maximum u-th coordinates for this bin.
623  min_and_max_coordinates[u].first =
624  Bin_array_pt->min_and_max_coordinates(u).first + nbin_in_dir * range;
625  min_and_max_coordinates[u].second =
626  min_and_max_coordinates[u].first + range;
627  }
628  }
629 
630 
631  /// ///////////////////////////////////////////////////////////////////////////
632  /// ///////////////////////////////////////////////////////////////////////////
633  /// ///////////////////////////////////////////////////////////////////////////
634  /// SamplePointContainer base class
635  /// ///////////////////////////////////////////////////////////////////////////
636  /// ///////////////////////////////////////////////////////////////////////////
637  /// ///////////////////////////////////////////////////////////////////////////
638 
639  /// File to record sequence of visited sample points in
641 
642  /// Boolean flag to make to make locate zeta fail
644 
645  /// Use equally spaced sample points? (otherwise vertices are sampled
646  /// repeatedly
648 
649  /// Time setup?
651 
652  /// Offset of sample point container boundaries beyond max/min coords
654 
655 
656  //==============================================================================
657  /// Max. bin dimension (number of bins in coordinate directions)
658  //==============================================================================
660  {
661  unsigned dim = ndim_zeta();
662  unsigned n_max_level = Dimensions_of_bin_array[0];
663  if (dim >= 2)
664  {
665  if (Dimensions_of_bin_array[1] > n_max_level)
666  {
667  n_max_level = Dimensions_of_bin_array[1];
668  }
669  }
670  if (dim == 3)
671  {
672  if (Dimensions_of_bin_array[2] > n_max_level)
673  {
674  n_max_level = Dimensions_of_bin_array[2];
675  }
676  }
677  return n_max_level;
678  }
679 
680 
681  //========================================================================
682  /// Setup the min and max coordinates for the mesh, in each dimension
683  //========================================================================
685  {
686  // Get the lagrangian dimension
687  int n_lagrangian = ndim_zeta();
688 
689  // Storage locally (i.e. in parallel on each processor)
690  // for the minimum and maximum coordinates
691  double zeta_min_local[n_lagrangian];
692  double zeta_max_local[n_lagrangian];
693  for (int i = 0; i < n_lagrangian; i++)
694  {
695  zeta_min_local[i] = DBL_MAX;
696  zeta_max_local[i] = -DBL_MAX;
697  }
698 
699  // Loop over the elements of the mesh
700  unsigned n_el = Mesh_pt->nelement();
701  for (unsigned e = 0; e < n_el; e++)
702  {
703  FiniteElement* el_pt = Mesh_pt->finite_element_pt(e);
704 
705  // Get the number of vertices (nplot=2 does the trick)
706  unsigned n_plot = 2;
707  unsigned n_plot_points = el_pt->nplot_points(n_plot);
708 
709  // Loop over the number of plot points
710  for (unsigned iplot = 0; iplot < n_plot_points; iplot++)
711  {
712  Vector<double> s_local(n_lagrangian);
713  Vector<double> zeta_global(n_lagrangian);
714 
715  // Get the local s -- need to sample over the entire range
716  // of the elements!
717  bool use_equally_spaced_interior_sample_points = false;
718  el_pt->get_s_plot(
719  iplot, n_plot, s_local, use_equally_spaced_interior_sample_points);
720 
721  // Now interpolate to global coordinates
722  if (Use_eulerian_coordinates_during_setup)
723  {
724  el_pt->interpolated_x(s_local, zeta_global);
725  }
726  else
727  {
728  el_pt->interpolated_zeta(s_local, zeta_global);
729  }
730 
731  // Check the max and min in each direction
732  for (int i = 0; i < n_lagrangian; i++)
733  {
734  // Is the coordinate less than the minimum?
735  if (zeta_global[i] < zeta_min_local[i])
736  {
737  zeta_min_local[i] = zeta_global[i];
738  }
739  // Is the coordinate bigger than the maximum?
740  if (zeta_global[i] > zeta_max_local[i])
741  {
742  zeta_max_local[i] = zeta_global[i];
743  }
744  }
745  }
746  }
747 
748  // Global extrema - in parallel, need to get max/min across all processors
749  double zeta_min[n_lagrangian];
750  double zeta_max[n_lagrangian];
751  for (int i = 0; i < n_lagrangian; i++)
752  {
753  zeta_min[i] = 0.0;
754  zeta_max[i] = 0.0;
755  }
756 
757 #ifdef OOMPH_HAS_MPI
758  // If the mesh has been distributed and we want consistent bins
759  // across all processors
760  if (Mesh_pt->is_mesh_distributed())
761  {
762  // .. we need a non-null communicator!
763  if (Mesh_pt->communicator_pt() != 0)
764  {
765  int n_proc = Mesh_pt->communicator_pt()->nproc();
766  if (n_proc > 1)
767  {
768  // Get the minima and maxima over all processors
769  MPI_Allreduce(zeta_min_local,
770  zeta_min,
771  n_lagrangian,
772  MPI_DOUBLE,
773  MPI_MIN,
774  Mesh_pt->communicator_pt()->mpi_comm());
775  MPI_Allreduce(zeta_max_local,
776  zeta_max,
777  n_lagrangian,
778  MPI_DOUBLE,
779  MPI_MAX,
780  Mesh_pt->communicator_pt()->mpi_comm());
781  }
782  }
783  else // Null communicator - throw an error
784  {
785  std::ostringstream error_message_stream;
786  error_message_stream << "Communicator not set for a Mesh\n"
787  << "that was created from a distributed Mesh";
788  throw OomphLibError(error_message_stream.str(),
789  OOMPH_CURRENT_FUNCTION,
790  OOMPH_EXCEPTION_LOCATION);
791  }
792  }
793  else // If the mesh hasn't been distributed then the
794  // max and min are the same on all processors
795  {
796  for (int i = 0; i < n_lagrangian; i++)
797  {
798  zeta_min[i] = zeta_min_local[i];
799  zeta_max[i] = zeta_max_local[i];
800  }
801  }
802 #else // If we're not using MPI then the mesh can't be distributed
803  for (int i = 0; i < n_lagrangian; i++)
804  {
805  zeta_min[i] = zeta_min_local[i];
806  zeta_max[i] = zeta_max_local[i];
807  }
808 #endif
809 
810  // Decrease/increase min and max to allow for any overshoot in
811  // meshes that may move around
812  // There's no point in doing this for DIM_LAGRANGIAN==1
813  for (int i = 0; i < n_lagrangian; i++)
814  {
815  double length = zeta_max[i] - zeta_min[i];
816  zeta_min[i] -= ((Percentage_offset / 100.0) * length);
817  zeta_max[i] += ((Percentage_offset / 100.0) * length);
818  }
819 
820  // Set the entries as the Min/Max_coords vector
821  Min_and_max_coordinates.resize(n_lagrangian);
822  for (int i = 0; i < n_lagrangian; i++)
823  {
824  Min_and_max_coordinates[i].first = zeta_min[i];
825  Min_and_max_coordinates[i].second = zeta_max[i];
826  }
827  }
828 
829 
830  /// ///////////////////////////////////////////////////////////////////////////
831  /// ///////////////////////////////////////////////////////////////////////////
832  /// ///////////////////////////////////////////////////////////////////////////
833  /// RefineableBin array class
834  /// ///////////////////////////////////////////////////////////////////////////
835  /// ///////////////////////////////////////////////////////////////////////////
836  /// ///////////////////////////////////////////////////////////////////////////
837 
838  //==============================================================================
839  /// Constructor
840  //==============================================================================
842  SamplePointContainerParameters* sample_point_container_parameters_pt)
844  sample_point_container_parameters_pt->mesh_pt(),
845  sample_point_container_parameters_pt->min_and_max_coordinates(),
846  sample_point_container_parameters_pt
847  ->use_eulerian_coordinates_during_setup(),
848  sample_point_container_parameters_pt
849  ->ignore_halo_elements_during_locate_zeta_search(),
850  sample_point_container_parameters_pt
851  ->nsample_points_generated_per_element()),
852  BinArray(
853  sample_point_container_parameters_pt->mesh_pt(),
854  sample_point_container_parameters_pt->min_and_max_coordinates(),
855  dynamic_cast<BinArrayParameters*>(sample_point_container_parameters_pt)
856  ->dimensions_of_bin_array(),
857  sample_point_container_parameters_pt
858  ->use_eulerian_coordinates_during_setup(),
859  sample_point_container_parameters_pt
860  ->ignore_halo_elements_during_locate_zeta_search(),
861  sample_point_container_parameters_pt
862  ->nsample_points_generated_per_element())
863  {
864  RefineableBinArrayParameters* ref_bin_array_parameters_pt =
865  dynamic_cast<RefineableBinArrayParameters*>(
866  sample_point_container_parameters_pt);
867 
868 #ifdef PARANOID
869  if (ref_bin_array_parameters_pt == 0)
870  {
871  throw OomphLibError("Wrong sample_point_container_parameters_pt",
872  OOMPH_CURRENT_FUNCTION,
873  OOMPH_EXCEPTION_LOCATION);
874  }
875 #endif
876 
878  ref_bin_array_parameters_pt->bin_array_is_recursive();
879  Depth = ref_bin_array_parameters_pt->depth();
880  Max_depth = ref_bin_array_parameters_pt->max_depth();
882  ref_bin_array_parameters_pt->max_number_of_sample_point_per_bin();
883  Root_bin_array_pt = ref_bin_array_parameters_pt->root_bin_array_pt();
884 
885  // Set default size of bin array (and spatial dimension!)
886  if (Dimensions_of_bin_array.size() == 0)
887  {
888  int dim = 0;
889  if (Mesh_pt->nelement() != 0)
890  {
891  dim = Mesh_pt->finite_element_pt(0)->dim();
892  }
893 
894  // Need to do an Allreduce to ensure that the dimension is consistent
895  // even when no elements are assigned to a certain processor
896 #ifdef OOMPH_HAS_MPI
897  // Only a problem if the mesh has been distributed
898  if (Mesh_pt->is_mesh_distributed())
899  {
900  // Need a non-null communicator
901  if (Mesh_pt->communicator_pt() != 0)
902  {
903  int n_proc = Mesh_pt->communicator_pt()->nproc();
904  if (n_proc > 1)
905  {
906  int dim_reduce;
907  MPI_Allreduce(&dim,
908  &dim_reduce,
909  1,
910  MPI_INT,
911  MPI_MAX,
912  Mesh_pt->communicator_pt()->mpi_comm());
913  dim = dim_reduce;
914  }
915  }
916  }
917 #endif
918 
920  }
921 
922  // Have we specified max/min coordinates?
923  // If not, compute them on the fly from mesh
924  if (Min_and_max_coordinates.size() == 0)
925  {
927  }
928 
929  // Get total number of bins and make space
930  unsigned dim = Dimensions_of_bin_array.size();
931  unsigned n_bin = 1;
932  for (unsigned i = 0; i < dim; i++)
933  {
934  n_bin *= Dimensions_of_bin_array[i];
935  }
936  Bin_pt.resize(n_bin, 0);
937 
938  // I'm my own root bin array
939  if (Depth == 0)
940  {
941  Root_bin_array_pt = this;
942  }
943 
944 #ifdef PARANOID
945  if (Depth > 0)
946  {
947  if (Root_bin_array_pt == 0)
948  {
949  throw OomphLibError(
950  "Must specify root_bin_array for lower-level bin arrays\n",
951  OOMPH_CURRENT_FUNCTION,
952  OOMPH_EXCEPTION_LOCATION);
953  }
954  }
955 #endif
956 
957  // Initialise
962  2; // hierher tune this and create public static default
964  10; // hierher UINT MAX is temporary bypass! tune this and create public
965  // static default
966 
967  // Now fill the bastard...
968  if (Depth == 0)
969  {
970  // Time it
971  double t_start = 0.0;
973  {
974  t_start = TimingHelpers::timer();
975  }
976  fill_bin_array();
978  {
979  double t_end = TimingHelpers::timer();
981  oomph_info << "Time for setup of " << dim
982  << "-dimensional sample point container containing " << npts
983  << " sample points: " << t_end - t_start
984  << " sec (ref_bin); third party: 0 sec ( = 0 %)"
985  << std::endl;
986  }
987  }
988  }
989 
990 
991  //==============================================================================
992  /// Boundaries of specified bin in each coordinate direction.
993  /// *.first = min; *.second = max.
994  //==============================================================================
996  const unsigned& bin_index,
997  Vector<std::pair<double, double>>& min_and_max_coordinates_of_bin)
998  {
999  unsigned bin_index_local = bin_index;
1000 
1001  // temporary storage for the eulerian dim
1002  unsigned current_dim = ndim_zeta();
1003  min_and_max_coordinates_of_bin.resize(current_dim);
1004  for (unsigned u = 0; u < current_dim; u++)
1005  {
1006  // The number of bins there are according to the u-th dimension
1007  unsigned nbin_in_dir = bin_index_local % dimension_of_bin_array(u);
1008  bin_index_local /= dimension_of_bin_array(u);
1009 
1010  // The range between the maximum and minimum u-th coordinates of a bin
1011  double range =
1012  (Min_and_max_coordinates[u].second - Min_and_max_coordinates[u].first) /
1013  double(Dimensions_of_bin_array[u]);
1014 
1015  // Now updating the minimum and maximum u-th coordinates for this bin.
1016  min_and_max_coordinates_of_bin[u].first =
1017  Min_and_max_coordinates[u].first + double(nbin_in_dir) * range;
1018  min_and_max_coordinates_of_bin[u].second =
1019  min_and_max_coordinates_of_bin[u].first + range;
1020  }
1021  }
1022 
1023 
1024  //==============================================================================
1025  /// Output neighbouring bins up to given "radius" of the specified bin
1026  //==============================================================================
1027  void RefineableBinArray::output_bin_vertices(std::ofstream& outfile)
1028  {
1029  // Loop over bins
1030  unsigned n_bin = Bin_pt.size();
1031  for (unsigned i = 0; i < n_bin; i++)
1032  {
1033  if (Bin_pt[i] != 0)
1034  {
1035  Bin_pt[i]->output_bin_vertices(outfile);
1036  }
1037  }
1038  }
1039 
1040 
1041  //==============================================================================
1042  /// Output neighbouring bins up to given "radius" of the specified bin
1043  //==============================================================================
1044  void RefineableBinArray::output_neighbouring_bins(const unsigned& bin_index,
1045  const unsigned& radius,
1046  std::ofstream& outfile)
1047  {
1048  unsigned n_lagr = ndim_zeta();
1049 
1050  Vector<unsigned> neighbouring_bin_index;
1051  get_neighbouring_bins_helper(bin_index, radius, neighbouring_bin_index);
1052  unsigned nneigh = neighbouring_bin_index.size();
1053 
1054  // Outline of bin structure
1055  switch (n_lagr)
1056  {
1057  case 1:
1058  outfile << "ZONE I=2\n"
1059  << Min_and_max_coordinates[0].first << std::endl
1060  << Min_and_max_coordinates[0].second << std::endl;
1061  break;
1062 
1063  case 2:
1064 
1065  outfile << "ZONE I=2, J=2\n"
1066  << Min_and_max_coordinates[0].first << " "
1067  << Min_and_max_coordinates[1].first << " "
1068  << "\n"
1069 
1070  << Min_and_max_coordinates[0].second << " "
1071  << Min_and_max_coordinates[1].first << " "
1072  << "\n"
1073 
1074  << Min_and_max_coordinates[0].first << " "
1075  << Min_and_max_coordinates[1].second << " "
1076  << "\n"
1077 
1078  << Min_and_max_coordinates[0].second << " "
1079  << Min_and_max_coordinates[1].second << " "
1080  << "\n";
1081  break;
1082 
1083  case 3:
1084 
1085  outfile << "ZONE I=2, J=2, K=2 \n"
1086  << Min_and_max_coordinates[0].first << " "
1087  << Min_and_max_coordinates[1].first << " "
1088  << Min_and_max_coordinates[2].first << " "
1089  << "\n"
1090 
1091  << Min_and_max_coordinates[0].second << " "
1092  << Min_and_max_coordinates[1].first << " "
1093  << Min_and_max_coordinates[2].first << " "
1094  << "\n"
1095 
1096  << Min_and_max_coordinates[0].first << " "
1097  << Min_and_max_coordinates[1].second << " "
1098  << Min_and_max_coordinates[2].first << " "
1099  << "\n"
1100 
1101  << Min_and_max_coordinates[0].second << " "
1102  << Min_and_max_coordinates[1].second << " "
1103  << Min_and_max_coordinates[2].first << " "
1104  << "\n"
1105 
1106  << Min_and_max_coordinates[0].first << " "
1107  << Min_and_max_coordinates[1].first << " "
1108  << Min_and_max_coordinates[2].second << " "
1109  << "\n"
1110 
1111  << Min_and_max_coordinates[0].second << " "
1112  << Min_and_max_coordinates[1].first << " "
1113  << Min_and_max_coordinates[2].second << " "
1114  << "\n"
1115 
1116  << Min_and_max_coordinates[0].first << " "
1117  << Min_and_max_coordinates[1].second << " "
1118  << Min_and_max_coordinates[2].second << " "
1119  << "\n"
1120 
1121  << Min_and_max_coordinates[0].second << " "
1122  << Min_and_max_coordinates[1].second << " "
1123  << Min_and_max_coordinates[2].second << " "
1124  << "\n";
1125  break;
1126 
1127  default:
1128 
1129  oomph_info << "n_lagr=" << n_lagr << std::endl;
1130  throw OomphLibError(
1131  "Wrong dimension!", OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
1132  }
1133 
1134  // Loop over neighbours
1135  for (unsigned i = 0; i < nneigh; i++)
1136  {
1137  Vector<std::pair<double, double>> min_and_max_coordinates(n_lagr);
1138  get_bin_boundaries(neighbouring_bin_index[i], min_and_max_coordinates);
1139 
1140  switch (n_lagr)
1141  {
1142  case 1:
1143  outfile << "ZONE I=2\n"
1144  << min_and_max_coordinates[0].first << std::endl
1145  << min_and_max_coordinates[0].second << std::endl;
1146  break;
1147 
1148  case 2:
1149 
1150  outfile << "ZONE I=2, J=2\n"
1151  << min_and_max_coordinates[0].first << " "
1152  << min_and_max_coordinates[1].first << " "
1153  << "\n"
1154 
1155  << min_and_max_coordinates[0].second << " "
1156  << min_and_max_coordinates[1].first << " "
1157  << "\n"
1158 
1159  << min_and_max_coordinates[0].first << " "
1160  << min_and_max_coordinates[1].second << " "
1161  << "\n"
1162 
1163  << min_and_max_coordinates[0].second << " "
1164  << min_and_max_coordinates[1].second << " "
1165  << "\n";
1166  break;
1167 
1168  case 3:
1169 
1170  outfile << "ZONE I=2, J=2, K=2\n"
1171  << min_and_max_coordinates[0].first << " "
1172  << min_and_max_coordinates[1].first << " "
1173  << min_and_max_coordinates[2].first << " "
1174  << "\n"
1175 
1176  << min_and_max_coordinates[0].second << " "
1177  << min_and_max_coordinates[1].first << " "
1178  << min_and_max_coordinates[2].first << " "
1179  << "\n"
1180 
1181  << min_and_max_coordinates[0].first << " "
1182  << min_and_max_coordinates[1].second << " "
1183  << min_and_max_coordinates[2].first << " "
1184  << "\n"
1185 
1186  << min_and_max_coordinates[0].second << " "
1187  << min_and_max_coordinates[1].second << " "
1188  << min_and_max_coordinates[2].first << " "
1189  << "\n"
1190 
1191  << min_and_max_coordinates[0].first << " "
1192  << min_and_max_coordinates[1].first << " "
1193  << min_and_max_coordinates[2].second << " "
1194  << "\n"
1195 
1196  << min_and_max_coordinates[0].second << " "
1197  << min_and_max_coordinates[1].first << " "
1198  << min_and_max_coordinates[2].second << " "
1199  << "\n"
1200 
1201  << min_and_max_coordinates[0].first << " "
1202  << min_and_max_coordinates[1].second << " "
1203  << min_and_max_coordinates[2].second << " "
1204  << "\n"
1205 
1206  << min_and_max_coordinates[0].second << " "
1207  << min_and_max_coordinates[1].second << " "
1208  << min_and_max_coordinates[2].second << " "
1209  << "\n";
1210  break;
1211 
1212  default:
1213 
1214  oomph_info << "n_lagr=" << n_lagr << std::endl;
1215  throw OomphLibError("Wrong dimension!",
1216  OOMPH_CURRENT_FUNCTION,
1217  OOMPH_EXCEPTION_LOCATION);
1218  }
1219  }
1220  }
1221 
1222 
1223  //========================================================================
1224  /// Profiling function to compare performance of two different
1225  /// versions of the get_neighbouring_bins_helper(...) function
1226  //========================================================================
1228  {
1229  unsigned old_faster = 0;
1230  unsigned new_faster = 0;
1231  double t_total_new = 0.0;
1232  double t_total_old = 0.0;
1233 
1234  unsigned dim = ndim_zeta();
1235 
1236  // Choose bin in middle of the domain
1237  Vector<double> zeta(dim);
1238  for (unsigned i = 0; i < dim; i++)
1239  {
1240  zeta[i] = 0.5 * (Min_and_max_coordinates[i].first +
1241  Min_and_max_coordinates[i].second);
1242  }
1243 
1244  // Finding the bin in which the point is located
1245  int bin_index = coords_to_bin_index(zeta);
1246 
1247 #ifdef PARANOID
1248  if (bin_index < 0)
1249  {
1250  throw OomphLibError("Negative bin index...",
1251  OOMPH_CURRENT_FUNCTION,
1252  OOMPH_EXCEPTION_LOCATION);
1253  }
1254 #endif
1255 
1256  // Start at this radius (radius = 0 is the central bin)
1257  unsigned radius = 0;
1258 
1259  // "coordinates" of the bin which is most likely to contain the
1260  // point
1261  Vector<unsigned> bin_index_v(dim);
1262  coords_to_vectorial_bin_index(zeta, bin_index_v);
1263 
1264  // We loop over all the dimensions to find the maximum radius we have to
1265  // do the spiraling if we want to be sure there is no bin left at the end
1266  unsigned max_radius = 0;
1267  for (unsigned k = 0; k < dim; k++)
1268  {
1269  unsigned local =
1270  std::max((bin_index_v[k] + 1),
1271  (Dimensions_of_bin_array[k] - bin_index_v[k] - 1));
1272  if (local > max_radius)
1273  {
1274  max_radius = local;
1275  }
1276  }
1277 
1278  // Vector which will store the indices of the neighbouring bins
1279  // at the current radius
1280  Vector<unsigned> bin_index_at_current_radius_old;
1281  Vector<unsigned> bin_index_at_current_radius_new;
1282  while (radius <= max_radius)
1283  {
1284  // Get the neighbouring bins
1285  bin_index_at_current_radius_old.clear();
1286  double t_start = TimingHelpers::timer();
1288  bin_index, radius, bin_index_at_current_radius_old, true);
1289  unsigned nbin_at_current_radius_old =
1290  bin_index_at_current_radius_old.size();
1291  double t_end = TimingHelpers::timer();
1292  double t_old = t_end - t_start;
1293 
1294  bin_index_at_current_radius_new.clear();
1295  double t_start_new = TimingHelpers::timer();
1297  bin_index, radius, bin_index_at_current_radius_new, false);
1298  unsigned nbin_at_current_radius_new =
1299  bin_index_at_current_radius_new.size();
1300  double t_end_new = TimingHelpers::timer();
1301 
1302  double t_new = t_end_new - t_start_new;
1303 
1304  if (nbin_at_current_radius_new != nbin_at_current_radius_old)
1305  {
1306  oomph_info << "Number of bins don't match: new = "
1307  << nbin_at_current_radius_new
1308  << "old = " << nbin_at_current_radius_old
1309  << " radius = " << radius << std::endl;
1310  oomph_info << "Old: " << std::endl;
1311  for (unsigned i = 0; i < nbin_at_current_radius_old; i++)
1312  {
1313  oomph_info << bin_index_at_current_radius_old[i] << " ";
1314  }
1315  oomph_info << std::endl;
1316  oomph_info << "New: " << std::endl;
1317  for (unsigned i = 0; i < nbin_at_current_radius_new; i++)
1318  {
1319  oomph_info << bin_index_at_current_radius_new[i] << " ";
1320  }
1321  oomph_info << std::endl;
1322  }
1323 
1324  t_total_new += t_new;
1325  t_total_old += t_old;
1326 
1327  if (t_new < t_old)
1328  {
1329  new_faster++;
1330  }
1331  else
1332  {
1333  old_faster++;
1334  }
1335  radius++;
1336  }
1337 
1338 
1339  oomph_info << "Number of times old/new version was faster: " << old_faster
1340  << " " << new_faster << std::endl
1341  << "Total old/new time: " << t_total_old << " " << t_total_new
1342  << " " << std::endl;
1343  }
1344 
1345 
1346  //==============================================================================
1347  /// Helper function for computing the bin indices of neighbouring bins
1348  /// at a given "radius" of the specified bin
1349  //==============================================================================
1351  const unsigned& bin_index,
1352  const unsigned& radius,
1353  Vector<unsigned>& neighbouring_bin_index,
1354  const bool& use_old_version)
1355  {
1356  // OLD VERSION
1357  if (use_old_version)
1358  {
1359  neighbouring_bin_index.clear();
1360 
1361  // Quick return (slightly hacky -- the machinery below adds the
1362  // "home" bin twice...)
1363  if (radius == 0)
1364  {
1365  neighbouring_bin_index.push_back(bin_index);
1366  return;
1367  }
1368 
1369  // translate old code
1370  unsigned level = radius;
1371  unsigned bin = bin_index;
1372 
1373  // Dimension
1374  const unsigned n_lagrangian = this->ndim_zeta();
1375 
1376  // This will be different depending on the number of Lagrangian
1377  // coordinates
1378  if (n_lagrangian == 1)
1379  {
1380  // Reserve memory for the container where we return the indices
1381  // of the neighbouring bins (2 bins max, left and right)
1382  neighbouring_bin_index.reserve(2);
1383 
1384  // Single "loop" in one direction - always a vector of max size 2
1385  unsigned nbr_bin_left = bin - level;
1386  if (nbr_bin_left < Dimensions_of_bin_array[0])
1387  {
1388  unsigned nbr_bin = nbr_bin_left;
1389  neighbouring_bin_index.push_back(nbr_bin);
1390  }
1391  unsigned nbr_bin_right = bin + level;
1392  if ((nbr_bin_right < Dimensions_of_bin_array[0]) &&
1393  (nbr_bin_right != nbr_bin_left))
1394  {
1395  unsigned nbr_bin = nbr_bin_right;
1396  neighbouring_bin_index.push_back(nbr_bin);
1397  }
1398  }
1399  else if (n_lagrangian == 2)
1400  {
1401  // Reserve memory for the container where we return the indices
1402  // of the neighbouring bins
1403  const unsigned n_max_neighbour_bins = 8 * level;
1404  neighbouring_bin_index.reserve(n_max_neighbour_bins);
1405 
1406  const unsigned n_total_bin =
1408 
1409  // Which row of the bin structure is the current bin on?
1410  // This is just given by the integer answer of dividing bin
1411  // by Nbin_x (the number of bins in a single row)
1412  // e.g. in a 6x6 grid, bins 6 through 11 would all have bin_row=1
1413  const unsigned bin_row = bin / Dimensions_of_bin_array[0];
1414 
1415  // The neighbour_bin vector contains all bin numbers at the
1416  // specified "distance" (level) away from the current bin
1417 
1418  // Row/column length
1419  const unsigned n_length = (level * 2) + 1;
1420 
1421  {
1422  // Visit all the bins at the specified distance (level) away
1423  // from the current bin. In order to obtain the same order in
1424  // the visited bins as the previous algorithm we visit all the
1425  // bins at the specified distance (level) as follows:
1426 
1427  // Suppose we want the bins at distance (level=2) of the
1428  // specified bin, then we visit them as indicated below
1429 
1430  // 01 02 03 04 05 // First row
1431  // 06 07
1432  // 08 B 09
1433  // 10 11
1434  // 12 13 14 15 16 // Last row
1435  // ^--------------- First column
1436  // ^-- Last column
1437 
1438  // ----------------------------------------------------------------
1439  // Visit all the bins in the first row at the specified
1440  // distance (level) away from the current bin
1441 
1442  // ------------------ FIRST ROW ------------------------
1443  // Pre-compute the distance in the j-direction
1444  const unsigned j_precomputed = level * Dimensions_of_bin_array[0];
1445  // Pre-compute the row where the bin should lie on
1446  const unsigned j_initial_row = bin_row - level;
1447 
1448  // Loop over the columns (of the first row)
1449  for (unsigned i = 0; i < n_length; i++)
1450  {
1451  // --------- First row ------------------------------------------
1452  const unsigned initial_neighbour_bin =
1453  bin - (level - i) - j_precomputed;
1454  // This number might fall on the wrong row of the bin
1455  // structure; this needs to be tested? Not sure why, but leave
1456  // the test!
1457 
1458  // Which row is this number on? (see above)
1459  const unsigned initial_neighbour_bin_row =
1460  initial_neighbour_bin / Dimensions_of_bin_array[0];
1461  // These numbers for the rows must match; if it is then add
1462  // initial_neighbour_bin to the neighbour scheme (The bin
1463  // number must also be greater than zero and less than the
1464  // total number of bins)
1465  if ((j_initial_row == initial_neighbour_bin_row) &&
1466  (initial_neighbour_bin < n_total_bin))
1467  {
1468  neighbouring_bin_index.push_back(initial_neighbour_bin);
1469  }
1470 
1471  } // for (unsigned i=0;i<n_length;i++)
1472 
1473  // Then visit all the bins in the first and last column at the
1474  // specified distance (level) away from the current bin
1475 
1476  // ------------------ FIRST AND LAST COLUMNS ---------------------
1477  // Loop over the rows (of the first and last column)
1478  for (unsigned j = 1; j < n_length - 1; j++)
1479  {
1480  // --------- First column ---------------------------------------
1481  const unsigned initial_neighbour_bin =
1482  bin - (level) - ((level - j) * Dimensions_of_bin_array[0]);
1483  // This number might fall on the wrong row of the bin
1484  // structure; this needs to be tested? Not sure why, but leave
1485  // the test!
1486 
1487  // Which row is this number on? (see above)
1488  const unsigned initial_neighbour_bin_row =
1489  initial_neighbour_bin / Dimensions_of_bin_array[0];
1490 
1491  // Which row should it be on?
1492  const unsigned initial_row = bin_row - (level - j);
1493 
1494  // These numbers for the rows must match; if it is then add
1495  // initial_neighbour_bin to the neighbour scheme (The bin
1496  // number must also be greater than zero and less than the
1497  // total number of bins)
1498  if ((initial_row == initial_neighbour_bin_row) &&
1499  (initial_neighbour_bin < n_total_bin))
1500  {
1501  neighbouring_bin_index.push_back(initial_neighbour_bin);
1502  }
1503 
1504  // --------- Last column -----------------------------------------
1505  const unsigned final_neighbour_bin =
1506  bin + (level) - ((level - j) * Dimensions_of_bin_array[0]);
1507  // This number might fall on the wrong row of the bin
1508  // structure; this needs to be tested? Not sure why, but leave
1509  // the test!
1510 
1511  // Which row is this number on? (see above)
1512  const unsigned final_neighbour_bin_row =
1513  final_neighbour_bin / Dimensions_of_bin_array[0];
1514 
1515  // Which row should it be on?
1516  const unsigned final_row = bin_row - (level - j);
1517 
1518  // These numbers for the rows must match; if it is then add
1519  // initial_neighbour_bin to the neighbour scheme (The bin
1520  // number must also be greater than zero and less than the
1521  // total number of bins)
1522  if ((final_row == final_neighbour_bin_row) &&
1523  (final_neighbour_bin < n_total_bin))
1524  {
1525  neighbouring_bin_index.push_back(final_neighbour_bin);
1526  }
1527 
1528  } // for (unsigned j=1;j<n_length-1;j++)
1529 
1530  // ------------------ LAST ROW ------------------------
1531  // Pre-compute the row where the bin should lie on
1532  const unsigned j_final_row = bin_row + level;
1533 
1534  // Loop over the columns (of the last row)
1535  for (unsigned i = 0; i < n_length; i++)
1536  {
1537  // --------- Last row ------------------------------------------
1538  const unsigned final_neighbour_bin =
1539  bin - (level - i) + j_precomputed;
1540  // This number might fall on the wrong row of the bin
1541  // structure; this needs to be tested? Not sure why, but leave
1542  // the test!
1543 
1544  // Which row is this number on? (see above)
1545  const unsigned final_neighbour_bin_row =
1546  final_neighbour_bin / Dimensions_of_bin_array[0];
1547  // These numbers for the rows must match; if it is then add
1548  // initial_neighbour_bin to the neighbour scheme (The bin
1549  // number must also be greater than zero and less than the
1550  // total number of bins)
1551  if ((j_final_row == final_neighbour_bin_row) &&
1552  (final_neighbour_bin < n_total_bin))
1553  {
1554  neighbouring_bin_index.push_back(final_neighbour_bin);
1555  }
1556 
1557  } // for (unsigned i=0;i<n_length;i++)
1558  }
1559  }
1560  else if (n_lagrangian == 3)
1561  {
1562  // Reserve memory for the container where we return the indices
1563  // of the neighbouring bins
1564  const unsigned n_max_neighbour_bins =
1565  8 * level * (3 + 2 * (level - 1)) +
1566  2 * (2 * (level - 1) + 1) * (2 * (level - 1) + 1);
1567  neighbouring_bin_index.reserve(n_max_neighbour_bins);
1568 
1569  unsigned n_total_bin = Dimensions_of_bin_array[0] *
1572 
1573  // Which layer of the bin structure is the current bin on?
1574  // This is just given by the integer answer of dividing bin
1575  // by Nbin_x*Nbin_y (the number of bins in a single layer
1576  // e.g. in a 6x6x6 grid, bins 72 through 107 would all have bin_layer=2
1577  unsigned bin_layer =
1579 
1580  // Which row in this layer is the bin number on?
1581  unsigned bin_row = (bin / Dimensions_of_bin_array[0]) -
1582  (bin_layer * Dimensions_of_bin_array[1]);
1583 
1584  // The neighbour_bin vector contains all bin numbers at the
1585  // specified "distance" (level) away from the current bin
1586 
1587  // Row/column/layer length
1588  unsigned n_length = (level * 2) + 1;
1589 
1590  // Loop over the layers
1591  for (unsigned k = 0; k < n_length; k++)
1592  {
1593  // Loop over the rows
1594  for (unsigned j = 0; j < n_length; j++)
1595  {
1596  // Loop over the columns
1597  for (unsigned i = 0; i < n_length; i++)
1598  {
1599  // Only do this for the end points of every row/layer/column
1600  if ((k == 0) || (k == n_length - 1) || (j == 0) ||
1601  (j == n_length - 1) || (i == 0) || (i == n_length - 1))
1602  {
1603  unsigned nbr_bin = bin - level + i -
1604  ((level - j) * Dimensions_of_bin_array[0]) -
1605  ((level - k) * Dimensions_of_bin_array[0] *
1607  // This number might fall on the wrong
1608  // row or layer of the bin structure; this needs to be tested
1609 
1610  // Which layer is this number on?
1611  unsigned nbr_bin_layer = nbr_bin / (Dimensions_of_bin_array[0] *
1613 
1614  // Which row is this number on? (see above)
1615  unsigned nbr_bin_row =
1616  (nbr_bin / Dimensions_of_bin_array[0]) -
1617  (nbr_bin_layer * Dimensions_of_bin_array[1]);
1618 
1619  // Which layer and row should it be on, given level?
1620  unsigned layer = bin_layer - level + k;
1621  unsigned row = bin_row - level + j;
1622 
1623  // These layers and rows must match up:
1624  // if so then add nbr_bin to the neighbour schemes
1625  // (The bin number must also be greater than zero
1626  // and less than the total number of bins)
1627  if ((row == nbr_bin_row) && (layer == nbr_bin_layer) &&
1628  (nbr_bin < n_total_bin))
1629  {
1630  neighbouring_bin_index.push_back(nbr_bin);
1631  }
1632  }
1633  }
1634  }
1635  }
1636  }
1637  }
1638  // LOUIS'S VERSION
1639  else
1640  {
1641  neighbouring_bin_index.clear();
1642 
1643  // Just testing if the radius is equal to 0
1644  if (radius == 0)
1645  {
1646  // in this case we only have to push back the bin
1647  neighbouring_bin_index.push_back(bin_index);
1648  }
1649  // Else, if the radius is different from 0
1650  else
1651  {
1652  unsigned dim = ndim_zeta();
1653 
1654  // The vector which will store the coordinates of the bin in the bin
1655  // arrray
1656  Vector<int> vector_of_positions(3);
1657 
1658  // Will store locally the dimension of the bin array
1659  Vector<int> vector_of_dimensions(3);
1660 
1661  // Will store the radiuses for each dimension
1662  // If it is 0, that means the dimension is not vector_of_active_dim
1663  Vector<int> vector_of_radiuses(3);
1664 
1665  // Stores true if the dimension is "active" or false if the
1666  // dimension is inactive (for example the third dimension is inactive in
1667  // a 2D mesh).
1668  std::vector<bool> vector_of_active_dim(3);
1669 
1670  // Will store the coefficients you have to multiply each bin coordinate
1671  // to have the correct unsigned corresponding to the bin index.
1672  Vector<int> vector_of_coef(3);
1673 
1674 
1675  // First initializing this MyArrays for the active dimensions
1676  unsigned coef = 1;
1677  for (unsigned u = 0; u < dim; u++)
1678  {
1679  vector_of_positions[u] =
1680  (((bin_index / coef) % (Dimensions_of_bin_array[u])));
1681  vector_of_coef[u] = coef;
1682  coef *= Dimensions_of_bin_array[u];
1683  vector_of_dimensions[u] = Dimensions_of_bin_array[u];
1684  vector_of_radiuses[u] = radius;
1685  vector_of_active_dim[u] = true;
1686  }
1687  // Filling the rest with default values
1688  for (unsigned u = dim; u < 3; u++)
1689  {
1690  vector_of_positions[u] = 0;
1691  vector_of_coef[u] = 0;
1692  vector_of_dimensions[u] = 1;
1693  vector_of_radiuses[u] = 0;
1694  vector_of_active_dim[u] = false;
1695  }
1696 
1697  // First we fill the bins which corresponds to x+radius and x-radius in
1698  // the bin array (x being the first coordinate/dimension).
1699  // For j equal to radius or -radius
1700  for (int j = -vector_of_radiuses[0]; j <= vector_of_radiuses[0];
1701  j += 2 * vector_of_radiuses[0]) // j corresponds to x
1702  {
1703  int local_tempj =
1704  vector_of_positions[0] + j; // Corresponding bin index
1705  // if we are in the bin array
1706  if (local_tempj >= 0 && local_tempj < vector_of_dimensions[0])
1707  {
1708  // Loop over all the bins
1709  for (int i = -vector_of_radiuses[1]; i <= vector_of_radiuses[1];
1710  i++)
1711  {
1712  // i corresponds to y (2nd dim)
1713  int local_tempi = vector_of_positions[1] + i;
1714  // if we are still in the bin array
1715  if (local_tempi >= 0 && local_tempi < vector_of_dimensions[1])
1716  {
1717  for (int k = -vector_of_radiuses[2]; k <= vector_of_radiuses[2];
1718  k++)
1719  {
1720  // k corresponds to z (third dimension)
1721  int local_tempk = vector_of_positions[2] + k;
1722  // if we are still in the bin array
1723  if (local_tempk >= 0 && local_tempk < vector_of_dimensions[2])
1724  {
1725  neighbouring_bin_index.push_back(
1726  local_tempj * vector_of_coef[0] +
1727  local_tempi * vector_of_coef[1] +
1728  local_tempk * vector_of_coef[2]);
1729  }
1730  }
1731  }
1732  }
1733  }
1734  }
1735  // Secondly we get the bins corresponding to y+radius and y-radius
1736  // only if the second dimension is active
1737  if (vector_of_active_dim[1])
1738  {
1739  // For i equal to radius or -radius (i corresponds to y)
1740  for (int i = -vector_of_radiuses[1]; i <= vector_of_radiuses[1];
1741  i += 2 * vector_of_radiuses[1])
1742  {
1743  int local_tempi = vector_of_positions[1] + i;
1744  if (local_tempi >= 0 && local_tempi < vector_of_dimensions[1])
1745  {
1746  // We loop over all the surface
1747  for (int j = -vector_of_radiuses[0] + 1;
1748  j <= vector_of_radiuses[0] - 1;
1749  j++)
1750  {
1751  int local_tempj = vector_of_positions[0] + j;
1752  if (local_tempj >= 0 && local_tempj < vector_of_dimensions[0])
1753  {
1754  for (int k = -vector_of_radiuses[2];
1755  k <= vector_of_radiuses[2];
1756  k++)
1757  {
1758  int local_tempk = vector_of_positions[2] + k;
1759  if (local_tempk >= 0 &&
1760  local_tempk < vector_of_dimensions[2])
1761  {
1762  neighbouring_bin_index.push_back(
1763  local_tempj * vector_of_coef[0] +
1764  local_tempi * vector_of_coef[1] +
1765  local_tempk * vector_of_coef[2]);
1766  }
1767  }
1768  }
1769  }
1770  }
1771  }
1772  }
1773  // Thirdly we get the bins corresponding to z+radius and z-radius
1774  // if the third dimension is active.
1775  if (vector_of_active_dim[2])
1776  {
1777  // for k equal to radius or -radius (k corresponds to z)
1778  for (int k = -vector_of_radiuses[2]; k <= vector_of_radiuses[2];
1779  k += 2 * vector_of_radiuses[2])
1780  {
1781  int local_tempk = vector_of_positions[2] + k;
1782  if (local_tempk >= 0 && local_tempk < vector_of_dimensions[2])
1783  {
1784  // We loop over all the surface
1785  for (int j = -vector_of_radiuses[0] + 1;
1786  j <= vector_of_radiuses[0] - 1;
1787  j++)
1788  {
1789  int local_tempj = vector_of_positions[0] + j;
1790  if (local_tempj >= 0 && local_tempj < vector_of_dimensions[0])
1791  {
1792  for (int i = -vector_of_radiuses[1] + 1;
1793  i <= vector_of_radiuses[1] - 1;
1794  i++)
1795  {
1796  int local_tempi = vector_of_positions[1] + i;
1797  if (local_tempi >= 0 &&
1798  local_tempi < vector_of_dimensions[1])
1799  {
1800  neighbouring_bin_index.push_back(
1801  local_tempj * vector_of_coef[0] +
1802  local_tempi * vector_of_coef[1] +
1803  local_tempk * vector_of_coef[2]);
1804  }
1805  }
1806  }
1807  }
1808  }
1809  }
1810  }
1811  }
1812  } // end new version
1813  }
1814 
1815 
1816  //==============================================================================
1817  /// Compute total number of sample points recursively
1818  //==============================================================================
1821  {
1822  unsigned count = 0;
1823  unsigned n_bin = nbin();
1824  for (unsigned i = 0; i < n_bin; i++)
1825  {
1826  if (Bin_pt[i] != 0)
1827  {
1828  count +=
1829  Bin_pt[i]->total_number_of_sample_points_computed_recursively();
1830  }
1831  }
1832  return count;
1833  }
1834 
1835 
1836  //============================================================
1837  /// Get (linearly enumerated) bin index of bin that
1838  /// contains specified zeta
1839  //============================================================
1840  unsigned BinArray::coords_to_bin_index(const Vector<double>& zeta)
1841  {
1842  unsigned coef = 1;
1843  unsigned n_bin = 0;
1844  const unsigned dim = ndim_zeta();
1845 
1846  // Loop over all the dimensions
1847  for (unsigned u = 0; u < dim; u++)
1848  {
1849  // for each one get the correct bin "coordinate"
1850  unsigned local_bin_number = 0;
1851 
1852  if (zeta[u] < Min_and_max_coordinates[u].first)
1853  {
1854  local_bin_number = 0;
1855  }
1856  else if (zeta[u] > Min_and_max_coordinates[u].second)
1857  {
1858  local_bin_number = dimensions_of_bin_array(u) - 1;
1859  }
1860  else
1861  {
1862  local_bin_number = (int(std::min(
1863  dimensions_of_bin_array(u) - 1,
1864  unsigned(floor(double(zeta[u] - Min_and_max_coordinates[u].first) /
1865  double(Min_and_max_coordinates[u].second -
1866  Min_and_max_coordinates[u].first) *
1867  double(dimensions_of_bin_array(u)))))));
1868  }
1869 
1870  /// Update the coef and the bin index
1871  n_bin += local_bin_number * coef;
1872  coef *= dimensions_of_bin_array(u);
1873  }
1874 
1875  // return the correct bin index
1876  return (n_bin);
1877  }
1878 
1879  //==========================================================================
1880  /// Fill the bin array with sample points from FiniteElements stored in mesh
1881  //==========================================================================
1883  {
1884  // Fill 'em in:
1885  unsigned nel = Mesh_pt->nelement();
1886  for (unsigned e = 0; e < nel; e++)
1887  {
1888  FiniteElement* el_pt = Mesh_pt->finite_element_pt(e);
1889 
1890  // Total number of sample point we will create
1891  unsigned nplot =
1892  el_pt->nplot_points(Nsample_points_generated_per_element);
1893 
1894  /// For all the sample points we have to create ...
1895  for (unsigned j = 0; j < nplot; j++)
1896  {
1897  // ... create it: Pass element index in mesh (vector
1898  // of elements and index of sample point within element
1899  SamplePoint* new_sample_point_pt = new SamplePoint(e, j);
1900 
1901  // Coordinates of this point
1902  Vector<double> zeta(ndim_zeta());
1903  Vector<double> s(ndim_zeta());
1904  bool use_equally_spaced_interior_sample_points =
1906  el_pt->get_s_plot(j,
1908  s,
1909  use_equally_spaced_interior_sample_points);
1911  {
1912  el_pt->interpolated_x(s, zeta);
1913  }
1914  else
1915  {
1916  el_pt->interpolated_zeta(s, zeta);
1917  }
1918 
1919 #ifdef PARANOID
1920 
1921  // Check if point is inside
1922  bool is_inside = true;
1923  std::ostringstream error_message;
1924  unsigned dim = ndim_zeta();
1925  for (unsigned i = 0; i < dim; i++)
1926  {
1927  if ((zeta[i] < Min_and_max_coordinates[i].first) ||
1928  (zeta[i] > Min_and_max_coordinates[i].second))
1929  {
1930  is_inside = false;
1931  error_message << "Sample point at zeta[" << i << "] = " << zeta[i]
1932  << " is outside limits of bin array: "
1933  << Min_and_max_coordinates[i].first << " and "
1934  << Min_and_max_coordinates[i].second << std::endl;
1935  }
1936  }
1937 
1938  if (!is_inside)
1939  {
1940  error_message << "Please correct the limits passed to the "
1941  << "constructor." << std::endl;
1942  throw OomphLibError(error_message.str(),
1943  OOMPH_CURRENT_FUNCTION,
1944  OOMPH_EXCEPTION_LOCATION);
1945  }
1946 
1947 #endif
1948 
1949 
1950  // Finding the correct bin to put the sample point
1951  unsigned bin_index = coords_to_bin_index(zeta);
1952 
1953  // if the bin is not yet created, create it
1954  if (Bin_pt[bin_index] == 0)
1955  {
1956  Bin_pt[bin_index] = new RefineableBin(this, bin_index);
1957  }
1958 
1959  // ... and then fill the bin with this new sample point
1960  Bin_pt[bin_index]->add_sample_point(new_sample_point_pt, zeta);
1961  }
1962  }
1963  }
1964 
1965 
1966  //==================================================================
1967  /// Get "coordinates" of bin that contains specified zeta
1968  //==================================================================
1969  void BinArray::coords_to_vectorial_bin_index(const Vector<double>& zeta,
1970  Vector<unsigned>& bin_index)
1971  {
1972  unsigned dim = ndim_zeta();
1973  bin_index.resize(dim);
1974  for (unsigned u = 0; u < dim; u++)
1975  {
1976  if (zeta[u] < Min_and_max_coordinates[u].first)
1977  {
1978  bin_index[u] = 0;
1979  }
1980  else if (zeta[u] > Min_and_max_coordinates[u].second)
1981  {
1982  bin_index[u] = dimensions_of_bin_array(u) - 1;
1983  }
1984  else
1985  {
1986  bin_index[u] = (int(
1987  std::min(dimensions_of_bin_array(u) - 1,
1988  unsigned(floor((zeta[u] - Min_and_max_coordinates[u].first) /
1989  double(Min_and_max_coordinates[u].second -
1990  Min_and_max_coordinates[u].first) *
1991  double(dimensions_of_bin_array(u)))))));
1992  }
1993  }
1994  }
1995 
1996 
1997  //==============================================================================
1998  /// Find sub-GeomObject (finite element) and the local coordinate
1999  /// s within it that contains point with global coordinate zeta.
2000  /// sub_geom_object_pt=0 if point can't be found.
2001  //==============================================================================
2002  void RefineableBinArray::locate_zeta(const Vector<double>& zeta,
2003  GeomObject*& sub_geom_object_pt,
2004  Vector<double>& s)
2005  {
2006  // Default: we've failed miserably
2007  sub_geom_object_pt = 0;
2008 
2009  unsigned dim = ndim_zeta();
2010 
2011  // Top level book keeping and sanity checking
2012  if (Depth == 0)
2013  {
2014  // Reset counter for number of sample points visited.
2015  // If we can't find the point we should at least make sure that
2016  // we've visited all the sample points before giving up.
2018  0;
2019 
2020  // Does the zeta coordinate lie within the current (top level!) bin
2021  // structure? Skip this test if we want to always fail because that's
2022  // usually done to trace out the spiral path
2024  {
2025  // Loop over the lagrangian dimension
2026  for (unsigned i = 0; i < dim; i++)
2027  {
2028  // If the i-th coordinate is less than the minimum
2029  if (zeta[i] < Min_and_max_coordinates[i].first)
2030  {
2031  return;
2032  }
2033  // Otherwise coordinate may be bigger than the maximum
2034  else if (zeta[i] > Min_and_max_coordinates[i].second)
2035  {
2036  return;
2037  }
2038  }
2039  }
2040  }
2041 
2042  // Finding the bin in which the point is located
2043  int bin_index = coords_to_bin_index(zeta);
2044 
2045 #ifdef PARANOID
2046  if (bin_index < 0)
2047  {
2048  throw OomphLibError("Negative bin index...",
2049  OOMPH_CURRENT_FUNCTION,
2050  OOMPH_EXCEPTION_LOCATION);
2051  }
2052 #endif
2053 
2054  // Start at this radius (radius = 0 is the central bin)
2055  unsigned radius = 0;
2056 
2057  // "coordinates" of the bin which is most likely to contain the
2058  // point
2059  Vector<unsigned> bin_index_v(dim);
2060  coords_to_vectorial_bin_index(zeta, bin_index_v);
2061 
2062  // We loop over all the dimensions to find the maximum radius we have to
2063  // do the spiraling if we want to be sure there is no bin left at the end
2064  unsigned max_radius = 0;
2065  for (unsigned k = 0; k < dim; k++)
2066  {
2067  unsigned local =
2068  std::max((bin_index_v[k] + 1),
2069  (Dimensions_of_bin_array[k] - bin_index_v[k] - 1));
2070  if (local > max_radius)
2071  {
2072  max_radius = local;
2073  }
2074  }
2075 
2076  // Vector which will store the indices of the neighbouring bins
2077  // at the current radius
2078  Vector<unsigned> bin_index_at_current_radius;
2079  while (radius <= max_radius)
2080  {
2081  // Get the neighbouring bins
2082  bin_index_at_current_radius.clear();
2084  bin_index, radius, bin_index_at_current_radius);
2085  // How many are there
2086  unsigned nbin_at_current_radius = bin_index_at_current_radius.size();
2087  unsigned n_bin = nbin();
2088 
2089  // Keep looping over entries (stop if we found geom object)
2090  unsigned k = 0;
2091  while ((k < nbin_at_current_radius) && (sub_geom_object_pt == 0))
2092  {
2093  int neigh_bin_index = bin_index_at_current_radius[k];
2094 #ifdef PARANOID
2095  if (neigh_bin_index < 0)
2096  {
2097  throw OomphLibError("Negative neighbour bin index...",
2098  OOMPH_CURRENT_FUNCTION,
2099  OOMPH_EXCEPTION_LOCATION);
2100  }
2101 #endif
2102  if (neigh_bin_index < int(n_bin))
2103  {
2104  // If the bin exists
2105  if (Bin_pt[neigh_bin_index] != 0)
2106  {
2107  // We call the correct method to locate_zeta in the bin
2108  Bin_pt[neigh_bin_index]->locate_zeta(zeta, sub_geom_object_pt, s);
2109  }
2110  }
2111  k++;
2112  }
2113 
2114  // Reached end of loop over bins at this radius (or found the point)
2115  // Which one?
2116  if (sub_geom_object_pt != 0)
2117  {
2118  return;
2119  }
2120  // Increment radius
2121  else
2122  {
2123  radius++;
2124  }
2125  }
2126 
2127 
2128 #ifdef PARANOID
2129 
2130  // If we still haven't found the point, check that we've at least visited
2131  // all the sample points
2132  if (Depth == 0)
2133  {
2134  if (
2137  {
2138  if (max_search_radius() == DBL_MAX)
2139  {
2140  std::ostringstream error_message;
2141  error_message
2142  << "Zeta not found after visiting "
2144  << " sample points out of "
2146  << "Where are the missing sample points???\n";
2147  throw OomphLibError(error_message.str(),
2148  OOMPH_CURRENT_FUNCTION,
2149  OOMPH_EXCEPTION_LOCATION);
2150  }
2151  }
2152  }
2153 
2154 #endif
2155  }
2156 
2157  /// Default number of bins (in each coordinate direction)
2159 
2160 
2161  /// /////////////////////////////////////////////////////////////////////////////
2162  /// /////////////////////////////////////////////////////////////////////////////
2163  /// /////////////////////////////////////////////////////////////////////////////
2164 
2165 
2166  //======================================================================
2167  /// Constructor
2168  //======================================================================
2170  SamplePointContainerParameters* sample_point_container_parameters_pt)
2172  sample_point_container_parameters_pt->mesh_pt(),
2173  sample_point_container_parameters_pt->min_and_max_coordinates(),
2174  sample_point_container_parameters_pt
2175  ->use_eulerian_coordinates_during_setup(),
2176  sample_point_container_parameters_pt
2177  ->ignore_halo_elements_during_locate_zeta_search(),
2178  sample_point_container_parameters_pt
2179  ->nsample_points_generated_per_element()),
2180  BinArray(
2181  sample_point_container_parameters_pt->mesh_pt(),
2182  sample_point_container_parameters_pt->min_and_max_coordinates(),
2183  dynamic_cast<BinArrayParameters*>(sample_point_container_parameters_pt)
2184  ->dimensions_of_bin_array(),
2185  sample_point_container_parameters_pt
2186  ->use_eulerian_coordinates_during_setup(),
2187  sample_point_container_parameters_pt
2188  ->ignore_halo_elements_during_locate_zeta_search(),
2189  sample_point_container_parameters_pt
2190  ->nsample_points_generated_per_element())
2191  {
2192  // Set default size of bin array (and spatial dimension!)
2193  if (Dimensions_of_bin_array.size() == 0)
2194  {
2195  int dim = 0;
2196  if (Mesh_pt->nelement() != 0)
2197  {
2198  dim = Mesh_pt->finite_element_pt(0)->dim();
2199  }
2200 
2201 
2202  // Need to do an Allreduce to ensure that the dimension is consistent
2203  // even when no elements are assigned to a certain processor
2204 #ifdef OOMPH_HAS_MPI
2205  // Only a problem if the mesh has been distributed
2206  if (Mesh_pt->is_mesh_distributed())
2207  {
2208  // Need a non-null communicator
2209  if (Mesh_pt->communicator_pt() != 0)
2210  {
2211  int n_proc = Mesh_pt->communicator_pt()->nproc();
2212  if (n_proc > 1)
2213  {
2214  int dim_reduce;
2215  MPI_Allreduce(&dim,
2216  &dim_reduce,
2217  1,
2218  MPI_INT,
2219  MPI_MAX,
2220  Mesh_pt->communicator_pt()->mpi_comm());
2221  dim = dim_reduce;
2222  }
2223  }
2224  }
2225 #endif
2226 
2228  }
2229 
2230  // Have we specified max/min coordinates?
2231  // If not, compute them on the fly from mesh
2232  if (Min_and_max_coordinates.size() == 0)
2233  {
2235  }
2236 
2237  // Spiraling parameters
2238  Max_spiral_level = UINT_MAX;
2240 
2241  NonRefineableBinArrayParameters* non_ref_bin_array_parameters_pt =
2242  dynamic_cast<NonRefineableBinArrayParameters*>(
2243  sample_point_container_parameters_pt);
2244 
2245 #ifdef PARANOID
2246  if (non_ref_bin_array_parameters_pt == 0)
2247  {
2248  throw OomphLibError("Wrong sample_point_container_parameters_pt",
2249  OOMPH_CURRENT_FUNCTION,
2250  OOMPH_EXCEPTION_LOCATION);
2251  }
2252 #endif
2253 
2254  Nspiral_chunk = non_ref_bin_array_parameters_pt->nspiral_chunk();
2256 
2257  // Time it
2258  double t_start = 0.0;
2260  {
2261  t_start = TimingHelpers::timer();
2262  }
2263 
2264  // Now fill the bastard...
2265  fill_bin_array();
2266 
2268  {
2269  double t_end = TimingHelpers::timer();
2271  oomph_info << "Time for setup of " << Dimensions_of_bin_array.size()
2272  << "-dimensional sample point container containing " << npts
2273  << " sample points: " << t_end - t_start
2274  << " sec (non-ref_bin); third party: 0 sec ( = 0 %)"
2275  << std::endl;
2276  }
2277  }
2278 
2279 
2280  //==============================================================================
2281  /// Compute total number of sample points recursively
2282  //==============================================================================
2285  {
2286  // Get pointer to map-based representation
2287  const std::map<unsigned, Vector<std::pair<FiniteElement*, Vector<double>>>>*
2288  map_pt = Bin_object_coord_pairs.map_pt();
2289 
2290  // Initialise
2291  unsigned count = 0;
2292 
2293  // loop...
2294  typedef std::map<
2295  unsigned,
2296  Vector<std::pair<FiniteElement*, Vector<double>>>>::const_iterator IT;
2297  for (IT it = map_pt->begin(); it != map_pt->end(); it++)
2298  {
2299  count += (*it).second.size();
2300  }
2301  return count;
2302  }
2303 
2304 
2305  //========================================================================
2306  /// Output bins
2307  //========================================================================
2308  void NonRefineableBinArray::output_bins(std::ofstream& outfile)
2309  {
2310  // Spatial dimension of bin
2311  const unsigned n_lagrangian = this->ndim_zeta();
2312 
2313  unsigned nbin_x = Dimensions_of_bin_array[0];
2314  unsigned nbin_y = 1;
2315  if (n_lagrangian > 1) nbin_y = Dimensions_of_bin_array[1];
2316  unsigned nbin_z = 1;
2317  if (n_lagrangian > 2) nbin_z = Dimensions_of_bin_array[2];
2318 
2319  unsigned b = 0;
2320  for (unsigned iz = 0; iz < nbin_z; iz++)
2321  {
2322  for (unsigned iy = 0; iy < nbin_y; iy++)
2323  {
2324  for (unsigned ix = 0; ix < nbin_x; ix++)
2325  {
2326  unsigned nentry = Bin_object_coord_pairs[b].size();
2327  for (unsigned e = 0; e < nentry; e++)
2328  {
2329  FiniteElement* el_pt = Bin_object_coord_pairs[b][e].first;
2330  Vector<double> s(Bin_object_coord_pairs[b][e].second);
2331  Vector<double> zeta(n_lagrangian);
2333  {
2334  el_pt->interpolated_x(s, zeta);
2335  }
2336  else
2337  {
2338  el_pt->interpolated_zeta(s, zeta);
2339  }
2340  for (unsigned i = 0; i < n_lagrangian; i++)
2341  {
2342  outfile << zeta[i] << " ";
2343  }
2344  outfile << ix << " " << iy << " " << iz << " " << b << " "
2345  << std::endl;
2346  }
2347  b++;
2348  }
2349  }
2350  }
2351  }
2352 
2353 
2354  //========================================================================
2355  /// Output bin vertices (allowing display of bins as zones).
2356  //========================================================================
2357  void NonRefineableBinArray::output_bin_vertices(std::ofstream& outfile)
2358  {
2359  // Store the lagrangian dimension
2360  const unsigned n_lagrangian = this->ndim_zeta();
2361 
2362  unsigned nbin = Dimensions_of_bin_array[0];
2363  if (n_lagrangian > 1) nbin *= Dimensions_of_bin_array[1];
2364  if (n_lagrangian > 2) nbin *= Dimensions_of_bin_array[2];
2365 
2366  for (unsigned i_bin = 0; i_bin < nbin; i_bin++)
2367  {
2368  // Get bin vertices
2369  Vector<Vector<double>> bin_vertex;
2370  get_bin_vertices(i_bin, bin_vertex);
2371  switch (n_lagrangian)
2372  {
2373  case 1:
2374  outfile << "ZONE I=2\n";
2375  break;
2376 
2377  case 2:
2378  outfile << "ZONE I=2, J=2\n";
2379  break;
2380 
2381  case 3:
2382  outfile << "ZONE I=2, J=2, K=2\n";
2383  break;
2384  }
2385 
2386  unsigned nvertex = bin_vertex.size();
2387  for (unsigned i = 0; i < nvertex; i++)
2388  {
2389  for (unsigned j = 0; j < n_lagrangian; j++)
2390  {
2391  outfile << bin_vertex[i][j] << " ";
2392  }
2393  outfile << std::endl;
2394  }
2395  }
2396  }
2397 
2398 
2399  //========================================================================
2400  /// Fill the bin array with sample points from FiniteElements stored in mesh
2401  //========================================================================
2403  {
2404  // Store the lagrangian dimension
2405  const unsigned n_lagrangian = this->ndim_zeta();
2406 
2407  // Flush all objects out of the bin structure
2409 
2410  // Temporary storage in bin
2411  std::map<unsigned, Vector<std::pair<FiniteElement*, Vector<double>>>>
2412  tmp_bin_object_coord_pairs;
2413 
2414  // Total number of bins
2415  unsigned ntotalbin = nbin();
2416 
2417  // Initialise the structure that keep tracks of the occupided bins
2418  Bin_object_coord_pairs.initialise(ntotalbin);
2419 
2420 
2421  // Issue warning about small number of bins
2423  {
2424  // Calculate the (nearest integer) number of elements per bin
2425  unsigned n_mesh_element = Mesh_pt->nelement();
2426  unsigned elements_per_bin = n_mesh_element / ntotalbin;
2427  // If it is above the threshold then issue a warning
2428  if (elements_per_bin > Threshold_for_elements_per_bin_warning)
2429  {
2431  {
2433  std::ostringstream warn_message;
2434  warn_message
2435  << "The average (integer) number of elements per bin is \n\n"
2436  << elements_per_bin << ", which is more than \n\n"
2437  << " "
2438  "NonRefineableBinArray::Threshold_for_elements_per_bin_warning="
2440  << "\n\nIf the lookup seems slow (and you have the memory),"
2441  << "consider increasing\n"
2442  << "BinArray::Dimensions_of_bin_array from their current\n"
2443  << "values of { ";
2444  unsigned nn = Dimensions_of_bin_array.size();
2445  for (unsigned ii = 0; ii < nn; ii++)
2446  {
2447  warn_message << Dimensions_of_bin_array[ii] << " ";
2448  }
2449  warn_message
2450  << " }.\n"
2451  << "\nNOTE: You can suppress this warning by increasing\n\n"
2452  << " NonRefineableBinArray::"
2453  << "Threshold_for_elements_per_bin_warning\n\n"
2454  << "or by setting \n\n "
2455  << "NonRefineableBinArray::Suppress_warning_about_small_number_of_"
2456  "bins\n\n"
2457  << "to true (both are public static data).\n\n";
2458  OomphLibWarning(warn_message.str(),
2459  OOMPH_CURRENT_FUNCTION,
2460  OOMPH_EXCEPTION_LOCATION);
2461  }
2462  }
2463  }
2464 
2465 
2466  // Increase overall counter
2467  Total_nbin_cells_counter += ntotalbin;
2468 
2469 
2470  // Issue warning?
2472  {
2475  {
2477  {
2479  std::ostringstream warn_message;
2480  warn_message
2481  << "Have allocated \n\n"
2482  << " NonRefineableBinArray::Total_nbin_cells_counter="
2484  << "\n\nbin cells, which is more than \n\n"
2485  << " NonRefineableBinArray::"
2486  << "Threshold_for_total_bin_cell_number_warning="
2487  << NonRefineableBinArray::
2488  Threshold_for_total_bin_cell_number_warning
2489  << "\n\nIf you run out of memory, consider reducing\n"
2490  << "BinArray::Dimensions_of_bin_array from their current\n"
2491  << "values of { ";
2492  unsigned nn = Dimensions_of_bin_array.size();
2493  for (unsigned ii = 0; ii < nn; ii++)
2494  {
2495  warn_message << Dimensions_of_bin_array[ii] << " ";
2496  }
2497  warn_message
2498  << " }.\n"
2499  << "\nNOTE: You can suppress this warning by increasing\n\n"
2500  << " NonRefineableBinArray::"
2501  << "Threshold_for_total_bin_cell_number_warning\n\n"
2502  << "or by setting \n\n NonRefineableBinArray::"
2503  << "Suppress_warning_about_large_total_number_of_bins\n\n"
2504  << "to true (both are public static data).\n\n"
2505  << "NOTE: I'll only issue this warning once -- total number of\n"
2506  << "bins may grow yet further!\n";
2507  OomphLibWarning(warn_message.str(),
2508  OOMPH_CURRENT_FUNCTION,
2509  OOMPH_EXCEPTION_LOCATION);
2510  }
2511  }
2512  }
2513 
2514  /// Loop over subobjects (elements) to decide which bin they belong in...
2515  unsigned n_sub = Mesh_pt->nelement();
2516  for (unsigned e = 0; e < n_sub; e++)
2517  {
2518  // Cast to the element (sub-object) first
2519  FiniteElement* el_pt =
2520  dynamic_cast<FiniteElement*>(Mesh_pt->finite_element_pt(e));
2521 
2522  // Get specified number of points within the element
2523  unsigned n_plot_points =
2524  el_pt->nplot_points(Nsample_points_generated_per_element);
2525 
2526  for (unsigned iplot = 0; iplot < n_plot_points; iplot++)
2527  {
2528  // Storage for local and global coordinates
2529  Vector<double> local_coord(n_lagrangian, 0.0);
2530  Vector<double> global_coord(n_lagrangian, 0.0);
2531 
2532  // Get local coordinate and interpolate to global
2533  bool use_equally_spaced_interior_sample_points =
2535  el_pt->get_s_plot(iplot,
2537  local_coord,
2538  use_equally_spaced_interior_sample_points);
2539 
2540  // Now get appropriate global coordinate
2542  {
2543  el_pt->interpolated_x(local_coord, global_coord);
2544  }
2545  else
2546  {
2547  el_pt->interpolated_zeta(local_coord, global_coord);
2548  }
2549 
2550  // Which bin are the global coordinates in?
2551  unsigned bin_number = 0;
2552  unsigned multiplier = 1;
2553  // Loop over the dimension
2554  for (unsigned i = 0; i < n_lagrangian; i++)
2555  {
2556 #ifdef PARANOID
2557  if ((global_coord[i] < Min_and_max_coordinates[i].first) ||
2558  (global_coord[i] > Min_and_max_coordinates[i].second))
2559  {
2560  std::ostringstream error_message;
2561  error_message
2562  << "Bin sample point " << iplot << " in element " << e << "\n"
2563  << "is outside bin limits in coordinate direction " << i << ":\n"
2564  << "Sample point coordinate: " << global_coord[i] << "\n"
2565  << "Max bin coordinate : "
2566  << Min_and_max_coordinates[i].second << "\n"
2567  << "Min bin coordinate : " << Min_and_max_coordinates[i].first
2568  << "\n"
2569  << "You should either setup the bin boundaries manually\n"
2570  << "or increase the percentage offset by which the\n"
2571  << "automatically computed bin limits are increased \n"
2572  << "beyond their sampled max/mins. This is defined in\n"
2573  << "the (public) namespace member\n\n"
2574  << "SamplePointContainer::Percentage_offset \n\n which \n"
2575  << "currently has the value: "
2577  throw OomphLibError(error_message.str(),
2578  OOMPH_CURRENT_FUNCTION,
2579  OOMPH_EXCEPTION_LOCATION);
2580  }
2581 
2582 #endif
2583  unsigned bin_number_i =
2584  int(Dimensions_of_bin_array[i] *
2585  ((global_coord[i] - Min_and_max_coordinates[i].first) /
2586  (Min_and_max_coordinates[i].second -
2587  Min_and_max_coordinates[i].first)));
2588 
2589  // Buffer the case when the global coordinate is the maximum
2590  // value
2591  if (bin_number_i == Dimensions_of_bin_array[i])
2592  {
2593  bin_number_i -= 1;
2594  }
2595 
2596  // Add to the bin number
2597  bin_number += multiplier * bin_number_i;
2598 
2599  // Sort out the multiplier
2600  multiplier *= Dimensions_of_bin_array[i];
2601  }
2602 
2603  // Add element-sample local coord pair to the calculated bin
2604  tmp_bin_object_coord_pairs[bin_number].push_back(
2605  std::make_pair(el_pt, local_coord));
2606  }
2607  }
2608 
2609  // Finally copy filled vectors across -- wiping memory from temporary
2610  // map as we go along is good and wouldn't be possible if we
2611  // filled the SparseVector's internal map within that class.
2612  typedef std::map<
2613  unsigned,
2614  Vector<std::pair<FiniteElement*, Vector<double>>>>::iterator IT;
2615  for (IT it = tmp_bin_object_coord_pairs.begin();
2616  it != tmp_bin_object_coord_pairs.end();
2617  it++)
2618  {
2619  Bin_object_coord_pairs.set_value((*it).first, (*it).second);
2620  // Make space immediately
2621  (*it).second.clear();
2622  }
2623  }
2624 
2625 
2626  //========================================================================
2627  /// Provide some stats on the fill level of the associated bin
2628  //========================================================================
2630  unsigned& max_n_entry,
2631  unsigned& min_n_entry,
2632  unsigned& tot_n_entry,
2633  unsigned& n_empty) const
2634  {
2635  // Total number of bins
2636  n_bin = nbin();
2637  n_empty = n_bin - Bin_object_coord_pairs.nnz();
2638 
2639  // Get pointer to map-based representation
2640  const std::map<unsigned, Vector<std::pair<FiniteElement*, Vector<double>>>>*
2641  map_pt = Bin_object_coord_pairs.map_pt();
2642 
2643  // Initialise
2644  max_n_entry = 0;
2645  min_n_entry = UINT_MAX;
2646  tot_n_entry = 0;
2647 
2648  // Do stats
2649  typedef std::map<
2650  unsigned,
2651  Vector<std::pair<FiniteElement*, Vector<double>>>>::const_iterator IT;
2652  for (IT it = map_pt->begin(); it != map_pt->end(); it++)
2653  {
2654  unsigned nentry = (*it).second.size();
2655  if (nentry > max_n_entry) max_n_entry = nentry;
2656  if (nentry < min_n_entry) min_n_entry = nentry;
2657  tot_n_entry += nentry;
2658  }
2659  }
2660 
2661 
2662  //========================================================================
2663  /// Fill bin by diffusion, populating each empty bin with the same content
2664  /// as the first non-empty bin found during a spiral-based search
2665  /// up to the specified "radius" (default 1)
2666  //========================================================================
2668  const unsigned& bin_diffusion_radius)
2669  {
2670  // oomph_info << "PROFILING GET_NEIGHBOURING_BINS_HELPER():" << std::endl;
2671  // profile_get_neighbouring_bins_helper();
2672 
2673  // Loop over all bins to check if they're empty
2674  std::list<unsigned> empty_bins;
2675  unsigned n_bin = nbin();
2676  std::vector<bool> was_empty_until_current_iteration(n_bin, false);
2677  for (unsigned i = 0; i < n_bin; i++)
2678  {
2679  if (Bin_object_coord_pairs[i].size() == 0)
2680  {
2681  empty_bins.push_front(i);
2682  was_empty_until_current_iteration[i] = true;
2683  }
2684  }
2685 
2686  // Now keep processing the empty bins until there are none left
2687  unsigned iter = 0;
2688  Vector<unsigned> newly_filled_bin;
2689  while (empty_bins.size() != 0)
2690  {
2691  newly_filled_bin.clear();
2692  newly_filled_bin.reserve(empty_bins.size());
2693  for (std::list<unsigned>::iterator it = empty_bins.begin();
2694  it != empty_bins.end();
2695  it++)
2696  {
2697  unsigned bin = (*it);
2698 
2699  // Look for immediate neighbours within the specified "bin radius"
2700  unsigned level = bin_diffusion_radius;
2701  Vector<unsigned> neighbour_bin;
2702  get_neighbouring_bins_helper(bin, level, neighbour_bin);
2703  unsigned n_neigh = neighbour_bin.size();
2704 
2705  // Find closest pair
2706  double min_dist = DBL_MAX;
2707  std::pair<FiniteElement*, Vector<double>> closest_pair;
2708  for (unsigned i = 0; i < n_neigh; i++)
2709  {
2710  unsigned neigh_bin = neighbour_bin[i];
2711 
2712  // Only allow to re-populate from bins that were already filled at
2713  // previous iteration, otherwise things can progate too fast
2714  if (!was_empty_until_current_iteration[neigh_bin])
2715  {
2716  unsigned nbin_content = Bin_object_coord_pairs[neigh_bin].size();
2717  for (unsigned j = 0; j < nbin_content; j++)
2718  {
2719  FiniteElement* el_pt = Bin_object_coord_pairs[neigh_bin][j].first;
2720  Vector<double> s(Bin_object_coord_pairs[neigh_bin][j].second);
2721  Vector<double> x(2);
2722  el_pt->interpolated_x(s, x);
2723  // Get minimum distance of sample point from any of the vertices
2724  // of current bin
2725  // hierher Louis questions if this is the right thing to do!
2726  // Matthias agrees
2727  // with him but hasn't done anything yet...
2728  // should use the distance to the centre of gravity of
2729  // the empty bin instead!
2730  double dist = min_distance(bin, x);
2731  if (dist < min_dist)
2732  {
2733  min_dist = dist;
2734  closest_pair = Bin_object_coord_pairs[neigh_bin][j];
2735  }
2736  }
2737  }
2738  }
2739 
2740  // Have we filled the bin?
2741  if (min_dist != DBL_MAX)
2742  {
2743  Vector<std::pair<FiniteElement*, Vector<double>>> new_entry;
2744  new_entry.push_back(closest_pair);
2745  Bin_object_coord_pairs.set_value(bin, new_entry);
2746 
2747  // Record that we've filled it.
2748  newly_filled_bin.push_back(bin);
2749 
2750  // Wipe entry without breaking the linked list (Andrew's trick --
2751  // nice!)
2752  std::list<unsigned>::iterator it_to_be_deleted = it;
2753  it--;
2754  empty_bins.erase(it_to_be_deleted);
2755  }
2756  }
2757 
2758  // Get ready for next iteration on remaining empty bins
2759  iter++;
2760  // Now update the vector that records which bins were empty up to now
2761  unsigned n = newly_filled_bin.size();
2762  for (unsigned i = 0; i < n; i++)
2763  {
2764  was_empty_until_current_iteration[newly_filled_bin[i]] = false;
2765  }
2766  }
2767 
2768 
2769 #ifdef PARANOID
2770  // Loop over all bins to check if they're empty
2771  n_bin = nbin();
2772  for (unsigned i = 0; i < n_bin; i++)
2773  {
2774  if (Bin_object_coord_pairs[i].size() == 0)
2775  {
2776  std::ostringstream error_message_stream;
2777  error_message_stream << "Bin " << i << " is still empty\n"
2778  << "after trying to fill it by diffusion\n";
2779  throw OomphLibError(error_message_stream.str(),
2780  OOMPH_CURRENT_FUNCTION,
2781  OOMPH_EXCEPTION_LOCATION);
2782  }
2783  }
2784 
2785 #endif
2786  }
2787 
2788 
2789  //=================================================================
2790  /// Get the number of the bin containing the specified coordinate.
2791  /// Bin number is negative if the coordinate is outside
2792  /// the bin structure.
2793  //=================================================================
2794  void NonRefineableBinArray::get_bin(const Vector<double>& zeta,
2795  int& bin_number)
2796  {
2797  // Default for point not found
2798  bin_number = -1;
2799 
2800  // Get the lagrangian dimension
2801  const unsigned n_lagrangian = this->ndim_zeta();
2802 
2803  // Does the zeta coordinate lie within the current bin structure?
2804 
2805  // Loop over the lagrangian dimension
2806  for (unsigned i = 0; i < n_lagrangian; i++)
2807  {
2808  // If the i-th coordinate is less than the minimum
2809  if (zeta[i] < Min_and_max_coordinates[i].first)
2810  {
2811  return;
2812  }
2813  // Otherwise coordinate may be bigger than the maximum
2814  else if (zeta[i] > Min_and_max_coordinates[i].second)
2815  {
2816  return;
2817  }
2818  }
2819 
2820  // Use the min and max coords of the bin structure, to find
2821  // the bin structure containing the current zeta cooordinate
2822 
2823  // Initialise for subsequent computation
2824  bin_number = 0;
2825 
2826  // Offset for rows/matrices in higher dimensions
2827  unsigned multiplier = 1;
2828 
2829  // Loop over the dimension
2830  for (unsigned i = 0; i < n_lagrangian; i++)
2831  {
2832  // Find the bin number of the current coordinate
2833  unsigned bin_number_i =
2834  int(Dimensions_of_bin_array[i] *
2835  ((zeta[i] - Min_and_max_coordinates[i].first) /
2836  (Min_and_max_coordinates[i].second -
2837  Min_and_max_coordinates[i].first)));
2838  // Buffer the case when we are exactly on the edge
2839  if (bin_number_i == Dimensions_of_bin_array[i])
2840  {
2841  bin_number_i -= 1;
2842  }
2843  // Now add to the bin number using the multiplier
2844  bin_number += multiplier * bin_number_i;
2845  // Increase the current row/matrix multiplier for the next loop
2846  multiplier *= Dimensions_of_bin_array[i];
2847  }
2848 
2849 
2850 #ifdef PARANOID
2851 
2852  // Tolerance for "out of bin" test
2853  double tol = 1.0e-10;
2854 
2855  unsigned nvertex = (int)pow(2, n_lagrangian);
2856  Vector<Vector<double>> bin_vertex(nvertex);
2857  for (unsigned j = 0; j < nvertex; j++)
2858  {
2859  bin_vertex[j].resize(n_lagrangian);
2860  }
2861  get_bin_vertices(bin_number, bin_vertex);
2862  for (unsigned i = 0; i < n_lagrangian; i++)
2863  {
2864  double min_vertex_coord = DBL_MAX;
2865  double max_vertex_coord = -DBL_MAX;
2866  for (unsigned j = 0; j < nvertex; j++)
2867  {
2868  if (bin_vertex[j][i] < min_vertex_coord)
2869  {
2870  min_vertex_coord = bin_vertex[j][i];
2871  }
2872  if (bin_vertex[j][i] > max_vertex_coord)
2873  {
2874  max_vertex_coord = bin_vertex[j][i];
2875  }
2876  }
2877  if (zeta[i] < min_vertex_coord - tol)
2878  {
2879  std::ostringstream error_message_stream;
2880  error_message_stream
2881  << "Trouble! " << i << " -th coordinate of sample point, " << zeta[i]
2882  << " , isn't actually between limits, " << min_vertex_coord << " and "
2883  << max_vertex_coord << " [it's below by more than " << tol << " !] "
2884  << std::endl;
2885  throw OomphLibError(error_message_stream.str(),
2886  OOMPH_CURRENT_FUNCTION,
2887  OOMPH_EXCEPTION_LOCATION);
2888  }
2889 
2890  if (zeta[i] > max_vertex_coord + tol)
2891  {
2892  std::ostringstream error_message_stream;
2893  error_message_stream
2894  << "Trouble! " << i << " -th coordinate of sample point, " << zeta[i]
2895  << " , isn't actually between limits, " << min_vertex_coord << " and "
2896  << max_vertex_coord << " [it's above by more than " << tol << "!] "
2897  << std::endl;
2898  throw OomphLibError(error_message_stream.str(),
2899  OOMPH_CURRENT_FUNCTION,
2900  OOMPH_EXCEPTION_LOCATION);
2901  }
2902  }
2903 #endif
2904  }
2905 
2906 
2907  //========================================================================
2908  /// Get vector of vectors containing the coordinates of the
2909  /// vertices of the i_bin-th bin: bin_vertex[j][i] contains the
2910  /// i-th coordinate of the j-th vertex.
2911  //========================================================================
2913  const unsigned& i_bin, Vector<Vector<double>>& bin_vertex)
2914  {
2915  // Spatial dimension of bin
2916  const unsigned n_lagrangian = this->ndim_zeta();
2917 
2918  // How many vertices do we have?
2919  unsigned n_vertices = 1;
2920  for (unsigned i = 0; i < n_lagrangian; i++)
2921  {
2922  n_vertices *= 2;
2923  }
2924  bin_vertex.resize(n_vertices);
2925 
2926  // Vectors for min [0] and max [1] coordinates of the bin in each
2927  // coordinate direction
2928  Vector<Vector<double>> zeta_vertex_bin(2);
2929  zeta_vertex_bin[0].resize(n_lagrangian);
2930  zeta_vertex_bin[1].resize(n_lagrangian);
2931 
2932  Vector<double> dzeta;
2933  unsigned count = 0;
2934  Vector<unsigned> i_1d;
2935 
2936  // Deal with different spatial dimensions separately
2937  switch (n_lagrangian)
2938  {
2939  case 1:
2940 
2941  // Assign vertex coordinates of the bin directly
2942  dzeta.resize(1);
2943  dzeta[0] = (Min_and_max_coordinates[0].second -
2944  Min_and_max_coordinates[0].first) /
2945  double(Dimensions_of_bin_array[0]);
2946  bin_vertex[0].resize(1);
2947  bin_vertex[0][0] =
2948  Min_and_max_coordinates[0].first + double(i_bin) * dzeta[0];
2949  bin_vertex[1].resize(1);
2950  bin_vertex[1][0] =
2951  Min_and_max_coordinates[0].first + double(i_bin + 1) * dzeta[0];
2952 
2953  break;
2954 
2955  case 2:
2956 
2957  dzeta.resize(2);
2958  dzeta[0] = (Min_and_max_coordinates[0].second -
2959  Min_and_max_coordinates[0].first) /
2960  double(Dimensions_of_bin_array[0]);
2961  dzeta[1] = (Min_and_max_coordinates[1].second -
2962  Min_and_max_coordinates[1].first) /
2963  double(Dimensions_of_bin_array[1]);
2964 
2965  i_1d.resize(2);
2966  i_1d[0] = i_bin % Dimensions_of_bin_array[0];
2967  i_1d[1] = (i_bin - i_1d[0]) / Dimensions_of_bin_array[0];
2968 
2969  // Max/min coordinates of the bin
2970  for (unsigned i = 0; i < n_lagrangian; i++)
2971  {
2972  zeta_vertex_bin[0][i] =
2973  Min_and_max_coordinates[i].first + double(i_1d[i]) * dzeta[i];
2974  zeta_vertex_bin[1][i] =
2975  Min_and_max_coordinates[i].first + double(i_1d[i] + 1) * dzeta[i];
2976  }
2977 
2978  // Build 4 vertex coordinates
2979  count = 0;
2980  for (unsigned i_min_max = 0; i_min_max < 2; i_min_max++)
2981  {
2982  for (unsigned j_min_max = 0; j_min_max < 2; j_min_max++)
2983  {
2984  bin_vertex[count].resize(2);
2985  bin_vertex[count][0] = zeta_vertex_bin[i_min_max][0];
2986  bin_vertex[count][1] = zeta_vertex_bin[j_min_max][1];
2987  count++;
2988  }
2989  }
2990 
2991  break;
2992 
2993  case 3:
2994 
2995  dzeta.resize(3);
2996  dzeta[0] = (Min_and_max_coordinates[0].second -
2997  Min_and_max_coordinates[0].first) /
2998  double(Dimensions_of_bin_array[0]);
2999  dzeta[1] = (Min_and_max_coordinates[1].second -
3000  Min_and_max_coordinates[1].first) /
3001  double(Dimensions_of_bin_array[1]);
3002  dzeta[2] = (Min_and_max_coordinates[2].second -
3003  Min_and_max_coordinates[2].first) /
3004  double(Dimensions_of_bin_array[2]);
3005 
3006  i_1d.resize(3);
3007  i_1d[0] = i_bin % Dimensions_of_bin_array[0];
3008  i_1d[1] = ((i_bin - i_1d[0]) / Dimensions_of_bin_array[0]) %
3010  i_1d[2] = (i_bin - (i_1d[1] * Dimensions_of_bin_array[0] + i_1d[0])) /
3012 
3013  // Max/min coordinates of the bin
3014  for (unsigned i = 0; i < n_lagrangian; i++)
3015  {
3016  zeta_vertex_bin[0][i] =
3017  Min_and_max_coordinates[i].first + double(i_1d[i]) * dzeta[i];
3018  zeta_vertex_bin[1][i] =
3019  Min_and_max_coordinates[i].first + double(i_1d[i] + 1) * dzeta[i];
3020  }
3021 
3022  // Build 8 vertex coordinates
3023  count = 0;
3024  for (unsigned i_min_max = 0; i_min_max < 2; i_min_max++)
3025  {
3026  for (unsigned j_min_max = 0; j_min_max < 2; j_min_max++)
3027  {
3028  for (unsigned k_min_max = 0; k_min_max < 2; k_min_max++)
3029  {
3030  bin_vertex[count].resize(3);
3031  bin_vertex[count][0] = zeta_vertex_bin[i_min_max][0];
3032  bin_vertex[count][1] = zeta_vertex_bin[j_min_max][1];
3033  bin_vertex[count][2] = zeta_vertex_bin[k_min_max][2];
3034  count++;
3035  }
3036  }
3037  }
3038 
3039  break;
3040 
3041  default:
3042 
3043  std::ostringstream error_message;
3044  error_message << "Can't deal with bins in dimension " << n_lagrangian
3045  << "\n";
3046  throw OomphLibError(error_message.str(),
3047  OOMPH_CURRENT_FUNCTION,
3048  OOMPH_EXCEPTION_LOCATION);
3049  }
3050  }
3051 
3052 
3053  //========================================================================
3054  /// Compute the minimum distance of any vertex in the specified bin
3055  /// from the specified Lagrangian coordinate zeta.
3056  //========================================================================
3057  double NonRefineableBinArray::min_distance(const unsigned& i_bin,
3058  const Vector<double>& zeta)
3059  {
3060  // Spatial dimension of bin
3061  const unsigned n_lagrangian = this->ndim_zeta();
3062 
3063  // Get bin vertices
3064  Vector<Vector<double>> bin_vertex;
3065  get_bin_vertices(i_bin, bin_vertex);
3066  double min_dist = DBL_MAX;
3067  unsigned nvertex = bin_vertex.size();
3068  for (unsigned v = 0; v < nvertex; v++)
3069  {
3070  double dist = 0.0;
3071  for (unsigned i = 0; i < n_lagrangian; i++)
3072  {
3073  dist += pow(bin_vertex[v][i] - zeta[i], 2);
3074  }
3075  dist = sqrt(dist);
3076  if (dist < min_dist) min_dist = dist;
3077  }
3078  return min_dist;
3079  }
3080 
3081 
3082  //==============================================================================
3083  /// Find the sub geometric object and local coordinate therein that
3084  /// corresponds to the intrinsic coordinate zeta. If sub_geom_object_pt=0
3085  /// on return from this function, none of the constituent sub-objects
3086  /// contain the required coordinate.
3087  //==============================================================================
3088  void NonRefineableBinArray::locate_zeta(const Vector<double>& zeta,
3089  GeomObject*& sub_geom_object_pt,
3090  Vector<double>& s)
3091  {
3092  // Reset counter for number of sample points visited only if we're
3093  // starting from the beginning
3094  if (current_min_spiral_level() == 0)
3095  {
3097  0;
3098  }
3099 
3100  // Initialise return to null -- if it's still null when we're
3101  // leaving we've failed!
3102  sub_geom_object_pt = 0;
3103 
3104  // Get the lagrangian dimension
3105  const unsigned n_lagrangian = this->ndim_zeta();
3106 
3107  // Does the zeta coordinate lie within the current bin structure?
3108  // Skip this test if we want to always fail because that's usually
3109  // done to trace out the spiral path
3111  {
3112  // Loop over the lagrangian dimension
3113  for (unsigned i = 0; i < n_lagrangian; i++)
3114  {
3115  // If the i-th coordinate is less than the minimum
3116  if (zeta[i] < Min_and_max_coordinates[i].first)
3117  {
3118  return;
3119  }
3120  // Otherwise coordinate may be bigger than the maximum
3121  else if (zeta[i] > Min_and_max_coordinates[i].second)
3122  {
3123  return;
3124  }
3125  }
3126  }
3127 
3128  // Use the min and max coords of the bin structure, to find
3129  // the bin structure containing the current zeta cooordinate
3130  unsigned bin_number = 0;
3131 
3132  // Offset for rows/matrices in higher dimensions
3133  unsigned multiplier = 1;
3134 
3135  // Loop over the dimension
3136  for (unsigned i = 0; i < n_lagrangian; i++)
3137  {
3138  // Find the bin number of the current coordinate
3139  unsigned bin_number_i =
3140  int(Dimensions_of_bin_array[i] *
3141  ((zeta[i] - Min_and_max_coordinates[i].first) /
3142  (Min_and_max_coordinates[i].second -
3143  Min_and_max_coordinates[i].first)));
3144 
3145  // Buffer the case when we are exactly on the edge
3146  if (bin_number_i == Dimensions_of_bin_array[i])
3147  {
3148  bin_number_i -= 1;
3149  }
3150 
3151  // Now add to the bin number using the multiplier
3152  bin_number += multiplier * bin_number_i;
3153 
3154  // Increase the current row/matrix multiplier for the next loop
3155  multiplier *= Dimensions_of_bin_array[i];
3156  }
3157 
3158  // Loop over spirals that are to be visited in one go
3159  Vector<unsigned> neighbour_bin;
3160  unsigned min_level = current_min_spiral_level();
3161  unsigned max_level = current_max_spiral_level();
3162  for (unsigned i_level = min_level; i_level <= max_level; i_level++)
3163  {
3164  // Call helper function to find the neighbouring bins at this
3165  // level
3166  get_neighbouring_bins_helper(bin_number, i_level, neighbour_bin);
3167 
3168  // Total number of bins to be visited
3169  unsigned n_nbr_bin = neighbour_bin.size();
3170 
3171  // // keep around and add "false" as last argument to previous call
3172  // // to get_neighbouring_bins_helper(...) for annotation below to make
3173  // sense
3174  // {
3175  // Vector<unsigned> old_neighbour_bin;
3176  // get_neighbouring_bins_helper(bin_number,
3177  // i_level,
3178  // old_neighbour_bin,
3179  // true); // true=use old version!
3180  // unsigned nbin_new = neighbour_bin.size();
3181  // unsigned nbin_old = old_neighbour_bin.size();
3182  // unsigned n=std::min(nbin_new,nbin_old);
3183  // std::sort(old_neighbour_bin.begin(),
3184  // old_neighbour_bin.end());
3185  // std::sort(neighbour_bin.begin(),
3186  // neighbour_bin.end());
3187  // oomph_info << "# of neighbouring bins: "
3188  // << nbin_new << " " << nbin_old;
3189  // if (nbin_new!=nbin_old)
3190  // {
3191  // oomph_info << " DIFFERENT!";
3192  // }
3193  // oomph_info << std::endl;
3194  // for (unsigned i=0;i<n;i++)
3195  // {
3196  // oomph_info << neighbour_bin[i] << " "
3197  // << old_neighbour_bin[i] << " ";
3198  // if (neighbour_bin[i]!=
3199  // old_neighbour_bin[i])
3200  // {
3201  // oomph_info << "DIFFFFERENT";
3202  // }
3203  // oomph_info << std::endl;
3204  // }
3205  // if (nbin_new>nbin_old)
3206  // {
3207  // for (unsigned i=n;i<nbin_new;i++)
3208  // {
3209  // oomph_info << "NNEW:" << neighbour_bin[i]
3210  // << std::endl;
3211  // }
3212  // }
3213  // if (nbin_old>nbin_new)
3214  // {
3215  // for (unsigned i=n;i<nbin_old;i++)
3216  // {
3217  // oomph_info << "OOLD:" << old_neighbour_bin[i]
3218  // << std::endl;
3219  // }
3220  // }
3221  // }
3222 
3223 
3224  // Set bool for finding zeta
3225  bool found_zeta = false;
3226  for (unsigned i_nbr = 0; i_nbr < n_nbr_bin; i_nbr++)
3227  {
3228  // Only search if bin is within the max. radius but min_distance
3229  // is expensive...
3230  bool do_it = true;
3231  if (Max_search_radius < DBL_MAX)
3232  {
3233  if (min_distance(neighbour_bin[i_nbr], zeta) > Max_search_radius)
3234  {
3235  do_it = false;
3236  }
3237  }
3238  if (do_it)
3239  {
3240  // Get the number of element-sample point pairs in this bin
3241  unsigned n_sample =
3242  Bin_object_coord_pairs[neighbour_bin[i_nbr]].size();
3243 
3244  // Don't do anything if this bin has no sample points
3245  if (n_sample > 0)
3246  {
3247  for (unsigned i_sam = 0; i_sam < n_sample; i_sam++)
3248  {
3249  // Get the element
3250  FiniteElement* el_pt =
3251  Bin_object_coord_pairs[neighbour_bin[i_nbr]][i_sam].first;
3252 
3253  // Get the local coordinate
3254  s = Bin_object_coord_pairs[neighbour_bin[i_nbr]][i_sam].second;
3255 
3256  // History of sample points visited
3258  {
3259  unsigned cached_dim_zeta = this->ndim_zeta();
3260  Vector<double> zeta_sample(cached_dim_zeta);
3262  {
3263  el_pt->interpolated_x(s, zeta_sample);
3264  }
3265  else
3266  {
3267  el_pt->interpolated_zeta(s, zeta_sample);
3268  }
3269  double dist = 0.0;
3270  for (unsigned ii = 0; ii < cached_dim_zeta; ii++)
3271  {
3272  BinArray::Visited_sample_points_file << zeta_sample[ii]
3273  << " ";
3274  dist +=
3275  (zeta[ii] - zeta_sample[ii]) * (zeta[ii] - zeta_sample[ii]);
3276  }
3279  << " " << sqrt(dist) << std::endl;
3280  }
3281 
3282  // Use this coordinate as the initial guess
3283  bool use_coordinate_as_initial_guess = true;
3284 
3285  // Attempt to find zeta within a sub-object
3286  el_pt->locate_zeta(
3287  zeta, sub_geom_object_pt, s, use_coordinate_as_initial_guess);
3288 
3289 
3291 
3292  // Always fail? (Used for debugging, e.g. to trace out
3293  // spiral path)
3295  {
3296  sub_geom_object_pt = 0;
3297  }
3298 
3299 
3300 #ifdef OOMPH_HAS_MPI
3301  // Ignore halos?
3303  {
3304  // Dynamic cast the result to a FiniteElement
3305  FiniteElement* test_el_pt =
3306  dynamic_cast<FiniteElement*>(sub_geom_object_pt);
3307  if (test_el_pt != 0)
3308  {
3309  // We only want to exit if this is a non-halo element
3310  if (test_el_pt->is_halo())
3311  {
3312  sub_geom_object_pt = 0;
3313  }
3314  }
3315  }
3316 #endif
3317 
3318  // If the FiniteElement is non-halo and has been located, exit
3319  if (sub_geom_object_pt != 0)
3320  {
3321  found_zeta = true;
3322  break;
3323  }
3324  } // end loop over sample points
3325  }
3326 
3327 
3328  if (found_zeta)
3329  {
3330  return; // break;
3331  }
3332 
3333  } // end of don't search if outside search radius
3334  } // end loop over bins at this level
3335  } // End of loop over levels
3336  }
3337 
3338 
3339  /// Default number of bins (in each coordinate direction)
3341 
3342  /// Counter for overall number of bins allocated -- used to
3343  /// issue warning if this exceeds a threshhold. (Default assignment
3344  /// of 100^DIM bins per MeshAsGeomObject can be a killer if there
3345  /// are huge numbers of sub-meshes (e.g. in unstructured FSI).
3347 
3348  /// Total number of bins above which warning is issued.
3349  /// (Default assignment of 100^DIM bins per MeshAsGeomObject can
3350  /// be a killer if there are huge numbers of sub-meshes (e.g. in
3351  /// unstructured FSI).
3352  unsigned long
3354  50000000;
3355 
3356  /// Boolean to supppress warnings about large number of bins
3357  bool
3359  false;
3360 
3361  /// Boolean flag to make sure that warning about large number
3362  /// of bin cells only gets triggered once.
3364  false;
3365 
3366  /// Fraction of elements/bin that triggers warning. Too many
3367  /// elements per bin can lead to very slow computations
3369 
3370  /// Boolean to supppress warnings about small number of bins
3372  false;
3373 
3374  /// Boolean flag to make sure that warning about small number
3375  /// of bin cells only gets triggered once.
3377  false;
3378 
3379 
3380  /// /////////////////////////////////////////////////////////////////////////////
3381  /// /////////////////////////////////////////////////////////////////////////////
3382  /// /////////////////////////////////////////////////////////////////////////////
3383 
3384 #ifdef OOMPH_HAS_CGAL
3385 
3386 
3387  //====================================================================
3388  /// Constructor
3389  //====================================================================
3391  SamplePointContainerParameters* sample_point_container_parameters_pt)
3393  sample_point_container_parameters_pt->mesh_pt(),
3394  sample_point_container_parameters_pt->min_and_max_coordinates(),
3395  sample_point_container_parameters_pt
3396  ->use_eulerian_coordinates_during_setup(),
3397  sample_point_container_parameters_pt
3398  ->ignore_halo_elements_during_locate_zeta_search(),
3399  sample_point_container_parameters_pt
3400  ->nsample_points_generated_per_element())
3401  {
3402  // Get the spatial dimension (int because of mpi below)
3403  int dim = 0;
3404  if (Mesh_pt->nelement() != 0)
3405  {
3406  dim = Mesh_pt->finite_element_pt(0)->dim();
3407  }
3408 
3409  // Need to do an Allreduce to ensure that the dimension is consistent
3410  // even when no elements are assigned to a certain processor
3411 #ifdef OOMPH_HAS_MPI
3412  // Only a problem if the mesh has been distributed
3413  if (Mesh_pt->is_mesh_distributed())
3414  {
3415  // Need a non-null communicator
3416  if (Mesh_pt->communicator_pt() != 0)
3417  {
3418  int n_proc = Mesh_pt->communicator_pt()->nproc();
3419  if (n_proc > 1)
3420  {
3421  int dim_reduce;
3422  MPI_Allreduce(&dim,
3423  &dim_reduce,
3424  1,
3425  MPI_INT,
3426  MPI_MAX,
3427  Mesh_pt->communicator_pt()->mpi_comm());
3428  dim = dim_reduce;
3429  }
3430  }
3431  }
3432 #endif
3433 
3434  Ndim_zeta = dim;
3435 
3436  // Have we specified max/min coordinates?
3437  // If not, compute them on the fly from mesh
3438  if (Min_and_max_coordinates.size() == 0)
3439  {
3441  }
3442 
3443 
3444  // Time it
3445  double t_start = 0.0;
3447  {
3448  t_start = TimingHelpers::timer();
3449  }
3450 
3451  // Fill the bastard!
3452  double CGAL_setup_time = get_sample_points();
3453 
3455  {
3456  double t_end = TimingHelpers::timer();
3458  oomph_info << "Time for setup of " << dim
3459  << "-dimensional sample point container containing " << npts
3460  << " sample points: " << t_end - t_start
3461  << " sec (cgal); third party: " << CGAL_setup_time
3462  << " sec ( = " << CGAL_setup_time / (t_end - t_start) * 100.0
3463  << " %)" << std::endl;
3464  }
3465 
3466  // Initialise
3471  2; // hierher tune this and create public static default
3473  10; // UINT MAX is temporary bypass! tune this and create public static
3474  // default
3475  }
3476 
3477  //==============================================================================
3478  /// Get the sample points; returns time taken for setup of CGAL tree
3479  //==============================================================================
3481  {
3482  // Number of elements
3483  unsigned nel = Mesh_pt->nelement();
3484 
3485  // Estimate number of sample points
3486  unsigned n_sample_estimate = 0;
3487  if (nel > 0)
3488  {
3489  FiniteElement* el_pt = Mesh_pt->finite_element_pt(0);
3490  if (el_pt != 0)
3491  {
3492  // Total number of sample point we will create
3493  n_sample_estimate =
3494  nel * el_pt->nplot_points(Nsample_points_generated_per_element);
3495  }
3496  }
3497  CGAL_sample_point_zeta_d.reserve(n_sample_estimate);
3498  Sample_point_pt.reserve(n_sample_estimate);
3499 
3500  // Fill 'em in:
3501  for (unsigned e = 0; e < nel; e++)
3502  {
3503  FiniteElement* el_pt = Mesh_pt->finite_element_pt(e);
3504 
3505  // Total number of sample point we will create
3506  unsigned nplot =
3507  el_pt->nplot_points(Nsample_points_generated_per_element);
3508 
3509  /// For all the sample points we have to create ...
3510  for (unsigned j = 0; j < nplot; j++)
3511  {
3512  // ... create it: Pass element index in mesh (vector
3513  // of elements and index of sample point within element
3514  SamplePoint* new_sample_point_pt = new SamplePoint(e, j);
3515 
3516  // Coordinates of this point
3517  Vector<double> zeta(ndim_zeta());
3518  Vector<double> s(ndim_zeta());
3519  bool use_equally_spaced_interior_sample_points =
3521  el_pt->get_s_plot(j,
3523  s,
3524  use_equally_spaced_interior_sample_points);
3526  {
3527  el_pt->interpolated_x(s, zeta);
3528  }
3529  else
3530  {
3531  el_pt->interpolated_zeta(s, zeta);
3532  }
3533 
3534 #ifdef PARANOID
3535 
3536  // Check if point is inside
3537  bool is_inside = true;
3538  std::ostringstream error_message;
3539  unsigned dim = ndim_zeta();
3540  for (unsigned i = 0; i < dim; i++)
3541  {
3542  if ((zeta[i] < Min_and_max_coordinates[i].first) ||
3543  (zeta[i] > Min_and_max_coordinates[i].second))
3544  {
3545  is_inside = false;
3546  error_message << "Sample point at zeta[" << i << "] = " << zeta[i]
3547  << " is outside limits of sample point container: "
3548  << Min_and_max_coordinates[i].first << " and "
3549  << Min_and_max_coordinates[i].second << std::endl;
3550  }
3551  }
3552 
3553  if (!is_inside)
3554  {
3555  error_message << "Please correct the limits passed to the "
3556  << "constructor." << std::endl;
3557  throw OomphLibError(error_message.str(),
3558  OOMPH_CURRENT_FUNCTION,
3559  OOMPH_EXCEPTION_LOCATION);
3560  }
3561 
3562 #endif
3563 
3564  CGAL_sample_point_zeta_d.push_back(
3565  Kernel_d::Point_d(zeta.size(), zeta.begin(), zeta.end()));
3566  Sample_point_pt.push_back(new_sample_point_pt);
3567  }
3568  }
3569 
3570  // Make tree structure
3571  double CGAL_setup_time = 0.0;
3573  {
3574  CGAL_setup_time = TimingHelpers::timer();
3575  }
3576 
3577  CGAL_tree_d_pt = new K_neighbor_search_d::Tree(
3578  boost::make_zip_iterator(boost::make_tuple(
3579  CGAL_sample_point_zeta_d.begin(), Sample_point_pt.begin())),
3580  boost::make_zip_iterator(boost::make_tuple(CGAL_sample_point_zeta_d.end(),
3581  Sample_point_pt.end())));
3583  {
3584  CGAL_setup_time = TimingHelpers::timer() - CGAL_setup_time;
3585  }
3586  return CGAL_setup_time;
3587  }
3588 
3589 
3590  //==============================================================================
3591  /// Compute total number of sample points in sample point container
3592  //==============================================================================
3595  {
3596  return Sample_point_pt.size();
3597  }
3598 
3599 
3600  //==============================================================================
3601  /// Find the sub geometric object and local coordinate therein that
3602  /// corresponds to the intrinsic coordinate zeta. If sub_geom_object_pt=0
3603  /// on return from this function, none of the constituent sub-objects
3604  /// contain the required coordinate.
3605  //==============================================================================
3606  void CGALSamplePointContainer::locate_zeta(const Vector<double>& zeta,
3607  GeomObject*& sub_geom_object_pt,
3608  Vector<double>& s)
3609  {
3610  // Top level book keeping and sanity checking
3612  {
3613  // Reset counter for number of sample points visited.
3614  // If we can't find the point we should at least make sure that
3615  // we've visited all the sample points before giving up.
3617  0;
3618  }
3619 
3620  // Initialise return to null -- if it's still null when we're
3621  // leaving we've failed!
3622  sub_geom_object_pt = 0;
3623 
3624  // Get the lagrangian dimension
3625  const unsigned n_lagrangian = this->ndim_zeta();
3626 
3627  // Does the zeta coordinate lie within the current bin structure?
3628  // Skip this test if we want to always fail because that's usually
3629  // done to trace out the spiral path
3630  if (!SamplePointContainer::Always_fail_elemental_locate_zeta)
3631  {
3632  // Loop over the lagrangian dimension
3633  for (unsigned i = 0; i < n_lagrangian; i++)
3634  {
3635  // If the i-th coordinate is less than the minimum
3636  if (zeta[i] < Min_and_max_coordinates[i].first)
3637  {
3638  return;
3639  }
3640  // Otherwise coordinate may be bigger than the maximum
3641  else if (zeta[i] > Min_and_max_coordinates[i].second)
3642  {
3643  return;
3644  }
3645  }
3646  }
3647 
3648  // Number of sample points
3649  unsigned n_sample = Sample_point_pt.size();
3650 
3651  // Create CGAL query -- this is the point we want!
3652  Point_d query(zeta.size(), zeta.begin(), zeta.end());
3653 
3654  // Max. number of nearest neighbours
3655  const unsigned n_nearest_neighbours_max = std::min(
3657 
3658  // Start with just one...
3659  unsigned n_nearest_neighbours = 1;
3660  unsigned n_neighbours_visited_last_time = 0;
3661  bool can_increase_n_nearest_neighbours = true;
3662  bool keep_going = true;
3663  while (keep_going)
3664  {
3665  // Find specified number of nearest neighbours only
3666  const unsigned n_nearest_neighbours_actual =
3667  std::min(n_nearest_neighbours, n_nearest_neighbours_max);
3668  K_neighbor_search_d search(
3669  *CGAL_tree_d_pt, query, n_nearest_neighbours_actual);
3670 
3671  // Search
3672  unsigned count = 0;
3673  for (K_neighbor_search_d::iterator it = search.begin();
3674  it != search.end();
3675  it++)
3676  {
3677  count++;
3678 
3679  if ((count > n_neighbours_visited_last_time) &&
3680  (count >
3682  {
3683  // Recover the sample point
3684  SamplePoint* sample_point_pt = boost::get<1>(it->first);
3685 
3686  // Get the element
3687  FiniteElement* el_pt = Mesh_pt->finite_element_pt(
3688  sample_point_pt->element_index_in_mesh());
3689 
3690 
3691 #ifdef OOMPH_HAS_MPI
3692  // We only look at the sample point if it isn't halo
3693  // if we are set up to ignore the halo elements
3695  (el_pt->is_halo()))
3696  {
3697  // Halo
3698  }
3699  else
3700  {
3701 #endif
3702 
3703  // Provide initial guess for Newton search using local coordinate
3704  // of sample point
3705  bool use_equally_spaced_interior_sample_points =
3707  unsigned i = sample_point_pt->sample_point_index_in_element();
3708  el_pt->get_s_plot(i,
3710  s,
3711  use_equally_spaced_interior_sample_points);
3712 
3713  bool do_it = true;
3714  if (Max_search_radius < DBL_MAX)
3715  {
3716  unsigned cached_dim_zeta = ndim_zeta();
3717  Vector<double> zeta_sample(cached_dim_zeta);
3719  {
3720  el_pt->interpolated_x(s, zeta_sample);
3721  }
3722  else
3723  {
3724  el_pt->interpolated_zeta(s, zeta_sample);
3725  }
3726  double dist_sq = 0.0;
3727  for (unsigned ii = 0; ii < cached_dim_zeta; ii++)
3728  {
3729  dist_sq +=
3730  (zeta[ii] - zeta_sample[ii]) * (zeta[ii] - zeta_sample[ii]);
3731  }
3732  if (dist_sq > Max_search_radius * Max_search_radius)
3733  {
3734  do_it = false;
3735  }
3736  }
3737  if (do_it)
3738  {
3739  // History of sample points visited
3741  {
3742  unsigned cached_dim_zeta = ndim_zeta();
3743  Vector<double> zeta_sample(cached_dim_zeta);
3745  {
3746  el_pt->interpolated_x(s, zeta_sample);
3747  }
3748  else
3749  {
3750  el_pt->interpolated_zeta(s, zeta_sample);
3751  }
3752  double dist = 0.0;
3753  for (unsigned ii = 0; ii < cached_dim_zeta; ii++)
3754  {
3756  << zeta_sample[ii] << " ";
3757  dist +=
3758  (zeta[ii] - zeta_sample[ii]) * (zeta[ii] - zeta_sample[ii]);
3759  }
3762  << " " << sqrt(dist) << std::endl;
3763  }
3764 
3765  // Bump counter
3767 
3768  bool use_coordinate_as_initial_guess = true;
3769  el_pt->locate_zeta(
3770  zeta, sub_geom_object_pt, s, use_coordinate_as_initial_guess);
3771 
3772  // Always fail? (Used for debugging, e.g. to trace out
3773  // spiral path)
3775  {
3776  sub_geom_object_pt = 0;
3777  }
3778 
3779  if (sub_geom_object_pt != 0)
3780  {
3781  return;
3782  }
3783  }
3784 
3785 #ifdef OOMPH_HAS_MPI
3786  }
3787 #endif
3788  }
3789  }
3790 
3791  n_neighbours_visited_last_time = count;
3792 
3793  // Can we increase the number of neighbours further?
3794  if (can_increase_n_nearest_neighbours)
3795  {
3796  unsigned factor_for_increase_in_nearest_neighbours = 10;
3797  n_nearest_neighbours *= factor_for_increase_in_nearest_neighbours;
3798 
3799  // There's no point going any further (next time)
3800  if (n_nearest_neighbours > n_nearest_neighbours_max)
3801  {
3802  can_increase_n_nearest_neighbours = false;
3803  }
3804  }
3805  // Bailing out; not found but we can't increase number of search pts
3806  // further
3807  else
3808  {
3809  keep_going = false;
3810  }
3811  } // while loop to increase number of nearest neighbours
3812  }
3813 
3814 
3815  //==============================================================================
3816  /// Find the sub geometric object and local coordinate therein that
3817  /// corresponds to the intrinsic coordinate zeta, using up to the specified
3818  /// number of sample points as initial guess for the Newton-based search.
3819  /// If this fails, return the nearest sample point.
3820  //==============================================================================
3822  const Vector<double>& zeta,
3823  const unsigned& max_sample_points_for_newton_based_search,
3824  GeomObject*& sub_geom_object_pt,
3825  Vector<double>& s)
3826  {
3827  // Reset counter for number of sample points visited.
3829 
3830  // Initialise return to null -- if it's still null when we're
3831  // leaving we've failed!
3832  sub_geom_object_pt = 0;
3833 
3834  // Number of sample points
3835  unsigned n_sample = Sample_point_pt.size();
3836 
3837  // Create CGAL query -- this is the point we want!
3838  Point_d query(zeta.size(), zeta.begin(), zeta.end());
3839 
3840  // Max. number of nearest neighbours
3841  const unsigned n_nearest_neighbours_max =
3842  std::min(n_sample, max_sample_points_for_newton_based_search);
3843 
3844  // Find 'em
3845  K_neighbor_search_d search(
3846  *CGAL_tree_d_pt, query, n_nearest_neighbours_max);
3847 
3848  // Do Newton method starting from each of the nearest sample points
3849  for (K_neighbor_search_d::iterator it = search.begin(); it != search.end();
3850  it++)
3851  {
3852  // Recover the sample point
3853  SamplePoint* sample_point_pt = boost::get<1>(it->first);
3854 
3855  // Get the element
3856  FiniteElement* el_pt =
3857  Mesh_pt->finite_element_pt(sample_point_pt->element_index_in_mesh());
3858 
3859 
3860 #ifdef OOMPH_HAS_MPI
3861 
3862  // We only look at the sample point if it isn't halo
3863  // if we are set up to ignore the halo elements
3865  (el_pt->is_halo()))
3866  {
3867  // Halo
3868  }
3869  else
3870  { // not halo
3871 
3872 #endif
3873 
3874  // Provide initial guess for Newton search using local coordinate
3875  // of sample point
3876  bool use_equally_spaced_interior_sample_points =
3878  unsigned i = sample_point_pt->sample_point_index_in_element();
3879  el_pt->get_s_plot(i,
3881  s,
3882  use_equally_spaced_interior_sample_points);
3883 
3884  bool do_it = true;
3885  if (Max_search_radius < DBL_MAX)
3886  {
3887  unsigned cached_dim_zeta = ndim_zeta();
3888  Vector<double> zeta_sample(cached_dim_zeta);
3890  {
3891  el_pt->interpolated_x(s, zeta_sample);
3892  }
3893  else
3894  {
3895  el_pt->interpolated_zeta(s, zeta_sample);
3896  }
3897  double dist_sq = 0.0;
3898  for (unsigned ii = 0; ii < cached_dim_zeta; ii++)
3899  {
3900  dist_sq +=
3901  (zeta[ii] - zeta_sample[ii]) * (zeta[ii] - zeta_sample[ii]);
3902  }
3903  if (dist_sq > Max_search_radius * Max_search_radius)
3904  {
3905  do_it = false;
3906  }
3907  }
3908  if (do_it)
3909  {
3910  // History of sample points visited
3912  {
3913  unsigned cached_dim_zeta = ndim_zeta();
3914  Vector<double> zeta_sample(cached_dim_zeta);
3916  {
3917  el_pt->interpolated_x(s, zeta_sample);
3918  }
3919  else
3920  {
3921  el_pt->interpolated_zeta(s, zeta_sample);
3922  }
3923  double dist = 0.0;
3924  for (unsigned ii = 0; ii < cached_dim_zeta; ii++)
3925  {
3927  << zeta_sample[ii] << " ";
3928  dist +=
3929  (zeta[ii] - zeta_sample[ii]) * (zeta[ii] - zeta_sample[ii]);
3930  }
3933  << " " << sqrt(dist) << std::endl;
3934  }
3935 
3936  // Bump counter
3938 
3939  bool use_coordinate_as_initial_guess = true;
3940  el_pt->locate_zeta(
3941  zeta, sub_geom_object_pt, s, use_coordinate_as_initial_guess);
3942 
3943  // Always fail? (Used for debugging, e.g. to trace out
3944  // spiral path)
3946  {
3947  sub_geom_object_pt = 0;
3948  }
3949 
3950  if (sub_geom_object_pt != 0)
3951  {
3952  return;
3953  }
3954  }
3955 
3956 #ifdef OOMPH_HAS_MPI
3957  }
3958 #endif
3959  }
3960 
3961  // We've searched over all the sample points but the Newton method
3962  // hasn't converged from any, so just use the nearest one
3963  K_neighbor_search_d::iterator it = search.begin();
3964 
3965  // Recover the sample point
3966  SamplePoint* sample_point_pt = boost::get<1>(it->first);
3967 
3968  // Get the element
3969  FiniteElement* el_pt =
3970  Mesh_pt->finite_element_pt(sample_point_pt->element_index_in_mesh());
3971 
3972  // Get local coordinate of sample point in element
3973  bool use_equally_spaced_interior_sample_points =
3975  unsigned i = sample_point_pt->sample_point_index_in_element();
3976  el_pt->get_s_plot(i,
3978  s,
3979  use_equally_spaced_interior_sample_points);
3980 
3981  sub_geom_object_pt = el_pt;
3982  }
3983 
3984 
3985 #endif // cgal
3986 
3987 } // namespace oomph
e
Definition: cfortran.h:571
static char t char * s
Definition: cfortran.h:568
cstr elem_len * i
Definition: cfortran.h:603
///////////////////////////////////////////////////////////////////// ///////////////////////////////...
unsigned dimension_of_bin_array(const unsigned &i) const
Number of bins in coordinate direction i.
unsigned max_bin_dimension() const
Max. bin dimension (number of bins in coordinate directions)
Vector< unsigned > dimensions_of_bin_array() const
Number of bins in coordinate directions. Const vector-based version.
void get_neighbouring_bins_helper(const unsigned &bin_index, const unsigned &radius, Vector< unsigned > &neighbouring_bin_index, const bool &use_old_version=true)
Helper function for computing the bin indices of neighbouring bins at a given "radius" of the specifi...
unsigned ndim_zeta() const
Dimension of the zeta ( = dim of local coordinate of elements)
Vector< unsigned > Dimensions_of_bin_array
Number of bins in each coordinate direction.
unsigned coords_to_bin_index(const Vector< double > &zeta)
Get (linearly enumerated) bin index of bin that contains specified zeta.
void profile_get_neighbouring_bins_helper()
Profiling function to compare performance of two different versions of the get_neighbouring_bins_help...
void coords_to_vectorial_bin_index(const Vector< double > &zeta, Vector< unsigned > &bin_index)
Get "coordinates" of bin that contains specified zeta.
void locate_zeta(const Vector< double > &zeta, GeomObject *&sub_geom_object_pt, Vector< double > &s)
Find sub-GeomObject (finite element) and the local coordinate s within it that contains point with gl...
unsigned ndim_zeta() const
Dimension of the zeta ( = dim of local coordinate of elements)
CGAL::Orthogonal_k_neighbor_search< Traits_d > K_neighbor_search_d
CGALSamplePointContainer(SamplePointContainerParameters *sample_point_container_parameters_pt)
Constructor.
unsigned & last_sample_point_to_actually_lookup_during_locate_zeta()
When searching through sample points only actually do the locate_zeta calls when when the counter is ...
void limited_locate_zeta(const Vector< double > &zeta, const unsigned &max_sample_points_for_newton_based_search, GeomObject *&sub_geom_object_pt, Vector< double > &s)
Find the sub geometric object and local coordinate therein that corresponds to the intrinsic coordina...
unsigned Multiplier_for_max_sample_point_to_actually_lookup_during_locate_zeta
Every time we've completed a "spiral", visiting a finite number of sample points in a deterministic o...
unsigned Last_sample_point_to_actually_lookup_during_locate_zeta
When searching through sample points only actually do the locate_zeta calls when when the counter is ...
Vector< SamplePoint * > Sample_point_pt
Vector storing pointers to sample point objects (which represent sample point in terms of number of e...
double get_sample_points()
Get the sample points; return time for setup of CGAL tree.
unsigned Initial_last_sample_point_to_actually_lookup_during_locate_zeta
When searching through sample points only actually do the locate_zeta calls when when the counter exc...
unsigned First_sample_point_to_actually_lookup_during_locate_zeta
When searching through sample points only actually do the locate_zeta calls when when the counter exc...
Vector< Point_d > CGAL_sample_point_zeta_d
Vector containing sample point coordinates.
K_neighbor_search_d::Tree * CGAL_tree_d_pt
Pointer to tree-based representation of sample points.
unsigned Ndim_zeta
Dimension of the zeta ( = dim of local coordinate of elements)
unsigned & first_sample_point_to_actually_lookup_during_locate_zeta()
When searching through sample points only actually do the locate_zeta calls when when the counter exc...
unsigned total_number_of_sample_points_computed_recursively() const
Compute total number of sample points in sample point container.
static bool Already_warned_about_small_number_of_bin_cells
Boolean flag to make sure that warning about small number of bin cells only gets triggered once.
void get_bin(const Vector< double > &zeta, int &bin_number)
Get the number of the bin containing the specified coordinate. Bin number is negative if the coordina...
static bool Suppress_warning_about_large_total_number_of_bins
Boolean to supppress warnings about large number of bins.
void fill_bin_array()
Fill the bin array with sample points from FiniteElements stored in mesh.
unsigned Nspiral_chunk
Number of spirals to be searched in one go.
unsigned Max_spiral_level
Max. spiralling level (for efficiency; effect similar to max_search_radius)
static unsigned long Total_nbin_cells_counter
Counter for overall number of bins allocated – used to issue warning if this exceeds a threshhold....
void locate_zeta(const Vector< double > &zeta, GeomObject *&sub_geom_object_pt, Vector< double > &s)
Find sub-GeomObject (finite element) and the local coordinate s within it that contains point with gl...
static unsigned Threshold_for_elements_per_bin_warning
Fraction of elements/bin that triggers warning. Too many elements per bin can lead to very slow compu...
unsigned Current_min_spiral_level
Current min. spiralling level.
void get_bin_vertices(const unsigned &i_bin, Vector< Vector< double >> &bin_vertex)
Get vector of vectors containing the coordinates of the vertices of the i_bin-th bin: bin_vertex[j][i...
unsigned Current_max_spiral_level
Current max. spiralling level.
static bool Suppress_warning_about_small_number_of_bins
Boolean to supppress warnings about small number of bins.
void fill_bin_by_diffusion(const unsigned &bin_diffusion_radius=1)
Fill bin by diffusion, populating each empty bin with the same content as the first non-empty bin fou...
unsigned total_number_of_sample_points_computed_recursively() const
Compute total number of sample points recursively.
void output_bin_vertices(std::ofstream &outfile)
Output bin vertices (allowing display of bins as zones).
static bool Already_warned_about_large_number_of_bin_cells
Boolean flag to make sure that warning about large number of bin cells only gets triggered once.
SparseVector< Vector< std::pair< FiniteElement *, Vector< double > > > > Bin_object_coord_pairs
Storage for paired objects and coords in each bin.
void output_bins(std::ofstream &outfile)
Output bins.
static unsigned Default_n_bin_1d
Default number of bins (in each coordinate direction). (Note: don't move this into a common base clas...
unsigned & current_max_spiral_level()
Access function to current max. spiral level.
void get_fill_stats(unsigned &n_bin, unsigned &max_n_entry, unsigned &min_n_entry, unsigned &tot_n_entry, unsigned &n_empty) const
Provide some stats on the fill level of the associated bin.
void flush_bins_of_objects()
Flush the storage for the binning method (and decrement counter for total number of bins in active us...
static unsigned long Threshold_for_total_bin_cell_number_warning
Total number of bins above which warning is issued. (Default assignment of 100^DIM bins per MeshAsGeo...
NonRefineableBinArray(SamplePointContainerParameters *bin_array_parameters_pt)
Constructor.
unsigned & current_min_spiral_level()
Access function to current min. spiral level.
double min_distance(const unsigned &i_bin, const Vector< double > &zeta)
Compute the minimum distance of any vertex in the specified bin from the specified Lagrangian coordin...
unsigned nbin() const
Total number of bins (empty or not)
///////////////////////////////////////////////////////////////////// ///////////////////////////////...
unsigned Multiplier_for_max_sample_point_to_actually_lookup_during_locate_zeta
Every time we've completed a "spiral", visiting a finite number of sample points in a deterministic o...
Vector< RefineableBin * > Bin_pt
Vector of pointers to constituent RefineableBins.
unsigned Max_depth
Max depth of the hierarchical bin_array.
unsigned total_number_of_sample_points_computed_recursively() const
Compute total number of sample points recursively.
unsigned First_sample_point_to_actually_lookup_during_locate_zeta
When searching through sample points recursively from the top level RefineableBinArray (in determinis...
static unsigned Default_n_bin_1d
Default number of bins (in each coordinate direction) (Note: don't move this into a common base class...
void locate_zeta(const Vector< double > &zeta, GeomObject *&sub_geom_object_pt, Vector< double > &s)
Find sub-GeomObject (finite element) and the local coordinate s within it that contains point with gl...
unsigned nbin() const
Number of bins (not taking recursion into account)
RefineableBinArray * Root_bin_array_pt
Pointer to root bin array.
unsigned Depth
Variable which stores the Depth value of the bin_array. Useful for debugging and for preventing "infi...
unsigned Max_number_of_sample_point_per_bin
Maximum number of sample points in bin (before it's subdivided recursively)
RefineableBinArray * root_bin_array_pt() const
Root bin array.
void fill_bin_array()
Fill the bin array with sample points from FiniteElements stored in mesh.
void output_bin_vertices(std::ofstream &outfile)
Output bin vertices (allowing display of bins as zones).
void output_neighbouring_bins(const unsigned &bin_index, const unsigned &radius, std::ofstream &outfile)
Output neighbouring bins at given "radius" of the specified bin.
unsigned Last_sample_point_to_actually_lookup_during_locate_zeta
When searching through sample points recursively from the top level RefineableBinArray (in determinis...
void get_bin_boundaries(const unsigned &bin_index, Vector< std::pair< double, double >> &min_and_max_coordinates)
Boundaries of specified bin in each coordinate direction. *.first = min; *.second = max.
unsigned Initial_last_sample_point_to_actually_lookup_during_locate_zeta
When searching through sample points recursively from the top level RefineableBinArray (in determinis...
RefineableBinArray(SamplePointContainerParameters *bin_array_parameters_pt)
Constructor.
bool Bin_array_is_recursive
Variable which stores if the RefineableBinArray is recursive or not.
RefineableBin class. Contains sample points and is embedded in a RefineableBinArray....
void output(std::ofstream &outfile, const bool &don_t_recurse=false)
Output bin; x,[y,[z]],n_sample_points.
void add_sample_point(SamplePoint *new_sample_point_pt, const Vector< double > &zeta_coordinates)
Add a new sample point to RefineableBin.
void get_bin_boundaries(Vector< std::pair< double, double >> &min_and_max_coordinates)
Boundaries of bin in each coordinate direction. *.first = min; *.second = max.
void output_bin_vertices(std::ofstream &outfile)
Output bin vertices (allowing display of bins as zones).
unsigned total_number_of_sample_points_computed_recursively() const
Compute total number of sample points recursively.
~RefineableBin()
Destructor.
void locate_zeta(const Vector< double > &zeta, GeomObject *&sub_geom_object_pt, Vector< double > &s)
Find sub-GeomObject (finite element) and the local coordinate s within it that contains point with gl...
void make_sub_bin_array(const Vector< std::pair< double, double >> &min_and_max_coordinates)
Method for building a new subbin_array (called when the Bin size is greater than the Max_number_of_sa...
///////////////////////////////////////////////////////////////////// ///////////////////////////////...
static bool Always_fail_elemental_locate_zeta
Boolean flag to make to make locate zeta fail. Used for debugging/ illustration of search procedures.
static double Percentage_offset
Offset of sample point container boundaries beyond max/min coords.
Vector< std::pair< double, double > > Min_and_max_coordinates
Vector of pairs of doubles for min and maximum coordinates. Call: Min_and_max_coordinates[j] gives me...
static bool Enable_timing_of_setup
Time setup?
bool ignore_halo_elements_during_locate_zeta_search() const
Ignore halo elements?
unsigned & nsample_points_generated_per_element()
"Measure of" number of sample points generated in each element
bool Ignore_halo_elements_during_locate_zeta_search
Ignore halo elements?
const Vector< std::pair< double, double > > & min_and_max_coordinates() const
Vector of pair of doubles for min and maximum coordinates. min (first) and max. (second) coordinates.
bool use_eulerian_coordinates_during_setup() const
Use Eulerian coordinates (i.e. interpolated_x) rather than zeta itself (i.e. interpolated_zeta) to id...
unsigned Nsample_points_generated_per_element
"Measure of" number of sample points generated in each element
unsigned Total_number_of_sample_points_visited_during_locate_zeta_from_top_level
Counter to keep track of how many sample points we've visited during top level call to locate_zeta.
bool Use_eulerian_coordinates_during_setup
Use Eulerian coordinates (i.e. interpolated_x) rather than zeta itself (i.e. interpolated_zeta) to id...
Mesh * Mesh_pt
Pointer to mesh from whose FiniteElements sample points are created.
double Max_search_radius
Max radius beyond which we stop searching the bin. Initialised to DBL_MAX so keep going until the poi...
static std::ofstream Visited_sample_points_file
File to record sequence of visited sample points in. Used for debugging/ illustration of search proce...
double & max_search_radius()
Set maximum search radius for locate zeta. This is initialised do DBL_MAX so we brutally search throu...
virtual unsigned & total_number_of_sample_points_visited_during_locate_zeta_from_top_level()
Counter to keep track of how many sample points we've visited during top level call to locate_zeta....
void setup_min_and_max_coordinates()
Helper function to compute the min and max coordinates for the mesh, in each dimension.
static bool Use_equally_spaced_interior_sample_points
Use equally spaced sample points? (otherwise vertices are sampled repeatedly.
///////////////////////////////////////////////////////////////// ///////////////////////////////////...
unsigned element_index_in_mesh() const
Access function to the index of finite element in its mesh.
unsigned sample_point_index_in_element() const
Index of sample point within element.
double timer()
returns the time in seconds after some point in past
//////////////////////////////////////////////////////////////////// ////////////////////////////////...
OomphInfo oomph_info
Single (global) instantiation of the OomphInfo object – this is used throughout the library as a "rep...