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