k-dot-p 0.1

cartesian_grid.h++

Go to the documentation of this file.
00001 /*
00002  *
00003 
00004  Copyright (C) 2009 Joseph Pingenot
00005 
00006  This program is free software: you can redistribute it and/or modify
00007  it under the terms of the GNU Affero General Public License as published by
00008  the Free Software Foundation, either version 3 of the License, or
00009  (at your option) any later version.
00010 
00011  This program is distributed in the hope that it will be useful,
00012  but WITHOUT ANY WARRANTY; without even the implied warranty of
00013  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014  GNU Affero General Public License for more details.
00015 
00016  You should have received a copy of the GNU Affero General Public License
00017  along with this program.  If not, see <http://www.gnu.org/licenses/>.
00018 
00019 */
00020 
00021 #ifndef CARTESIAN_GRID_HXX___
00022 #define CARTESIAN_GRID_HXX___
00023 
00024 #include <stdlib.h>
00025 #include <stdio.h>
00026 #include <glib.h>
00027 #include <math.h>
00028 #include <libmodelxx/shapes.h++>
00029 #include <libmodelxx/function_specification.h++>
00030 
00031 namespace kdotp {
00032   namespace libmodelxx {
00033     namespace grid {
00034 
00035 #define CARTESIAN_GRID_GERROR_DOMAIN 309
00036 
00037       char* long_unsigned_to_string(long unsigned* val);
00038 
00039       /**
00040    \var componets: number of pieces of data per grid site
00041    \var T: type of data to store in each grid site.
00042    \var D number of dimensions for the grid.
00043       */
00044       template <typename T, unsigned int D, unsigned int Nc=1>
00045       class cartesian_grid {
00046       public:
00047   /**This function pointer is used to do something at each point,
00048    *  e.g. set a member of the struct at location.
00049    */
00050   typedef GError* (*set_points_callback)(T* location, void* data);
00051 
00052   /**This is a function pointer used whne using a builtin callback, in order to determine the actual value of T from a double-precision value (i.e. the value of the function at that point.
00053    */
00054   typedef GError* (*get_point_value_from_double_callback)(T* location, double* value, int dim, void* data);
00055 
00056   /**This is used to set a location based upon a position-dependent function.
00057    * x is a vector to the location in the global coordinate system
00058    * location is a pointer to the storage at this point
00059    */
00060   typedef GError* (*set_point_function_callback_d)(double* x, int dim, T* location, void* data);
00061   
00062   /**This is used to set a location based upon a position-dependent function.
00063    * X is a vector to the location in grid sites
00064    * location is a pointer to the storage at this point
00065    */
00066   typedef GError* (*set_point_function_callback_i)(unsigned int* X, int dim, T* location, void* data);
00067 
00068   /**This is used when restoring from a buffer (e.g. HDF5)*/
00069   cartesian_grid(const unsigned* box_size, const double* site_length, long unsigned bufflen, const T* data_buffer) {
00070     catesian_grid_init(box_size, site_length, NULL, data_buffer, NULL, 0, NULL);
00071   }
00072   /**This is used when restoring from an indexed grid*/
00073   cartesian_grid(const T* indices, long unsigned n_indices, const cartesian_grid<long unsigned, D, Nc>* indexed_grid) {
00074     catesian_grid_init(indexed_grid->L, indexed_grid->a, NULL, NULL, indices, n_indices, indexed_grid);
00075   }
00076   
00077   cartesian_grid(GList* box_size, GList* site_length, T def_value) {
00078     unsigned ell[D];
00079     double ay[D];
00080     unsigned int d;
00081     GList *b;
00082     GList *a_l;
00083     for(d=0, b=(box_size), a_l=(site_length); d<D; d++, a_l=(a_l->next), b=(b->next)) {
00084       if(b == NULL) {fprintf(stderr, "kdotp::libmodelxx::grid::cartesian_grid::cartesian_grid(const struct grid*): Too few box sizes given for the dimension (gave %d, dimension is =%d). Fix your grid(){} information!\n", d, D); exit(1);}
00085       if(a_l == NULL) {fprintf(stderr, "kdotp::libmodelxx::grid::cartesian_grid::cartesian_grid(const struct grid*): Too few site lengths given for the dimension (gave %d, dimension is =%d). Fix your grid(){} information!\n", d, D); exit(2);}
00086       ell[d] = *(int*)(b->data);
00087       ay[d] = *(double*)(a_l->data);
00088     }
00089     cartesian_grid_init(ell, ay, &def_value, NULL, NULL, 0, NULL);
00090   }
00091 
00092   cartesian_grid(const unsigned* box_size, const double* site_length, T def_value) {
00093     cartesian_grid_init(box_size, site_length, &def_value, NULL, NULL, 0, NULL);
00094   }
00095 
00096   /**This is the central constructor (but an init method) since constructors can't call each other*/
00097   void cartesian_grid_init(const unsigned* box_size, const double* site_length, T* def_value, const T* buffer, const T* indices, long unsigned n_indices, const cartesian_grid<long unsigned, D, Nc>* indexed_grid) {
00098     num_pts = 1;
00099     unsigned int d;
00100     for(d=0; d<D; d++) {
00101       L[d] = box_size[d];
00102       a[d] = site_length[d];
00103       if(a[d] < 0.0) {fprintf(stderr, "kdotp::libmodelxx::grid::cartesian_grid::cartesian_grid_init(const struct grid*): negative site length given (%f) Fix your grid(){} information!\n", a[d]); exit(3);}
00104       if(L[d] < 0) {fprintf(stderr, "kdotp::libmodelxx::grid::cartesian_grid::cartesian_grid_init(const struct grid*): negative box size given (%d) Fix your grid(){} information!\n", L[d]); exit(4);}
00105       num_pts *= L[d];
00106       //fprintf(stderr, "L[%d]=%d num_pts=%lu\n", d, L[d], num_pts);
00107     }
00108     if((indexed_grid != NULL) && (indexed_grid->num_pts != num_pts)) {
00109       fprintf(stderr, "kdotp::libmodelxx::grid::cartesian_grid::cartesian_grid_init(const struct grid*): indexed grid data size (%lu) not the same as the target's size (%lu)\n", indexed_grid->num_pts, num_pts); 
00110       exit(4);
00111     }
00112     data = (T*)malloc(num_pts*Nc*sizeof(T));
00113     /*The grid is now allocated; we now need to set up the structure.*/
00114     for(long unsigned i=0; i<num_pts; i++) {
00115       if(def_value != NULL) {
00116         data[i] = *def_value;
00117       }else if(buffer != NULL) {
00118         data[i] = buffer[i];
00119       }else{
00120         //if(unlikely(indexed_grid->data[i] >= n_indices)) {
00121         if(indexed_grid->data[i] >= n_indices) {
00122     fprintf(stderr, "kdotp::libmodelxx::grid::cartesian_grid::cartesian_grid_init(const struct grid*): invalid index in the index array (%lu)\n", indexed_grid->data[i]); exit(4);
00123         }
00124         data[i] = indices[indexed_grid->data[i]];
00125       }
00126     }
00127     /*Set up ste_x, ste_X, and the respective local symbol tables to save several operations per unit.*/
00128     switch(D) {
00129     case 1:
00130       ste_x.dt=::kdotp::libmodelxx::postprocessing::SCALAR;
00131       break;
00132     case 2:
00133       ste_x.dt=::kdotp::libmodelxx::postprocessing::VECTOR2;
00134       break;
00135     case 3:
00136       ste_x.dt=::kdotp::libmodelxx::postprocessing::VECTOR3;
00137       break;
00138     default:
00139       ste_x.dt=::kdotp::libmodelxx::postprocessing::INVALID;
00140     };
00141     ste_X.dt=ste_x.dt;
00142     ste_x.value = ste_X.value = NULL;
00143     ste_X.st=ste_x.st=::kdotp::libmodelxx::postprocessing::CONSTANT_SYMBOL;
00144     st_x = ::kdotp::libmodelxx::postprocessing::new_symbol_table();
00145     st_X = ::kdotp::libmodelxx::postprocessing::new_symbol_table();
00146     add_symbol_table_entry(st_x, "x", (struct ::kdotp::libmodelxx::postprocessing::symbol_table_entry*)&ste_x);
00147     add_symbol_table_entry(st_X, "X", (struct ::kdotp::libmodelxx::postprocessing::symbol_table_entry*)&ste_X);
00148   }
00149 
00150   /**
00151    *Set all components at the points that are in the shape
00152    *defined by the tree.
00153    *\param st* pointer to the shape tree
00154    *\param spcb callback called at each point.
00155    *\param privdat private data for the callback function.
00156    *\return GError containing the error, if any.
00157    */
00158   struct ezstruct {
00159     set_points_callback spcb;
00160     void* privdat;
00161   };
00162   static GError* set_point_function_callback_d_imp(double* x, int dim, T* location, void* data) {
00163     struct ezstruct* ezs = (struct ezstruct*)data;
00164     return ezs->spcb(location, ezs->privdat);
00165   }
00166   GError* set_points(const struct shape_tree *st, set_points_callback spcb, GHashTable* global_symbols, void* privdat=NULL) {
00167     struct ezstruct ezs = {spcb, privdat};
00168     return set_points(st, &set_point_function_callback_d_imp, NULL, global_symbols, &ezs);
00169   }
00170 
00171   /**This is implemented as a set_point_function callback
00172    * x is the floating-point position
00173    * T is the location to store the value.
00174    * data is a pointer to the callback data struct
00175    */
00176   struct cartesian_set_function_callback_data {
00177     /**The expression (function) to evaluate*/
00178     struct postprocessing::function_exp *exp;
00179     /**This gets called with the return value of the function.
00180      */
00181     get_point_value_from_double_callback cb;
00182     /*Holds the global symbol table*/
00183     GHashTable* global_symbol_table;
00184     GHashTable* local_symbol_table;
00185     struct ::kdotp::libmodelxx::postprocessing::symbol_table_entry_const *ste_x;
00186     /**Private data for the callback function above*/
00187     void* privdat;
00188   };
00189   static GError* set_point_function(double* x, int dee, T* location, void* privdat) {
00190     struct cartesian_set_function_callback_data* d = (struct cartesian_set_function_callback_data*)privdat;
00191     get_point_value_from_double_callback cb = d->cb;
00192     int dim = get_function_datatype(d->exp, ((struct cartesian_set_function_callback_data*)privdat)->global_symbol_table, ((struct cartesian_set_function_callback_data*)privdat)->local_symbol_table);
00193     if(dim < 0) return g_error_new(CARTESIAN_GRID_GERROR_DOMAIN, 200, "kdotp::libkdotp::libmodelxx::grid::cartesian_grid::set_point_function: got invalid dimension from function datatype: %d", dim);
00194     if(dim < 1) dim = 1;
00195     double* value = new double[dim];
00196     GError *e = NULL;
00197     /*Set the x value.*/
00198     ((struct cartesian_set_function_callback_data*)privdat)->ste_x->value = x;
00199     if((e=evaluate_function(value, d->exp, ((struct cartesian_set_function_callback_data*)privdat)->global_symbol_table, ((struct cartesian_set_function_callback_data*)privdat)->local_symbol_table)) != NULL) {
00200       GError *err = NULL;
00201       g_propagate_prefixed_error(&err, e, "kdotp::libkdotp::libmodelxx::grid::cartesian_grid::set_point_function: got error when evaluating function.");
00202       delete[] value;
00203       return err;
00204     }
00205     e= NULL;
00206     e = (*cb)(location, value, dim, d->privdat);
00207     if(e != NULL) {
00208       GError *err = NULL;
00209       g_propagate_prefixed_error(&err, e, "kdotp::libkdotp::libmodelxx::grid::cartesian_grid::set_point_function: got error when setting material.");
00210       delete[] value;
00211       return err;
00212     }
00213     fprintf(stderr, "x=%g->location=%p\n", x[0], (void*)location);
00214     delete[] value;
00215     return NULL;
00216   }
00217   /**
00218    *Set all components at the points that are in the shape
00219    *defined by the tree.
00220    *\param st* pointer to the shape tree
00221    *\param T* pointer to an Nc-size array of values to be set
00222    *\return int with the error code. Needs upgraded to GError.
00223    */
00224   GError* set_points(const struct shape_tree *st, postprocessing::function_exp *exp, GHashTable* global_symbol_table, get_point_value_from_double_callback cb, void* privdat=NULL) {
00225     struct cartesian_set_function_callback_data csf = {exp, cb, global_symbol_table, st_x, &ste_x, privdat};
00226     return set_points(st, &set_point_function, NULL, global_symbol_table, &csf);
00227   }
00228 
00229   GError* set_points(const struct shape_tree *st, set_point_function_callback_d dcb, set_point_function_callback_i icb, GHashTable* global_symbols, void* privdat = NULL) {
00230     /*X is the integer location*/
00231     unsigned int X[D];
00232     /*x is the floating-point location*/
00233     double x[D];
00234     unsigned int d;
00235     for(d=0; d<D; d++) X[d]=0;
00236     /*X[0] is the lowest dimension; X[D-1] is the lowest
00237      *Here's the idea: X can be viewed as an integer number with
00238      *    a digit-dependent basis.  The algorithm:
00239      *1) carry is set to 0 going into the loop
00240      *2) When the counter is updated, carry will be set to 0,
00241      *     unless the last "digit" overflows, in which case carry stays 1.
00242      *3) If carry is still 1 coming out of the X update, we're done.
00243      */
00244     GError *e = NULL;
00245     unsigned int carry=0;
00246     unsigned int c;
00247     while(carry == 0) {
00248       point_index_to_realspace(X, x);
00249       if(point_is_in_tree(x, st, global_symbols)) {
00250         //fprintf(stderr, "Y");
00251         /*Note that this for loop can likely be unrolled.
00252          *The if statement should be compiled out; it'll never
00253          *change at runtime.
00254          */
00255         for(c=0; c<Nc; c++) {
00256     if(Nc == 1) {
00257       if(dcb != NULL) {
00258         e = dcb(x, D, &data[point_index_to_storage_index(X)], privdat);
00259       }else{
00260         e = icb(X, D, &data[point_index_to_storage_index(X)], privdat);
00261       }
00262     }else{
00263       if(dcb != NULL) {
00264         e = dcb(x, D, &data[point_index_to_storage_index(X, c)], privdat);
00265       }else{
00266         e = icb(X, D, &data[point_index_to_storage_index(X, c)], privdat);
00267       }
00268     }
00269     if(e != NULL) {
00270       GError *err = NULL;
00271       GString *s = g_string_new("");
00272       GString *S = g_string_new("");
00273       for(unsigned int i=0; i<D; i++) {
00274         g_string_append_printf(s, " %g", x[i]);
00275         g_string_append_printf(S, " %u", X[i]);
00276       }
00277       g_propagate_prefixed_error(&err, e, "kdotp::libmodeling::grid::cartesian_grid::set_points<full>: Got error evaluating point %s (grid site %s) c=%u: ", s->str, S->str, c);
00278       g_string_free(s, TRUE);
00279       g_string_free(S, TRUE);
00280       return err;
00281     }
00282         }
00283         //}else{
00284         //fprintf(stderr, "N");
00285       }
00286       /*Now update our point.*/
00287       carry=1;
00288       for(d=0; ((d<D)&&(carry==1)); d++) {
00289         //fprintf(stderr, "%d->", X[d]);
00290         X[d] += carry;
00291         //fprintf(stderr, "%d/", X[d]);
00292         if(X[d] >= L[d]) {
00293     X[d] = 0;
00294     carry = 1;
00295         }else{
00296     carry = 0;
00297         }
00298       }
00299       //fprintf(stderr, "\n");
00300     }
00301     return 0;
00302   }
00303 
00304   /*Does something at each point.
00305    *\param callback. Takes unsigned int* (location in grid space) unsigned int* (location in real space), component ,dimensions, location, and private data.
00306    *\param privdat private data for the callback.
00307    *\return GError if error occurred.
00308    */
00309   GError* for_each_point(GError* (*thing_to_do)(unsigned* X, double* x, unsigned c, unsigned dim, T* location, void* privdat), void* privdat=NULL) {
00310     /*X is the integer location*/
00311     unsigned int X[D];
00312     /*x is the floating-point location*/
00313     double x[D];
00314     unsigned int d;
00315     for(d=0; d<D; d++) X[d]=0;
00316     /*X[0] is the lowest dimension; X[D-1] is the lowest
00317      *Here's the idea: X can be viewed as an integer number with
00318      *    a digit-dependent basis.  The algorithm:
00319      *1) carry is set to 0 going into the loop
00320      *2) When the counter is updated, carry will be set to 0,
00321      *     unless the last "digit" overflows, in which case carry stays 1.
00322      *3) If carry is still 1 coming out of the X update, we're done.
00323      */
00324     GError *e = NULL;
00325     unsigned int carry=0;
00326     unsigned int c;
00327     while(carry == 0) {
00328       point_index_to_realspace(X, x);
00329       //fprintf(stderr, "Y");
00330       /*Note that this for loop can likely be unrolled.
00331        *The if statement should be compiled out; it'll never
00332        *change at runtime.
00333        */
00334       for(c=0; c<Nc; c++) {
00335         if(Nc == 1) {
00336     e = thing_to_do(X, x, 0, D, &data[point_index_to_storage_index(X)], privdat);
00337         }else{
00338     e = thing_to_do(X, x, c, D, &data[point_index_to_storage_index(X, c)], privdat);
00339         }
00340         if(e != NULL) {
00341     GError *err = NULL;
00342     GString *s = g_string_new("");
00343     GString *S = g_string_new("");
00344     for(unsigned int i=0; i<D; i++) {
00345       g_string_append_printf(s, " %g", x[i]);
00346       g_string_append_printf(S, " %u", X[i]);
00347     }
00348     g_propagate_prefixed_error(&err, e, "kdotp::libmodeling::grid::cartesian_grid::set_points<full>: Got error evaluating point %s (grid site %s) c=%u: ", s->str, S->str, c);
00349     g_string_free(s, TRUE);
00350     g_string_free(S, TRUE);
00351     return err;
00352         }
00353       }
00354       /*Now update our point.*/
00355       carry=1;
00356       /*We should exit this loop with carry=0 unless we incremented past the end of the final dimension (i.e. we'd need to carry into the D+1 dimension*/
00357       for(d=0; ((d<D)&&(carry==1)); d++) {
00358         //fprintf(stderr, "%d->", X[d]);
00359         X[d] += carry;
00360         //fprintf(stderr, "%d/", X[d]);
00361         if(X[d] >= L[d]) {
00362     X[d] = 0;
00363     carry = 1;
00364         }else{
00365     carry = 0;
00366         }
00367       }
00368       //fprintf(stderr, "\n");
00369     }
00370     return NULL;
00371   }
00372       
00373   /**
00374    *Set all components at the points that are in the shape
00375    *defined by the tree.
00376    *\param st* pointer to the shape tree
00377    *\param T* pointer to an Nc-size array of values to be set
00378    *\return int with the error code. Needs upgraded to GError.
00379    */
00380   int set_points(const struct shape_tree *st, T* val, GHashTable* global_symbols) {
00381     /*X is the integer location*/
00382     unsigned int X[D];
00383     /*x is the floating-point location*/
00384     double x[D];
00385     unsigned int d;
00386     for(d=0; d<D; d++) X[d]=0;
00387     /*X[0] is the lowest dimension; X[D-1] is the lowest
00388      *Here's the idea: X can be viewed as an integer number with
00389      *    a digit-dependent basis.  The algorithm:
00390      *1) carry is set to 0 going into the loop
00391      *2) When the counter is updated, carry will be set to 0,
00392      *     unless the last "digit" overflows, in which case carry stays 1.
00393      *3) If carry is still 1 coming out of the X update, we're done.
00394      */
00395     unsigned int carry=0;
00396     unsigned int c;
00397     while(carry == 0) {
00398       point_index_to_realspace(X, x);
00399       if(point_is_in_tree(x, st, global_symbols)) {
00400         //fprintf(stderr, "Y");
00401         /*Note that this for loop can likely be unrolled.
00402          *The if statement should be compiled out; it'll never
00403          *change at runtime.
00404          */
00405         for(c=0; c<Nc; c++) {
00406     if(Nc == 1) {
00407       data[point_index_to_storage_index(X)] = val[c];
00408     }else{
00409       data[point_index_to_storage_index(X, c)] = val[c];
00410     }
00411         }
00412         //}else{
00413         //fprintf(stderr, "N");
00414       }
00415       /*Now update our point.*/
00416       carry=1;
00417       for(d=0; ((d<D)&&(carry==1)); d++) {
00418         //fprintf(stderr, "%d->", X[d]);
00419         X[d] += carry;
00420         //fprintf(stderr, "%d/", X[d]);
00421         if(X[d] >= L[d]) {
00422     X[d] = 0;
00423     carry = 1;
00424         }else{
00425     carry = 0;
00426         }
00427       }
00428       //fprintf(stderr, "\n");
00429     }
00430     return 0;
00431   }
00432 
00433   /**
00434    *Covert a point within the grid from index to realspace
00435    *\param X integer array of size D, holding the grid indices
00436    *\param x double array of size D, to hold the position
00437    */
00438   void point_index_to_realspace(const unsigned int* X, double* x) const {
00439     unsigned int d;
00440     for(d=0; d<D; d++) {
00441       /*Formulated to put 0 in the center of the grid*/
00442       x[d] = (double(X[d]) - double(L[d])/2.0)*a[d];
00443     }
00444   }
00445   /**
00446    *Covert a point (index-based) to a location within storage
00447    *\param X integer array of size D, holding the grid indices.
00448    *\param c component number (default is 0; saves a save/load
00449    *if there's just one!)
00450    *\return long unsigned int, index into the storage.
00451    **/
00452   inline long unsigned int point_index_to_storage_index(const unsigned int* X, unsigned int c=0) const {
00453     unsigned int d;
00454     /*We initialize with c, the component, already done.*/
00455     unsigned long int block_offset = Nc;
00456     unsigned long int index = c;
00457     for(d=0; d<D; d++) {
00458       index += X[d]*block_offset;
00459       block_offset *= L[d];
00460     }
00461     return index;
00462   }
00463 
00464   bool point_is_in_tree(const double* x, const struct shape_tree *st, GHashTable* global_syms) const {
00465     bool l, r;
00466     switch(st->op) {
00467     case OR:
00468       return point_is_in_tree(x, st->l, global_syms) || point_is_in_tree(x, st->r, global_syms);
00469     case XOR:
00470       l = point_is_in_tree(x, st->l, global_syms);
00471       r = point_is_in_tree(x, st->r, global_syms);
00472       return (l || r) && (!(l && r));
00473     case AND:
00474       return point_is_in_tree(x, st->l, global_syms) && point_is_in_tree(x, st->r, global_syms);
00475     case NOT:
00476       return !point_is_in_tree(x, st->l, global_syms);
00477     case LEAF:
00478       break;
00479     default:
00480       fprintf(stderr, "kdotp::libmodelxx::grid::cartesian_grid::point_is_in_tree: unknown shape tree operation %d. Assuming point NOT in tree.\n", st->op);
00481       return false;
00482     }
00483     /*This code only executes if we are in a leaf*/
00484     struct shape* s = (struct shape*)st;
00485     switch(s->type) {
00486     case GLOBAL:
00487       /*A "global" shape is everywhere.*/
00488       return true;
00489     case BLOCK:
00490       return point_is_in_shape(x, (struct shape_block*)(s), global_syms);
00491     case ABSBLOCK:
00492       return point_is_in_shape(x, (struct shape_block*)(s), global_syms);
00493     default:
00494       fprintf(stderr, "kdotp::libmodelxx::grid::cartesian_grid::point_is_in_tree: unknown shape type %d. Assuming point NOT in tree.\n", s->type);
00495       return false;
00496     }
00497     /*If we've hit this point, we've gone too far.*/
00498     return false;
00499   }
00500   /**
00501    *Determines if a point is within the given shape.
00502    *\note TODO_FOR_SHAPE
00503    *\note Overload point_is_in_shape to implement a new shape.*/
00504   bool point_is_in_shape(const double* x, const struct shape_block* b, GHashTable* global_syms) const {
00505       /*Check if the point lies within the box (dist to center
00506        * less than half edge length, for each edge.*/
00507       //fprintf(stderr, "piis: x[%d]=%g center[%d]=%g L[%d]=%g\n", d, x[d], d, (b->center)[d], d, (b->L)[d]);
00508       /*fprintf(stderr, "point_is_in_shape: %g: center=%g L=%g x-center=%g L/2=%g: ", x[d], b->center[d], b->L[d], fabs(x[d] - b->center[d]), fabs(b->L[d]/2.0));*/
00509       double center[D];
00510       double L[D];
00511       if(get_function_datatype(b->center, global_syms, NULL) != D) {
00512         return false;
00513       }
00514       if(get_function_datatype(b->L, global_syms, NULL) != D) {
00515         return false;
00516       }
00517       GError *e = evaluate_function(center, b->center, global_syms, NULL);
00518       if(e != NULL) {
00519         fprintf(stderr, "ERROR evaluating center function for block shape: %s", e->message);
00520         g_error_free(e);
00521         return false;
00522       }
00523       e = evaluate_function(L, b->L, global_syms, NULL);
00524       if(e != NULL) {
00525         fprintf(stderr, "ERROR evaluating size function for block shape: %s", e->message);
00526         g_error_free(e);
00527         return false;
00528       }
00529     for(unsigned int d = 0; d<D; d++) {
00530       switch (b->type) {
00531       case BLOCK:
00532         if(!(fabs(x[d] - (center)[d]) <= fabs((L)[d]/2.0))) {
00533     return false;
00534         }
00535         break;
00536       case ABSBLOCK:
00537         if(center[d] > L[d]) {
00538     if(!((x[d] >= L[d]) && (x[d] <= center[d]))) return false;
00539         }else{
00540     if(!((x[d] <= L[d]) && (x[d] >= center[d]))) return false;
00541         }
00542         break;
00543       default:
00544         fprintf(stderr, "ERROR in point_is_in_shape (block argument): block isn't a block or an absblock?! (is %d).\n", b->type);
00545         return false;
00546       }
00547     }
00548     /*fprintf(stderr, "TRUE\n");*/
00549     return true;
00550   }
00551 
00552   /**helper function for create_indexed_unique_component_grid*/
00553   long unsigned get_index_for_component_and_store_if_new(GList** comps, bool (*is_same)(T* a, T* b), T* comp) {
00554     long unsigned index=0;
00555     for(GList* l=*comps; l != NULL; l=l->next, index++) {
00556       if(is_same(comp, (T*)l->data)) {
00557         return index;
00558       }
00559     }
00560     *comps = g_list_append(*comps, comp);
00561     return index;
00562   }
00563   /**Create a new grid which contains unique component indices.  The initial use case for this is creating an integer-based material map.  We then have an array of materials and a grid of material assignments.
00564    *\param indices pointer to a place to store an array of type T (the final array; the index stored in the grid is the array index to get the component
00565    *\param n_indices number of T's stored in the indices array
00566    *\param indexed_grid pointer to a new, identically-spec'ed Cartesian grid, but with indices into the component array instead of component.
00567    *\param is_same callback to compare to items (return true if same, false otherwise)
00568    *\returns pointer to a GError containing the error, or NULL if no error occurred.
00569    */
00570   GError* create_indexed_unique_component_grid(T** indices, long unsigned *n_indices, cartesian_grid<long unsigned, D, Nc> **indexed_grid, bool (*is_same)(T* a, T* b)) {
00571     *indexed_grid = new cartesian_grid<long unsigned, D, Nc>(L, a, 0);
00572     /*The easy way to do this is not to care about our location (it's really irrelevant; we only care about whether or not this component is unique or not.*/
00573     /*List of the unique components.*/
00574     GList *components = NULL;
00575     for(long unsigned i=0; i<num_pts; i++) {
00576       ((*indexed_grid)->data)[i] = get_index_for_component_and_store_if_new(&components, is_same, &(data[i]));
00577     }
00578     *n_indices = g_list_length(components);
00579     *indices = (T*)malloc(sizeof(T)*(*n_indices));
00580     if(*indices == NULL) {
00581       return g_error_new(CARTESIAN_GRID_GERROR_DOMAIN, 200, "kdotp::libkdotp::libmodelxx::grid::cartesian_grid::create_indexed_unique_component_grid: failed to allocate storage for the index array");
00582     }
00583     GList *l;
00584     long unsigned i=0;
00585     for(l=components, i=0; l!=NULL; l=l->next, i++) {
00586       (*indices)[i] = *(T*)(l->data);
00587     }
00588     g_list_free(components);
00589     return NULL;
00590   }
00591 
00592 
00593   /*Callback to implement the dump.
00594    */
00595   struct dump_foreach_callback_privdat {
00596     GOutputStream *gos;
00597     char* (*t_to_string)(T*);
00598     GString *s;
00599   };
00600   static GError* dump_foreach_callback(unsigned* X, double* x, unsigned c, unsigned dim, T* location, void* privdat) {
00601     struct dump_foreach_callback_privdat *cbp = (struct dump_foreach_callback_privdat*)privdat;
00602     g_string_printf(cbp->s, "%u\t%g\t", X[0], x[0]);
00603     for(unsigned d=1; d<dim; d++) {
00604       g_string_append_printf(cbp->s, "%u\t%g\t", X[d], x[d]);
00605     }
00606     char* data = cbp->t_to_string(location);
00607     g_string_append_printf(cbp->s, "%u\t%s\n", c, data);
00608     free(data);
00609     GError *e=NULL;
00610     gsize bytes_written;
00611     //fprintf(stderr, "str=%s\n", cbp->s->str);
00612     if(!g_output_stream_write_all(cbp->gos, cbp->s->str, cbp->s->len, &bytes_written, NULL, &e)) {
00613       GError *err=NULL;
00614       g_propagate_prefixed_error(&err, e, "kdotp::libmodelxx::grid::cartesian_grid.h++::dump: error writing line (%s). ", cbp->s->str);
00615       return err;
00616     }
00617     return NULL;
00618   }
00619   /**Dumps the grid to a file (gfos) in ASCII.
00620    *\param gos GOutputStream to write to.
00621    *\param t_to_string callback to convert T to a string.
00622    *\return the GError of the error that occurred, or NULL if no error.
00623    */
00624   GError* dump(GOutputStream *gos, char* (*t_to_string)(T*)) {
00625     struct dump_foreach_callback_privdat dcp = {gos, t_to_string, NULL};
00626     dcp.s = g_string_new("");
00627     /*Write the header.*/
00628     GError *e = NULL;
00629     gsize bytes_written;
00630     GString *s = g_string_new("#Grid dimensions:\n");
00631     if(!g_output_stream_write_all(gos, s->str, s->len, &bytes_written, NULL, &e)) {
00632       GError *err=NULL;
00633       g_propagate_prefixed_error(&err, e, "kdotp::libmodelxx::grid::cartesian_grid.h++::dump: error writing header.\n");
00634       return err;
00635     }
00636     g_string_printf(s, "%u", D);
00637     for(unsigned d=0; d<D; d++) {
00638       g_string_append_printf(s, "\t%u\t%g", L[d], a[d]);
00639     }
00640     g_string_append_printf(s, "\t%u\n", Nc);
00641     if(!g_output_stream_write_all(gos, s->str, s->len, &bytes_written, NULL, &e)) {
00642       GError *err=NULL;
00643       g_propagate_prefixed_error(&err, e, "kdotp::libmodelxx::grid::cartesian_grid.h++::dump: error writing header.\n");
00644       return err;
00645     }
00646     s = g_string_assign(s, "#");
00647     for(unsigned d=0; d<D; d++) {
00648       g_string_append_printf(s, "X%u\tx%u\t", d, d);
00649     }
00650     s = g_string_append(s, "\n");
00651     if(!g_output_stream_write_all(gos, s->str, s->len, &bytes_written, NULL, &e)) {
00652       GError *err=NULL;
00653       g_propagate_prefixed_error(&err, e, "kdotp::libmodelxx::grid::cartesian_grid.h++::dump: error writing header.\n");
00654       return err;
00655     }
00656     e = for_each_point(dump_foreach_callback, (void*)(&dcp));
00657     g_string_free(s, TRUE);
00658     if(e != NULL) {
00659       GError *err = NULL;
00660       g_propagate_prefixed_error(&err, e, "kdotp::libmodelxx::grid::cartesian_grid.h++::dump: error writing grid data.\n");
00661       return err;
00662     }
00663     return NULL;
00664   }
00665 
00666   /**Like dump, but dumps an *indexed* version.*/
00667   GError* dump_indexed(GOutputStream *gos, bool (*is_same)(T* a, T* b), char* (*t_to_string)(T*)) {
00668     T* indices;
00669     long unsigned n_indices;
00670     cartesian_grid<long unsigned, D, Nc>* indexed_grid;
00671     GError *e=NULL;
00672     e = create_indexed_unique_component_grid(&indices, &n_indices, &indexed_grid, is_same);
00673     if(e != NULL) {
00674       GError *err = NULL;
00675       g_propagate_prefixed_error(&err, e, "kdotp::libmodelxx::grid::cartesian_grid.h++::dump_indexed: error getting indexed grid.\n");
00676       return err;
00677     }
00678     GString *s = g_string_new("#material assignments:\n");
00679     g_string_append_printf(s, "%lu\n", n_indices);
00680     gsize bytes_written;
00681     if(!g_output_stream_write_all(gos, s->str, s->len, &bytes_written, NULL, &e)) {
00682       GError *err=NULL;
00683       g_propagate_prefixed_error(&err, e, "kdotp::libmodelxx::grid::cartesian_grid.h++::dump_indexed: error writing header.\n");
00684       free(indices);
00685       delete indexed_grid;
00686       return err;
00687     }
00688     for(long unsigned i=0; i<n_indices; i++) {
00689       char* rstr;
00690       g_string_printf(s, "%s\n", rstr=t_to_string(&(indices[i])));
00691       if(!g_output_stream_write_all(gos, s->str, s->len, &bytes_written, NULL, &e)) {
00692         GError *err=NULL;
00693         g_propagate_prefixed_error(&err, e, "kdotp::libmodelxx::grid::cartesian_grid.h++::dump_indexed: error writing material %lu (%s).\n", i, rstr);
00694         free(indices);
00695         free(rstr);
00696         delete indexed_grid;
00697         return err;
00698       }
00699       //fprintf(stderr, "index %lu: %s\n", i, rstr);
00700       free(rstr);
00701     }
00702     e=indexed_grid->dump(gos, long_unsigned_to_string);
00703     if(e != NULL) {
00704       GError *err=NULL;
00705       g_propagate_prefixed_error(&err, e, "kdotp::libmodelxx::grid::cartesian_grid.h++::dump_indexed: error dumping index grid.\n");
00706       free(indices);
00707       delete indexed_grid;
00708       return err;
00709     }
00710     free(indices);
00711     delete indexed_grid;
00712     return NULL;
00713   }
00714 
00715   /**Sets a point in the grid, by grid site
00716    *\note this is pretty much just a wrapper around using point_index_to_storage_index.
00717    */
00718   inline void set_point(unsigned* X, T* val, unsigned c=0) {
00719     data[point_index_to_storage_index(X, c)] = *val;
00720   }
00721   inline void set_point(unsigned* X, T& val, unsigned c=0) {
00722     data[point_index_to_storage_index(X, c)] = val;
00723   }
00724   inline void set_point_(unsigned* X, T& val, unsigned c=0) {
00725     data[point_index_to_storage_index(X, c)] = val;
00726   }
00727 
00728   /**Sets a point in the grid, by grid site
00729    *\note this is pretty much just a wrapper around using point_index_to_storage_index.
00730    *\note that we use store_pointer to get out a *pointer* to the datum, *not* a copy!
00731    *\note THIS DOES NOT MAKE A COPY!
00732    */
00733   inline void get_point(unsigned* X, T** store_pointer, unsigned c=0) {
00734     *store_pointer = &data[point_index_to_storage_index(X, c)];
00735   }
00736   /**same as get_point, but returns the pointer instead
00737    *\note THIS DOES NOT MAKE A COPY!
00738    */
00739   inline T* get_point_r(unsigned* X, unsigned c=0) {
00740     return &data[point_index_to_storage_index(X, c)];
00741   }
00742 
00743   /*\var Length (in grid sites) of each edge of the compuational box*/
00744   unsigned int L[D];
00745   /*\var distance between grid points*/
00746   double a[D];
00747   /*Data storage*/
00748   long unsigned int num_pts;
00749   T* data;
00750   struct ::kdotp::libmodelxx::postprocessing::symbol_table_entry_const ste_x;
00751   GHashTable* st_x;
00752   struct ::kdotp::libmodelxx::postprocessing::symbol_table_entry_const ste_X;
00753   GHashTable* st_X;
00754       private:
00755   /*Make these unsafe defaults not exist*/
00756   cartesian_grid() {}
00757   cartesian_grid(const cartesian_grid& g) {}
00758   cartesian_grid operator=(const cartesian_grid& g) {return *this;}
00759       };
00760       
00761 
00762     }
00763   }
00764 }
00765 #endif
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Defines