|
k-dot-p 0.1
|
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