commit 8cd65b39870900e06ef77c25af924e29ecc4f5fa parent f980c7743b18510d20cf926bbc539e84816d9d2d Author: Vincent Forest <vincent.forest@meso-star.com> Date: Thu, 17 Sep 2020 13:32:56 +0200 Merge branch 'feature_green_function_write' into develop Diffstat:
34 files changed, 917 insertions(+), 106 deletions(-)
diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt @@ -34,7 +34,7 @@ find_package(Star3D 0.7 REQUIRED) find_package(StarSP 0.8 REQUIRED) find_package(StarEnc2D 0.5 REQUIRED) find_package(StarEnc3D 0.5 REQUIRED) -find_package(RSys 0.8.1 REQUIRED) +find_package(RSys 0.10 REQUIRED) find_package(OpenMP 2.0 REQUIRED) set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${RCMAKE_SOURCE_DIR}) diff --git a/src/sdis.h b/src/sdis.h @@ -116,7 +116,7 @@ static const struct sdis_interface_fragment SDIS_INTERFACE_FRAGMENT_NULL = enum sdis_estimator_type { SDIS_ESTIMATOR_TEMPERATURE, /* In Kelvin */ SDIS_ESTIMATOR_FLUX, /* In Watt/m^2 */ - SDIS_ESTIMATOR_MEAN_POWER, /* In Watt */ + SDIS_ESTIMATOR_POWER, /* In Watt */ SDIS_ESTIMATOR_TYPES_COUNT__ }; @@ -503,22 +503,22 @@ struct sdis_solve_camera_args { static const struct sdis_solve_camera_args SDIS_SOLVE_CAMERA_ARGS_DEFAULT = SDIS_SOLVE_CAMERA_ARGS_DEFAULT__; -struct sdis_compute_mean_power_args { +struct sdis_compute_power_args { size_t nrealisations; struct sdis_medium* medium; /* Medium to solve */ double time_range[2]; /* Observation time */ double fp_to_meter; /* Scale from floating point units to meters */ struct ssp_rng* rng_state; /* Initial RNG state. May be NULL */ }; -#define SDIS_COMPUTE_MEAN_POWER_ARGS_DEFAULT__ { \ +#define SDIS_COMPUTE_POWER_ARGS_DEFAULT__ { \ 10000, /* #realisations */ \ NULL, /* Medium */ \ {DBL_MAX,DBL_MAX}, /* Time range */ \ 1, /* FP to meter */ \ NULL /* RNG state */ \ } -static const struct sdis_compute_mean_power_args -SDIS_COMPUTE_MEAN_POWER_ARGS_DEFAULT = SDIS_COMPUTE_MEAN_POWER_ARGS_DEFAULT__; +static const struct sdis_compute_power_args +SDIS_COMPUTE_POWER_ARGS_DEFAULT = SDIS_COMPUTE_POWER_ARGS_DEFAULT__; BEGIN_DECLS @@ -945,9 +945,9 @@ sdis_estimator_get_total_flux struct sdis_mc* flux); SDIS_API res_T -sdis_estimator_get_mean_power +sdis_estimator_get_power (const struct sdis_estimator* estimator, - struct sdis_mc* mean_power); + struct sdis_mc* power); SDIS_API res_T sdis_estimator_get_paths_count @@ -991,6 +991,17 @@ sdis_green_function_solve const double time_range[2], /* Observation time */ struct sdis_estimator** estimator); +SDIS_API res_T +sdis_green_function_write + (struct sdis_green_function* green, + FILE* stream); + +SDIS_API res_T +sdis_green_function_create_from_stream + (struct sdis_scene* scn, /* Scene from which the green was evaluated */ + FILE* stream, /* Stream into which the green was serialized */ + struct sdis_green_function** green); + /* Retrieve the number of valid paths used to estimate the green function. It * is actually equal to the number of successful realisations. */ SDIS_API res_T @@ -1122,12 +1133,12 @@ sdis_solve_medium struct sdis_estimator** estimator); /* P = SUM(volumic_power(x)) / Nrealisations * Volume - * mean power (in Watt) = time_range[0] == time_range[1] + * power (in Watt) = time_range[0] == time_range[1] * ? P : P / (time_range[1] - time_range[0]) */ SDIS_API res_T -sdis_compute_mean_power +sdis_compute_power (struct sdis_scene* scn, - const struct sdis_compute_mean_power_args* args, + const struct sdis_compute_power_args* args, struct sdis_estimator** estimator); /******************************************************************************* diff --git a/src/sdis_device_c.h b/src/sdis_device_c.h @@ -27,7 +27,7 @@ struct ssp_rng; struct ssp_rng_proxy; -struct name { FITEM; }; +struct name { FITEM; void* mem; }; #define FITEM_TYPE name #include <rsys/free_list.h> diff --git a/src/sdis_estimator.c b/src/sdis_estimator.c @@ -98,7 +98,10 @@ res_T sdis_estimator_get_temperature (const struct sdis_estimator* estimator, struct sdis_mc* mc) { - if(!estimator || !mc) return RES_BAD_ARG; + if(!estimator || !mc + || ( estimator->type != SDIS_ESTIMATOR_TEMPERATURE + && estimator->type != SDIS_ESTIMATOR_FLUX)) + return RES_BAD_ARG; SETUP_MC(mc, &estimator->temperature); return RES_OK; } @@ -116,7 +119,7 @@ res_T sdis_estimator_get_convective_flux (const struct sdis_estimator* estimator, struct sdis_mc* flux) { - if(!estimator || !flux ||estimator->type != SDIS_ESTIMATOR_FLUX) + if(!estimator || !flux || estimator->type != SDIS_ESTIMATOR_FLUX) return RES_BAD_ARG; SETUP_MC(flux, &estimator->fluxes[FLUX_CONVECTIVE]); return RES_OK; @@ -143,18 +146,18 @@ sdis_estimator_get_total_flux } res_T -sdis_estimator_get_mean_power - (const struct sdis_estimator* estimator, struct sdis_mc* mean_power) +sdis_estimator_get_power + (const struct sdis_estimator* estimator, struct sdis_mc* power) { - if(!estimator || !mean_power || estimator->type != SDIS_ESTIMATOR_MEAN_POWER) + if(!estimator || !power || estimator->type != SDIS_ESTIMATOR_POWER) return RES_BAD_ARG; - SETUP_MC(mean_power, &estimator->mean_power.power); - mean_power->E *= estimator->mean_power.spread; + SETUP_MC(power, &estimator->power.power); + power->E *= estimator->power.spread; - if(estimator->mean_power.time_range[0] - != estimator->mean_power.time_range[1]) { - mean_power->E /= /* From Joule to Watt */ - (estimator->mean_power.time_range[1]-estimator->mean_power.time_range[0]); + if(estimator->power.time_range[0] + != estimator->power.time_range[1]) { + power->E /= /* From Joule to Watt */ + (estimator->power.time_range[1]-estimator->power.time_range[0]); } return RES_OK; } diff --git a/src/sdis_estimator_c.h b/src/sdis_estimator_c.h @@ -44,7 +44,7 @@ struct sdis_estimator { struct accum power; double spread; double time_range[2]; - } mean_power; + } power; size_t nrealisations; /* #successes */ size_t nfailures; @@ -105,7 +105,7 @@ estimator_setup_temperature } static INLINE void -estimator_setup_mean_power +estimator_setup_power (struct sdis_estimator* estim, const double sum, const double sum2, @@ -113,12 +113,12 @@ estimator_setup_mean_power const double time_range[2]) { ASSERT(estim && estim->nrealisations && time_range); - estim->mean_power.power.sum = sum; - estim->mean_power.power.sum2 = sum2; - estim->mean_power.power.count = estim->nrealisations; - estim->mean_power.spread = spread; - estim->mean_power.time_range[0] = time_range[0]; - estim->mean_power.time_range[1] = time_range[1]; + estim->power.power.sum = sum; + estim->power.power.sum2 = sum2; + estim->power.power.count = estim->nrealisations; + estim->power.spread = spread; + estim->power.time_range[0] = time_range[0]; + estim->power.time_range[1] = time_range[1]; } static INLINE void diff --git a/src/sdis_green.c b/src/sdis_green.c @@ -16,10 +16,11 @@ #include "sdis_device_c.h" #include "sdis_estimator_c.h" #include "sdis_green.h" +#include "sdis_interface_c.h" #include "sdis_log.h" #include "sdis_medium_c.h" #include "sdis_misc.h" -#include "sdis_interface_c.h" +#include "sdis_scene_c.h" #include <star/ssp.h> @@ -98,6 +99,7 @@ green_path_init(struct mem_allocator* allocator, struct green_path* path) darray_flux_term_init(allocator, &path->flux_terms); darray_power_term_init(allocator, &path->power_terms); path->limit.vertex = SDIS_RWALK_VERTEX_NULL; + path->limit.fragment = SDIS_INTERFACE_FRAGMENT_NULL; path->limit_id = UINT_MAX; path->limit_type = SDIS_POINT_NONE; path->ilast_medium = UINT16_MAX; @@ -164,6 +166,96 @@ green_path_copy_and_release(struct green_path* dst, struct green_path* src) return RES_OK; } +static res_T +green_path_write(const struct green_path* path, FILE* stream) +{ + size_t sz = 0; + res_T res = RES_OK; + ASSERT(path && stream); + + #define WRITE(Var, N) { \ + if(fwrite((Var), sizeof(*(Var)), (N), stream) != (N)) { \ + res = RES_IO_ERR; \ + goto error; \ + } \ + } (void)0 + + /* Write the list of flux terms */ + sz = darray_flux_term_size_get(&path->flux_terms); + WRITE(&sz, 1); + WRITE(darray_flux_term_cdata_get(&path->flux_terms), sz); + + /* Write the list of power terms */ + sz = darray_power_term_size_get(&path->power_terms); + WRITE(&sz, 1); + WRITE(darray_power_term_cdata_get(&path->power_terms), sz); + + /* Write the limit point */ + WRITE(&path->limit, 1); + WRITE(&path->limit_id, 1); + WRITE(&path->limit_type, 1); + + /* Write miscellaneous data */ + WRITE(&path->ilast_medium, 1); + WRITE(&path->ilast_interf, 1); + + #undef WRITE + +exit: + return res; +error: + goto exit; +} + +static res_T +green_path_read(struct green_path* path, FILE* stream) +{ + size_t sz = 0; + res_T res = RES_OK; + ASSERT(path && stream); + + #define READ(Var, N) { \ + if(fread((Var), sizeof(*(Var)), (N), stream) != (N)) { \ + if(feof(stream)) { \ + res = RES_BAD_ARG; \ + } else if(ferror(stream)) { \ + res = RES_IO_ERR; \ + } else { \ + res = RES_UNKNOWN_ERR; \ + } \ + goto error; \ + } \ + } (void)0 + + /* Read the list of flux terms */ + READ(&sz, 1); + res = darray_flux_term_resize(&path->flux_terms, sz); + if(res != RES_OK) goto error; + READ(darray_flux_term_data_get(&path->flux_terms), sz); + + /* Read the list of power tems */ + READ(&sz, 1); + res = darray_power_term_resize(&path->power_terms, sz); + if(res != RES_OK) goto error; + READ(darray_power_term_data_get(&path->power_terms), sz); + + /* Read the limit point */ + READ(&path->limit, 1); + READ(&path->limit_id, 1); + READ(&path->limit_type, 1); + + /* Read the miscellaneous data */ + READ(&path->ilast_medium, 1); + READ(&path->ilast_interf, 1); + + #undef READ + +exit: + return res; +error: + goto exit; +} + /* Generate the dynamic array of green paths */ #define DARRAY_NAME green_path #define DARRAY_DATA struct green_path @@ -199,12 +291,44 @@ struct sdis_green_function { FILE* rng_state; ref_T ref; - struct sdis_device* dev; + struct sdis_scene* scn; }; /******************************************************************************* * Helper functions ******************************************************************************/ +enum rng_type { + RNG_KISS, + RNG_MT_19937_64, + RNG_RANLUX48, + RNG_THREEFRY, + RNG_UNKNOWN +}; + +static INLINE enum rng_type +get_rng_type_enum(const struct ssp_rng_type* type) +{ + ASSERT(type); + if(ssp_rng_type_eq(type, &ssp_rng_kiss)) return RNG_KISS; + if(ssp_rng_type_eq(type, &ssp_rng_mt19937_64)) return RNG_MT_19937_64; + if(ssp_rng_type_eq(type, &ssp_rng_ranlux48)) return RNG_RANLUX48; + if(ssp_rng_type_eq(type, &ssp_rng_threefry)) return RNG_THREEFRY; + return RNG_UNKNOWN; +} + +static INLINE void +get_rng_type_ssp(const enum rng_type type, struct ssp_rng_type* ssp_type) +{ + switch(type) { + case RNG_KISS: *ssp_type = ssp_rng_kiss; break; + case RNG_MT_19937_64: *ssp_type = ssp_rng_mt19937_64; break; + case RNG_RANLUX48: *ssp_type = ssp_rng_ranlux48; break; + case RNG_THREEFRY: *ssp_type = ssp_rng_threefry; break; + case RNG_UNKNOWN: memset(ssp_type, 0, sizeof(*ssp_type)); break; + default: FATAL("Unreachable code.\n"); break; + } +} + static res_T ensure_medium_registration (struct sdis_green_function* green, @@ -338,7 +462,7 @@ green_function_solve_path if(time_curr <= 0 || (path->limit_type == SDIS_VERTEX && time_curr <= medium_get_t0(medium))) { - log_err(green->dev, + log_err(green->scn->dev, "%s: invalid observation time \"%g\": the initial condition is reached " "while instationary system are not supported by the green function.\n", FUNC_NAME, time); @@ -370,6 +494,280 @@ error: goto exit; } +static res_T +write_media(struct sdis_green_function* green, FILE* stream) +{ + struct htable_medium_iterator it, it_end; + size_t nmedia = 0; + res_T res = RES_OK; + ASSERT(green && stream); + + #define WRITE(Var) { \ + if(fwrite((Var), sizeof(*(Var)), 1, stream) != 1) { \ + res = RES_IO_ERR; \ + goto error; \ + } \ + } (void)0 + + nmedia = htable_medium_size_get(&green->media); + WRITE(&nmedia); + + htable_medium_begin(&green->media, &it); + htable_medium_end(&green->media, &it_end); + while(!htable_medium_iterator_eq(&it, &it_end)) { + const struct sdis_medium* mdm = *htable_medium_iterator_data_get(&it); + htable_medium_iterator_next(&it); + WRITE(&mdm->id); + WRITE(&mdm->type); + } + + #undef WRITE + +exit: + return res; +error: + goto exit; +} + +static res_T +read_media(struct sdis_green_function* green, FILE* stream) +{ + size_t nmedia = 0; + size_t imedium = 0; + res_T res = RES_OK; + ASSERT(green && stream); + + #define READ(Var) { \ + if(fread((Var), sizeof(*(Var)), 1, stream) != 1) { \ + if(feof(stream)) { \ + res = RES_BAD_ARG; \ + } else if(ferror(stream)) { \ + res = RES_IO_ERR; \ + } else { \ + res = RES_UNKNOWN_ERR; \ + } \ + goto error; \ + } \ + } (void)0 + + READ(&nmedia); + FOR_EACH(imedium, 0, nmedia) { + struct name* name = NULL; + struct sdis_medium* mdm = NULL; + struct fid id; + enum sdis_medium_type mdm_type; + + READ(&id); + READ(&mdm_type); + + name = flist_name_get(&green->scn->dev->media_names, id); + if(!name) { + log_err(green->scn->dev, "%s: a Stardis medium is missing.\n", + FUNC_NAME); + res = RES_BAD_ARG; + goto error; + } + + mdm = name->mem; + + if(mdm_type != mdm->type) { + log_err(green->scn->dev, "%s: inconsistency between the a Stardis medium " + "and its serialised data.\n", FUNC_NAME); + res = RES_BAD_ARG; + goto error; + } + + res = ensure_medium_registration(green, mdm); + if(res != RES_OK) goto error; + } + + #undef READ + +exit: + return res; +error: + goto exit; +} + +static res_T +write_interfaces(struct sdis_green_function* green, FILE* stream) +{ + struct htable_interf_iterator it, it_end; + size_t ninterfaces = 0; + res_T res = RES_OK; + ASSERT(green && stream); + + #define WRITE(Var) { \ + if(fwrite((Var), sizeof(*(Var)), 1, stream) != 1) { \ + res = RES_IO_ERR; \ + goto error; \ + } \ + } (void)0 + ninterfaces = htable_interf_size_get(&green->interfaces); + WRITE(&ninterfaces); + + htable_interf_begin(&green->interfaces, &it); + htable_interf_end(&green->interfaces, &it_end); + while(!htable_interf_iterator_eq(&it, &it_end)) { + const struct sdis_interface* interf = *htable_interf_iterator_data_get(&it); + htable_interf_iterator_next(&it); + WRITE(&interf->id); + WRITE(&interf->medium_front->id); + WRITE(&interf->medium_front->type); + WRITE(&interf->medium_back->id); + WRITE(&interf->medium_back->type); + } + #undef WRITE + +exit: + return res; +error: + goto exit; +} + +static res_T +read_interfaces(struct sdis_green_function* green, FILE* stream) +{ + size_t ninterfs = 0; + size_t iinterf = 0; + res_T res = RES_OK; + ASSERT(green && stream); + + #define READ(Var) { \ + if(fread((Var), sizeof(*(Var)), 1, stream) != 1) { \ + if(feof(stream)) { \ + res = RES_BAD_ARG; \ + } else if(ferror(stream)) { \ + res = RES_IO_ERR; \ + } else { \ + res = RES_UNKNOWN_ERR; \ + } \ + goto error; \ + } \ + } (void)0 + + READ(&ninterfs); + FOR_EACH(iinterf, 0, ninterfs) { + struct name* name = NULL; + struct sdis_interface* interf = NULL; + struct sdis_medium* mdm_front = NULL; + struct sdis_medium* mdm_back = NULL; + struct fid id; + struct fid mdm_front_id; + struct fid mdm_back_id; + enum sdis_medium_type mdm_front_type; + enum sdis_medium_type mdm_back_type; + + READ(&id); + READ(&mdm_front_id); + READ(&mdm_front_type); + READ(&mdm_back_id); + READ(&mdm_back_type); + + name = flist_name_get(&green->scn->dev->interfaces_names, id); + if(!name) { + log_err(green->scn->dev, "%s: a Stardis interface is missing.\n", + FUNC_NAME); + res = RES_BAD_ARG; + goto error; + } + + interf = name->mem; + mdm_front = flist_name_get(&green->scn->dev->media_names, mdm_front_id)->mem; + mdm_back = flist_name_get(&green->scn->dev->media_names, mdm_back_id)->mem; + + if(mdm_front != interf->medium_front + || mdm_back != interf->medium_back + || mdm_front_type != interf->medium_front->type + || mdm_back_type != interf->medium_back->type) { + log_err(green->scn->dev, "%s: inconsistency between the a Stardis interface " + "and its serialised data.\n", FUNC_NAME); + res = RES_BAD_ARG; + goto error; + } + + res = ensure_interface_registration(green, interf); + if(res != RES_OK) goto error; + } + + #undef READ + +exit: + return res; +error: + goto exit; +} + +static res_T +write_paths_list(struct sdis_green_function* green, FILE* stream) +{ + size_t npaths = 0; + size_t ipath = 0; + res_T res = RES_OK; + ASSERT(green && stream); + + #define WRITE(Var) { \ + if(fwrite((Var), sizeof(*(Var)), 1, stream) != 1) { \ + res = RES_IO_ERR; \ + goto error; \ + } \ + } (void)0 + npaths = darray_green_path_size_get(&green->paths); + WRITE(&npaths); + FOR_EACH(ipath, 0, npaths) { + const struct green_path* path = NULL; + path = darray_green_path_cdata_get(&green->paths) + ipath; + + res = green_path_write(path, stream); + if(res != RES_OK) goto error; + } + #undef WRITE + +exit: + return res; +error: + goto exit; +} + +static res_T +read_paths_list(struct sdis_green_function* green, FILE* stream) +{ + size_t npaths = 0; + size_t ipath = 0; + res_T res = RES_OK; + + #define READ(Var) { \ + if(fread((Var), sizeof(*(Var)), 1, stream) != 1) { \ + if(feof(stream)) { \ + res = RES_BAD_ARG; \ + } else if(ferror(stream)) { \ + res = RES_IO_ERR; \ + } else { \ + res = RES_UNKNOWN_ERR; \ + } \ + goto error; \ + } \ + } (void)0 + + READ(&npaths); + res = darray_green_path_resize(&green->paths, npaths); + if(res != RES_OK) goto error; + + FOR_EACH(ipath, 0, npaths) { + struct green_path* path = NULL; + path = darray_green_path_data_get(&green->paths) + ipath; + + res = green_path_read(path, stream); + if(res != RES_OK) goto error; + } + #undef READ + +exit: + return res; +error: + goto exit; +} + static void green_function_clear(struct sdis_green_function* green) { @@ -406,18 +804,18 @@ green_function_clear(struct sdis_green_function* green) static void green_function_release(ref_T* ref) { - struct sdis_device* dev; + struct sdis_scene* scn; struct sdis_green_function* green; ASSERT(ref); green = CONTAINER_OF(ref, struct sdis_green_function, ref); - dev = green->dev; + scn = green->scn; green_function_clear(green); htable_medium_release(&green->media); htable_interf_release(&green->interfaces); darray_green_path_release(&green->paths); if(green->rng_state) fclose(green->rng_state); - MEM_RM(dev->allocator, green); - SDIS(device_ref_put(dev)); + MEM_RM(scn->dev->allocator, green); + SDIS(scene_ref_put(scn)); } /******************************************************************************* @@ -460,7 +858,7 @@ sdis_green_function_solve goto error; } - res = ssp_rng_create(green->dev->allocator, &green->rng_type, &rng); + res = ssp_rng_create(green->scn->dev->allocator, &green->rng_type, &rng); if(res != RES_OK) goto error; /* Avoid correlation by defining the RNG state from the final state of the @@ -472,7 +870,7 @@ sdis_green_function_solve npaths = darray_green_path_size_get(&green->paths); /* Create the estimator */ - res = estimator_create(green->dev, SDIS_ESTIMATOR_TEMPERATURE, &estimator); + res = estimator_create(green->scn->dev, SDIS_ESTIMATOR_TEMPERATURE, &estimator); if(res != RES_OK) goto error; /* Solve the green function */ @@ -508,6 +906,161 @@ error: } res_T +sdis_green_function_write(struct sdis_green_function* green, FILE* stream) +{ + struct ssp_rng* rng = NULL; + enum rng_type rng_type = RNG_UNKNOWN; + hash256_T hash; + res_T res = RES_OK; + + if(!green || !stream) { + res = RES_BAD_ARG; + goto error; + } + + #define WRITE(Var, Nb) { \ + if(fwrite((Var), sizeof(*(Var)), (Nb), stream) != (Nb)) { \ + res = RES_IO_ERR; \ + goto error; \ + } \ + } (void)0 + + rng_type = get_rng_type_enum(&green->rng_type); + if(rng_type == RNG_UNKNOWN) { + log_err(green->scn->dev, + "%s: could not function a green function with an unknown RNG type.\n", + FUNC_NAME); + res = RES_BAD_ARG; + goto error; + } + + WRITE(&SDIS_GREEN_FUNCTION_VERSION, 1); + + res = scene_compute_hash(green->scn, hash); + if(res != RES_OK) goto error; + WRITE(hash, sizeof(hash256_T)); + + res = write_media(green, stream); + if(res != RES_OK) goto error; + res = write_interfaces(green, stream); + if(res != RES_OK) goto error; + res = write_paths_list(green, stream); + if(res != RES_OK) goto error; + + WRITE(&green->npaths_valid, 1); + WRITE(&green->npaths_invalid, 1); + WRITE(&green->realisation_time, 1); + WRITE(&rng_type, 1); + #undef WRITE + + /* Create a temporary RNG used to serialise the RNG state */ + res = ssp_rng_create(green->scn->dev->allocator, &green->rng_type, &rng); + if(res != RES_OK) goto error; + rewind(green->rng_state); + res = ssp_rng_read(rng, green->rng_state); + if(res != RES_OK) goto error; + res = ssp_rng_write(rng, stream); + if(res != RES_OK) goto error; + +exit: + if(rng) SSP(rng_ref_put(rng)); + return res; +error: + goto exit; +} + +res_T +sdis_green_function_create_from_stream + (struct sdis_scene* scn, + FILE* stream, + struct sdis_green_function** out_green) +{ + hash256_T hash0, hash1; + struct sdis_green_function* green = NULL; + struct ssp_rng* rng = NULL; + enum rng_type rng_type = RNG_UNKNOWN; + int version = 0; + res_T res = RES_OK; + + if(!scn || !stream || !out_green) { + res = RES_BAD_ARG; + goto error; + } + + res = green_function_create(scn, &green); + if(res != RES_OK) goto error; + + #define READ(Var, Nb) { \ + if(fread((Var), sizeof(*(Var)), (Nb), stream) != (Nb)) { \ + if(feof(stream)) { \ + res = RES_BAD_ARG; \ + } else if(ferror(stream)) { \ + res = RES_IO_ERR; \ + } else { \ + res = RES_UNKNOWN_ERR; \ + } \ + goto error; \ + } \ + } (void)0 + + READ(&version, 1); + if(version != SDIS_GREEN_FUNCTION_VERSION) { + log_err(green->scn->dev, + "%s: unexpected green function version %d. Expecting a green function " + "in version %d.\n", + FUNC_NAME, version, SDIS_GREEN_FUNCTION_VERSION); + res = RES_BAD_ARG; + goto error; + } + + res = scene_compute_hash(green->scn, hash0); + if(res != RES_OK) goto error; + + READ(hash1, sizeof(hash256_T)); + if(!hash256_eq(hash0, hash1)) { + log_err(green->scn->dev, + "%s: the submitted scene does not match scene used to estimate the green " + "function.\n", FUNC_NAME); + res = RES_BAD_ARG; + goto error; + } + + res = read_media(green, stream); + if(res != RES_OK) goto error; + res = read_interfaces(green, stream); + if(res != RES_OK) goto error; + res = read_paths_list(green, stream); + if(res != RES_OK) goto error; + + READ(&green->npaths_valid, 1); + READ(&green->npaths_invalid, 1); + READ(&green->realisation_time, 1); + READ(&rng_type, 1); + #undef READ + + get_rng_type_ssp(rng_type, &green->rng_type); + + /* Create a temporary RNG used to deserialise the RNG state */ + res = ssp_rng_create(green->scn->dev->allocator, &green->rng_type, &rng); + if(res != RES_OK) goto error; + res = ssp_rng_read(rng, stream); + if(res != RES_OK) goto error; + res = ssp_rng_write(rng, green->rng_state); + if(res != RES_OK) goto error; + +exit: + if(rng) SSP(rng_ref_put(rng)); + if(out_green) *out_green = green; + return res; +error: + if(green) { + SDIS(green_function_ref_put(green)); + green = NULL; + } + goto exit; +} + +res_T sdis_green_function_get_paths_count (const struct sdis_green_function* green, size_t* npaths) { @@ -733,23 +1286,23 @@ error: ******************************************************************************/ res_T green_function_create - (struct sdis_device* dev, struct sdis_green_function** out_green) + (struct sdis_scene* scn, struct sdis_green_function** out_green) { struct sdis_green_function* green = NULL; res_T res = RES_OK; - ASSERT(dev && out_green); + ASSERT(scn && out_green); - green = MEM_CALLOC(dev->allocator, 1, sizeof(*green)); + green = MEM_CALLOC(scn->dev->allocator, 1, sizeof(*green)); if(!green) { res = RES_MEM_ERR; goto error; } ref_init(&green->ref); - SDIS(device_ref_get(dev)); - green->dev = dev; - htable_medium_init(dev->allocator, &green->media); - htable_interf_init(dev->allocator, &green->interfaces); - darray_green_path_init(dev->allocator, &green->paths); + SDIS(scene_ref_get(scn)); + green->scn = scn; + htable_medium_init(scn->dev->allocator, &green->media); + htable_interf_init(scn->dev->allocator, &green->interfaces); + darray_green_path_init(scn->dev->allocator, &green->paths); green->npaths_valid = SIZE_MAX; green->npaths_invalid = SIZE_MAX; diff --git a/src/sdis_green.h b/src/sdis_green.h @@ -18,6 +18,11 @@ #include <rsys/rsys.h> +/* Current version the green function data structure. One should increment it + * and perform a version management onto serialized data when the gren function + * data structure is updated. */ +static const int SDIS_GREEN_FUNCTION_VERSION = 0; + /* Forward declaration */ struct accum; struct sdis_green_function; @@ -34,7 +39,7 @@ static const struct green_path_handle GREEN_PATH_HANDLE_NULL = extern LOCAL_SYM res_T green_function_create - (struct sdis_device* dev, + (struct sdis_scene* scn, struct sdis_green_function** green); /* Merge `src' into `dst' an clear `src' */ diff --git a/src/sdis_heat_path_boundary_Xd.h b/src/sdis_heat_path_boundary_Xd.h @@ -926,7 +926,6 @@ XD(solid_boundary_with_flux_path) rwalk->mdm = mdm; rwalk->hit = SXD_HIT_NULL; rwalk->hit_side = SDIS_SIDE_NULL__; - } /* Register the new vertex against the heat path */ @@ -990,7 +989,7 @@ XD(boundary_path) /* Check if the boundary flux is known. Note that currently, only solid media * can have a flux as limit condition */ mdm = interface_get_medium(interf, frag.side); - if(sdis_medium_get_type(mdm) == SDIS_SOLID ) { + if(sdis_medium_get_type(mdm) == SDIS_SOLID) { const double phi = interface_side_get_flux(interf, &frag); if(phi != SDIS_FLUX_NONE) { res = XD(solid_boundary_with_flux_path) diff --git a/src/sdis_interface.c b/src/sdis_interface.c @@ -153,6 +153,7 @@ sdis_interface_create interf->dev = dev; interf->shader = *shader; interf->id = flist_name_add(&dev->interfaces_names); + flist_name_get(&dev->interfaces_names, interf->id)->mem = interf; if(data) { SDIS(data_ref_get(data)); diff --git a/src/sdis_medium.c b/src/sdis_medium.c @@ -68,6 +68,7 @@ medium_create medium->dev = dev; medium->type = type; medium->id = flist_name_add(&dev->media_names); + flist_name_get(&dev->media_names, medium->id)->mem = medium; exit: if(out_medium) *out_medium = medium; diff --git a/src/sdis_scene.c b/src/sdis_scene.c @@ -13,6 +13,10 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ +#define _POSIX_C_SOURCE 200809L /* mmap support */ +#define _DEFAULT_SOURCE 1 /* MAP_POPULATE support */ +#define _BSD_SOURCE 1 /* MAP_POPULATE for glibc < 2.19 */ + #include "sdis_scene_Xd.h" /* Generate the Generic functions of the scene */ @@ -22,10 +26,12 @@ #include "sdis_scene_Xd.h" #include "sdis.h" +#include "sdis_interface_c.h" #include "sdis_scene_c.h" #include <float.h> #include <limits.h> +#include <sys/mman.h> /******************************************************************************* * Helper function @@ -390,3 +396,93 @@ scene_get_medium_in_closed_boundaries : scene_get_medium_in_closed_boundaries_3d(scn, pos, out_medium); } +res_T +scene_compute_hash(const struct sdis_scene* scn, hash256_T hash) +{ + void* data = NULL; + FILE* stream = NULL; + size_t iprim, nprims; + size_t len; + res_T res = RES_OK; + ASSERT(scn && hash); + + stream = tmpfile(); + if(!stream) { + res = RES_IO_ERR; + goto error; + } + + #define WRITE(Var, Nb) \ + if(fwrite((Var), sizeof(*(Var)), Nb, stream) != (Nb)) { \ + res = RES_IO_ERR; \ + goto error; \ + } (void)0 + if(scene_is_2d(scn)) { + S2D(scene_view_primitives_count(scn->s2d_view, &nprims)); + } else { + S3D(scene_view_primitives_count(scn->s3d_view, &nprims)); + } + FOR_EACH(iprim, 0, nprims) { + struct sdis_interface* interf = NULL; + size_t ivert; + + if(scene_is_2d(scn)) { + struct s2d_primitive prim; + S2D(scene_view_get_primitive(scn->s2d_view, (unsigned)iprim, &prim)); + FOR_EACH(ivert, 0, 2) { + struct s2d_attrib attr; + S2D(segment_get_vertex_attrib(&prim, ivert, S2D_POSITION, &attr)); + WRITE(attr.value, 2); + } + } else { + struct s3d_primitive prim; + S3D(scene_view_get_primitive(scn->s3d_view, (unsigned)iprim, &prim)); + FOR_EACH(ivert, 0, 3) { + struct s3d_attrib attr; + S3D(triangle_get_vertex_attrib(&prim, ivert, S3D_POSITION, &attr)); + WRITE(attr.value, 3); + } + } + + interf = scene_get_interface(scn, (unsigned)iprim); + WRITE(&interf->medium_front->type, 1); + WRITE(&interf->medium_front->id, 1); + WRITE(&interf->medium_back->type, 1); + WRITE(&interf->medium_back->id, 1); + } + #undef WRITE + + len = (size_t)ftell(stream); + rewind(stream); +#ifdef COMPILER_GCC + data = mmap(NULL, len, PROT_READ, MAP_PRIVATE|MAP_POPULATE, fileno(stream), 0); + if(data == MAP_FAILED) { + res = RES_IO_ERR; + goto error; + } +#else + data = MEM_ALLOC_ALIGNED(scn->dev->allocator, len, 16); + if(!data) { + res = RES_MEM_ERR; + goto error; + } + if(fread(data, len, 1, stream) != 1) { + res = RES_IO_ERR; + goto error; + } +#endif + + res = hash_sha256(scn->dev->allocator, data, len, hash); + if(res != RES_OK) goto error; + +exit: +#ifdef COMPILER_GCC + if(data) munmap(data, len); +#else + if(data) MEM_RM(scn->dev->allocator, data); +#endif + if(stream) fclose(stream); + return res; +error: + goto exit; +} diff --git a/src/sdis_scene_c.h b/src/sdis_scene_c.h @@ -20,6 +20,7 @@ #include <star/s3d.h> #include <rsys/dynamic_array_uint.h> +#include <rsys/hash.h> #include <rsys/hash_table.h> #include <rsys/ref_count.h> @@ -248,6 +249,11 @@ scene_get_medium_in_closed_boundaries const double position[], struct sdis_medium** medium); +extern LOCAL_SYM res_T +scene_compute_hash + (const struct sdis_scene* scn, + hash256_T hash); + static INLINE void scene_get_enclosure_ids (const struct sdis_scene* scn, diff --git a/src/sdis_solve.c b/src/sdis_solve.c @@ -541,15 +541,15 @@ sdis_solve_medium_green_function } res_T -sdis_compute_mean_power +sdis_compute_power (struct sdis_scene* scn, - const struct sdis_compute_mean_power_args* args, + const struct sdis_compute_power_args* args, struct sdis_estimator** estimator) { if(!scn) return RES_BAD_ARG; if(scene_is_2d(scn)) { - return compute_mean_power_2d(scn, args, estimator); + return compute_power_2d(scn, args, estimator); } else { - return compute_mean_power_3d(scn, args, estimator); + return compute_power_3d(scn, args, estimator); } } diff --git a/src/sdis_solve_boundary_Xd.h b/src/sdis_solve_boundary_Xd.h @@ -214,7 +214,7 @@ XD(solve_boundary) greens = MEM_CALLOC(scn->dev->allocator, scn->dev->nthreads, sizeof(*greens)); if(!greens) { res = RES_MEM_ERR; goto error; } FOR_EACH(i, 0, scn->dev->nthreads) { - res = green_function_create(scn->dev, &greens[i]); + res = green_function_create(scn, &greens[i]); if(res != RES_OK) goto error; } } diff --git a/src/sdis_solve_medium_Xd.h b/src/sdis_solve_medium_Xd.h @@ -284,7 +284,7 @@ XD(solve_medium) greens = MEM_CALLOC(scn->dev->allocator, scn->dev->nthreads, sizeof(*greens)); if(!greens) { res = RES_MEM_ERR; goto error; } FOR_EACH(i, 0, scn->dev->nthreads) { - res = green_function_create(scn->dev, &greens[i]); + res = green_function_create(scn, &greens[i]); if(res != RES_OK) goto error; } } @@ -478,9 +478,9 @@ error: } static res_T -XD(compute_mean_power) +XD(compute_power) (struct sdis_scene* scn, - const struct sdis_compute_mean_power_args* args, + const struct sdis_compute_power_args* args, struct sdis_estimator** out_estimator) { struct darray_enclosure_cumul cumul; @@ -563,7 +563,7 @@ XD(compute_mean_power) [darray_enclosure_cumul_size_get(&cumul)-1].cumul; /* Create the estimator */ - res = estimator_create(scn->dev, SDIS_ESTIMATOR_MEAN_POWER, &estimator); + res = estimator_create(scn->dev, SDIS_ESTIMATOR_POWER, &estimator); if(res != RES_OK) goto error; nrealisations = args->nrealisations; @@ -640,7 +640,7 @@ XD(compute_mean_power) estimator_setup_realisations_count(estimator, nrealisations, acc_mpow.count); estimator_setup_realisation_time(estimator, acc_time.sum, acc_time.sum2); - estimator_setup_mean_power + estimator_setup_power (estimator, acc_mpow.sum, acc_mpow.sum2, spread, args->time_range); res = estimator_save_rng_state(estimator, rng_proxy); if(res != RES_OK) goto error; diff --git a/src/sdis_solve_probe_Xd.h b/src/sdis_solve_probe_Xd.h @@ -115,7 +115,7 @@ XD(solve_probe) greens = MEM_CALLOC(scn->dev->allocator, scn->dev->nthreads, sizeof(*greens)); if(!greens) { res = RES_MEM_ERR; goto error; } FOR_EACH(i, 0, scn->dev->nthreads) { - res = green_function_create(scn->dev, &greens[i]); + res = green_function_create(scn, &greens[i]); if(res != RES_OK) goto error; } } diff --git a/src/sdis_solve_probe_boundary_Xd.h b/src/sdis_solve_probe_boundary_Xd.h @@ -150,7 +150,7 @@ XD(solve_probe_boundary) greens = MEM_CALLOC(scn->dev->allocator, scn->dev->nthreads, sizeof(*greens)); if(!greens) { res = RES_MEM_ERR; goto error; } FOR_EACH(i, 0, scn->dev->nthreads) { - res = green_function_create(scn->dev, &greens[i]); + res = green_function_create(scn, &greens[i]); if(res != RES_OK) goto error; } } diff --git a/src/test_sdis_compute_mean_power.c b/src/test_sdis_compute_mean_power.c @@ -182,7 +182,7 @@ main(int argc, char** argv) struct sdis_fluid_shader fluid_shader = DUMMY_FLUID_SHADER; struct sdis_solid_shader solid_shader = DUMMY_SOLID_SHADER; struct sdis_interface_shader interf_shader = SDIS_INTERFACE_SHADER_NULL; - struct sdis_compute_mean_power_args args = SDIS_COMPUTE_MEAN_POWER_ARGS_DEFAULT; + struct sdis_compute_power_args args = SDIS_COMPUTE_POWER_ARGS_DEFAULT; size_t nverts = 0; size_t ntris = 0; double ref = 0; @@ -229,35 +229,35 @@ main(int argc, char** argv) OK(sdis_scene_create(dev, ntris, get_indices, get_interface, nverts, get_position, &ctx, &scn)); - /* Test sdis_compute_mean_power function */ + /* Test sdis_compute_power function */ args.nrealisations = N; args.medium = solid0; args.time_range[0] = INF; args.time_range[1] = INF; - BA(sdis_compute_mean_power(NULL, &args, &estimator)); - BA(sdis_compute_mean_power(scn, NULL, &estimator)); - BA(sdis_compute_mean_power(scn, &args, NULL)); + BA(sdis_compute_power(NULL, &args, &estimator)); + BA(sdis_compute_power(scn, NULL, &estimator)); + BA(sdis_compute_power(scn, &args, NULL)); args.nrealisations = 0; - BA(sdis_compute_mean_power(scn, &args, &estimator)); + BA(sdis_compute_power(scn, &args, &estimator)); args.nrealisations = N; args.medium = NULL; - BA(sdis_compute_mean_power(scn, &args, &estimator)); + BA(sdis_compute_power(scn, &args, &estimator)); args.medium = solid0; args.fp_to_meter = 0; - BA(sdis_compute_mean_power(scn, &args, &estimator)); + BA(sdis_compute_power(scn, &args, &estimator)); args.fp_to_meter = 1; args.time_range[0] = args.time_range[1] = -1; - BA(sdis_compute_mean_power(scn, &args, &estimator)); + BA(sdis_compute_power(scn, &args, &estimator)); args.time_range[0] = 1; - BA(sdis_compute_mean_power(scn, &args, &estimator)); + BA(sdis_compute_power(scn, &args, &estimator)); args.time_range[1] = 0; - BA(sdis_compute_mean_power(scn, &args, &estimator)); + BA(sdis_compute_power(scn, &args, &estimator)); args.time_range[0] = args.time_range[1] = INF; - OK(sdis_compute_mean_power(scn, &args, &estimator)); + OK(sdis_compute_power(scn, &args, &estimator)); - BA(sdis_estimator_get_mean_power(NULL, &mpow)); - BA(sdis_estimator_get_mean_power(estimator, NULL)); - OK(sdis_estimator_get_mean_power(estimator, &mpow)); + BA(sdis_estimator_get_power(NULL, &mpow)); + BA(sdis_estimator_get_power(estimator, NULL)); + OK(sdis_estimator_get_power(estimator, &mpow)); OK(sdis_estimator_get_realisation_time(estimator, &time)); /* Check results for solid 0 */ @@ -269,8 +269,8 @@ main(int argc, char** argv) /* Check results for solid 1 */ args.medium = solid1; - OK(sdis_compute_mean_power(scn, &args, &estimator)); - OK(sdis_estimator_get_mean_power(estimator, &mpow)); + OK(sdis_compute_power(scn, &args, &estimator)); + OK(sdis_estimator_get_power(estimator, &mpow)); ref = PI * 10 * POWER1; printf("Mean power of the solid1 = %g ~ %g +/- %g\n", ref, mpow.E, mpow.SE); @@ -280,8 +280,8 @@ main(int argc, char** argv) /* Check for a not null time range */ args.time_range[0] = 0; args.time_range[1] = 10; - OK(sdis_compute_mean_power(scn, &args, &estimator)); - OK(sdis_estimator_get_mean_power(estimator, &mpow)); + OK(sdis_compute_power(scn, &args, &estimator)); + OK(sdis_estimator_get_power(estimator, &mpow)); ref = PI * 10 * POWER1 / 10; printf("Mean power of the solid1 in [0, 10] s = %g ~ %g +/- %g\n", ref, mpow.E, mpow.SE); @@ -298,12 +298,12 @@ main(int argc, char** argv) /* Check invalid medium */ args.time_range[0] = args.time_range[1] = 1; args.medium = solid1; - BA(sdis_compute_mean_power(scn, &args, &estimator)); + BA(sdis_compute_power(scn, &args, &estimator)); /* Check non constant volumic power */ args.medium = solid0; - OK(sdis_compute_mean_power(scn, &args, &estimator)); - OK(sdis_estimator_get_mean_power(estimator, &mpow)); + OK(sdis_compute_power(scn, &args, &estimator)); + OK(sdis_estimator_get_power(estimator, &mpow)); ref = 4.0/3.0*PI*POWER0 + PI*10*POWER1; printf("Mean power of the sphere+cylinder = %g ~ %g +/- %g\n", ref, mpow.E, mpow.SE); diff --git a/src/test_sdis_conducto_radiative.c b/src/test_sdis_conducto_radiative.c @@ -431,6 +431,7 @@ main(int argc, char** argv) OK(sdis_green_function_solve(green, solve_args.time_range, &estimator2)); check_green_function(green); check_estimator_eq(estimator, estimator2); + check_green_serialization(green, scn, solve_args.time_range); OK(sdis_estimator_ref_put(estimator)); OK(sdis_estimator_ref_put(estimator2)); diff --git a/src/test_sdis_conducto_radiative_2d.c b/src/test_sdis_conducto_radiative_2d.c @@ -429,6 +429,7 @@ main(int argc, char** argv) OK(sdis_green_function_solve(green, solve_args.time_range, &estimator2)); check_green_function(green); check_estimator_eq(estimator, estimator2); + check_green_serialization(green, scn, solve_args.time_range); OK(sdis_estimator_ref_put(estimator)); OK(sdis_estimator_ref_put(estimator2)); diff --git a/src/test_sdis_convection.c b/src/test_sdis_convection.c @@ -300,6 +300,7 @@ main(int argc, char** argv) OK(sdis_green_function_solve(green, solve_args.time_range, &estimator2)); check_green_function(green); check_estimator_eq(estimator, estimator2); + check_green_serialization(green, box_scn, solve_args.time_range); OK(sdis_estimator_ref_put(estimator2)); OK(sdis_green_function_ref_put(green)); } @@ -341,6 +342,7 @@ main(int argc, char** argv) OK(sdis_green_function_solve(green, solve_args.time_range, &estimator2)); check_green_function(green); check_estimator_eq(estimator, estimator2); + check_green_serialization(green, square_scn, solve_args.time_range); OK(sdis_estimator_ref_put(estimator2)); OK(sdis_green_function_ref_put(green)); } diff --git a/src/test_sdis_convection_non_uniform.c b/src/test_sdis_convection_non_uniform.c @@ -316,6 +316,7 @@ main(int argc, char** argv) OK(sdis_green_function_solve(green, solve_args.time_range, &estimator2)); check_green_function(green); check_estimator_eq(estimator, estimator2); + check_green_serialization(green, box_scn, solve_args.time_range); OK(sdis_estimator_ref_put(estimator2)); OK(sdis_green_function_ref_put(green)); } @@ -356,6 +357,7 @@ main(int argc, char** argv) OK(sdis_green_function_solve(green, solve_args.time_range, &estimator2)); check_green_function(green); check_estimator_eq(estimator, estimator2); + check_green_serialization(green, square_scn, solve_args.time_range); OK(sdis_estimator_ref_put(estimator2)); OK(sdis_green_function_ref_put(green)); } diff --git a/src/test_sdis_flux.c b/src/test_sdis_flux.c @@ -221,6 +221,7 @@ solve check_green_function(green); check_estimator_eq(estimator, estimator2); + check_green_serialization(green, scn, time_range); OK(sdis_estimator_ref_put(estimator)); OK(sdis_estimator_ref_put(estimator2)); diff --git a/src/test_sdis_solve_boundary.c b/src/test_sdis_solve_boundary.c @@ -348,6 +348,7 @@ main(int argc, char** argv) check_green_function(green); OK(sdis_green_function_solve(green, probe_args.time_range, &estimator2)); check_estimator(estimator2, N, ref); + check_green_serialization(green, box_scn, probe_args.time_range); OK(sdis_green_function_ref_put(green)); OK(sdis_estimator_ref_put(estimator)); @@ -378,6 +379,7 @@ main(int argc, char** argv) check_green_function(green); OK(sdis_green_function_solve(green, probe_args.time_range, &estimator2)); check_estimator(estimator2, N, ref); + check_green_serialization(green, square_scn, probe_args.time_range); OK(sdis_estimator_ref_put(estimator)); OK(sdis_estimator_ref_put(estimator2)); @@ -465,11 +467,11 @@ main(int argc, char** argv) BA(GREEN(box_scn, &bound_args, &green)); sides[0] = SDIS_FRONT; - OK(GREEN(box_scn, &bound_args, &green)); check_green_function(green); OK(sdis_green_function_solve(green, bound_args.time_range, &estimator2)); check_estimator(estimator2, N, ref); + check_green_serialization(green, box_scn, bound_args.time_range); OK(sdis_green_function_ref_put(green)); OK(sdis_estimator_ref_put(estimator)); @@ -506,6 +508,7 @@ main(int argc, char** argv) check_green_function(green); OK(sdis_green_function_solve(green, bound_args.time_range, &estimator2)); check_estimator(estimator2, N, ref); + check_green_serialization(green, square_scn, bound_args.time_range); OK(sdis_green_function_ref_put(green)); OK(sdis_estimator_ref_put(estimator)); @@ -538,6 +541,7 @@ main(int argc, char** argv) check_green_function(green); OK(sdis_green_function_solve(green, bound_args.time_range, &estimator2)); check_estimator(estimator2, N, ref); + check_green_serialization(green, box_scn, bound_args.time_range); OK(sdis_green_function_ref_put(green)); OK(sdis_estimator_ref_put(estimator)); @@ -555,6 +559,7 @@ main(int argc, char** argv) check_green_function(green); OK(sdis_green_function_solve(green, bound_args.time_range, &estimator2)); check_estimator(estimator2, N, ref); + check_green_serialization(green, square_scn, bound_args.time_range); OK(sdis_green_function_ref_put(green)); OK(sdis_estimator_ref_put(estimator)); diff --git a/src/test_sdis_solve_medium.c b/src/test_sdis_solve_medium.c @@ -459,6 +459,7 @@ main(int argc, char** argv) OK(sdis_green_function_solve(green, solve_args.time_range, &estimator2)); check_green_function(green); check_estimator_eq(estimator, estimator2); + check_green_serialization(green, scn, solve_args.time_range); OK(sdis_green_function_ref_put(green)); diff --git a/src/test_sdis_solve_medium_2d.c b/src/test_sdis_solve_medium_2d.c @@ -402,6 +402,7 @@ main(int argc, char** argv) OK(sdis_green_function_solve(green, solve_args.time_range, &estimator2)); check_green_function(green); check_estimator_eq(estimator, estimator2); + check_green_serialization(green, scn, solve_args.time_range); OK(sdis_green_function_ref_put(green)); diff --git a/src/test_sdis_solve_probe.c b/src/test_sdis_solve_probe.c @@ -259,6 +259,7 @@ main(int argc, char** argv) struct sdis_data* data = NULL; struct sdis_estimator* estimator = NULL; struct sdis_estimator* estimator2 = NULL; + struct sdis_estimator* estimator3 = NULL; struct sdis_green_function* green = NULL; const struct sdis_heat_path* path = NULL; struct sdis_fluid_shader fluid_shader = DUMMY_FLUID_SHADER; @@ -272,6 +273,7 @@ main(int argc, char** argv) struct interf* interface_param; struct ssp_rng* rng_state = NULL; enum sdis_estimator_type type; + FILE* stream = NULL; double ref; const size_t N = 1000; const size_t N_dump = 10; @@ -470,14 +472,34 @@ main(int argc, char** argv) check_green_function(green); check_estimator_eq(estimator, estimator2); + CHK(stream = tmpfile()); + BA(sdis_green_function_write(NULL, stream)); + BA(sdis_green_function_write(green, NULL)); + OK(sdis_green_function_write(green, stream)); + BA(sdis_green_function_ref_get(NULL)); OK(sdis_green_function_ref_get(green)); BA(sdis_green_function_ref_put(NULL)); OK(sdis_green_function_ref_put(green)); OK(sdis_green_function_ref_put(green)); + rewind(stream); + BA(sdis_green_function_create_from_stream(NULL, stream, &green)); + BA(sdis_green_function_create_from_stream(scn, NULL, &green)); + BA(sdis_green_function_create_from_stream(scn, stream, NULL)); + OK(sdis_green_function_create_from_stream(scn, stream, &green)); + CHK(!fclose(stream)); + + OK(sdis_green_function_solve(green, solve_args.time_range, &estimator3)); + + check_green_function(green); + check_estimator_eq_strict(estimator2, estimator3); + + OK(sdis_green_function_ref_put(green)); + OK(sdis_estimator_ref_put(estimator)); OK(sdis_estimator_ref_put(estimator2)); + OK(sdis_estimator_ref_put(estimator3)); OK(sdis_solve_probe(scn, &solve_args, &estimator)); BA(sdis_estimator_get_paths_count(NULL, &n)); diff --git a/src/test_sdis_solve_probe2.c b/src/test_sdis_solve_probe2.c @@ -268,6 +268,7 @@ main(int argc, char** argv) OK(sdis_green_function_solve(green, solve_args.time_range, &estimator2)); check_green_function(green); check_estimator_eq(estimator, estimator2); + check_green_serialization(green, scn, solve_args.time_range); /* Release data */ OK(sdis_estimator_ref_put(estimator)); diff --git a/src/test_sdis_solve_probe2_2d.c b/src/test_sdis_solve_probe2_2d.c @@ -267,6 +267,7 @@ main(int argc, char** argv) OK(sdis_green_function_solve(green, solve_args.time_range, &estimator2)); check_green_function(green); check_estimator_eq(estimator, estimator2); + check_green_serialization(green, scn, solve_args.time_range); /* Release data */ OK(sdis_estimator_ref_put(estimator)); @@ -280,3 +281,4 @@ main(int argc, char** argv) CHK(mem_allocated_size() == 0); return 0; } + diff --git a/src/test_sdis_solve_probe3.c b/src/test_sdis_solve_probe3.c @@ -324,6 +324,7 @@ main(int argc, char** argv) OK(sdis_green_function_solve(green, solve_args.time_range, &estimator2)); check_green_function(green); check_estimator_eq(estimator, estimator2); + check_green_serialization(green, scn, solve_args.time_range); /* Release data */ OK(sdis_estimator_ref_put(estimator)); diff --git a/src/test_sdis_solve_probe3_2d.c b/src/test_sdis_solve_probe3_2d.c @@ -316,6 +316,7 @@ main(int argc, char** argv) OK(sdis_green_function_solve(green, solve_args.time_range, &estimator2)); check_green_function(green); check_estimator_eq(estimator, estimator2); + check_green_serialization(green, scn, solve_args.time_range); /* Release data */ OK(sdis_estimator_ref_put(estimator)); diff --git a/src/test_sdis_utils.c b/src/test_sdis_utils.c @@ -363,3 +363,35 @@ dump_heat_paths(FILE* stream, const struct sdis_estimator* estimator) fprintf(stream, "0.0 0.0 1.0 1.0\n"); /* 0.0 = Blue: success */ fprintf(stream, "1.0 0.0 0.0 1.0\n"); /* 1.0 = Red: failure */ } + +void +check_green_serialization + (struct sdis_green_function* green, + struct sdis_scene* scn, + const double time_range[2]) +{ + FILE* stream = NULL; + struct sdis_estimator *e1 = NULL; + struct sdis_estimator *e2 = NULL; + struct sdis_green_function* green2 = NULL; + + CHK(green && time_range); + CHK(stream = tmpfile()); + + OK(sdis_green_function_write(green, stream)); + + rewind(stream); + OK(sdis_green_function_create_from_stream(scn, stream, &green2)); + CHK(!fclose(stream)); + check_green_function(green2); + + OK(sdis_green_function_solve(green, time_range, &e1)); + OK(sdis_green_function_solve(green2, time_range, &e2)); + check_estimator_eq_strict(e1, e2); + + OK(sdis_estimator_ref_put(e1)); + OK(sdis_estimator_ref_put(e2)); + OK(sdis_green_function_ref_put(green2)); +} + + diff --git a/src/test_sdis_utils.h b/src/test_sdis_utils.h @@ -252,26 +252,82 @@ check_estimator_eq OK(sdis_estimator_get_type(e2, &type2)); CHK(type1 == type2); - OK(sdis_estimator_get_temperature(e1, &mc1)); - OK(sdis_estimator_get_temperature(e2, &mc2)); - CHK(mc1.E + 3*mc1.SE >= mc2.E - 3*mc2.SE); - CHK(mc1.E - 3*mc1.SE <= mc2.E + 3*mc2.SE); - - if(type1 == SDIS_ESTIMATOR_FLUX) { - OK(sdis_estimator_get_convective_flux(e1, &mc1)); - OK(sdis_estimator_get_convective_flux(e2, &mc2)); - CHK(mc1.E + 3*mc1.SE >= mc2.E - 3*mc2.SE); - CHK(mc1.E - 3*mc1.SE <= mc2.E + 3*mc2.SE); - - OK(sdis_estimator_get_radiative_flux(e1, &mc1)); - OK(sdis_estimator_get_radiative_flux(e2, &mc2)); - CHK(mc1.E + 3*mc1.SE >= mc2.E - 3*mc2.SE); - CHK(mc1.E - 3*mc1.SE <= mc2.E + 3*mc2.SE); - - OK(sdis_estimator_get_total_flux(e1, &mc1)); - OK(sdis_estimator_get_total_flux(e2, &mc2)); - CHK(mc1.E + 3*mc1.SE >= mc2.E - 3*mc2.SE); - CHK(mc1.E - 3*mc1.SE <= mc2.E + 3*mc2.SE); + switch(type1) { + case SDIS_ESTIMATOR_TEMPERATURE: + OK(sdis_estimator_get_temperature(e1, &mc1)); + OK(sdis_estimator_get_temperature(e2, &mc2)); + CHK(mc1.E + 3*mc1.SE >= mc2.E - 3*mc2.SE); + CHK(mc1.E - 3*mc1.SE <= mc2.E + 3*mc2.SE); + break; + + case SDIS_ESTIMATOR_FLUX: + OK(sdis_estimator_get_convective_flux(e1, &mc1)); + OK(sdis_estimator_get_convective_flux(e2, &mc2)); + CHK(mc1.E + 3*mc1.SE >= mc2.E - 3*mc2.SE); + CHK(mc1.E - 3*mc1.SE <= mc2.E + 3*mc2.SE); + + OK(sdis_estimator_get_radiative_flux(e1, &mc1)); + OK(sdis_estimator_get_radiative_flux(e2, &mc2)); + CHK(mc1.E + 3*mc1.SE >= mc2.E - 3*mc2.SE); + CHK(mc1.E - 3*mc1.SE <= mc2.E + 3*mc2.SE); + + OK(sdis_estimator_get_total_flux(e1, &mc1)); + OK(sdis_estimator_get_total_flux(e2, &mc2)); + CHK(mc1.E + 3*mc1.SE >= mc2.E - 3*mc2.SE); + CHK(mc1.E - 3*mc1.SE <= mc2.E + 3*mc2.SE); + break; + + case SDIS_ESTIMATOR_POWER: + OK(sdis_estimator_get_power(e1, &mc1)); + OK(sdis_estimator_get_power(e2, &mc2)); + CHK(mc1.E + 3*mc1.SE >= mc2.E - 3*mc2.SE); + CHK(mc1.E - 3*mc1.SE <= mc2.E + 3*mc2.SE); + break; + + default: FATAL("Unreachable code.\n"); break; + } +} + +static INLINE void +check_estimator_eq_strict + (const struct sdis_estimator* e1, const struct sdis_estimator* e2) +{ + struct sdis_mc mc1, mc2; + enum sdis_estimator_type type1, type2; + ASSERT(e1 && e2); + + OK(sdis_estimator_get_type(e1, &type1)); + OK(sdis_estimator_get_type(e2, &type2)); + CHK(type1 == type2); + + switch(type1) { + case SDIS_ESTIMATOR_TEMPERATURE: + OK(sdis_estimator_get_temperature(e1, &mc1)); + OK(sdis_estimator_get_temperature(e2, &mc2)); + CHK(mc1.E == mc2.E && mc1.V == mc2.V && mc1.SE == mc2.SE); + break; + + case SDIS_ESTIMATOR_FLUX: + OK(sdis_estimator_get_convective_flux(e1, &mc1)); + OK(sdis_estimator_get_convective_flux(e2, &mc2)); + CHK(mc1.E == mc2.E && mc1.V == mc2.V && mc1.SE == mc2.SE); + + OK(sdis_estimator_get_radiative_flux(e1, &mc1)); + OK(sdis_estimator_get_radiative_flux(e2, &mc2)); + CHK(mc1.E == mc2.E && mc1.V == mc2.V && mc1.SE == mc2.SE); + + OK(sdis_estimator_get_total_flux(e1, &mc1)); + OK(sdis_estimator_get_total_flux(e2, &mc2)); + CHK(mc1.E == mc2.E && mc1.V == mc2.V && mc1.SE == mc2.SE); + break; + + case SDIS_ESTIMATOR_POWER: + OK(sdis_estimator_get_power(e1, &mc1)); + OK(sdis_estimator_get_power(e2, &mc2)); + CHK(mc1.E == mc2.E && mc1.V == mc2.V && mc1.SE == mc2.SE); + break; + + default: FATAL("Unreachable code.\n"); break; } } @@ -295,5 +351,11 @@ dump_heat_paths (FILE* stream, const struct sdis_estimator* estimator); +extern LOCAL_SYM void +check_green_serialization + (struct sdis_green_function* green, + struct sdis_scene* scn, + const double time_range[2]); + #endif /* TEST_SDIS_UTILS_H */ diff --git a/src/test_sdis_volumic_power.c b/src/test_sdis_volumic_power.c @@ -247,6 +247,7 @@ solve check_green_function(green); check_estimator_eq(estimator, estimator2); + check_green_serialization(green, scn, time_range); OK(sdis_estimator_ref_put(estimator)); OK(sdis_estimator_ref_put(estimator2));