All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
tensor_grid.h
Go to the documentation of this file.
1 /*
2  -------------------------------------------------------------------
3 
4  Copyright (C) 2006-2014, Andrew W. Steiner
5 
6  This file is part of O2scl.
7 
8  O2scl is free software; you can redistribute it and/or modify
9  it under the terms of the GNU General Public License as published by
10  the Free Software Foundation; either version 3 of the License, or
11  (at your option) any later version.
12 
13  O2scl is distributed in the hope that it will be useful,
14  but WITHOUT ANY WARRANTY; without even the implied warranty of
15  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16  GNU General Public License for more details.
17 
18  You should have received a copy of the GNU General Public License
19  along with O2scl. If not, see <http://www.gnu.org/licenses/>.
20 
21  -------------------------------------------------------------------
22 */
23 #ifndef O2SCL_TENSOR_GRID_H
24 #define O2SCL_TENSOR_GRID_H
25 
26 /** \file tensor_grid.h
27  \brief File defining \ref o2scl::tensor_grid and rank-specific children
28 */
29 
30 #include <iostream>
31 #include <cstdlib>
32 #include <string>
33 #include <fstream>
34 #include <sstream>
35 
36 #include <gsl/gsl_matrix.h>
37 #include <gsl/gsl_ieee_utils.h>
38 
39 #include <o2scl/err_hnd.h>
40 #include <o2scl/interp.h>
41 #include <o2scl/tensor.h>
42 #include <o2scl/table3d.h>
43 
44 // Forward definition of the tensor_grid class for HDF I/O
45 namespace o2scl {
46  class tensor_grid;
47 }
48 
49 // Forward definition of HDF I/O to extend friendship
50 namespace o2scl_hdf {
51  class hdf_file;
52  void hdf_input(hdf_file &hf, o2scl::tensor_grid &t, std::string name);
53  void hdf_output(hdf_file &hf, o2scl::tensor_grid &t, std::string name);
54 }
55 
56 #ifndef DOXYGEN_NO_O2NS
57 namespace o2scl {
58 #endif
59 
60  /** \brief Tensor class with arbitrary dimensions with a grid
61 
62  This tensor class allows one to assign the indexes to numerical
63  scales, so that n-dimensional interpolation can be performed. To
64  set the grid, use \ref set_grid() or \ref set_grid_packed() and
65  then interpolation can be done using \ref interp_linear() or
66  \ref interpolate().
67 
68  By convention, member functions ending in the _val
69  suffix return the closest grid-point to some user-specified
70  values.
71 
72  \comment
73  I like how hist_new only allows you to set the
74  grid if it's the same size as the old grid or the tensor
75  is empty. This same practice could be applied here, to
76  force the user to clear the tensor before resetting the grid.
77  (10/24/11 - Actually, maybe this is a bad idea, because
78  this class is more analogous to ubvector, which doesn't
79  behave this way.)
80  \endcomment
81 
82  \todo Make this a template like the \ref o2scl::tensor class?
83 
84  \todo It is possible for the user to create a tensor_grid
85  object, upcast it to a tensor object, and then use
86  tensor::resize() to resize the tensor, failing to resize the
87  grid. This probably needs fixing.
88 
89  \future Only allocate space for grid if it is set
90  \future Consider creating a new set_grid() function which
91  takes grids from an object like uniform_grid. Maybe make a
92  constructor for a tensor_grid object which just takes
93  as input a set of grids?
94  */
95  class tensor_grid :
96  public tensor<boost::numeric::ublas::vector<double>,
97  boost::numeric::ublas::vector<size_t> > {
98 
99  public:
100 
103  typedef boost::numeric::ublas::range range;
104  typedef boost::numeric::ublas::vector_range<ubvector> ubvector_range;
105  typedef boost::numeric::ublas::vector_range<ubvector_size_t>
106  ubvector_size_t_range;
107 
108 #ifndef DOXYGEN_INTERNAL
109 
110  protected:
111 
112  /// A rank-sized set of arrays for the grid points
114 
115  /// If true, the grid has been set by the user
116  bool grid_set;
117 
118  /// Interpolation type
119  size_t itype;
120 
121  /// Return a reference to the data (for HDF I/O)
123  return data;
124  }
125 
126 #endif
127 
128  public:
129 
130  /// Create an empty tensor with zero rank
132  grid_set=false;
134  }
135 
136  /** \brief Create a tensor of rank \c rank with sizes given in \c dim
137 
138  The parameter \c dim must be a vector of sizes with length \c
139  rank. If the user requests any of the sizes to be zero, this
140  constructor will call the error handler.
141  */
142  template<class size_vec_t>
143  tensor_grid(size_t rank, const size_vec_t &dim) :
144  tensor<ubvector,ubvector_size_t>(rank,dim) {
145  grid_set=false;
147  // Note that the parent method sets rk to be equal to rank
148  for(size_t i=0;i<rk;i++) {
149  if (dim[i]==0) {
150  O2SCL_ERR((((std::string)"Requested zero size with non-zero ")+
151  "rank for index "+szttos(i)+" in tensor_grid::"+
152  "tensor_grid(size_t,size_vec_t)").c_str(),
153  exc_einval);
154  }
155  }
156  }
157 
158  virtual ~tensor_grid() {
159  }
160 
161  /// \name Set functions
162  //@{
163  /// Set the element closest to grid point \c grdp to value \c val
164  template<class vec_t>
165  void set_val(const vec_t &grdp, double val) {
166 
167  // Find indices
168  ubvector_size_t index(rk);
169  for(size_t i=0;i<rk;i++) {
170  index[i]=lookup_grid(i,grdp[i]);
171  }
172 
173  // Pack
174  size_t ix=index[0];
175  for(size_t i=1;i<rk;i++) {
176  ix*=size[i];
177  ix+=index[i];
178  }
179 
180  // Set value
181  data[ix]=val;
182 
183  return;
184  }
185 
186  /** \brief Set the element closest to grid point \c grdp to value
187  \c val
188 
189  The parameters \c closest and \c grdp may be identical,
190  allowing one to update a vector \c grdp with the
191  closest grid point.
192  */
193  template<class vec_t, class vec2_t>
194  void set_val(const vec_t &grdp, double val, vec2_t &closest) {
195 
196  // Find indices
197  ubvector_size_t index(rk);
198  for(size_t i=0;i<rk;i++) {
199  index[i]=lookup_grid_val(i,grdp[i],closest[i]);
200  }
201 
202  // Pack
203  size_t ix=index[0];
204  for(size_t i=1;i<rk;i++) {
205  ix*=size[i];
206  ix+=index[i];
207  }
208 
209  // Set value
210  data[ix]=val;
211 
212  return;
213  }
214  //@}
215 
216  /// \name Get functions
217  //@{
218  /// Get the element closest to grid point \c grdp
219  template<class vec_t> double get_val(const vec_t &grdp) {
220 
221  // Find indices
222  ubvector_size_t index(rk);
223  for(size_t i=0;i<rk;i++) {
224  index[i]=lookup_grid(i,grdp[i]);
225  }
226 
227  // Pack
228  size_t ix=index[0];
229  for(size_t i=1;i<rk;i++) {
230  ix*=size[i];
231  ix+=index[i];
232  }
233 
234  // Set value
235  return data[ix];
236  }
237 
238  /** \brief Get the element closest to grid point \c grdp to
239  value \c val
240 
241  The parameters \c grdp and \c closest may refer to the
242  same object.
243  */
244  template<class vec_t, class vec2_t>
245  double get_val(const vec_t &grdp, vec2_t &closest) {
246 
247  // Find indices
248  ubvector_size_t index(rk);
249  for(size_t i=0;i<rk;i++) {
250  index[i]=lookup_grid_val(i,grdp[i],closest[i]);
251  }
252 
253  // Pack
254  size_t ix=index[0];
255  for(size_t i=1;i<rk;i++) {
256  ix*=size[i];
257  ix+=index[i];
258  }
259 
260  // Set value
261  return data[ix];
262  }
263  //@}
264 
265  /// \name Resize method
266  //@{
267  /** \brief Resize the tensor to rank \c rank with sizes
268  given in \c dim
269 
270  The parameter \c dim must be a vector of sizes with a length
271  equal to \c rank. This resize method is always destructive,
272  and the grid is always reset.
273 
274  If the user requests any of the sizes to be zero, this
275  function will call the error handler.
276  */
277  template<class size_vec_t>
278  void resize(size_t rank, const size_vec_t &dim) {
279  // Double check that none of the sizes that the user
280  // specified are zero
281  for(size_t i=0;i<rank;i++) {
282  if (dim[i]==0) {
283  O2SCL_ERR((((std::string)"Requested zero size with non-zero ")+
284  "rank for index "+szttos(i)+" in tensor_grid::"+
285  "resize().").c_str(),exc_einval);
286  }
287  }
288  // Set the new rank
289  rk=rank;
290  // Resize the size vector
291  size.resize(rk);
292  // Reset the grid
293  grid_set=false;
294  grid.resize(0);
295  // If the new rank is zero, reset the data, otherwise,
296  // update the size vector and reset the data vector
297  if (rank==0) {
298  data.resize(0);
299  return;
300  } else {
301  size_t tot=1;
302  for(size_t i=0;i<rk;i++) {
303  size[i]=dim[i];
304  tot*=size[i];
305  }
306  data.resize(tot);
307  }
308  return;
309  }
310 
311  //@}
312 
313  /// \name Grid manipulation
314  //@{
315  /// Return true if the grid has been set
316  bool is_grid_set() const { return grid_set; }
317 
318  /** \brief Set the grid
319 
320  The grid must be specified for all of the dimensions at
321  once. Denote \f$ (\mathrm{size})_0 \f$ as the size
322  of the first dimension, \f$ (\mathrm{size})_1 \f$ as the
323  size of the second dimesion, and so on. Then the
324  first \f$ (\mathrm{size})_0 \f$ entries in \c grid must
325  be the grid for the first dimension, the next
326  \f$ (\mathrm{size})_1 \f$ entries must be the grid
327  for the second dimension, and so on. Thus \c grid
328  must be a vector of size
329  \f[
330  \sum_{i=0}^{\mathrm{rank}} (\mathrm{size})_i
331  \f]
332 
333  Note that the grid is copied so the function argument may
334  be destroyed by the user after calling set_grid_packed() without
335  affecting the tensor grid.
336 
337  \future Define a more generic interface for matrix types
338  */
339  template<class vec_t>
340  void set_grid_packed(const vec_t &grid_vec) {
341  if (rk==0) {
342  O2SCL_ERR2("Tried to set grid for empty tensor in ",
343  "tensor_grid::set_grid_packed().",exc_einval);
344  }
345  size_t ngrid=0;
346  for(size_t i=0;i<rk;i++) ngrid+=size[i];
347  grid.resize(ngrid);
348  for(size_t i=0;i<ngrid;i++) {
349  grid[i]=grid_vec[i];
350  }
351  grid_set=true;
352  return;
353  }
354 
355  /** \brief Set grid from a vector of vectors of grid points
356  */
357  template<class vec_vec_t>
358  void set_grid(const vec_vec_t &grid_vecs) {
359  if (rk==0) {
360  O2SCL_ERR2("Tried to set grid for empty tensor in ",
361  "tensor_grid::set_grid().",exc_einval);
362  }
363  size_t ngrid=0;
364  for(size_t i=0;i<rk;i++) ngrid+=size[i];
365  grid.resize(ngrid);
366  size_t k=0;
367  for(size_t i=0;i<rk;i++) {
368  for(size_t j=0;j<size[i];j++) {
369  grid[k]=grid_vecs[i][j];
370  k++;
371  }
372  }
373  grid_set=true;
374  return;
375  }
376 
377  /// Lookup jth value on the ith grid
378  double get_grid(size_t i, size_t j) const {
379  if (!grid_set) {
380  O2SCL_ERR("Grid not set in tensor_grid::get_grid().",
381  exc_einval);
382  }
383  if (i>=rk) {
384  O2SCL_ERR((((std::string)"Index ")+szttos(i)+
385  " greater than or equal to rank, "+szttos(rk)+
386  ", in tensor_grid::get_grid().").c_str(),
387  exc_einval);
388  }
389  size_t istart=0;
390  for(size_t k=0;k<i;k++) istart+=size[k];
391  return grid[istart+j];
392  }
393 
394  /// Set the jth value on the ith grid
395  void set_grid(size_t i, size_t j, double val) {
396  if (!grid_set) {
397  O2SCL_ERR("Grid not set in tensor_grid::get_grid().",
398  exc_einval);
399  }
400  if (i>=rk) {
401  O2SCL_ERR((((std::string)"Index ")+szttos(i)+
402  " greater than or equal to rank, "+szttos(rk)+
403  ", in tensor_grid::get_grid().").c_str(),
404  exc_einval);
405  }
406  size_t istart=0;
407  for(size_t k=0;k<i;k++) istart+=size[k];
408  grid[istart+j]=val;
409  return;
410  }
411 
412  /// Lookup index for grid closest to \c val
413  size_t lookup_grid(size_t i, double val) {
414  if (!grid_set) {
415  O2SCL_ERR("Grid not set in tensor_grid::lookup_grid().",
416  exc_einval);
417  }
418  if (i>=rk) {
419  O2SCL_ERR((((std::string)"Index ")+szttos(i)+
420  " greater than or equal to rank, "+szttos(rk)+
421  ", in tensor_grid::lookup_grid().").c_str(),
422  exc_einval);
423  }
424  size_t istart=0;
425 
426  for(size_t j=0;j<i;j++) {
427  istart+=size[j];
428  }
429  size_t best=istart;
430  double min=fabs(grid[istart]-val);
431  for(size_t j=istart;j<istart+size[i];j++) {
432  if (fabs(grid[j]-val)<min) {
433  best=j;
434  min=fabs(grid[j]-val);
435  }
436  }
437  return best-istart;
438  }
439 
440  /** \brief Lookup indices for grid closest point to \c vals
441 
442  The values in \c vals are not modified by this function.
443 
444  \comment
445  This function must have a different name than
446  lookup_grid() because the template types cause
447  confusion between the two functions.
448  \endcomment
449  */
450  template<class vec_t, class size_vec_t>
451  void lookup_grid_vec(const vec_t &vals, size_vec_t &indices) const {
452  for(size_t k=0;k<rk;k++) {
453  indices[k]=lookup_grid(k,vals[k]);
454  }
455  return;
456  }
457 
458  /** \brief Lookup index for grid closest to \c val, returning the
459  grid point
460 
461  The parameters \c val and \c val2 may refer to the
462  same object.
463  */
464  size_t lookup_grid_val(size_t i, const double &val, double &val2) {
465  if (i>=rk) {
466  O2SCL_ERR((((std::string)"Index ")+szttos(i)+
467  " greater than or equal to rank, "+szttos(rk)+
468  ", in tensor_grid::lookup_grid_val().").c_str(),
469  exc_einval);
470  }
471  if (grid_set==false) {
472  O2SCL_ERR("Grid not set in tensor_grid::lookup_grid_val().",
473  exc_einval);
474  }
475  size_t istart=0;
476  for(size_t j=0;j<i;j++) istart+=size[j];
477  size_t best=istart;
478  double min=fabs(grid[istart]-val);
479  val2=grid[istart];
480  for(size_t j=istart;j<istart+size[i];j++) {
481  if (fabs(grid[j]-val)<min) {
482  best=j;
483  min=fabs(grid[j]-val);
484  val2=grid[j];
485  }
486  }
487  return best-istart;
488  }
489 
490  /// Lookup index for grid closest to \c val
491  size_t lookup_grid_packed(size_t i, double val) {
492  if (!grid_set) {
493  O2SCL_ERR("Grid not set in tensor_grid::lookup_grid_packed().",
494  exc_einval);
495  }
496  if (i>=rk) {
497  O2SCL_ERR((((std::string)"Index ")+szttos(i)+" greater than rank, "+
498  szttos(rk)+
499  ", in tensor_grid::lookup_grid_packed().").c_str(),
500  exc_einval);
501  }
502  size_t istart=0;
503  for(size_t j=0;j<i;j++) istart+=size[j];
504  size_t best=istart;
505  double min=fabs(grid[istart]-val);
506  for(size_t j=istart;j<istart+size[i];j++) {
507  if (fabs(grid[j]-val)<min) {
508  best=j;
509  min=fabs(grid[j]-val);
510  }
511  }
512  return best;
513  }
514 
515  /// Lookup index for grid closest to \c val
516  size_t lookup_grid_packed_val(size_t i, double val, double &val2) {
517  if (!grid_set) {
518  O2SCL_ERR("Grid not set in tensor_grid::lookup_grid_packed().",
519  exc_einval);
520  }
521  if (i>=rk) {
522  O2SCL_ERR((((std::string)"Index ")+szttos(i)+" greater than rank, "+
523  szttos(rk)+
524  ", in tensor_grid::lookup_grid_packed().").c_str(),
525  exc_einval);
526  }
527  size_t istart=0;
528  for(size_t j=0;j<i;j++) istart+=size[j];
529  size_t best=istart;
530  double min=fabs(grid[istart]-val);
531  val2=grid[istart];
532  for(size_t j=istart;j<istart+size[i];j++) {
533  if (fabs(grid[j]-val)<min) {
534  best=j;
535  min=fabs(grid[j]-val);
536  val2=grid[j];
537  }
538  }
539  return best;
540  }
541  //@}
542 
543  /// \name Slicing
544  //@{
545  /** \brief Create a slice in a table3d object with an aligned
546  grid
547 
548  This function uses the grid associated with indices \c ix_x
549  and \c ix_y, and the tensor interpolation function to copy to
550  the slice named \c slice_name in the table3d object \c tab .
551 
552  If the table3d object does not currently have a grid set, then
553  the grid is automatically set to be the same as that stored in
554  the tensor_grid object associated with ranks \c ix_x and \c
555  iy_y. If the \ref o2scl::table3d object does have a grid set,
556  then the values returned by \ref o2scl::table3d::get_nx() and
557  \ref o2scl::table3d::get_ny() must be equal to the size of the
558  tensor in indices \c ix_x and ix_y, respectively.
559 
560  This currently requires a copy of all the tensor data
561  into the table3d object.
562  */
563  template<class size_vec_t>
564  void copy_slice_align(size_t ix_x, size_t ix_y, size_vec_t &index,
565  table3d &tab, std::string slice_name) {
566 
567  if (ix_x>=rk || ix_y>=rk || ix_x==ix_y) {
568  O2SCL_ERR2("Either indices greater than rank or x and y ind",
569  "ices equal in tensor_grid::copy_slice_align().",
570  exc_efailed);
571  }
572 
573  // Get current table3d grid
574  size_t nx, ny;
575  tab.get_size(nx,ny);
576 
577  if (nx==0 && ny==0) {
578 
579  // If there's no grid, just create it
580  std::vector<double> gx, gy;
581  for(size_t i=0;i<size[ix_x];i++) {
582  gx.push_back(this->get_grid(ix_x,i));
583  }
584  for(size_t i=0;i<size[ix_y];i++) {
585  gy.push_back(this->get_grid(ix_y,i));
586  }
587  nx=gx.size();
588  ny=gy.size();
589  tab.set_xy("x",nx,gx,"y",ny,gy);
590  }
591 
592  // Check that the grids are commensurate
593  if (nx!=size[ix_x] || ny!=size[ix_y]) {
594  O2SCL_ERR2("Grids not commensurate in ",
595  "tensor_grid::copy_slice_align().",exc_einval);
596  }
597 
598  // Create slice if not already present
599  size_t is;
600  if (!tab.is_slice(slice_name,is)) tab.new_slice(slice_name);
601 
602  // Copy over data
603  for(size_t i=0;i<nx;i++) {
604  for(size_t j=0;j<ny;j++) {
605  index[ix_x]=i;
606  index[ix_y]=j;
607  double val=this->get(index);
608  tab.set(i,j,slice_name,val);
609  }
610  }
611 
612  return;
613  }
614 
615  /** \brief Copy to a slice in a table3d object using interpolation
616 
617  This function uses the grid associated with indices \c ix_x
618  and \c ix_y, and the tensor interpolation function to copy the
619  tensor information to the slice named \c slice_name in the
620  table3d object \c tab .
621 
622  \note This function uses the \ref tensor_grid::interp_linear()
623  for the interpolation.
624  */
625  template<class size_vec_t>
626  void copy_slice_interp(size_t ix_x, size_t ix_y, size_vec_t &index,
627  table3d &tab, std::string slice_name) {
628 
629  if (ix_x>=rk || ix_y>=rk || ix_x==ix_y) {
630  O2SCL_ERR2("Either indices greater than rank or x and y ",
631  "indices equal in tensor_grid::copy_slice_interp().",
632  exc_efailed);
633  }
634 
635  // Get current table3d grid
636  size_t nx, ny;
637  tab.get_size(nx,ny);
638 
639  if (nx==0 && ny==0) {
640  // If there's no grid, then just use the aligned version
641  return copy_slice_align(ix_x,ix_y,index,tab,slice_name);
642  }
643 
644  // Create vector of values to interpolate with
645  std::vector<double> vals(rk);
646  for(size_t i=0;i<rk;i++) {
647  if (i!=ix_x && i!=ix_y) vals[i]=this->get_grid(i,index[i]);
648  }
649 
650  // Create slice if not already present
651  size_t is;
652  if (!tab.is_slice(slice_name,is)) tab.new_slice(slice_name);
653 
654  // Loop through the table grid to perform the interpolation
655  for(size_t i=0;i<nx;i++) {
656  for(size_t j=0;j<ny;j++) {
657  vals[ix_x]=tab.get_grid_x(i);
658  vals[ix_y]=tab.get_grid_y(j);
659  tab.set(i,j,slice_name,this->interp_linear(vals));
660  }
661  }
662 
663  return;
664  }
665  //@}
666 
667  /// \name Interpolation
668  //@{
669  /// Set interpolation type
670  void set_interp_type(size_t interp_type) {
671  itype=interp_type;
672  return;
673  }
674 
675  /** \brief Interpolate values \c vals into the tensor,
676  returning the result
677 
678  \warning This is being deprecated and may be removed
679  or completely rewritten in later versions.
680 
681  This is a quick and dirty implementation of n-dimensional
682  interpolation by recursive application of the 1-dimensional
683  routine from \ref interp_vec, using the base
684  interpolation object specified in the template parameter \c
685  base_interp_t. This will be slow for sufficiently large data
686  sets.
687 
688  \future Maybe make this a template as well?
689 
690  \future It should be straightforward to improve the scaling of
691  this algorithm significantly by creating a "window" of local
692  points around the point of interest. This could be done easily
693  by constructing an initial subtensor. However, this should
694  probably be superceded by a more generic alternative which
695  avoids explicit use of the 1-d interpolation types.
696  */
697  double interpolate(double *vals) {
698 
699  typedef interp_vec<ubvector> interp_t;
700 
701  if (rk==1) {
702 
703  interp_t si(size[0],grid,data,itype);
704  return si.eval(vals[0]);
705 
706  } else {
707 
708  // Get total number of interpolations at this level
709  size_t ss=1;
710  for(size_t i=1;i<rk;i++) ss*=size[i];
711 
712  // Create space for y vectors and interpolators
713  std::vector<ubvector> yvec(ss);
714  std::vector<interp_t *> si(ss);
715  for(size_t i=0;i<ss;i++) {
716  yvec[i].resize(size[0]);
717  }
718 
719  // Create space for interpolation results
720  tensor_grid tdat;
721  ubvector_size_t_range size_new(size,range(1,rk));
722  tdat.resize(rk-1,size_new);
723 
724  // Set grid for temporary tensor
725  ubvector_range grid_new(grid,range(size[0],grid.size()));
726  tdat.set_grid_packed(grid_new);
727 
728  // Create starting coordinate and counter
729  ubvector_size_t co(rk);
730  for(size_t i=0;i<rk;i++) co[i]=0;
731  size_t cnt=0;
732 
733  // Loop over every interpolation
734  bool done=false;
735  while(done==false) {
736 
737  // Fill yvector with the appropriate data
738  for(size_t i=0;i<size[0];i++) {
739  co[0]=i;
740  yvec[cnt][i]=get(co);
741  }
742 
743  si[cnt]=new interp_t(size[0],grid,yvec[cnt],itype);
744 
745  ubvector_size_t_range co2(co,range(1,rk));
746  tdat.set(co2,si[cnt]->eval(vals[0]));
747 
748  // Go to next interpolation
749  cnt++;
750  co[rk-1]++;
751  // carry if necessary
752  for(int j=((int)rk)-1;j>0;j--) {
753  if (co[j]>=size[j]) {
754  co[j]=0;
755  co[j-1]++;
756  }
757  }
758 
759  // Test if done
760  if (cnt==ss) done=true;
761 
762  // End of while loop
763  }
764 
765  // Now call the next level of interpolation
766  double res=tdat.interpolate(vals+1);
767 
768  for(size_t i=0;i<ss;i++) {
769  delete si[i];
770  }
771 
772  return res;
773  }
774  }
775 
776  /** \brief Perform a linear interpolation of \c v into the
777  function implied by the tensor and grid
778 
779  This performs multi-dimensional linear interpolation (or
780  extrapolation) It works by first using \ref o2scl::search_vec
781  to find the interval containing (or closest to) the specified
782  point in each direction and constructing the corresponding
783  hypercube of size \f$ 2^{\mathrm{rank}} \f$ containing \c v.
784  It then calls \ref interp_linear_power_two() to perform the
785  interpolation in that hypercube.
786  */
787  template<class vec2_t> double interp_linear(vec2_t &v) {
788 
789  // Find the the corner of the hypercube containing v
790  size_t rgs=0;
791  std::vector<size_t> loc(rk);
792  std::vector<double> gnew;
793  for(size_t i=0;i<rk;i++) {
794  std::vector<double> grid_unpacked(size[i]);
795  for(size_t j=0;j<size[i];j++) {
796  grid_unpacked[j]=grid[j+rgs];
797  }
798  search_vec<std::vector<double> > sv(size[i],grid_unpacked);
799  loc[i]=sv.find(v[i]);
800  gnew.push_back(grid_unpacked[loc[i]]);
801  gnew.push_back(grid_unpacked[loc[i]+1]);
802  rgs+=size[i];
803  }
804 
805  // Now construct a 2^{rk}-sized tensor containing only that
806  // hypercube
807  std::vector<size_t> snew(rk);
808  for(size_t i=0;i<rk;i++) {
809  snew[i]=2;
810  }
811  tensor_grid tnew(rk,snew);
812  tnew.set_grid_packed(gnew);
813 
814  // Copy over the relevant data
815  for(size_t i=0;i<tnew.total_size();i++) {
816  std::vector<size_t> index_new(rk), index_old(rk);
817  tnew.unpack_indices(i,index_new);
818  for(size_t j=0;j<rk;j++) index_old[j]=index_new[j]+loc[j];
819  tnew.set(index_new,get(index_old));
820  }
821 
822  // Now use interp_power_two()
823  return tnew.interp_linear_power_two(v);
824  }
825 
826  /** \brief Perform linear interpolation assuming that all
827  indices can take only two values
828 
829  This function works by recursively slicing the hypercube of
830  size \f$ 2^{\mathrm{rank}} \f$ into a hypercube of size \f$
831  2^{\mathrm{rank-1}} \f$ performing linear interpolation for
832  each pair of points.
833  */
834  template<class vec2_t> double interp_linear_power_two(vec2_t &v) {
835 
836  if (rk==1) {
837  return data[0]+(data[1]-data[0])/(grid[1]-grid[0])*(v[0]-grid[0]);
838  }
839 
840  size_t last=rk-1;
841  double frac=(v[last]-get_grid(last,0))/
842  (get_grid(last,1)-get_grid(last,0));
843 
844  // Create new size vector and grid
845  tensor_grid tnew(rk-1,size);
846  tnew.set_grid_packed(grid);
847 
848  // Create data in new tensor, removing the last index through
849  // linear interpolation
850  for(size_t i=0;i<tnew.total_size();i++) {
851  std::vector<size_t> index(rk);
852  tnew.unpack_indices(i,index);
853  index[rk-1]=0;
854  double val_lo=get(index);
855  index[rk-1]=1;
856  double val_hi=get(index);
857  tnew.set(index,val_lo+frac*(val_hi-val_lo));
858  }
859 
860  // Recursively interpolate the smaller tensor
861  return tnew.interp_linear_power_two(v);
862  }
863  //@}
864 
865  friend void o2scl_hdf::hdf_output(o2scl_hdf::hdf_file &hf, tensor_grid &t,
866  std::string name);
867 
869  std::string name);
870 
871  };
872 
873  /** \brief Rank 1 tensor with a grid
874 
875  \future Make rank-specific get_val and set_val functions?
876  */
877  class tensor_grid1 : public tensor_grid {
878 
879  public:
880 
881  /// Create an empty tensor
883 
884  /// Create a rank 2 tensor of size \c (sz,sz2,sz3)
885  tensor_grid1(size_t sz) : tensor_grid() {
886  this->rk=1;
887  this->size.resize(1);
888  this->size[0]=sz;
889  this->data.resize(sz);
890  this->grid_set=false;
891  }
892 
893  virtual ~tensor_grid1() {
894  }
895 
896  /// Get the element indexed by \c (ix1)
897  double &get(size_t ix1) {
898  size_t sz[1]={ix1};
899  return tensor_grid::get(sz);
900  }
901 
902  /// Get the element indexed by \c (ix1)
903  const double &get(size_t ix1) const {
904  size_t sz[1]={ix1};
905  return tensor_grid::get(sz);
906  }
907 
908  /// Set the element indexed by \c (ix1) to value \c val
909  void set(size_t ix1, double val) {
910  size_t sz[1]={ix1};
911  tensor_grid::set(sz,val);
912  }
913 
914  /// Interpolate \c x and return the results
915  double interp(double x) {
916  return interpolate(&x);
917  }
918 
919  /// Interpolate \c x and return the results
920  double interp_linear(double x) {
921  double arr[1]={x};
922  return tensor_grid::interp_linear(arr);
923  }
924  };
925 
926  /** \brief Rank 2 tensor with a grid
927  */
928  class tensor_grid2 : public tensor_grid {
929 
930  public:
931 
932  /// Create an empty tensor
934 
935  /// Create a rank 2 tensor of size \c (sz,sz2)
936  tensor_grid2(size_t sz, size_t sz2) : tensor_grid() {
937  this->rk=2;
938  this->size.resize(2);
939  this->size[0]=sz;
940  this->size[1]=sz2;
941  size_t tot=sz*sz2;
942  this->data.resize(tot);
943  this->grid_set=false;
944  }
945 
946  virtual ~tensor_grid2() {
947  }
948 
949  /// Get the element indexed by \c (ix1,ix2)
950  double &get(size_t ix1, size_t ix2) {
951  size_t sz[2]={ix1,ix2};
952  return tensor_grid::get(sz);
953  }
954 
955  /// Get the element indexed by \c (ix1,ix2)
956  const double &get(size_t ix1, size_t ix2) const {
957  size_t sz[2]={ix1,ix2};
958  return tensor_grid::get(sz);
959  }
960 
961  /// Set the element indexed by \c (ix1,ix2) to value \c val
962  void set(size_t ix1, size_t ix2, double val) {
963  size_t sz[2]={ix1,ix2};
964  tensor_grid::set(sz,val);
965  return;
966  }
967 
968  /// Interpolate \c (x,y) and return the results
969  double interp(double x, double y) {
970  double arr[2]={x,y};
971  return interpolate(arr);
972  }
973 
974  /// Interpolate \c (x,y) and return the results
975  double interp_linear(double x, double y) {
976  double arr[2]={x,y};
977  return tensor_grid::interp_linear(arr);
978  }
979  };
980 
981  /** \brief Rank 3 tensor with a grid
982  */
983  class tensor_grid3 : public tensor_grid {
984 
985  public:
986 
987  /// Create an empty tensor
989 
990  /// Create a rank 3 tensor of size \c (sz,sz2,sz3)
991  tensor_grid3(size_t sz, size_t sz2, size_t sz3) : tensor_grid () {
992  this->rk=3;
993  this->size.resize(3);
994  this->size[0]=sz;
995  this->size[1]=sz2;
996  this->size[2]=sz3;
997  size_t tot=sz*sz2*sz3;
998  this->data.resize(tot);
999  this->grid_set=false;
1000  }
1001 
1002  virtual ~tensor_grid3() {
1003  }
1004 
1005  /// Get the element indexed by \c (ix1,ix2,ix3)
1006  double &get(size_t ix1, size_t ix2, size_t ix3) {
1007  size_t sz[3]={ix1,ix2,ix3};
1008  return tensor_grid::get(sz);
1009  }
1010 
1011  /// Get the element indexed by \c (ix1,ix2,ix3)
1012  const double &get(size_t ix1, size_t ix2, size_t ix3) const {
1013  size_t sz[3]={ix1,ix2,ix3};
1014  return tensor_grid::get(sz);
1015  }
1016 
1017  /// Set the element indexed by \c (ix1,ix2,ix3) to value \c val
1018  void set(size_t ix1, size_t ix2, size_t ix3, double val) {
1019  size_t sz[3]={ix1,ix2, ix3};
1020  tensor_grid::set(sz,val);
1021  return;
1022  }
1023 
1024  /// Interpolate \c (x,y,z) and return the results
1025  double interp(double x, double y, double z) {
1026  double arr[3]={x,y,z};
1027  return interpolate(arr);
1028  }
1029 
1030  /// Interpolate \c (x,y,z) and return the results
1031  double interp_linear(double x, double y, double z) {
1032  double arr[3]={x,y,z};
1033  return tensor_grid::interp_linear(arr);
1034  }
1035  };
1036 
1037  /** \brief Rank 4 tensor with a grid
1038  */
1039  class tensor_grid4 : public tensor_grid {
1040 
1041  public:
1042 
1043  /// Create an empty tensor
1045 
1046  /// Create a rank 4 tensor of size \c (sz,sz2,sz3,sz4)
1047  tensor_grid4(size_t sz, size_t sz2, size_t sz3,
1048  size_t sz4) : tensor_grid () {
1049  this->rk=4;
1050  this->size.resize(4);
1051  this->size[0]=sz;
1052  this->size[1]=sz2;
1053  this->size[2]=sz3;
1054  this->size[3]=sz4;
1055  size_t tot=sz*sz2*sz3*sz4;
1056  this->data.resize(tot);
1057  this->grid_set=false;
1058  }
1059 
1060  virtual ~tensor_grid4() {
1061  }
1062 
1063  /// Get the element indexed by \c (ix1,ix2,ix3,ix4)
1064  double &get(size_t ix1, size_t ix2, size_t ix3, size_t ix4) {
1065  size_t sz[4]={ix1,ix2,ix3,ix4};
1066  return tensor_grid::get(sz);
1067  }
1068 
1069  /// Get the element indexed by \c (ix1,ix2,ix3,ix4)
1070  const double &get(size_t ix1, size_t ix2, size_t ix3,
1071  size_t ix4) const {
1072  size_t sz[4]={ix1,ix2,ix3,ix4};
1073  return tensor_grid::get(sz);
1074  }
1075 
1076  /// Set the element indexed by \c (ix1,ix2,ix3,ix4) to value \c val
1077  void set(size_t ix1, size_t ix2, size_t ix3, size_t ix4,
1078  double val) {
1079  size_t sz[4]={ix1,ix2,ix3,ix4};
1080  tensor_grid::set(sz,val);
1081  return;
1082  }
1083 
1084  /// Interpolate \c (x,y,z,a) and return the results
1085  double interp(double x, double y, double z, double a) {
1086  double arr[4]={x,y,z,a};
1087  return interpolate(arr);
1088  }
1089 
1090  /// Interpolate \c (x,y,z,a) and return the results
1091  double interp_linear(double x, double y, double z, double a) {
1092  double arr[4]={x,y,z,a};
1093  return tensor_grid::interp_linear(arr);
1094  }
1095  };
1096 
1097 #ifndef DOXYGEN_NO_O2NS
1098 }
1099 #endif
1100 
1101 #endif
1102 
1103 
1104 
tensor_grid1(size_t sz)
Create a rank 2 tensor of size (sz,sz2,sz3)
Definition: tensor_grid.h:885
ubvector grid
A rank-sized set of arrays for the grid points.
Definition: tensor_grid.h:113
bool is_grid_set() const
Return true if the grid has been set.
Definition: tensor_grid.h:316
Interpolation class for pre-specified vector.
Definition: interp.h:1420
Tensor class with arbitrary dimensions with a grid.
Definition: tensor_grid.h:95
void hdf_output(hdf_file &hf, o2scl::tensor_grid &t, std::string name)
Output a o2scl::tensor_grid object to a hdf_file.
tensor_grid4()
Create an empty tensor.
Definition: tensor_grid.h:1044
double get_val(const vec_t &grdp, vec2_t &closest)
Get the element closest to grid point grdp to value val.
Definition: tensor_grid.h:245
Rank 1 tensor with a grid.
Definition: tensor_grid.h:877
bool is_slice(std::string name, size_t &ix) const
Return true if slice is already present.
double interp_linear(double x, double y, double z, double a)
Interpolate (x,y,z,a) and return the results.
Definition: tensor_grid.h:1091
double get_val(const vec_t &grdp)
Get the element closest to grid point grdp.
Definition: tensor_grid.h:219
void copy_slice_align(size_t ix_x, size_t ix_y, size_vec_t &index, table3d &tab, std::string slice_name)
Create a slice in a table3d object with an aligned grid.
Definition: tensor_grid.h:564
tensor_grid3(size_t sz, size_t sz2, size_t sz3)
Create a rank 3 tensor of size (sz,sz2,sz3)
Definition: tensor_grid.h:991
size_t lookup_grid_val(size_t i, const double &val, double &val2)
Lookup index for grid closest to val, returning the grid point.
Definition: tensor_grid.h:464
double get_grid(size_t i, size_t j) const
Lookup jth value on the ith grid.
Definition: tensor_grid.h:378
double get_grid_x(size_t ix)
Get x grid point at index ix.
tensor_grid(size_t rank, const size_vec_t &dim)
Create a tensor of rank rank with sizes given in dim.
Definition: tensor_grid.h:143
invalid argument supplied by user
Definition: err_hnd.h:59
tensor_grid2(size_t sz, size_t sz2)
Create a rank 2 tensor of size (sz,sz2)
Definition: tensor_grid.h:936
size_t lookup_grid_packed(size_t i, double val)
Lookup index for grid closest to val.
Definition: tensor_grid.h:491
tensor_grid4(size_t sz, size_t sz2, size_t sz3, size_t sz4)
Create a rank 4 tensor of size (sz,sz2,sz3,sz4)
Definition: tensor_grid.h:1047
Rank 2 tensor with a grid.
Definition: tensor_grid.h:928
void set(size_t ix1, size_t ix2, size_t ix3, size_t ix4, double val)
Set the element indexed by (ix1,ix2,ix3,ix4) to value val.
Definition: tensor_grid.h:1077
double interp_linear(double x, double y, double z)
Interpolate (x,y,z) and return the results.
Definition: tensor_grid.h:1031
void set_val(const vec_t &grdp, double val, vec2_t &closest)
Set the element closest to grid point grdp to value val.
Definition: tensor_grid.h:194
void set_grid(size_t i, size_t j, double val)
Set the jth value on the ith grid.
Definition: tensor_grid.h:395
generic failure
Definition: err_hnd.h:61
tensor_grid1()
Create an empty tensor.
Definition: tensor_grid.h:882
Rank 3 tensor with a grid.
Definition: tensor_grid.h:983
void lookup_grid_vec(const vec_t &vals, size_vec_t &indices) const
Lookup indices for grid closest point to vals.
Definition: tensor_grid.h:451
double interp_linear(vec2_t &v)
Perform a linear interpolation of v into the function implied by the tensor and grid.
Definition: tensor_grid.h:787
tensor_grid()
Create an empty tensor with zero rank.
Definition: tensor_grid.h:131
tensor_grid3()
Create an empty tensor.
Definition: tensor_grid.h:988
double interp_linear(double x)
Interpolate x and return the results.
Definition: tensor_grid.h:920
void set(const size_vec_t &index, double val)
Set the element indexed by index to value val.
Definition: tensor.h:186
double interp(double x, double y, double z, double a)
Interpolate (x,y,z,a) and return the results.
Definition: tensor_grid.h:1085
#define O2SCL_ERR2(d, d2, n)
Set an error, two-string version.
Definition: err_hnd.h:281
void set_grid(const vec_vec_t &grid_vecs)
Set grid from a vector of vectors of grid points.
Definition: tensor_grid.h:358
double interp_linear_power_two(vec2_t &v)
Perform linear interpolation assuming that all indices can take only two values.
Definition: tensor_grid.h:834
size_t itype
Interpolation type.
Definition: tensor_grid.h:119
void set_val(const vec_t &grdp, double val)
Set the element closest to grid point grdp to value val.
Definition: tensor_grid.h:165
Rank 4 tensor with a grid.
Definition: tensor_grid.h:1039
void get_size(size_t &nx, size_t &ny) const
Get the size of the slices.
double & get(const size_vec_t &index)
Get the element indexed by index.
Definition: tensor.h:227
double interp(double x, double y)
Interpolate (x,y) and return the results.
Definition: tensor_grid.h:969
size_t find(const double x0) const
Search an increasing or decreasing vector for the interval containing x0
Definition: search_vec.h:136
#define O2SCL_ERR(d, n)
Set an error with message d and code n.
Definition: err_hnd.h:273
size_t lookup_grid(size_t i, double val)
Lookup index for grid closest to val.
Definition: tensor_grid.h:413
void set(size_t ix1, double val)
Set the element indexed by (ix1) to value val.
Definition: tensor_grid.h:909
ubvector & get_data()
Return a reference to the data (for HDF I/O)
Definition: tensor_grid.h:122
void unpack_indices(size_t ix, size_vec_t &index)
Unpack the single vector index into indices.
Definition: tensor.h:460
bool grid_set
If true, the grid has been set by the user.
Definition: tensor_grid.h:116
void resize(size_t rank, const size_vec_t &dim)
Resize the tensor to rank rank with sizes given in dim.
Definition: tensor_grid.h:278
void set(size_t ix1, size_t ix2, size_t ix3, double val)
Set the element indexed by (ix1,ix2,ix3) to value val.
Definition: tensor_grid.h:1018
double get_grid_y(size_t iy)
Get y grid point at index iy.
void set(size_t ix, size_t iy, std::string name, double val)
Set element in slice name at location ix,iy to value val.
void set_grid_packed(const vec_t &grid_vec)
Set the grid.
Definition: tensor_grid.h:340
double interp(double x, double y, double z)
Interpolate (x,y,z) and return the results.
Definition: tensor_grid.h:1025
Searching class for monotonic data with caching.
Definition: search_vec.h:78
A data structure containing many slices of two-dimensional data points defined on a grid...
Definition: table3d.h:76
double interp(double x)
Interpolate x and return the results.
Definition: tensor_grid.h:915
void set_interp_type(size_t interp_type)
Set interpolation type.
Definition: tensor_grid.h:670
Store data in an O<span style='position: relative; top: 0.3em; font-size: 0.8em'>2</span>scl O$_2$scl...
Definition: hdf_file.h:93
void new_slice(std::string name)
Add a new slice.
size_t total_size() const
Returns the size of the tensor (the product of the sizes over every index)
Definition: tensor.h:421
size_t lookup_grid_packed_val(size_t i, double val, double &val2)
Lookup index for grid closest to val.
Definition: tensor_grid.h:516
tensor_grid2()
Create an empty tensor.
Definition: tensor_grid.h:933
double interp_linear(double x, double y)
Interpolate (x,y) and return the results.
Definition: tensor_grid.h:975
double interpolate(double *vals)
Interpolate values vals into the tensor, returning the result.
Definition: tensor_grid.h:697
void set_xy(std::string x_name, size_t nx, const vec_t &x, std::string y_name, size_t ny, const vec2_t &y)
Initialize the x-y grid.
Definition: table3d.h:109
std::string szttos(size_t x)
Convert a size_t to a string.
boost::numeric::ublas::vector< size_t > size
A rank-sized vector of the sizes of each dimension.
Definition: tensor.h:133
void hdf_input(hdf_file &hf, o2scl::table< vec_t > &t, std::string name)
Input a o2scl::table object from a hdf_file.
Definition: hdf_io.h:55
Linear.
Definition: interp.h:48
void set(size_t ix1, size_t ix2, double val)
Set the element indexed by (ix1,ix2) to value val.
Definition: tensor_grid.h:962
void copy_slice_interp(size_t ix_x, size_t ix_y, size_vec_t &index, table3d &tab, std::string slice_name)
Copy to a slice in a table3d object using interpolation.
Definition: tensor_grid.h:626
Tensor class with arbitrary dimensions.
Definition: tensor.h:121

Documentation generated with Doxygen. Provided under the GNU Free Documentation License (see License Information).
Hosted at Get Object-oriented Scientific Computing
Lib at SourceForge.net. Fast, secure and Free Open Source software
downloads..