diff --git a/applications/clawpack/advection/2d/swirl/swirl.cpp b/applications/clawpack/advection/2d/swirl/swirl.cpp index 1370c532e..daaee6f93 100644 --- a/applications/clawpack/advection/2d/swirl/swirl.cpp +++ b/applications/clawpack/advection/2d/swirl/swirl.cpp @@ -74,7 +74,17 @@ void run_program(fclaw_global_t* glob) /* --------------------------------------------------------------- Run --------------------------------------------------------------- */ - fclaw_initialize(glob); + + fclaw_options_t *fclaw_opt = fclaw_get_options(glob); + if(fclaw_opt->restart) + { + fclaw_restart(glob); + } + else + { + fclaw_initialize(glob); + } + fclaw_run(glob); fclaw_finalize(glob); @@ -109,9 +119,7 @@ main (int argc, char **argv) if (!vexit) { /* Create global structure which stores the domain, timers, etc */ - int size, rank; - sc_MPI_Comm mpicomm = fclaw_app_get_mpi_size_rank (app, &size, &rank); - fclaw_global_t *glob = fclaw_global_new_comm (mpicomm, size, rank); + fclaw_global_t *glob = fclaw_global_new (app); /* Store option packages in glob */ fclaw_options_store (glob, fclaw_opt); diff --git a/applications/clawpack/advection/2d/swirl/swirl_options.c b/applications/clawpack/advection/2d/swirl/swirl_options.c index cecb029c8..f5037052c 100644 --- a/applications/clawpack/advection/2d/swirl/swirl_options.c +++ b/applications/clawpack/advection/2d/swirl/swirl_options.c @@ -65,45 +65,6 @@ swirl_destroy(user_options_t *user) FCLAW_FREE (user); } -static void -swirl_destroy_void(void *user) -{ - swirl_destroy((user_options_t*) user); -} - -static size_t -options_packsize(void* user) -{ - return sizeof(user_options_t); -} - -static size_t -options_pack(void* user, char* buffer) -{ - user_options_t* opts = (user_options_t*) user; - - //pack entire struct - return FCLAW_PACK(*opts, buffer); -} - -static size_t -options_unpack(char* buffer, void** user) -{ - user_options_t** opts_ptr = (user_options_t**) user; - - *opts_ptr = FCLAW_ALLOC(user_options_t,1); - - return FCLAW_UNPACK(buffer, *opts_ptr); -} - -static fclaw_packing_vtable_t packing_vt = -{ - options_pack, - options_unpack, - options_packsize, - swirl_destroy_void -}; - /* ------- Generic option handling routines that call above routines ----- */ static void* options_register (fclaw_app_t * app, void *package, sc_options_t * opt) @@ -189,8 +150,6 @@ user_options_t* swirl_options_register (fclaw_app_t * app, fclaw_app_set_attribute(app,"user",user); - fclaw_app_register_options_packing_vtable("user", &packing_vt); - return user; } diff --git a/applications/clawpack/advection/3d/swirl/swirl.cpp b/applications/clawpack/advection/3d/swirl/swirl.cpp index e9ac481f8..a7f523712 100644 --- a/applications/clawpack/advection/3d/swirl/swirl.cpp +++ b/applications/clawpack/advection/3d/swirl/swirl.cpp @@ -173,7 +173,18 @@ void run_program(fclaw_global_t* glob) /* --------------------------------------------------------------- Run --------------------------------------------------------------- */ - fclaw_initialize(glob); + + fclaw_options_t *fclaw_opt = fclaw_get_options(glob); + if(fclaw_opt->restart) + { + fclaw_restart(glob); + } + else + { + fclaw_initialize(glob); + } + + fclaw_run(glob); fclaw_finalize(glob); } @@ -205,9 +216,7 @@ main (int argc, char **argv) if (!vexit) { /* Options have been checked and are valid */ - int size, rank; - sc_MPI_Comm mpicomm = fclaw_app_get_mpi_size_rank (app, &size, &rank); - fclaw_global_t *glob = fclaw_global_new_comm (mpicomm, size, rank); + fclaw_global_t *glob = fclaw_global_new(app); /* Store option packages in glob */ fclaw_options_store (glob, fclaw_opt); diff --git a/applications/demo/2d/swirl_restart/swirl_options.c b/applications/demo/2d/swirl_restart/swirl_options.c index cecb029c8..f5037052c 100644 --- a/applications/demo/2d/swirl_restart/swirl_options.c +++ b/applications/demo/2d/swirl_restart/swirl_options.c @@ -65,45 +65,6 @@ swirl_destroy(user_options_t *user) FCLAW_FREE (user); } -static void -swirl_destroy_void(void *user) -{ - swirl_destroy((user_options_t*) user); -} - -static size_t -options_packsize(void* user) -{ - return sizeof(user_options_t); -} - -static size_t -options_pack(void* user, char* buffer) -{ - user_options_t* opts = (user_options_t*) user; - - //pack entire struct - return FCLAW_PACK(*opts, buffer); -} - -static size_t -options_unpack(char* buffer, void** user) -{ - user_options_t** opts_ptr = (user_options_t**) user; - - *opts_ptr = FCLAW_ALLOC(user_options_t,1); - - return FCLAW_UNPACK(buffer, *opts_ptr); -} - -static fclaw_packing_vtable_t packing_vt = -{ - options_pack, - options_unpack, - options_packsize, - swirl_destroy_void -}; - /* ------- Generic option handling routines that call above routines ----- */ static void* options_register (fclaw_app_t * app, void *package, sc_options_t * opt) @@ -189,8 +150,6 @@ user_options_t* swirl_options_register (fclaw_app_t * app, fclaw_app_set_attribute(app,"user",user); - fclaw_app_register_options_packing_vtable("user", &packing_vt); - return user; } diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 324aa8a60..df07dd8a5 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -27,6 +27,7 @@ add_library(forestclaw_c OBJECT fclaw_physical_bc.c fclaw_ghost_fill.c fclaw_output.c + fclaw_restart.c fclaw_run.c fclaw_diagnostics.c fclaw_rays.c @@ -43,6 +44,8 @@ add_library(forestclaw_c OBJECT fclaw_edge_neighbors.c fclaw_face_neighbors.c fclaw_farraybox.cpp + fclaw_file.c + fclaw_context.c fclaw2d_convenience.c fclaw2d_output_tikz.c fclaw2d_file.c @@ -112,6 +115,7 @@ install(FILES fclaw_patch.h fclaw_vtable.h fclaw_output.h + fclaw_restart.h fclaw_time_sync.h fclaw_update_single_step.h fclaw_physical_bc.h @@ -129,6 +133,8 @@ install(FILES fclaw_map_query.h fclaw_map_query_defs.h fclaw_diagnostics.h + fclaw_file.h + fclaw_context.h forestclaw2d.h fp_exception_glibc_extension.h fclaw2d_convenience.h @@ -155,6 +161,7 @@ if(BUILD_TESTING) fclaw_options.h.TEST.cpp fclaw_patch.h.TEST.cpp fclaw_vtable.h.TEST.cpp + fclaw_context.h.TEST.cpp ) target_link_libraries(forestclaw.TEST testutils forestclaw) diff --git a/src/Makefile.am b/src/Makefile.am index 41c34e2b3..c11ca1e58 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -30,6 +30,7 @@ libforestclaw_installed_headers = \ src/fclaw_patch.h \ src/fclaw_vtable.h \ src/fclaw_output.h \ + src/fclaw_restart.h \ src/fclaw_time_sync.h \ src/fclaw_update_single_step.h \ src/fclaw_physical_bc.h \ @@ -47,6 +48,8 @@ libforestclaw_installed_headers = \ src/fclaw_map_query.h \ src/fclaw_map_query_defs.h \ src/fclaw_diagnostics.h \ + src/fclaw_file.h \ + src/fclaw_context.h \ src/forestclaw2d.h \ src/fclaw2d_convenience.h \ src/fp_exception_glibc_extension.h \ @@ -92,6 +95,7 @@ libforestclaw_compiled_sources = \ src/fclaw_rays.c \ src/fclaw_ghost_fill.c \ src/fclaw_output.c \ + src/fclaw_restart.c \ src/fclaw_run.c \ src/fclaw_diagnostics.c \ src/fclaw_update_single_step.c \ @@ -107,6 +111,8 @@ libforestclaw_compiled_sources = \ src/fclaw_edge_neighbors.c \ src/fclaw_face_neighbors.c \ src/fclaw_farraybox.cpp \ + src/fclaw_file.c \ + src/fclaw_context.c \ src/fclaw2d_convenience.c \ src/fclaw2d_output_tikz.c \ src/fclaw2d_file.c \ @@ -194,6 +200,7 @@ src_forestclaw_TEST_SOURCES = \ src/fclaw_global.h.TEST.cpp \ src/fclaw_options.h.TEST.cpp \ src/fclaw_patch.h.TEST.cpp \ + src/fclaw_context.h.TEST.cpp \ src/fclaw_vtable.h.TEST.cpp src_forestclaw_TEST_CPPFLAGS = \ diff --git a/src/fclaw2d_to_3d.h b/src/fclaw2d_to_3d.h index 047ded034..8caaa4c4f 100644 --- a/src/fclaw2d_to_3d.h +++ b/src/fclaw2d_to_3d.h @@ -218,5 +218,6 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #define fclaw2d_match_wrap_cb fclaw3d_match_wrap_cb #define fclaw2d_intersect_wrap_cb fclaw3d_intersect_wrap_cb #define fclaw2d_interpolate_point_wrap_cb fclaw3d_interpolate_point_wrap_cb +#define fclaw2d_file_error_wrap fclaw3d_file_error_wrap #endif /* !FCLAW2D_TO_3D_H */ diff --git a/src/fclaw2d_wrap.c b/src/fclaw2d_wrap.c index 7836a287b..f01d3f23a 100644 --- a/src/fclaw2d_wrap.c +++ b/src/fclaw2d_wrap.c @@ -24,16 +24,19 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include +#include #ifndef P4_TO_P8 #include #include +#include #else #include #include +#include #endif @@ -322,3 +325,60 @@ fclaw2d_interpolate_point_wrap_cb (fclaw2d_domain_t * domain_2d, return retval; } + +int fclaw2d_file_error_wrap(int errcode) +{ + switch(errcode) + { + case FCLAW2D_FILE_ERR_SUCCESS: + return FCLAW_FILE_ERR_SUCCESS; + case FCLAW2D_FILE_ERR_FILE: + return FCLAW_FILE_ERR_FILE; + case FCLAW2D_FILE_ERR_NOT_SAME: + return FCLAW_FILE_ERR_NOT_SAME; + case FCLAW2D_FILE_ERR_AMODE: + return FCLAW_FILE_ERR_AMODE; + case FCLAW2D_FILE_ERR_NO_SUCH_FILE: + return FCLAW_FILE_ERR_NO_SUCH_FILE; + case FCLAW2D_FILE_ERR_FILE_EXIST: + return FCLAW_FILE_ERR_FILE_EXIST; + case FCLAW2D_FILE_ERR_BAD_FILE: + return FCLAW_FILE_ERR_BAD_FILE; + case FCLAW2D_FILE_ERR_ACCESS: + return FCLAW_FILE_ERR_ACCESS; + case FCLAW2D_FILE_ERR_NO_SPACE: + return FCLAW_FILE_ERR_NO_SPACE; + case FCLAW2D_FILE_ERR_QUOTA: + return FCLAW_FILE_ERR_QUOTA; + case FCLAW2D_FILE_ERR_READ_ONLY: + return FCLAW_FILE_ERR_READ_ONLY; + case FCLAW2D_FILE_ERR_IN_USE: + return FCLAW_FILE_ERR_IN_USE; + case FCLAW2D_FILE_ERR_IO: + return FCLAW_FILE_ERR_IO; + case FCLAW2D_FILE_ERR_FORMAT: + return FCLAW_FILE_ERR_FORMAT; + case FCLAW2D_FILE_ERR_SECTION_TYPE: + return FCLAW_FILE_ERR_SECTION_TYPE; + case FCLAW2D_FILE_ERR_CONN: + return FCLAW_FILE_ERR_CONN; + case FCLAW2D_FILE_ERR_P4EST: + return FCLAW_FILE_ERR_P4EST; + case FCLAW2D_FILE_ERR_IN_DATA: + return FCLAW_FILE_ERR_IN_DATA; + case FCLAW2D_FILE_ERR_COUNT: + return FCLAW_FILE_ERR_COUNT; + case FCLAW2D_FILE_ERR_DIM: + return FCLAW_FILE_ERR_DIM; + case FCLAW2D_FILE_ERR_UNKNOWN: + return FCLAW_FILE_ERR_UNKNOWN; + case FCLAW2D_FILE_ERR_PART: + return FCLAW_FILE_ERR_PART; + case FCLAW2D_FILE_ERR_NOT_IMPLEMENTED: + return FCLAW_FILE_ERR_NOT_IMPLEMENTED; + case FCLAW2D_FILE_ERR_LASTCODE: + return FCLAW_FILE_ERR_LASTCODE; + default: + SC_ABORT_NOT_REACHED(); + } +} \ No newline at end of file diff --git a/src/fclaw2d_wrap.h b/src/fclaw2d_wrap.h index 913188614..0bc40e712 100644 --- a/src/fclaw2d_wrap.h +++ b/src/fclaw2d_wrap.h @@ -113,6 +113,15 @@ fclaw2d_interpolate_point_wrap_cb (fclaw2d_domain_t * domain, int blockno, int patchno, void *point, void *user); +/** + * @brief Wrap get dimension independent domain from a 2d error code. + * + * @param errcode the 2d error code + * @return int the dimension independent error code + */ +int +fclaw2d_file_error_wrap(int errcode); + #ifdef __cplusplus #if 0 { diff --git a/src/fclaw3d_wrap.h b/src/fclaw3d_wrap.h index fb78b81e9..3f9b42ba1 100644 --- a/src/fclaw3d_wrap.h +++ b/src/fclaw3d_wrap.h @@ -115,6 +115,15 @@ fclaw3d_interpolate_point_wrap_cb (fclaw3d_domain_t * domain, int blockno, int patchno, void *point, void *user); +/** + * @brief Wrap get dimension independent domain from a 3d error code. + * + * @param errcode the 3d error code + * @return int the dimension independent error code + */ +int +fclaw3d_file_error_wrap(int errcode); + #ifdef __cplusplus #if 0 { diff --git a/src/fclaw_base.c b/src/fclaw_base.c index c0df4d475..c84fd393d 100644 --- a/src/fclaw_base.c +++ b/src/fclaw_base.c @@ -31,7 +31,6 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. static const char *fclaw_configdir = ".forestclaw"; static const char *fclaw_env_configdir = "FCLAW_INI_DIR"; static int fclaw_package_id = -1; -static fclaw_pointer_map_t* packing_vtables = NULL; int fclaw_app_exit_type_to_status (fclaw_exit_type_t vexit) @@ -332,10 +331,6 @@ fclaw_app_destroy (fclaw_app_t * a) FCLAW_ASSERT (a->opt_pkg != NULL); FCLAW_ASSERT (a->opt != NULL); - /* destroy central structures */ - sc_keyvalue_destroy (a->attributes); - sc_options_destroy (a->opt); - /* let the options packages clean up their memory */ for (zz = a->opt_pkg->elem_count; zz > 0; --zz) { @@ -350,9 +345,11 @@ fclaw_app_destroy (fclaw_app_t * a) } sc_array_destroy (a->opt_pkg); - FCLAW_FREE (a); + /* destroy central structures */ + sc_keyvalue_destroy (a->attributes); + sc_options_destroy (a->opt); - if(packing_vtables!=NULL) fclaw_pointer_map_destroy(packing_vtables); + FCLAW_FREE (a); sc_finalize (); @@ -929,22 +926,6 @@ fclaw_app_get_options (fclaw_app_t * a) } -void fclaw_app_register_options_packing_vtable(const char*name,fclaw_packing_vtable_t* vtable){ - if(packing_vtables == NULL) - { - packing_vtables = fclaw_pointer_map_new(); - } - fclaw_pointer_map_insert(packing_vtables, name, vtable, NULL); -} - -fclaw_packing_vtable_t* fclaw_app_get_options_packing_vtable(const char*name){ - if(packing_vtables == NULL) - { - packing_vtables = fclaw_pointer_map_new(); - } - return (fclaw_packing_vtable_t*) fclaw_pointer_map_get(packing_vtables,name); -} - void fclaw_abortf(const char *fmt, ...){ va_list ap; diff --git a/src/fclaw_base.h b/src/fclaw_base.h index 66d8ff61f..677f096aa 100644 --- a/src/fclaw_base.h +++ b/src/fclaw_base.h @@ -488,24 +488,6 @@ void fclaw_app_options_register (fclaw_app_t * a, const fclaw_app_options_vtable_t * vt, void *package); -typedef struct fclaw_packing_vtable fclaw_packing_vtable_t; - -/** - * @brief Register a vtable used for packing an options structure - * - * @param name the name, this should be the same name used for storing options in the glob - * @param vtable the vtable - */ -void fclaw_app_register_options_packing_vtable(const char*name,fclaw_packing_vtable_t* vtable); - -/** - * @brief Get an options packing vtable - * - * @param name the name, this should be the same name used for storing options in the glob - * @return fclaw_packing_vtable_t* the vtable - */ -fclaw_packing_vtable_t* fclaw_app_get_options_packing_vtable(const char* name); - /** * \brief Check if core options have been registered for this app * diff --git a/src/fclaw_context.c b/src/fclaw_context.c new file mode 100644 index 000000000..d2857fa75 --- /dev/null +++ b/src/fclaw_context.c @@ -0,0 +1,316 @@ +/* +Copyright (c) 2012-2024 Carsten Burstedde, Donna Calhoun, Scott Aiton +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, this +list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright notice, +this list of conditions and the following disclaimer in the documentation +and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#include +#include + +#define PACKING_VTABLE_NAME "fclaw_context_t" + +typedef enum +{ + FCLAW_CONTEXT_INT, + FCLAW_CONTEXT_DOUBLE, + FCLAW_CONTEXT_POINTER +} type_t; + +typedef struct value +{ + type_t type; + union + { + int i; + double d; + } value; + + void *pointer; + +} value_t; + +static void +value_destroy(void *data) +{ + value_t *value = (value_t *)data; + FCLAW_FREE(value); +} + +struct fclaw_context +{ + int initializing; + int saved; + fclaw_pointer_map_t *values; +}; + +static fclaw_context_t * +context_new() +{ + fclaw_context_t *context = FCLAW_ALLOC(fclaw_context_t, 1); + context->saved = 0; + context->initializing = 1; + context->values = fclaw_pointer_map_new(); + return context; +} + +static void +context_destroy(void *data) +{ + fclaw_context_t *context = (fclaw_context_t *)data; + fclaw_pointer_map_destroy(context->values); + FCLAW_FREE(context); +} + +static void +reset_pointers(const char *key, void *data, void *user) +{ + value_t *value = (value_t *)data; + value->pointer = NULL; +} + +fclaw_context_t* fclaw_context_get(fclaw_global_t *glob, const char *name) +{ + fclaw_context_t *context = + (fclaw_context_t*) fclaw_global_get_attribute(glob, name); + + if(context == NULL) + { + context = context_new(); + fclaw_global_attribute_store(glob, name, context, PACKING_VTABLE_NAME, context_destroy); + } + else + { + context->initializing = 0; + if(!context->saved) + { + fclaw_abortf("fclaw_context_get: Context needs to be saved before it can be retrieved again\n"); + } + context->saved = 0; + fclaw_pointer_map_iterate(context->values, reset_pointers, NULL); + } + + return context; +} + + +void fclaw_context_get_int(fclaw_context_t *context, + const char *name, + int *value) +{ + value_t *v = (value_t*) fclaw_pointer_map_get(context->values, name); + if(v != NULL) + { + if(v->type != FCLAW_CONTEXT_INT) + { + fclaw_abortf("fclaw_context_get_int: Value %s is not an int\n", name); + } + *value = v->value.i; + } + else if (context->initializing) + { + v = FCLAW_ALLOC(value_t, 1); + v->type = FCLAW_CONTEXT_INT; + fclaw_pointer_map_insert(context->values, name, v, value_destroy); + } + else + { + fclaw_abortf("fclaw_context_get_int: Value %s not found\n", name); + } + + v->pointer = value; +} + +void fclaw_context_get_double(fclaw_context_t *context, + const char *name, + double *value) +{ + value_t *v = (value_t*) fclaw_pointer_map_get(context->values, name); + if(v != NULL) + { + if(v->type != FCLAW_CONTEXT_DOUBLE) + { + fclaw_abortf("fclaw_context_get_double: Value %s is not a double\n", name); + } + *value = v->value.d; + } + else if(context->initializing) + { + v = FCLAW_ALLOC(value_t, 1); + v->type = FCLAW_CONTEXT_DOUBLE; + fclaw_pointer_map_insert(context->values, name, v, value_destroy); + } + else + { + fclaw_abortf("fclaw_context_get_double: Value %s not found\n", name); + } + + v->pointer = value; +} + +static +void save_value(const char *key, void *data, void *user) +{ + value_t *value = (value_t *) data; + if(value->pointer == NULL) + { + fclaw_abortf("fclaw_context_save: Value %s has no pointer\n", key); + } + if(value->type == FCLAW_CONTEXT_INT) + { + value->value.i = *(int *)value->pointer; + } + else if(value->type == FCLAW_CONTEXT_DOUBLE) + { + value->value.d = *(double *)value->pointer; + } + else + { + SC_ABORT_NOT_REACHED(); + } +} + +void fclaw_context_save(fclaw_context_t *context) +{ + fclaw_pointer_map_iterate(context->values, save_value, NULL); + context->saved = 1; +} + + +static +void pack_value(const char *key, void *data, void *user) +{ + char **buffer = (char **)user; + value_t *value = (value_t *)data; + *buffer += fclaw_pack_string(key, *buffer); + *buffer += fclaw_pack_int(value->type, *buffer); + if(value->type == FCLAW_CONTEXT_INT) + { + *buffer += fclaw_pack_int(value->value.i, *buffer); + } + else if(value->type == FCLAW_CONTEXT_DOUBLE) + { + *buffer += fclaw_pack_double(value->value.d, *buffer); + } + else + { + SC_ABORT_NOT_REACHED(); + } +} + +static +size_t pack_context(fclaw_global_t *glob, void *data, char *buffer) +{ + char* buffer_start = buffer; + fclaw_context_t *context = (fclaw_context_t *)data; + + if(!context->saved) + { + fclaw_abortf("fclaw_context: Context not saved, cannot pack\n"); + } + + buffer += fclaw_pack_int(fclaw_pointer_map_size(context->values), buffer); + fclaw_pointer_map_iterate(context->values, pack_value, &buffer); + return buffer - buffer_start; +} + +static +void value_packsize(const char *key, void *data, void *user) +{ + size_t *size = (size_t *)user; + value_t *value = (value_t *)data; + *size += fclaw_packsize_string(key); + *size += sizeof(int); + if(value->type == FCLAW_CONTEXT_INT) + { + *size += sizeof(int); + } + else if(value->type == FCLAW_CONTEXT_DOUBLE) + { + *size += sizeof(double); + } + else + { + SC_ABORT_NOT_REACHED(); + } +} + +static +size_t context_packsize(fclaw_global_t *glob, void *data) +{ + fclaw_context_t *context = (fclaw_context_t *)data; + size_t size = sizeof(int); + fclaw_pointer_map_iterate(context->values, value_packsize, &size); + return size; +} + +static +size_t context_unpack(fclaw_global_t *glob, char *buffer, void *data) +{ + char* buffer_start = buffer; + fclaw_context_t *context = (fclaw_context_t *)data; + context->initializing = 0; + context->saved = 1; + int size; + buffer += fclaw_unpack_int(buffer, &size); + int i; + for(i = 0; i < size; ++i) + { + char *key; + buffer += fclaw_unpack_string(buffer, &key); + value_t *value = FCLAW_ALLOC(value_t, 1); + buffer += fclaw_unpack_int(buffer,(int*) &value->type); + if(value->type == FCLAW_CONTEXT_INT) + { + buffer += fclaw_unpack_int(buffer, &value->value.i); + } + else if(value->type == FCLAW_CONTEXT_DOUBLE) + { + buffer += fclaw_unpack_double(buffer, &value->value.d); + } + else + { + SC_ABORT_NOT_REACHED(); + } + value->pointer = NULL; + fclaw_pointer_map_insert(context->values, key, value, value_destroy); + FCLAW_FREE(key); + } + return buffer - buffer_start; +} + +static void* context_new_void(fclaw_global_t *glob) +{ + return context_new(); +} + +fclaw_packing_vtable_t fclaw_context_vtable = { + pack_context, + context_unpack, + context_packsize, + context_new_void, + context_destroy +}; + +void fclaw_context_vtable_initialize(fclaw_global_t *glob) +{ + fclaw_global_vtable_store(glob, PACKING_VTABLE_NAME, &fclaw_context_vtable, NULL); +} \ No newline at end of file diff --git a/src/fclaw_context.h b/src/fclaw_context.h new file mode 100644 index 000000000..81bec5c74 --- /dev/null +++ b/src/fclaw_context.h @@ -0,0 +1,146 @@ +/* +Copyright (c) 2012-2024 Carsten Burstedde, Donna Calhoun, Scott Aiton +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, this +list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright notice, +this list of conditions and the following disclaimer in the documentation +and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +/** + * @file + * + * @brief This file contains the declaration of the fclaw_context_t structure and related functions. + * + * The fclaw_context_t structure represents a context for functions that can be paused and resumed. + * It provides functions to retrieve and save values to the context object. + * + * Example usage: + * + * // Get the context object from the global context + * fclaw_context_t *context = fclaw_context_get(glob, "my_context"); + * + * // Get an integer value from the context object + * int value; + * fclaw_context_get_int(context, "my_value", &value, 10); + * + * // Get a double value from the context object + * double value; + * fclaw_context_get_double(context, "my_value", &value, 3.14); + * + * // Save values to the context object + * // This should be called right before exit points in a function + * fclaw_context_save(context); + * + * This is designed with some restrictions in mind: + * - The context object shoulde be retrieved at the beginning of a function with fclaw_context_get. + * - The values should be retrieved with fclaw_context_get_int or fclaw_context_get_double. + * - These should be called in the same manner every time the resumable function is called. + * - If these arent called in the same manner, the program will abort. + * - The values should be saved with fclaw_context_save right before exit points in the function. + * - the save call will save all the variables pointed to in the get_double/int calls. + * + * + */ + +#ifndef FCLAW_CONTEXT_H +#define FCLAW_CONTEXT_H + +#include + +#ifdef __cplusplus +extern "C" +{ +#if 0 +} +#endif +#endif + +/** + * @brief Context structure + */ +typedef struct fclaw_context fclaw_context_t; + +/** + * @brief Get the context object from glob. If the context object does not exist, it is created. + * + * If the context exists, calling the function will reset all pointers associated with the values. + * + * fclaw_context_save needs to be called before the context object can be retrieved again. + * + * @param glob the global context + * @return fclaw_context_t* the context object + */ +fclaw_context_t* fclaw_context_get(fclaw_global_t *glob, const char *name); + +/** + * @brief Get an integer value from the context object. + * If the value does not exist, the current value does not change. + * + * If the context isn't new and the value does not exist, an error message is printed and the program aborts. + * + * @param context the context object + * @param name the name of the value + * @param value a pointer the value, if the value does not exist, the value is not changed + */ +void fclaw_context_get_int(fclaw_context_t *context, + const char *name, + int *value); + +/** + * @brief Get a double value from the context object. + * If the value does not exist, the current value does not change. + * + * If the context isn't new and the value does not exist, an error message is printed and the program aborts. + * + * @param context the context object + * @param name the name of the value + * @param value a pointer the value, if the value does not exist, the value is not changed + */ +void fclaw_context_get_double(fclaw_context_t *context, + const char *name, + double *value); + +/** + * @brief Save values to the context object. Should be called right before exit points in a function. + * + * This will get the values from the pointers provided in the get functions. + * + * If the context is not new, and all values have not been retrieved (ie fclaw_context_get_int or fclaw_context_get_double), + * this function will abort with an error message. + * + * @param context the context object to save to + */ +void fclaw_context_save(fclaw_context_t *context); + +/** + * @brief Initializes the vtable needed for packing context objects + * + * @param glob the global context + */ +void fclaw_context_vtable_initialize(fclaw_global_t *glob); + +#ifdef __cplusplus +#if 0 +{ +#endif +} +#endif + +#endif /* !FCLAW_MATH_H */ diff --git a/src/fclaw_context.h.TEST.cpp b/src/fclaw_context.h.TEST.cpp new file mode 100644 index 000000000..d3f07a833 --- /dev/null +++ b/src/fclaw_context.h.TEST.cpp @@ -0,0 +1,481 @@ +/* +Copyright (c) 2012-2024 Carsten Burstedde, Donna Calhoun, Scott Aiton +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, this +list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright notice, +this list of conditions and the following disclaimer in the documentation +and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#include +#include + +TEST_CASE("fclaw_context_get new context") +{ + fclaw_global_t* glob = fclaw_global_new_comm(sc_MPI_COMM_SELF, 1, 0); + fclaw_context_t *context = fclaw_context_get(glob, "test"); + CHECK_NE(context, nullptr); + fclaw_global_destroy(glob); +} + +TEST_CASE("fclaw_context_get two new contexts") +{ + fclaw_global_t* glob = fclaw_global_new_comm(sc_MPI_COMM_SELF, 1, 0); + fclaw_context_t *context1 = fclaw_context_get(glob, "test1"); + fclaw_context_t *context2 = fclaw_context_get(glob, "test2"); + CHECK_NE(context1, nullptr); + CHECK_NE(context2, nullptr); + CHECK_NE(context1, context2); + fclaw_global_destroy(glob); +} + +TEST_CASE("fclaw_context_get existing context without saving") +{ + fclaw_global_t* glob = fclaw_global_new_comm(sc_MPI_COMM_SELF, 1, 0); + fclaw_context_t *context1 = fclaw_context_get(glob, "test"); + CHECK_NE(context1, nullptr); + //should fail since it wasnn't saved + CHECK_SC_ABORTED(fclaw_context_get(glob, "test")); +} + +TEST_CASE("fclaw_context_get existing context") +{ + fclaw_global_t* glob = fclaw_global_new_comm(sc_MPI_COMM_SELF, 1, 0); + fclaw_context_t *context1 = fclaw_context_get(glob, "test"); + CHECK_NE(context1, nullptr); + fclaw_context_save(context1); + fclaw_context_t *context2 = fclaw_context_get(glob, "test"); + CHECK_EQ(context1, context2); + fclaw_global_destroy(glob); +} + +TEST_CASE("fclaw_context_get two existing contexts") +{ + fclaw_global_t* glob = fclaw_global_new_comm(sc_MPI_COMM_SELF, 1, 0); + fclaw_context_t *context1 = fclaw_context_get(glob, "test1"); + fclaw_context_t *context2 = fclaw_context_get(glob, "test2"); + CHECK_NE(context1, nullptr); + CHECK_NE(context2, nullptr); + CHECK_NE(context1, context2); + fclaw_context_save(context1); + fclaw_context_save(context2); + fclaw_context_t *context3 = fclaw_context_get(glob, "test1"); + fclaw_context_t *context4 = fclaw_context_get(glob, "test2"); + CHECK_EQ(context1, context3); + CHECK_EQ(context2, context4); + fclaw_global_destroy(glob); +} + +TEST_CASE("fclaw_context_get_int new context") +{ + for(int default_value : {-100, 0, 42}) + { + fclaw_global_t* glob = fclaw_global_new_comm(sc_MPI_COMM_SELF, 1, 0); + fclaw_context_t *context = fclaw_context_get(glob, "test"); + int value = default_value; + fclaw_context_get_int(context, "test", &value); + CHECK_EQ(value, default_value); + fclaw_global_destroy(glob); + } +} + +TEST_CASE("fclaw_context_get_int new context two values") +{ + for(int default_value1 : {-100, 0, 42}) + for(int default_value2 : {-1, 1, 1024}) + { + fclaw_global_t* glob = fclaw_global_new_comm(sc_MPI_COMM_SELF, 1, 0); + fclaw_context_t *context = fclaw_context_get(glob, "test"); + int value1 = default_value1; + fclaw_context_get_int(context, "test1", &value1); + CHECK_EQ(value1, default_value1); + int value2 = default_value2; + fclaw_context_get_int(context, "test2", &value2); + CHECK_EQ(value2, default_value2); + fclaw_global_destroy(glob); + } +} + +TEST_CASE("fclaw_context_get_int existing context") +{ + for(int default_value : {-100, 0, 42}) + for(int changed_value : {-1, 4, 82}) + { + fclaw_global_t* glob = fclaw_global_new_comm(sc_MPI_COMM_SELF, 1, 0); + fclaw_context_t *context = fclaw_context_get(glob, "test"); + + int value1 = default_value; + + fclaw_context_get_int(context, "test", &value1); + CHECK_EQ(value1, default_value); + + fclaw_context_save(context); + int value2 = 0; + fclaw_context_get_int(context, "test", &value2); + CHECK_EQ(value2, default_value); + + value2 = changed_value; + fclaw_context_save(context); + int value3 = 0; + fclaw_context_get_int(context, "test", &value3); + CHECK_EQ(value3, changed_value); + + fclaw_global_destroy(glob); + } +} + +TEST_CASE("fclaw_context_get_int existing context two values") +{ + for(int default_value1 : {-100, 0, 42}) + for(int changed_value1 : {-1, 4, 82}) + for(int default_value2: {-100, 0, 42}) + for(int changed_value2: {-1, 4, 82}) + { + fclaw_global_t* glob = fclaw_global_new_comm(sc_MPI_COMM_SELF, 1, 0); + fclaw_context_t *context = fclaw_context_get(glob, "test"); + + int value = default_value1; + int value2 = default_value2; + + fclaw_context_get_int(context, "test1", &value); + fclaw_context_get_int(context, "test2", &value2); + + CHECK_EQ(value, default_value1); + CHECK_EQ(value2, default_value2); + + fclaw_context_save(context); + + fclaw_context_get_int(context, "test1", &value); + fclaw_context_get_int(context, "test2", &value2); + + CHECK_EQ(value, default_value1); + CHECK_EQ(value2, default_value2); + + value = changed_value1; + value2 = changed_value2; + + fclaw_context_save(context); + + fclaw_context_get_int(context, "test1", &value); + fclaw_context_get_int(context, "test2", &value2); + + CHECK_EQ(value, changed_value1); + CHECK_EQ(value2, changed_value2); + + fclaw_global_destroy(glob); + } +} + +TEST_CASE("fclaw_context_get_int called for non-existing value") +{ + fclaw_global_t* glob = fclaw_global_new_comm(sc_MPI_COMM_SELF, 1, 0); + fclaw_context_t *context = fclaw_context_get(glob, "test"); + fclaw_context_save(context); + + // second get call, since we didn't get_int in first, should fail + context = fclaw_context_get(glob, "test"); + int value; + CHECK_SC_ABORTED(fclaw_context_get_int(context, "test", &value)); +} + +TEST_CASE("fclaw_context_get_int called for non-exising value other value") +{ + fclaw_global_t* glob = fclaw_global_new_comm(sc_MPI_COMM_SELF, 1, 0); + fclaw_context_t *context = fclaw_context_get(glob, "test"); + int value = 0; + fclaw_context_get_int(context, "test", &value); + fclaw_context_save(context); + + context = fclaw_context_get(glob, "test"); + CHECK_SC_ABORTED(fclaw_context_get_int(context, "test-does-not-exist", &value)); +} + +TEST_CASE("fclaw_context_get_int save without getting all variables") +{ + fclaw_global_t* glob = fclaw_global_new_comm(sc_MPI_COMM_SELF, 1, 0); + fclaw_context_t *context = fclaw_context_get(glob, "test"); + int value = 0; + fclaw_context_get_int(context, "test", &value); + fclaw_context_save(context); + + // second get call, since we don't get_int, should fail + context = fclaw_context_get(glob, "test"); + CHECK_SC_ABORTED(fclaw_context_save(context)); +} + +TEST_CASE("fclaw_context_get_double new context") +{ + for(double default_value : {-100, 0, 42}) + { + fclaw_global_t* glob = fclaw_global_new_comm(sc_MPI_COMM_SELF, 1, 0); + fclaw_context_t *context = fclaw_context_get(glob, "test"); + double value = default_value; + fclaw_context_get_double(context, "test", &value); + CHECK_EQ(value, default_value); + fclaw_global_destroy(glob); + } +} + +TEST_CASE("fclaw_context_get_double new context two values") +{ + for(double default_value1 : {-100, 0, 42}) + for(double default_value2 : {-1, 1, 1024}) + { + fclaw_global_t* glob = fclaw_global_new_comm(sc_MPI_COMM_SELF, 1, 0); + fclaw_context_t *context = fclaw_context_get(glob, "test"); + double value1 = default_value1; + fclaw_context_get_double(context, "test1", &value1); + CHECK_EQ(value1, default_value1); + double value2 = default_value2; + fclaw_context_get_double(context, "test2", &value2); + CHECK_EQ(value2, default_value2); + fclaw_global_destroy(glob); + } +} + +TEST_CASE("fclaw_context_get_double existing context") +{ + for(double default_value : {-100, 0, 42}) + for(double changed_value : {-1, 4, 82}) + { + fclaw_global_t* glob = fclaw_global_new_comm(sc_MPI_COMM_SELF, 1, 0); + fclaw_context_t *context = fclaw_context_get(glob, "test"); + + double value = default_value; + + fclaw_context_get_double(context, "test", &value); + CHECK_EQ(value, default_value); + + fclaw_context_save(context); + double value2 = 0; + fclaw_context_get_double(context, "test", &value2); + CHECK_EQ(value2, default_value); + + value2 = changed_value; + fclaw_context_save(context); + double value3 = 0; + fclaw_context_get_double(context, "test", &value3); + CHECK_EQ(value3, changed_value); + + fclaw_global_destroy(glob); + } +} + +TEST_CASE("fclaw_context_get_double existing context two values") +{ + for(double default_value1 : {-100, 0, 42}) + for(double changed_value1 : {-1, 4, 82}) + for(double default_value2: {-100, 0, 42}) + for(double changed_value2: {-1, 4, 82}) + { + fclaw_global_t* glob = fclaw_global_new_comm(sc_MPI_COMM_SELF, 1, 0); + fclaw_context_t *context = fclaw_context_get(glob, "test"); + + double value = default_value1; + double value2 = default_value2; + + fclaw_context_get_double(context, "test1", &value); + fclaw_context_get_double(context, "test2", &value2); + + CHECK_EQ(value, default_value1); + CHECK_EQ(value2, default_value2); + + fclaw_context_save(context); + value = 0; value2 = 0; + + fclaw_context_get_double(context, "test1", &value); + fclaw_context_get_double(context, "test2", &value2); + + CHECK_EQ(value, default_value1); + CHECK_EQ(value2, default_value2); + + value = changed_value1; + value2 = changed_value2; + + fclaw_context_save(context); + value = 0; value2 = 0; + + fclaw_context_get_double(context, "test1", &value); + fclaw_context_get_double(context, "test2", &value2); + + CHECK_EQ(value, changed_value1); + CHECK_EQ(value2, changed_value2); + + fclaw_global_destroy(glob); + } +} + +TEST_CASE("fclaw_context_get_double called for non-existing value") +{ + fclaw_global_t* glob = fclaw_global_new_comm(sc_MPI_COMM_SELF, 1, 0); + fclaw_context_t *context = fclaw_context_get(glob, "test"); + fclaw_context_save(context); + + // second get call, since we didn't get_double in first, should fail + context = fclaw_context_get(glob, "test"); + double value; + CHECK_SC_ABORTED(fclaw_context_get_double(context, "test", &value)); +} + +TEST_CASE("fclaw_context_get_double called for non-exising value other value") +{ + fclaw_global_t* glob = fclaw_global_new_comm(sc_MPI_COMM_SELF, 1, 0); + fclaw_context_t *context = fclaw_context_get(glob, "test"); + double value = 0; + fclaw_context_get_double(context, "test", &value); + fclaw_context_save(context); + + context = fclaw_context_get(glob, "test"); + CHECK_SC_ABORTED(fclaw_context_get_double(context, "test-does-not-exist", &value)); +} + +TEST_CASE("fclaw_context_get_double save without getting all variables") +{ + fclaw_global_t* glob = fclaw_global_new_comm(sc_MPI_COMM_SELF, 1, 0); + fclaw_context_t *context = fclaw_context_get(glob, "test"); + double value = 0; + fclaw_context_get_double(context, "test", &value); + fclaw_context_save(context); + + // second get call, since we don't get_double, should fail + context = fclaw_context_get(glob, "test"); + CHECK_SC_ABORTED(fclaw_context_save(context)); +} + +TEST_CASE("fclaw_context_get_double and fclaw_context_get_int called for same value") +{ + for(int default_value : {-100, 0, 42}) + for(double default_double : {-100, 0, 42}) + { + fclaw_global_t* glob = fclaw_global_new_comm(sc_MPI_COMM_SELF, 1, 0); + fclaw_context_t *context = fclaw_context_get(glob, "test"); + + int value = default_value; + fclaw_context_get_int(context, "test", &value); + CHECK_EQ(value, default_value); + + double value_double = default_double; + fclaw_context_get_double(context, "test2", &value_double); + CHECK_EQ(value_double, default_double); + + fclaw_context_save(context); + value = 0; value_double = 0; + + fclaw_context_get_int(context, "test", &value); + fclaw_context_get_double(context, "test2", &value_double); + + CHECK_EQ(value, default_value); + CHECK_EQ(value_double, default_double); + + fclaw_global_destroy(glob); + } +} + +TEST_CASE("fclaw_context_get_double and fclaw_context_get_int called for same key") +{ + for(int default_value : {-100, 0, 42}) + for(double default_double : {-100, 0, 42}) + { + fclaw_global_t* glob = fclaw_global_new_comm(sc_MPI_COMM_SELF, 1, 0); + fclaw_context_t *context = fclaw_context_get(glob, "test"); + + int value = default_value; + fclaw_context_get_int(context, "test", &value); + CHECK_EQ(value, default_value); + + double value_double = default_double; + CHECK_SC_ABORTED(fclaw_context_get_double(context, "test", &value_double)); + } + + for(double default_double : {-100, 0, 42}) + { + fclaw_global_t* glob = fclaw_global_new_comm(sc_MPI_COMM_SELF, 1, 0); + fclaw_context_t *context = fclaw_context_get(glob, "test"); + + double value_double = default_double; + fclaw_context_get_double(context, "test", &value_double); + + int value; + CHECK_SC_ABORTED(fclaw_context_get_int(context, "test", &value)); + } +} + +TEST_CASE("fclaw_context pack/unpack glob int and double without save") +{ + for(int default_value : {-100, 0, 42}) + for(double default_double : {-100, 0, 42}) + { + fclaw_global_t* glob = fclaw_global_new_comm(sc_MPI_COMM_SELF, 1, 0); + fclaw_context_vtable_initialize(glob); + fclaw_context_t *context = fclaw_context_get(glob, "test"); + + int value = default_value; + fclaw_context_get_int(context, "test", &value); + CHECK_EQ(value, default_value); + + double value_double = default_double; + fclaw_context_get_double(context, "test2", &value_double); + CHECK_EQ(value_double, default_double); + + char buffer[fclaw_global_packsize(glob)]; + CHECK_SC_ABORTED(fclaw_global_pack(glob, buffer)); + } +} + +TEST_CASE("fclaw_context pack/unpack glob int and double") +{ + for(int default_value : {-100, 0, 42}) + for(double default_double : {-100, 0, 42}) + { + fclaw_global_t* glob = fclaw_global_new_comm(sc_MPI_COMM_SELF, 1, 0); + fclaw_context_vtable_initialize(glob); + fclaw_context_t *context = fclaw_context_get(glob, "test"); + + int value = default_value; + fclaw_context_get_int(context, "test", &value); + CHECK_EQ(value, default_value); + + double value_double = default_double; + fclaw_context_get_double(context, "test2", &value_double); + CHECK_EQ(value_double, default_double); + + fclaw_context_save(context); + + char buffer[fclaw_global_packsize(glob)]; + fclaw_global_pack(glob, buffer); + + fclaw_global_t* glob2 = fclaw_global_new_comm(sc_MPI_COMM_SELF, 1, 0); + fclaw_context_vtable_initialize(glob2); + + fclaw_global_unpack(buffer, glob2); + + fclaw_context_t *context2 = fclaw_context_get(glob2, "test"); + int value2 = 0; + double value_double2 = 0; + + fclaw_context_get_int(context2, "test", &value2); + CHECK_EQ(value2, default_value); + + fclaw_context_get_double(context2, "test2", &value_double2); + CHECK_EQ(value_double2, default_double); + + fclaw_global_destroy(glob); + fclaw_global_destroy(glob2); + } +} \ No newline at end of file diff --git a/src/fclaw_diagnostics.c b/src/fclaw_diagnostics.c index 9b9c3dd21..6fd0e8905 100644 --- a/src/fclaw_diagnostics.c +++ b/src/fclaw_diagnostics.c @@ -44,6 +44,11 @@ void diagnostics_vt_destroy(void* vt) FCLAW_FREE (vt); } +static +void diagnostics_accumulator_destroy(void* acc) +{ + FCLAW_FREE (acc); +} /* --------------------------------------------------- Public interface ------------------------------------------------ */ @@ -57,6 +62,14 @@ fclaw_diagnostics_vtable_t* fclaw_diagnostics_vt(fclaw_global_t* glob) return diagnostics_vt; } +fclaw_diagnostics_accumulator_t* fclaw_diagnostics_get_acc(fclaw_global_t* glob) +{ + fclaw_diagnostics_accumulator_t* acc = (fclaw_diagnostics_accumulator_t*) + fclaw_global_get_attribute(glob, "fclaw_diagnostics_accumulator"); + FCLAW_ASSERT(acc != NULL); + return acc; +} + /* global_maximum is in forestclaw2d.c */ double fclaw_domain_global_minimum (fclaw_domain_t* domain, double d) { @@ -93,7 +106,13 @@ void fclaw_diagnostics_initialize(fclaw_global_t *glob) { fclaw_diagnostics_vtable_t *diag_vt = fclaw_diagnostics_vt(glob); - fclaw_diagnostics_accumulator_t *acc = glob->acc; + fclaw_diagnostics_accumulator_t *acc = FCLAW_ALLOC(fclaw_diagnostics_accumulator_t, 1); + fclaw_global_attribute_store(glob, + "fclaw_diagnostics_accumulator", + acc, + NULL, + diagnostics_accumulator_destroy); + const fclaw_options_t *fclaw_opt = fclaw_get_options(glob); /* Return an error accumulator */ @@ -122,7 +141,7 @@ void fclaw_diagnostics_initialize(fclaw_global_t *glob) void fclaw_diagnostics_gather(fclaw_global_t *glob, int init_flag) { - fclaw_diagnostics_accumulator_t *acc = glob->acc; + fclaw_diagnostics_accumulator_t *acc = fclaw_diagnostics_get_acc(glob); const fclaw_options_t *fclaw_opt = fclaw_get_options(glob); fclaw_diagnostics_vtable_t *diag_vt = fclaw_diagnostics_vt(glob); @@ -182,7 +201,7 @@ void fclaw_diagnostics_gather(fclaw_global_t *glob, void fclaw_diagnostics_reset(fclaw_global_t *glob) { - fclaw_diagnostics_accumulator_t *acc = glob->acc; + fclaw_diagnostics_accumulator_t *acc = fclaw_diagnostics_get_acc(glob); const fclaw_options_t *fclaw_opt = fclaw_get_options(glob); fclaw_diagnostics_vtable_t *diag_vt = fclaw_diagnostics_vt(glob); @@ -208,7 +227,7 @@ void fclaw_diagnostics_reset(fclaw_global_t *glob) void fclaw_diagnostics_finalize(fclaw_global_t *glob) { - fclaw_diagnostics_accumulator_t *acc = glob->acc; + fclaw_diagnostics_accumulator_t *acc = fclaw_diagnostics_get_acc(glob); const fclaw_options_t *fclaw_opt = fclaw_get_options(glob); fclaw_diagnostics_vtable_t *diag_vt = fclaw_diagnostics_vt(glob); diff --git a/src/fclaw_diagnostics.h b/src/fclaw_diagnostics.h index b49fa9468..b2486ee1d 100644 --- a/src/fclaw_diagnostics.h +++ b/src/fclaw_diagnostics.h @@ -106,6 +106,15 @@ struct fclaw_diagnostics_vtable fclaw_diagnostics_vtable_t* fclaw_diagnostics_vt(struct fclaw_global* glob); + +/** + * @brief get the accumulator for diagnostic information + * + * @param glob global context + * @return fclaw_diagnostics_accumulator_t accumulator + */ +fclaw_diagnostics_accumulator_t* fclaw_diagnostics_get_acc(struct fclaw_global* glob); + void fclaw_diagnostics_vtable_initialize(struct fclaw_global* glob); double fclaw_domain_global_minimum (struct fclaw_domain* domain, double d); diff --git a/src/fclaw_file.c b/src/fclaw_file.c new file mode 100644 index 000000000..f2b0f0313 --- /dev/null +++ b/src/fclaw_file.c @@ -0,0 +1,318 @@ +/* +Copyright (c) 2012 Carsten Burstedde, Donna Calhoun +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, this +list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright notice, +this list of conditions and the following disclaimer in the documentation +and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#include +#include +#include +#include +#include + +struct fclaw_file_context +{ + int refine_dim; + fclaw2d_file_context_t *d2; + fclaw3d_file_context_t *d3; +}; + +static fclaw_file_context_t *wrap_file_2d(fclaw2d_file_context_t *d2) +{ + if(d2 == NULL) + { + return NULL; + } + fclaw_file_context_t *fc = FCLAW_ALLOC (fclaw_file_context_t, 1); + fc->refine_dim = 2; + fc->d2 = d2; + fc->d3 = NULL; + return fc; +} + +static fclaw_file_context_t *wrap_file_3d(fclaw3d_file_context_t *d3) +{ + if(d3 == NULL) + { + return NULL; + } + fclaw_file_context_t *fc = FCLAW_ALLOC (fclaw_file_context_t, 1); + fc->refine_dim = 3; + fc->d2 = NULL; + fc->d3 = d3; + return fc; +} + +/* handle the return when the returned file context is NULL */ +static +fclaw_file_context_t* handle_return_value(fclaw_file_context_t * fc) +{ + if(fc->d2 == NULL && fc->d3 == NULL) + { + FCLAW_FREE(fc); + return NULL; + } + else + { + return fc; + } +} + +fclaw_file_context_t *fclaw_file_open_write (const char *filename, + const char *user_string, + fclaw_domain_t * domain, + int *errcode) +{ + if(domain->refine_dim == 2) + { + fclaw2d_file_context_t *d2 = fclaw2d_file_open_write (filename, user_string, + domain->d2, errcode); + *errcode = fclaw2d_file_error_wrap(*errcode); + return wrap_file_2d(d2); + } + else if(domain->refine_dim == 3) + { + fclaw3d_file_context_t *d3 = fclaw3d_file_open_write (filename, user_string, + domain->d3, errcode); + *errcode = fclaw3d_file_error_wrap(*errcode); + return wrap_file_3d(d3); + } + else + { + SC_ABORT_NOT_REACHED (); + } +} + +int fclaw_file_write_partition (const char *filename, + const char *user_string, + fclaw_domain_t * domain, int *errcode) +{ + if(domain->refine_dim == 2) + { + int retval = fclaw2d_file_write_partition (filename, user_string, domain->d2, errcode); + *errcode = fclaw2d_file_error_wrap(*errcode); + return retval; + } + else if(domain->refine_dim == 3) + { + int retval = fclaw3d_file_write_partition (filename, user_string, domain->d3, errcode); + *errcode = fclaw3d_file_error_wrap(*errcode); + return retval; + } + else + { + SC_ABORT_NOT_REACHED (); + } +} + +fclaw_file_context_t *fclaw_file_write_block (fclaw_file_context_t * + fc, const char *user_string, + size_t block_size, + sc_array_t * block_data, + int *errcode) +{ + if(fc->refine_dim == 2) + { + fc->d2 = fclaw2d_file_write_block (fc->d2, user_string, + block_size, block_data, errcode); + *errcode = fclaw2d_file_error_wrap(*errcode); + } + else if(fc->refine_dim == 3) + { + fc->d3 = fclaw3d_file_write_block (fc->d3, user_string, + block_size, block_data, errcode); + *errcode = fclaw3d_file_error_wrap(*errcode); + } + else + { + SC_ABORT_NOT_REACHED (); + } + return handle_return_value(fc); +} + +fclaw_file_context_t *fclaw_file_write_array (fclaw_file_context_t * + fc, const char *user_string, + size_t patch_size, + sc_array_t * patch_data, + int *errcode) +{ + if(fc->refine_dim == 2) + { + fc->d2 = fclaw2d_file_write_array (fc->d2, user_string, + patch_size, patch_data, errcode); + *errcode = fclaw2d_file_error_wrap(*errcode); + } + else if(fc->refine_dim == 3) + { + fc->d3 = fclaw3d_file_write_array (fc->d3, user_string, + patch_size, patch_data, errcode); + *errcode = fclaw3d_file_error_wrap(*errcode); + } + else + { + SC_ABORT_NOT_REACHED (); + } + return handle_return_value(fc); +} + +int fclaw_file_read_partition (int refine_dim, + const char *filename, char *user_string, + sc_MPI_Comm mpicomm, sc_array_t * partition, + int *errcode) +{ + if(refine_dim == 2) + { + int retval = fclaw2d_file_read_partition (filename, user_string, mpicomm, partition, errcode); + *errcode = fclaw2d_file_error_wrap(*errcode); + return retval; + } + else if(refine_dim == 3) + { + int retval = fclaw3d_file_read_partition (filename, user_string, mpicomm, partition, errcode); + *errcode = fclaw3d_file_error_wrap(*errcode); + return retval; + } + else + { + fclaw_abortf("Invalid refine_dim %d\n", refine_dim); + } +} + +fclaw_file_context_t *fclaw_file_open_read (int refine_dim, + const char *filename, + char *user_string, + sc_MPI_Comm mpicomm, + sc_array_t * partition, + fclaw_domain_t ** domain, + int *errcode) +{ + if(refine_dim == 2) + { + fclaw2d_domain_t *new_domain; + fclaw2d_file_context_t *d2 = fclaw2d_file_open_read (filename, user_string, + mpicomm, partition, &new_domain, errcode); + + *domain = fclaw_domain_wrap_2d(new_domain); + *errcode = fclaw2d_file_error_wrap(*errcode); + return wrap_file_2d(d2); + } + else if(refine_dim == 3) + { + fclaw3d_domain_t *new_domain; + fclaw3d_file_context_t *d3 = fclaw3d_file_open_read (filename, user_string, + mpicomm, partition, &new_domain, errcode); + *domain = fclaw_domain_wrap_3d(new_domain); + *errcode = fclaw3d_file_error_wrap(*errcode); + return wrap_file_3d(d3); + } + else + { + fclaw_abortf("Invalid refine_dim %d\n", refine_dim); + } +} + +fclaw_file_context_t *fclaw_file_read_block (fclaw_file_context_t * + fc, char *user_string, + size_t block_size, + sc_array_t * block_data, + int *errcode) +{ + if(fc->refine_dim == 2) + { + fc->d2 = fclaw2d_file_read_block (fc->d2, user_string, + block_size, block_data, errcode); + *errcode = fclaw2d_file_error_wrap(*errcode); + } + else if(fc->refine_dim == 3) + { + fc->d3 = fclaw3d_file_read_block (fc->d3, user_string, + block_size, block_data, errcode); + *errcode = fclaw3d_file_error_wrap(*errcode); + } + else + { + SC_ABORT_NOT_REACHED (); + } + return handle_return_value(fc); +} + +fclaw_file_context_t *fclaw_file_read_array (fclaw_file_context_t * + fc, char *user_string, + size_t patch_size, + sc_array_t * patch_data, + int *errcode) +{ + if(fc->refine_dim == 2) + { + fc->d2 = fclaw2d_file_read_array (fc->d2, user_string, + patch_size, patch_data, errcode); + *errcode = fclaw2d_file_error_wrap(*errcode); + } + else if(fc->refine_dim == 3) + { + fc->d3 = fclaw3d_file_read_array (fc->d3, user_string, + patch_size, patch_data, errcode); + *errcode = fclaw3d_file_error_wrap(*errcode); + } + else + { + SC_ABORT_NOT_REACHED (); + } + return handle_return_value(fc); +} + +int fclaw_file_close (fclaw_file_context_t * fc, int *errcode) +{ + int retval; + if(fc->refine_dim == 2) + { + retval = fclaw2d_file_close (fc->d2, errcode); + *errcode = fclaw2d_file_error_wrap(*errcode); + } + else if(fc->refine_dim == 3) + { + retval = fclaw3d_file_close (fc->d3, errcode); + *errcode = fclaw3d_file_error_wrap(*errcode); + } + else + { + SC_ABORT_NOT_REACHED (); + } + FCLAW_FREE(fc); + return retval; +} + +int fclaw_file_error_string (int refine_dim, int errcode, char *string, int *resultlen) +{ + if(refine_dim == 2) + { + return fclaw2d_file_error_string (errcode, string, resultlen); + } + else if(refine_dim == 3) + { + return fclaw3d_file_error_string (errcode, string, resultlen); + } + else + { + fclaw_abortf("Invalid refine_dim %d\n", refine_dim); + } +} diff --git a/src/fclaw_file.h b/src/fclaw_file.h new file mode 100644 index 000000000..1f80fd52d --- /dev/null +++ b/src/fclaw_file.h @@ -0,0 +1,512 @@ +/* +Copyright (c) 2012 Carsten Burstedde, Donna Calhoun +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, this +list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright notice, +this list of conditions and the following disclaimer in the documentation +and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +/** \file fclaw_file.h + * Routines for parallel IO for \ref fclaw_domain_t and generic data. + * + * Principle: All files are associated with a single domain, i.e. one can + * write only one domain to one file. + */ + +#ifndef FCLAW_FILE_H +#define FCLAW_FILE_H + +#include + +#ifdef __cplusplus +extern "C" +{ +#if 0 +} /* need this because indent is dumb */ +#endif +#endif + +#define FCLAW_FILE_USER_STRING_BYTES 48 /**< number of user string bytes */ +#define FCLAW_FILE_MAX_BLOCK_SIZE ((1000L * 1000L * 1000L * 1000L * 10L) - 1L) /**< maximal data size of a block */ +#define FCLAW_FILE_MAX_FIELD_ENTRY_SIZE ((1000L * 1000L * 1000L * 1000L * 10L) - 1L) /**< maximal data size per field entry*/ + +/** Error values for fclaw_file functions. + * In the future we may add further error codes. Therefore, the error codes + * should only be used by the enum but not by the explicit numeric values since + * these explicit numeric values may change. + */ +typedef enum fclaw_file_error +{ + FCLAW_FILE_ERR_SUCCESS = 0, /**< file function completed with success */ + FCLAW_FILE_ERR_FILE = sc_MPI_ERR_LASTCODE, /**< invalid file handle */ + FCLAW_FILE_ERR_NOT_SAME, /**< collective arg not identical */ + FCLAW_FILE_ERR_AMODE, /**< access mode error */ + FCLAW_FILE_ERR_NO_SUCH_FILE, /**< file does not exist */ + FCLAW_FILE_ERR_FILE_EXIST, /**< file exists already */ + FCLAW_FILE_ERR_BAD_FILE, /**< invalid file name */ + FCLAW_FILE_ERR_ACCESS, /**< permission denied */ + FCLAW_FILE_ERR_NO_SPACE, /**< not enough space */ + FCLAW_FILE_ERR_QUOTA, /**< quota exceeded */ + FCLAW_FILE_ERR_READ_ONLY, /**< read only file (system) */ + FCLAW_FILE_ERR_IN_USE, /**< file currently open by other process */ + FCLAW_FILE_ERR_IO, /**< other I/O error */ + FCLAW_FILE_ERR_FORMAT, /**< read file has a wrong format */ + FCLAW_FILE_ERR_SECTION_TYPE, /**< a valid non-matching section type */ + FCLAW_FILE_ERR_CONN, /**< invalid serialized connectivity data */ + FCLAW_FILE_ERR_P4EST, /**< invalid p4est data */ + FCLAW_FILE_ERR_IN_DATA, /**< input data of file function is invalid */ + FCLAW_FILE_ERR_COUNT, /**< read or write count error that was not + classified as a format error */ + FCLAW_FILE_ERR_DIM, /**< file has wrong dimension */ + FCLAW_FILE_ERR_UNKNOWN, /**< unknown error */ + FCLAW_FILE_ERR_PART, /**< invalid partition data */ + FCLAW_FILE_ERR_NOT_IMPLEMENTED, /**< functionality is not implemented */ + FCLAW_FILE_ERR_LASTCODE /**< to define own error codes for + a higher level application + that is using fclaw_file + functions */ +} +fclaw_file_error_t; + +/** Opaque context used for writing a fclaw2d data file. */ +typedef struct fclaw_file_context fclaw_file_context_t; + +/** Create and open a file that is associated with the given domain structure. + * + * This is a collective function call that overwrites the file if it exists + * already. This function writes a header with metadata of the underlying + * p4est of the passed \b domain to the file. In addition, the passed \b domain + * is written to the file. + * + * The opened file can be used to write to the file using the functions + * \ref fclaw_file_write_block, \ref fclaw_file_write_array and + * potentially other functions operating on \ref fclaw_file_context_t that + * may be implemented on the top of the current fclaw_file routines. + * + * This function does not abort on MPI I/O errors but returns NULL. + * Without MPI I/O the function may abort on file system dependent + * errors. + * + * \param [in] filename Path to parallel file that is to be created. + * \param [in] user_string A NUL-terminated user string that is written to the + * file header having FCLAW_FILE_USER_STRING_BYTES + * bytes including the NUL-termination. Shorter + * user strings are padded by spaces in the file header. + * Too long user strings result in an error with the + * error code \ref FCLAW_FILE_ERR_IN_DATA. + * \param [in] domain The underlying p4est is used for the metadata of the + * the created file and the \b domain is written to the + * file. + * \param [out] errcode An errcode that can be interpreted by + * \ref fclaw_file_error_string. + * \return Newly allocated context to continue writing and + * eventually closing the file. NULL in case of error. + */ +fclaw_file_context_t *fclaw_file_open_write (const char *filename, + const char *user_string, + fclaw_domain_t * domain, + int *errcode); + +/** Write the partition of a domain to a partition file. + * + * This function writes the partition of the passed \b domain to a partition + * file. The user can read the partition to an array using \ref + * fclaw_file_read_partition and then pass the read array to \ref + * fclaw_file_open_read to use the read partition. + * + * The function and all its parameters are collective. + * + * This function does not abort on MPI I/O errors but returns -1. + * Without MPI I/O the function may abort on file system dependent + * errors. + * + * \param [in] filename Path to partition file that is to be created. + * \param [in] user_string A NUL-terminated user string that is written to + * the partition file header having \ref + * FCLAW_FILE_USER_STRING_BYTES bytes including + * the NUL-termination. Shorter user strings are + * padded by spaces in the file header. + * Too long user strings result in an error with the + * error code \ref FCLAW_FILE_ERR_IN_DATA. + * \param [out] errcode An errcode that can be interpreted by + * \ref fclaw_file_error_string. + * \return 0 for a successful write of the partition file. + * -1 in case of an error. + */ +int fclaw_file_write_partition (const char *filename, + const char *user_string, + fclaw_domain_t * domain, int *errcode); + +/** Write a serial data block to an opened parallel file. + * + * This is a collective function. + * This function writes a serial data block to the opened file. + * + * The number of block bytes must be less or equal \ref + * FCLAW_FILE_MAX_BLOCK_SIZE. + * + * This function does not abort on MPI I/O errors but returns NULL. + * Without MPI I/O the function may abort on file system dependent + * errors. + * + * \param [in, out] fc Context previously created by \ref + * fclaw_file_open_write. It keeps track + * of the data sets written one after another. + * \param [in] user_string A NUL-terminated user string that is written to + * the section header having + * FCLAW_FILE_USER_STRING_BYTES bytes including + * the NUL-termination. Shorter user strings are + * padded by spaces in the section header. Too long + * user strings result in an error with the error + * code \ref FCLAW_FILE_ERR_IN_DATA. + * \param [in] block_size The size of the block in bytes. May be equal to + * 0. In this case the section header and the padding + * is still written. This function returns the passed + * \b fc parameter and sets errcode to \ref + * FCLAW_FILE_ERR_SUCCESS if it is called for + * \b block_size == 0. + * \param [in] block_data A sc_array with one element and element size + * equal to \b block_size. + * The array points to the block data. The user is + * responsible for the validality of the block + * data. block_data can be NULL if \b block_size == 0. + * \param [out] errcode An errcode that can be interpreted by + * \ref fclaw_file_error_string. + * \return Return a pointer to input context or NULL in case + * of errors that does not abort the program. + * In case of error the file is tried to close + * and \b fc is freed. + */ +fclaw_file_context_t *fclaw_file_write_block (fclaw_file_context_t * + fc, const char *user_string, + size_t block_size, + sc_array_t * block_data, + int *errcode); + +/** Write per-patch data to a parallel output file. + * + * This is a collective function. + * This function writes the per-patch data with respect the domain that was passed + * to the \ref fclaw_file_open_write for opening the file. + * + * The per-patch data is written in parallel according to the partition of the + * domain and the underlying p4est, respectively. + * The data size per patch must be fixed. + * + * This function does not abort on MPI I/O errors but returns NULL. + * Without MPI I/O the function may abort on file system dependent + * errors. + * + * \param [in, out] fc Context previously created by \ref + * fclaw_file_open_write. It keeps track + * of the data sets written one after another. + * \param [in] user_string A NUL-terminated user string that is written to + * the section header having + * FCLAW_FILE_USER_STRING_BYTES bytes including + * the NUL-termination. Shorter user strings are + * padded by spaces in the section header. Too long + * user strings result in an error with the error + * code \ref FCLAW_FILE_ERR_IN_DATA. + * \param [in] patch_size The number of bytes per patch. This number + * must coincide with \b patch_data->elem_size. + * \param [in] patch_data An array of the length number of local patches + * with the element size equal to sizeof (sc_array_t). + * This means each element of \b patch_data must be + * a sc_array. These sc_arrays must have an element + * size of \b patch_size and store the actual + * patch data. This memory layout enables the user + * to write by indirect addressing, i.e. to write + * non-contigous patch data. The patch data is + * expected to be stored according to the Morton + * order of the patches. For \b patch_size == 0 + * the function writes an empty array. The section + * header and the padding is still written. + * In this case the function passes successfully and + * \b errcode is set to \ref FCLAW_FILE_ERR_SUCCESS. + * \param [out] errcode An errcode that can be interpreted by + * \ref fclaw_file_error_string. + * \return Return a pointer to input context or NULL in case + * of errors that does not abort the program. + * In case of error the file is tried to close + * and \b fc is freed. + */ +fclaw_file_context_t *fclaw_file_write_array (fclaw_file_context_t * + fc, const char *user_string, + size_t patch_size, + sc_array_t * patch_data, + int *errcode); + +/** Read a partition array from file. + * + * This function reads the partition array, i.e. the global first patch + * array from a partition file that was written using + * \ref fclaw_file_write_partition. The read partition can be passed to + * \ref fclaw_file_open_read. + * + * This function guarantees that on successful output the read partition + * is valid in the sense that the partition array has 0 as first entry and is + * non-decreasing. + * + * The function and all its parameters are collective. + * + * This function does not abort on MPI I/O errors but returns -1. + * Without MPI I/O the function may abort on file system dependent + * errors. + * + * \param [in] refine_dim The refine dimension. + * \param [in] filename The path to the partition file. + * \param [out] user_string At least \ref FCLAW_FILE_USER_STRING_BYTES + * bytes. The user string is written + * to the passed array including padding spaces + * and a trailing NUL-termination. + * \param [in] mpicomm The MPI communicator is required to synchronize + * the \b errcode and the output array \b partition. + * It is important to notice that \b partition is + * only available on MPI ranks that are part of the + * passed \b mpicomm. Therefore, \b mpicomm should + * coincide with the mpicomm parameter of \ref + * fclaw_file_open_read to ensure that the + * partition parameter of \ref + * fclaw_file_open_read is collectivly available. + * \param [out] partition A sc_array with element size equals to + * sizeof (p4est_gloidx_t). On successful output + * the array is filled with the read partition. + * In case of an error, the function does not + * guarantee that \b partition stays untouched + * but it is guaranteed that the user is not + * required to call \ref sc_array_reset on + * \b partition. + * \param [out] errcode An errcode that can be interpreted by + * \ref fclaw_file_error_string. + * \return 0 for a successful read of the partition file. + * -1 in case of an error. + */ +int fclaw_file_read_partition (int refine_dim, + const char *filename, char *user_string, + sc_MPI_Comm mpicomm, sc_array_t * partition, + int *errcode); + +/** Open a file for reading and read the stored domain. + * The user string is broadcasted to all ranks after reading. + * The file must exist and be at least of the size of the file header. + * + * This is a collective function. + * If the file has wrong metadata the function reports the error using + * \ref fclaw_errorf, collectively closes the file and deallocates + * the file context. In this case the function returns NULL on all ranks. + * The wrong file format or a wrong file header causes \ref FCLAW_FILE_ERR_FORMAT + * as errcode. + * + * After calling this function the user can continue reading the opened file + * by calling \ref fclaw_file_read_block, \ref fclaw_file_read_array and + * potentially other functions operating on \ref fclaw_file_context_t that + * may be implemented on the top of the current fclaw_file routines. + * + * This function does not abort on MPI I/O errors but returns NULL. + * Without MPI I/O the function may abort on file system dependent + * errors. + * + * \param [in] refine_dim The refinement dimension. + * \param [in] filename The path to the file that is opened. + * \param [out] user_string At least \ref FCLAW_FILE_USER_STRING_BYTES + * bytes. The user string is written + * to the passed array including padding spaces + * and a trailing NUL-termination. + * \param [in] mpicomm MPI communicator that is used to read the file and + * is used for potential other reading operations of + * MPI communicator dependent objects. + * \param [in] partition A sc_array of the size of number of MPI ranks + 1 + * with sizeof (p4est_gloidx_t) as element size + * or NULL. + * The sc_array must contain a valid partition, i.e. + * the first element is 0, the array is + * non-decreasing and the last array entry equals + * the number of global patches of the domain in + * the file pointed to by \b filename. + * If any of these conditions is violated, the + * function returns NULL and set \b errcode to + * \ref FCLAW_FILE_ERR_PART. + * The user can pass NULL for using the uniform + * partition with respect to the quadrant count. + * In both cases the respective partition, either + * read or computed, is used for the parallel I/O + * operations and stored in the returned \b domain. + * The user can use \ref fclaw_file_read_partition + * to read a partition array from file. + * \param [out] domain Newly allocated domain that is read from the file. + * \param [out] errcode An errcode that can be interpreted by + * \ref fclaw_file_error_string. + * \return Newly allocated context to continue reading + * and eventually closing the file. NULL in + * case of error. + */ +fclaw_file_context_t *fclaw_file_open_read (int refine_dim, + const char *filename, + char *user_string, + sc_MPI_Comm mpicomm, + sc_array_t * partition, + fclaw_domain_t ** domain, + int *errcode); + +/** Read a serial data block from an opened file. + * + * This is a collective function. + * + * This function requires an opened file context. + * + * The passed \b block_size is compared to the block size stored in the file. + * If the values do not equal each other, the function reports details, closes + * and deallocates the file context. The return value in this case is NULL. + * If the data block section header information is not matching the passed + * parameters the function sets \ref FCLAW_FILE_ERR_FORMAT for errcode. + * + * This function does not abort on MPI I/O errors but returns NULL. + * Without MPI I/O the function may abort on file system dependent + * errors. + * + * \param [in] fc Context previously created by \ref + * fclaw_file_open_read. It keeps track + * of the data sets read one after another. + * \param [out] user_string At least \ref FCLAW_FILE_USER_STRING_BYTES + * bytes. The user string is written + * to the passed array including padding spaces + * and a trailing NUL-termination. + * \param [in] block_size The size of the header that is read. + * \param [in, out] block_data \b block_size allocated bytes in an sc_array + * with one element and \b block_size as element + * size. This data will be filled with the block + * data from the file. If this is NULL it means that + * the current header block is skipped and the + * internal file pointer of the file context is + * set to the next data section. If the current data + * section is not a data block, the file is closed + * and the file context is deallocated. Furthermore, + * in this case the function returns NULL and sets + * errcode to \ref FCLAW_FILE_ERR_FORMAT. In case + * of skipping the data block section \b block_size + * needs also to coincide with the data block size + * given in the file. + * \param [out] errcode An errcode that can be interpreted by + * \ref fclaw_file_error_string. + * \return Return a pointer to input context or NULL in case + * of errors that does not abort the program. + * In case of error the file is tried to close + * and \b fc is freed. + */ +fclaw_file_context_t *fclaw_file_read_block (fclaw_file_context_t * + fc, char *user_string, + size_t block_size, + sc_array_t * block_data, + int *errcode); + +/** Read per-patch data from a parallel output file. + * + * This is a collective function. + * The function closes and deallocates the file context and returns NULL + * if the bytes the user wants to read exceed the given file and/or + * the element size of the array given by \b patch_data->elem_size does not + * coincide with the element size according to the array metadata given in + * the file. + * + * The data is read in parallel using the partition of the domain (and the + * underlying p4est) that is associated with the passed file context in the + * sense that the file context was created using the respective domain. + * The data size per patch must be fixed. + * + * This function does not abort on MPI I/O errors but returns NULL. + * Without MPI I/O the function may abort on file system dependent + * errors. + * + * \param [in] fc Context previously created by \ref + * fclaw_file_open_read. It keeps track + * of the data sets read one after another. + * \param [out] user_string At least \ref FCLAW_FILE_USER_STRING_BYTES + * bytes. The user string is written + * to the passed array including padding spaces + * and a trailing NUL-termination. + * \param [in] patch_size The number of bytes per patch. This number + * must coincide with \b patch_data->elem_size. + * \param [in,out] patch_data An array of the length number of local patches + * with the element size equal to sizeof (sc_array_t). + * This means each element of \b patch_data must be + * a sc_array. These sc_arrays must have an element + * size of \b patch_size. This memory layout enables + * the user to read by indirect addressing, i.e. to + * read into non-contigous patch data. The patch data + * is read according to the Morton order of the patches. + * \b patch_size must coincide with the section data + * size in the file. \b patch_data == NULL means that + * the data is skipped and the internal file pointer + * is incremented. In the case of skipping + * \b patch_size is still checked using the + * corresponding value read from the file. The data + * is read using the partition of patches given by the + * domain that is associated to \b fc. + * \param [out] errcode An errcode that can be interpreted by + * \ref fclaw_file_error_string. + * \return Return a pointer to input context or NULL in case + * of errors that does not abort the program. + * In case of error the file is tried to close + * and \b fc is freed. + */ +fclaw_file_context_t *fclaw_file_read_array (fclaw_file_context_t * + fc, char *user_string, + size_t patch_size, + sc_array_t * patch_data, + int *errcode); + +/** Close a file opened for parallel write/read and free the context. + * + * This is a collective function. + * + * This function does not abort on MPI I/O errors but returns NULL. + * Without MPI I/O the function may abort on file system dependent + * errors. + * + * \param [in,out] fc Context previously created by \ref + * fclaw_file_open_write or \ref + * fclaw_file_open_read. Is freed. + * \param [out] errcode An errcode that can be interpreted by \ref + * fclaw_file_error_string. + * \return 0 for a successful call and -1 in case of + * an error. See also errcode argument. + */ +int fclaw_file_close (fclaw_file_context_t * fc, int *errcode); + +/** Turn fclaw_file errcode into a string. + * + * \param [in] refine_dim The refinement dimension. + * \param [in] errcode An errcode that is output by a + * fclaw_file function. + * \param [in,out] string At least sc_MPI_MAX_ERROR_STRING bytes. + * \param [out] resultlen Length of string on return. + * \return 0 on success or + * something else on invalid arguments. + */ +int fclaw_file_error_string (int refine_dim, int errcode, char *string, int *resultlen); + +#ifdef __cplusplus +#if 0 +{ /* need this because indent is dumb */ +#endif +} +#endif + +#endif /* !FCLAW_FILE_H */ diff --git a/src/fclaw_forestclaw.c b/src/fclaw_forestclaw.c index 93fc51864..3a74c4265 100644 --- a/src/fclaw_forestclaw.c +++ b/src/fclaw_forestclaw.c @@ -31,6 +31,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include #include #include +#include #include @@ -42,6 +43,7 @@ void fclaw_vtables_initialize(fclaw_global_t *glob) fclaw_elliptic_vtable_initialize(glob); fclaw_gauges_vtable_initialize(glob); fclaw_ray_vtable_initialize(glob); + fclaw_context_vtable_initialize(glob); } void fclaw_problem_setup(fclaw_global_t *glob) diff --git a/src/fclaw_forestclaw.h b/src/fclaw_forestclaw.h index ac4b143c0..20e46e373 100644 --- a/src/fclaw_forestclaw.h +++ b/src/fclaw_forestclaw.h @@ -38,8 +38,20 @@ struct fclaw_global; void fclaw_problem_setup(struct fclaw_global *glob); void fclaw_vtables_initialize(struct fclaw_global *glob); +/** + * @brief Intialize flags in the domain + * + * @param glob the global context + */ +void fclaw_initialize_domain_flags(struct fclaw_global *glob); void fclaw_initialize (struct fclaw_global *glob); +/** + * @brief Perform a restart. This will use the settings in fclaw_options + * + * @param glob the global context + */ +void fclaw_restart (struct fclaw_global *glob); void fclaw_run (struct fclaw_global *glob); void fclaw_finalize(struct fclaw_global *glob); diff --git a/src/fclaw_gauges.c b/src/fclaw_gauges.c index cc80a21d5..1dfd6d079 100644 --- a/src/fclaw_gauges.c +++ b/src/fclaw_gauges.c @@ -106,7 +106,12 @@ void gauge_initialize(fclaw_global_t* glob, void** acc) gauge_acc->dim = gauge_dim; - glob->gauge_info = FCLAW_ALLOC_ZERO(fclaw_gauge_info_t,1); + fclaw_gauge_info_t *gauge_info = FCLAW_ALLOC_ZERO(fclaw_gauge_info_t,1); + fclaw_global_attribute_store(glob, + "gauge_info", + gauge_info, + NULL, + NULL); if (num_gauges > 0) { @@ -146,11 +151,11 @@ void gauge_initialize(fclaw_global_t* glob, void** acc) int num_blocks = glob->domain->num_blocks; - glob->gauge_info->block_offsets = sc_array_new_count(sizeof(int), + gauge_info->block_offsets = sc_array_new_count(sizeof(int), num_blocks+1); - glob->gauge_info->coordinates = sc_array_new_count(gauge_dim*sizeof(double), - num_gauges); + gauge_info->coordinates = sc_array_new_count(gauge_dim*sizeof(double), + num_gauges); /* We don't know how the blocks are arranged in the brick domain so we reverse engineer this information */ @@ -160,7 +165,7 @@ void gauge_initialize(fclaw_global_t* glob, void** acc) fclaw_block_t *blocks = glob->domain->blocks; int number_of_gauges_set = 0; - int *bo = (int*) sc_array_index_int(glob->gauge_info->block_offsets,0); + int *bo = (int*) sc_array_index_int(gauge_info->block_offsets,0); bo[0] = 0; double p0[gauge_dim]; @@ -253,7 +258,7 @@ void gauge_initialize(fclaw_global_t* glob, void** acc) domain in [0,mi]x[0,mj]. This may not work for the cubed sphere case */ - double *c = (double*) sc_array_index_int(glob->gauge_info->coordinates, ng); + double *c = (double*) sc_array_index_int(gauge_info->coordinates, ng); c[0] = fclaw_opt->mi*(p[0] - xll); c[1] = fclaw_opt->mj*(p[1] - yll); if (gauge_dim == 3) @@ -268,7 +273,7 @@ void gauge_initialize(fclaw_global_t* glob, void** acc) } /* Set number of gauges for block nb */ - bo = (int*) sc_array_index_int(glob->gauge_info->block_offsets, nb+1); + bo = (int*) sc_array_index_int(gauge_info->block_offsets, nb+1); bo[0] = number_of_gauges_set; total_gauges_set += number_of_gauges_set; } @@ -351,7 +356,7 @@ void fclaw_locate_gauges(fclaw_global_t *glob) fclaw_gauge_acc_t* gauge_acc = - (fclaw_gauge_acc_t*) glob->acc->gauge_accumulator; + (fclaw_gauge_acc_t*) fclaw_diagnostics_get_acc(glob)->gauge_accumulator; //fclaw_gauge_info_t* gauge_info = glob->gauge_info; /* Locate each gauge in the new mesh */ @@ -364,9 +369,11 @@ void fclaw_locate_gauges(fclaw_global_t *glob) sc_array_t *results = sc_array_new_size(sizeof(int), num); + fclaw_gauge_info_t* gauge_info = + (fclaw_gauge_info_t *) fclaw_global_get_attribute(glob,"gauge_info"); fclaw_domain_search_points(glob->domain, - glob->gauge_info->block_offsets, - glob->gauge_info->coordinates, results); + gauge_info->block_offsets, + gauge_info->coordinates, results); for (i = 0; i < gauge_acc->num_gauges; ++i) { @@ -399,7 +406,8 @@ void gauge_finalize(fclaw_global_t *glob, void** acc) /* Clean up gauges and print anything left over in buffers */ fclaw_gauge_acc_t* gauge_acc = *((fclaw_gauge_acc_t**) acc); fclaw_gauge_t *gauges = gauge_acc->gauges; - fclaw_gauge_info_t* gauge_info = glob->gauge_info; + fclaw_gauge_info_t* gauge_info = + (fclaw_gauge_info_t *) fclaw_global_get_attribute(glob,"gauge_info"); for(int i = 0; i < gauge_acc->num_gauges; i++) { @@ -420,14 +428,14 @@ void gauge_finalize(fclaw_global_t *glob, void** acc) FCLAW_FREE(gauge_acc->gauges); } - if (glob->gauge_info->block_offsets != NULL) + if (gauge_info->block_offsets != NULL) { - sc_array_destroy(glob->gauge_info->block_offsets); + sc_array_destroy(gauge_info->block_offsets); } - if (glob->gauge_info->coordinates != NULL) + if (gauge_info->coordinates != NULL) { - sc_array_destroy(glob->gauge_info->coordinates); + sc_array_destroy(gauge_info->coordinates); } FCLAW_FREE(gauge_acc); diff --git a/src/fclaw_global.c b/src/fclaw_global.c index 7205d822c..507a99a5d 100644 --- a/src/fclaw_global.c +++ b/src/fclaw_global.c @@ -37,8 +37,10 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include #include #include +#include -fclaw_global_t* fclaw_global_new (void) +static +fclaw_global_t* global_new (void) { fclaw_global_t *glob; @@ -52,6 +54,7 @@ fclaw_global_t* fclaw_global_new (void) glob->pkg_container = fclaw_package_container_new (); glob->vtables = fclaw_pointer_map_new (); glob->options = fclaw_pointer_map_new (); + glob->attributes = fclaw_pointer_map_new (); glob->count_amr_advance = 0; glob->count_ghost_exchange = 0; @@ -66,10 +69,26 @@ fclaw_global_t* fclaw_global_new (void) glob->curr_time = 0; glob->cont = NULL; -#ifndef P4_TO_P8 - /* think about how this can work independent of dimension */ - glob->acc = FCLAW_ALLOC (fclaw_diagnostics_accumulator_t, 1); -#endif /* P4_TO_P8 */ + return glob; +} + +fclaw_global_t* fclaw_global_new (fclaw_app_t * app) +{ + fclaw_global_t *glob = global_new (); + + glob->mpicomm = fclaw_app_get_mpi_size_rank(app, &glob->mpisize, &glob->mpirank); + + sc_options_t *sc_options = fclaw_app_get_options(app); + fclaw_global_attribute_store(glob, + "fclaw_options", + sc_options, + NULL, NULL); + + void *fclaw_opt_sections = fclaw_app_get_attribute(app, "fclaw_opt_sections", NULL); + fclaw_global_attribute_store(glob, + "fclaw_opt_sections", + fclaw_opt_sections, + NULL, NULL); return glob; } @@ -77,7 +96,7 @@ fclaw_global_t* fclaw_global_new (void) fclaw_global_t* fclaw_global_new_comm (sc_MPI_Comm mpicomm, int mpisize, int mpirank) { - fclaw_global_t *glob = fclaw_global_new (); + fclaw_global_t *glob = global_new (); /* * Set the communicator. @@ -91,93 +110,6 @@ fclaw_global_t* fclaw_global_new_comm (sc_MPI_Comm mpicomm, return glob; } -#ifndef P4_TO_P8 -// packing unpacking functions only 2d for now - -static void check_vt(fclaw_packing_vtable_t* vt, const char* name) -{ - char msg[1024]; - sprintf(msg,"Unregistered options packing vtable for \"%s\"",name); - SC_CHECK_ABORT ((vt != NULL), msg); -} - -static void -pack_iterator_callback(const char* key, void* value, void* user) -{ - char** buffer_ptr = (char **) user; - - *buffer_ptr += fclaw_pack_string(key, *buffer_ptr); - - fclaw_packing_vtable_t* vt = fclaw_app_get_options_packing_vtable(key); - check_vt(vt,key); - - // advance buffer pointer - *buffer_ptr += vt->pack(value,*buffer_ptr); -} - -size_t -fclaw2d_global_pack(const fclaw_global_t * glob, char* buffer) -{ - const char* buffer_start = buffer; - - buffer += fclaw_pack_double(glob->curr_time, buffer); - buffer += fclaw_pack_double(glob->curr_dt, buffer); - - buffer += fclaw_pack_size_t(fclaw_pointer_map_size(glob->options), buffer); - - fclaw_pointer_map_iterate(glob->options, pack_iterator_callback, &buffer); - - return (buffer-buffer_start); -} - -static void -packsize_iterator_callback(const char* key, void* value, void* user) -{ - size_t* options_size = (size_t*) user; - fclaw_packing_vtable_t* vt = fclaw_app_get_options_packing_vtable(key); - check_vt(vt,key); - (*options_size) += fclaw_packsize_string(key) + vt->size(value); -} - -size_t -fclaw2d_global_packsize(const fclaw_global_t * glob) -{ - size_t options_size = sizeof(size_t); - fclaw_pointer_map_iterate(glob->options, packsize_iterator_callback, &options_size); - return 2*sizeof(double) + options_size; -} - -size_t -fclaw2d_global_unpack(char* buffer, fclaw_global_t ** glob_ptr) -{ - char* buffer_start = buffer; - - fclaw_global_t* glob = fclaw_global_new(); - *glob_ptr = glob; - - buffer += fclaw_unpack_double(buffer,&glob->curr_time); - buffer += fclaw_unpack_double(buffer,&glob->curr_dt); - - size_t num_option_structs; - buffer += fclaw_unpack_size_t(buffer,&num_option_structs); - - for(size_t i = 0; i< num_option_structs; i++) - { - char * key; - buffer += fclaw_unpack_string(buffer,&key); - fclaw_packing_vtable_t* vt = fclaw_app_get_options_packing_vtable(key); - check_vt(vt,key); - void * options; - buffer += vt->unpack(buffer,&options); - fclaw_pointer_map_insert(glob->options, key, options, vt->destroy); - FCLAW_FREE(key); - } - - return buffer-buffer_start; -} - -#endif - void fclaw_global_store_domain (fclaw_global_t* glob, fclaw_domain_t* domain) { @@ -212,10 +144,8 @@ fclaw_global_destroy (fclaw_global_t * glob) if(glob->pkg_container != NULL) fclaw_package_container_destroy ((fclaw_package_container_t *)glob->pkg_container); if(glob->vtables != NULL) fclaw_pointer_map_destroy (glob->vtables); if(glob->options != NULL) fclaw_pointer_map_destroy (glob->options); + if(glob->attributes != NULL) fclaw_pointer_map_destroy (glob->attributes); -#ifndef P4_TO_P8 - FCLAW_FREE (glob->acc); -#endif FCLAW_FREE (glob); } @@ -290,6 +220,237 @@ void* fclaw_global_get_options (fclaw_global_t* glob, const char* key) return options; } +/* + * @brief struct for store attributes and metadata + */ +typedef +struct attribute_entry +{ + /* the key to the packing vtable, NULL if not used */ + char* packing_vtable_key; + /* the attribute */ + void* attribute; + /* the callback to destroy the attribute, NULL if not used*/ + fclaw_pointer_map_value_destroy_t destroy; +} attribute_entry_t; + +/* callback to destroy attribute entry */ +static void +attribute_entry_destroy(void* value) +{ + attribute_entry_t* entry = (attribute_entry_t*) value; + if(entry->destroy != NULL) + { + entry->destroy(entry->attribute); + } + FCLAW_FREE(entry->packing_vtable_key); + FCLAW_FREE(entry); +} + +void +fclaw_global_attribute_store (fclaw_global_t * glob, + const char * key, + void* attribute, + const char * packing_vtable_key, + fclaw_pointer_map_value_destroy_t destroy) +{ + attribute_entry_t *entry = FCLAW_ALLOC(attribute_entry_t,1); + if(packing_vtable_key != NULL) + { + entry->packing_vtable_key = FCLAW_ALLOC(char,strlen(packing_vtable_key)+1); + strcpy(entry->packing_vtable_key,packing_vtable_key); + } + else + { + entry->packing_vtable_key = NULL; + } + entry->attribute = attribute; + entry->destroy = destroy; + fclaw_pointer_map_insert(glob->attributes, key, entry, attribute_entry_destroy); +} + +void * +fclaw_global_get_attribute (fclaw_global_t* glob, const char* key) +{ + attribute_entry_t *entry = + (attribute_entry_t*) fclaw_pointer_map_get(glob->attributes, key); + void * attribute = NULL; + if(entry != NULL) + { + attribute = entry->attribute; + } + return attribute; +} + +/* *************************************** + * Packing and unpacking functions + * ***************************************/ + +static void +check_vt(fclaw_packing_vtable_t* vt, + const char* name, + const char* vtable_name) +{ + if(vt == NULL) + { + char msg[BUFSIZ]; + snprintf(msg, BUFSIZ, "Unregistered attribute packing vtable \"%s\" for attribute \"%s\"",vtable_name,name); + SC_CHECK_ABORT ((vt != NULL), msg); + } +} + +static void +num_to_pack_cb(const char* key, void* value, void* user) +{ + size_t *num_to_pack = (size_t*) user; + attribute_entry_t* entry = (attribute_entry_t*) value; + if(entry->packing_vtable_key != NULL) + { + (*num_to_pack)++; + } +} +typedef +struct pack_iter +{ + fclaw_global_t* glob; + char** buffer_ptr; + size_t num_packed; +} pack_iter_t; + +static void +pack_attribute_cb(const char* key, void* value, void* user) +{ + pack_iter_t *iter = (pack_iter_t*) user; + attribute_entry_t* entry = (attribute_entry_t*) value; + if(entry->packing_vtable_key != NULL) + { + fclaw_packing_vtable_t* vt + = (fclaw_packing_vtable_t*) fclaw_global_get_vtable(iter->glob, entry->packing_vtable_key); + check_vt(vt, key, entry->packing_vtable_key); + // advance buffer pointer + *iter->buffer_ptr += fclaw_pack_string(entry->packing_vtable_key, *iter->buffer_ptr); + *iter->buffer_ptr += fclaw_pack_string(key, *iter->buffer_ptr); + *iter->buffer_ptr += vt->pack(iter->glob, entry->attribute, *iter->buffer_ptr); + } +} + +size_t +fclaw_global_pack(fclaw_global_t * glob, char* buffer) +{ + const char* buffer_start = buffer; + + buffer += fclaw_pack_double(glob->curr_time, buffer); + buffer += fclaw_pack_double(glob->curr_dt, buffer); + + size_t num_to_pack = 0; + fclaw_pointer_map_iterate(glob->attributes, num_to_pack_cb, &num_to_pack); + buffer += fclaw_pack_size_t(num_to_pack, buffer); + + pack_iter_t iter; + iter.glob = glob; + iter.buffer_ptr = &buffer; + fclaw_pointer_map_iterate(glob->attributes, pack_attribute_cb, &iter); + + return (buffer-buffer_start); +} + +typedef +struct packsize_iter +{ + fclaw_global_t* glob; + size_t size; +} packsize_iter_t; + +static void +attribute_packsize_cb(const char* key, void* value, void* user) +{ + packsize_iter_t* iter = (packsize_iter_t*) user; + attribute_entry_t* entry = (attribute_entry_t*) value; + if(entry->packing_vtable_key != NULL) + { + fclaw_packing_vtable_t* vt = + (fclaw_packing_vtable_t*) fclaw_global_get_vtable(iter->glob, entry->packing_vtable_key); + check_vt(vt, key, entry->packing_vtable_key); + iter->size += + fclaw_packsize_string(entry->packing_vtable_key) + + fclaw_packsize_string(key) + + vt->size(iter->glob, entry->attribute); + } +} + +size_t +fclaw_global_packsize(fclaw_global_t * glob) +{ + packsize_iter_t iter; + iter.glob = glob; + iter.size = sizeof(size_t); + fclaw_pointer_map_iterate(glob->attributes, attribute_packsize_cb, &iter); + return 2*sizeof(double) + iter.size; +} + +size_t +fclaw_global_unpack(char * buffer, fclaw_global_t * glob) +{ + char *buffer_start = buffer; + + buffer += fclaw_unpack_double(buffer,&glob->curr_time); + buffer += fclaw_unpack_double(buffer,&glob->curr_dt); + + size_t num_attributes; + buffer += fclaw_unpack_size_t(buffer,&num_attributes); + + for(size_t i = 0; i< num_attributes; i++) + { + char *packing_vtable_key; + buffer += fclaw_unpack_string(buffer,&packing_vtable_key); + + char *attribute_key; + buffer += fclaw_unpack_string(buffer,&attribute_key); + + fclaw_packing_vtable_t *vt = + (fclaw_packing_vtable_t *) fclaw_global_get_vtable(glob, packing_vtable_key); + + check_vt(vt, attribute_key, packing_vtable_key); + + attribute_entry_t *entry + = (attribute_entry_t *) fclaw_pointer_map_get(glob->attributes, attribute_key); + + if(entry == NULL) + { + entry = FCLAW_ALLOC(attribute_entry_t,1); + entry->packing_vtable_key = packing_vtable_key; + entry->attribute = vt->new_data(glob); + entry->destroy = vt->destroy; + fclaw_pointer_map_insert(glob->attributes, attribute_key, entry, attribute_entry_destroy); + } + else + { + FCLAW_ASSERT(strcmp(entry->packing_vtable_key,packing_vtable_key) == 0); + FCLAW_FREE(packing_vtable_key); + } + + buffer += vt->unpack(glob, buffer, entry->attribute); + + FCLAW_FREE(attribute_key); + } + + return buffer-buffer_start; +} +void +fclaw_global_vtable_store (fclaw_global_t * glob, + const char * key, + void * vtable, + fclaw_pointer_map_value_destroy_t destroy) +{ + fclaw_pointer_map_insert(glob->vtables, key, vtable, destroy); +} + +void * +fclaw_global_get_vtable (fclaw_global_t* glob, const char* key) +{ + return fclaw_pointer_map_get(glob->vtables, key); +} + static fclaw_global_t* fclaw2d_global_glob = NULL; void fclaw_global_set_static (fclaw_global_t* glob) diff --git a/src/fclaw_global.h b/src/fclaw_global.h index 757ec38a4..a1d76a278 100644 --- a/src/fclaw_global.h +++ b/src/fclaw_global.h @@ -30,6 +30,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include /* Needed to store the map context */ #include /* Needed to create statically allocated array of timers */ +#include /* Needed to store vtables and options */ #ifdef __cplusplus extern "C" @@ -79,22 +80,14 @@ struct fclaw_global /** Solver packages for internal use. */ struct fclaw_package_container *pkg_container; - struct fclaw_pointer_map *vtables; /**< Vtables */ - struct fclaw_pointer_map *options; /**< options */ + fclaw_pointer_map_t *vtables; /**< Vtables */ + fclaw_pointer_map_t *options; /**< options */ + + fclaw_pointer_map_t *attributes; /**< attributes */ struct fclaw_map_context* cont; struct fclaw_domain *domain; - /* CB: is this a good place for the accumulator? - Would it be possible to add and retrieve it as an anonymous - object that does not need to be known to this file? */ - struct fclaw_diagnostics_accumulator *acc; - - /* CB: this is application specific. - Would it not be cleaner to add the gauges in a way to global - that this file does not need to know about gauges at all? */ - struct fclaw_gauge_info* gauge_info; - void *user; }; @@ -115,7 +108,7 @@ struct fclaw_package_container; struct fclaw_diagnostics_accumulator; /** Allocate a new global structure. */ -fclaw_global_t* fclaw_global_new (void); +fclaw_global_t* fclaw_global_new (fclaw_app_t * app); fclaw_global_t* fclaw_global_new_comm (sc_MPI_Comm mpicomm, int mpisize, int mpirank); @@ -149,7 +142,7 @@ struct fclaw_map_context* fclaw_map_get(fclaw_global_t* glob); * @param buffer the buffer to write to * @return size_t number of bytes written */ -size_t fclaw2d_global_pack(const fclaw_global_t * glob, char* buffer); +size_t fclaw_global_pack(fclaw_global_t * glob, char* buffer); /** * @brief Get the number of bytes needed to pack the global structure @@ -157,16 +150,16 @@ size_t fclaw2d_global_pack(const fclaw_global_t * glob, char* buffer); * @param glob the structure * @return size_t the number of bytes needed to store structure */ -size_t fclaw2d_global_packsize(const fclaw_global_t * glob); +size_t fclaw_global_packsize(fclaw_global_t * glob); /** * @brief Unpack global structure from buffer * * @param buffer the buffer to read from - * @param glob newly create global structure + * @param glob glob structure to write to * @return size_t number of bytes read */ -size_t fclaw2d_global_unpack(char* buffer, fclaw_global_t** glob); +size_t fclaw_global_unpack(char* buffer, fclaw_global_t* glob); void fclaw_global_iterate_level (fclaw_global_t * glob, int level, fclaw_patch_callback_t pcb, void *user); @@ -207,6 +200,58 @@ void fclaw_global_options_store (fclaw_global_t* glob, const char* key, void* op */ void* fclaw_global_get_options (fclaw_global_t* glob, const char* key); +/** + * @brief Store an attribute structure in the glob + * + * @param glob the global context + * @param key the key to store the attribute under + * @param attribute the attribute structure + * @param packing_vtable_key The key to the packing vtable, NULL if not needed + * The packing vtable is expected to be of type fclaw_packing_vtable_t + * @param destroy the callback to destroy the attribute, NULL if not needed + */ +void +fclaw_global_attribute_store (fclaw_global_t * glob, + const char * key, + void* attribute, + const char * packing_vtable_key, + fclaw_pointer_map_value_destroy_t destroy); + +/** + * @brief Get an attribute structure from the glob + * + * @param glob the global context + * @param key the key to retrieve the attribute from + * @return void* the attribute, NULL if not found + */ +void * +fclaw_global_get_attribute (fclaw_global_t* glob, const char* key); + + +/** + * @brief Store a vtable + * + * @param glob the global context + * @param key the key + * @param vtable the vtable + * @param destroy the callback to destroy the vtable, NULL if not needed + */ +void +fclaw_global_vtable_store(fclaw_global_t * glob, + const char * key, + void * vtable, + fclaw_pointer_map_value_destroy_t destroy); + +/** + * @brief Get a vtable + * + * @param glob the global context + * @param key the key + * @return void* the vtable + */ +void * +fclaw_global_get_vtable(fclaw_global_t * glob, const char * key); + /** * @brief Store a glob variable in static memory * diff --git a/src/fclaw_global.h.TEST.cpp b/src/fclaw_global.h.TEST.cpp index 6804d2e23..9c2a6cf89 100644 --- a/src/fclaw_global.h.TEST.cpp +++ b/src/fclaw_global.h.TEST.cpp @@ -32,62 +32,57 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include #include - -TEST_CASE("fclaw2d_global_pack with no options") +TEST_CASE("fclaw_global_new default options") { + fclaw_global_t* glob = fclaw_global_new_comm(sc_MPI_COMM_SELF, 1, 0);; - for(double curr_time : {1.0, 1.2}) - for(double curr_dt : {1.0, 1.2}) - { - fclaw_global_t* glob1; - glob1 = fclaw_global_new_comm(sc_MPI_COMM_SELF, 1, 0); - glob1->curr_time = curr_time; - glob1->curr_dt = curr_dt; - - size_t packsize = fclaw2d_global_packsize(glob1); - - REQUIRE_GT(packsize, 0); - char buffer[packsize]; + CHECK_EQ(glob->curr_time, 0.0); + CHECK_EQ(glob->curr_dt, 0.0); - size_t bytes_written = fclaw2d_global_pack(glob1, buffer); + CHECK_EQ(glob->count_amr_advance, 0); + CHECK_EQ(glob->count_ghost_exchange, 0); + CHECK_EQ(glob->count_amr_regrid, 0); + CHECK_EQ(glob->count_amr_new_domain, 0); + CHECK_EQ(glob->count_single_step, 0); + CHECK_EQ(glob->count_elliptic_grids, 0); + CHECK_EQ(glob->count_multiproc_corner, 0); + CHECK_EQ(glob->count_grids_per_proc, 0); + CHECK_EQ(glob->count_grids_remote_boundary, 0); + CHECK_EQ(glob->count_grids_local_boundary, 0); - REQUIRE_EQ(bytes_written, packsize); + CHECK_EQ(glob->mpisize, 1); + CHECK_EQ(glob->mpirank, 0); - fclaw_global_t* glob2; - size_t bytes_read = fclaw2d_global_unpack(buffer, &glob2); + CHECK_EQ(fclaw_pointer_map_size(glob->vtables), 0); + CHECK_EQ(fclaw_pointer_map_size(glob->options), 0); + CHECK_EQ(fclaw_pointer_map_size(glob->attributes), 0); + CHECK(glob->cont == nullptr); + CHECK(glob->domain == nullptr); + CHECK(glob->user == nullptr); - REQUIRE_EQ(bytes_read, packsize); - CHECK_EQ(glob1->curr_time, glob2->curr_time); - CHECK_EQ(glob1->curr_dt, glob2->curr_dt); - - CHECK_EQ(fclaw_pointer_map_size(glob2->options), 0); - - - fclaw_global_destroy(glob1); - fclaw_global_destroy(glob2); - } + fclaw_global_destroy(glob); } namespace { -struct dummy_options +struct dummy_attribute { size_t size; char value; - dummy_options(size_t size_in, char value_in) + dummy_attribute(size_t size_in, char value_in) :size(size_in),value(value_in) { //nothing to do } }; -size_t pack_dummy_options(void* user, char* buffer) +size_t pack_dummy_options(fclaw_global_t *glob, void *user, char *buffer) { - dummy_options* options = (dummy_options*) user; + dummy_attribute* options = (dummy_attribute*) user; char* buffer_start = buffer; buffer += fclaw_pack_size_t(options->size, buffer); @@ -98,8 +93,9 @@ size_t pack_dummy_options(void* user, char* buffer) return buffer-buffer_start; }; -size_t unpack_dummy_options(char* buffer, void** user) +size_t unpack_dummy_options(fclaw_global_t *glob, char* buffer, void* user) { + dummy_attribute* attribute = (dummy_attribute*) user; char* buffer_start = buffer; @@ -111,32 +107,36 @@ size_t unpack_dummy_options(char* buffer, void** user) } buffer += size; - *user = new dummy_options(size,value); + attribute->size = size; + attribute->value = value; return buffer-buffer_start; }; -size_t packsize_dummy_options(void* user) +size_t packsize_dummy_attribute(fclaw_global_t *glob, void* user) { - dummy_options* options = (dummy_options*) user; + dummy_attribute* options = (dummy_attribute*) user; return sizeof(size_t) + options->size; }; - -void destroy_dummy_options(void* user){ - delete (dummy_options*) user; +void * new_dummy_attribute(fclaw_global_t *glob){ + return new dummy_attribute(0,0); +} +void destroy_dummy_attribute(void* user){ + delete (dummy_attribute*) user; } fclaw_packing_vtable_t dummy_opts_vt = { pack_dummy_options, unpack_dummy_options, - packsize_dummy_options, - destroy_dummy_options + packsize_dummy_attribute, + new_dummy_attribute, + destroy_dummy_attribute }; } -TEST_CASE("fclaw_global_pack with no options structure") +TEST_CASE("fclaw_global_pack with no packed attributes") { - + for(bool extra_non_packed_attribute : {true, false}) for(double curr_time : {1.0, 1.2}) for(double curr_dt : {1.0, 1.2}) { @@ -145,127 +145,182 @@ TEST_CASE("fclaw_global_pack with no options structure") glob1->curr_time = curr_time; glob1->curr_dt = curr_dt; - size_t packsize = fclaw2d_global_packsize(glob1); + if(extra_non_packed_attribute) + { + dummy_attribute* attribute = new dummy_attribute(40, 'b'); + fclaw_global_attribute_store(glob1, "dummy_not_packed", attribute, NULL, destroy_dummy_attribute); + } + + size_t packsize = fclaw_global_packsize(glob1); REQUIRE_GT(packsize, 0); char buffer[packsize]; - size_t bytes_written = fclaw2d_global_pack(glob1, buffer); + size_t bytes_written = fclaw_global_pack(glob1, buffer); REQUIRE_EQ(bytes_written, packsize); - fclaw_global_t* glob2; - size_t bytes_read = fclaw2d_global_unpack(buffer, &glob2); + fclaw_global_t* glob2 = fclaw_global_new_comm(sc_MPI_COMM_SELF, 1, 0);; + size_t bytes_read = fclaw_global_unpack(buffer, glob2); REQUIRE_EQ(bytes_read, packsize); CHECK_EQ(glob1->curr_time, glob2->curr_time); CHECK_EQ(glob1->curr_dt, glob2->curr_dt); - REQUIRE_EQ(fclaw_pointer_map_size(glob2->options), 0); + REQUIRE_EQ(fclaw_pointer_map_size(glob2->attributes), 0); fclaw_global_destroy(glob1); fclaw_global_destroy(glob2); } } -TEST_CASE("fclaw_global_pack with a single options structure") +TEST_CASE("fclaw_global_pack with a single packed attribute") { + for(bool extra_non_packed_attribute : {true, false}) + for(bool already_stored_attribute : {true, false}) for(double curr_time : {1.0, 1.2}) for(double curr_dt : {1.0, 1.2}) { char dummy[] = "dummy1"; std::vector args = {dummy}; - char ** argv = args.data(); - int argc = 1; //fclaw_app_t* app = fclaw_app_new_on_comm(sc_MPI_COMM_WORLD,&argc,&argv,NULL); fclaw_global_t* glob1; - glob1 = fclaw_global_new_comm(sc_MPI_COMM_SELF, 1, 0); + glob1 = fclaw_global_new_comm(sc_MPI_COMM_SELF, 1, 0);; + fclaw_global_vtable_store(glob1, "dummy1_vtable", &dummy_opts_vt, NULL); + glob1->curr_time = curr_time; glob1->curr_dt = curr_dt; - dummy_options* options = new dummy_options(20, 'a'); - fclaw_app_register_options_packing_vtable("dummy1", &dummy_opts_vt); - fclaw_pointer_map_insert(glob1->options, "dummy1", options, destroy_dummy_options); + dummy_attribute* attribute1 = new dummy_attribute(20, 'a'); + fclaw_global_attribute_store(glob1, "dummy1", attribute1, "dummy1_vtable", destroy_dummy_attribute); - size_t packsize = fclaw2d_global_packsize(glob1); + if(extra_non_packed_attribute) + { + dummy_attribute* attribute = new dummy_attribute(40, 'b'); + fclaw_global_attribute_store(glob1, "dummy_not_packed", attribute, NULL, destroy_dummy_attribute); + } + + size_t packsize = fclaw_global_packsize(glob1); REQUIRE_GT(packsize, 0); char buffer[packsize]; - size_t bytes_written = fclaw2d_global_pack(glob1, buffer); + size_t bytes_written = fclaw_global_pack(glob1, buffer); REQUIRE_EQ(bytes_written, packsize); - fclaw_global_t* glob2; - size_t bytes_read = fclaw2d_global_unpack(buffer, &glob2); + fclaw_global_t* glob2 = fclaw_global_new_comm(sc_MPI_COMM_SELF, 1, 0);; + fclaw_global_vtable_store(glob2, "dummy1_vtable", &dummy_opts_vt, NULL); - REQUIRE_EQ(bytes_read, packsize); + dummy_attribute* attribute2 = NULL; + if(already_stored_attribute) + { + attribute2 = new dummy_attribute(99, 'z'); + fclaw_global_attribute_store(glob2, "dummy1", attribute2, "dummy1_vtable", destroy_dummy_attribute); + } - CHECK_EQ(glob1->curr_time, glob2->curr_time); - CHECK_EQ(glob1->curr_dt, glob2->curr_dt); + size_t bytes_read = fclaw_global_unpack(buffer, glob2); - REQUIRE_EQ(fclaw_pointer_map_size(glob2->options), 1); + if(!already_stored_attribute) + { + attribute2 = (dummy_attribute*)(fclaw_global_get_attribute(glob2, "dummy1")); + REQUIRE_NE(attribute2, nullptr); + } - dummy_options* options_unpacked = (dummy_options*) fclaw_pointer_map_get(glob2->options, "dummy1"); - REQUIRE(options_unpacked != nullptr); + REQUIRE_EQ(bytes_read, packsize); - CHECK_EQ(options_unpacked->size, options->size); - CHECK_EQ(options_unpacked->value, options->value); + CHECK_EQ(glob1->curr_time, glob2->curr_time); + CHECK_EQ(glob1->curr_dt, glob2->curr_dt); + REQUIRE_EQ(fclaw_pointer_map_size(glob2->attributes), 1); + CHECK_EQ(attribute2->size, attribute1->size); + CHECK_EQ(attribute2->value, attribute1->value); fclaw_global_destroy(glob1); fclaw_global_destroy(glob2); } } -TEST_CASE("fclaw_global_pack with two options structure") +TEST_CASE("fclaw_global_pack with two packed attributes") { + for(bool extra_non_packed_attribute : {true, false}) + for(bool already_stored_attribute_1 : {true, false}) + for(bool already_stored_attribute_2 : {true, false}) for(double curr_time : {1.0, 1.2}) for(double curr_dt : {1.0, 1.2}) { fclaw_global_t* glob1; - glob1 = fclaw_global_new_comm(sc_MPI_COMM_SELF, 1, 0); + glob1 = fclaw_global_new_comm(sc_MPI_COMM_SELF, 1, 0);; + fclaw_global_vtable_store(glob1, "dummy1", &dummy_opts_vt, NULL); + fclaw_global_vtable_store(glob1, "dummy2", &dummy_opts_vt, NULL); glob1->curr_time = curr_time; glob1->curr_dt = curr_dt; - dummy_options* options = new dummy_options(20, 'a'); - dummy_options* options2 = new dummy_options(40, 'b'); - fclaw_app_register_options_packing_vtable("dummy1", &dummy_opts_vt); - fclaw_pointer_map_insert(glob1->options, "dummy1", options, destroy_dummy_options); - fclaw_app_register_options_packing_vtable("dummy2", &dummy_opts_vt); - fclaw_pointer_map_insert(glob1->options, "dummy2", options2, destroy_dummy_options); + dummy_attribute* attribute1_1 = new dummy_attribute(20, 'a'); + dummy_attribute* attribute1_2 = new dummy_attribute(40, 'b'); + + fclaw_global_attribute_store(glob1, "dummy1", attribute1_1, "dummy1", destroy_dummy_attribute); + fclaw_global_attribute_store(glob1, "dummy2", attribute1_2, "dummy2", destroy_dummy_attribute); - size_t packsize = fclaw2d_global_packsize(glob1); + if(extra_non_packed_attribute) + { + dummy_attribute* attribute = new dummy_attribute(40, 'b'); + fclaw_global_attribute_store(glob1, "dummy_not_packed", attribute, NULL, destroy_dummy_attribute); + } + + size_t packsize = fclaw_global_packsize(glob1); REQUIRE_GT(packsize, 0); char buffer[packsize]; - size_t bytes_written = fclaw2d_global_pack(glob1, buffer); + size_t bytes_written = fclaw_global_pack(glob1, buffer); REQUIRE_EQ(bytes_written, packsize); - fclaw_global_t* glob2; - size_t bytes_read = fclaw2d_global_unpack(buffer, &glob2); + fclaw_global_t* glob2 = fclaw_global_new_comm(sc_MPI_COMM_SELF, 1, 0);; + fclaw_global_vtable_store(glob2, "dummy1", &dummy_opts_vt, NULL); + fclaw_global_vtable_store(glob2, "dummy2", &dummy_opts_vt, NULL); + + dummy_attribute* attribute2_1 = NULL; + dummy_attribute* attribute2_2 = NULL; + if(already_stored_attribute_1) + { + attribute2_1 = new dummy_attribute(99, 'z'); + fclaw_global_attribute_store(glob2, "dummy1", attribute2_1, "dummy1", destroy_dummy_attribute); + } + if(already_stored_attribute_2) + { + attribute2_2 = new dummy_attribute(99, 'z'); + fclaw_global_attribute_store(glob2, "dummy2", attribute2_2, "dummy2", destroy_dummy_attribute); + } + + size_t bytes_read = fclaw_global_unpack(buffer, glob2); + + if(!already_stored_attribute_1) + { + attribute2_1 = (dummy_attribute*)(fclaw_global_get_attribute(glob2, "dummy1")); + REQUIRE_NE(attribute2_1, nullptr); + } + if(!already_stored_attribute_2) + { + attribute2_2 = (dummy_attribute*)(fclaw_global_get_attribute(glob2, "dummy2")); + REQUIRE_NE(attribute2_2, nullptr); + } REQUIRE_EQ(bytes_read, packsize); CHECK_EQ(glob1->curr_time, glob2->curr_time); CHECK_EQ(glob1->curr_dt, glob2->curr_dt); - REQUIRE_EQ(fclaw_pointer_map_size(glob2->options), 2); - - dummy_options* options_unpacked = (dummy_options*) fclaw_pointer_map_get(glob2->options, "dummy1"); - dummy_options* options_unpacked2 = (dummy_options*) fclaw_pointer_map_get(glob2->options, "dummy2"); - REQUIRE(options_unpacked != nullptr); - REQUIRE(options_unpacked2 != nullptr); + REQUIRE_EQ(fclaw_pointer_map_size(glob2->attributes), 2); - CHECK_EQ(options_unpacked->size, options->size); - CHECK_EQ(options_unpacked->value, options->value); + CHECK_EQ(attribute2_1->size, attribute1_1->size); + CHECK_EQ(attribute2_1->value, attribute1_1->value); - CHECK_EQ(options_unpacked2->size, options2->size); - CHECK_EQ(options_unpacked2->value, options2->value); + CHECK_EQ(attribute2_2->size, attribute1_2->size); + CHECK_EQ(attribute2_2->value, attribute1_2->value); fclaw_global_destroy(glob1); fclaw_global_destroy(glob2); @@ -278,48 +333,49 @@ TEST_CASE("fclaw_global_pack aborts with unregistered vtable") glob1->curr_time = 100; glob1->curr_dt = 200; - dummy_options* options = new dummy_options(20, 'a'); - fclaw_pointer_map_insert(glob1->options, "dummy1", options, destroy_dummy_options); + dummy_attribute* attribute = new dummy_attribute(20, 'a'); + fclaw_global_attribute_store(glob1, "dummy1", attribute, "pack_dummy1", destroy_dummy_attribute); - char buffer[100]; - CHECK_SC_ABORTED(fclaw2d_global_pack(glob1, buffer)); + char buffer[BUFSIZ]; + CHECK_SC_ABORTED(fclaw_global_pack(glob1, buffer)); } -TEST_CASE("fclaw2d_global_packsize aborts with unregistered vtable") +TEST_CASE("fclaw_global_packsize aborts with unregistered vtable") { fclaw_global_t* glob1; glob1 = fclaw_global_new_comm(sc_MPI_COMM_SELF, 1, 0);; glob1->curr_time = 100; glob1->curr_dt = 200; - dummy_options* options = new dummy_options(20, 'a'); - fclaw_pointer_map_insert(glob1->options, "dummy1", options, destroy_dummy_options); + dummy_attribute* attribute = new dummy_attribute(20, 'a'); + fclaw_global_attribute_store(glob1, "dummy1", attribute, "pack_dummy1", destroy_dummy_attribute); - CHECK_SC_ABORTED(fclaw2d_global_packsize(glob1)); + CHECK_SC_ABORTED(fclaw_global_packsize(glob1)); } -TEST_CASE("fclaw_global_unppack aborts with unregistered vtable") +TEST_CASE("fclaw_global_unpack aborts with unregistered vtable") { fclaw_global_t* glob1; glob1 = fclaw_global_new_comm(sc_MPI_COMM_SELF, 1, 0);; glob1->curr_time = 1; glob1->curr_dt = 1; - dummy_options* options = new dummy_options(20, 'a'); - fclaw_app_register_options_packing_vtable("dummy1", &dummy_opts_vt); - fclaw_pointer_map_insert(glob1->options, "dummy1", options, destroy_dummy_options); + dummy_attribute* attribute = new dummy_attribute(20, 'a'); + fclaw_global_vtable_store(glob1, "pack_dummy1", &dummy_opts_vt, NULL); + fclaw_global_attribute_store(glob1, "dummy1", attribute, "pack_dummy1", destroy_dummy_attribute); - size_t packsize = fclaw2d_global_packsize(glob1); + size_t packsize = fclaw_global_packsize(glob1); REQUIRE_GT(packsize, 0); char buffer[packsize]; - size_t bytes_written = fclaw2d_global_pack(glob1, buffer); + size_t bytes_written = fclaw_global_pack(glob1, buffer); REQUIRE_EQ(bytes_written, packsize); - fclaw_global_t* glob2=nullptr; - fclaw_app_register_options_packing_vtable("dummy1", nullptr); - CHECK_SC_ABORTED(fclaw2d_global_unpack(buffer, &glob2)); + fclaw_global_t* glob2=fclaw_global_new_comm(sc_MPI_COMM_SELF, 1, 0);; + //no vtables in glob2 + CHECK_SC_ABORTED(fclaw_global_unpack(buffer, glob2)); } + TEST_CASE("fclaw_global_options_store and fclaw_global_get_options test") { fclaw_global_t* glob = fclaw_global_new_comm(sc_MPI_COMM_SELF, 1, 0);; @@ -355,7 +411,7 @@ TEST_CASE("fclaw_global_options_store and fclaw_global_get_options test") { fclaw_global_destroy(glob); } -TEST_CASE("fclaw2d_global_set_global") +TEST_CASE("fclaw_global_set_global") { fclaw_global_t* glob = (fclaw_global_t*)123; fclaw_global_set_static(glob); @@ -377,7 +433,7 @@ TEST_CASE("fclaw_global_clear_static") #ifdef FCLAW_ENABLE_DEBUG -TEST_CASE("fclaw2d_global_set_global twice fails") +TEST_CASE("fclaw_global_set_global twice fails") { fclaw_global_t* glob = (fclaw_global_t*)123; fclaw_global_set_static(glob); @@ -385,14 +441,85 @@ TEST_CASE("fclaw2d_global_set_global twice fails") fclaw_global_clear_static(); } -TEST_CASE("fclaw2d_global_unset_global assert fails when NULL") +TEST_CASE("fclaw_global_unset_global assert fails when NULL") { CHECK_SC_ABORTED(fclaw_global_clear_static()); } -TEST_CASE("fclaw2d_global_get_global assert fails when NULL") +TEST_CASE("fclaw_global_get_global assert fails when NULL") { CHECK_SC_ABORTED(fclaw_global_get_static_global()); } #endif + +TEST_CASE("fclaw_global_vtable_store and fclaw_global_get_vtable test") { + fclaw_global_t* glob = fclaw_global_new_comm(sc_MPI_COMM_SELF, 1, 0);; + + // Test with an integer + int vtable1 = 10; + const char* key1 = "vtable1"; + fclaw_global_vtable_store(glob, key1, &vtable1, nullptr); + + int* retrieved_vtable1 = static_cast(fclaw_global_get_vtable(glob, key1)); + CHECK_EQ(*retrieved_vtable1, vtable1); + + // Test with a string + const char* vtable2 = "Test string"; + const char* key2 = "vtable2"; + fclaw_global_vtable_store(glob, key2, &vtable2, nullptr); + + const char** retrieved_vtable2 = static_cast(fclaw_global_get_vtable(glob, key2)); + CHECK_EQ(*retrieved_vtable2, vtable2); + + // Test with a non-existing key + const char* key3 = "non-existing key"; + void* retrieved_vtable3 = fclaw_global_get_vtable(glob, key3); + CHECK_EQ(retrieved_vtable3, nullptr); + + // Test with a destroy callback + int* vtable4 = new int(20); + const char* key4 = "vtable4"; + fclaw_global_vtable_store(glob, key4, vtable4, [](void* ptr) { delete static_cast(ptr); }); + + int* retrieved_vtable4 = static_cast(fclaw_global_get_vtable(glob, key4)); + CHECK_EQ(*retrieved_vtable4, *vtable4); + + fclaw_global_destroy(glob); +} + +TEST_CASE("fclaw_global_attribute_store and fclaw_global_get_attribute test") { + fclaw_global_t* glob = fclaw_global_new_comm(sc_MPI_COMM_SELF, 1, 0);; + + // Test with an integer + int attribute1 = 10; + const char* key1 = "attribute1"; + fclaw_global_attribute_store(glob, key1, &attribute1, nullptr, nullptr); + + int* retrieved_attribute1 = static_cast(fclaw_global_get_attribute(glob, key1)); + CHECK_EQ(*retrieved_attribute1, attribute1); + + // Test with a string + const char* attribute2 = "Test string"; + const char* key2 = "attribute2"; + fclaw_global_attribute_store(glob, key2, &attribute2, nullptr, nullptr); + + const char** retrieved_attribute2 = static_cast(fclaw_global_get_attribute(glob, key2)); + CHECK_EQ(*retrieved_attribute2, attribute2); + + // Test with a non-existing key + const char* key3 = "non-existing key"; + void* retrieved_attribute3 = fclaw_global_get_attribute(glob, key3); + CHECK_EQ(retrieved_attribute3, nullptr); + + // Test with a destroy callback + int* attribute4 = new int(20); + const char* key4 = "attribute4"; + fclaw_global_attribute_store(glob, key4, attribute4, nullptr, [](void* ptr) { delete static_cast(ptr); }); + + int* retrieved_attribute4 = static_cast(fclaw_global_get_attribute(glob, key4)); + CHECK_EQ(*retrieved_attribute4, *attribute4); + + fclaw_global_destroy(glob); +} + diff --git a/src/fclaw_initialize.c b/src/fclaw_initialize.c index 4fca9c294..fa0c8a96c 100644 --- a/src/fclaw_initialize.c +++ b/src/fclaw_initialize.c @@ -42,6 +42,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include #include #include +#include #if defined(_OPENMP) #include @@ -69,54 +70,18 @@ void cb_initialize (fclaw_domain_t *domain, } - -/* ----------------------------------------------------------------- - Public interface - ----------------------------------------------------------------- */ -void fclaw_initialize(fclaw_global_t *glob) +static +void build_initial_domain(fclaw_global_t *glob) { + fclaw_initialize_domain_flags(glob); fclaw_domain_t** domain = &glob->domain; - int time_interp = 0; const fclaw_options_t *fclaw_opt = fclaw_get_options(glob); - /* set partitioning */ - fclaw_domain_set_partitioning(*domain, fclaw_opt->partition_for_coarsening); - - /* This mapping context is needed by fortran mapping functions */ - fclaw_map_context_t *cont = glob->cont; - FCLAW_MAP_SET_CONTEXT(&cont); - - int maxthreads = 0; - -#if defined(_OPENMP) - maxthreads = omp_get_max_threads(); -#endif - - fclaw_global_essentialf("Max threads set to %d\n",maxthreads); - int minlevel = fclaw_opt->minlevel; int maxlevel = fclaw_opt->maxlevel; - /* Initialize all timers */ - int i; - for (i = 0; i < FCLAW_TIMER_COUNT; ++i) { - fclaw_timer_init (&glob->timers[i]); - } - - /* start timing */ - fclaw_domain_barrier (*domain); - fclaw_timer_start (&glob->timers[FCLAW_TIMER_WALLTIME]); - fclaw_timer_start (&glob->timers[FCLAW_TIMER_INIT]); - - /* User defined problem setup */ - fclaw_problem_setup(glob); - - /* set specific refinement strategy */ - fclaw_domain_set_refinement - (*domain, fclaw_opt->smooth_refine, fclaw_opt->smooth_level, - fclaw_opt->coarsen_delay); - + int time_interp = 0; /* ------------------------------------------------ Set up initial domain. @@ -241,7 +206,57 @@ void fclaw_initialize(fclaw_global_t *glob) (*domain)->global_maxlevel,0.0, time_interp,FCLAW_TIMER_INIT); } +} + +void fclaw_initialize_domain_flags(fclaw_global_t *glob) +{ + const fclaw_options_t *fclaw_opt = fclaw_get_options(glob); + + /* set specific refinement strategy */ + fclaw_domain_set_refinement + (glob->domain, fclaw_opt->smooth_refine, fclaw_opt->smooth_level, + fclaw_opt->coarsen_delay); + + /* set partitioning */ + fclaw_domain_set_partitioning(glob->domain, fclaw_opt->partition_for_coarsening); +} +static void +pre_setup(fclaw_global_t* glob) +{ + fclaw_domain_t** domain = &glob->domain; + + /* This mapping context is needed by fortran mapping functions */ + fclaw_map_context_t *cont = glob->cont; + FCLAW_MAP_SET_CONTEXT(&cont); + + int maxthreads = 0; + +#if defined(_OPENMP) + maxthreads = omp_get_max_threads(); +#endif + + fclaw_global_essentialf("Max threads set to %d\n",maxthreads); + + + /* Initialize all timers */ + int i; + for (i = 0; i < FCLAW_TIMER_COUNT; ++i) { + fclaw_timer_init (&glob->timers[i]); + } + + /* start timing */ + fclaw_domain_barrier (*domain); + fclaw_timer_start (&glob->timers[FCLAW_TIMER_WALLTIME]); + fclaw_timer_start (&glob->timers[FCLAW_TIMER_INIT]); + + /* User defined problem setup */ + fclaw_problem_setup(glob); +} + +static void +post_setup(fclaw_global_t* glob) +{ fclaw_diagnostics_initialize(glob); fclaw_locate_gauges(glob); @@ -249,8 +264,37 @@ void fclaw_initialize(fclaw_global_t *glob) /* Print global minimum and maximum levels */ fclaw_global_infof("Global minlevel %d maxlevel %d\n", - (*domain)->global_minlevel, (*domain)->global_maxlevel); + glob->domain->global_minlevel, glob->domain->global_maxlevel); /* Stop timer */ fclaw_timer_stop (&glob->timers[FCLAW_TIMER_INIT]); } +/* ----------------------------------------------------------------- + Public interface + ----------------------------------------------------------------- */ +void fclaw_initialize(fclaw_global_t *glob) +{ + pre_setup(glob); + + build_initial_domain(glob); + + post_setup(glob); +} + +void fclaw_restart(fclaw_global_t *glob) +{ + pre_setup(glob); + + const fclaw_options_t *fclaw_opt = fclaw_get_options(glob); + + const char* partition_filename = NULL; + if(strcmp(fclaw_opt->partition_file,"") != 0) + { + partition_filename = fclaw_opt->partition_file; + } + + fclaw_restart_from_file(glob, fclaw_opt->restart_file, + partition_filename); + + post_setup(glob); +} diff --git a/src/fclaw_options.c b/src/fclaw_options.c index 6dd3803d0..d9fd58f0e 100644 --- a/src/fclaw_options.c +++ b/src/fclaw_options.c @@ -124,6 +124,23 @@ fclaw_register (fclaw_options_t* fclaw_opt, sc_options_t * opt) sc_options_add_bool (opt, 0, "output", &fclaw_opt->output, 0, "Enable output [F]"); + sc_options_add_bool (opt, 0, "checkpoint", &fclaw_opt->checkpoint, 0, + "Enable checkpoint output [F]"); + + /* ------------------------------- Restart options --------------------------------- */ + + sc_options_add_bool (opt, 0, "restart", &fclaw_opt->restart, 0, + "Restart from file [F]"); + + sc_options_add_string(opt, 0, "restart-file", + &fclaw_opt->restart_file, + "","Filename of restart file. " + " If defined, a restart will be performed frome the specified file. [""]"); + + sc_options_add_string(opt, 0, "partition-file", + &fclaw_opt->partition_file, + "","Partition file associated with restart file. " + " This should be specified if a restart file is specified. [""]"); /* -------------------------------------- Gauges --------------------------------- */ /* Gauge options */ @@ -358,6 +375,7 @@ fclaw_register (fclaw_options_t* fclaw_opt, sc_options_t * opt) sc_options_add_double(opt, 0, "max-refinement-ratio", &fclaw_opt->max_refinement_ratio, 1.0, "Ratio of patches to refine before paritioning and continuing refinement. [1.0]"); + fclaw_opt->is_registered = 1; fclaw_opt->is_unpacked = 0; @@ -452,116 +470,6 @@ fclaw_options_destroy(fclaw_options_t* fclaw_opt) FCLAW_FREE(fclaw_opt); } -static void -fclaw_options_destroy_void(void* user) -{ - fclaw_options_t* fclaw_opt = (fclaw_options_t*) user; - fclaw_options_destroy(fclaw_opt); -} - -/* ------------------------------------------------------------------------ - Options packing - ------------------------------------------------------------------------ */ - -static size_t options_packsize(void* user){ - fclaw_options_t* opts = (fclaw_options_t*) user; - - size_t size = sizeof(fclaw_options_t); - size += fclaw_packsize_string(opts->run_directory); - size += fclaw_packsize_string(opts->scale_string); - size += fclaw_packsize_string(opts->shift_string); - size += 3*sizeof(double); //scale - size += 3*sizeof(double); //shift - size += fclaw_packsize_string(opts->tikz_figsize_string); - size += 2*sizeof(double); //tickz_figsize - size += fclaw_packsize_string(opts->tikz_plot_prefix); - size += fclaw_packsize_string(opts->tikz_plot_suffix); - size += fclaw_packsize_string(opts->prefix); - size += fclaw_packsize_string(opts->logging_prefix); - - return size; -} - -static size_t options_pack(void* user, char* buffer){ - char* buffer_start = buffer; - - fclaw_options_t* opts = (fclaw_options_t*) user; - - //pack entire struct - buffer += FCLAW_PACK(*opts, buffer); - - //append arrays to buffer - buffer += fclaw_pack_string(opts->run_directory, buffer); - buffer += fclaw_pack_string(opts->scale_string, buffer); - buffer += fclaw_pack_string(opts->shift_string, buffer); - for(size_t i = 0; i < 3; i++){ - buffer += fclaw_pack_double(opts->scale[i], buffer); - buffer += fclaw_pack_double(opts->shift[i], buffer); - } - buffer += fclaw_pack_string(opts->tikz_figsize_string, buffer); - buffer += fclaw_pack_double(opts->tikz_figsize[0], buffer); - buffer += fclaw_pack_double(opts->tikz_figsize[1], buffer); - buffer += fclaw_pack_string(opts->tikz_plot_prefix, buffer); - buffer += fclaw_pack_string(opts->tikz_plot_suffix, buffer); - buffer += fclaw_pack_string(opts->prefix, buffer); - buffer += fclaw_pack_string(opts->logging_prefix, buffer); - - return buffer-buffer_start; -} - -static size_t options_unpack(char* buffer, void** user){ - char* buffer_start = buffer; - - fclaw_options_t** opts_ptr = (fclaw_options_t**) user; - *opts_ptr = FCLAW_ALLOC(fclaw_options_t,1); - fclaw_options_t* opts = *opts_ptr; - - buffer += FCLAW_UNPACK(buffer, opts); - - buffer += fclaw_unpack_string(buffer, (char **) &opts->run_directory); - buffer += fclaw_unpack_string(buffer, (char **) &opts->scale_string); - buffer += fclaw_unpack_string(buffer, (char **) &opts->shift_string); - opts->scale = FCLAW_ALLOC(double,3); - opts->shift = FCLAW_ALLOC(double,3); - for(size_t i = 0; i < 3; i++){ - buffer += fclaw_unpack_double(buffer, &opts->scale[i]); - buffer += fclaw_unpack_double(buffer, &opts->shift[i]); - } - buffer += fclaw_unpack_string(buffer, (char **) &opts->tikz_figsize_string); - opts->tikz_figsize = FCLAW_ALLOC(double,2); - buffer += fclaw_unpack_double(buffer, &opts->tikz_figsize[0]); - buffer += fclaw_unpack_double(buffer, &opts->tikz_figsize[1]); - buffer += fclaw_unpack_string(buffer, (char **) &opts->tikz_plot_prefix); - buffer += fclaw_unpack_string(buffer, (char **) &opts->tikz_plot_suffix); - buffer += fclaw_unpack_string(buffer, (char **) &opts->prefix); - buffer += fclaw_unpack_string(buffer, (char **) &opts->logging_prefix); - - sc_keyvalue_t *kv = opts->kv_timing_verbosity = sc_keyvalue_new (); - sc_keyvalue_set_int (kv, "wall", FCLAW_TIMER_PRIORITY_WALL); - sc_keyvalue_set_int (kv, "summary", FCLAW_TIMER_PRIORITY_SUMMARY); - sc_keyvalue_set_int (kv, "exclusive", FCLAW_TIMER_PRIORITY_EXCLUSIVE); - sc_keyvalue_set_int (kv, "counters", FCLAW_TIMER_PRIORITY_COUNTERS); - sc_keyvalue_set_int (kv, "details", FCLAW_TIMER_PRIORITY_DETAILS); - sc_keyvalue_set_int (kv, "extra", FCLAW_TIMER_PRIORITY_EXTRA); - sc_keyvalue_set_int (kv, "all", FCLAW_TIMER_PRIORITY_EXTRA); - - opts->is_unpacked = 1; - - return buffer-buffer_start; -} - -static fclaw_packing_vtable_t packing_vt = -{ - options_pack, - options_unpack, - options_packsize, - fclaw_options_destroy_void -}; - -const fclaw_packing_vtable_t* fclaw_options_get_packing_vtable(){ - return &packing_vt; -} - /* ------------------------------------------------------------------------ Generic functions - these call the functions above ------------------------------------------------------------------------ */ @@ -623,6 +531,15 @@ options_destroy (fclaw_app_t * a, void *package, void *registered) /* Destroy option arrays created in post-process */ fclaw_options_destroy (fclaw_opt); + + /* Destroy linked list of section names */ + sc_keyvalue_t * fclaw_opt_sections = + (sc_keyvalue_t*) fclaw_app_get_attribute(a, "fclaw_opt_sections", NULL); + if(fclaw_opt_sections != NULL) + { + sc_keyvalue_destroy(fclaw_opt_sections); + fclaw_app_set_attribute(a, "fclaw_opt_sections", NULL); + } } static const fclaw_app_options_vtable_t options_vtable = { @@ -658,10 +575,28 @@ fclaw_options_t* fclaw_options_register (fclaw_app_t * a, configfile, &options_vtable, fclaw_opt); - - /* register packing vtable */ - fclaw_app_register_options_packing_vtable("fclaw2d", &packing_vt); + /* append to list of sections for fclaw_opts */ + sc_keyvalue_t *fclaw_opt_sections = + (sc_keyvalue_t*) fclaw_app_get_attribute(a, "fclaw_opt_sections", NULL); + if(fclaw_opt_sections == NULL) + { + fclaw_opt_sections = sc_keyvalue_new(); + fclaw_app_set_attribute(a, "fclaw_opt_sections", fclaw_opt_sections); + } + char *key = strdup(section == NULL ? "Options" : section); + char* curr_char = key; + while(*curr_char != '\0') + { + *curr_char = tolower(*curr_char); + curr_char++; + } + /* set to 1 for the section, so if checking the section + exists int the keyvalue, the return value is 1 */ + sc_keyvalue_set_int(fclaw_opt_sections, + key, + 1); + return fclaw_opt; } diff --git a/src/fclaw_options.h b/src/fclaw_options.h index 1dcf7b26a..4efc45946 100644 --- a/src/fclaw_options.h +++ b/src/fclaw_options.h @@ -54,13 +54,6 @@ fclaw_options_t* fclaw_options_register (fclaw_app_t * a, const char *section, const char *configfile); -/** - * @brief Get the packing vtable for the options - * - * @return const fclaw_packing_vtable_t* the vtable - */ -const fclaw_packing_vtable_t* fclaw_options_get_packing_vtable(); - /* These can be called from external routines (in torthem, for example?) */ fclaw_exit_type_t fclaw_options_postprocess (fclaw_options_t * fclaw_opt); @@ -228,6 +221,12 @@ struct fclaw_options int verbosity; /**< TODO: Do we have guidelines here? */ int output; + int checkpoint; + + int restart; + const char * restart_file; /**< filename of restart file */ + const char * partition_file; /**< filename of partition file */ + int tikz_out; /* Boolean */ const char *tikz_figsize_string; diff --git a/src/fclaw_options.h.TEST.cpp b/src/fclaw_options.h.TEST.cpp index 65abc113e..909200565 100644 --- a/src/fclaw_options.h.TEST.cpp +++ b/src/fclaw_options.h.TEST.cpp @@ -82,216 +82,5 @@ TEST_CASE("fclaw_options_store fails if called twice on a glob") fclaw_global_destroy(glob1); fclaw_global_destroy(glob2); } -TEST_CASE("fclaw_options packing/unpacking") -{ - fclaw_options_t* opts = FCLAW_ALLOC_ZERO(fclaw_options_t,1); - opts->dim = 3; - opts->run_directory = "test"; - opts->initial_dt = 0.1; - opts->tfinal = 1.0; - opts->outstyle = 1; - opts->nout = 10; - opts->nstep = 100; - opts->subcycle = 0; - opts->use_fixed_dt = 1; - opts->max_cfl = .2; - opts->desired_cfl = .3; - opts->reduce_cfl = 0; -// double tout[] = {0.5,0.6,0.7,0.8,0.9}; -// opts->tout = tout; - opts->refratio = 2; - opts->minlevel = 4; - opts->maxlevel = 3; - opts->regrid_interval = 5; - opts->smooth_refine = 2; - opts->refine_threshold = 3.0; - opts->time_sync = 0; - opts->output_gauges = 1; - opts->gauge_buffer_length = 300; - opts->output_rays = 2; - opts->manifold = 2; - opts->mi = 3; - opts->mj = 4; - opts->periodic_x = 0; - opts->periodic_y = 1; - opts->flux_correction = 1; - opts->fluctuation_correction = 2; - opts->coarsen_delay = 3; - opts->init_ghostcell = 0; - opts->advance_one_step = 1; - opts->outstyle_uses_maxlevel = 2; - opts->timeinterp2fillghost = 3; - opts->scale_string = "blah"; - double scale[3] = {1.0,2.0,3.0}; - opts->scale = scale; - opts->shift_string = "jbkal"; - double shift[3] = {4.0,5.0,6.0}; - opts->shift = shift; - opts->phi = 3.5; - opts->ax = 3.98; - opts->bx = 32.38; - opts->ay = 32.90; - opts->by = 32.90; - opts->az = 104.9; - opts->bz = 3290.9023; - opts->run_user_diagnostics = 1; - opts->compute_error = 2; - opts->conservation_check = 3; - opts->trapfpe = 3; - opts->report_timing = 3; - opts->report_timing_verbosity = 3; - opts->mpi_debug = 2; - opts->ghost_patch_pack_area = 3; - opts->ghost_patch_pack_extra = 4; - opts->ghost_patch_pack_numextrafields=3298; - opts->verbosity = 3; - opts->output = 3; - opts->tikz_out = 3; - opts->tikz_figsize_string ="jdfajfda"; - double figsize[2] = {3.0,4.0}; - opts->tikz_figsize = figsize; - opts->tikz_plot_fig = 3; - opts->tikz_plot_prefix = "plot2jk"; - opts->tikz_plot_suffix = "plot3jk"; - opts->tikz_mesh_only= 0; - opts->prefix = "jdsjkl"; - opts->vtkspace = 0.328; - opts->weighted_partition = 0; - opts->is_registered = 1; - opts->logging_prefix = "werqreqw"; - opts->is_unpacked = false; - - const fclaw_packing_vtable_t* vt = fclaw_options_get_packing_vtable(); - - size_t size = vt->size(opts); - char buffer[size]; - size_t bytes_written = vt->pack(opts,buffer); - REQUIRE_EQ(bytes_written,size); - - fclaw_options_t* output_opts = nullptr; - size_t bytes_read = vt->unpack(buffer,(void**)&output_opts); - - REQUIRE_EQ(bytes_read,size); - REQUIRE_NE(output_opts,nullptr); - - CHECK_EQ(opts->dim , output_opts->dim); - - CHECK_NE(opts->run_directory , output_opts->run_directory); - CHECK_UNARY(!strcmp(opts->run_directory, output_opts->run_directory)); - - CHECK_EQ(opts->initial_dt , output_opts->initial_dt); - CHECK_EQ(opts->tfinal , output_opts->tfinal); - CHECK_EQ(opts->outstyle , output_opts->outstyle); - CHECK_EQ(opts->nout , output_opts->nout); - CHECK_EQ(opts->nstep , output_opts->nstep); - CHECK_EQ(opts->subcycle , output_opts->subcycle); - CHECK_EQ(opts->use_fixed_dt , output_opts->use_fixed_dt); - CHECK_EQ(opts->max_cfl , output_opts->max_cfl); - CHECK_EQ(opts->desired_cfl , output_opts->desired_cfl ); - CHECK_EQ(opts->reduce_cfl , output_opts->reduce_cfl); - -// CHECK_NE(opts->tout , output_opts->tout); -// for(int i = 0; i < 5; i++) -// { -// CHECK_EQ(opts->tout[i],output_opts->tout[i]); -// } - - CHECK_EQ(opts->refratio , output_opts->refratio); - CHECK_EQ(opts->minlevel , output_opts->minlevel); - CHECK_EQ(opts->maxlevel , output_opts->maxlevel); - CHECK_EQ(opts->regrid_interval , output_opts->regrid_interval); - CHECK_EQ(opts->smooth_refine , output_opts->smooth_refine); - CHECK_EQ(opts->refine_threshold , output_opts->refine_threshold); - CHECK_EQ(opts->time_sync , output_opts->time_sync); - CHECK_EQ(opts->output_gauges , output_opts->output_gauges); - CHECK_EQ(opts->gauge_buffer_length , output_opts->gauge_buffer_length); - CHECK_EQ(opts->output_rays , output_opts->output_rays); - CHECK_EQ(opts->manifold , output_opts->manifold); - CHECK_EQ(opts->mi , output_opts->mi); - CHECK_EQ(opts->mj , output_opts->mj); - CHECK_EQ(opts->periodic_x , output_opts->periodic_x); - CHECK_EQ(opts->periodic_y , output_opts->periodic_y); - CHECK_EQ(opts->flux_correction , output_opts->flux_correction); - CHECK_EQ(opts->fluctuation_correction , output_opts->fluctuation_correction); - CHECK_EQ(opts->coarsen_delay , output_opts->coarsen_delay); - CHECK_EQ(opts->init_ghostcell , output_opts->init_ghostcell); - CHECK_EQ(opts->advance_one_step , output_opts->advance_one_step); - CHECK_EQ(opts->outstyle_uses_maxlevel , output_opts->outstyle_uses_maxlevel); - CHECK_EQ(opts->timeinterp2fillghost , output_opts->timeinterp2fillghost); - - CHECK_NE(opts->scale_string , output_opts->scale_string); - CHECK_UNARY(!strcmp(opts->scale_string, output_opts->scale_string)); - - CHECK_NE(opts->scale , output_opts->scale); - for(int i = 0; i < 3; i++) - { - CHECK_EQ(opts->scale[i],output_opts->scale[i]); - } - - CHECK_NE(opts->shift_string , output_opts->shift_string); - CHECK_UNARY(!strcmp(opts->shift_string, output_opts->shift_string)); - - CHECK_NE(opts->shift , output_opts->shift); - for(int i = 0; i < 3; i++) - { - CHECK_EQ(opts->shift[i],output_opts->shift[i]); - } - - CHECK_EQ(opts->phi , output_opts->phi); - CHECK_EQ(opts->ax , output_opts->ax); - CHECK_EQ(opts->bx , output_opts->bx); - CHECK_EQ(opts->ay , output_opts->ay); - CHECK_EQ(opts->by , output_opts->by); - CHECK_EQ(opts->az , output_opts->az); - CHECK_EQ(opts->bz , output_opts->bz); - CHECK_EQ(opts->run_user_diagnostics , output_opts->run_user_diagnostics); - CHECK_EQ(opts->compute_error , output_opts->compute_error); - CHECK_EQ(opts->conservation_check , output_opts->conservation_check); - CHECK_EQ(opts->trapfpe , output_opts->trapfpe); - CHECK_EQ(opts->report_timing , output_opts->report_timing); - CHECK_EQ(opts->report_timing_verbosity , output_opts->report_timing_verbosity); - CHECK_EQ(opts->mpi_debug , output_opts->mpi_debug); - CHECK_EQ(opts->ghost_patch_pack_area , output_opts->ghost_patch_pack_area); - CHECK_EQ(opts->ghost_patch_pack_extra , output_opts->ghost_patch_pack_extra); - CHECK_EQ(opts->ghost_patch_pack_numextrafields , output_opts->ghost_patch_pack_numextrafields); - CHECK_EQ(opts->verbosity , output_opts->verbosity); - CHECK_EQ(opts->output , output_opts->output); - CHECK_EQ(opts->tikz_out , output_opts->tikz_out); - - CHECK_NE(opts->tikz_figsize_string , output_opts->tikz_figsize_string); - CHECK_UNARY(!strcmp(opts->tikz_figsize_string, output_opts->tikz_figsize_string)); - - CHECK_NE(opts->tikz_figsize , output_opts->tikz_figsize); - for(int i = 0; i < 2; i++) - { - CHECK_EQ(opts->tikz_figsize[i],output_opts->tikz_figsize[i]); - } - - CHECK_EQ(opts->tikz_plot_fig , output_opts->tikz_plot_fig); - - CHECK_NE(opts->tikz_plot_prefix , output_opts->tikz_plot_prefix); - CHECK_UNARY(!strcmp(opts->tikz_plot_prefix, output_opts->tikz_plot_prefix)); - - CHECK_NE(opts->tikz_plot_suffix , output_opts->tikz_plot_suffix); - CHECK_UNARY(!strcmp(opts->tikz_plot_suffix, output_opts->tikz_plot_suffix)); - - CHECK_EQ(opts->tikz_mesh_only , output_opts->tikz_mesh_only); - - CHECK_NE(opts->prefix , output_opts->prefix); - CHECK_UNARY(!strcmp(opts->prefix, output_opts->prefix)); - - CHECK_EQ(opts->vtkspace , output_opts->vtkspace); - CHECK_EQ(opts->weighted_partition , output_opts->weighted_partition); - CHECK_EQ(opts->is_registered , output_opts->is_registered); - - CHECK_NE(opts->logging_prefix , output_opts->logging_prefix); - CHECK_UNARY(!strcmp(opts->logging_prefix, output_opts->logging_prefix)); - - CHECK_UNARY(output_opts->is_unpacked); - - vt->destroy(output_opts); - - FCLAW_FREE(opts); -} #endif \ No newline at end of file diff --git a/src/fclaw_output.c b/src/fclaw_output.c index 3a437cb5a..76f545383 100644 --- a/src/fclaw_output.c +++ b/src/fclaw_output.c @@ -24,6 +24,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include +#include #include #include #include @@ -69,8 +70,6 @@ fclaw_output_frame (fclaw_global_t * glob, int iframe) { fclaw2d_output_frame_tikz(glob,iframe); } -} - - - + +} diff --git a/src/fclaw_output.h b/src/fclaw_output.h index 85eafd8a3..4bb1d02a2 100644 --- a/src/fclaw_output.h +++ b/src/fclaw_output.h @@ -38,6 +38,22 @@ struct fclaw_global; /* This is a hack !! */ void fclaw_output_frame(struct fclaw_global * glob, int iframe); +/** + * @brief Write out a checkpoint file. + * + * This will only output if the checkpoint_out flag is set in fclaw_options. + * + * This will write two files: a fort_frame_[iframe].checkpoint file and a + * fort_frame_[iframe].partition file. + * + * The partition file is optionally used when restarting to ensure that the + * domain is partitioned in the same way as before. + * + * @param glob the global context + * @param iframe the frame number + */ +void fclaw_output_checkpoint(struct fclaw_global * glob, int iframe); + void fclaw2d_output_frame_tikz(struct fclaw_global* glob, int iframe); #ifdef __cplusplus diff --git a/src/fclaw_packing.h b/src/fclaw_packing.h index 31f56372f..28c9b1165 100644 --- a/src/fclaw_packing.h +++ b/src/fclaw_packing.h @@ -27,6 +27,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #define FCLAW_PACKING_H #include +#include #ifdef __cplusplus extern "C" @@ -50,27 +51,45 @@ extern "C" /** * @brief Pack userdata into a buffer + * @param glob global context * @param userdata pointer to userdata * @param buffer buffer to pack into + * @return size_t number of bytes written */ -typedef size_t (*fclaw_packing_pack_t)(void* userdata, - char* buffer); +typedef size_t (*fclaw_packing_pack_t)(fclaw_global_t *glob, + void *userdata, + char *buffer); /** * @brief Unpack userdata from buffer + * @param glob global context * @param buffer buffer to unpack from - * @return newly create userdata + * @param userdata user data to read from + * @return size_t number of bytes read */ -typedef size_t (*fclaw_packing_unpack_t)(char* buffer,void**); +typedef size_t (*fclaw_packing_unpack_t)(fclaw_global_t *glob, + char *buffer, + void *userdata); /** * @brief Get the size needed to pack userdata - * @return the size + * @param glob global context + * @param userdata pointer to userdata + * @return size_t number of bytes needed to pack userdata + */ +typedef size_t (*fclaw_packing_packsize_t)(fclaw_global_t *glob, + void *userdata); + +/** + * @brief create new userdata + * @param glob global context + * @return void * pointer to new userdata */ -typedef size_t (*fclaw_packing_packsize_t)(void* userdata); +typedef void * (*fclaw_packing_new_t)(fclaw_global_t *glob); /** * @brief destroy userdata + * @param value pointer to userdata to destroy */ -typedef void (*fclaw_packing_destroy_t)(void* value); +typedef void (*fclaw_packing_destroy_t)(void *value); /** * @brief vtable for packing functions @@ -80,8 +99,9 @@ typedef struct fclaw_packing_vtable fclaw_packing_pack_t pack; /**< function for packing */ fclaw_packing_unpack_t unpack; /**< function for unpacking*/ fclaw_packing_packsize_t size; /**< function for packing size */ + fclaw_packing_new_t new_data; /**< function for creating new data */ fclaw_packing_destroy_t destroy; /**< function for destroying */ -} fclaw_useradata_vtable_t; +} fclaw_packing_vtable_t; /** * @brief Get the size needed for packing a string diff --git a/src/fclaw_patch.c b/src/fclaw_patch.c index 72bf73a87..d592b7aa2 100644 --- a/src/fclaw_patch.c +++ b/src/fclaw_patch.c @@ -808,6 +808,41 @@ void fclaw_patch_partition_unpack(fclaw_global_t *glob, patch_data_unpack(glob,this_patch,pdata_unpack_data_from_here); } +/* ----------------------------------- Restart --------------------------------------- */ + +int fclaw_patch_checkpoint_num_pointers(fclaw_global_t* glob) +{ + fclaw_patch_vtable_t *patch_vt = fclaw_patch_vt(glob); + FCLAW_ASSERT(patch_vt->checkpoint_num_pointers != NULL); + return patch_vt->checkpoint_num_pointers(glob); +} + +void fclaw_patch_checkpoint_pointer_sizes(struct fclaw_global *glob, size_t restart_sizes[]) +{ + fclaw_patch_vtable_t *patch_vt = fclaw_patch_vt(glob); + FCLAW_ASSERT(patch_vt->checkpoint_pointer_sizes != NULL); + patch_vt->checkpoint_pointer_sizes(glob, restart_sizes); +} + +void fclaw_patch_checkpoint_names(fclaw_global_t* glob, const char *names[]) +{ + fclaw_patch_vtable_t *patch_vt = fclaw_patch_vt(glob); + FCLAW_ASSERT(patch_vt->checkpoint_names != NULL); + return patch_vt->checkpoint_names(glob, names); +} + +void* fclaw_patch_checkpoint_get_pointer(struct fclaw_global* glob, + struct fclaw_patch* this_patch, + int blockno, + int patchno, + int pointerno) +{ + fclaw_patch_vtable_t *patch_vt = fclaw_patch_vt(glob); + FCLAW_ASSERT(patch_vt->checkpoint_get_pointer != NULL); + return patch_vt->checkpoint_get_pointer(glob, this_patch, blockno, patchno, pointerno); +} + + /* ----------------------------- Conservative updates --------------------------------- */ /* We need to virtualize this because we call it from fclaw_face_neighbors */ diff --git a/src/fclaw_patch.h b/src/fclaw_patch.h index d0ec0ea61..7122778b6 100644 --- a/src/fclaw_patch.h +++ b/src/fclaw_patch.h @@ -830,6 +830,52 @@ void fclaw_patch_partition_unpack(struct fclaw_global *glob, */ size_t fclaw_patch_partition_packsize(struct fclaw_global* glob); +///@} +/* ------------------------------------------------------------------------------------ */ +/// @name Checkpoint +/* ------------------------------------------------------------------------------------ */ +///@{ + +/** + * @brief Get the number of pointers to store in the checkpoint + * + * @param glob the global context + * @return int the number of restart pointers + */ +int fclaw_patch_checkpoint_num_pointers(struct fclaw_global* glob); + +/** + * @brief Get the sizes of the checkpoint data + * + * @param[in] glob the global context + * @param[out] restart_sizes an array of length ::fclaw_patch_restart_num_pointers + * with the sizes of the restart data + */ +void fclaw_patch_checkpoint_pointer_sizes(struct fclaw_global* glob, size_t restart_sizes[]); + +/** + * @brief Get the names of the checkpoint data. + * + * @param glob the global context + * @return sc_array_t* an array of strings + */ +void fclaw_patch_checkpoint_names(struct fclaw_global* glob, const char *names[]); + +/** + * @brief Get a specific pointer for the checkpoint + * + * @param glob the global context + * @param this_patch the patch context + * @param blockno the block number + * @param patchno the patch number + * @param pointerno the pointer number + * @return void* the pointer + */ +void *fclaw_patch_checkpoint_get_pointer(struct fclaw_global* glob, + struct fclaw_patch* this_patch, + int blockno, + int patchno, + int pointerno); ///@} /* ------------------------------------------------------------------------------------ */ @@ -1544,6 +1590,53 @@ typedef void (*fclaw_patch_destroy_user_data_t)(struct fclaw_global* glob, */ typedef void* (*fclaw_patch_metric_patch_t)(struct fclaw_patch *patch); +///@} +/* ------------------------------------------------------------------------------------ */ +/// @name Checkpoint Functions (typedefs) +/* ------------------------------------------------------------------------------------ */ +///@{ + +/** + * @brief Get the number of pointers to store in the checkpoint + * + * @param glob the global context + * @return int the number of restart pointers + */ +typedef int (*checkpoint_num_pointers_t)(struct fclaw_global *glob); + +/** + * @brief Get the sizes of the checkpoint data + * + * @param[in] glob the global context + * @param[out] restart_sizes an array of length ::fclaw_patch_restart_num_pointers + * with the sizes of the restart data + */ +typedef void (*checkpoint_pointer_sizes_t)(struct fclaw_global *glob, size_t sizes[]); + +/** + * @brief Get the names of the checkpoint data. + * + * @param glob the global context + * @return sc_array_t* an array of strings + */ +typedef void (*checkpoint_names_t)(struct fclaw_global *glob, const char *restart_names[]); + +/** + * @brief Get a specific pointer for the checkpoint + * + * @param glob the global context + * @param this_patch the patch context + * @param blockno the block number + * @param patchno the patch number + * @param pointerno the pointer number + * @return void* the pointer + */ +typedef void *(*checkpoint_get_pointer_t)(struct fclaw_global* glob, + struct fclaw_patch* this_patch, + int blockno, + int patchno, + int pointerno); + ///@} /* ------------------------------------------------------------------------------------ */ /// @name Virtual Table @@ -1716,6 +1809,19 @@ struct fclaw_patch_vtable /** @} */ + /** @{ @name Checkpoint Functions */ + + /** @copybrief :: checkpoint_num_pointers_t */ + checkpoint_num_pointers_t checkpoint_num_pointers; + /** @copybrief :: checkpoint_pointer_sizes_t */ + checkpoint_pointer_sizes_t checkpoint_pointer_sizes; + /** @copybrief :: checkpoint_names_t */ + checkpoint_names_t checkpoint_names; + /** @copybrief :: checkpoint_get_pointer_t */ + checkpoint_get_pointer_t checkpoint_get_pointer; + + /** @} */ + /** True if vtable has been set */ int is_set; }; diff --git a/src/fclaw_restart.c b/src/fclaw_restart.c new file mode 100644 index 000000000..564b86637 --- /dev/null +++ b/src/fclaw_restart.c @@ -0,0 +1,776 @@ +/* +Copyright (c) 2012-2024 Carsten Burstedde, Donna Calhoun, Scott Aiton +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, this +list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright notice, +this list of conditions and the following disclaimer in the documentation +and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/** + * @brief Check the error code and print an error message if not successful + */ +#define CHECK_ERROR_CODE(refine_dim, errcode, str) \ +do { \ + int reslen, retval; \ + char err_str[sc_MPI_MAX_ERROR_STRING]; \ + if (errcode != FCLAW_FILE_ERR_SUCCESS) \ + { \ + retval = fclaw_file_error_string (refine_dim, errcode, err_str, &reslen); \ + if(retval != 0) \ + { \ + fclaw_global_errorf ("%s: error string function not successful", str); \ + } \ + fclaw_global_errorf("%s: %s\n", str, err_str); \ + } \ +} while(0) + +/** + * @brief Check the error code and abort with message if not successful + */ +#define CHECK_ERROR_CODE_AND_ABORT(refine_dim, errcode, str) \ +do { \ + int reslen, retval; \ + char err_str[sc_MPI_MAX_ERROR_STRING]; \ + if (errcode != FCLAW_FILE_ERR_SUCCESS) \ + { \ + retval = fclaw_file_error_string (refine_dim, errcode, err_str, &reslen); \ + SC_CHECK_ABORTF (!retval, "%s: error string function not successful", str); \ + SC_ABORTF ("%s: %*.*s", str, reslen, reslen, err_str); \ + } \ +} while(0) + + +/** + * @brief Get the ini file for the options as a string + * + * @param glob the global context + * @return char* the ini file as a string, NULL if an error occurs. Needs to be freed by the caller + */ +static char* +get_used_ini(fclaw_global_t * glob) +{ + char *buffer = NULL; + long length = 0; + if(glob->mpirank == 0) + { + sc_options_t * options = (sc_options_t*) fclaw_global_get_attribute(glob, "fclaw_options"); + if(options == NULL) + { + fclaw_abortf("fclaw_restart.c: Cannot find sc options structure in glob." + " Make sure the fclaw_global_new(app) constructor is being used in main.\n"); + } + + int retval = sc_options_save (fclaw_get_package_id (), + FCLAW_VERBOSITY_ERROR, + options, + "fclaw_options.ini.used"); + if(retval != 0) + { + fclaw_global_productionf("fclaw_restart.c: Error saving options\n"); + return NULL; + } + + // read the entire file into a string + FILE *file = fopen("fclaw_options.ini.used", "r"); + if (file == NULL) + { + printf("fclaw_restart.c: Cannot open file\n"); + return NULL; + } + + fseek(file, 0, SEEK_END); + length = ftell(file); + fseek(file, 0, SEEK_SET); + + buffer = FCLAW_ALLOC(char, length + 1); + if (buffer) + { + fread(buffer, 1, length, file); + } + fclose(file); + + buffer[length] = '\0'; + } + //broadcast the lenth + sc_MPI_Bcast(&length, 1, sc_MPI_LONG, 0, glob->mpicomm); + //allocate the buffer on other ranks + if(glob->mpirank != 0) + { + buffer = FCLAW_ALLOC(char, length + 1); + } + FCLAW_ASSERT(buffer != NULL); + //broadcast the string + sc_MPI_Bcast(buffer, length+1, sc_MPI_CHAR, 0, glob->mpicomm); + + return buffer; + + +} + +/** + * @brief Check if option should be skipped for comparison + * + * @param fclaw_opt_sections the sections containing the core options + * @param section the section name + * @param key the key name + * @return int true if the option should be skipped, false otherwise + */ +static int +skip_option(sc_keyvalue_t *fclaw_opt_sections, const char* section, const char* key) +{ + int skip = 0; + if(sc_keyvalue_get_int(fclaw_opt_sections, section, 0)) + { + //skip the section: part of the key + const char* key_substr = key + strlen(section) + 1; + if(strcmp(key_substr, "restart-file") == 0) + { + skip = 1; + } + else if(strcmp(key_substr, "partition-file") == 0) + { + skip = 1; + } + else if(strcmp(key_substr, "restart") == 0) + { + skip = 1; + } + else if(strcmp(key_substr, "checkpoint") == 0) + { + skip = 1; + } + } + return skip; +} + +/** + * @brief compare two ini dictionaries + * + * @param fclaw_opt_secitons the sections containing the core options + * @param expected the expected dictionary + * @param actual the actual dictionary + * @return int the number of differences found + */ +static int +compare_dictionaries(sc_keyvalue_t *fclaw_opt_secitons, + dictionary *expected, + dictionary *actual) +{ + int num_differences = 0; + int nsec = iniparser_getnsec(expected); + for (int i_sec = 0; i_sec < nsec; i_sec++) + { + char* section = iniparser_getsecname(expected, i_sec); + if(strcmp(section, "arguments") != 0) + { + if(iniparser_find_entry(actual,section)) + { + int nkey = iniparser_getsecnkeys(expected, section); + char** keys = iniparser_getseckeys(expected, section); + + for (int i_key = 0; i_key < nkey; i_key++) + { + char* key = keys[i_key]; + if(skip_option(fclaw_opt_secitons, section, key)) + { + continue; + } + + if(iniparser_find_entry(actual, key)) + { + char* expected_value = iniparser_getstring(expected, key, NULL); + char* actual_value = iniparser_getstring(actual, key, NULL); + if(strcmp(expected_value, actual_value) != 0) + { + fclaw_global_productionf("restarting with mismatched value for [%s]. Value in checkpoint [%s], value being run with [%s].\n", key, expected_value, actual_value); + num_differences++; + } + + } + else + { + fclaw_global_productionf("Checkpoint file has unused option %s.\n", keys[i_key]); + num_differences++; + } + } + free (keys); + } + else + { + fclaw_global_productionf("Checkpoint file has unused section [%s].\n", section); + num_differences++; + } + } + } + // do inverse and look for options in actual that are not in expected + nsec = iniparser_getnsec(actual); + for(int i_sec = 0; i_sec < nsec; i_sec++) + { + char* section = iniparser_getsecname(actual, i_sec); + if(strcmp(section, "arguments") != 0) + { + if(!iniparser_find_entry(expected, section)) + { + fclaw_global_productionf("Checkpoint file is missing section [%s].\n", section); + num_differences++; + } + else + { + int nkey = iniparser_getsecnkeys(actual, section); + char** keys = iniparser_getseckeys(actual, section); + + for(int i_key = 0; i_key < nkey; i_key++) + { + char* key = keys[i_key]; + if(skip_option(fclaw_opt_secitons, section, key)) + { + continue; + } + + if(!iniparser_find_entry(expected, key)) + { + fclaw_global_productionf("Checkpoint file is missing option %s.\n", keys[i_key]); + num_differences++; + } + } + free(keys); + } + } + } + return num_differences; +} + +/** + * @brief Compare provided options with the options stored in the checkpoint + * + * @param glob the global context + * @param checkpoint_ini the ini file from the checkpoint + */ +static void +check_options(fclaw_global_t * glob, const char* checkpoint_ini) +{ + if(glob->mpirank == 0) + { + fclaw_global_productionf("\n"); + fclaw_global_productionf("=========== Comparing with options stored in checkpoint ===========\n"); + fclaw_global_productionf("\n"); + + //save the used ini file + sc_options_t * options = + (sc_options_t*) fclaw_global_get_attribute(glob, "fclaw_options"); + int retval = sc_options_save (fclaw_get_package_id (), + FCLAW_VERBOSITY_ERROR, + options, + "fclaw_options.ini.used"); + + if(retval != 0) + { + fclaw_abortf("fclaw_restart.c: Error saving current options\n"); + } + + //save the restart ini file to fclaw_options.ini.checkpoint + FILE *file = fopen("fclaw_options.ini.checkpoint", "w"); + if (file == NULL) + { + printf("Cannot open file\n"); + return; + } + fprintf(file, "%s", checkpoint_ini); + fclose(file); + + fclaw_global_productionf("Checkpoint options have been saved to fclaw_options.ini.checkpoint\n"); + fclaw_global_productionf("\n"); + + dictionary *actual = iniparser_load("fclaw_options.ini.used"); + dictionary *expected = iniparser_load("fclaw_options.ini.checkpoint"); + + sc_keyvalue_t *fclaw_opt_sections + = (sc_keyvalue_t*) fclaw_global_get_attribute(glob, "fclaw_opt_sections"); + int num_differences = compare_dictionaries(fclaw_opt_sections, expected, actual); + + iniparser_freedict(actual); + iniparser_freedict(expected); + + if(num_differences == 0) + { + fclaw_global_productionf("No differences found.\n"); + } + + fclaw_global_productionf("\n"); + fclaw_global_productionf("===================================================================\n"); + fclaw_global_productionf("\n"); + } +} + +static void +free_used_ini(void* data) +{ + char* buffer = (char*) data; + FCLAW_FREE(buffer); +} + +/** + * @brief Check that the user string matches an expected string. + * The user string returned by fclaw_file functions is padded with spaces, + * so we need to check that the strings match up to the first space and that + * the rest of the string is just spaces. + * + * @param expected the expected string + * @param actual the actual string + */ +static +void check_user_string(const char* expected, const char* actual) +{ + if(strncmp(expected, actual, strlen(expected)) != 0) + { + fclaw_abortf("fclaw_restart.c: User string mismatch: %s != %s\n", expected, actual); + } + else + { + //also check that rest of the string is just spaces + for(int i = strlen(expected); i < FCLAW_FILE_USER_STRING_BYTES; i++) + { + if(actual[i] != '\0') + { + break; + } + else if(actual[i] != ' ') + { + fclaw_abortf("fclaw_restart.c: User string mismatch: %s != %s\n", expected, actual); + } + } + } +} + +typedef struct pack_iter +{ + fclaw_global_t * glob; + int curr_index; + size_t size; + sc_array_t* patches; + int pointerno; +}pack_iter_t; + + +/** + * @brief Set patch data from the checkpoint, user data is a pack_iter_t + */ +static void +set_patches(fclaw_domain_t * domain, fclaw_patch_t * patch, int blockno, int patchno, void *user) +{ + pack_iter_t *user_data = (pack_iter_t*)user; + sc_array_t *patches = user_data->patches; + sc_array_t * current_arr = (sc_array_t *) sc_array_index (patches, user_data->curr_index); + + fclaw_build_mode_t build_mode = FCLAW_BUILD_FOR_UPDATE; + + if(user_data->pointerno == 0) + { + fclaw_patch_build(user_data->glob, patch, blockno, patchno,(void*) &build_mode); + } + + void* data = fclaw_patch_checkpoint_get_pointer(user_data->glob, patch, blockno, patchno, user_data->pointerno); + + memcpy(data, sc_array_index(current_arr, 0), user_data->size); + + sc_array_reset(current_arr); + + user_data->curr_index++; +} + +static +void restart (fclaw_global_t * glob, + const char* restart_filename, + const char* partition_filename, + fclaw_timer_names_t timer) +{ + int refine_dim = glob->domain->refine_dim; + fclaw_domain_reset(glob); + + int errcode; + sc_array_t* partition = NULL; + char user_string[FCLAW_FILE_USER_STRING_BYTES]; + if(partition_filename != NULL) + { + partition = sc_array_new(sizeof(p4est_gloidx_t)); + fclaw_file_read_partition(refine_dim, + partition_filename, + user_string, + glob->mpicomm, + partition, + &errcode); + check_user_string("Partition", user_string); + CHECK_ERROR_CODE_AND_ABORT(refine_dim, errcode, "restart read_partition"); + } + + fclaw_file_context_t *fc + = fclaw_file_open_read (refine_dim, + restart_filename, + user_string, + glob->mpicomm, + partition, + &glob->domain, + &errcode); + check_user_string("ForestClaw checkpoint file", user_string); + CHECK_ERROR_CODE_AND_ABORT(refine_dim, errcode, "restart open_file"); + + fclaw_domain_setup(glob, glob->domain); + + if(partition != NULL) + { + sc_array_destroy(partition); + } + + sc_array_t array; + + //read the version major + + sc_array_init_size(&array, sizeof(int), 1); + fc = fclaw_file_read_block(fc, user_string, sizeof(int), &array, &errcode); + + check_user_string("checkpoint_version_major", user_string); + CHECK_ERROR_CODE_AND_ABORT(refine_dim, errcode, "restart read version_major"); + + int version_major = *((int*) sc_array_index(&array, 0)); + + sc_array_reset(&array); + + + //read the version minor + + sc_array_init_size(&array, sizeof(int), 1); + fc = fclaw_file_read_block(fc, user_string, sizeof(int), &array, &errcode); + + check_user_string("checkpoint_version_minor", user_string); + CHECK_ERROR_CODE_AND_ABORT(refine_dim, errcode, "restart read version_minor"); + + int version_minor = *((int*) sc_array_index(&array, 0)); + + sc_array_reset(&array); + + //version check + if(version_major != 1 || version_minor != 0) + { + fclaw_abortf("fclaw_restart.c: Incompatible checkpoint version: %d.%d\n", version_major, version_minor); + } + + //read the length of the used_ini string + + sc_array_init_size(&array, sizeof(size_t), 1); + fc = fclaw_file_read_block(fc, user_string, sizeof(size_t), &array, &errcode); + + + check_user_string("used_ini_length", user_string); + CHECK_ERROR_CODE_AND_ABORT(refine_dim, errcode, "restart read used_ini_length"); + + size_t ini_length = *((size_t*) sc_array_index(&array, 0)); + sc_array_reset(&array); + + //read the used_ini string + + sc_array_init_size(&array, ini_length, 1); + fc = fclaw_file_read_block(fc, user_string, ini_length, &array, &errcode); + + + check_user_string("used_ini", user_string); + CHECK_ERROR_CODE_AND_ABORT(refine_dim, errcode, "restart read used_ini"); + + const char* used_ini = (const char*) sc_array_index(&array, 0); + check_options(glob, used_ini); + + sc_array_reset(&array); + + //read the length of the glob buffer + + sc_array_init_size(&array, sizeof(size_t), 1); + + fc = fclaw_file_read_block(fc, user_string, sizeof(size_t), &array, &errcode); + + check_user_string("glob_size", user_string); + CHECK_ERROR_CODE_AND_ABORT(refine_dim, errcode, "restart read globsize"); + + size_t glob_packsize = *((size_t*) sc_array_index(&array, 0)); + + sc_array_reset(&array); + + //read the glob buffer + + sc_array_init_size(&array, glob_packsize, 1); + + fc = fclaw_file_read_block(fc, user_string, glob_packsize, &array, &errcode); + + check_user_string("glob", user_string); + CHECK_ERROR_CODE_AND_ABORT(refine_dim, errcode, "restart read glob buffer"); + + fclaw_global_unpack((char *) sc_array_index(&array, 0), glob); + + sc_array_reset(&array); + + //read patch data + + int num_pointers = fclaw_patch_checkpoint_num_pointers(glob); + size_t sizes[num_pointers]; + fclaw_patch_checkpoint_pointer_sizes(glob, sizes); + const char* names[num_pointers]; + fclaw_patch_checkpoint_names(glob, names); + + for(int i = 0; i < num_pointers; i++) + { + sc_array_t *patches = sc_array_new_count(sizeof(sc_array_t), glob->domain->local_num_patches); + pack_iter_t user; + user.glob = glob; + user.curr_index = 0; + user.patches = patches; + user.size = sizes[i]; + user.pointerno = i; + + fc = fclaw_file_read_array(fc, user_string, sizes[i], patches, &errcode); + + check_user_string(names[i], user_string); + CHECK_ERROR_CODE_AND_ABORT(refine_dim, errcode, "restart read patches"); + + fclaw_domain_iterate_patches(glob->domain, set_patches, &user); + + sc_array_destroy(patches); + } + + fclaw_file_close(fc, &errcode); + CHECK_ERROR_CODE_AND_ABORT(refine_dim, errcode, "restart close file"); + + fclaw_initialize_domain_flags(glob); + fclaw_exchange_setup(glob,timer); + fclaw_regrid_set_neighbor_types(glob); +} + +/** + * @brief Get patch data for the checkpoint, user data is a pack_iter_t + */ +static void +get_patches(fclaw_domain_t * domain, fclaw_patch_t * patch, int blockno, int patchno, void *user) +{ + pack_iter_t *user_data = (pack_iter_t*)user; + sc_array_t *patches = user_data->patches; + sc_array_t * current_arr = (sc_array_t *) sc_array_index (patches, user_data->curr_index); + + void* data = fclaw_patch_checkpoint_get_pointer(user_data->glob, patch, blockno, patchno, user_data->pointerno); + + sc_array_init_data(current_arr, data, user_data->size, 1); + + user_data->curr_index++; +} + + +static void +checkpoint_output_frame (fclaw_global_t * glob, int iframe) +{ + int refine_dim = glob->domain->refine_dim; + + char filename[BUFSIZ]; + char parition_filename[BUFSIZ]; + snprintf(filename, BUFSIZ, "fort_frame_%04d.checkpoint", iframe); + snprintf(parition_filename, BUFSIZ, "fort_frame_%04d.partition", iframe); + + int errcode; + fclaw_file_context_t *fc + = fclaw_file_open_write (filename, "ForestClaw checkpoint file", + glob->domain, &errcode); + CHECK_ERROR_CODE(refine_dim , errcode, "checkpoint open file"); + if(errcode != FCLAW_FILE_ERR_SUCCESS) + { + return; + } + + sc_array_t array; + + //dont know if we are going to bother with supporting older versions + //of checkpoint files, but we will write the version number anyway + + //write version major + + int version_major = 1; + sc_array_init_data(&array, &version_major, sizeof(int), 1); + + fc = fclaw_file_write_block(fc, "checkpoint_version_major", sizeof(int), &array, &errcode); + CHECK_ERROR_CODE(refine_dim, errcode, "checkpoint write version_major"); + if(errcode != FCLAW_FILE_ERR_SUCCESS) + { + return; + } + + //write version minor + + int version_minor = 0; + sc_array_init_data(&array, &version_minor, sizeof(int), 1); + fc = fclaw_file_write_block(fc, "checkpoint_version_minor", sizeof(int), &array, &errcode); + CHECK_ERROR_CODE(refine_dim , errcode, "checkpoint write version_minor"); + if(errcode != FCLAW_FILE_ERR_SUCCESS) + { + return; + } + + //write the used_ini length and string + + char* used_ini = + (char*) fclaw_global_get_attribute(glob, "fclaw_used_ini"); + if(used_ini == NULL) + { + used_ini = get_used_ini(glob); + if(used_ini == NULL) + { + return; + } + fclaw_global_attribute_store(glob, + "fclaw_used_ini", + used_ini, + NULL, + free_used_ini); + } + + size_t used_ini_length = strlen(used_ini); + sc_array_init_data(&array, &used_ini_length, sizeof(size_t), 1); + + fc = fclaw_file_write_block(fc, "used_ini_length", sizeof(size_t), &array, &errcode); + CHECK_ERROR_CODE(refine_dim , errcode, "write used_ini_length"); + if(errcode != FCLAW_FILE_ERR_SUCCESS) + { + return; + } + + sc_array_init_data(&array, used_ini, used_ini_length, 1); + fc = fclaw_file_write_block(fc, "used_ini", used_ini_length, &array, &errcode); + CHECK_ERROR_CODE(refine_dim , errcode, "write used_ini"); + if(errcode != FCLAW_FILE_ERR_SUCCESS) + { + return; + } + + //write size of glob buffer + + size_t glob_packsize = fclaw_global_packsize(glob); + sc_array_init_data(&array, &glob_packsize, sizeof(size_t), 1); + + fc = fclaw_file_write_block(fc, "glob_size", sizeof(size_t), &array, &errcode); + CHECK_ERROR_CODE(refine_dim , errcode, "write globsize"); + if(errcode != FCLAW_FILE_ERR_SUCCESS) + { + return; + } + + //write glob buffer + + sc_array_t glob_buffer; + sc_array_init_size(&glob_buffer, glob_packsize, 1); + fclaw_global_pack(glob,(char *) sc_array_index(&glob_buffer, 0)); + + fc = fclaw_file_write_block(fc, "glob", glob_packsize, &glob_buffer, &errcode); + CHECK_ERROR_CODE(refine_dim , errcode, "write glob buffer"); + if(errcode != FCLAW_FILE_ERR_SUCCESS) + { + return; + } + + sc_array_reset(&glob_buffer); + + //write patch data + + int num_pointers = fclaw_patch_checkpoint_num_pointers(glob); + size_t sizes[num_pointers]; + fclaw_patch_checkpoint_pointer_sizes(glob, sizes); + const char* names[num_pointers]; + fclaw_patch_checkpoint_names(glob, names); + for(int i = 0; i < num_pointers; i++) + { + sc_array_t *patches = sc_array_new_count(sizeof(sc_array_t), glob->domain->local_num_patches); + pack_iter_t user; + user.glob = glob; + user.curr_index = 0; + user.patches = patches; + user.size = sizes[i]; + user.pointerno = i; + fclaw_domain_iterate_patches(glob->domain, get_patches, &user); + + + fc = fclaw_file_write_array(fc, names[i], sizes[i], patches, &errcode); + CHECK_ERROR_CODE(refine_dim , errcode, "write patches"); + if(errcode != FCLAW_FILE_ERR_SUCCESS) + { + return; + } + + for(int i = 0; i < glob->domain->local_num_patches; i++) + { + sc_array_t * current_arr = (sc_array_t *) sc_array_index (patches, i); + sc_array_reset(current_arr); + } + sc_array_destroy(patches); + } + + + fclaw_file_close(fc, &errcode); + fclaw_file_write_partition (parition_filename, + "Paritition", + glob->domain, &errcode); + CHECK_ERROR_CODE(refine_dim , errcode, "close file"); + if(errcode != FCLAW_FILE_ERR_SUCCESS) + { + return; + } +} + +/* ----------------------------------------------------------------------- + Public interface + -------------------------------------------------------------------- */ + +void +fclaw_restart_from_file (fclaw_global_t * glob, + const char* restart_filename, + const char* partition_filename) +{ + restart(glob, restart_filename, partition_filename, FCLAW_TIMER_INIT); +} + +void fclaw_output_checkpoint(fclaw_global_t* glob, int iframe) +{ + const fclaw_options_t *fclaw_opt = fclaw_get_options(glob); + + if(fclaw_opt->checkpoint) + { + fclaw_timer_start (&glob->timers[FCLAW_TIMER_OUTPUT]); + + checkpoint_output_frame(glob,iframe); + + fclaw_timer_stop (&glob->timers[FCLAW_TIMER_OUTPUT]); + } +} \ No newline at end of file diff --git a/src/fclaw_restart.h b/src/fclaw_restart.h new file mode 100644 index 000000000..df5474336 --- /dev/null +++ b/src/fclaw_restart.h @@ -0,0 +1,80 @@ +/* +Copyright (c) 2012-2024 Carsten Burstedde, Donna Calhoun, Scott Aiton +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, this +list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright notice, +this list of conditions and the following disclaimer in the documentation +and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef FCLAW_RESTART_H +#define FCLAW_RESTART_H + +#ifdef __cplusplus +extern "C" +{ +#if 0 +} +#endif +#endif + +struct fclaw_global; /* This is a hack !! */ + + +/** + * @brief Restarts the forestclaw simulation from a restart file. + * + * This function is responsible for restarting the simulation from a previously saved state. + * This is meant to be called from fclaw_initalize() + * + * This will print an error message and exit for any error. + * + * @param glob The global context + * @param restart_filename The filename of the restart file. + * @param partition_filename The filename of the partition file. + */ +void +fclaw_restart_from_file (struct fclaw_global * glob, + const char* restart_filename, + const char* partition_filename); + +/** + * @brief Tests the restart functionality by reading data from a restart file. + * + * This function is used to do an "in memory" restart test. + * It deletes the current domain and creates a new domain from the restart file, + * and overwrites the values in glob with the values from the restart file. + * + * @param glob The pointer to the global context + * @param restart_filename The filename of the restart file to read from. + * @param partition_filename The filename of the partition file to read from. + */ +void +fclaw_restart_test_from_file (struct fclaw_global * glob, + const char* restart_filename, + const char* partition_filename); + +#ifdef __cplusplus +#if 0 +{ +#endif +} +#endif + +#endif diff --git a/src/fclaw_run.c b/src/fclaw_run.c index 914d4f2b0..8fa534b2f 100644 --- a/src/fclaw_run.c +++ b/src/fclaw_run.c @@ -33,6 +33,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include #include #include +#include +#include #include "fclaw_math.h" @@ -111,7 +113,6 @@ static void outstyle_0(fclaw_global_t *glob) } - /* ------------------------------------------------------------------------------- Output style 1 Output times are at times [0,dT, 2*dT, 3*dT,...,Tfinal], where dT = tfinal/nout @@ -120,6 +121,8 @@ static void outstyle_1(fclaw_global_t *glob) { fclaw_domain_t** domain = &glob->domain; + /* get context object from glob, if there is none, a new one will be created */ + fclaw_context_t *ctx = fclaw_context_get(glob, "fclaw_run_outstyle1_ctx"); /* Set error to 0 */ int init_flag = 1; /* Store anything that needs to be stored */ @@ -127,6 +130,7 @@ void outstyle_1(fclaw_global_t *glob) init_flag = 0; int iframe = 0; + fclaw_context_get_int(ctx, "iframe", &iframe); fclaw_output_frame(glob,iframe); const fclaw_options_t *fclaw_opt = fclaw_get_options(glob); @@ -136,15 +140,19 @@ void outstyle_1(fclaw_global_t *glob) double initial_dt = fclaw_opt->initial_dt; int level_factor = pow_int(2,fclaw_opt->maxlevel - fclaw_opt->minlevel); double dt_minlevel = initial_dt; + fclaw_context_get_double(ctx, "dt_minlevel", &dt_minlevel); double t0 = 0; double dt_outer = (final_time-t0)/((double) nout); double t_curr = t0; + fclaw_context_get_double(ctx, "t_curr", &t_curr); int n_inner = 0; + fclaw_context_get_int(ctx, "n_inner", &n_inner); - int n; - for(n = 0; n < nout; n++) + int n = 0; + fclaw_context_get_int(ctx, "n", &n); + while(n < nout) { double tstart = t_curr; @@ -293,6 +301,15 @@ void outstyle_1(fclaw_global_t *glob) glob->curr_time = t_curr; iframe++; fclaw_output_frame(glob,iframe); + + /* increment n before checkpoint since we want to start at next + iteration when restarting */ + n++; + + /* save context values */ + fclaw_context_save(ctx); + /* output checkpoint */ + fclaw_output_checkpoint(glob, iframe); } } @@ -308,12 +325,15 @@ static void outstyle_3(fclaw_global_t *glob) { fclaw_domain_t** domain = &glob->domain; + /* get context object from glob, if there is none, a new one will be created */ + fclaw_context_t *ctx = fclaw_context_get(glob, "fclaw_run_outstyle3_ctx"); int init_flag = 1; fclaw_diagnostics_gather(glob,init_flag); init_flag = 0; int iframe = 0; + fclaw_context_get_int(ctx, "iframe", &iframe); fclaw_output_frame(glob,iframe); @@ -325,6 +345,7 @@ void outstyle_3(fclaw_global_t *glob) double t0 = 0; double dt_minlevel = initial_dt; + fclaw_context_get_double(ctx, "dt_minlevel", &dt_minlevel); glob->curr_time = t0; int nstep_outer = fclaw_opt->nout; int nstep_inner = fclaw_opt->nstep; @@ -348,7 +369,9 @@ void outstyle_3(fclaw_global_t *glob) } int n = 0; + fclaw_context_get_int(ctx, "n", &n); double t_curr = t0; + fclaw_context_get_double(ctx, "t_curr", &t_curr); while (n < nstep_outer) { double dt_step = dt_minlevel; @@ -441,6 +464,11 @@ void outstyle_3(fclaw_global_t *glob) iframe++; fclaw_diagnostics_gather(glob,init_flag); fclaw_output_frame(glob,iframe); + + /* save context values */ + fclaw_context_save(ctx); + /* output checkpoint */ + fclaw_output_checkpoint(glob, iframe); } } } @@ -449,9 +477,12 @@ void outstyle_3(fclaw_global_t *glob) static void outstyle_4(fclaw_global_t *glob) { + /* get context object from glob, if there is none, a new one will be created */ + fclaw_context_t *ctx = fclaw_context_get(glob, "fclaw_run_outstyle4_ctx"); /* Write out an initial time file */ int iframe = 0; + fclaw_context_get_int(ctx, "iframe", &iframe); fclaw_output_frame(glob,iframe); int init_flag = 1; @@ -466,8 +497,10 @@ void outstyle_4(fclaw_global_t *glob) double t0 = 0; double t_curr = t0; + fclaw_context_get_double(ctx, "t_curr", &t_curr); glob->curr_time = t_curr; int n = 0; + fclaw_context_get_int(ctx, "n", &n); while (n < nstep_outer) { /* Get current domain data since it may change during regrid */ @@ -504,6 +537,11 @@ void outstyle_4(fclaw_global_t *glob) fclaw_diagnostics_gather(glob,init_flag); iframe++; fclaw_output_frame(glob,iframe); + + /* save context values */ + fclaw_context_save(ctx); + /* output checkpoint */ + fclaw_output_checkpoint(glob, iframe); } } } @@ -539,4 +577,4 @@ void fclaw_run(fclaw_global_t *glob) fclaw_global_essentialf("Outstyle %d not implemented yet\n", fclaw_opt->outstyle); exit(0); } -} +} \ No newline at end of file diff --git a/src/patches/clawpatch/fclaw_clawpatch.cpp b/src/patches/clawpatch/fclaw_clawpatch.cpp index 6e5daa438..2a52820ee 100644 --- a/src/patches/clawpatch/fclaw_clawpatch.cpp +++ b/src/patches/clawpatch/fclaw_clawpatch.cpp @@ -1550,6 +1550,53 @@ void clawpatch_partition_unpack(fclaw_global_t *glob, cp->griddata.copyFromMemory((double*)unpack_data_from_here); } +/* ---------------------------- Restart ----------------------------------------------- */ + +static +int restart_num_pointers(fclaw_global_t *glob) +{ + return 1; +} + +static +void restart_pointer_sizes(fclaw_global_t *glob, + size_t sizes[]) +{ + fclaw_clawpatch_options_t* opts = fclaw_clawpatch_get_options(glob); + sizes[0] = sizeof(double)*opts->meqn; + if(opts->patch_dim == 2) + { + sizes[0] *= (opts->mx+2*opts->mbc)*(opts->my+2*opts->mbc); + } + else + { + sizes[0] *= (opts->mx+2*opts->mbc)*(opts->my+2*opts->mbc)*(opts->mz+2*opts->mbc); + } +} +static +void restart_names(fclaw_global_t *glob, + const char *names[]) +{ + names[0] = "q"; +} + +static +void *get_pointer(fclaw_global_t *glob, + fclaw_patch_t *patch, + int blockno, + int patchno, + int pointerno) +{ + if (pointerno == 0) + { + return fclaw_clawpatch_get_q(glob,patch); + } + else + { + SC_ABORT_NOT_REACHED(); + } +} + /* ------------------------------------ Virtual table -------------------------------- */ static @@ -1850,6 +1897,12 @@ void fclaw_clawpatch_vtable_initialize(fclaw_global_t* glob, patch_vt->partition_pack = clawpatch_partition_pack; patch_vt->partition_unpack = clawpatch_partition_unpack; + /* restart */ + patch_vt->checkpoint_num_pointers = restart_num_pointers; + patch_vt->checkpoint_pointer_sizes = restart_pointer_sizes; + patch_vt->checkpoint_names = restart_names; + patch_vt->checkpoint_get_pointer = get_pointer; + /* output functions */ clawpatch_vt->time_header_ascii = fclaw_clawpatch_time_header_ascii; clawpatch_vt->cb_output_ascii = cb_clawpatch_output_ascii; diff --git a/src/patches/clawpatch/fclaw_clawpatch_options.c b/src/patches/clawpatch/fclaw_clawpatch_options.c index f8254772f..b7e7862f8 100644 --- a/src/patches/clawpatch/fclaw_clawpatch_options.c +++ b/src/patches/clawpatch/fclaw_clawpatch_options.c @@ -206,59 +206,6 @@ fclaw_clawpatch_options_destroy (fclaw_clawpatch_options_t *clawpatch_opt) FCLAW_FREE(clawpatch_opt); } -static void -clawpatch_destroy_void(void *clawpatch_opt) -{ - fclaw_clawpatch_options_destroy ((fclaw_clawpatch_options_t *) clawpatch_opt); -} - -static size_t -options_packsize(void* user) -{ - return sizeof(fclaw_clawpatch_options_t); -} - -static size_t -options_pack(void* user, char* buffer) -{ - char* buffer_start = buffer; - fclaw_clawpatch_options_t* opts = (fclaw_clawpatch_options_t*) user; - - //pack entire struct - buffer += FCLAW_PACK(*opts,buffer); - - return buffer - buffer_start; -} - -static size_t -options_unpack(char* buffer, void** user) -{ - char* buffer_start = buffer; - fclaw_clawpatch_options_t** opts_ptr = (fclaw_clawpatch_options_t**) user; - - *opts_ptr = FCLAW_ALLOC(fclaw_clawpatch_options_t,1); - - buffer += FCLAW_UNPACK(buffer,*opts_ptr); - - (*opts_ptr)->kv_refinement_criteria = kv_refinement_criterea_new(); - - return buffer - buffer_start; -} - -static fclaw_packing_vtable_t packing_vt = -{ - options_pack, - options_unpack, - options_packsize, - clawpatch_destroy_void -}; - -const fclaw_packing_vtable_t* -fclaw_clawpatch_options_get_packing_vtable() -{ - return &packing_vt; -} - /* ------------------------------------------------------------------------ Generic functions - these call the functions above ------------------------------------------------------------------------ */ @@ -273,8 +220,6 @@ options_register(fclaw_app_t * a, void *optpkg, sc_options_t * opt) fclaw_clawpatch_options_t *clawpatch_opt = (fclaw_clawpatch_options_t *) optpkg; - fclaw_app_register_options_packing_vtable("clawpatch", &packing_vt); - return clawpatch_register(clawpatch_opt,opt); } diff --git a/src/patches/clawpatch/fclaw_clawpatch_options.h b/src/patches/clawpatch/fclaw_clawpatch_options.h index 845da4a8f..352d981cc 100644 --- a/src/patches/clawpatch/fclaw_clawpatch_options.h +++ b/src/patches/clawpatch/fclaw_clawpatch_options.h @@ -170,14 +170,6 @@ void fclaw_clawpatch_options_store (struct fclaw_global *glob, */ fclaw_clawpatch_options_t* fclaw_clawpatch_get_options(struct fclaw_global* glob); -/** - * @brief Get the packing vtable for fclaw_clawpatch_options_t - * - * @return const fclaw_packing_vtable_t* the vtable - */ -const fclaw_packing_vtable_t* fclaw_clawpatch_options_get_packing_vtable(); - - #ifdef __cplusplus #if 0 { /* need this because indent is dumb */ diff --git a/src/patches/clawpatch/fclaw_clawpatch_options.h.TEST.cpp b/src/patches/clawpatch/fclaw_clawpatch_options.h.TEST.cpp index c27561d8d..38854c35f 100644 --- a/src/patches/clawpatch/fclaw_clawpatch_options.h.TEST.cpp +++ b/src/patches/clawpatch/fclaw_clawpatch_options.h.TEST.cpp @@ -107,94 +107,3 @@ TEST_CASE("fclaw_clawpatch_options_store fails if called twice on a glob") } #endif -TEST_CASE("2d fclaw_clawpatch_options packing/unpacking") -{ - fclaw_clawpatch_options_t* opts = fclaw_clawpatch_options_new(2); - opts->mx = 5; - opts->my = 6; - opts->maux = 4; - opts->mbc = 3; - opts->meqn = 32; - opts->rhs_fields = 39; - opts->refinement_criteria = 1; - opts->interp_stencil_width = 3; - opts->ghost_patch_pack_aux = 7; - opts->save_aux = 1; - opts->is_registered = 1; - - const fclaw_packing_vtable_t* vt = fclaw_clawpatch_options_get_packing_vtable(); - - size_t size = vt->size(opts); - char buffer[size]; - size_t bytes_written = vt->pack(opts,buffer); - REQUIRE_EQ(bytes_written,size); - - fclaw_clawpatch_options_t* output_opts = nullptr; - size_t bytes_read = vt->unpack(buffer,(void**)&output_opts); - - REQUIRE_EQ(bytes_read,size); - REQUIRE_NE(output_opts,nullptr); - - CHECK_EQ(output_opts->patch_dim,2); - CHECK_EQ(output_opts->mx,opts->mx); - CHECK_EQ(output_opts->my,opts->my); - CHECK_EQ(output_opts->maux,opts->maux); - CHECK_EQ(output_opts->mbc,opts->mbc); - CHECK_EQ(output_opts->meqn,opts->meqn); - CHECK_EQ(output_opts->rhs_fields,opts->rhs_fields); - CHECK_EQ(output_opts->refinement_criteria,opts->refinement_criteria); - CHECK_EQ(output_opts->interp_stencil_width,opts->interp_stencil_width); - CHECK_EQ(output_opts->ghost_patch_pack_aux,opts->ghost_patch_pack_aux); - CHECK_EQ(output_opts->save_aux,opts->save_aux); - CHECK_EQ(output_opts->is_registered,opts->is_registered); - - vt->destroy(output_opts); - fclaw_clawpatch_options_destroy(opts); -} - -TEST_CASE("3d fclaw_clawpatch_options packing/unpacking") -{ - fclaw_clawpatch_options_t* opts = fclaw_clawpatch_options_new(3); - opts->mx = 5; - opts->my = 6; - opts->mz = 3; - opts->maux = 4; - opts->mbc = 3; - opts->meqn = 32; - opts->rhs_fields = 39; - opts->refinement_criteria = 1; - opts->interp_stencil_width = 3; - opts->ghost_patch_pack_aux = 7; - opts->save_aux = 1; - opts->is_registered = 1; - - const fclaw_packing_vtable_t* vt = fclaw_clawpatch_options_get_packing_vtable(); - - size_t size = vt->size(opts); - char buffer[size]; - size_t bytes_written = vt->pack(opts,buffer); - REQUIRE_EQ(bytes_written,size); - - fclaw_clawpatch_options_t* output_opts = nullptr; - size_t bytes_read = vt->unpack(buffer,(void**)&output_opts); - - REQUIRE_EQ(bytes_read,size); - REQUIRE_NE(output_opts,nullptr); - - CHECK_EQ(output_opts->patch_dim,3); - CHECK_EQ(output_opts->mx,opts->mx); - CHECK_EQ(output_opts->my,opts->my); - CHECK_EQ(output_opts->mz,opts->mz); - CHECK_EQ(output_opts->maux,opts->maux); - CHECK_EQ(output_opts->mbc,opts->mbc); - CHECK_EQ(output_opts->meqn,opts->meqn); - CHECK_EQ(output_opts->rhs_fields,opts->rhs_fields); - CHECK_EQ(output_opts->refinement_criteria,opts->refinement_criteria); - CHECK_EQ(output_opts->interp_stencil_width,opts->interp_stencil_width); - CHECK_EQ(output_opts->ghost_patch_pack_aux,opts->ghost_patch_pack_aux); - CHECK_EQ(output_opts->save_aux,opts->save_aux); - CHECK_EQ(output_opts->is_registered,opts->is_registered); - - vt->destroy(output_opts); - fclaw_clawpatch_options_destroy(opts); -} \ No newline at end of file diff --git a/src/solvers/fc2d_clawpack4.6/fc2d_clawpack46_options.c b/src/solvers/fc2d_clawpack4.6/fc2d_clawpack46_options.c index 0d5112e47..f95b09953 100644 --- a/src/solvers/fc2d_clawpack4.6/fc2d_clawpack46_options.c +++ b/src/solvers/fc2d_clawpack4.6/fc2d_clawpack46_options.c @@ -132,104 +132,6 @@ void clawpack46_destroy (fc2d_clawpack46_options_t * clawopt) FCLAW_FREE (clawopt); } -static void clawpack46_destroy_void(void* user) -{ - fc2d_clawpack46_options_t* clawopt = (fc2d_clawpack46_options_t*) user; - clawpack46_destroy(clawopt); -} - -static size_t -options_packsize(void* user) -{ - fc2d_clawpack46_options_t* opts = (fc2d_clawpack46_options_t*) user; - - size_t size = sizeof(fc2d_clawpack46_options_t); - size += fclaw_packsize_string(opts->order_string); - size += 2*sizeof(int); /* order */ - size += opts->mwaves*sizeof(int); /* mthlim */ - size += fclaw_packsize_string(opts->mthlim_string); - size += 4*sizeof(int); /* mthbc */ - size += fclaw_packsize_string(opts->mthbc_string); - - return size; -} - -static size_t -options_pack(void* user, char* buffer) -{ - char* buffer_start = buffer; - - fc2d_clawpack46_options_t* opts = (fc2d_clawpack46_options_t*) user; - - //pack entire struct - buffer += FCLAW_PACK(*opts, buffer); - - //append arrays to buffer - buffer += fclaw_pack_string(opts->order_string,buffer); - buffer += fclaw_pack_int(opts->order[0],buffer); - buffer += fclaw_pack_int(opts->order[1],buffer); - for(size_t i = 0; i < opts->mwaves; i++) - { - buffer += fclaw_pack_int(opts->mthlim[i],buffer); - } - buffer += fclaw_pack_string(opts->mthlim_string,buffer); - for(size_t i = 0; i < 4; i++) - { - buffer += fclaw_pack_int(opts->mthbc[i],buffer); - } - buffer += fclaw_pack_string(opts->mthbc_string,buffer); - - return buffer-buffer_start; -} - -static size_t -options_unpack(char* buffer, void** user) -{ - char* buffer_start = buffer; - - fc2d_clawpack46_options_t** opts_ptr = (fc2d_clawpack46_options_t**) user; - *opts_ptr = FCLAW_ALLOC(fc2d_clawpack46_options_t,1); - fc2d_clawpack46_options_t* opts = *opts_ptr; - - buffer += FCLAW_UNPACK(buffer, opts); - - //unpack arrays - buffer += fclaw_unpack_string(buffer,(char**) &opts->order_string); - opts->order = FCLAW_ALLOC(int,2); - buffer += fclaw_unpack_int(buffer,&opts->order[0]); - buffer += fclaw_unpack_int(buffer,&opts->order[1]); - opts->mthlim = FCLAW_ALLOC(int,opts->mwaves); - for(size_t i = 0; i < opts->mwaves; i++) - { - buffer += fclaw_unpack_int(buffer,&opts->mthlim[i]); - } - buffer += fclaw_unpack_string(buffer,(char**) &opts->mthlim_string); - opts->mthbc = FCLAW_ALLOC(int,4); - for(size_t i = 0; i < 4; i++) - { - buffer += fclaw_unpack_int(buffer,&opts->mthbc[i]); - } - buffer += fclaw_unpack_string(buffer,(char**) &opts->mthbc_string); - - opts->is_unpacked = 1; - - return buffer-buffer_start; -} - -static fclaw_packing_vtable_t packing_vt = -{ - options_pack, - options_unpack, - options_packsize, - clawpack46_destroy_void -}; - -const fclaw_packing_vtable_t* -fc2d_clawpack46_options_get_packing_vtable() -{ - return &packing_vt; -} - /* ------------------------------------------------------ Generic calls to options handling; each calls clawpack-specific options call back @@ -309,8 +211,6 @@ fc2d_clawpack46_options_t* fc2d_clawpack46_options_register (fclaw_app_t * app, const char *section, const char *configfile) { - fclaw_app_register_options_packing_vtable("fc2d_clawpack46", &packing_vt); - fc2d_clawpack46_options_t *clawopt; FCLAW_ASSERT (app != NULL); diff --git a/src/solvers/fc2d_clawpack4.6/fc2d_clawpack46_options.h b/src/solvers/fc2d_clawpack4.6/fc2d_clawpack46_options.h index 5bfaf4802..1b0cfb071 100644 --- a/src/solvers/fc2d_clawpack4.6/fc2d_clawpack46_options.h +++ b/src/solvers/fc2d_clawpack4.6/fc2d_clawpack46_options.h @@ -94,13 +94,6 @@ void fc2d_clawpack46_options_store (struct fclaw_global* glob, fc2d_clawpack46_o void fc2d_clawpack46_output(struct fclaw_global *glob, int iframe); -/** - * @brief Get the packing vtable for fc2d_clawpack46_options_t - * - * @return const fclaw_packing_vtable_t* the vtable - */ -const fclaw_packing_vtable_t* fc2d_clawpack46_options_get_packing_vtable(); - #ifdef __cplusplus #if 0 { diff --git a/src/solvers/fc2d_clawpack4.6/fc2d_clawpack46_options.h.TEST.cpp b/src/solvers/fc2d_clawpack4.6/fc2d_clawpack46_options.h.TEST.cpp index 5df6e1001..06376b40f 100644 --- a/src/solvers/fc2d_clawpack4.6/fc2d_clawpack46_options.h.TEST.cpp +++ b/src/solvers/fc2d_clawpack4.6/fc2d_clawpack46_options.h.TEST.cpp @@ -83,80 +83,4 @@ TEST_CASE("fc2d_clawpack46_options_store fails if called twice on a glob") fclaw_global_destroy(glob2); } -TEST_CASE("fc2d_clawpack46_options packing/unpacking") -{ - fc2d_clawpack46_options_t* opts = FCLAW_ALLOC_ZERO(fc2d_clawpack46_options_t,1); - opts->mwaves = 5; - opts->order_string = "[2 2]"; - int order[] = {2,2}; - opts->order = order; - int mthlim[] = {5,4,3,2,1}; - opts->mthlim = mthlim; - opts->mthlim_string = "[5 4 3 2 1]"; - int mthbc[] = {0, 1, 1, 1}; - opts->mthbc = mthbc; - opts->mthbc_string = "[0 1 1 1]"; - - int method[] = {0,4,3,2,5,6,99}; - for(size_t i = 0; i < 7; ++i) - opts->method[i] = method[i]; - - opts->mcapa = 3; - opts->src_term = 2; - opts->use_fwaves = 1; - - opts->ascii_out = 2; - opts->vtk_out = 3; - - opts->is_registered = 1; - - opts->is_unpacked = 0; - - const fclaw_packing_vtable_t* vt = fc2d_clawpack46_options_get_packing_vtable(); - - size_t size = vt->size(opts); - char buffer[size]; - size_t bytes_written = vt->pack(opts,buffer); - REQUIRE_EQ(bytes_written,size); - - fc2d_clawpack46_options_t* output_opts = nullptr; - size_t bytes_read = vt->unpack(buffer,(void**)&output_opts); - - REQUIRE_EQ(bytes_read,size); - REQUIRE_NE(output_opts,nullptr); - - CHECK_EQ(output_opts->mwaves, opts->mwaves); - - CHECK_NE(output_opts->order_string, opts->order_string); - CHECK_UNARY(!strcmp(output_opts->order_string, opts->order_string)); - - CHECK_EQ(output_opts->order[0], opts->order[0]); - CHECK_EQ(output_opts->order[1], opts->order[1]); - - for(size_t i = 0; i < 5; ++i) - CHECK_EQ(output_opts->mthlim[i], opts->mthlim[i]); - - CHECK_NE(output_opts->mthlim_string, opts->mthlim_string); - CHECK_UNARY(!strcmp(output_opts->mthlim_string, opts->mthlim_string)); - - for(size_t i = 0; i < 4; ++i) - CHECK_EQ(output_opts->mthbc[i], opts->mthbc[i]); - - CHECK_NE(output_opts->mthbc_string, opts->mthbc_string); - CHECK_UNARY(!strcmp(output_opts->mthbc_string, opts->mthbc_string)); - - for(size_t i = 0; i < 7; ++i) - CHECK_EQ(output_opts->method[i], opts->method[i]); - - CHECK_EQ(output_opts->mcapa, opts->mcapa); - CHECK_EQ(output_opts->src_term, opts->src_term); - CHECK_EQ(output_opts->use_fwaves, opts->use_fwaves); - CHECK_EQ(output_opts->ascii_out, opts->ascii_out); - CHECK_EQ(output_opts->vtk_out, opts->vtk_out); - CHECK_EQ(output_opts->is_registered, opts->is_registered); - CHECK_UNARY(output_opts->is_unpacked); - - vt->destroy(output_opts); - FCLAW_FREE(opts); -} #endif \ No newline at end of file diff --git a/src/solvers/fc2d_clawpack5/fc2d_clawpack5_options.c b/src/solvers/fc2d_clawpack5/fc2d_clawpack5_options.c index 784ae770b..658d4ea28 100644 --- a/src/solvers/fc2d_clawpack5/fc2d_clawpack5_options.c +++ b/src/solvers/fc2d_clawpack5/fc2d_clawpack5_options.c @@ -125,105 +125,6 @@ clawpack5_destroy (fc2d_clawpack5_options_t * clawopt) FCLAW_FREE (clawopt); } -static void clawpack5_destroy_void(void* user) -{ - fc2d_clawpack5_options_t* clawopt = (fc2d_clawpack5_options_t*) user; - clawpack5_destroy(clawopt); -} - -static size_t -options_packsize(void* user) -{ - fc2d_clawpack5_options_t* opts = (fc2d_clawpack5_options_t*) user; - - size_t size = sizeof(fc2d_clawpack5_options_t); - size += fclaw_packsize_string(opts->order_string); - size += 2*sizeof(int); /* order */ - size += opts->mwaves*sizeof(int); /* mthlim */ - size += fclaw_packsize_string(opts->mthlim_string); - size += 4*sizeof(int); /* mthbc */ - size += fclaw_packsize_string(opts->mthbc_string); - - return size; -} - -static size_t -options_pack(void* user, char* buffer) -{ - char* buffer_start = buffer; - - fc2d_clawpack5_options_t* opts = (fc2d_clawpack5_options_t*) user; - - //pack entire struct - buffer += FCLAW_PACK(*opts, buffer); - - //append arrays to buffer - buffer += fclaw_pack_string(opts->order_string,buffer); - buffer += fclaw_pack_int(opts->order[0],buffer); - buffer += fclaw_pack_int(opts->order[1],buffer); - for(size_t i = 0; i < opts->mwaves; i++) - { - buffer += fclaw_pack_int(opts->mthlim[i],buffer); - } - buffer += fclaw_pack_string(opts->mthlim_string,buffer); - for(size_t i = 0; i < 4; i++) - { - buffer += fclaw_pack_int(opts->mthbc[i],buffer); - } - buffer += fclaw_pack_string(opts->mthbc_string,buffer); - - return buffer-buffer_start; -} - -static size_t -options_unpack(char* buffer, void** user) -{ - char* buffer_start = buffer; - - fc2d_clawpack5_options_t** opts_ptr = (fc2d_clawpack5_options_t**) user; - *opts_ptr = FCLAW_ALLOC(fc2d_clawpack5_options_t,1); - fc2d_clawpack5_options_t* opts = *opts_ptr; - - buffer += FCLAW_UNPACK(buffer, opts); - - //unpack arrays - buffer += fclaw_unpack_string(buffer,(char**) &opts->order_string); - opts->order = FCLAW_ALLOC(int,2); - buffer += fclaw_unpack_int(buffer,&opts->order[0]); - buffer += fclaw_unpack_int(buffer,&opts->order[1]); - opts->mthlim = FCLAW_ALLOC(int,opts->mwaves); - for(size_t i = 0; i < opts->mwaves; i++) - { - buffer += fclaw_unpack_int(buffer,&opts->mthlim[i]); - } - buffer += fclaw_unpack_string(buffer,(char**) &opts->mthlim_string); - opts->mthbc = FCLAW_ALLOC(int,4); - for(size_t i = 0; i < 4; i++) - { - buffer += fclaw_unpack_int(buffer,&opts->mthbc[i]); - } - buffer += fclaw_unpack_string(buffer,(char**) &opts->mthbc_string); - - opts->is_unpacked = 1; - - return buffer-buffer_start; -} - -static fclaw_packing_vtable_t packing_vt = -{ - options_pack, - options_unpack, - options_packsize, - clawpack5_destroy_void -}; - -const fclaw_packing_vtable_t* -fc2d_clawpack5_options_get_packing_vtable() -{ - return &packing_vt; -} - - /* ------------------------------------------------------------------- Functions below are part of the options vtable; no need to change these They call functions above @@ -231,8 +132,6 @@ fc2d_clawpack5_options_get_packing_vtable() static void* options_register (fclaw_app_t * app, void *package, sc_options_t * opt) { - fclaw_app_register_options_packing_vtable("fc2d_clawpack5", &packing_vt); - fc2d_clawpack5_options_t *clawopt; FCLAW_ASSERT (app != NULL); diff --git a/src/solvers/fc2d_clawpack5/fc2d_clawpack5_options.h b/src/solvers/fc2d_clawpack5/fc2d_clawpack5_options.h index d066c688e..64bf17390 100644 --- a/src/solvers/fc2d_clawpack5/fc2d_clawpack5_options.h +++ b/src/solvers/fc2d_clawpack5/fc2d_clawpack5_options.h @@ -94,13 +94,6 @@ void CLAWPACK5_SET_AMR_MODULE(const int* mwaves_in, const int* mcapa_in, const int mthlim_in[], const int method_in[], const int *use_fwaves); -/** - * @brief Get the packing vtable for fc2d_clawpack5_options_t - * - * @return const fclaw_packing_vtable_t* the vtable - */ -const fclaw_packing_vtable_t* fc2d_clawpack5_options_get_packing_vtable(); - #ifdef __cplusplus #if 0 { diff --git a/src/solvers/fc2d_clawpack5/fc2d_clawpack5_options.h.TEST.cpp b/src/solvers/fc2d_clawpack5/fc2d_clawpack5_options.h.TEST.cpp index 6d32ff140..0ebf78b11 100644 --- a/src/solvers/fc2d_clawpack5/fc2d_clawpack5_options.h.TEST.cpp +++ b/src/solvers/fc2d_clawpack5/fc2d_clawpack5_options.h.TEST.cpp @@ -83,80 +83,4 @@ TEST_CASE("fc2d_clawpack5_options_store fails if called twice on a glob") fclaw_global_destroy(glob2); } -TEST_CASE("fc2d_clawpack5_options packing/unpacking") -{ - fc2d_clawpack5_options_t* opts = FCLAW_ALLOC_ZERO(fc2d_clawpack5_options_t,1); - opts->mwaves = 5; - opts->order_string = "[2 2]"; - int order[] = {2,2}; - opts->order = order; - int mthlim[] = {5,4,3,2,1}; - opts->mthlim = mthlim; - opts->mthlim_string = "[5 4 3 2 1]"; - int mthbc[] = {0, 1, 1, 1}; - opts->mthbc = mthbc; - opts->mthbc_string = "[0 1 1 1]"; - - int method[] = {0,4,3,2,5,6,99}; - for(size_t i = 0; i < 7; ++i) - opts->method[i] = method[i]; - - opts->mcapa = 3; - opts->src_term = 2; - opts->use_fwaves = 1; - - opts->ascii_out = 2; - opts->vtk_out = 3; - - opts->is_registered = 1; - - opts->is_unpacked = 0; - - const fclaw_packing_vtable_t* vt = fc2d_clawpack5_options_get_packing_vtable(); - - size_t size = vt->size(opts); - char buffer[size]; - size_t bytes_written = vt->pack(opts,buffer); - REQUIRE_EQ(bytes_written,size); - - fc2d_clawpack5_options_t* output_opts = nullptr; - size_t bytes_read = vt->unpack(buffer,(void**)&output_opts); - - REQUIRE_EQ(bytes_read,size); - REQUIRE_NE(output_opts,nullptr); - - CHECK_EQ(output_opts->mwaves, opts->mwaves); - - CHECK_NE(output_opts->order_string, opts->order_string); - CHECK_UNARY(!strcmp(output_opts->order_string, opts->order_string)); - - CHECK_EQ(output_opts->order[0], opts->order[0]); - CHECK_EQ(output_opts->order[1], opts->order[1]); - - for(size_t i = 0; i < 5; ++i) - CHECK_EQ(output_opts->mthlim[i], opts->mthlim[i]); - - CHECK_NE(output_opts->mthlim_string, opts->mthlim_string); - CHECK_UNARY(!strcmp(output_opts->mthlim_string, opts->mthlim_string)); - - for(size_t i = 0; i < 4; ++i) - CHECK_EQ(output_opts->mthbc[i], opts->mthbc[i]); - - CHECK_NE(output_opts->mthbc_string, opts->mthbc_string); - CHECK_UNARY(!strcmp(output_opts->mthbc_string, opts->mthbc_string)); - - for(size_t i = 0; i < 7; ++i) - CHECK_EQ(output_opts->method[i], opts->method[i]); - - CHECK_EQ(output_opts->mcapa, opts->mcapa); - CHECK_EQ(output_opts->src_term, opts->src_term); - CHECK_EQ(output_opts->use_fwaves, opts->use_fwaves); - CHECK_EQ(output_opts->ascii_out, opts->ascii_out); - CHECK_EQ(output_opts->vtk_out, opts->vtk_out); - CHECK_EQ(output_opts->is_registered, opts->is_registered); - CHECK_UNARY(output_opts->is_unpacked); - - vt->destroy(output_opts); - FCLAW_FREE(opts); -} #endif \ No newline at end of file diff --git a/test/test.hpp b/test/test.hpp index 20f6ad870..c54e36bb9 100644 --- a/test/test.hpp +++ b/test/test.hpp @@ -2,6 +2,7 @@ #define FCLAW_TEST_HPP #include #include +#include bool test_output_vtk();