stardis-solver

Solve coupled heat transfers
git clone git://git.meso-star.fr/stardis-solver.git
Log | Files | Refs | README | LICENSE

commit c79bea63847a5caf927c3e7251b0183a0a444316
parent 34a3152c88013b25186945e52a8678cb41bc5b7c
Author: Vincent Forest <vincent.forest@meso-star.com>
Date:   Tue,  4 Jun 2024 15:43:41 +0200

Merge branch 'feature_track_enclosures' into develop

Diffstat:
Msrc/sdis_Xd_begin.h | 41-----------------------------------------
Msrc/sdis_heat_path.h | 85++++++++++++++++++++++++++++++++++++++++++++++++++++++++-----------------------
Msrc/sdis_heat_path_boundary_Xd.h | 94++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-------
Msrc/sdis_heat_path_boundary_Xd_c.h | 427+++++++++++++++++++++++++++++++++++++++++++++++--------------------------------
Msrc/sdis_heat_path_boundary_Xd_handle_external_net_flux.h | 12++++++------
Msrc/sdis_heat_path_boundary_Xd_solid_fluid_picard1.h | 53+++++++++++++++++++++++++++++------------------------
Msrc/sdis_heat_path_boundary_Xd_solid_fluid_picardN.h | 54+++++++++++++++++++++++++++++-------------------------
Msrc/sdis_heat_path_boundary_Xd_solid_solid.h | 44+++++++++++++++++++++++---------------------
Msrc/sdis_heat_path_boundary_c.h | 167++++++++++++++++++++++++++++++++-----------------------------------------------
Msrc/sdis_heat_path_conductive.c | 8++++----
Msrc/sdis_heat_path_conductive_c.h | 22++++++++++------------
Msrc/sdis_heat_path_conductive_delta_sphere_Xd.h | 94++++++++++++++++++++++++++++++++++++++++---------------------------------------
Msrc/sdis_heat_path_conductive_wos_Xd.h | 247++++++++++++++++++++++++++++++++++++++++---------------------------------------
Msrc/sdis_heat_path_convective_Xd.h | 193++++++++++++++++++++++++++++++-------------------------------------------------
Msrc/sdis_heat_path_radiative_Xd.h | 85+++++++++++++++++++++++++++++++++++++++++++++----------------------------------
Msrc/sdis_misc.c | 83++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-----
Msrc/sdis_misc.h | 18+++++-------------
Dsrc/sdis_misc_Xd.h | 90-------------------------------------------------------------------------------
Msrc/sdis_realisation.c | 42++++++++++++++++++++++++++++--------------
Msrc/sdis_realisation.h | 20+++++++++++---------
Msrc/sdis_realisation_Xd.h | 128+++++++++++++++++++++++++++++++++++++++++++++----------------------------------
Msrc/sdis_scene.c | 48++++++++++++++++++++++++++++++++++++++++--------
Msrc/sdis_scene_Xd.h | 65++++++++++++++++++++++++++++++++---------------------------------
Msrc/sdis_scene_c.h | 39+++++++++++++++++++++++----------------
Msrc/sdis_solve_camera.c | 30++++++++++++------------------
Msrc/sdis_solve_medium_Xd.h | 32+++++++++++++++++++-------------
Msrc/sdis_solve_probe_Xd.h | 28+++++++++++++++++++++-------
Msrc/test_sdis_solve_camera.c | 1022+++++++++++++++++++++++++++++++++++++++++--------------------------------------
28 files changed, 1731 insertions(+), 1540 deletions(-)

diff --git a/src/sdis_Xd_begin.h b/src/sdis_Xd_begin.h @@ -76,44 +76,3 @@ /* Macro making generic its submitted name to SDIS_XD_DIMENSION */ #define XD(Name) CONCAT(CONCAT(CONCAT(Name, _), DIM), d) - -/* Generate the generic data structures and constants */ -#if (SDIS_XD_DIMENSION == 2 && !defined(SDIS_2D_H)) \ -|| (SDIS_XD_DIMENSION == 3 && !defined(SDIS_3D_H)) - #if SDIS_XD_DIMENSION == 2 - #define SDIS_2D_H - #else - #define SDIS_3D_H - #endif - -struct rwalk_context; - -/* Current state of the random walk */ -struct XD(rwalk) { - struct sdis_rwalk_vertex vtx; /* Position and time of the Random walk */ - struct sdis_medium* mdm; /* Medium in which the random walk lies */ - struct sXd(hit) hit; /* Hit of the random walk */ - - /* Direction along which the random walk reached the radiative environment */ - double dir[3]; - - double elapsed_time; - enum sdis_side hit_side; -}; -static const struct XD(rwalk) XD(RWALK_NULL) = { - SDIS_RWALK_VERTEX_NULL__, NULL, SXD_HIT_NULL__, {0,0,0}, 0, SDIS_SIDE_NULL__ -}; - -struct XD(temperature) { - res_T (*func)/* Next function to invoke in order to compute the temperature */ - (struct sdis_scene* scn, - struct rwalk_context* ctx, - struct XD(rwalk)* rwalk, - struct ssp_rng* rng, - struct XD(temperature)* temp); - double value; /* Current value of the temperature */ - int done; -}; -static const struct XD(temperature) XD(TEMPERATURE_NULL) = { NULL, 0, 0 }; - -#endif /* SDIX_<2|3>D_H */ diff --git a/src/sdis_heat_path.h b/src/sdis_heat_path.h @@ -17,6 +17,7 @@ #define SDIS_HEAT_PATH_H #include "sdis.h" +#include "sdis_scene_c.h" #include <rsys/dynamic_array.h> #include <rsys/dynamic_array_size_t.h> @@ -24,12 +25,8 @@ /* Forward declarations */ struct green_path_handle; -struct rwalk_2d; -struct rwalk_3d; struct sdis_scene; struct ssp_rng; -struct temperature_2d; -struct temperature_3d; /******************************************************************************* * Context of a random walk, i.e. its data concerning the current system and the @@ -87,6 +84,46 @@ get_picard_order(const struct rwalk_context* ctx) } /******************************************************************************* + * 2D/3D random walk and associated temperature, i.e. current state of the + * sampled path + ******************************************************************************/ +struct rwalk { + struct sdis_rwalk_vertex vtx; /* Position and time of the Random walk */ + unsigned enc_id; /* Id of the enclosure in which the random walk lies */ + struct s2d_hit hit_2d; + struct s3d_hit hit_3d; + + /* Direction along which the random walk reached the radiative environment */ + double dir[3]; + + double elapsed_time; + enum sdis_side hit_side; +}; +#define RWALK_NULL__ { \ + SDIS_RWALK_VERTEX_NULL__, \ + ENCLOSURE_ID_NULL, \ + S2D_HIT_NULL__, \ + S3D_HIT_NULL__, \ + {0,0,0}, \ + 0, \ + SDIS_SIDE_NULL__ \ +} +static const struct rwalk RWALK_NULL = RWALK_NULL__; + +struct temperature { + res_T (*func)/* Next function to invoke in order to compute the temperature */ + (struct sdis_scene* scn, + struct rwalk_context* ctx, + struct rwalk* rwalk, + struct ssp_rng* rng, + struct temperature* temp); + double value; /* Current value of the temperature */ + int done; +}; +#define TEMPERATURE_NULL__ {NULL,0,0} +static const struct temperature TEMPERATURE_NULL = TEMPERATURE_NULL__; + +/******************************************************************************* * Heat path data structure used to record the geometry of sampled paths ******************************************************************************/ /* Generate the dynamic array of heat vertices */ @@ -261,34 +298,34 @@ trace_radiative_path_2d (struct sdis_scene* scn, const float ray_dir[3], struct rwalk_context* ctx, - struct rwalk_2d* rwalk, + struct rwalk* rwalk, struct ssp_rng* rng, - struct temperature_2d* temperature); + struct temperature* temperature); extern LOCAL_SYM res_T trace_radiative_path_3d (struct sdis_scene* scn, const float ray_dir[3], struct rwalk_context* ctx, - struct rwalk_3d* rwalk, + struct rwalk* rwalk, struct ssp_rng* rng, - struct temperature_3d* temperature); + struct temperature* temperature); extern LOCAL_SYM res_T radiative_path_2d (struct sdis_scene* scn, struct rwalk_context* ctx, - struct rwalk_2d* rwalk, + struct rwalk* rwalk, struct ssp_rng* rng, - struct temperature_2d* temperature); + struct temperature* temperature); extern LOCAL_SYM res_T radiative_path_3d (struct sdis_scene* scn, struct rwalk_context* ctx, - struct rwalk_3d* rwalk, + struct rwalk* rwalk, struct ssp_rng* rng, - struct temperature_3d* temperature); + struct temperature* temperature); /******************************************************************************* * Convective path @@ -297,17 +334,17 @@ extern LOCAL_SYM res_T convective_path_2d (struct sdis_scene* scn, struct rwalk_context* ctx, - struct rwalk_2d* rwalk, + struct rwalk* rwalk, struct ssp_rng* rng, - struct temperature_2d* temperature); + struct temperature* temperature); extern LOCAL_SYM res_T convective_path_3d (struct sdis_scene* scn, struct rwalk_context* ctx, - struct rwalk_3d* rwalk, + struct rwalk* rwalk, struct ssp_rng* rng, - struct temperature_3d* temperature); + struct temperature* temperature); /******************************************************************************* * Conductive path @@ -316,17 +353,17 @@ extern LOCAL_SYM res_T conductive_path_2d (struct sdis_scene* scn, struct rwalk_context* ctx, - struct rwalk_2d* rwalk, + struct rwalk* rwalk, struct ssp_rng* rng, - struct temperature_2d* temperature); + struct temperature* temperature); extern LOCAL_SYM res_T conductive_path_3d (struct sdis_scene* scn, struct rwalk_context* ctx, - struct rwalk_3d* rwalk, + struct rwalk* rwalk, struct ssp_rng* rng, - struct temperature_3d* temperature); + struct temperature* temperature); /******************************************************************************* * Boundary sub-path @@ -335,16 +372,16 @@ extern LOCAL_SYM res_T boundary_path_2d (struct sdis_scene* scn, struct rwalk_context* ctx, - struct rwalk_2d* rwalk, + struct rwalk* rwalk, struct ssp_rng* rng, - struct temperature_2d* temperature); + struct temperature* temperature); extern LOCAL_SYM res_T boundary_path_3d (struct sdis_scene* scn, struct rwalk_context* ctx, - struct rwalk_3d* rwalk, + struct rwalk* rwalk, struct ssp_rng* rng, - struct temperature_3d* temperature); + struct temperature* temperature); #endif /* SDIS_HEAT_PATH_H */ diff --git a/src/sdis_heat_path_boundary_Xd.h b/src/sdis_heat_path_boundary_Xd.h @@ -25,15 +25,67 @@ #include "sdis_Xd_begin.h" /******************************************************************************* + * Helper functions + ******************************************************************************/ +/* This function checks whether the random walk is on a boundary and, if so, + * verifies that the temperature of the medium attached to the interface is + * known. This medium can be different from the medium of the enclosure. Indeed, + * the enclosure can contain several media used to set the temperatures of + * several boundary conditions. Hence this function, which queries the medium on + * the trajectory coming from a boundary */ +static res_T +XD(handle_known_medium_temperature) + (struct sdis_scene* scn, + struct rwalk_context* ctx, + struct rwalk* rwalk, + struct temperature* T) +{ + struct sdis_interface* interf = NULL; + struct sdis_medium* mdm = NULL; + double temperature = SDIS_TEMPERATURE_NONE; + res_T res = RES_OK; + ASSERT(scn && ctx && rwalk && T); + + /* Not at an interface */ + if(SXD_HIT_NONE(&rwalk->XD(hit))) return RES_OK; /* Nothing to do */ + + interf = scene_get_interface(scn, rwalk->XD(hit).prim.prim_id); + mdm = rwalk->hit_side==SDIS_FRONT ? interf->medium_front: interf->medium_back; + + temperature = medium_get_temperature(mdm, &rwalk->vtx); + + /* Check if the temperature is known */ + if(SDIS_TEMPERATURE_IS_UNKNOWN(temperature)) goto exit; + + T->value += temperature; + T->done = 1; + + if(ctx->green_path) { + res = green_path_set_limit_vertex + (ctx->green_path, mdm, &rwalk->vtx, rwalk->elapsed_time); + if(res != RES_OK) goto error; + } + + if(ctx->heat_path) { + heat_path_get_last_vertex(ctx->heat_path)->weight = T->value; + } + +exit: + return res; +error: + goto exit; +} + +/******************************************************************************* * Local functions ******************************************************************************/ res_T XD(boundary_path) (struct sdis_scene* scn, struct rwalk_context* ctx, - struct XD(rwalk)* rwalk, + struct rwalk* rwalk, struct ssp_rng* rng, - struct XD(temperature)* T) + struct temperature* T) { struct sdis_interface_fragment frag = SDIS_INTERFACE_FRAGMENT_NULL; struct sdis_interface* interf = NULL; @@ -42,15 +94,16 @@ XD(boundary_path) double tmp; res_T res = RES_OK; ASSERT(scn && ctx && rwalk && rng && T); - ASSERT(rwalk->mdm == NULL); - ASSERT(!SXD_HIT_NONE(&rwalk->hit)); + ASSERT(rwalk->enc_id == ENCLOSURE_ID_NULL); + ASSERT(!SXD_HIT_NONE(&rwalk->XD(hit))); - XD(setup_interface_fragment)(&frag, &rwalk->vtx, &rwalk->hit, rwalk->hit_side); + XD(setup_interface_fragment) + (&frag, &rwalk->vtx, &rwalk->XD(hit), rwalk->hit_side); - fX(normalize)(rwalk->hit.normal, rwalk->hit.normal); + fX(normalize)(rwalk->XD(hit).normal, rwalk->XD(hit).normal); /* Retrieve the current interface */ - interf = scene_get_interface(scn, rwalk->hit.prim.prim_id); + interf = scene_get_interface(scn, rwalk->XD(hit).prim.prim_id); /* Check if the boundary temperature is known */ tmp = interface_side_get_temperature(interf, &frag); @@ -82,6 +135,32 @@ XD(boundary_path) } if(res != RES_OK) goto error; +#if 1 + if(T->done) goto exit; + + /* Handling limit boundary condition, i.e. the trajectory originates from a + * boundary and the medium temperature is known (e.g. Robin's condition). To + * simplify data description, we allow in such a situation, to define several + * medium on the same enclosure, each with a fixed temperature, i.e. different + * conditions are defined for the different interfaces that detour the + * enclosure. As a result, no path can be sampled in this enclosure, which is + * beyond the system boundary. The boundary medium must therefore be + * interrogated from the interface. + * + * Note that we check this boundary condition with convective paths to handle + * Robin's boundary conditions. But we also make this check when passing + * through conduction when there's no reason why a solid should have a fixed + * temperature and not its boundary: it should be a Dirichlet condition. + * Although it's not physical, such systems can still be defined + * computationally, and in fact it's also a handy way of testing + * border cases */ + if(T->func == XD(convective_path) || T->func == XD(conductive_path)) { + res = XD(handle_known_medium_temperature)(scn, ctx, rwalk, T); + if(res != RES_OK) goto error; + if(T->done) goto exit; /* That's all folks */ + } +#endif + exit: return res; error: @@ -89,4 +168,3 @@ error: } #include "sdis_Xd_end.h" - diff --git a/src/sdis_heat_path_boundary_Xd_c.h b/src/sdis_heat_path_boundary_Xd_c.h @@ -26,18 +26,18 @@ #include "sdis_Xd_begin.h" struct XD(find_reinjection_ray_args) { - const struct sdis_medium* solid; /* Medium into which the reinjection occurs */ - const struct XD(rwalk)* rwalk; /* Current random walk state */ + const struct rwalk* rwalk; /* Current random walk state */ float dir0[DIM]; /* Challenged ray direction */ float dir1[DIM]; /* Challenged ray direction */ double distance; /* Maximum reinjection distance */ + unsigned solid_enc_id; /* Enclosure id into which the reinjection occurs */ /* Define if the random walk position can be moved or not to find a valid * reinjection direction */ int can_move; }; static const struct XD(find_reinjection_ray_args) -XD(FIND_REINJECTION_RAY_ARGS_NULL) = { NULL, NULL, {0}, {0}, 0, 0 }; +XD(FIND_REINJECTION_RAY_ARGS_NULL) = { NULL, {0}, {0}, 0, ENCLOSURE_ID_NULL, 0 }; struct XD(reinjection_ray) { double org[DIM]; /* Origin of the reinjection */ @@ -55,80 +55,150 @@ XD(REINJECTION_RAY_NULL) = { {0}, {0}, 0, SXD_HIT_NULL__, 0 }; /******************************************************************************* * Helper functions ******************************************************************************/ -static INLINE int +static INLINE res_T XD(check_find_reinjection_ray_args) - (const struct XD(find_reinjection_ray_args)* args) + (struct sdis_scene* scn, + const struct XD(find_reinjection_ray_args)* args) { - return args - && args->solid - && args->rwalk - && args->distance > 0 - && fX(is_normalized)(args->dir0) - && fX(is_normalized)(args->dir1); + const struct enclosure* enc = NULL; + struct sdis_medium* mdm = NULL; + res_T res = RES_OK; + ASSERT(scn); + + /* Check pointers */ + if(!args || !args->rwalk) return RES_BAD_ARG; + + /* Check distance */ + if(args->distance <= 0) return RES_BAD_ARG; + + /* Check directions */ + if(!fX(is_normalized)(args->dir0) || !fX(is_normalized)(args->dir1)) { + return RES_BAD_ARG; + } + + /* Check enclosure id */ + if(args->solid_enc_id == ENCLOSURE_ID_NULL) { + return RES_BAD_ARG; + } + enc = scene_get_enclosure(scn, args->solid_enc_id); + + /* Check the enclosure */ + enc = scene_get_enclosure(scn, args->solid_enc_id); + if(enc->medium_id != MEDIUM_ID_MULTI) { + if((res = scene_get_enclosure_medium(scn, enc, &mdm)) != RES_OK) return res; + if(sdis_medium_get_type(mdm) != SDIS_SOLID) { + res = RES_BAD_ARG; + } + } + + return RES_OK; } -static INLINE int +static INLINE res_T XD(check_sample_reinjection_step_args) - (const struct XD(sample_reinjection_step_args)* args) + (struct sdis_scene* scn, + const struct sample_reinjection_step_args* args) { - return args - && args->rng - && args->solid - && args->solid->type == SDIS_SOLID - && args->rwalk - && args->distance > 0 - && (unsigned)args->side < SDIS_SIDE_NULL__; + const struct enclosure* enc = NULL; + struct sdis_medium* mdm = NULL; + res_T res = RES_OK; + ASSERT(scn); + + /* Check pointers */ + if(!args || !args->rng || !args->rwalk) return RES_BAD_ARG; + + /* Check distance */ + if(args->distance <= 0) return RES_BAD_ARG; + + /* Check side */ + if((unsigned)args->side >= SDIS_SIDE_NULL__) return RES_BAD_ARG; + + /* Check enclosure id */ + if(args->solid_enc_id == ENCLOSURE_ID_NULL) { + return RES_BAD_ARG; + } + + /* Check the enclosure */ + enc = scene_get_enclosure(scn, args->solid_enc_id); + if(enc->medium_id != MEDIUM_ID_MULTI) { + if((res = scene_get_enclosure_medium(scn, enc, &mdm)) != RES_OK) return res; + if(sdis_medium_get_type(mdm) != SDIS_SOLID) { + return RES_BAD_ARG; + } + } + + return RES_OK; } -static INLINE int -XD(check_reinjection_step)(const struct XD(reinjection_step)* step) +static INLINE res_T +XD(check_reinjection_step)(const struct reinjection_step* step) { - return step - && fX(is_normalized)(step->direction) - && step->distance > 0; + /* Check pointer */ + if(!step) return RES_BAD_ARG; + + /* Check direction */ + if(!fX(is_normalized)(step->direction)) return RES_BAD_ARG; + + /* Check distance */ + if(step->distance <= 0) return RES_BAD_ARG; + + return RES_OK; } -static INLINE int -XD(check_solid_reinjection_args)(const struct XD(solid_reinjection_args)* args) +static INLINE res_T +XD(check_solid_reinjection_args)(const struct solid_reinjection_args* args) { - return args - && XD(check_reinjection_step)(args->reinjection) - && args->rng - && args->rwalk - && args->rwalk_ctx - && args->T - && args->fp_to_meter > 0; + /* Check pointers */ + if(!args || !args->rng || !args->rwalk || !args->rwalk_ctx || !args->T) + return RES_BAD_ARG; + + /* Check unit */ + if(args->fp_to_meter <= 0) return RES_BAD_ARG; + + return XD(check_reinjection_step)(args->reinjection); } /* Check that the interface fragment is consistent with the current state of * the random walk */ -static INLINE int +static INLINE res_T XD(check_rwalk_fragment_consistency) - (const struct XD(rwalk)* rwalk, + (const struct rwalk* rwalk, const struct sdis_interface_fragment* frag) { double N[DIM]; double uv[2] = {0, 0}; ASSERT(rwalk && frag); - dX(normalize)(N, dX_set_fX(N, rwalk->hit.normal)); - if( SXD_HIT_NONE(&rwalk->hit) - || !dX(eq_eps)(rwalk->vtx.P, frag->P, 1.e-6) - || !dX(eq_eps)(N, frag->Ng, 1.e-6) - || !( (IS_INF(rwalk->vtx.time) && IS_INF(frag->time)) - || eq_eps(rwalk->vtx.time, frag->time, 1.e-6))) { - return 0; + + /* Check intersection */ + if(SXD_HIT_NONE(&rwalk->XD(hit))) return RES_BAD_ARG; + + /* Check positions */ + if(!dX(eq_eps)(rwalk->vtx.P, frag->P, 1.e-6)) return RES_BAD_ARG; + + /* Check normals */ + dX(normalize)(N, dX_set_fX(N, rwalk->XD(hit).normal)); + if(!dX(eq_eps)(N, frag->Ng, 1.e-6)) return RES_BAD_ARG; + + /* Check time */ + if(!eq_eps(rwalk->vtx.time, frag->time, 1.e-6) + && !(IS_INF(rwalk->vtx.time) && IS_INF(frag->time))) { + return RES_BAD_ARG; } + + /* Check parametric coordinates */ #if (SDIS_XD_DIMENSION == 2) - uv[0] = rwalk->hit.u; + uv[0] = rwalk->XD(hit).u; #else - d2_set_f2(uv, rwalk->hit.uv); + d2_set_f2(uv, rwalk->XD(hit).uv); #endif - return d2_eq_eps(uv, frag->uv, 1.e-6); + if(!d2_eq_eps(uv, frag->uv, 1.e-6)) return RES_BAD_ARG; + + return RES_OK; } static void XD(sample_reinjection_dir) - (const struct XD(rwalk)* rwalk, + (const struct rwalk* rwalk, struct ssp_rng* rng, float dir[DIM]) { @@ -145,15 +215,15 @@ XD(sample_reinjection_dir) * discard the sqrt(2)/2 constant. */ const uint64_t r = ssp_rng_uniform_uint64(rng, 0, 1); ASSERT(rwalk && rng && dir); - ASSERT(!SXD_HIT_NONE(&rwalk->hit)); - ASSERT(!rwalk->mdm); + ASSERT(!SXD_HIT_NONE(&rwalk->XD(hit))); + ASSERT(rwalk->enc_id == ENCLOSURE_ID_NULL); if(r) { - dir[0] = rwalk->hit.normal[0] - rwalk->hit.normal[1]; - dir[1] = rwalk->hit.normal[0] + rwalk->hit.normal[1]; + dir[0] = rwalk->XD(hit).normal[0] - rwalk->XD(hit).normal[1]; + dir[1] = rwalk->XD(hit).normal[0] + rwalk->XD(hit).normal[1]; } else { - dir[0] = rwalk->hit.normal[0] + rwalk->hit.normal[1]; - dir[1] =-rwalk->hit.normal[0] + rwalk->hit.normal[1]; + dir[0] = rwalk->XD(hit).normal[0] + rwalk->XD(hit).normal[1]; + dir[1] =-rwalk->XD(hit).normal[0] + rwalk->XD(hit).normal[1]; } f2_normalize(dir, dir); #else @@ -162,17 +232,17 @@ XD(sample_reinjection_dir) * radius of its base is 1. */ float frame[9]; ASSERT(rwalk && rng && dir); - ASSERT(!SXD_HIT_NONE(&rwalk->hit)); - ASSERT(!rwalk->mdm); - ASSERT(fX(is_normalized)(rwalk->hit.normal)); + ASSERT(!SXD_HIT_NONE(&rwalk->XD(hit))); + ASSERT(rwalk->enc_id == ENCLOSURE_ID_NULL); + ASSERT(fX(is_normalized)(rwalk->XD(hit).normal)); ssp_ran_circle_uniform_float(rng, dir, NULL); dir[2] = (float)(1.0/sqrt(2)); - f33_basis(frame, rwalk->hit.normal); + f33_basis(frame, rwalk->XD(hit).normal); f33_mulf3(dir, frame, dir); f3_normalize(dir, dir); - ASSERT(eq_epsf(f3_dot(dir, rwalk->hit.normal), (float)(1.0/sqrt(3)), 1.e-4f)); + ASSERT(eq_epsf(f3_dot(dir, rwalk->XD(hit).normal), (float)(1.0/sqrt(3)), 1.e-4f)); #endif } @@ -180,7 +250,7 @@ XD(sample_reinjection_dir) #if DIM == 2 static void XD(move_away_primitive_boundaries) - (const struct XD(rwalk)* rwalk, + (const struct rwalk* rwalk, const double delta, double position[DIM]) /* Position to move */ { @@ -189,9 +259,9 @@ XD(move_away_primitive_boundaries) float dir[DIM]; float len; const float st = 0.5f; - ASSERT(rwalk && !SXD_HIT_NONE(&rwalk->hit) && delta > 0); + ASSERT(rwalk && !SXD_HIT_NONE(&rwalk->XD(hit)) && delta > 0); - SXD(primitive_get_attrib(&rwalk->hit.prim, SXD_POSITION, st, &attr)); + SXD(primitive_get_attrib(&rwalk->XD(hit).prim, SXD_POSITION, st, &attr)); fX_set_dX(pos, position); fX(sub)(dir, attr.value, pos); @@ -205,7 +275,7 @@ XD(move_away_primitive_boundaries) * numerical issues leading to inconsistent random walks. */ static void XD(move_away_primitive_boundaries) - (const struct XD(rwalk)* rwalk, + (const struct rwalk* rwalk, const double delta, double position[DIM]) { @@ -222,14 +292,14 @@ XD(move_away_primitive_boundaries) int imin = 0; int imid = 0; int i; - ASSERT(rwalk && delta > 0 && !S3D_HIT_NONE(&rwalk->hit)); + ASSERT(rwalk && delta > 0 && !S3D_HIT_NONE(&rwalk->XD(hit))); fX_set_dX(P, position); /* Fetch triangle vertices */ - S3D(triangle_get_vertex_attrib(&rwalk->hit.prim, 0, S3D_POSITION, &v0)); - S3D(triangle_get_vertex_attrib(&rwalk->hit.prim, 1, S3D_POSITION, &v1)); - S3D(triangle_get_vertex_attrib(&rwalk->hit.prim, 2, S3D_POSITION, &v2)); + S3D(triangle_get_vertex_attrib(&rwalk->XD(hit).prim, 0, S3D_POSITION, &v0)); + S3D(triangle_get_vertex_attrib(&rwalk->XD(hit).prim, 1, S3D_POSITION, &v1)); + S3D(triangle_get_vertex_attrib(&rwalk->XD(hit).prim, 2, S3D_POSITION, &v2)); /* Compute the edge vector */ f3_sub(E[0], v1.value, v0.value); @@ -315,10 +385,10 @@ XD(find_reinjection_ray) /* # attempts to find a ray direction */ int MAX_ATTEMPTS = 1; - /* Physical properties */ - struct sdis_interface* interf; - struct sdis_medium* mdm0; - struct sdis_medium* mdm1; + /* Enclosures */ + unsigned enc_ids[2] = {ENCLOSURE_ID_NULL, ENCLOSURE_ID_NULL}; + unsigned enc0_id = ENCLOSURE_ID_NULL; + unsigned enc1_id = ENCLOSURE_ID_NULL; struct hit_filter_data filter_data = HIT_FILTER_DATA_NULL; struct sXd(hit) hit; @@ -338,7 +408,7 @@ XD(find_reinjection_ray) res_T res = RES_OK; ASSERT(scn && args && ray); - ASSERT(XD(check_find_reinjection_ray_args)(args)); + ASSERT(XD(check_find_reinjection_ray_args)(scn, args) == RES_OK); *ray = XD(REINJECTION_RAY_NULL); MAX_ATTEMPTS = args->can_move ? 2 : 1; @@ -350,39 +420,39 @@ XD(find_reinjection_ray) do { fX_set_dX(org, ray->org); - filter_data.XD(hit) = args->rwalk->hit; + filter_data.XD(hit) = args->rwalk->XD(hit); filter_data.epsilon = args->distance * 0.01; SXD(scene_view_trace_ray (scn->sXd(view), org, args->dir0, range, &filter_data, &hit0)); SXD(scene_view_trace_ray (scn->sXd(view), org, args->dir1, range, &filter_data, &hit1)); - /* Retrieve the medium at the reinjection pos along dir0 */ - if(SXD_HIT_NONE(&hit0)) { + /* Retrieve the enclosure at the reinjection pos along dir0 */ + if(!SXD_HIT_NONE(&hit0)) { + scene_get_enclosure_ids(scn, hit0.prim.prim_id, enc_ids); + side = fX(dot)(args->dir0, hit0.normal) < 0 ? SDIS_FRONT : SDIS_BACK; + enc0_id = enc_ids[side]; + } else { XD(move_pos)(dX(set)(tmp, ray->org), args->dir0, (float)args->distance); - res = scene_get_medium_in_closed_boundaries(scn, tmp, &mdm0); - if(res == RES_BAD_OP) { mdm0 = NULL; res = RES_OK; } + res = scene_get_enclosure_id_in_closed_boundaries(scn, tmp, &enc0_id); + if(res == RES_BAD_OP) { enc0_id = ENCLOSURE_ID_NULL; res = RES_OK; } if(res != RES_OK) goto error; - } else { - interf = scene_get_interface(scn, hit0.prim.prim_id); - side = fX(dot)(args->dir0, hit0.normal) < 0 ? SDIS_FRONT : SDIS_BACK; - mdm0 = interface_get_medium(interf, side); } - /* Retrieve the medium at the reinjection pos along dir1 */ - if(SXD_HIT_NONE(&hit1)) { + /* Retrieve the enclosure at the reinjection pos along dir1 */ + if(!SXD_HIT_NONE(&hit1)) { + scene_get_enclosure_ids(scn, hit1.prim.prim_id, enc_ids); + side = fX(dot)(args->dir1, hit1.normal) < 0 ? SDIS_FRONT : SDIS_BACK; + enc1_id = enc_ids[side]; + } else { XD(move_pos)(dX(set)(tmp, ray->org), args->dir1, (float)args->distance); - res = scene_get_medium_in_closed_boundaries(scn, tmp, &mdm1); - if(res == RES_BAD_OP) { mdm1 = NULL; res = RES_OK; } + res = scene_get_enclosure_id_in_closed_boundaries(scn, tmp, &enc1_id); + if(res == RES_BAD_OP) { enc1_id = ENCLOSURE_ID_NULL; res = RES_OK; } if(res != RES_OK) goto error; - } else { - interf = scene_get_interface(scn, hit1.prim.prim_id); - side = fX(dot)(args->dir1, hit1.normal) < 0 ? SDIS_FRONT : SDIS_BACK; - mdm1 = interface_get_medium(interf, side); } dst0 = dst1 = -1; - if(mdm0 == args->solid) { /* Check reinjection consistency */ + if(enc0_id == args->solid_enc_id) { /* Check reinjection consistency */ if(hit0.distance <= dst_adjusted) { dst0 = hit0.distance; } else { @@ -390,7 +460,7 @@ XD(find_reinjection_ray) hit0 = SXD_HIT_NULL; } } - if(mdm1 == args->solid) { /* Check reinjection consistency */ + if(enc1_id == args->solid_enc_id) { /* Check reinjection consistency */ if(hit1.distance <= dst_adjusted) { dst1 = hit1.distance; } else { @@ -503,23 +573,25 @@ XD(find_reinjection_ray_and_check_validity) struct XD(reinjection_ray)* ray) { double pos[DIM]; - struct sdis_medium* reinject_mdm; res_T res = RES_OK; ASSERT(scn && args && ray); - ASSERT(XD(check_find_reinjection_ray_args)(args)); + ASSERT(XD(check_find_reinjection_ray_args)(scn, args) == RES_OK); /* Select a reinjection direction */ res = XD(find_reinjection_ray)(scn, args, ray); if(res != RES_OK) goto error; if(SXD_HIT_NONE(&ray->hit)) { - /* Check medium consistency at the reinjection position */ + unsigned enc_id = ENCLOSURE_ID_NULL; + + /* Obtain the enclosure in which the reinjection position lies */ XD(move_pos)(dX(set)(pos, ray->org), ray->dir, (float)ray->dst); - res = scene_get_medium_in_closed_boundaries(scn, pos, &reinject_mdm); + res = scene_get_enclosure_id_in_closed_boundaries(scn, pos, &enc_id); if(res != RES_OK) goto error; - if(reinject_mdm != args->solid) { + /* Check enclosure consistency at the reinjection position */ + if(enc_id != args->solid_enc_id) { res = RES_BAD_OP; goto error; } @@ -535,9 +607,9 @@ static res_T XD(handle_volumic_power) (struct sdis_medium* solid, struct rwalk_context* rwalk_ctx, - struct XD(rwalk)* rwalk, + struct rwalk* rwalk, const double reinject_dst_m, - struct XD(temperature)* T) + struct temperature* T) { double power; double lambda; @@ -592,22 +664,22 @@ error: res_T XD(sample_reinjection_step_solid_fluid) (struct sdis_scene* scn, - const struct XD(sample_reinjection_step_args)* args, - struct XD(reinjection_step)* step) + const struct sample_reinjection_step_args* args, + struct reinjection_step* step) { /* Input/output data of the function finding a valid reinjection ray */ struct XD(find_reinjection_ray_args) find_reinject_ray_args = XD(FIND_REINJECTION_RAY_ARGS_NULL); struct XD(reinjection_ray) ray = XD(REINJECTION_RAY_NULL); + /* Enclosures */ + const struct enclosure* solid_enc = NULL; + unsigned enc_ids[2] = {ENCLOSURE_ID_NULL, ENCLOSURE_ID_NULL}; + /* In 2D it is useless to try to resample a reinjection direction since there * is only one possible direction */ const int MAX_ATTEMPTS = DIM == 2 ? 1 : 10; - /* Enclosure */ - const struct enclosure* solid_enclosure = NULL; - unsigned enc_ids[2]; - /* Miscellaneous variables */ float dir0[DIM]; /* Sampled direction */ float dir1[DIM]; /* Sampled direction reflected */ @@ -616,23 +688,23 @@ XD(sample_reinjection_step_solid_fluid) /* Pre-conditions */ ASSERT(scn && args && step); - ASSERT(XD(check_sample_reinjection_step_args)(args)); + ASSERT(XD(check_sample_reinjection_step_args)(scn, args) == RES_OK); /* Initialise the reinjection step */ - *step = XD(REINJECTION_STEP_NULL); + *step = REINJECTION_STEP_NULL; /* Check whether the solid enclosure is part of the system, or whether it is * only there to describe boundary conditions. In the latter case, the * enclosure has no geometrical existence and it is sufficient to return a * valid reinjection step which will be used to select the next step. Note * that if the trajectory passes through the solid enclosure, it will stop, - * i.e. the temperature of the solid should be fixed. If it doesn't, it's an + * i.e. the temperature of the solid should be fixed. If it doesn't, it's a * error */ - scene_get_enclosure_ids(scn, args->rwalk->hit.prim.prim_id, enc_ids); - solid_enclosure = scene_get_enclosure(scn, enc_ids[args->side]); - if(solid_enclosure->medium_id == ENCLOSURE_MULTI_MEDIA) { - step->hit = SXD_HIT_NULL; - fX(normalize)(step->direction, args->rwalk->hit.normal); + scene_get_enclosure_ids(scn, args->rwalk->XD(hit).prim.prim_id, enc_ids); + solid_enc = scene_get_enclosure(scn, enc_ids[args->side]); + if(solid_enc->medium_id == MEDIUM_ID_MULTI) { + step->XD(hit) = SXD_HIT_NULL; + fX(normalize)(step->direction, args->rwalk->XD(hit).normal); if(args->side == SDIS_BACK) fX(minus)(step->direction, step->direction); step->distance = (float)args->distance; goto exit; /* That's all folks! */ @@ -644,7 +716,7 @@ XD(sample_reinjection_step_solid_fluid) XD(sample_reinjection_dir)(args->rwalk, args->rng, dir0); /* Reflect the sampled direction around the normal */ - XD(reflect)(dir1, dir0, args->rwalk->hit.normal); + XD(reflect)(dir1, dir0, args->rwalk->XD(hit).normal); /* Flip the sampled directions if one wants to reinject to back side */ if(args->side == SDIS_BACK) { @@ -653,7 +725,7 @@ XD(sample_reinjection_step_solid_fluid) } /* Find the reinjection step */ - find_reinject_ray_args.solid = args->solid; + find_reinject_ray_args.solid_enc_id = args->solid_enc_id; find_reinject_ray_args.rwalk = args->rwalk; find_reinject_ray_args.distance = args->distance; find_reinject_ray_args.can_move = 1; @@ -676,7 +748,7 @@ XD(sample_reinjection_step_solid_fluid) } /* Setup the reinjection step */ - step->hit = ray.hit; + step->XD(hit) = ray.hit; step->distance = ray.dst; fX(set)(step->direction, ray.dir); @@ -687,7 +759,7 @@ XD(sample_reinjection_step_solid_fluid) /* Post-conditions */ ASSERT(dX(eq)(args->rwalk->vtx.P, ray.org)); - ASSERT(XD(check_reinjection_step)(step)); + ASSERT(XD(check_reinjection_step)(step) == RES_OK); exit: return res; @@ -698,10 +770,10 @@ error: res_T XD(sample_reinjection_step_solid_solid) (struct sdis_scene* scn, - const struct XD(sample_reinjection_step_args)* args_frt, - const struct XD(sample_reinjection_step_args)* args_bck, - struct XD(reinjection_step)* step_frt, - struct XD(reinjection_step)* step_bck) + const struct sample_reinjection_step_args* args_frt, + const struct sample_reinjection_step_args* args_bck, + struct reinjection_step* step_frt, + struct reinjection_step* step_bck) { /* Input/output data of the function finding a valid reinjection ray */ struct XD(find_reinjection_ray_args) find_reinject_ray_frt_args = @@ -715,7 +787,7 @@ XD(sample_reinjection_step_solid_solid) double rwalk_pos_backup[DIM]; /* Variables shared by the two side */ - struct XD(rwalk)* rwalk = NULL; + struct rwalk* rwalk = NULL; struct ssp_rng* rng = NULL; /* In 2D it is useless to try to resample a reinjection direction since there @@ -723,26 +795,26 @@ XD(sample_reinjection_step_solid_solid) const int MAX_ATTEMPTS = DIM == 2 ? 1 : 10; /* Enclosure */ - const struct enclosure* enclosure_bck = NULL; - const struct enclosure* enclosure_frt = NULL; - int multiple_media_bck = 0; - int multiple_media_frt = 0; unsigned enc_ids[2]; + const struct enclosure* enc_frt = NULL; + const struct enclosure* enc_bck = NULL; float dir_frt_samp[DIM]; /* Sampled direction */ float dir_frt_refl[DIM]; /* Sampled direction reflected */ float dir_bck_samp[DIM]; /* Negated sampled direction */ float dir_bck_refl[DIM]; /* Negated sampled direction reflected */ + int multi_frt = 0; + int multi_bck = 0; int iattempt = 0; /* #attempts to find a reinjection dir */ res_T res = RES_OK; /* Pre-conditions */ ASSERT(scn && args_frt && args_bck && step_frt && step_bck); - ASSERT(XD(check_sample_reinjection_step_args)(args_frt)); - ASSERT(XD(check_sample_reinjection_step_args)(args_bck)); + ASSERT(XD(check_sample_reinjection_step_args)(scn, args_frt) == RES_OK); + ASSERT(XD(check_sample_reinjection_step_args)(scn, args_bck) == RES_OK); ASSERT(args_frt->side == SDIS_FRONT); ASSERT(args_bck->side == SDIS_BACK); - ASSERT(SXD_PRIMITIVE_EQ(&args_frt->rwalk->hit.prim, &args_bck->rwalk->hit.prim)); + ASSERT(SXD_PRIMITIVE_EQ(&args_frt->rwalk->XD(hit).prim, &args_bck->rwalk->XD(hit).prim)); rng = args_frt->rng; rwalk = args_frt->rwalk; @@ -750,8 +822,8 @@ XD(sample_reinjection_step_solid_solid) ASSERT(args_bck->rwalk == rwalk); /* Initialise the reinjection steps */ - *step_frt = XD(REINJECTION_STEP_NULL); - *step_bck = XD(REINJECTION_STEP_NULL); + *step_frt = REINJECTION_STEP_NULL; + *step_bck = REINJECTION_STEP_NULL; /* Check whether the solid enclosure is part of the system, or whether it is * only there to describe boundary conditions. In the latter case, the @@ -760,25 +832,23 @@ XD(sample_reinjection_step_solid_solid) * that if the trajectory passes through the solid enclosure, it will stop, * i.e. the temperature of the solid should be fixed. If it doesn't, it's an * error */ - scene_get_enclosure_ids(scn, args_frt->rwalk->hit.prim.prim_id, enc_ids); - enclosure_frt = scene_get_enclosure(scn, enc_ids[SDIS_FRONT]); - enclosure_bck = scene_get_enclosure(scn, enc_ids[SDIS_BACK]); - if(enclosure_frt->medium_id == ENCLOSURE_MULTI_MEDIA) { - step_frt->hit = SXD_HIT_NULL; - fX(normalize)(step_frt->direction, args_frt->rwalk->hit.normal); + scene_get_enclosure_ids(scn, args_frt->rwalk->XD(hit).prim.prim_id, enc_ids); + enc_frt = scene_get_enclosure(scn, enc_ids[SDIS_FRONT]); + enc_bck = scene_get_enclosure(scn, enc_ids[SDIS_BACK]); + if(enc_frt->medium_id == MEDIUM_ID_MULTI) { + step_frt->XD(hit) = SXD_HIT_NULL; + fX(normalize)(step_frt->direction, args_frt->rwalk->XD(hit).normal); step_frt->distance = (float)args_frt->distance; - multiple_media_frt = 1; + multi_frt = 1; } - if(enclosure_bck->medium_id == ENCLOSURE_MULTI_MEDIA) { - step_bck->hit = SXD_HIT_NULL; - fX(normalize)(step_bck->direction, args_bck->rwalk->hit.normal); - fX(minus)(step_bck->direction, step_bck->direction); + if(enc_bck->medium_id == MEDIUM_ID_MULTI) { + step_bck->XD(hit) = SXD_HIT_NULL; + fX(normalize)(step_bck->direction, args_bck->rwalk->XD(hit).normal); step_bck->distance = (float)args_bck->distance; - multiple_media_bck = 1; + multi_bck = 1; } - if(multiple_media_frt && multiple_media_bck) - goto exit; /* That's all folks! */ + if(multi_frt && multi_bck) goto exit; /* That's all folks */ dX(set)(rwalk_pos_backup, rwalk->vtx.P); iattempt = 0; @@ -789,16 +859,15 @@ XD(sample_reinjection_step_solid_solid) /* Sample a reinjection direction and reflect it around the normal. Then * reflect them on the back side of the interface. */ XD(sample_reinjection_dir)(rwalk, rng, dir_frt_samp); - XD(reflect)(dir_frt_refl, dir_frt_samp, rwalk->hit.normal); + XD(reflect)(dir_frt_refl, dir_frt_samp, rwalk->XD(hit).normal); fX(minus)(dir_bck_samp, dir_frt_samp); fX(minus)(dir_bck_refl, dir_frt_refl); /* Reject the sampling of the re-injection step if it has already been * defined, i.e. if the enclosure is a limit condition */ - if(!multiple_media_frt) { - + if(!multi_frt) { /* Find the reinjection ray for the front side */ - find_reinject_ray_frt_args.solid = args_frt->solid; + find_reinject_ray_frt_args.solid_enc_id = args_frt->solid_enc_id; find_reinject_ray_frt_args.rwalk = args_frt->rwalk; find_reinject_ray_frt_args.distance = args_frt->distance; find_reinject_ray_frt_args.can_move = 1; @@ -815,10 +884,9 @@ XD(sample_reinjection_step_solid_solid) /* Reject the sampling of the re-injection step if it has already been * defined, i.e. if the enclosure is a limit condition */ - if(!multiple_media_bck) { - + if(!multi_bck) { /* Select the reinjection direction and distance for the back side */ - find_reinject_ray_bck_args.solid = args_bck->solid; + find_reinject_ray_bck_args.solid_enc_id = args_bck->solid_enc_id; find_reinject_ray_bck_args.rwalk = args_bck->rwalk; find_reinject_ray_bck_args.distance = args_bck->distance; find_reinject_ray_bck_args.can_move = 1; @@ -834,7 +902,7 @@ XD(sample_reinjection_step_solid_solid) /* If random walk was moved to find a valid rinjection ray on back side, * one has to find a valid reinjection on front side from the new pos */ - if(ray_bck.position_was_moved && !multiple_media_frt) { + if(ray_bck.position_was_moved) { find_reinject_ray_frt_args.can_move = 0; res = XD(find_reinjection_ray_and_check_validity) (scn, &find_reinject_ray_frt_args, &ray_frt); @@ -858,17 +926,17 @@ XD(sample_reinjection_step_solid_solid) } /* Setup the front and back reinjection steps */ - if(!multiple_media_frt) { - step_frt->hit = ray_frt.hit; + if(!multi_frt) { + step_frt->XD(hit) = ray_frt.hit; step_frt->distance = ray_frt.dst; fX(set)(step_frt->direction, ray_frt.dir); - ASSERT(XD(check_reinjection_step)(step_frt)); /* Post-condition */ + ASSERT(XD(check_reinjection_step)(step_frt) == RES_OK); /* Post-condition */ } - if(!multiple_media_bck) { - step_bck->hit = ray_bck.hit; + if(!multi_bck) { + step_bck->XD(hit) = ray_bck.hit; step_bck->distance = ray_bck.dst; fX(set)(step_bck->direction, ray_bck.dir); - ASSERT(XD(check_reinjection_step)(step_bck)); /* Post-condition */ + ASSERT(XD(check_reinjection_step)(step_bck) == RES_OK); /* Post-condition */ } exit: @@ -879,17 +947,28 @@ error: res_T XD(solid_reinjection) - (struct sdis_medium* solid, - struct XD(solid_reinjection_args)* args) + (struct sdis_scene* scn, + const unsigned solid_enc_id, + struct solid_reinjection_args* args) { + /* Properties */ struct solid_props props = SOLID_PROPS_NULL; + struct sdis_medium* solid = NULL; + const struct enclosure* enc = NULL; + double reinject_dst_m; /* Reinjection distance in meters */ double mu; res_T res = RES_OK; - ASSERT(solid && XD(check_solid_reinjection_args)(args)); + ASSERT(XD(check_solid_reinjection_args)(args) == RES_OK); + ASSERT(solid_enc_id != ENCLOSURE_ID_NULL); reinject_dst_m = args->reinjection->distance * args->fp_to_meter; + /* Get the enclosure medium properties */ + enc = scene_get_enclosure(scn, solid_enc_id); + res = scene_get_enclosure_medium(scn, enc, &solid); + if(res != RES_OK) goto error; + ASSERT(sdis_medium_get_type(solid) == SDIS_SOLID); res = solid_get_properties(solid, &args->rwalk->vtx, &props); if(res != RES_OK) goto error; @@ -899,10 +978,10 @@ XD(solid_reinjection) if(res != RES_OK) goto error; /* Time rewind */ - args->rwalk->mdm = solid; /* Medium into which the time is rewind */ + args->rwalk->enc_id = solid_enc_id; /* Enclosure into which the time is rewind */ mu = (2*DIM*props.lambda)/(props.rho*props.cp*reinject_dst_m*reinject_dst_m); - res = XD(time_rewind) - (mu, props.t0, args->rng, args->rwalk, args->rwalk_ctx, args->T); + res = time_rewind + (scn, mu, props.t0, args->rng, args->rwalk, args->rwalk_ctx, args->T); if(res != RES_OK) goto error; /* Test if a limit condition was reached */ @@ -915,18 +994,18 @@ XD(solid_reinjection) args->reinjection->distance); /* The random walk is in the solid */ - if(args->reinjection->hit.distance != args->reinjection->distance) { + if(args->reinjection->XD(hit).distance != args->reinjection->distance) { args->T->func = XD(conductive_path); - args->rwalk->mdm = solid; - args->rwalk->hit = SXD_HIT_NULL; + args->rwalk->enc_id = solid_enc_id; + args->rwalk->XD(hit) = SXD_HIT_NULL; args->rwalk->hit_side = SDIS_SIDE_NULL__; /* The random walk is at a boundary */ } else { args->T->func = XD(boundary_path); - args->rwalk->mdm = NULL; - args->rwalk->hit = args->reinjection->hit; - if(fX(dot)(args->reinjection->hit.normal, args->reinjection->direction) < 0) { + args->rwalk->enc_id = ENCLOSURE_ID_NULL; + args->rwalk->XD(hit) = args->reinjection->XD(hit); + if(fX(dot)(args->reinjection->XD(hit).normal, args->reinjection->direction) < 0) { args->rwalk->hit_side = SDIS_FRONT; } else { args->rwalk->hit_side = SDIS_BACK; @@ -952,7 +1031,7 @@ res_T XD(handle_net_flux) (const struct sdis_scene* scn, const struct handle_net_flux_args* args, - struct XD(temperature)* T) + struct temperature* T) { double flux_term; double phi; @@ -1013,7 +1092,7 @@ XD(check_Tref) if((Bound) < 0) { \ log_err(scn->dev, \ "%s: the "Name" temperature cannot be negative " \ - "to sample a radiative path (T"Name" = %g K).\n", \ + "to sample a radiative path -- T"Name" = %g K\n", \ func_name, (Bound)); \ return RES_BAD_OP_IRRECOVERABLE; \ } \ @@ -1032,7 +1111,7 @@ XD(check_Tref) if(SDIS_TEMPERATURE_IS_UNKNOWN(Tref)) { log_err(scn->dev, - "%s: the reference temperature is unknown at `"FORMAT_VECX". " + "%s: the reference temperature is unknown at ("FORMAT_VECX"). " "Sampling a radiative path requires a valid reference temperature field.\n", func_name, SPLITX(pos)); return RES_BAD_OP_IRRECOVERABLE; @@ -1040,7 +1119,7 @@ XD(check_Tref) if(Tref < 0) { log_err(scn->dev, - "%s: the reference temperature is negative at `"FORMAT_VECX" (Tref = %g K). " + "%s: the reference temperature is negative at ("FORMAT_VECX") and Tref = %g K. " "Sampling a radiative path requires a known, positive reference " "temperature field.\n", func_name, SPLITX(pos), Tref); @@ -1049,7 +1128,7 @@ XD(check_Tref) if(Tref < scn->tmin || scn->tmax < Tref) { log_err(scn->dev, - "%s: invalid reference temperature at `"FORMAT_VECX"' (Tref = %g K). " + "%s: invalid reference temperature at ("FORMAT_VECX") and Tref=%g K. " "It must be included in the provided temperature range " "(Tmin = %g K; Tmax = %g K)\n", func_name, SPLITX(pos), Tref, scn->tmin, scn->tmax); diff --git a/src/sdis_heat_path_boundary_Xd_handle_external_net_flux.h b/src/sdis_heat_path_boundary_Xd_handle_external_net_flux.h @@ -173,7 +173,7 @@ static INLINE res_T XD(check_handle_external_net_flux_args) (const struct sdis_scene* scn, const char* func_name, - const struct XD(handle_external_net_flux_args)* args) + const struct handle_external_net_flux_args* args) { int net_flux = 0; res_T res = RES_OK; @@ -181,7 +181,7 @@ XD(check_handle_external_net_flux_args) /* Handle bugs */ ASSERT(scn && func_name && args); ASSERT(args->interf && args->frag); - ASSERT(!SXD_HIT_NONE(args->hit)); + ASSERT(!SXD_HIT_NONE(args->XD(hit))); ASSERT(args->h_cond >= 0 && args->h_conv >= 0 && args->h_radi >= 0); ASSERT(args->h_cond + args->h_conv + args->h_radi > 0); @@ -453,8 +453,8 @@ res_T XD(handle_external_net_flux) (const struct sdis_scene* scn, struct ssp_rng* rng, - const struct XD(handle_external_net_flux_args)* args, - struct XD(temperature)* T) + const struct handle_external_net_flux_args* args, + struct temperature* T) { /* Terms to be registered in the green function */ struct sdis_green_external_flux_terms green = @@ -516,13 +516,13 @@ XD(handle_external_net_flux) * interface side */ cos_theta = d3_dot(N, src_sample.dir); if(cos_theta > 0) { - Ld = XD(direct_contribution)(scn, &src_sample, frag.P, args->hit); + Ld = XD(direct_contribution)(scn, &src_sample, frag.P, args->XD(hit)); incident_flux_direct = cos_theta * Ld / src_sample.pdf; /* [W/m^2] */ } /* Calculate the incident diffuse flux [W/m^2] */ res = XD(compute_incident_diffuse_flux) - (scn, rng, frag.P, N, frag.time, args->hit, &incident_flux_diffuse); + (scn, rng, frag.P, N, frag.time, args->XD(hit), &incident_flux_diffuse); if(res != RES_OK) goto error; /* Calculate the incident flux without the part scattered by the environment. diff --git a/src/sdis_heat_path_boundary_Xd_solid_fluid_picard1.h b/src/sdis_heat_path_boundary_Xd_solid_fluid_picard1.h @@ -31,8 +31,8 @@ static INLINE res_T XD(rwalk_get_Tref) (const struct sdis_scene* scn, - const struct XD(rwalk)* rwalk, - const struct XD(temperature)* T, + const struct rwalk* rwalk, + const struct temperature* T, double* out_Tref) { double Tref = SDIS_TEMPERATURE_NONE; @@ -52,16 +52,16 @@ XD(rwalk_get_Tref) } else { struct sdis_interface_fragment frag; struct sdis_interface* interf = NULL; - ASSERT(!SXD_HIT_NONE(&rwalk->hit)); + ASSERT(!SXD_HIT_NONE(&rwalk->XD(hit))); /* Fetch the interface where the random walk ends */ - interf = scene_get_interface(scn, rwalk->hit.prim.prim_id); + interf = scene_get_interface(scn, rwalk->XD(hit).prim.prim_id); ASSERT(rwalk->hit_side!=SDIS_FRONT || interf->medium_front->type==SDIS_FLUID); ASSERT(rwalk->hit_side!=SDIS_BACK || interf->medium_back->type==SDIS_FLUID); /* Fragment on the fluid side of the boundary onto which the rwalk ends */ XD(setup_interface_fragment) - (&frag, &rwalk->vtx, &rwalk->hit, rwalk->hit_side); + (&frag, &rwalk->vtx, &rwalk->XD(hit), rwalk->hit_side); Tref = interface_side_get_reference_temperature(interf, &frag); } @@ -85,30 +85,32 @@ XD(solid_fluid_boundary_picard1_path) (struct sdis_scene* scn, struct rwalk_context* ctx, const struct sdis_interface_fragment* frag, - struct XD(rwalk)* rwalk, + struct rwalk* rwalk, struct ssp_rng* rng, - struct XD(temperature)* T) + struct temperature* T) { /* Input argument used to handle the net flux */ struct handle_net_flux_args handle_net_flux_args = HANDLE_NET_FLUX_ARGS_NULL; /* Input argument used to handle the external net flux */ - struct XD(handle_external_net_flux_args) handle_external_net_flux_args = - XD(HANDLE_EXTERNAL_NET_FLUX_ARGS_NULL); + struct handle_external_net_flux_args handle_external_net_flux_args = + HANDLE_EXTERNAL_NET_FLUX_ARGS_NULL; /* Input/output arguments of the function used to sample a reinjection */ - struct XD(sample_reinjection_step_args) samp_reinject_step_args = - XD(SAMPLE_REINJECTION_STEP_ARGS_NULL); - struct XD(reinjection_step) reinject_step = - XD(REINJECTION_STEP_NULL); + struct sample_reinjection_step_args samp_reinject_step_args = + SAMPLE_REINJECTION_STEP_ARGS_NULL; + struct reinjection_step reinject_step = REINJECTION_STEP_NULL; /* Temperature and random walk state of the sampled radiative path */ - struct XD(temperature) T_s; - struct XD(rwalk) rwalk_s; + struct temperature T_s; + struct rwalk rwalk_s; /* Fragment on the fluid side of the boundary */ struct sdis_interface_fragment frag_fluid; + /* The enclosures split by the boundary */ + unsigned enc_ids[2] = {ENCLOSURE_ID_NULL, ENCLOSURE_ID_NULL}; + /* Data attached to the boundary */ struct sdis_interface* interf = NULL; struct sdis_medium* solid = NULL; @@ -136,10 +138,10 @@ XD(solid_fluid_boundary_picard1_path) res_T res = RES_OK; ASSERT(scn && rwalk && rng && T && ctx); - ASSERT(XD(check_rwalk_fragment_consistency)(rwalk, frag)); + ASSERT(XD(check_rwalk_fragment_consistency)(rwalk, frag) == RES_OK); /* Retrieve the solid and the fluid split by the boundary */ - interf = scene_get_interface(scn, rwalk->hit.prim.prim_id); + interf = scene_get_interface(scn, rwalk->XD(hit).prim.prim_id); solid = interface_get_medium(interf, SDIS_FRONT); fluid = interface_get_medium(interf, SDIS_BACK); solid_side = SDIS_FRONT; @@ -150,6 +152,9 @@ XD(solid_fluid_boundary_picard1_path) ASSERT(fluid->type == SDIS_FLUID); } + /* Get the enclosures split by the boundary */ + scene_get_enclosure_ids(scn, rwalk->XD(hit).prim.prim_id, enc_ids); + /* Setup a fragment for the fluid side */ frag_fluid = *frag; frag_fluid.side = fluid_side; @@ -178,7 +183,7 @@ XD(solid_fluid_boundary_picard1_path) /* Sample a reinjection step */ samp_reinject_step_args.rng = rng; - samp_reinject_step_args.solid = solid; + samp_reinject_step_args.solid_enc_id = enc_ids[solid_side]; samp_reinject_step_args.rwalk = rwalk; samp_reinject_step_args.distance = delta_boundary; samp_reinject_step_args.side = solid_side; @@ -222,7 +227,7 @@ XD(solid_fluid_boundary_picard1_path) /* Handle the external net flux if any */ handle_external_net_flux_args.interf = interf; handle_external_net_flux_args.frag = frag; - handle_external_net_flux_args.hit = &rwalk->hit; + handle_external_net_flux_args.XD(hit) = &rwalk->XD(hit); handle_external_net_flux_args.green_path = ctx->green_path; handle_external_net_flux_args.picard_order = get_picard_order(ctx); handle_external_net_flux_args.h_cond = h_cond; @@ -248,15 +253,15 @@ XD(solid_fluid_boundary_picard1_path) /* Switch in convective path */ if(r < p_conv) { T->func = XD(convective_path); - rwalk->mdm = fluid; + rwalk->enc_id = enc_ids[fluid_side]; rwalk->hit_side = fluid_side; break; } /* Switch in conductive path */ if(r < p_conv + p_cond) { - struct XD(solid_reinjection_args) solid_reinject_args = - XD(SOLID_REINJECTION_ARGS_NULL); + struct solid_reinjection_args solid_reinject_args = + SOLID_REINJECTION_ARGS_NULL; /* Perform the reinjection into the solid */ solid_reinject_args.reinjection = &reinject_step; @@ -265,7 +270,7 @@ XD(solid_fluid_boundary_picard1_path) solid_reinject_args.rng = rng; solid_reinject_args.T = T; solid_reinject_args.fp_to_meter = scn->fp_to_meter; - res = XD(solid_reinjection)(solid, &solid_reinject_args); + res = XD(solid_reinjection)(scn, enc_ids[solid_side], &solid_reinject_args); if(res != RES_OK) goto error; break; } @@ -282,7 +287,7 @@ XD(solid_fluid_boundary_picard1_path) /* Sample a radiative path and get the Tref at its end. */ T_s = *T; rwalk_s = *rwalk; - rwalk_s.mdm = fluid; + rwalk_s.enc_id = enc_ids[fluid_side]; rwalk_s.hit_side = fluid_side; res = XD(radiative_path)(scn, ctx, &rwalk_s, rng, &T_s); if(res != RES_OK) goto error; diff --git a/src/sdis_heat_path_boundary_Xd_solid_fluid_picardN.h b/src/sdis_heat_path_boundary_Xd_solid_fluid_picardN.h @@ -66,23 +66,23 @@ error: static INLINE res_T XD(sample_path) (struct sdis_scene* scn, - const struct XD(rwalk)* rwalk_from, + const struct rwalk* rwalk_from, struct rwalk_context* ctx, struct ssp_rng* rng, - struct XD(temperature)* T) + struct temperature* T) { - struct XD(rwalk) rwalk = XD(RWALK_NULL); + struct rwalk rwalk = RWALK_NULL; res_T res = RES_OK; ASSERT(rwalk_from && rng && T); /* Clean-up the output variable */ - *T = XD(TEMPERATURE_NULL); + *T = TEMPERATURE_NULL; T->func = XD(boundary_path); /* Init the random walk */ rwalk.vtx = rwalk_from->vtx; - rwalk.mdm = rwalk_from->mdm; - rwalk.hit = rwalk_from->hit; + rwalk.enc_id = rwalk_from->enc_id; + rwalk.XD(hit) = rwalk_from->XD(hit); rwalk.hit_side = rwalk_from->hit_side; /* Start the registration of a new heat path */ @@ -128,15 +128,14 @@ XD(solid_fluid_boundary_picardN_path) (struct sdis_scene* scn, struct rwalk_context* ctx, const struct sdis_interface_fragment* frag, - struct XD(rwalk)* rwalk, + struct rwalk* rwalk, struct ssp_rng* rng, - struct XD(temperature)* T) + struct temperature* T) { /* Input/output arguments of the function used to sample a reinjection */ - struct XD(sample_reinjection_step_args) samp_reinject_step_args = - XD(SAMPLE_REINJECTION_STEP_ARGS_NULL); - struct XD(reinjection_step) reinject_step = - XD(REINJECTION_STEP_NULL); + struct sample_reinjection_step_args samp_reinject_step_args = + SAMPLE_REINJECTION_STEP_ARGS_NULL; + struct reinjection_step reinject_step = REINJECTION_STEP_NULL; /* Fragment on the fluid side of the boundary */ struct sdis_interface_fragment frag_fluid; @@ -145,6 +144,9 @@ XD(solid_fluid_boundary_picardN_path) struct sdis_heat_vertex hvtx = SDIS_HEAT_VERTEX_NULL; struct sdis_heat_vertex hvtx_s = SDIS_HEAT_VERTEX_NULL; + /* The enclosures split by the boundary */ + unsigned enc_ids[2] = {ENCLOSURE_ID_NULL, ENCLOSURE_ID_NULL}; + /* Data attached to the boundary */ struct sdis_interface* interf = NULL; struct sdis_medium* solid = NULL; @@ -172,8 +174,7 @@ XD(solid_fluid_boundary_picardN_path) res_T res = RES_OK; ASSERT(scn && rwalk && rng && T && ctx); - ASSERT(XD(check_rwalk_fragment_consistency)(rwalk, frag)); - + ASSERT(XD(check_rwalk_fragment_consistency)(rwalk, frag) == RES_OK); /* Fetch the Min/max temperature */ Tmin = ctx->Tmin; @@ -184,7 +185,7 @@ XD(solid_fluid_boundary_picardN_path) That3 = ctx->That3; /* Retrieve the solid and the fluid split by the boundary */ - interf = scene_get_interface(scn, rwalk->hit.prim.prim_id); + interf = scene_get_interface(scn, rwalk->XD(hit).prim.prim_id); solid = interface_get_medium(interf, SDIS_FRONT); fluid = interface_get_medium(interf, SDIS_BACK); solid_side = SDIS_FRONT; @@ -195,6 +196,9 @@ XD(solid_fluid_boundary_picardN_path) ASSERT(fluid->type == SDIS_FLUID); } + /* Get the enclosures split by the boundary */ + scene_get_enclosure_ids(scn, rwalk->XD(hit).prim.prim_id, enc_ids); + /* Check that no net flux is set for this interface since the provided * picardN algorithm does not handle it */ res = check_net_flux(scn, interf, frag, get_picard_order(ctx)); @@ -219,7 +223,7 @@ XD(solid_fluid_boundary_picardN_path) /* Sample a reinjection step */ samp_reinject_step_args.rng = rng; - samp_reinject_step_args.solid = solid; + samp_reinject_step_args.solid_enc_id = enc_ids[solid_side]; samp_reinject_step_args.rwalk = rwalk; samp_reinject_step_args.distance = delta_boundary; samp_reinject_step_args.side = solid_side; @@ -256,8 +260,8 @@ XD(solid_fluid_boundary_picardN_path) /* Null collision main loop */ for(;;) { /* Temperature and random walk state of the sampled radiative path */ - struct XD(temperature) T_s; - struct XD(rwalk) rwalk_s; + struct temperature T_s; + struct rwalk rwalk_s; double h_radi, h_radi_min, h_radi_max; /* Radiative coefficients */ double p_radi, p_radi_min, p_radi_max; /* Radiative probas */ @@ -272,15 +276,15 @@ XD(solid_fluid_boundary_picardN_path) /* Switch in convective path */ if(r < p_conv) { T->func = XD(convective_path); - rwalk->mdm = fluid; + rwalk->enc_id = enc_ids[fluid_side]; rwalk->hit_side = fluid_side; break; } /* Switch in conductive path */ if(r < p_conv + p_cond) { - struct XD(solid_reinjection_args) solid_reinject_args = - XD(SOLID_REINJECTION_ARGS_NULL); + struct solid_reinjection_args solid_reinject_args = + SOLID_REINJECTION_ARGS_NULL; /* Perform the reinjection into the solid */ solid_reinject_args.reinjection = &reinject_step; @@ -289,7 +293,7 @@ XD(solid_fluid_boundary_picardN_path) solid_reinject_args.rng = rng; solid_reinject_args.T = T; solid_reinject_args.fp_to_meter = scn->fp_to_meter; - res = XD(solid_reinjection)(solid, &solid_reinject_args); + res = XD(solid_reinjection)(scn, enc_ids[solid_side], &solid_reinject_args); if(res != RES_OK) goto error; break; } @@ -303,7 +307,7 @@ XD(solid_fluid_boundary_picardN_path) /* Sample a radiative path */ T_s = *T; rwalk_s = *rwalk; - rwalk_s.mdm = fluid; + rwalk_s.enc_id = enc_ids[fluid_side]; rwalk_s.hit_side = fluid_side; res = XD(radiative_path)(scn, ctx, &rwalk_s, rng, &T_s); if(res != RES_OK) goto error; @@ -340,9 +344,9 @@ XD(solid_fluid_boundary_picardN_path) } (void)0 #define COMPUTE_TEMPERATURE(Result, RWalk, Temp) { \ - struct XD(temperature) T_p; \ + struct temperature T_p; \ if((Temp)->done) { /* Ambient radiative temperature */ \ - ASSERT(SXD_HIT_NONE(&(RWalk)->hit)); \ + ASSERT(SXD_HIT_NONE(&(RWalk)->XD(hit))); \ T_p = *(Temp); \ } else { \ res = XD(sample_path)(scn, RWalk, ctx, rng, &T_p); \ diff --git a/src/sdis_heat_path_boundary_Xd_solid_solid.h b/src/sdis_heat_path_boundary_Xd_solid_solid.h @@ -33,28 +33,29 @@ XD(solid_solid_boundary_path) (struct sdis_scene* scn, struct rwalk_context* ctx, const struct sdis_interface_fragment* frag, - struct XD(rwalk)* rwalk, + struct rwalk* rwalk, struct ssp_rng* rng, - struct XD(temperature)* T) + struct temperature* T) { /* Input/output arguments of the function used to sample a reinjection */ - struct XD(sample_reinjection_step_args) samp_reinject_step_frt_args = - XD(SAMPLE_REINJECTION_STEP_ARGS_NULL); - struct XD(sample_reinjection_step_args) samp_reinject_step_bck_args = - XD(SAMPLE_REINJECTION_STEP_ARGS_NULL); - struct XD(reinjection_step) reinject_step_frt = XD(REINJECTION_STEP_NULL); - struct XD(reinjection_step) reinject_step_bck = XD(REINJECTION_STEP_NULL); - struct XD(reinjection_step)* reinject_step = NULL; + struct sample_reinjection_step_args samp_reinject_step_frt_args = + SAMPLE_REINJECTION_STEP_ARGS_NULL; + struct sample_reinjection_step_args samp_reinject_step_bck_args = + SAMPLE_REINJECTION_STEP_ARGS_NULL; + struct reinjection_step reinject_step_frt = REINJECTION_STEP_NULL; + struct reinjection_step reinject_step_bck = REINJECTION_STEP_NULL; + struct reinjection_step* reinject_step = NULL; /* Reinjection arguments */ - struct XD(solid_reinjection_args) solid_reinject_args = - XD(SOLID_REINJECTION_ARGS_NULL); + struct solid_reinjection_args solid_reinject_args = + SOLID_REINJECTION_ARGS_NULL; /* Data attached to the boundary */ + unsigned enc_ids[2] = {ENCLOSURE_ID_NULL, ENCLOSURE_ID_NULL}; struct sdis_interface* interf = NULL; struct sdis_medium* solid_frt = NULL; struct sdis_medium* solid_bck = NULL; - struct sdis_medium* solid = NULL; + unsigned solid_enc_id = ENCLOSURE_ID_NULL; /* Solid to re-inject */ double lambda_frt; double lambda_bck; @@ -67,11 +68,12 @@ XD(solid_solid_boundary_path) res_T res = RES_OK; ASSERT(scn && ctx && frag && rwalk && rng && T); - ASSERT(XD(check_rwalk_fragment_consistency)(rwalk, frag)); + ASSERT(XD(check_rwalk_fragment_consistency)(rwalk, frag) == RES_OK); (void)frag, (void)ctx; - /* Retrieve the two solids split by the boundary */ - interf = scene_get_interface(scn, rwalk->hit.prim.prim_id); + /* Retrieve the two enclosures and associated media split by the boundary */ + scene_get_enclosure_ids(scn, rwalk->XD(hit).prim.prim_id, enc_ids); + interf = scene_get_interface(scn, rwalk->XD(hit).prim.prim_id); solid_frt = interface_get_medium(interf, SDIS_FRONT); solid_bck = interface_get_medium(interf, SDIS_BACK); ASSERT(solid_frt->type == SDIS_SOLID); @@ -93,8 +95,8 @@ XD(solid_solid_boundary_path) /* Sample a front/back reinjection steps */ samp_reinject_step_frt_args.rng = rng; samp_reinject_step_bck_args.rng = rng; - samp_reinject_step_frt_args.solid = solid_frt; - samp_reinject_step_bck_args.solid = solid_bck; + samp_reinject_step_frt_args.solid_enc_id = enc_ids[SDIS_FRONT]; + samp_reinject_step_bck_args.solid_enc_id = enc_ids[SDIS_BACK]; samp_reinject_step_frt_args.rwalk = rwalk; samp_reinject_step_bck_args.rwalk = rwalk; samp_reinject_step_frt_args.distance = delta_boundary_frt; @@ -102,7 +104,7 @@ XD(solid_solid_boundary_path) samp_reinject_step_frt_args.side = SDIS_FRONT; samp_reinject_step_bck_args.side = SDIS_BACK; res = XD(sample_reinjection_step_solid_solid) - (scn, + (scn, &samp_reinject_step_frt_args, &samp_reinject_step_bck_args, &reinject_step_frt, @@ -150,10 +152,10 @@ XD(solid_solid_boundary_path) if(r < proba) { /* Reinject in front */ reinject_step = &reinject_step_frt; - solid = solid_frt; + solid_enc_id = enc_ids[SDIS_FRONT]; } else { /* Reinject in back */ reinject_step = &reinject_step_bck; - solid = solid_bck; + solid_enc_id = enc_ids[SDIS_BACK]; } /* Perform the reinjection into the solid */ @@ -163,7 +165,7 @@ XD(solid_solid_boundary_path) solid_reinject_args.rwalk_ctx = ctx; solid_reinject_args.T = T; solid_reinject_args.fp_to_meter = scn->fp_to_meter; - res = XD(solid_reinjection)(solid, &solid_reinject_args); + res = XD(solid_reinjection)(scn, solid_enc_id, &solid_reinject_args); if(res != RES_OK) goto error; exit: diff --git a/src/sdis_heat_path_boundary_c.h b/src/sdis_heat_path_boundary_c.h @@ -21,123 +21,92 @@ #include <rsys/rsys.h> /* Forward declarations */ -struct rwalk_2d; -struct rwalk_3d; +struct rwalk; struct sdis_scene; struct sdis_medium; /******************************************************************************* * Sample a reinjection step ******************************************************************************/ -struct sample_reinjection_step_args_2d { +struct sample_reinjection_step_args { struct ssp_rng* rng; /* Random number generator to use */ - const struct sdis_medium* solid; /* Solid in which to reinject */ - struct rwalk_2d* rwalk; /* Current state of the random walk */ + struct rwalk* rwalk; /* Current state of the random walk */ double distance; /* Maximum Reinjection distance */ + unsigned solid_enc_id; /* Enclosured Id of the solid in which to reinject */ enum sdis_side side; /* Side of the boundary to re-inject */ }; -struct sample_reinjection_step_args_3d { - struct ssp_rng* rng; /* Random number generator to use */ - const struct sdis_medium* solid; /* Medium in which to reinject */ - struct rwalk_3d* rwalk; /* Current random walk state */ - double distance; /* Maximum Reinjection distance */ - enum sdis_side side; /* Side of the boundary to re-inject */ -}; - -struct reinjection_step_2d { - struct s2d_hit hit; /* Intersection along the reinjection direction */ - float direction[2]; /* Reinjection direction */ - float distance; /* Reinjection distance */ -}; +#define SAMPLE_REINJECTION_STEP_ARGS_NULL__ \ + {NULL, NULL, -1, ENCLOSURE_ID_NULL, SDIS_SIDE_NULL__} +static const struct sample_reinjection_step_args +SAMPLE_REINJECTION_STEP_ARGS_NULL = SAMPLE_REINJECTION_STEP_ARGS_NULL__; -struct reinjection_step_3d { - struct s3d_hit hit; /* Intersection along the reinjection direction */ +struct reinjection_step { + struct s2d_hit hit_2d; /* 2D Intersection along the reinjection direction */ + struct s3d_hit hit_3d; /* 3D Intersection along the reinjection direction */ float direction[3]; /* Reinjection direction */ float distance; /* Reinjection distance */ }; -#define SAMPLE_REINJECTION_STEP_ARGS_NULL___2d \ - {NULL, NULL, NULL, -1, SDIS_SIDE_NULL__} -#define SAMPLE_REINJECTION_STEP_ARGS_NULL___3d \ - {NULL, NULL, NULL, -1, SDIS_SIDE_NULL__} -static const struct sample_reinjection_step_args_2d -SAMPLE_REINJECTION_STEP_ARGS_NULL_2d = SAMPLE_REINJECTION_STEP_ARGS_NULL___2d; -static const struct sample_reinjection_step_args_3d -SAMPLE_REINJECTION_STEP_ARGS_NULL_3d = SAMPLE_REINJECTION_STEP_ARGS_NULL___3d; - -#define REINJECTION_STEP_NULL___2d {S2D_HIT_NULL__, {0,0}, 0} -#define REINJECTION_STEP_NULL___3d {S3D_HIT_NULL__, {0,0,0}, 0} -static const struct reinjection_step_2d -REINJECTION_STEP_NULL_2d = REINJECTION_STEP_NULL___2d; -static const struct reinjection_step_3d -REINJECTION_STEP_NULL_3d = REINJECTION_STEP_NULL___3d; +#define REINJECTION_STEP_NULL__ {S2D_HIT_NULL__, S3D_HIT_NULL__, {0,0,0}, 0} +static const struct reinjection_step REINJECTION_STEP_NULL = + REINJECTION_STEP_NULL__; extern LOCAL_SYM res_T sample_reinjection_step_solid_fluid_2d (struct sdis_scene* scn, - const struct sample_reinjection_step_args_2d* args, - struct reinjection_step_2d* step); + const struct sample_reinjection_step_args* args, + struct reinjection_step* step); extern LOCAL_SYM res_T sample_reinjection_step_solid_fluid_3d (struct sdis_scene* scn, - const struct sample_reinjection_step_args_3d* args, - struct reinjection_step_3d *step); + const struct sample_reinjection_step_args* args, + struct reinjection_step *step); extern LOCAL_SYM res_T sample_reinjection_step_solid_solid_2d (struct sdis_scene* scn, - const struct sample_reinjection_step_args_2d* args_front, - const struct sample_reinjection_step_args_2d* args_back, - struct reinjection_step_2d* step_front, - struct reinjection_step_2d* step_back); + const struct sample_reinjection_step_args* args_front, + const struct sample_reinjection_step_args* args_back, + struct reinjection_step* step_front, + struct reinjection_step* step_back); extern LOCAL_SYM res_T sample_reinjection_step_solid_solid_3d (struct sdis_scene* scn, - const struct sample_reinjection_step_args_3d* args_front, - const struct sample_reinjection_step_args_3d* args_back, - struct reinjection_step_3d* step_front, - struct reinjection_step_3d* step_back); + const struct sample_reinjection_step_args* args_front, + const struct sample_reinjection_step_args* args_back, + struct reinjection_step* step_front, + struct reinjection_step* step_back); /******************************************************************************* * Reinject the random walk into a solid ******************************************************************************/ -struct solid_reinjection_args_2d { - const struct reinjection_step_2d* reinjection; /* Reinjection to do */ +struct solid_reinjection_args { + const struct reinjection_step* reinjection; /* Reinjection to do */ struct rwalk_context* rwalk_ctx; - struct rwalk_2d* rwalk; /* Current state of the random walk */ + struct rwalk* rwalk; /* Current state of the random walk */ struct ssp_rng* rng; /* Random number generator */ - struct temperature_2d* T; + struct temperature* T; double fp_to_meter; }; -struct solid_reinjection_args_3d { - const struct reinjection_step_3d* reinjection; /* Reinjection to do */ - struct rwalk_context* rwalk_ctx; - struct rwalk_3d* rwalk; /* Current state of the random walk */ - struct ssp_rng* rng; /* Random number generator */ - struct temperature_3d* T; - double fp_to_meter; -}; - -#define SOLID_REINJECTION_ARGS_NULL___2d {NULL,NULL,NULL,NULL,NULL,0} -#define SOLID_REINJECTION_ARGS_NULL___3d {NULL,NULL,NULL,NULL,NULL,0} -static const struct solid_reinjection_args_2d SOLID_REINJECTION_ARGS_NULL_2d = - SOLID_REINJECTION_ARGS_NULL___2d; -static const struct solid_reinjection_args_3d SOLID_REINJECTION_ARGS_NULL_3d = - SOLID_REINJECTION_ARGS_NULL___3d; +#define SOLID_REINJECTION_ARGS_NULL__ {NULL,NULL,NULL,NULL,NULL,0} +static const struct solid_reinjection_args SOLID_REINJECTION_ARGS_NULL = + SOLID_REINJECTION_ARGS_NULL__; extern LOCAL_SYM res_T solid_reinjection_2d - (struct sdis_medium* solid, - struct solid_reinjection_args_2d* args); + (struct sdis_scene* scn, + const unsigned solid_enc_id, + struct solid_reinjection_args* args); extern LOCAL_SYM res_T solid_reinjection_3d - (struct sdis_medium* solid, - struct solid_reinjection_args_3d* args); + (struct sdis_scene* scn, + const unsigned solid_enc_id, + struct solid_reinjection_args* args); /******************************************************************************* * Handle net flux @@ -160,21 +129,22 @@ extern LOCAL_SYM res_T handle_net_flux_2d (const struct sdis_scene* scn, const struct handle_net_flux_args* args, - struct temperature_2d* T); + struct temperature* T); extern LOCAL_SYM res_T handle_net_flux_3d (const struct sdis_scene* scn, const struct handle_net_flux_args* args, - struct temperature_3d* T); + struct temperature* T); /******************************************************************************* * Handle external flux ******************************************************************************/ -struct handle_external_net_flux_args_2d { +struct handle_external_net_flux_args { struct sdis_interface* interf; const struct sdis_interface_fragment* frag; - const struct s2d_hit* hit; + const struct s2d_hit* hit_2d; + const struct s3d_hit* hit_3d; struct green_path_handle* green_path; /* Store the propagator */ struct sdis_heat_path* heat_path; /* Save paths */ @@ -199,26 +169,23 @@ struct handle_external_net_flux_args_3d { double h_radi; /* Radiative coefficient */ }; -#define HANDLE_EXTERNAL_NET_FLUX_ARGS_NULL___2d {NULL,NULL,NULL,NULL,NULL,0,0,0,0} -#define HANDLE_EXTERNAL_NET_FLUX_ARGS_NULL___3d {NULL,NULL,NULL,NULL,NULL,0,0,0,0} -static const struct handle_external_net_flux_args_2d -HANDLE_EXTERNAL_NET_FLUX_ARGS_NULL_2d = HANDLE_EXTERNAL_NET_FLUX_ARGS_NULL___2d; -static const struct handle_external_net_flux_args_3d -HANDLE_EXTERNAL_NET_FLUX_ARGS_NULL_3d = HANDLE_EXTERNAL_NET_FLUX_ARGS_NULL___3d; +#define HANDLE_EXTERNAL_NET_FLUX_ARGS_NULL__ {NULL,NULL,NULL,NULL,NULL,NULL,0,0,0,0} +static const struct handle_external_net_flux_args +HANDLE_EXTERNAL_NET_FLUX_ARGS_NULL = HANDLE_EXTERNAL_NET_FLUX_ARGS_NULL__; extern LOCAL_SYM res_T handle_external_net_flux_2d (const struct sdis_scene* scn, struct ssp_rng* rng, - const struct handle_external_net_flux_args_2d* args, - struct temperature_2d* T); + const struct handle_external_net_flux_args* args, + struct temperature* T); extern LOCAL_SYM res_T handle_external_net_flux_3d (const struct sdis_scene* scn, struct ssp_rng* rng, - const struct handle_external_net_flux_args_3d* args, - struct temperature_3d* T); + const struct handle_external_net_flux_args* args, + struct temperature* T); /******************************************************************************* * Miscellaneous functions @@ -246,9 +213,9 @@ solid_boundary_with_flux_path_2d struct rwalk_context* ctx, const struct sdis_interface_fragment* frag, const double phi, - struct rwalk_2d* rwalk, + struct rwalk* rwalk, struct ssp_rng* rng, - struct temperature_2d* T); + struct temperature* T); extern LOCAL_SYM res_T solid_boundary_with_flux_path_3d @@ -256,62 +223,62 @@ solid_boundary_with_flux_path_3d struct rwalk_context* ctx, const struct sdis_interface_fragment* frag, const double phi, - struct rwalk_3d* rwalk, + struct rwalk* rwalk, struct ssp_rng* rng, - struct temperature_3d* T); + struct temperature* T); extern LOCAL_SYM res_T solid_fluid_boundary_picard1_path_2d (struct sdis_scene* scn, struct rwalk_context* ctx, const struct sdis_interface_fragment* frag, - struct rwalk_2d* rwalk, + struct rwalk* rwalk, struct ssp_rng* rng, - struct temperature_2d* T); + struct temperature* T); extern LOCAL_SYM res_T solid_fluid_boundary_picard1_path_3d (struct sdis_scene* scn, struct rwalk_context* ctx, const struct sdis_interface_fragment* frag, - struct rwalk_3d* rwalk, + struct rwalk* rwalk, struct ssp_rng* rng, - struct temperature_3d* T); + struct temperature* T); extern LOCAL_SYM res_T solid_fluid_boundary_picardN_path_2d (struct sdis_scene* scn, struct rwalk_context* ctx, const struct sdis_interface_fragment* frag, - struct rwalk_2d* rwalk, + struct rwalk* rwalk, struct ssp_rng* rng, - struct temperature_2d* T); + struct temperature* T); extern LOCAL_SYM res_T solid_fluid_boundary_picardN_path_3d (struct sdis_scene* scn, struct rwalk_context* ctx, const struct sdis_interface_fragment* frag, - struct rwalk_3d* rwalk, + struct rwalk* rwalk, struct ssp_rng* rng, - struct temperature_3d* T); + struct temperature* T); extern LOCAL_SYM res_T solid_solid_boundary_path_2d (struct sdis_scene* scn, struct rwalk_context* ctx, const struct sdis_interface_fragment* frag, - struct rwalk_2d* rwalk, + struct rwalk* rwalk, struct ssp_rng* rng, - struct temperature_2d* T); + struct temperature* T); extern LOCAL_SYM res_T solid_solid_boundary_path_3d (struct sdis_scene* scn, struct rwalk_context* ctx, const struct sdis_interface_fragment* frag, - struct rwalk_3d* rwalk, + struct rwalk* rwalk, struct ssp_rng* rng, - struct temperature_3d* T); + struct temperature* T); #endif /* SDIS_HEAT_PATH_BOUNDARY_C_H */ diff --git a/src/sdis_heat_path_conductive.c b/src/sdis_heat_path_conductive.c @@ -75,9 +75,9 @@ res_T conductive_path_2d (struct sdis_scene* scn, struct rwalk_context* ctx, - struct rwalk_2d* rwalk, + struct rwalk* rwalk, struct ssp_rng* rng, - struct temperature_2d* T) + struct temperature* T) { res_T res = RES_OK; ASSERT(ctx); @@ -98,9 +98,9 @@ res_T conductive_path_3d (struct sdis_scene* scn, struct rwalk_context* ctx, - struct rwalk_3d* rwalk, + struct rwalk* rwalk, struct ssp_rng* rng, - struct temperature_3d* T) + struct temperature* T) { res_T res = RES_OK; ASSERT(ctx); diff --git a/src/sdis_heat_path_conductive_c.h b/src/sdis_heat_path_conductive_c.h @@ -19,15 +19,13 @@ #include <rsys/rsys.h> /* Forward declarations */ -struct rwalk_2d; -struct rwalk_3d; +struct rwalk; struct rwalk_context; struct sdis_device; struct sdis_scene; struct solid_props; struct ssp_rng; -struct temperature_2d; -struct temperature_3d; +struct temperature; extern LOCAL_SYM res_T check_solid_constant_properties @@ -44,17 +42,17 @@ extern LOCAL_SYM res_T conductive_path_delta_sphere_2d (struct sdis_scene* scn, struct rwalk_context* ctx, - struct rwalk_2d* rwalk, + struct rwalk* rwalk, struct ssp_rng* rng, - struct temperature_2d* T); + struct temperature* T); extern LOCAL_SYM res_T conductive_path_delta_sphere_3d (struct sdis_scene* scn, struct rwalk_context* ctx, - struct rwalk_3d* rwalk, + struct rwalk* rwalk, struct ssp_rng* rng, - struct temperature_3d* T); + struct temperature* T); /******************************************************************************* * Conductive paths using the walk on sphere algorithm @@ -63,16 +61,16 @@ extern LOCAL_SYM res_T conductive_path_wos_2d (struct sdis_scene* scn, struct rwalk_context* ctx, - struct rwalk_2d* rwalk, + struct rwalk* rwalk, struct ssp_rng* rng, - struct temperature_2d* T); + struct temperature* T); extern LOCAL_SYM res_T conductive_path_wos_3d (struct sdis_scene* scn, struct rwalk_context* ctx, - struct rwalk_3d* rwalk, + struct rwalk* rwalk, struct ssp_rng* rng, - struct temperature_3d* T); + struct temperature* T); #endif /* SDIS_HEAT_PATH_CONDUCTIVE_C_H */ diff --git a/src/sdis_heat_path_conductive_delta_sphere_Xd.h b/src/sdis_heat_path_conductive_delta_sphere_Xd.h @@ -111,7 +111,7 @@ XD(sample_next_step) static res_T XD(sample_next_step_robust) (struct sdis_scene* scn, - struct sdis_medium* current_mdm, + const unsigned current_enc_id, struct ssp_rng* rng, const double pos[DIM], const float delta_solid, @@ -121,13 +121,14 @@ XD(sample_next_step_robust) struct sXd(hit)* hit1, /* Hit used to adjust delta */ float* out_delta) { - struct sdis_medium* mdm; + unsigned enc_id = ENCLOSURE_ID_NULL; float delta; float org[DIM]; const size_t MAX_ATTEMPTS = 100; size_t iattempt = 0; res_T res = RES_OK; - ASSERT(scn && current_mdm && rng && pos && delta_solid > 0); + ASSERT(scn && rng && pos && delta_solid > 0); + ASSERT(current_enc_id != ENCLOSURE_ID_NULL); ASSERT(dir0 && dir1 && hit0 && hit1 && out_delta); fX_set_dX(org, pos); @@ -141,44 +142,30 @@ XD(sample_next_step_robust) /* Retrieve the medium of the next step */ if(hit0->distance > delta) { XD(move_pos)(dX(set)(pos_next, pos), dir0, delta); - res = scene_get_medium_in_closed_boundaries(scn, pos_next, &mdm); - if(res == RES_BAD_OP) { mdm = NULL; res = RES_OK; } + res = scene_get_enclosure_id_in_closed_boundaries(scn, pos_next, &enc_id); + if(res == RES_BAD_OP) { enc_id = ENCLOSURE_ID_NULL; res = RES_OK; } if(res != RES_OK) goto error; } else { - struct sdis_interface* interf; - enum sdis_side side; - interf = scene_get_interface(scn, hit0->prim.prim_id); - side = fX(dot)(dir0, hit0->normal) < 0 ? SDIS_FRONT : SDIS_BACK; - mdm = interface_get_medium(interf, side); + unsigned enc_ids[2] = {ENCLOSURE_ID_NULL, ENCLOSURE_ID_NULL}; + scene_get_enclosure_ids(scn, hit0->prim.prim_id, enc_ids); + enc_id = fX(dot)(dir0, hit0->normal) < 0 ? enc_ids[0] : enc_ids[1]; } /* Check medium consistency */ - if(current_mdm != mdm) { + if(current_enc_id != enc_id) { #if 0 -#if DIM == 2 - log_warn(scn->dev, - "%s: inconsistent medium during the solid random walk at {%g, %g}.\n", - FUNC_NAME, SPLIT2(pos)); -#else log_warn(scn->dev, - "%s: inconsistent medium during the solid random walk at {%g, %g, %g}.\n", - FUNC_NAME, SPLIT3(pos)); -#endif + "%s: inconsistent medium during the solid random walk -- " + "pos=("FORMAT_VECX")\n", FUNC_NAME, SPLITX(pos)); #endif } - } while(current_mdm != mdm && ++iattempt < MAX_ATTEMPTS); + } while(current_enc_id != enc_id && ++iattempt < MAX_ATTEMPTS); /* Handle error */ if(iattempt >= MAX_ATTEMPTS) { -#if DIM == 2 - log_warn(scn->dev, - "%s: could not find a next valid conductive step at {%g, %g}.\n", - FUNC_NAME, SPLIT2(pos)); -#else log_warn(scn->dev, - "%s: could not find a next valid conductive step at {%g, %g, %g}.\n", - FUNC_NAME, SPLIT3(pos)); -#endif + "%s: could not find a next valid conductive -- pos=("FORMAT_VECX")\n", + FUNC_NAME, SPLITX(pos)); res = RES_BAD_OP; goto error; } @@ -239,7 +226,7 @@ XD(handle_volumic_power) (const struct sdis_scene* scn, const struct XD(handle_volumic_power_args)* args, double* out_power_term, - struct XD(temperature)* T) + struct temperature* T) { double power_term = 0; res_T res = RES_OK; @@ -332,28 +319,43 @@ res_T XD(conductive_path_delta_sphere) (struct sdis_scene* scn, struct rwalk_context* ctx, - struct XD(rwalk)* rwalk, + struct rwalk* rwalk, struct ssp_rng* rng, - struct XD(temperature)* T) + struct temperature* T) { - double position_start[DIM]; + /* Enclosure/medium in which the conductive path starts */ + struct sdis_medium* mdm = NULL; + unsigned enc_id = ENCLOSURE_ID_NULL; + + /* Physical properties */ struct solid_props props_ref = SOLID_PROPS_NULL; double green_power_term = 0; - struct sdis_medium* mdm; + + /* Miscellaneous */ + double position_start[DIM] = {0}; size_t istep = 0; /* Help for debug */ res_T res = RES_OK; + + /* Check pre-conditions */ ASSERT(scn && rwalk && rng && T); - ASSERT(rwalk->mdm->type == SDIS_SOLID); - (void)ctx, (void)istep; + + (void)ctx, (void)istep; /* Avoid "unsued variable" warnings */ + + res = scene_get_enclosure_id_in_closed_boundaries(scn, rwalk->vtx.P, &enc_id); + if(res != RES_OK) goto error; + res = scene_get_enclosure_medium(scn, scene_get_enclosure(scn, enc_id), &mdm); + if(res != RES_OK) goto error; + ASSERT(sdis_medium_get_type(mdm) == SDIS_SOLID); /* Check the random walk consistency */ - res = scene_get_medium_in_closed_boundaries(scn, rwalk->vtx.P, &mdm); - if(res != RES_OK || mdm != rwalk->mdm) { + if(enc_id != rwalk->enc_id) { log_err(scn->dev, "%s: invalid solid random walk. " - "Unexpected medium at {%g, %g, %g}.\n", FUNC_NAME, SPLIT3(rwalk->vtx.P)); + "Unexpected enclosure -- pos=("FORMAT_VECX")\n", + FUNC_NAME, SPLITX(rwalk->vtx.P)); res = RES_BAD_OP_IRRECOVERABLE; goto error; } + /* Save the submitted position */ dX(set)(position_start, rwalk->vtx.P); @@ -396,7 +398,7 @@ XD(conductive_path_delta_sphere) if(ctx->green_path) { res = green_path_set_limit_vertex - (ctx->green_path, rwalk->mdm, &rwalk->vtx, rwalk->elapsed_time); + (ctx->green_path, mdm, &rwalk->vtx, rwalk->elapsed_time); if(res != RES_OK) goto error; } @@ -410,7 +412,7 @@ XD(conductive_path_delta_sphere) fX_set_dX(org, rwalk->vtx.P); /* Sample the direction to walk toward and compute the distance to travel */ - res = XD(sample_next_step_robust)(scn, mdm, rng, rwalk->vtx.P, + res = XD(sample_next_step_robust)(scn, enc_id, rng, rwalk->vtx.P, (float)props.delta, dir0, dir1, &hit0, &hit1, &delta); if(res != RES_OK) goto error; @@ -436,16 +438,16 @@ XD(conductive_path_delta_sphere) /* Rewind the time */ delta_m = delta * scn->fp_to_meter; mu = (2*DIM*props.lambda)/(props.rho*props.cp*delta_m*delta_m); - res = XD(time_rewind)(mu, props.t0, rng, rwalk, ctx, T); + res = time_rewind(scn, mu, props.t0, rng, rwalk, ctx, T); if(res != RES_OK) goto error; if(T->done) break; /* Limit condition was reached */ /* Define if the random walk hits something along dir0 */ if(hit0.distance > delta) { - rwalk->hit = SXD_HIT_NULL; + rwalk->XD(hit) = SXD_HIT_NULL; rwalk->hit_side = SDIS_SIDE_NULL__; } else { - rwalk->hit = hit0; + rwalk->XD(hit) = hit0; rwalk->hit_side = fX(dot)(hit0.normal, dir0) < 0 ? SDIS_FRONT : SDIS_BACK; } @@ -460,17 +462,17 @@ XD(conductive_path_delta_sphere) ++istep; /* Keep going while the solid random walk does not hit an interface */ - } while(SXD_HIT_NONE(&rwalk->hit)); + } while(SXD_HIT_NONE(&rwalk->XD(hit))); /* Register the power term for the green function */ if(ctx->green_path && props_ref.power != SDIS_VOLUMIC_POWER_NONE) { res = green_path_add_power_term - (ctx->green_path, rwalk->mdm, &rwalk->vtx, green_power_term); + (ctx->green_path, mdm, &rwalk->vtx, green_power_term); if(res != RES_OK) goto error; } T->func = XD(boundary_path); - rwalk->mdm = NULL; /* The random walk is at an interface between 2 media */ + rwalk->enc_id = ENCLOSURE_ID_NULL; /* At the interface between 2 media */ exit: return res; diff --git a/src/sdis_heat_path_conductive_wos_Xd.h b/src/sdis_heat_path_conductive_wos_Xd.h @@ -23,24 +23,67 @@ #include "sdis_Xd_begin.h" /******************************************************************************* + * Non generic helper functions + ******************************************************************************/ +#ifndef SDIS_HEAT_PATH_CONDUCTIVE_WOS_XD_H +#define SDIS_HEAT_PATH_CONDUCTIVE_WOS_XD_H + +static res_T +update_green_path + (struct green_path_handle* green_path, + struct rwalk* rwalk, + struct sdis_medium* mdm, + const struct solid_props* props, + const double power_term, + const struct temperature* T) +{ + res_T res = RES_OK; + ASSERT(mdm && props && T); + + /* Is the green function estimated? */ + if(!green_path) goto exit; + + /* Save power term for green function if any */ + if(props->power != SDIS_VOLUMIC_POWER_NONE) { + res = green_path_add_power_term(green_path, mdm, &rwalk->vtx, power_term); + if(res != RES_OK) goto error; + } + + /* Set the green path limit to the current position if the initial condition + * has been reached */ + if(T->done) { + res = green_path_set_limit_vertex + (green_path, mdm, &rwalk->vtx, rwalk->elapsed_time); + if(res != RES_OK) goto error; + } + +exit: + return res; +error: + goto exit; +} + +#endif /* SDIS_HEAT_PATH_CONDUCTIVE_WOS_XD_H */ + +/******************************************************************************* * Helper function ******************************************************************************/ static res_T -XD(check_medium_consistency) +XD(check_enclosure_consistency) (struct sdis_scene* scn, - const struct XD(rwalk)* rwalk) + const struct rwalk* rwalk) { - struct sdis_medium* mdm = NULL; + unsigned enc_id = ENCLOSURE_ID_NULL; res_T res = RES_OK; ASSERT(rwalk); - res = scene_get_medium_in_closed_boundaries(scn, rwalk->vtx.P, &mdm); + res = scene_get_enclosure_id_in_closed_boundaries(scn, rwalk->vtx.P, &enc_id); if(res != RES_OK) goto error; - /* Check medium consistency */ - if(mdm != rwalk->mdm) { + /* Check enclosure consistency */ + if(enc_id != rwalk->enc_id) { log_err(scn->dev, - "%s:%s: invalid solid walk. Unexpected medium (position: "FORMAT_VECX").\n", + "%s:%s: invalid solid walk. Unexpected enclosure -- pos=("FORMAT_VECX")\n", __FILE__, FUNC_NAME, SPLITX(rwalk->vtx.P)); res = RES_BAD_OP_IRRECOVERABLE; goto error; @@ -55,12 +98,13 @@ error: static res_T XD(time_travel) (struct sdis_scene* scn, - struct XD(rwalk)* rwalk, + struct rwalk* rwalk, struct ssp_rng* rng, + struct sdis_medium* mdm, const double alpha, /* Diffusivity, i.e. lambda/(rho*cp) */ const double t0, /* Initial time [s] */ double* distance, /* Displacement [m/fp_to_meter] */ - struct XD(temperature)* T) + struct temperature* T) { double dir[DIM] = {0}; double dst = 0; /* Distance [m] */ @@ -120,14 +164,14 @@ XD(time_travel) dX(add)(rwalk->vtx.P, rwalk->vtx.P, dir); /* Fetch the initial temperature */ - temperature = medium_get_temperature(rwalk->mdm, &rwalk->vtx); + temperature = medium_get_temperature(mdm, &rwalk->vtx); if(SDIS_TEMPERATURE_IS_UNKNOWN(temperature)) { log_err(scn->dev, "%s:%s: the path reaches the initial condition but the " - "%s temperature remains unknown -- position=%g, %g, %g\n", + "%s temperature remains unknown -- pos=("FORMAT_VECX")\n", __FILE__, FUNC_NAME, - medium_type_to_string(sdis_medium_get_type(rwalk->mdm)), - SPLIT3(rwalk->vtx.P)); + medium_type_to_string(sdis_medium_get_type(mdm)), + SPLITX(rwalk->vtx.P)); res = RES_BAD_ARG; goto error; } @@ -142,6 +186,32 @@ error: goto exit; } +static res_T +XD(handle_volumic_power_wos) + (struct sdis_scene* scn, + const struct solid_props* props, + const double distance, /* [m/fp_to_meter] */ + double* power_term, + struct temperature* T) +{ + double dst = distance * scn->fp_to_meter; /* [m] */ + double term = 0; + res_T res = RES_OK; + ASSERT(scn && props && distance >= 0 && power_term && T); + + if(props->power == SDIS_VOLUMIC_POWER_NONE) goto exit; + + /* No displacement => no power density */ + if(distance == 0) goto exit; + + term = dst*dst / (2*DIM*props->lambda); + T->value += props->power * term; + +exit: + *power_term = term; + return res; +} + #if DIM == 2 static INLINE enum sdis_side compute_hit_side_2d @@ -203,16 +273,15 @@ compute_hit_side_3d } #endif -/* Verify that the submitted position is in the expected medium */ +/* Verify that the submitted position is in the expected enclosure */ static res_T XD(check_diffusion_position) (struct sdis_scene* scn, - const struct sdis_medium* expected_medium, + const unsigned expected_enc_id, const double pos[DIM]) { - struct sdis_interface* interf = NULL; - struct sdis_medium* mdm = NULL; - enum sdis_side side; + unsigned enc_ids[2] = {ENCLOSURE_ID_NULL, ENCLOSURE_ID_NULL}; + enum sdis_side side = SDIS_SIDE_NULL__; struct sXd(hit) hit = SXD_HIT_NULL; float wos_pos[DIM] = {0}; @@ -220,7 +289,8 @@ XD(check_diffusion_position) res_T res = RES_OK; /* Check pre-conditions */ - ASSERT(scn && expected_medium && pos); + ASSERT(scn && pos); + ASSERT(expected_enc_id != ENCLOSURE_ID_NULL); /* Look for the nearest surface within 1 mm of the position to be checked. By * limiting the search radius we speed up the closest point query. If no @@ -239,11 +309,10 @@ XD(check_diffusion_position) SXD(scene_view_closest_point(scn->sXd(view), wos_pos, wos_radius, NULL, &hit)); if(SXD_HIT_NONE(&hit)) goto exit; - /* Fetch interface properties and check path consistency */ - interf = scene_get_interface(scn, hit.prim.prim_id); + /* Check path consistency */ + scene_get_enclosure_ids(scn, hit.prim.prim_id, enc_ids); side = XD(compute_hit_side)(&hit, pos); - mdm = side == SDIS_FRONT ? interf->medium_front : interf->medium_back; - if(mdm != expected_medium) { + if(enc_ids[side] != expected_enc_id) { res = RES_BAD_ARG; goto error; } @@ -258,15 +327,14 @@ static res_T XD(setup_hit_wos) (struct sdis_scene* scn, const struct sXd(hit)* hit, - struct XD(rwalk)* rwalk) + struct rwalk* rwalk) { /* Geometry */ struct sXd(primitive) prim; struct sXd(attrib) attr; /* Properties */ - struct sdis_interface* interf = NULL; - struct sdis_medium* mdm = NULL; + unsigned enc_ids[2] = {ENCLOSURE_ID_NULL, ENCLOSURE_ID_NULL}; enum sdis_side side = SDIS_SIDE_NULL__; /* Miscellaneous */ @@ -288,13 +356,12 @@ XD(setup_hit_wos) dX_set_fX(tgt, attr.value); side = XD(compute_hit_side)(hit, rwalk->vtx.P); - /* Fetch interface properties and check path consistency */ - interf = scene_get_interface(scn, hit->prim.prim_id); - mdm = side == SDIS_FRONT ? interf->medium_front : interf->medium_back; - if(mdm != rwalk->mdm) { + /* Check path consistency */ + scene_get_enclosure_ids(scn, hit->prim.prim_id, enc_ids); + if(enc_ids[side] != rwalk->enc_id) { log_err(scn->dev, - "%s:%s: the conductive path has reached an invalid interface; " - "unexpected medium (position: "FORMAT_VECX"; side: %s).\n", + "%s:%s: the conductive path has reached an invalid interface. " + "Unexpected enclosure -- pos=("FORMAT_VECX"), side=%s\n", __FILE__, FUNC_NAME, SPLITX(tgt), side == SDIS_FRONT ? "front" : "back"); res = RES_BAD_OP_IRRECOVERABLE; goto error; @@ -305,7 +372,7 @@ XD(setup_hit_wos) * the interface. So we can't yet assume that the random walk has left the * current medium */ dX(set)(rwalk->vtx.P, tgt); - rwalk->hit = *hit; + rwalk->XD(hit) = *hit; rwalk->hit_side = side; exit: @@ -320,11 +387,10 @@ XD(setup_hit_rt) const double pos[DIM], const double dir[DIM], const struct sXd(hit)* hit, - struct XD(rwalk)* rwalk) + struct rwalk* rwalk) { /* Properties */ - struct sdis_interface* interf = NULL; - struct sdis_medium* mdm = NULL; + unsigned enc_ids[2] = {ENCLOSURE_ID_NULL, ENCLOSURE_ID_NULL}; enum sdis_side side = SDIS_SIDE_NULL__; /* Miscellaneous */ @@ -344,12 +410,11 @@ XD(setup_hit_rt) side = dX(dot)(N, dir) > 0 ? SDIS_BACK : SDIS_FRONT; /* Fetch interface properties and check path consistency */ - interf = scene_get_interface(scn, hit->prim.prim_id); - mdm = side == SDIS_FRONT ? interf->medium_front : interf->medium_back; - if(mdm != rwalk->mdm) { + scene_get_enclosure_ids(scn, hit->prim.prim_id, enc_ids); + if(enc_ids[side] != rwalk->enc_id) { log_err(scn->dev, - "%s:%s: the conductive path has reached an invalid interface; " - "unexpected medium (position: "FORMAT_VECX"; side: %s).\n", + "%s:%s: the conductive path has reached an invalid interface. " + "Unexpected enclosure -- pos=("FORMAT_VECX"), side=%s\n", __FILE__, FUNC_NAME, SPLITX(tgt), side == SDIS_FRONT ? "front" : "back"); res = RES_BAD_OP_IRRECOVERABLE; goto error; @@ -360,7 +425,7 @@ XD(setup_hit_rt) * the interface. So we can't yet assume that the random walk has left the * current medium */ dX(set)(rwalk->vtx.P, tgt); - rwalk->hit = *hit; + rwalk->XD(hit) = *hit; rwalk->hit_side = side; exit: @@ -372,7 +437,7 @@ error: static res_T XD(sample_next_position) (struct sdis_scene* scn, - struct XD(rwalk)* rwalk, + struct rwalk* rwalk, struct ssp_rng* rng, double* distance) /* Displacement distance */ { @@ -425,7 +490,7 @@ XD(sample_next_position) * The next diffusion step would then detect an error. This is why we use a * new function based on the same geometric operator used in the present * algorithm. */ - res = XD(check_diffusion_position)(scn, rwalk->mdm, pos); + res = XD(check_diffusion_position)(scn, rwalk->enc_id, pos); /* Diffusion position is valid => move the path to the new position */ if(res == RES_OK) { @@ -459,8 +524,8 @@ XD(sample_next_position) * we don't care to save it. */ if(SXD_HIT_NONE(&hit)) { log_err(scn->dev, - "%s:%s: unable to find the next diffusion position " - "(position: "FORMAT_VECX"; direction: "FORMAT_VECX"; distance: %g\n", + "%s:%s: unable to find the next diffusion position -- " + "position=("FORMAT_VECX"), direction=("FORMAT_VECX"), distance=%g\n", __FILE__, FUNC_NAME, SPLITX(pos), SPLITX(dir), wos_distance); res = RES_BAD_OP_IRRECOVERABLE; goto error; @@ -478,67 +543,6 @@ error: goto exit; } -static res_T -XD(handle_volumic_power_wos) - (struct sdis_scene* scn, - const struct solid_props* props, - const double distance, /* [m/fp_to_meter] */ - double* power_term, - struct XD(temperature)* T) -{ - double dst = distance * scn->fp_to_meter; /* [m] */ - double term = 0; - res_T res = RES_OK; - ASSERT(scn && props && distance >= 0 && power_term && T); - - if(props->power == SDIS_VOLUMIC_POWER_NONE) goto exit; - - /* No displacement => no power density */ - if(distance == 0) goto exit; - - term = dst*dst / (2*DIM*props->lambda); - T->value += props->power * term; - -exit: - *power_term = term; - return res; -} - -static res_T -XD(update_green_path) - (struct green_path_handle* green_path, - struct XD(rwalk)* rwalk, - struct sdis_medium* mdm, - const struct solid_props* props, - const double power_term, - const struct XD(temperature)* T) -{ - res_T res = RES_OK; - ASSERT(mdm && props && T); - - /* Is the green function estimated? */ - if(!green_path) goto exit; - - /* Save power term for green function if any */ - if(props->power != SDIS_VOLUMIC_POWER_NONE) { - res = green_path_add_power_term(green_path, mdm, &rwalk->vtx, power_term); - if(res != RES_OK) goto error; - } - - /* Set the green path limit to the current position if the initial condition - * has been reached */ - if(T->done) { - res = green_path_set_limit_vertex - (green_path, mdm, &rwalk->vtx, rwalk->elapsed_time); - if(res != RES_OK) goto error; - } - -exit: - return res; -error: - goto exit; -} - /******************************************************************************* * Local function ******************************************************************************/ @@ -546,11 +550,12 @@ res_T XD(conductive_path_wos) (struct sdis_scene* scn, struct rwalk_context* ctx, - struct XD(rwalk)* rwalk, + struct rwalk* rwalk, struct ssp_rng* rng, - struct XD(temperature)* T) + struct temperature* T) { /* Properties */ + const struct enclosure* enc = NULL; struct sdis_medium* mdm = NULL; struct solid_props props_ref = SOLID_PROPS_NULL; struct solid_props props = SOLID_PROPS_NULL; @@ -566,18 +571,18 @@ XD(conductive_path_wos) /* Check pre-conditions */ ASSERT(scn && ctx && rwalk && rng && T); - ASSERT(sdis_medium_get_type(rwalk->mdm) == SDIS_SOLID); /* Is green evaluated evaluated */ green = ctx->green_path != NULL; - /* Keep track of the solid. After conduction, a boundary may have been - * reached, so the random walk medium is NULL. However, this medium is still - * needed to update the green path. Hence this backup */ - mdm = rwalk->mdm; + res = XD(check_enclosure_consistency)(scn, rwalk); + if(res != RES_OK) goto error; - res = XD(check_medium_consistency)(scn, rwalk); + /* Get the enclosure medium */ + enc = scene_get_enclosure(scn, rwalk->enc_id); + res = scene_get_enclosure_medium(scn, enc, &mdm); if(res != RES_OK) goto error; + ASSERT(sdis_medium_get_type(mdm) == SDIS_SOLID); /* Retrieve the solid properties at the current position. Use them to verify * that those that are supposed to be constant by the conductive random walk @@ -588,7 +593,7 @@ XD(conductive_path_wos) * position. By comparing them to the properties along the random walk, we * thus verify that the properties are constant throughout the random walk * with respect to the properties of the reinjected position. */ - solid_get_properties(rwalk->mdm, &rwalk->vtx, &props_ref); + solid_get_properties(mdm, &rwalk->vtx, &props_ref); props = props_ref; /* The algorithm assumes that lambda, rho and cp are constants. The @@ -620,7 +625,7 @@ XD(conductive_path_wos) if(res != RES_OK) goto error; /* Going back in time */ - res = XD(time_travel)(scn, rwalk, rng, alpha, props.t0, &dst, T); + res = XD(time_travel)(scn, rwalk, rng, mdm, alpha, props.t0, &dst, T); if(res != RES_OK) goto error; /* Add the volumic power density */ @@ -639,16 +644,16 @@ XD(conductive_path_wos) } /* The path reaches a boundary */ - if(!SXD_HIT_NONE(&rwalk->hit)) { + if(!SXD_HIT_NONE(&rwalk->XD(hit))) { T->func = XD(boundary_path); - rwalk->mdm = NULL; + rwalk->enc_id = ENCLOSURE_ID_NULL; break; } #undef REGISTER_VERTEX /* Retreive and check solid properties at the new position */ - res = solid_get_properties(rwalk->mdm, &rwalk->vtx, &props); + res = solid_get_properties(mdm, &rwalk->vtx, &props); if(res != RES_OK) goto error; res = check_solid_constant_properties(scn->dev, green, wos, &props_ref, &props); if(res != RES_OK) goto error; @@ -657,7 +662,7 @@ XD(conductive_path_wos) } /* Save green function data */ - res = XD(update_green_path) + res = update_green_path (ctx->green_path, rwalk, mdm, &props_ref, green_power_term, T); exit: diff --git a/src/sdis_heat_path_convective_Xd.h b/src/sdis_heat_path_convective_Xd.h @@ -66,57 +66,19 @@ error: * Helper functions ******************************************************************************/ static res_T -XD(register_heat_vertex_in_fluid) - (struct sdis_scene* scn, - struct rwalk_context* ctx, - struct XD(rwalk)* rwalk, - const double weight) -{ - struct sdis_rwalk_vertex vtx = SDIS_RWALK_VERTEX_NULL; - struct hit_filter_data filter_data = HIT_FILTER_DATA_NULL; - const float empirical_dst = 0.1f; - const float range[2] = {0, FLT_MAX}; - float org[DIM]; - float dir[DIM]; - float pos[DIM]; - float dst; - struct sXd(hit) hit; - - if(!ctx->heat_path) return RES_OK; - - ASSERT(!SXD_HIT_NONE(&rwalk->hit)); - - fX_set_dX(org, rwalk->vtx.P); - fX(set)(dir, rwalk->hit.normal); - if(rwalk->hit_side == SDIS_BACK) fX(minus)(dir, dir); - - filter_data.XD(hit) = rwalk->hit; - filter_data.epsilon = 1.e-6; - SXD(scene_view_trace_ray(scn->sXd(view), org, dir, range, &filter_data, &hit)); - dst = SXD_HIT_NONE(&hit) ? empirical_dst : hit.distance * 0.5f; - - vtx = rwalk->vtx; - fX(add)(pos, org, fX(mulf)(dir, dir, dst)); - dX_set_fX(vtx.P, pos); - - return register_heat_vertex(ctx->heat_path, &vtx, weight, - SDIS_HEAT_VERTEX_CONVECTION, (int)ctx->nbranchings); -} - -static res_T XD(handle_known_fluid_temperature) - (struct sdis_scene* scn, - struct rwalk_context* ctx, - struct XD(rwalk)* rwalk, - struct XD(temperature)* T) + (struct rwalk_context* ctx, + struct rwalk* rwalk, + struct sdis_medium* mdm, + struct temperature* T) { double temperature; int known_temperature; res_T res = RES_OK; - ASSERT(scn && ctx && rwalk && T); - ASSERT(sdis_medium_get_type(rwalk->mdm) == SDIS_FLUID); + ASSERT(ctx && rwalk && T); + ASSERT(sdis_medium_get_type(mdm) == SDIS_FLUID); - temperature = fluid_get_temperature(rwalk->mdm, &rwalk->vtx); + temperature = fluid_get_temperature(mdm, &rwalk->vtx); /* Check if the temperature is known */ known_temperature = SDIS_TEMPERATURE_IS_KNOWN(temperature); @@ -127,12 +89,13 @@ XD(handle_known_fluid_temperature) if(ctx->green_path) { res = green_path_set_limit_vertex - (ctx->green_path, rwalk->mdm, &rwalk->vtx, rwalk->elapsed_time); + (ctx->green_path, mdm, &rwalk->vtx, rwalk->elapsed_time); if(res != RES_OK) goto error; } - res = XD(register_heat_vertex_in_fluid)(scn, ctx, rwalk, T->value); - if(res != RES_OK) goto error; + if(ctx->heat_path) { + heat_path_get_last_vertex(ctx->heat_path)->weight = T->value; + } exit: return res; @@ -143,7 +106,7 @@ error: static res_T XD(handle_convective_path_startup) (struct sdis_scene* scn, - struct XD(rwalk)* rwalk, + struct rwalk* rwalk, int* path_starts_in_fluid) { const float range[2] = {FLT_MIN, FLT_MAX}; @@ -151,9 +114,8 @@ XD(handle_convective_path_startup) float org[DIM] = {0}; res_T res = RES_OK; ASSERT(scn && rwalk && path_starts_in_fluid); - ASSERT(sdis_medium_get_type(rwalk->mdm) == SDIS_FLUID); - *path_starts_in_fluid = SXD_HIT_NONE(&rwalk->hit); + *path_starts_in_fluid = SXD_HIT_NONE(&rwalk->XD(hit)); if(*path_starts_in_fluid == 0) goto exit; /* Nothing to do */ dir[DIM-1] = 1; @@ -161,8 +123,8 @@ XD(handle_convective_path_startup) /* Init the path hit field required to define the current enclosure and * fetch the interface data */ - SXD(scene_view_trace_ray(scn->sXd(view), org, dir, range, NULL, &rwalk->hit)); - if(SXD_HIT_NONE(&rwalk->hit)) { + SXD(scene_view_trace_ray(scn->sXd(view), org, dir, range, NULL, &rwalk->XD(hit))); + if(SXD_HIT_NONE(&rwalk->XD(hit))) { log_err(scn->dev, "%s: the position %g %g %g lies in the surrounding fluid whose " "temperature must be known.\n", FUNC_NAME, SPLIT3(rwalk->vtx.P)); @@ -170,7 +132,8 @@ XD(handle_convective_path_startup) goto error; } - rwalk->hit_side = fX(dot)(rwalk->hit.normal, dir) < 0 ? SDIS_FRONT : SDIS_BACK; + rwalk->hit_side = fX(dot)(rwalk->XD(hit).normal, dir) < 0 + ? SDIS_FRONT : SDIS_BACK; exit: return res; @@ -179,54 +142,28 @@ error: } static res_T -XD(fetch_fluid_enclosure) +XD(check_enclosure) (struct sdis_scene* scn, - struct XD(rwalk)* rwalk, - const struct enclosure** out_enclosure) + const struct rwalk* rwalk, + const struct enclosure* enc) { - const struct sdis_interface* interf; - const struct enclosure* enc; - unsigned enc_ids[2]; - unsigned enc_id; res_T res = RES_OK; - ASSERT(scn && rwalk && out_enclosure); - ASSERT(sdis_medium_get_type(rwalk->mdm) == SDIS_FLUID); - ASSERT(!SXD_HIT_NONE(&rwalk->hit)); - - /* Fetch the current interface and its associated enclosures */ - interf = scene_get_interface(scn, rwalk->hit.prim.prim_id); - scene_get_enclosure_ids(scn, rwalk->hit.prim.prim_id, enc_ids); - - /* Find the enclosure identifier of the current medium */ - ASSERT(interf->medium_front != interf->medium_back); - if(rwalk->mdm == interf->medium_front) { - enc_id = enc_ids[0]; - ASSERT(rwalk->hit_side == SDIS_FRONT); - } else { - ASSERT(rwalk->mdm == interf->medium_back); - enc_id = enc_ids[1]; - ASSERT(rwalk->hit_side == SDIS_BACK); - } + ASSERT(scn && rwalk && enc); - /* Fetch the enclosure data */ - enc = scene_get_enclosure(scn, enc_id); - ASSERT(enc != NULL); - if(enc->medium_id == ENCLOSURE_MULTI_MEDIA) { + if(enc->medium_id == MEDIUM_ID_MULTI) { /* The enclosures with multiple media are used to describe limit * conditions and therefore they cannot be fetched */ log_err(scn->dev, - "%s: enclosure with multiple media at {%g, %g, %g}. " - "Path should be reached a limit condition before.\n", - FUNC_NAME, rwalk->vtx.P[0], rwalk->vtx.P[1], DIM==3 ? rwalk->vtx.P[2]:0); + "%s: enclosure with multiple media at ("FORMAT_VECX"). " + "The path should be reached a limit condition before.\n", + FUNC_NAME, SPLITX(rwalk->vtx.P)); res = RES_BAD_ARG; goto error; } exit: - *out_enclosure = enc; return res; error: - enc = NULL; goto exit; } @@ -237,14 +174,22 @@ res_T XD(convective_path) (struct sdis_scene* scn, struct rwalk_context* ctx, - struct XD(rwalk)* rwalk, + struct rwalk* rwalk, struct ssp_rng* rng, - struct XD(temperature)* T) + struct temperature* T) { - struct sXd(attrib) attr_P, attr_N; + /* Properties */ struct fluid_props props_ref = FLUID_PROPS_NULL; - const struct sdis_interface* interf; - const struct enclosure* enc; + const struct sdis_interface* interf = NULL; + struct sdis_medium* mdm = NULL; + + /* Enclosure */ + unsigned enc_ids[2] = {ENCLOSURE_ID_NULL, ENCLOSURE_ID_NULL}; + const struct enclosure* enc = NULL; + + /* Miscellaneous */ + struct sXd(attrib) attr_P, attr_N; + struct sXd(hit)* rwalk_hit = NULL; double r; #if SDIS_XD_DIMENSION == 2 float st; @@ -253,11 +198,19 @@ XD(convective_path) #endif int path_starts_in_fluid; res_T res = RES_OK; - (void)rng, (void)ctx; + ASSERT(scn && ctx && rwalk && rng && T); - ASSERT(rwalk->mdm->type == SDIS_FLUID); + (void)rng, (void)ctx; /* Avoid "unsued variable" warnings */ - res = XD(handle_known_fluid_temperature)(scn, ctx, rwalk, T); + rwalk_hit = &rwalk->XD(hit); + + /* Get the enclosure medium */ + enc = scene_get_enclosure(scn, rwalk->enc_id); + if((res = XD(check_enclosure)(scn, rwalk, enc)) != RES_OK) goto error; + if((res = scene_get_enclosure_medium(scn, enc, &mdm)) != RES_OK) goto error; + ASSERT(sdis_medium_get_type(mdm) == SDIS_FLUID); + + res = XD(handle_known_fluid_temperature)(ctx, rwalk, mdm, T); if(res != RES_OK) goto error; if(T->done) goto exit; /* The fluid temperature is known */ @@ -266,13 +219,10 @@ XD(convective_path) res = XD(handle_convective_path_startup)(scn, rwalk, &path_starts_in_fluid); if(res != RES_OK) goto error; - res = XD(fetch_fluid_enclosure)(scn, rwalk, &enc); - if(res != RES_OK) goto error; - /* Retrieve the fluid properties at the current position. Use them to verify * that those that are supposed to be constant by the convective random walk * remain the same. */ - res = fluid_get_properties(rwalk->mdm, &rwalk->vtx, &props_ref); + res = fluid_get_properties(mdm, &rwalk->vtx, &props_ref); if(res != RES_OK) goto error; /* The hc upper bound can be 0 if h is uniformly 0. In that case the result @@ -280,7 +230,7 @@ XD(convective_path) if(enc->hc_upper_bound == 0) { ASSERT(path_starts_in_fluid); /* Cannot be in the fluid without starting there. */ rwalk->vtx.time = props_ref.t0; - res = XD(handle_known_fluid_temperature)(scn, ctx, rwalk, T); + res = XD(handle_known_fluid_temperature)(ctx, rwalk, mdm, T); if(res != RES_OK) goto error; if(T->done) { goto exit; /* Stop the random walk */ @@ -300,7 +250,7 @@ XD(convective_path) double mu; /* Fetch fluid properties */ - res = fluid_get_properties(rwalk->mdm, &rwalk->vtx, &props); + res = fluid_get_properties(mdm, &rwalk->vtx, &props); if(res != RES_OK) goto error; res = check_fluid_constant_properties(scn->dev, &props_ref, &props); @@ -308,7 +258,7 @@ XD(convective_path) /* Sample the time using the upper bound. */ mu = enc->hc_upper_bound / (props.rho * props.cp) * enc->S_over_V; - res = XD(time_rewind)(mu, props.t0, rng, rwalk, ctx, T); + res = time_rewind(scn, mu, props.t0, rng, rwalk, ctx, T); if(res != RES_OK) goto error; if(T->done) break; /* Limit condition was reached */ @@ -318,44 +268,47 @@ XD(convective_path) (enc->sXd(view), ssp_rng_canonical_float(rng), ssp_rng_canonical_float(rng), - &prim, &rwalk->hit.u)); - st = rwalk->hit.u; + &prim, &rwalk_hit->u)); + st = rwalk_hit->u; #else SXD(scene_view_sample (enc->sXd(view), ssp_rng_canonical_float(rng), ssp_rng_canonical_float(rng), ssp_rng_canonical_float(rng), - &prim, rwalk->hit.uv)); - f2_set(st, rwalk->hit.uv); + &prim, rwalk_hit->uv)); + f2_set(st, rwalk_hit->uv); #endif /* Map the sampled primitive id from the enclosure space to the scene * space. Note that the overall scene has only one shape. As a consequence * neither the geom_id nor the inst_id needs to be updated */ - rwalk->hit.prim.prim_id = enclosure_local2global_prim_id(enc, prim.prim_id); + rwalk_hit->prim.prim_id = enclosure_local2global_prim_id(enc, prim.prim_id); - SXD(primitive_get_attrib(&rwalk->hit.prim, SXD_POSITION, st, &attr_P)); - SXD(primitive_get_attrib(&rwalk->hit.prim, SXD_GEOMETRY_NORMAL, st, &attr_N)); + SXD(primitive_get_attrib(&rwalk_hit->prim, SXD_POSITION, st, &attr_P)); + SXD(primitive_get_attrib(&rwalk_hit->prim, SXD_GEOMETRY_NORMAL, st, &attr_N)); dX_set_fX(rwalk->vtx.P, attr_P.value); - fX(set)(rwalk->hit.normal, attr_N.value); + fX(set)(rwalk_hit->normal, attr_N.value); - /* Fetch the interface of the sampled point. */ - interf = scene_get_interface(scn, rwalk->hit.prim.prim_id); - if(rwalk->mdm == interf->medium_front) { - rwalk->hit_side = SDIS_FRONT; - } else if(rwalk->mdm == interf->medium_back) { + /* Define the interface side */ + scene_get_enclosure_ids(scn, rwalk_hit->prim.prim_id, enc_ids); + if(rwalk->enc_id == enc_ids[SDIS_BACK]) { rwalk->hit_side = SDIS_BACK; + } else if(rwalk->enc_id == enc_ids[SDIS_FRONT]) { + rwalk->hit_side = SDIS_FRONT; } else { - FATAL("Unexpected fluid interface.\n"); + FATAL("Unexpected fluid interface\n"); } + /* Get the interface properties */ + interf = scene_get_interface(scn, rwalk_hit->prim.prim_id); + /* Register the new vertex against the heat path */ res = register_heat_vertex(ctx->heat_path, &rwalk->vtx, T->value, SDIS_HEAT_VERTEX_CONVECTION, (int)ctx->nbranchings); if(res != RES_OK) goto error; /* Setup the fragment of the sampled position into the enclosure. */ - XD(setup_interface_fragment)(&frag, &rwalk->vtx, &rwalk->hit, rwalk->hit_side); + XD(setup_interface_fragment)(&frag, &rwalk->vtx, rwalk_hit, rwalk->hit_side); /* Fetch the convection coefficient of the sampled position */ hc = interface_get_convection_coef(interf, &frag); @@ -374,9 +327,9 @@ XD(convective_path) } } - rwalk->hit.distance = 0; + rwalk_hit->distance = 0; T->func = XD(boundary_path); - rwalk->mdm = NULL; /* The random walk is at an interface between 2 media */ + rwalk->enc_id = ENCLOSURE_ID_NULL; /* Interface between 2 enclosures */ exit: return res; diff --git a/src/sdis_heat_path_radiative_Xd.h b/src/sdis_heat_path_radiative_Xd.h @@ -35,9 +35,9 @@ XD(trace_radiative_path) (struct sdis_scene* scn, const float ray_dir[3], struct rwalk_context* ctx, - struct XD(rwalk)* rwalk, + struct rwalk* rwalk, struct ssp_rng* rng, - struct XD(temperature)* T) + struct temperature* T) { /* The radiative random walk is always performed in 3D. In 2D, the geometry * are assumed to be extruded to the infinity along the Z dimension. */ @@ -56,9 +56,11 @@ XD(trace_radiative_path) /* Launch the radiative random walk */ for(;;) { const struct sdis_interface* interf = NULL; + struct sdis_medium* chk_mdm = NULL; struct hit_filter_data filter_data = HIT_FILTER_DATA_NULL; struct sdis_interface_fragment frag = SDIS_INTERFACE_FRAGMENT_NULL; - struct sdis_medium* chk_mdm = NULL; + unsigned enc_ids[2] = {ENCLOSURE_ID_NULL, ENCLOSURE_ID_NULL}; + unsigned chk_enc_id = ENCLOSURE_ID_NULL; double alpha; double epsilon; double r; @@ -68,16 +70,16 @@ XD(trace_radiative_path) fX_set_dX(pos, rwalk->vtx.P); /* Trace the radiative ray */ - filter_data.XD(hit) = rwalk->hit; + filter_data.XD(hit) = rwalk->XD(hit); filter_data.epsilon = 1.e-6; #if (SDIS_XD_DIMENSION == 2) SXD(scene_view_trace_ray_3d - (scn->sXd(view), pos, dir, range, &filter_data, &rwalk->hit)); + (scn->sXd(view), pos, dir, range, &filter_data, &rwalk->XD(hit))); #else SXD(scene_view_trace_ray - (scn->sXd(view), pos, dir, range, &filter_data, &rwalk->hit)); + (scn->sXd(view), pos, dir, range, &filter_data, &rwalk->XD(hit))); #endif - if(SXD_HIT_NONE(&rwalk->hit)) { /* Fetch the ambient radiative temperature */ + if(SXD_HIT_NONE(&rwalk->XD(hit))) { /* Fetch the ambient radiative temperature */ struct sdis_radiative_ray ray = SDIS_RADIATIVE_RAY_NULL; double trad = 0; /* [K] */ @@ -127,11 +129,11 @@ XD(trace_radiative_path) } /* Define the hit side */ - rwalk->hit_side = fX(dot)(dir, rwalk->hit.normal) < 0 + rwalk->hit_side = fX(dot)(dir, rwalk->XD(hit).normal) < 0 ? SDIS_FRONT : SDIS_BACK; /* Move the random walk to the hit position */ - XD(move_pos)(rwalk->vtx.P, dir, rwalk->hit.distance); + XD(move_pos)(rwalk->vtx.P, dir, rwalk->XD(hit).distance); /* Register the random walk vertex against the heat path */ res = register_heat_vertex(ctx->heat_path, &rwalk->vtx, T->value, @@ -139,8 +141,8 @@ XD(trace_radiative_path) if(res != RES_OK) goto error; /* Fetch the new interface and setup the hit fragment */ - interf = scene_get_interface(scn, rwalk->hit.prim.prim_id); - XD(setup_interface_fragment)(&frag, &rwalk->vtx, &rwalk->hit, rwalk->hit_side); + interf = scene_get_interface(scn, rwalk->XD(hit).prim.prim_id); + XD(setup_interface_fragment)(&frag, &rwalk->vtx, &rwalk->XD(hit), rwalk->hit_side); /* Fetch the interface emissivity */ epsilon = interface_side_get_emissivity(interf, SDIS_INTERN_SOURCE_ID, &frag); @@ -156,35 +158,46 @@ XD(trace_radiative_path) r = ssp_rng_canonical(rng); if(r < epsilon) { T->func = XD(boundary_path); - rwalk->mdm = NULL; /* The random walk is at an interface between 2 media */ + rwalk->enc_id = ENCLOSURE_ID_NULL; /* Interface between 2 enclosures */ break; } /* Normalize the normal of the interface and ensure that it points toward the * current medium */ - fX(normalize)(N, rwalk->hit.normal); - if(rwalk->hit_side == SDIS_BACK){ - chk_mdm = interf->medium_back; - fX(minus)(N, N); - } else { - chk_mdm = interf->medium_front; + fX(normalize)(N, rwalk->XD(hit).normal); + if(rwalk->hit_side == SDIS_BACK) fX(minus)(N, N); + + /* Check that the radiative path still lies in the same enclosure */ + scene_get_enclosure_ids(scn, rwalk->XD(hit).prim.prim_id, enc_ids); + chk_enc_id = rwalk->hit_side == SDIS_FRONT ? enc_ids[0] : enc_ids[1]; + if(chk_enc_id != rwalk->enc_id) { + log_warn(scn->dev, + "%s: the radiative path has escaped from its cavity -- pos=(%g, %g, %g)\n", + FUNC_NAME, SPLIT3(rwalk->vtx.P)); + res = RES_BAD_OP; + goto error; } - if(chk_mdm != rwalk->mdm) { - /* To ease the setting of models, the external enclosure is allowed to be - * incoherent regarding media. Here a radiative path is allowed to join - * 2 different fluids. */ - const int outside = scene_is_outside - (scn, rwalk->hit_side, rwalk->hit.prim.prim_id); - if(outside && chk_mdm->type == SDIS_FLUID) { - rwalk->mdm = chk_mdm; - } else { - log_warn(scn->dev, "%s: inconsistent medium definition at `%g %g %g'.\n", - FUNC_NAME, SPLIT3(rwalk->vtx.P)); - res = RES_BAD_OP; - goto error; - } + /* Verify that the intersection, although in the same enclosure, touches the + * interface of a fluid. We verify this by interface, since a radiative path + * can be traced in an enclosure containing several media used to describe a + * set of boundary conditions. + * + * If the enclosure is good but the media type is not, this means that the + * radiative path is sampled in the wrong media. This is not a numerical + * problem, but a user problem: trying to sample a radiative path in a solid + * when semi-transparent solids are not yet supported by Stardis. This error + * is therefore fatal for the calculation */ + chk_mdm = rwalk->hit_side == SDIS_FRONT + ? interf->medium_front : interf->medium_back; + if(sdis_medium_get_type(chk_mdm)) { + log_err(scn->dev, + "%s: a radiative path cannot evolve in a solid -- pos=(%g, %g, %g)\n", + FUNC_NAME, SPLIT3(rwalk->vtx.P)); + res = RES_BAD_OP_IRRECOVERABLE; + goto error; } + alpha = interface_side_get_specular_fraction(interf, SDIS_INTERN_SOURCE_ID, &frag); r = ssp_rng_canonical(rng); if(r < alpha) { /* Sample specular part */ @@ -204,9 +217,9 @@ res_T XD(radiative_path) (struct sdis_scene* scn, struct rwalk_context* ctx, - struct XD(rwalk)* rwalk, + struct rwalk* rwalk, struct ssp_rng* rng, - struct XD(temperature)* T) + struct temperature* T) { /* The radiative random walk is always performed in 3D. In 2D, the geometry * are assumed to be extruded to the infinity along the Z dimension. */ @@ -215,11 +228,11 @@ XD(radiative_path) res_T res = RES_OK; ASSERT(scn && ctx && rwalk && rng && T); - ASSERT(!SXD_HIT_NONE(&rwalk->hit)); + ASSERT(!SXD_HIT_NONE(&rwalk->XD(hit))); /* Normalize the normal of the interface and ensure that it points toward the * current medium */ - fX(normalize(N, rwalk->hit.normal)); + fX(normalize(N, rwalk->XD(hit).normal)); if(rwalk->hit_side == SDIS_BACK) { fX(minus(N, N)); } diff --git a/src/sdis_misc.c b/src/sdis_misc.c @@ -14,12 +14,85 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include "sdis.h" +#include "sdis_heat_path.h" +#include "sdis_log.h" +#include "sdis_medium_c.h" +#include "sdis_misc.h" +#include "sdis_green.h" -/* Generate the generic functions */ -#define SDIS_XD_DIMENSION 2 -#include "sdis_misc_Xd.h" -#define SDIS_XD_DIMENSION 3 -#include "sdis_misc_Xd.h" +#include <star/ssp.h> + +res_T +time_rewind + (struct sdis_scene* scn, + const double mu, + const double t0, + struct ssp_rng* rng, + struct rwalk* rwalk, + const struct rwalk_context* ctx, + struct temperature* T) +{ + const struct enclosure* enc = NULL; + struct sdis_medium* mdm = NULL; + double temperature; + double tau; + res_T res = RES_OK; + ASSERT(scn && rwalk && ctx && rng && T); + + /* Get the current medium */ + enc = scene_get_enclosure(scn, rwalk->enc_id); + res = scene_get_enclosure_medium(scn, enc, &mdm); + if(res != RES_OK) goto error; + + /* Sample the time using the upper bound. */ + tau = ssp_ran_exp(rng, mu); + + /* Increment the elapsed time */ + ASSERT(rwalk->vtx.time >= t0); + rwalk->elapsed_time += MMIN(tau, rwalk->vtx.time - t0); + + if(IS_INF(rwalk->vtx.time)) goto exit; /* Steady computation */ + + /* Time rewind */ + rwalk->vtx.time = MMAX(rwalk->vtx.time - tau, t0); /* Time rewind */ + + /* The path does not reach the limit condition */ + if(rwalk->vtx.time > t0) goto exit; + + /* Fetch the initial temperature */ + temperature = medium_get_temperature(mdm, &rwalk->vtx); + if(SDIS_TEMPERATURE_IS_UNKNOWN(temperature)) { + log_err(mdm->dev, "the path reaches the limit condition but the " + "%s temperature remains unknown -- position=%g, %g, %g\n", + medium_type_to_string(sdis_medium_get_type(mdm)), + SPLIT3(rwalk->vtx.P)); + res = RES_BAD_ARG; + goto error; + } + + /* Update temperature */ + T->value += temperature; + T->done = 1; + + if(ctx->heat_path) { + /* Update the registered vertex data */ + struct sdis_heat_vertex* vtx; + vtx = heat_path_get_last_vertex(ctx->heat_path); + vtx->time = rwalk->vtx.time; + vtx->weight = T->value; + } + + if(ctx->green_path) { + res = green_path_set_limit_vertex + (ctx->green_path, mdm, &rwalk->vtx, rwalk->elapsed_time); + if(res != RES_OK) goto error; + } + +exit: + return res; +error: + goto exit; +} res_T check_primitive_uv_2d(struct sdis_device* dev, const double param_coord[]) diff --git a/src/sdis_misc.h b/src/sdis_misc.h @@ -148,22 +148,14 @@ register_heat_vertex } extern LOCAL_SYM res_T -time_rewind_2d - (const double mu, +time_rewind + (struct sdis_scene* scn, + const double mu, const double t0, /* Initial time */ struct ssp_rng* rng, - struct rwalk_2d* rwalk, + struct rwalk* rwalk, const struct rwalk_context* ctx, - struct temperature_2d* T); - -extern LOCAL_SYM res_T -time_rewind_3d - (const double mu, - const double t0, /* Initial time */ - struct ssp_rng* rng, - struct rwalk_3d* rwalk, - const struct rwalk_context* ctx, - struct temperature_3d* T); + struct temperature* T); /* Check the validity of the parametric coordinate onto a 2D primitive. If it * is invalid, the function prints an error message and return RES_BAD_ARG. */ diff --git a/src/sdis_misc_Xd.h b/src/sdis_misc_Xd.h @@ -1,90 +0,0 @@ -/* Copyright (C) 2016-2024 |Méso|Star> (contact@meso-star.com) - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. */ - -#include "sdis_heat_path.h" -#include "sdis_log.h" -#include "sdis_medium_c.h" -#include "sdis_misc.h" -#include "sdis_green.h" - -#include <star/ssp.h> - -#include "sdis_Xd_begin.h" - -res_T -XD(time_rewind) - (const double mu, - const double t0, - struct ssp_rng* rng, - struct XD(rwalk)* rwalk, - const struct rwalk_context* ctx, - struct XD(temperature)* T) -{ - double temperature; - double tau; - res_T res = RES_OK; - ASSERT(rwalk && rng && T); - - /* Sample the time using the upper bound. */ - tau = ssp_ran_exp(rng, mu); - - /* Increment the elapsed time */ - ASSERT(rwalk->vtx.time >= t0); - rwalk->elapsed_time += MMIN(tau, rwalk->vtx.time - t0); - - if(IS_INF(rwalk->vtx.time)) goto exit; /* Steady computation */ - - /* Time rewind */ - rwalk->vtx.time = MMAX(rwalk->vtx.time - tau, t0); /* Time rewind */ - - /* The path does not reach the limit condition */ - if(rwalk->vtx.time > t0) goto exit; - - /* Fetch the initial temperature */ - temperature = medium_get_temperature(rwalk->mdm, &rwalk->vtx); - if(SDIS_TEMPERATURE_IS_UNKNOWN(temperature)) { - log_err(rwalk->mdm->dev, "the path reaches the limit condition but the " - "%s temperature remains unknown -- position=%g, %g, %g\n", - medium_type_to_string(sdis_medium_get_type(rwalk->mdm)), - SPLIT3(rwalk->vtx.P)); - res = RES_BAD_ARG; - goto error; - } - - /* Update temperature */ - T->value += temperature; - T->done = 1; - - if(ctx->heat_path) { - /* Update the registered vertex data */ - struct sdis_heat_vertex* vtx; - vtx = heat_path_get_last_vertex(ctx->heat_path); - vtx->time = rwalk->vtx.time; - vtx->weight = T->value; - } - - if(ctx->green_path) { - res = green_path_set_limit_vertex(ctx->green_path, rwalk->mdm, - &rwalk->vtx, rwalk->elapsed_time); - if(res != RES_OK) goto error; - } - -exit: - return res; -error: - goto exit; -} - -#include "sdis_Xd_end.h" diff --git a/src/sdis_realisation.c b/src/sdis_realisation.c @@ -19,16 +19,30 @@ /******************************************************************************* * Helper functions ******************************************************************************/ -static INLINE int +static INLINE res_T check_ray_realisation_args(const struct ray_realisation_args* args) { - return args - && args->rng - && args->medium - && args->medium->type == SDIS_FLUID - && args->time >= 0 - && args->picard_order > 0 - && (unsigned)args->diff_algo < SDIS_DIFFUSION_ALGORITHMS_COUNT__; + /* Check pointers */ + if(!args || !args->rng) return RES_BAD_ARG; + + if(args->time < 0) return RES_BAD_ARG; + if(args->picard_order <= 0) return RES_BAD_ARG; + + if((unsigned)args->diff_algo >= SDIS_DIFFUSION_ALGORITHMS_COUNT__) { + return RES_BAD_ARG; + } + + /* Check the enclosure identifier. Only its validity is checked, not the fact + * that the enclosure is a fluid. Even though Stardis doesn't allow you to + * sample a radiative path in a solid, we don't query the medium of the + * enclosure since it may contain several: querying the medium will therefore + * return an error. The type of medium is checked later, when sampling the + * radiative path, when it reaches an interface whose medium must be a fluid*/ + if(args->enc_id == ENCLOSURE_ID_NULL) { + return RES_BAD_ARG; + } + + return RES_OK; } /******************************************************************************* @@ -47,17 +61,17 @@ ray_realisation_3d double* weight) { struct rwalk_context ctx = RWALK_CONTEXT_NULL; - struct rwalk_3d rwalk = RWALK_NULL_3d; - struct temperature_3d T = TEMPERATURE_NULL_3d; + struct rwalk rwalk = RWALK_NULL; + struct temperature T = TEMPERATURE_NULL; float dir[3]; res_T res = RES_OK; - ASSERT(scn && weight && check_ray_realisation_args(args)); + ASSERT(scn && weight && check_ray_realisation_args(args) == RES_OK); d3_set(rwalk.vtx.P, args->position); rwalk.vtx.time = args->time; - rwalk.hit = S3D_HIT_NULL; + rwalk.hit_3d = S3D_HIT_NULL; rwalk.hit_side = SDIS_SIDE_NULL__; - rwalk.mdm = args->medium; + rwalk.enc_id = args->enc_id; ctx.heat_path = args->heat_path; ctx.Tmin = scn->tmin; @@ -69,7 +83,7 @@ ray_realisation_3d ctx.max_branchings = args->picard_order - 1; ctx.irealisation = args->irealisation; ctx.diff_algo = args->diff_algo; - + f3_set_d3(dir, args->direction); /* Register the starting position against the heat path */ diff --git a/src/sdis_realisation.h b/src/sdis_realisation.h @@ -22,11 +22,13 @@ #include <rsys/rsys.h> /* Forward declarations */ +struct bound_flux_result; struct green_path_handle; +struct rwalk; struct sdis_heat_path; struct sdis_scene; struct ssp_rng; -struct bound_flux_result; +struct temperature; enum flux_flag { FLUX_FLAG_CONVECTIVE = BIT(FLUX_CONVECTIVE), @@ -41,24 +43,24 @@ extern LOCAL_SYM res_T sample_coupled_path_2d (struct sdis_scene* scn, struct rwalk_context* ctx, - struct rwalk_2d* rwalk, + struct rwalk* rwalk, struct ssp_rng* rng, - struct temperature_2d* T); + struct temperature* T); extern LOCAL_SYM res_T sample_coupled_path_3d (struct sdis_scene* scn, struct rwalk_context* ctx, - struct rwalk_3d* rwalk, + struct rwalk* rwalk, struct ssp_rng* rng, - struct temperature_3d* T); + struct temperature* T); /******************************************************************************* * Realisation at a given position and time IN a medium ******************************************************************************/ struct probe_realisation_args { struct ssp_rng* rng; - struct sdis_medium* medium; /* Medium into which the realisation starts */ + unsigned enc_id; /* Enclosure into which the realisation starts */ double position[3]; /* Probe position */ double time; /* Observation time */ size_t picard_order; /* Picard order to estimate radiative temperature */ @@ -69,7 +71,7 @@ struct probe_realisation_args { }; #define PROBE_REALISATION_ARGS_NULL__ { \ NULL, /* RNG */ \ - NULL, /* Medium */ \ + ENCLOSURE_ID_NULL, /* Enclosure */ \ {0,0,0}, /* Position */ \ -1, /* Observation time */ \ 0, /* Picard order */ \ @@ -180,7 +182,7 @@ boundary_flux_realisation_3d ******************************************************************************/ struct ray_realisation_args { struct ssp_rng* rng; - struct sdis_medium* medium; /* Medium into which the realisation starts */ + unsigned enc_id; /* Enclosure into which the realisation starts */ double position[3]; /* Ray position */ double direction[3]; /* Ray direction */ double time; /* Observation time */ @@ -191,7 +193,7 @@ struct ray_realisation_args { }; #define RAY_REALISATION_ARGS_NULL__ { \ NULL, /* RNG */ \ - NULL, /* Medium */ \ + ENCLOSURE_ID_NULL, /* Enclosure */ \ {0,0,0}, /* Position */ \ {0,0,0}, /* Direction */ \ -1, /* Observation time */ \ diff --git a/src/sdis_realisation_Xd.h b/src/sdis_realisation_Xd.h @@ -32,18 +32,19 @@ #ifndef SDIS_REALISATION_XD_H #define SDIS_REALISATION_XD_H -static INLINE int +static INLINE res_T check_probe_realisation_args(const struct probe_realisation_args* args) { return args && args->rng - && args->medium + && args->enc_id != ENCLOSURE_ID_NULL && args->time >= 0 && args->picard_order > 0 - && (unsigned)args->diff_algo < SDIS_DIFFUSION_ALGORITHMS_COUNT__; + && (unsigned)args->diff_algo < SDIS_DIFFUSION_ALGORITHMS_COUNT__ + ? RES_OK : RES_BAD_ARG; } -static INLINE int +static INLINE res_T check_boundary_realisation_args(const struct boundary_realisation_args* args) { return args @@ -55,10 +56,11 @@ check_boundary_realisation_args(const struct boundary_realisation_args* args) && args->time >= 0 && args->picard_order > 0 && (args->side == SDIS_FRONT || args->side == SDIS_BACK) - && (unsigned)args->diff_algo < SDIS_DIFFUSION_ALGORITHMS_COUNT__; + && (unsigned)args->diff_algo < SDIS_DIFFUSION_ALGORITHMS_COUNT__ + ? RES_OK : RES_BAD_ARG; } -static INLINE int +static INLINE res_T check_boundary_flux_realisation_args (const struct boundary_flux_realisation_args* args) { @@ -71,7 +73,8 @@ check_boundary_flux_realisation_args && args->time >= 0 && args->picard_order > 0 && (args->solid_side == SDIS_FRONT || args->solid_side == SDIS_BACK) - && (unsigned)args->diff_algo < SDIS_DIFFUSION_ALGORITHMS_COUNT__; + && (unsigned)args->diff_algo < SDIS_DIFFUSION_ALGORITHMS_COUNT__ + ? RES_OK : RES_BAD_ARG; } #endif /* SDIS_REALISATION_XD_H */ @@ -82,15 +85,15 @@ res_T XD(sample_coupled_path) (struct sdis_scene* scn, struct rwalk_context* ctx, - struct XD(rwalk)* rwalk, + struct rwalk* rwalk, struct ssp_rng* rng, - struct XD(temperature)* T) + struct temperature* T) { #ifndef NDEBUG /* Stack that saves the state of each recursion steps. */ struct entry { - struct XD(temperature) temperature; - struct XD(rwalk) rwalk; + struct temperature temperature; + struct rwalk rwalk; }* stack = NULL; size_t istack = 0; #endif @@ -109,8 +112,8 @@ XD(sample_coupled_path) while(!T->done) { /* Save the current random walk state */ - const struct XD(rwalk) rwalk_bkp = *rwalk; - const struct XD(temperature) T_bkp = *T; + const struct rwalk rwalk_bkp = *rwalk; + const struct temperature T_bkp = *T; size_t nfails = 0; /* #failures */ #ifndef NDEBUG @@ -171,27 +174,39 @@ XD(probe_realisation) struct probe_realisation_args* args, double* weight) { + /* Starting enclosure/medium */ + const struct enclosure* enc = NULL; + struct sdis_medium* mdm = NULL; + + /* Random walk */ struct rwalk_context ctx = RWALK_CONTEXT_NULL; - struct XD(rwalk) rwalk = XD(RWALK_NULL); - struct XD(temperature) T = XD(TEMPERATURE_NULL); + struct rwalk rwalk = RWALK_NULL; + struct temperature T = TEMPERATURE_NULL; + + /* Miscellaneous */ enum sdis_heat_vertex_type type; double t0; double (*get_initial_temperature) (const struct sdis_medium* mdm, const struct sdis_rwalk_vertex* vtx); res_T res = RES_OK; - ASSERT(scn && weight && check_probe_realisation_args(args)); + ASSERT(scn && weight && check_probe_realisation_args(args) == RES_OK); - switch(args->medium->type) { + /* Get the enclosure medium */ + enc = scene_get_enclosure(scn, args->enc_id); + res = scene_get_enclosure_medium(scn, enc, &mdm); + if(res != RES_OK) goto error; + + switch(sdis_medium_get_type(mdm)) { case SDIS_FLUID: T.func = XD(convective_path); get_initial_temperature = fluid_get_temperature; - t0 = fluid_get_t0(args->medium); + t0 = fluid_get_t0(mdm); break; case SDIS_SOLID: T.func = XD(conductive_path); get_initial_temperature = solid_get_temperature; - t0 = solid_get_t0(args->medium); + t0 = solid_get_t0(mdm); break; default: FATAL("Unreachable code\n"); break; } @@ -200,7 +215,7 @@ XD(probe_realisation) rwalk.vtx.time = args->time; /* Register the starting position against the heat path */ - type = args->medium->type == SDIS_SOLID + type = sdis_medium_get_type(mdm) == SDIS_SOLID ? SDIS_HEAT_VERTEX_CONDUCTION : SDIS_HEAT_VERTEX_CONVECTION; res = register_heat_vertex(args->heat_path, &rwalk.vtx, 0, type, 0); @@ -210,7 +225,7 @@ XD(probe_realisation) double tmp; /* Check the initial condition. */ rwalk.vtx.time = t0; - tmp = get_initial_temperature(args->medium, &rwalk.vtx); + tmp = get_initial_temperature(mdm, &rwalk.vtx); if(SDIS_TEMPERATURE_IS_KNOWN(tmp)) { *weight = tmp; goto exit; @@ -224,8 +239,8 @@ XD(probe_realisation) goto error; } - rwalk.hit = SXD_HIT_NULL; - rwalk.mdm = args->medium; + rwalk.XD(hit) = SXD_HIT_NULL; + rwalk.enc_id = args->enc_id; ctx.green_path = args->green_path; ctx.heat_path = args->heat_path; @@ -258,8 +273,8 @@ XD(boundary_realisation) double* weight) { struct rwalk_context ctx = RWALK_CONTEXT_NULL; - struct XD(rwalk) rwalk = XD(RWALK_NULL); - struct XD(temperature) T = XD(TEMPERATURE_NULL); + struct rwalk rwalk = RWALK_NULL; + struct temperature T = TEMPERATURE_NULL; struct sXd(attrib) attr; #if SDIS_XD_DIMENSION == 2 float st; @@ -267,13 +282,13 @@ XD(boundary_realisation) float st[2]; #endif res_T res = RES_OK; - ASSERT(scn && weight && check_boundary_realisation_args(args)); + ASSERT(scn && weight && check_boundary_realisation_args(args) == RES_OK); T.func = XD(boundary_path); rwalk.hit_side = args->side; - rwalk.hit.distance = 0; + rwalk.XD(hit).distance = 0; rwalk.vtx.time = args->time; - rwalk.mdm = NULL; /* The random walk is at an interface between 2 media */ + rwalk.enc_id = ENCLOSURE_ID_NULL; /* At an interface between 2 enclosures */ #if SDIS_XD_DIMENSION == 2 st = (float)args->uv[0]; @@ -283,20 +298,20 @@ XD(boundary_realisation) /* Fetch the primitive */ SXD(scene_view_get_primitive - (scn->sXd(view), (unsigned int)args->iprim, &rwalk.hit.prim)); + (scn->sXd(view), (unsigned int)args->iprim, &rwalk.XD(hit).prim)); /* Retrieve the world space position of the probe onto the primitive */ - SXD(primitive_get_attrib(&rwalk.hit.prim, SXD_POSITION, st, &attr)); + SXD(primitive_get_attrib(&rwalk.XD(hit).prim, SXD_POSITION, st, &attr)); dX_set_fX(rwalk.vtx.P, attr.value); /* Retrieve the primitive normal */ - SXD(primitive_get_attrib(&rwalk.hit.prim, SXD_GEOMETRY_NORMAL, st, &attr)); - fX(set)(rwalk.hit.normal, attr.value); + SXD(primitive_get_attrib(&rwalk.XD(hit).prim, SXD_GEOMETRY_NORMAL, st, &attr)); + fX(set)(rwalk.XD(hit).normal, attr.value); #if SDIS_XD_DIMENSION==2 - rwalk.hit.u = st; + rwalk.XD(hit).u = st; #else - f2_set(rwalk.hit.uv, st); + f2_set(rwalk.XD(hit).uv, st); #endif res = register_heat_vertex(args->heat_path, &rwalk.vtx, 0/*weight*/, @@ -332,14 +347,14 @@ XD(boundary_flux_realisation) struct boundary_flux_realisation_args* args, struct bound_flux_result* result) { + /* Random walk */ struct rwalk_context ctx = RWALK_CONTEXT_NULL; - struct XD(rwalk) rwalk; - struct XD(temperature) T; + struct rwalk rwalk = RWALK_NULL; + struct temperature T = TEMPERATURE_NULL; + + /* Boundary */ struct sXd(attrib) attr; struct sXd(primitive) prim; - struct sdis_interface* interf = NULL; - struct sdis_medium* fluid_mdm = NULL; - #if SDIS_XD_DIMENSION == 2 float st; #else @@ -347,13 +362,17 @@ XD(boundary_flux_realisation) #endif double P[SDIS_XD_DIMENSION]; float N[SDIS_XD_DIMENSION]; + unsigned enc_ids[2] = {ENCLOSURE_ID_NULL, ENCLOSURE_ID_NULL}; + enum sdis_side fluid_side; + + /* Miscellaneous */ double Tmin, Tmin2, Tmin3; double That, That2, That3; - enum sdis_side fluid_side; res_T res = RES_OK; char compute_radiative; char compute_convective; - ASSERT(scn && result && check_boundary_flux_realisation_args(args)); + + ASSERT(scn && result && check_boundary_flux_realisation_args(args) == RES_OK); #if SDIS_XD_DIMENSION == 2 #define SET_PARAM(Dest, Src) (Dest).u = (Src); @@ -386,14 +405,14 @@ XD(boundary_flux_realisation) SXD(primitive_get_attrib(&prim, SXD_GEOMETRY_NORMAL, st, &attr)); fX(set)(N, attr.value); - #define RESET_WALK(Side, Mdm) { \ - rwalk = XD(RWALK_NULL); \ + #define RESET_WALK(Side, EncId) { \ + rwalk = RWALK_NULL; \ rwalk.hit_side = (Side); \ - rwalk.hit.distance = 0; \ + rwalk.XD(hit).distance = 0; \ rwalk.vtx.time = args->time; \ - rwalk.mdm = (Mdm); \ - rwalk.hit.prim = prim; \ - SET_PARAM(rwalk.hit, st); \ + rwalk.enc_id = (EncId); \ + rwalk.XD(hit).prim = prim; \ + SET_PARAM(rwalk.XD(hit), st); \ ctx.Tmin = Tmin; \ ctx.Tmin3 = Tmin3; \ ctx.That = That; \ @@ -403,24 +422,23 @@ XD(boundary_flux_realisation) ctx.irealisation = args->irealisation; \ ctx.diff_algo = args->diff_algo; \ dX(set)(rwalk.vtx.P, P); \ - fX(set)(rwalk.hit.normal, N); \ - T = XD(TEMPERATURE_NULL); \ + fX(set)(rwalk.XD(hit).normal, N); \ + T = TEMPERATURE_NULL; \ } (void)0 /* Compute boundary temperature */ - RESET_WALK(args->solid_side, NULL); + RESET_WALK(args->solid_side, ENCLOSURE_ID_NULL); T.func = XD(boundary_path); res = XD(sample_coupled_path)(scn, &ctx, &rwalk, args->rng, &T); if(res != RES_OK) return res; result->Tboundary = T.value; - /* Fetch the fluid medium */ - interf = scene_get_interface(scn, (unsigned)args->iprim); - fluid_mdm = interface_get_medium(interf, fluid_side); + /* Get the enclosures */ + scene_get_enclosure_ids(scn, (unsigned)args->iprim, enc_ids); /* Compute radiative temperature */ if(compute_radiative) { - RESET_WALK(fluid_side, fluid_mdm); + RESET_WALK(fluid_side, enc_ids[fluid_side]); T.func = XD(radiative_path); res = XD(sample_coupled_path)(scn, &ctx, &rwalk, args->rng, &T); if(res != RES_OK) return res; @@ -430,7 +448,7 @@ XD(boundary_flux_realisation) /* Compute fluid temperature */ if(compute_convective) { - RESET_WALK(fluid_side, fluid_mdm); + RESET_WALK(fluid_side, enc_ids[fluid_side]); T.func = XD(convective_path); res = XD(sample_coupled_path)(scn, &ctx, &rwalk, args->rng, &T); if(res != RES_OK) return res; diff --git a/src/sdis_scene.c b/src/sdis_scene.c @@ -427,25 +427,57 @@ scene_get_interface(const struct sdis_scene* scn, const unsigned iprim) } res_T -scene_get_medium +scene_get_enclosure_id (struct sdis_scene* scn, const double pos[], - struct sdis_medium** out_medium) + unsigned* enc_id) { return scene_is_2d(scn) - ? scene_get_medium_2d(scn, pos, out_medium) - : scene_get_medium_3d(scn, pos, out_medium); + ? scene_get_enclosure_id_2d(scn, pos, enc_id) + : scene_get_enclosure_id_3d(scn, pos, enc_id); } res_T -scene_get_medium_in_closed_boundaries +scene_get_enclosure_id_in_closed_boundaries (struct sdis_scene* scn, const double pos[], - struct sdis_medium** out_medium) + unsigned* enc_id) { return scene_is_2d(scn) - ? scene_get_medium_in_closed_boundaries_2d(scn, pos, out_medium) - : scene_get_medium_in_closed_boundaries_3d(scn, pos, out_medium); + ? scene_get_enclosure_id_in_closed_boundaries_2d(scn, pos, enc_id) + : scene_get_enclosure_id_in_closed_boundaries_3d(scn, pos, enc_id); +} + +res_T +scene_get_enclosure_medium + (struct sdis_scene* scn, + const struct enclosure* enc, + struct sdis_medium** out_mdm) +{ + struct sdis_medium* mdm = NULL; + res_T res = RES_OK; + + ASSERT(scn && enc && out_mdm); + + /* Check that the enclosure doesn't surround multiple media */ + if(enc->medium_id == MEDIUM_ID_MULTI) { + log_warn(scn->dev, + "%s: invalid medium request. The enclosure includes several media.\n", + FUNC_NAME); + res = RES_BAD_OP; + goto error; + } + + /* Obtain enclosure medium */ + ASSERT(enc->medium_id < darray_medium_size_get(&scn->media)); + mdm = darray_medium_data_get(&scn->media)[enc->medium_id]; + +error: + *out_mdm = mdm; + goto exit; +exit: + mdm = NULL; + return res; } res_T diff --git a/src/sdis_scene_Xd.h b/src/sdis_scene_Xd.h @@ -823,7 +823,7 @@ XD(register_enclosure)(struct sdis_scene* scn, struct sencXd(enclosure)* enc) /* Setup the medium id of the enclosure */ if(header.enclosed_media_count > 1) { - enc_data->medium_id = ENCLOSURE_MULTI_MEDIA; + enc_data->medium_id = MEDIUM_ID_MULTI; } else { SENCXD(enclosure_get_medium(enc, 0, &enc_data->medium_id)); } @@ -1094,13 +1094,12 @@ error: /******************************************************************************* * Local functions ******************************************************************************/ -static INLINE res_T -XD(scene_get_medium) +static res_T +XD(scene_get_enclosure_id) (struct sdis_scene* scn, const double pos[DIM], - struct sdis_medium** out_medium) + unsigned* out_enc_id) { - struct sdis_medium* medium = NULL; size_t iprim, nprims; float P[DIM]; /* Range of the parametric coordinate into which positions are challenged */ @@ -1110,6 +1109,7 @@ XD(scene_get_medium) float st[3][2]; #endif size_t nsteps = 3; + unsigned enc_id = ENCLOSURE_ID_NULL; res_T res = RES_OK; ASSERT(scn && pos); @@ -1162,8 +1162,8 @@ XD(scene_get_medium) } while((SXD_HIT_NONE(&hit) || HIT_ON_BOUNDARY(&hit, P, dir)) && ++istep < nsteps); - /* No valid intersection is found on the current primitive. Challenge - * another. */ + /* No valid intersection is found on the current primitive. + * Challenge another. */ if(istep >= nsteps) continue; fX(normalize)(N, hit.normal); @@ -1171,18 +1171,17 @@ XD(scene_get_medium) /* Not too close and not roughly orthognonal */ if(hit.distance > 1.e-6 && absf(cos_N_dir) > 1.e-2f) { - const struct enclosure* enclosure = NULL; unsigned enc_ids[2]; - const struct sdis_interface* interf; - - interf = scene_get_interface(scn, hit.prim.prim_id); scene_get_enclosure_ids(scn, hit.prim.prim_id, enc_ids); - break; + enc_id = cos_N_dir < 0 ? enc_ids[0] : enc_ids[1]; + + break; /* That's all folks */ } } if(iprim >= nprims) { - log_warn(scn->dev, "%s: could not retrieve the medium at {%g, %g, %g}.\n", + log_warn(scn->dev, + "%s: cannot retrieve current enclosure at {%g, %g, %g}.\n", FUNC_NAME, P[0], P[1], DIM == 3 ? P[2] : 0); res = RES_BAD_OP; goto error; @@ -1190,31 +1189,32 @@ XD(scene_get_medium) if(iprim > 10 && iprim > (size_t)((double)nprims * 0.05)) { log_warn(scn->dev, - "%s: performance issue. Up to %lu primitives were tested to define the " - "current medium at {%g, %g, %g}.\n", + "%s: performance issue. Up to %lu primitives were tested to find " + "current enclosure at {%g, %g, %g}.\n", FUNC_NAME, (unsigned long)iprim, P[0], P[1], DIM == 3 ? P[2] : 0); } exit: - *out_medium = medium; + *out_enc_id = enc_id; return res; error: + enc_id = ENCLOSURE_ID_NULL; goto exit; } -static INLINE res_T -XD(scene_get_medium_in_closed_boundaries) +static res_T +XD(scene_get_enclosure_id_in_closed_boundaries) (struct sdis_scene* scn, const double pos[DIM], - struct sdis_medium** out_medium) + unsigned* out_enc_id) { - struct sdis_medium* medium = NULL; - float P[DIM]; - float frame[DIM*DIM]; float dirs[6][3] = {{1,0,0},{-1,0,0},{0,1,0},{0,-1,0},{0,0,1},{0,0,-1}}; + float frame[DIM*DIM]; + float P[DIM]; + unsigned enc_id = ENCLOSURE_ID_NULL; int idir; res_T res = RES_OK; - ASSERT(scn && pos); + ASSERT(scn && pos && out_enc_id); /* Build a frame that will be used to rotate the main axis by PI/4 around * each axis. This can avoid numerical issues when geometry is discretized @@ -1222,8 +1222,6 @@ XD(scene_get_medium_in_closed_boundaries) #if DIM == 2 f22_rotation(frame, (float)PI/4); #else -/* N[0] = N[1] = N[2] = (float)(1.0 / sqrt(3.0));*/ -/* f33_basis(frame, N);*/ f33_rotation(frame, (float)PI/4, (float)PI/4, (float)PI/4); #endif @@ -1252,22 +1250,23 @@ XD(scene_get_medium_in_closed_boundaries) /* Not too close and not roughly orthogonal */ if(hit.distance > 1.e-6 && absf(cos_N_dir) > 1.e-2f) { - const struct sdis_interface* interf; - interf = scene_get_interface(scn, hit.prim.prim_id); - medium = interface_get_medium - (interf, cos_N_dir < 0 ? SDIS_FRONT : SDIS_BACK); - break; + unsigned enc_ids[2]; + scene_get_enclosure_ids(scn, hit.prim.prim_id, enc_ids); + enc_id = cos_N_dir < 0 ? enc_ids[0] : enc_ids[1]; + + break; /* That's all folks */ } } - if(idir >= 2*DIM) { - res = XD(scene_get_medium)(scn, pos, &medium); + if(idir >= 2*DIM) { /* Fallback to scene_get_enclosure_id function */ + res = XD(scene_get_enclosure_id)(scn, pos, &enc_id); if(res != RES_OK) goto error; } exit: - *out_medium = medium; + *out_enc_id = enc_id; return res; error: + enc_id = ENCLOSURE_ID_NULL; goto exit; } diff --git a/src/sdis_scene_c.h b/src/sdis_scene_c.h @@ -26,6 +26,9 @@ #include <limits.h> +#define MEDIUM_ID_MULTI UINT_MAX +#define ENCLOSURE_ID_NULL UINT_MAX + struct prim_prop { struct sdis_interface* interf; unsigned front_enclosure; /* Id of the front facing enclosure */ @@ -71,8 +74,6 @@ medium_init(struct mem_allocator* allocator, struct sdis_medium** medium) *medium = NULL; } -#define ENCLOSURE_MULTI_MEDIA UINT_MAX - struct enclosure { struct s2d_scene_view* s2d_view; struct s3d_scene_view* s3d_view; @@ -97,7 +98,7 @@ enclosure_init(struct mem_allocator* allocator, struct enclosure* enc) enc->S_over_V = 0; enc->V = 0; enc->hc_upper_bound = 0; - enc->medium_id = ENCLOSURE_MULTI_MEDIA; + enc->medium_id = MEDIUM_ID_MULTI; } static INLINE void @@ -229,25 +230,31 @@ scene_get_interface const unsigned iprim); extern LOCAL_SYM res_T -scene_get_medium +scene_get_enclosure_id (struct sdis_scene* scene, const double position[], - struct sdis_medium** medium); + unsigned* enclosure_id); -/* This function assumes that the tested position lies into finite enclosure. - * The medium into which it lies is thus retrieved by tracing a random ray - * around the current position. For possible infinite enclosure, one has to use - * the `scene_get_medium' function instead that, in counterpart, can be more - * time consuming. +/* This function assumes that the position under test lies within a finite + * enclosure. The enclosure in which it is located is therefore retrieved by + * tracing a random ray around the current position. For infinite enclosures, + * you need to use the `scene_get_enclosure_id' function, which in turn may take + * longer. * - * Note that actually, the function internally calls scene_get_medium if no - * valid medium is found with the regular procedure. This may be due to - * numerical issues or wrong assumptions on the current medium (its boundaries - * are opened to infinity). */ + * Note that the function actually calls scene_get_enclosure internally if no + * valid enclosure is found with the normal procedure. This may be due to + * numerical problems or incorrect assumptions about the current enclosure (its + * limits are open to infinity). */ extern LOCAL_SYM res_T -scene_get_medium_in_closed_boundaries - (struct sdis_scene* scn, +scene_get_enclosure_id_in_closed_boundaries + (struct sdis_scene* scene, const double position[], + unsigned* enclosure_id); + +extern LOCAL_SYM res_T +scene_get_enclosure_medium + (struct sdis_scene* scene, + const struct enclosure* enclosure, struct sdis_medium** medium); extern LOCAL_SYM res_T diff --git a/src/sdis_solve_camera.c b/src/sdis_solve_camera.c @@ -84,7 +84,7 @@ static res_T solve_pixel (struct sdis_scene* scn, struct ssp_rng* rng, - struct sdis_medium* mdm, + const unsigned enc_id, const struct sdis_camera* cam, const double time_range[2], /* Observation time */ const size_t ipix[2], /* Pixel coordinate in the image space */ @@ -99,7 +99,7 @@ solve_pixel struct sdis_heat_path* pheat_path = NULL; size_t irealisation; res_T res = RES_OK; - ASSERT(scn && mdm && rng && cam && ipix && nrealisations); + ASSERT(scn && rng && cam && ipix && nrealisations); ASSERT(pix_sz && pix_sz[0] > 0 && pix_sz[1] > 0); ASSERT(pixel && time_range); @@ -136,7 +136,7 @@ solve_pixel /* Launch the realisation */ realis_args.rng = rng; - realis_args.medium = mdm; + realis_args.enc_id = enc_id; realis_args.time = time; realis_args.picard_order = picard_order; realis_args.heat_path = pheat_path; @@ -195,7 +195,7 @@ static res_T solve_tile (struct sdis_scene* scn, struct ssp_rng* rng, - struct sdis_medium* mdm, + const unsigned enc_id, const struct sdis_camera* cam, const double time_range[2], const size_t tile_org[2], /* Origin of the tile in pixel space */ @@ -211,7 +211,7 @@ solve_tile size_t mcode; /* Morton code of the tile pixel */ size_t npixels; res_T res = RES_OK; - ASSERT(scn && rng && mdm && cam && spp); + ASSERT(scn && rng && cam && spp); ASSERT(tile_size && tile_size[0] && tile_size[1]); ASSERT(pix_sz && pix_sz[0] > 0 && pix_sz[1] > 0 && time_range); @@ -241,8 +241,8 @@ solve_tile estimator = estimator_buffer_grab(buf, ipix_image[0], ipix_image[1]); } res = solve_pixel - (scn, rng, mdm, cam, time_range, ipix_image, spp, register_paths, pix_sz, - picard_order, diff_algo, estimator, pixel); + (scn, rng, enc_id, cam, time_range, ipix_image, spp, register_paths, + pix_sz, picard_order, diff_algo, estimator, pixel); if(res != RES_OK) goto error; } @@ -504,12 +504,14 @@ sdis_solve_camera /* Stardis variables */ struct sdis_estimator_buffer* buf = NULL; - struct sdis_medium* medium = NULL; /* Random number generators */ struct ssp_rng_proxy* rng_proxy = NULL; struct ssp_rng** per_thread_rng = NULL; + /* Enclosure & medium in which the probe lies */ + unsigned enc_id = ENCLOSURE_ID_NULL; + /* Miscellaneous */ size_t ntiles_x, ntiles_y, ntiles, ntiles_adjusted; size_t ntiles_proc; /* #tiles for the current proc */ @@ -537,17 +539,9 @@ sdis_solve_camera } /* Retrieve the medium in which the submitted position lies */ - res = scene_get_medium(scn, args->cam->position, &medium); + res = scene_get_enclosure_id(scn, args->cam->position, &enc_id); if(res != RES_OK) goto error; - if(medium->type != SDIS_FLUID) { - log_err(scn->dev, - "%s: the camera position `%g %g %g' must be in a fluid medium.\n", - FUNC_NAME, SPLIT3(args->cam->position)); - res = RES_BAD_ARG; - goto error; - } - /* Create the per thread RNGs */ res = create_per_thread_rng (scn->dev, args->rng_state, args->rng_type, &rng_proxy, &per_thread_rng); @@ -658,7 +652,7 @@ sdis_solve_camera /* Draw the tile */ res_local = solve_tile - (scn, rng, medium, args->cam, args->time_range, tile_org, tile_sz, + (scn, rng, enc_id, args->cam, args->time_range, tile_org, tile_sz, args->spp, register_paths, pix_sz, args->picard_order, args->diff_algo, buf, tile); if(res_local != RES_OK) { diff --git a/src/sdis_solve_medium_Xd.h b/src/sdis_solve_medium_Xd.h @@ -39,7 +39,7 @@ */ struct enclosure_cumul { - const struct enclosure* enc; + unsigned enc_id; double cumul; }; @@ -79,12 +79,13 @@ compute_medium_enclosure_cumulative while(!htable_enclosure_iterator_eq(&it, &end)) { struct enclosure_cumul enc_cumul; const struct enclosure* enc = htable_enclosure_iterator_data_get(&it); + const unsigned* enc_id = htable_enclosure_iterator_key_get(&it); htable_enclosure_iterator_next(&it); if(sdis_medium_get_id(mdm) != enc->medium_id) continue; accum += enc->V; - enc_cumul.enc = enc; + enc_cumul.enc_id = *enc_id; enc_cumul.cumul = accum; res = darray_enclosure_cumul_push_back(cumul, &enc_cumul); if(res != RES_OK) goto error; @@ -105,7 +106,7 @@ error: goto exit; } -static const struct enclosure* +static unsigned sample_medium_enclosure (const struct darray_enclosure_cumul* cumul, struct ssp_rng* rng) { @@ -137,7 +138,7 @@ sample_medium_enclosure enc_cumul_found = enc_cumuls + i; } - return enc_cumul_found->enc; + return enc_cumul_found->enc_id; } static INLINE res_T @@ -217,17 +218,22 @@ check_compute_power_args(const struct sdis_compute_power_args* args) ******************************************************************************/ static res_T XD(sample_enclosure_position) - (const struct enclosure* enc, + (struct sdis_scene* scn, + const unsigned enc_id, struct ssp_rng* rng, double pos[DIM]) { const size_t MAX_NCHALLENGES = 1000; + + const struct enclosure* enc = NULL; float lower[DIM], upper[DIM]; size_t ichallenge; size_t i; res_T res = RES_OK; - ASSERT(enc && rng && pos); + ASSERT(scn && rng && pos); + ASSERT(enc_id != ENCLOSURE_ID_NULL); + enc = scene_get_enclosure(scn, enc_id); SXD(scene_view_get_aabb(enc->sXd(view), lower, upper)); FOR_EACH(i, 0, DIM) { @@ -396,13 +402,13 @@ XD(solve_medium) struct accum* acc_time = &per_thread_acc_time[ithread]; struct green_path_handle* pgreen_path = NULL; struct green_path_handle green_path = GREEN_PATH_HANDLE_NULL; - const struct enclosure* enc = NULL; struct sdis_heat_path* pheat_path = NULL; struct sdis_heat_path heat_path; double weight; double time; double pos[DIM]; size_t n; + unsigned enc_id = ENCLOSURE_ID_NULL; int pcent; res_T res_local = RES_OK; res_T res_simul = RES_OK; @@ -425,8 +431,8 @@ XD(solve_medium) /* Uniformly Sample an enclosure that surround the submitted medium and * uniformly sample a position into it */ - enc = sample_medium_enclosure(&cumul, rng); - res_local = XD(sample_enclosure_position)(enc, rng, pos); + enc_id = sample_medium_enclosure(&cumul, rng); + res_local = XD(sample_enclosure_position)(scn, enc_id, rng, pos); if(res_local != RES_OK) { log_err(scn->dev, "%s: could not sample a medium position.\n", FUNC_NAME); ATOMIC_SET(&res, res_local); @@ -435,7 +441,7 @@ XD(solve_medium) /* Run a probe realisation */ realis_args.rng = rng; - realis_args.medium = args->medium; + realis_args.enc_id = enc_id; realis_args.time = time; realis_args.picard_order = args->picard_order; realis_args.green_path = pgreen_path; @@ -685,10 +691,10 @@ XD(compute_power) struct ssp_rng* rng = per_thread_rng[ithread]; struct accum* acc_mpow = &per_thread_acc_mpow[ithread]; struct accum* acc_time = &per_thread_acc_time[ithread]; - const struct enclosure* enc = NULL; double power = 0; double usec = 0; size_t n = 0; + unsigned enc_id = ENCLOSURE_ID_NULL; int pcent = 0; res_T res_local = RES_OK; @@ -702,8 +708,8 @@ XD(compute_power) /* Uniformly Sample an enclosure that surround the submitted medium and * uniformly sample a position into it */ - enc = sample_medium_enclosure(&cumul, rng); - res_local = XD(sample_enclosure_position)(enc, rng, vtx.P); + enc_id = sample_medium_enclosure(&cumul, rng); + res_local = XD(sample_enclosure_position)(scn, enc_id, rng, vtx.P); if(res_local != RES_OK) { log_err(scn->dev, "%s: could not sample a medium position.\n", FUNC_NAME); ATOMIC_SET(&res, res_local); diff --git a/src/sdis_solve_probe_Xd.h b/src/sdis_solve_probe_Xd.h @@ -116,7 +116,9 @@ XD(solve_one_probe) struct accum* acc_temp, struct accum* acc_time) { - struct sdis_medium* medium = NULL; /* Medium in which the probe lies */ + /* Enclosure in which the probe lies */ + unsigned enc_id = ENCLOSURE_ID_NULL; + size_t irealisation = 0; res_T res = RES_OK; ASSERT(scn && rng && check_solve_probe_args(args) == RES_OK); @@ -126,7 +128,7 @@ XD(solve_one_probe) *acc_time = ACCUM_NULL; /* Retrieve the medium in which the submitted position lies */ - res = scene_get_medium(scn, args->position, &medium); + res = scene_get_enclosure_id(scn, args->position, &enc_id); if(res != RES_OK) goto error; FOR_EACH(irealisation, 0, args->nrealisations) { @@ -144,7 +146,7 @@ XD(solve_one_probe) /* Run a realisation */ realis_args.rng = rng; - realis_args.medium = medium; + realis_args.enc_id = enc_id; realis_args.time = time; realis_args.picard_order = args->picard_order; realis_args.irealisation = irealisation; @@ -191,7 +193,6 @@ XD(solve_probe) size_t nthreads = 0; /* Stardis variables */ - struct sdis_medium* medium = NULL; struct sdis_estimator* estimator = NULL; struct sdis_green_function* green = NULL; struct sdis_green_function** per_thread_green = NULL; @@ -200,6 +201,10 @@ XD(solve_probe) struct ssp_rng_proxy* rng_proxy = NULL; struct ssp_rng** per_thread_rng = NULL; + /* Enclosure in which the probe lies */ + const struct enclosure* enc = NULL; + unsigned enc_id = ENCLOSURE_ID_NULL; + /* Miscellaneous */ struct accum* per_thread_acc_temp = NULL; struct accum* per_thread_acc_time = NULL; @@ -255,10 +260,19 @@ XD(solve_probe) if(!per_thread_acc_temp) { res = RES_MEM_ERR; goto error; } if(!per_thread_acc_time) { res = RES_MEM_ERR; goto error; } - /* Retrieve the medium in which the submitted position lies */ - res = scene_get_medium(scn, args->position, &medium); + /* Retrieve the enclosure in which the submitted position lies */ + res = scene_get_enclosure_id(scn, args->position, &enc_id); if(res != RES_OK) goto error; + /* Check that the enclosure does not contain multiple materials */ + enc = scene_get_enclosure(scn, enc_id); + if(enc->medium_id == MEDIUM_ID_MULTI) { + log_err(scn->dev, "%s: probe is in an enclosure with several media " + "-- pos=("FORMAT_VECX")\n", FUNC_NAME, SPLITX(args->position)); + res = RES_BAD_OP; + goto error; + } + /* Create the per thread green function */ if(out_green) { res = create_per_thread_green_function @@ -327,7 +341,7 @@ XD(solve_probe) /* Invoke the probe realisation */ realis_args.rng = rng; - realis_args.medium = medium; + realis_args.enc_id = enc_id; realis_args.time = time; realis_args.picard_order = args->picard_order; realis_args.green_path = pgreen_path; diff --git a/src/test_sdis_solve_camera.c b/src/test_sdis_solve_camera.c @@ -33,27 +33,38 @@ #define SPP 32 /* #Samples per pixel, i.e. #realisations per pixel */ /* - * The scene is composed of a solid cube whose temperature is unknown. The - * emissivity of the cube is 1 and its convection coefficient with the - * surrounding fluid at 300K is 0.1. At the center of the cube there is a spherical - * fluid cavity whose temperature is 350K. The convection coefficient between - * the solid and the cavity is 1 and the emissivity of this interface is null. - * The ambient radiative temperature of the system is 300K. + * The scene consists of a solid cube whose temperature is unknown. The + * emissivity of the cube is 1 and the convection coefficient with the + * surrounding fluid at 300 K is 0.1. At the center of the cube is a spherical + * cavity of fluid with a temperature of 350 K. The convection coefficient + * between the solid and the cavity is 1, and the emissivity of this interface + * is zero. The ambient radiative temperature of the system is 300 K. * - * In this test, we compute the radiative temperature that reaches a camera - * that looks the cube and we `dump' a normalized image of the result. + * Finally, a parallelepiped below the cube symbolizes the ground. The + * temperature of its Robin condition is 280 K. This geometry verifies that a + * camera can draw a scene in an enclosure containing several media, such as + * those used to define several boundary conditions. * - * (1,1,1) - * +----------------+ - * /' # # /| - * +----*--------*--+ | - * | ' # # | | - * | ' # 350K # | | - * | ' # # | | - * | +.....#..#.....|.+ - * |/ |/ - * +----------------+ - * (-1,-1,-1) + * In this test, we calculate the radiative temperature that reaches a camera + * looking at the cube and produce an image of the result written to the + * standard output in htrdr-image(5) format. + * + * + * +----------------+ + * /' # # /| + * +----*--------*--+ | __\ 300 K + * | ' # # | | / / + * | ' # 350K # | | \__/ + * | ' # # | | + * | +.....#..#.....|.+ + * |/ |/ + * +----------------+ 280K + * +---------------------------------__\------+ + * / / / /| + * / \__/ / + + * +------------------------------------------+ / + * | |/ + * +------------------------------------------+ */ /******************************************************************************* @@ -82,6 +93,52 @@ struct geometry { static const struct geometry GEOMETRY_NULL = {NULL, NULL, NULL}; static void +geometry_add_shape + (struct geometry* geom, + const double* positions, + const size_t nverts, + const size_t* indices, + const size_t nprims, + const double transform[12], /* May be NULL <=> no transformation */ + struct sdis_interface* interf) +{ + struct map_interf* geom_interf = NULL; + size_t nverts_prev = 0; + size_t i; + + CHK(geom != NULL); + CHK(positions != NULL); + CHK(indices != NULL); + CHK(nverts != 0); + CHK(nprims != 0); + CHK(interf != NULL); + + /* Save the previous number of vertices/primitives of the geometry */ + nverts_prev = sa_size(geom->positions) / 3; + + /* Add the vertices */ + FOR_EACH(i, 0, nverts) { + double* pos = sa_add(geom->positions, 3); + d3_set(pos, positions + i*3); + if(transform) { + d33_muld3(pos, transform, pos); + d3_add(pos, transform+9, pos); + } + } + + /* Add the indices */ + FOR_EACH(i, 0, nprims) { + sa_push(geom->indices, indices[i*3+0] + nverts_prev); + sa_push(geom->indices, indices[i*3+1] + nverts_prev); + sa_push(geom->indices, indices[i*3+2] + nverts_prev); + } + + geom_interf = sa_add(geom->interfaces, 1); + geom_interf->key = sa_size(geom->indices) / 3 - 1; + geom_interf->interf = interf; +} + +static void geometry_release(struct geometry* geom) { CHK(geom != NULL); @@ -143,43 +200,59 @@ geometry_get_interface *bound = interf->interf; } -/******************************************************************************* - * Fluid medium - ******************************************************************************/ -struct fluid { - double cp; - double rho; - double temperature; -}; -static const struct fluid FLUID_NULL = {0, 0, SDIS_TEMPERATURE_NONE}; - -static double -fluid_get_calorific_capacity - (const struct sdis_rwalk_vertex* vtx, struct sdis_data* data) +static void +add_cube(struct geometry* geom, struct sdis_interface* interf) { - CHK(data != NULL && vtx != NULL); - return ((const struct fluid*)sdis_data_cget(data))->cp; + struct s3dut_mesh_data msh_data; + struct s3dut_mesh* msh = NULL; + CHK(geom); + + OK(s3dut_create_cuboid(NULL, 2, 2, 2, &msh)); + OK(s3dut_mesh_get_data(msh, &msh_data)); + geometry_add_shape(geom, msh_data.positions, msh_data.nvertices, + msh_data.indices, msh_data.nprimitives, NULL, interf); + OK(s3dut_mesh_ref_put(msh)); } -static double -fluid_get_volumic_mass - (const struct sdis_rwalk_vertex* vtx, struct sdis_data* data) +static void +add_sphere(struct geometry* geom, struct sdis_interface* interf) { - CHK(data != NULL && vtx != NULL); - return ((const struct fluid*)sdis_data_cget(data))->rho; + struct s3dut_mesh_data msh_data; + struct s3dut_mesh* msh = NULL; + CHK(geom); + + OK(s3dut_create_sphere(NULL, 0.5, 32, 16, &msh)); + OK(s3dut_mesh_get_data(msh, &msh_data)); + geometry_add_shape(geom, msh_data.positions, msh_data.nvertices, + msh_data.indices, msh_data.nprimitives, NULL, interf); + OK(s3dut_mesh_ref_put(msh)); } -static double -fluid_get_temperature - (const struct sdis_rwalk_vertex* vtx, struct sdis_data* data) +static void +add_ground(struct geometry* geom, struct sdis_interface* interf) { - CHK(data != NULL && vtx != NULL); - return ((const struct fluid*)sdis_data_cget(data))->temperature; + struct s3dut_mesh_data msh_data; + struct s3dut_mesh* msh = NULL; + const double transform[12] = {1,0,0, 0,1,0, 0,0,1, 0,0,-4}; + CHK(geom); + + OK(s3dut_create_cuboid(NULL, 10, 10, 2, &msh)); + OK(s3dut_mesh_get_data(msh, &msh_data)); + geometry_add_shape(geom, msh_data.positions, msh_data.nvertices, + msh_data.indices, msh_data.nprimitives, transform, interf); + OK(s3dut_mesh_ref_put(msh)); } /******************************************************************************* - * Solid medium + * Media ******************************************************************************/ +struct fluid { + double cp; + double rho; + double temperature; +}; +static const struct fluid FLUID_NULL = {0, 0, SDIS_TEMPERATURE_NONE}; + struct solid { double cp; double lambda; @@ -189,48 +262,87 @@ struct solid { }; static const struct solid SOLID_NULL = {0, 0, 0, 0, SDIS_TEMPERATURE_NONE}; -static double -solid_get_calorific_capacity - (const struct sdis_rwalk_vertex* vtx, struct sdis_data* data) +#define MEDIUM_GETTER(Type, Prop) \ + static double \ + Type##_get_##Prop \ + (const struct sdis_rwalk_vertex* vtx, \ + struct sdis_data* data) \ + { \ + CHK(data && vtx); \ + return ((const struct Type*)sdis_data_cget(data))->Prop; \ + } +/* Fluid getters */ +MEDIUM_GETTER(fluid, cp) +MEDIUM_GETTER(fluid, rho) +MEDIUM_GETTER(fluid, temperature) +/* Solid getters */ +MEDIUM_GETTER(solid, cp) +MEDIUM_GETTER(solid, lambda) +MEDIUM_GETTER(solid, rho) +MEDIUM_GETTER(solid, delta) +MEDIUM_GETTER(solid, temperature) +#undef MEDIUM_GETTER + +static struct sdis_medium* +create_fluid + (struct sdis_device* dev, + const struct fluid* param) { - CHK(data != NULL && vtx != NULL); - return ((const struct solid*)sdis_data_cget(data))->cp; -} + struct sdis_fluid_shader fluid_shader = DUMMY_FLUID_SHADER; + struct sdis_data* data = NULL; + struct sdis_medium* fluid = NULL; -static double -solid_get_thermal_conductivity - (const struct sdis_rwalk_vertex* vtx, struct sdis_data* data) -{ - CHK(data != NULL && vtx != NULL); - return ((const struct solid*)sdis_data_cget(data))->lambda; -} + CHK(param != NULL); -static double -solid_get_volumic_mass - (const struct sdis_rwalk_vertex* vtx, struct sdis_data* data) -{ - CHK(data != NULL && vtx != NULL); - return ((const struct solid*)sdis_data_cget(data))->rho; -} + /* Copy the fluid parameters into the Stardis memory space */ + OK(sdis_data_create + (dev, sizeof(struct fluid), ALIGNOF(struct fluid), NULL, &data)); + memcpy(sdis_data_get(data), param, sizeof(struct fluid)); -static double -solid_get_delta - (const struct sdis_rwalk_vertex* vtx, struct sdis_data* data) -{ - CHK(data != NULL && vtx != NULL); - return ((const struct solid*)sdis_data_cget(data))->delta; + /* Setup the fluid shader */ + fluid_shader.calorific_capacity = fluid_get_cp; + fluid_shader.volumic_mass = fluid_get_rho; + fluid_shader.temperature = fluid_get_temperature; + + /* Create the fluid medium */ + OK(sdis_fluid_create(dev, &fluid_shader, data, &fluid)); + OK(sdis_data_ref_put(data)); + + return fluid; } -static double -solid_get_temperature - (const struct sdis_rwalk_vertex* vtx, struct sdis_data* data) +static struct sdis_medium* +create_solid + (struct sdis_device* dev, + const struct solid* param) { - CHK(data != NULL && vtx != NULL); - return ((const struct solid*)sdis_data_cget(data))->temperature; + struct sdis_solid_shader solid_shader = DUMMY_SOLID_SHADER; + struct sdis_data* data = NULL; + struct sdis_medium* solid = NULL; + + CHK(param != NULL); + + /* Copy the solid parameters into the Stardis memory space */ + OK(sdis_data_create + (dev, sizeof(struct solid), ALIGNOF(struct solid), NULL, &data)); + memcpy(sdis_data_get(data), param, sizeof(struct solid)); + + /* Setup the solid shader */ + solid_shader.calorific_capacity = solid_get_cp; + solid_shader.thermal_conductivity = solid_get_lambda; + solid_shader.volumic_mass = solid_get_rho; + solid_shader.delta = solid_get_delta; + solid_shader.temperature = solid_get_temperature; + + /* Create the solid medium */ + OK(sdis_solid_create(dev, &solid_shader, data, &solid)); + OK(sdis_data_ref_put(data)); + + return solid; } /******************************************************************************* - * Interface + * Interfaces ******************************************************************************/ struct interf { double hc; @@ -243,50 +355,76 @@ static const struct interf INTERF_NULL = { 0, 0, 0, SDIS_TEMPERATURE_NONE, SDIS_TEMPERATURE_NONE }; -static double -interface_get_convection_coef - (const struct sdis_interface_fragment* frag, struct sdis_data* data) -{ - CHK(data != NULL && frag != NULL); - return ((const struct interf*)sdis_data_cget(data))->hc; -} +#define INTERFACE_GETTER(Prop) \ + static double \ + interface_get_##Prop \ + (const struct sdis_interface_fragment* frag, \ + struct sdis_data* data) \ + { \ + CHK(data && frag); \ + return ((const struct interf*)sdis_data_cget(data))->Prop; \ + } +INTERFACE_GETTER(hc) +INTERFACE_GETTER(temperature) +INTERFACE_GETTER(reference_temperature) +#undef INTERFACE_GETTER + +#define INTERFACE_GETTER(Prop) \ + static double \ + interface_get_##Prop \ + (const struct sdis_interface_fragment* frag, \ + const unsigned source_id, \ + struct sdis_data* data) \ + { \ + CHK(data && frag); \ + (void)source_id; \ + return ((const struct interf*)sdis_data_cget(data))->Prop; \ + } +INTERFACE_GETTER(epsilon) +INTERFACE_GETTER(specular_fraction) +#undef INTERFACE_GETTER -static double -interface_get_emissivity - (const struct sdis_interface_fragment* frag, - const unsigned source_id, - struct sdis_data* data) +static struct sdis_interface* +create_interface + (struct sdis_device* dev, + struct sdis_medium* mdm_front, + struct sdis_medium* mdm_back, + const struct interf* param) { - (void)source_id; - CHK(data != NULL && frag != NULL); - return ((const struct interf*)sdis_data_cget(data))->epsilon; -} + struct sdis_interface_shader interface_shader = SDIS_INTERFACE_SHADER_NULL; + struct sdis_data* data = NULL; + struct sdis_interface* interf = NULL; -static double -interface_get_specular_fraction - (const struct sdis_interface_fragment* frag, - const unsigned source_id, - struct sdis_data* data) -{ - (void)source_id; - CHK(data != NULL && frag != NULL); - return ((const struct interf*)sdis_data_cget(data))->specular_fraction; -} + CHK(mdm_front != NULL); + CHK(mdm_back != NULL); -static double -interface_get_temperature - (const struct sdis_interface_fragment* frag, struct sdis_data* data) -{ - CHK(data != NULL && frag != NULL); - return ((const struct interf*)sdis_data_cget(data))->temperature; -} + /* Copy the interface parameters into the Stardis memory space */ + OK(sdis_data_create + (dev, sizeof(struct interf), ALIGNOF(struct interf), NULL, &data)); + memcpy(sdis_data_get(data), param, sizeof(struct interf)); -static double -interface_get_reference_temperature - (const struct sdis_interface_fragment* frag, struct sdis_data* data) -{ - CHK(data != NULL && frag != NULL); - return ((const struct interf*)sdis_data_cget(data))->reference_temperature; + /* Setup the interface shader */ + interface_shader.convection_coef = interface_get_hc; + interface_shader.front.temperature = interface_get_temperature; + interface_shader.back.temperature = interface_get_temperature; + if(sdis_medium_get_type(mdm_front) == SDIS_FLUID) { + interface_shader.front.emissivity = interface_get_epsilon; + interface_shader.front.specular_fraction = interface_get_specular_fraction; + interface_shader.front.reference_temperature = + interface_get_reference_temperature; + } + if(sdis_medium_get_type(mdm_back) == SDIS_FLUID) { + interface_shader.back.emissivity = interface_get_epsilon; + interface_shader.back.specular_fraction = interface_get_specular_fraction; + interface_shader.back.reference_temperature = + interface_get_reference_temperature; + } + /* Create the interface */ + OK(sdis_interface_create + (dev, mdm_front, mdm_back, &interface_shader, data, &interf)); + OK(sdis_data_ref_put(data)); + + return interf; } /******************************************************************************* @@ -339,254 +477,289 @@ create_radenv } /******************************************************************************* - * Helper functions + * Scene ******************************************************************************/ -static void -create_solid +static struct sdis_scene* +create_scene (struct sdis_device* dev, - const struct solid* param, - struct sdis_medium** solid) + struct sdis_radiative_env* radenv, + struct geometry* geom) { - struct sdis_data* data = NULL; - struct solid* solid_args = NULL; - struct sdis_solid_shader solid_shader = DUMMY_SOLID_SHADER; + struct sdis_scene_create_args scn_args = SDIS_SCENE_CREATE_ARGS_DEFAULT; + struct sdis_scene* scn = NULL; + size_t ntris = 0; + size_t npos = 0; + CHK(geom); - CHK(param != NULL); - CHK(solid != NULL); + ntris = sa_size(geom->indices) / 3; /* #primitives */ + npos = sa_size(geom->positions) / 3; /* #positions */ - /* Copy the solid parameters into the Stardis memory space */ - OK(sdis_data_create - (dev, sizeof(struct solid), ALIGNOF(struct solid), NULL, &data)); - solid_args = sdis_data_get(data); - memcpy(solid_args, param, sizeof(struct solid)); + scn_args.get_indices = geometry_get_indices; + scn_args.get_interface = geometry_get_interface; + scn_args.get_position = geometry_get_position; + scn_args.nprimitives = ntris; + scn_args.nvertices = npos; + scn_args.t_range[0] = 300; + scn_args.t_range[1] = 350; + scn_args.radenv = radenv; + scn_args.context = geom; - /* Setup the solid shader */ - solid_shader.calorific_capacity = solid_get_calorific_capacity; - solid_shader.calorific_capacity = solid_get_calorific_capacity; - solid_shader.thermal_conductivity = solid_get_thermal_conductivity; - solid_shader.volumic_mass = solid_get_volumic_mass; - solid_shader.delta = solid_get_delta; - solid_shader.temperature = solid_get_temperature; + OK(sdis_scene_create(dev, &scn_args, &scn)); + return scn; +} - /* Create the solid medium */ - OK(sdis_solid_create(dev, &solid_shader, data, solid)); +/******************************************************************************* + * Rendering point of view + ******************************************************************************/ +static struct sdis_camera* +create_camera(struct sdis_device* dev) +{ + const double pos[3] = {3, 3, 3}; + const double tgt[3] = {0, 0, 0}; + const double up[3] = {0, 0, 1}; + struct sdis_camera* cam = NULL; - /* Release the ownership onto the Stardis memory space storing the solid - * parameters */ - OK(sdis_data_ref_put(data)); + OK(sdis_camera_create(dev, &cam)); + OK(sdis_camera_set_proj_ratio(cam, (double)IMG_WIDTH/(double)IMG_HEIGHT)); + OK(sdis_camera_set_fov(cam, MDEG2RAD(70))); + OK(sdis_camera_look_at(cam, pos, tgt, up)); + return cam; } +/******************************************************************************* + * Draw the scene + ******************************************************************************/ static void -create_fluid - (struct sdis_device* dev, - const struct fluid* param, - struct sdis_medium** fluid) +check_pixel(const struct sdis_estimator* pixel) { - struct sdis_data* data = NULL; - struct fluid* fluid_args = NULL; - struct sdis_fluid_shader fluid_shader = DUMMY_FLUID_SHADER; - - CHK(param != NULL); - CHK(fluid != NULL); - - /* Copy the fluid parameters into the Stardis memory space */ - OK(sdis_data_create - (dev, sizeof(struct fluid), ALIGNOF(struct fluid), NULL, &data)); - fluid_args = sdis_data_get(data); - memcpy(fluid_args, param, sizeof(struct fluid)); - - /* Setup the fluid shader */ - fluid_shader.calorific_capacity = fluid_get_calorific_capacity; - fluid_shader.volumic_mass = fluid_get_volumic_mass; - fluid_shader.temperature = fluid_get_temperature; + struct sdis_mc T = SDIS_MC_NULL; + struct sdis_mc time = SDIS_MC_NULL; + size_t nfails = 0; + size_t nreals = 0; - /* Create the fluid medium */ - OK(sdis_fluid_create(dev, &fluid_shader, data, fluid)); + OK(sdis_estimator_get_realisation_count(pixel, &nreals)); + OK(sdis_estimator_get_failure_count(pixel, &nfails)); + OK(sdis_estimator_get_temperature(pixel, &T)); + OK(sdis_estimator_get_realisation_time(pixel, &time)); - /* Release the ownership onto the Stardis memory space storing the fluid - * parameters */ - OK(sdis_data_ref_put(data)); + CHK(nreals + nfails == SPP); + CHK(T.E > 0); + CHK(time.E > 0); } static void -create_interface - (struct sdis_device* dev, - struct sdis_medium* mdm_front, - struct sdis_medium* mdm_back, - const struct interf* param, - struct sdis_interface** interf) +check_image(const struct sdis_estimator_buffer* img) { - struct sdis_data* data = NULL; - struct interf* interface_args = NULL; - struct sdis_interface_shader interface_shader = SDIS_INTERFACE_SHADER_NULL; - - CHK(mdm_front != NULL); - CHK(mdm_back != NULL); - CHK(param != NULL); - CHK(interf != NULL); - - /* Copy the interface parameters into the Stardis memory space */ - OK(sdis_data_create - (dev, sizeof(struct interf), ALIGNOF(struct interf), NULL, &data)); - interface_args = sdis_data_get(data); - memcpy(interface_args, param, sizeof(struct interf)); - - /* Setup the interface shader */ - interface_shader.convection_coef = interface_get_convection_coef; - interface_shader.front.temperature = interface_get_temperature; - interface_shader.back.temperature = interface_get_temperature; - if(sdis_medium_get_type(mdm_front) == SDIS_FLUID) { - interface_shader.front.emissivity = interface_get_emissivity; - interface_shader.front.specular_fraction = interface_get_specular_fraction; - interface_shader.front.reference_temperature = - interface_get_reference_temperature; - } - if(sdis_medium_get_type(mdm_back) == SDIS_FLUID) { - interface_shader.back.emissivity = interface_get_emissivity; - interface_shader.back.specular_fraction = interface_get_specular_fraction; - interface_shader.back.reference_temperature = - interface_get_reference_temperature; + struct sdis_mc T = SDIS_MC_NULL; + struct sdis_mc time = SDIS_MC_NULL; + const struct sdis_estimator* pixel = NULL; + struct ssp_rng* rng_state = NULL; + size_t definition[2]; + size_t nreals, nfails; + size_t x, y; + + BA(sdis_estimator_buffer_get_realisation_count(NULL, &nreals)); + BA(sdis_estimator_buffer_get_realisation_count(img, NULL)); + OK(sdis_estimator_buffer_get_realisation_count(img, &nreals)); + + BA(sdis_estimator_buffer_get_failure_count(NULL, &nfails)); + BA(sdis_estimator_buffer_get_failure_count(img, NULL)); + OK(sdis_estimator_buffer_get_failure_count(img, &nfails)); + + BA(sdis_estimator_buffer_get_temperature(NULL, &T)); + BA(sdis_estimator_buffer_get_temperature(img, NULL)); + OK(sdis_estimator_buffer_get_temperature(img, &T)); + + BA(sdis_estimator_buffer_get_realisation_time(NULL, &time)); + BA(sdis_estimator_buffer_get_realisation_time(img, NULL)); + OK(sdis_estimator_buffer_get_realisation_time(img, &time)); + + BA(sdis_estimator_buffer_get_rng_state(NULL, &rng_state)); + BA(sdis_estimator_buffer_get_rng_state(img, NULL)); + OK(sdis_estimator_buffer_get_rng_state(img, &rng_state)); + + CHK(nreals + nfails == IMG_WIDTH*IMG_HEIGHT*SPP); + + fprintf(stderr, "Overall temperature ~ %g +/- %g\n", T.E, T.SE); + fprintf(stderr, "Time per realisation (in usec) ~ %g +/- %g\n", time.E, time.SE); + fprintf(stderr, "#failures = %lu/%lu\n", + (unsigned long)nfails, (unsigned long)(IMG_WIDTH*IMG_HEIGHT*SPP)); + + BA(sdis_estimator_buffer_get_definition(NULL, definition)); + BA(sdis_estimator_buffer_get_definition(img, NULL)); + OK(sdis_estimator_buffer_get_definition(img, definition)); + CHK(definition[0] == IMG_WIDTH); + CHK(definition[1] == IMG_HEIGHT); + + BA(sdis_estimator_buffer_at(NULL, 0, 0, &pixel)); + BA(sdis_estimator_buffer_at(img, IMG_WIDTH+1,0 , &pixel)); + BA(sdis_estimator_buffer_at(img, 0, IMG_HEIGHT+1, &pixel)); + BA(sdis_estimator_buffer_at(img, 0, 0, NULL)); + + /* Pixels ordered by row */ + FOR_EACH(y, 0, IMG_HEIGHT) { + FOR_EACH(x, 0, IMG_WIDTH) { + OK(sdis_estimator_buffer_at(img, x, y, &pixel)); + check_pixel(pixel); + } } - /* Create the interface */ - OK(sdis_interface_create - (dev, mdm_front, mdm_back, &interface_shader, data, interf)); +} - /* Release the ownership onto the Stardis memory space storing the interface - * parameters */ - OK(sdis_data_ref_put(data)); +/* Check that the images, although compatible from an estimation point of view, + * are not the same. This should be the case if different random sequences are + * used for each image */ +static void +check_image_difference + (const struct sdis_estimator_buffer* img0, + const struct sdis_estimator_buffer* img1) +{ + struct sdis_mc T0 = SDIS_MC_NULL; + struct sdis_mc T1 = SDIS_MC_NULL; + size_t definition0[2]; + size_t definition1[2]; + size_t nreals0, nfails0; + size_t nreals1, nfails1; + + OK(sdis_estimator_buffer_get_realisation_count(img0, &nreals0)); + OK(sdis_estimator_buffer_get_realisation_count(img1, &nreals1)); + + OK(sdis_estimator_buffer_get_failure_count(img0, &nfails0)); + OK(sdis_estimator_buffer_get_failure_count(img1, &nfails1)); + CHK(nreals0 + nfails0 == nreals1 + nfails1); + + OK(sdis_estimator_buffer_get_definition(img0, definition0)); + OK(sdis_estimator_buffer_get_definition(img1, definition1)); + CHK(definition0[0] == definition1[0]); + CHK(definition0[1] == definition1[1]); + + OK(sdis_estimator_buffer_get_temperature(img0, &T0)); + OK(sdis_estimator_buffer_get_temperature(img1, &T1)); + CHK(T0.E != T1.E || (T0.SE == 0 && T1.SE == 0)); + CHK(T0.E + 3*T0.SE >= T1.E - 3*T1.SE); + CHK(T0.E - 3*T0.SE <= T1.E + 3*T1.SE); } +/* Write an image in htrdr-image(5) format */ static void -geometry_add_shape - (struct geometry* geom, - const double* positions, - const size_t nverts, - const size_t* indices, - const size_t nprims, - const double transform[12], /* May be NULL <=> no transformation */ - struct sdis_interface* interf) +write_image(FILE* stream, struct sdis_estimator_buffer* img) { - struct map_interf* geom_interf = NULL; - size_t nverts_prev = 0; - size_t i; + size_t x, y; - CHK(geom != NULL); - CHK(positions != NULL); - CHK(indices != NULL); - CHK(nverts != 0); - CHK(nprims != 0); - CHK(interf != NULL); + /* Header */ + fprintf(stream, "%d %d\n", IMG_WIDTH, IMG_HEIGHT); - /* Save the previous number of vertices/primitives of the geometry */ - nverts_prev = sa_size(geom->positions) / 3; + /* Pixels ordered by row */ + FOR_EACH(y, 0, IMG_HEIGHT) { + FOR_EACH(x, 0, IMG_WIDTH) { + struct sdis_mc T = SDIS_MC_NULL; + const struct sdis_estimator* pixel = NULL; - /* Add the vertices */ - FOR_EACH(i, 0, nverts) { - double* pos = sa_add(geom->positions, 3); - d3_set(pos, positions + i*3); - if(transform) { - d33_muld3(pos, transform, pos); - d3_add(pos, transform+9, pos); + OK(sdis_estimator_buffer_at(img, x, y, &pixel)); + OK(sdis_estimator_get_temperature(pixel, &T)); + fprintf(stream, "%g %g 0 0 0 0 0 0\n", T.E, T.SE); } } +} - /* Add the indices */ - FOR_EACH(i, 0, nprims) { - sa_push(geom->indices, indices[i*3+0] + nverts_prev); - sa_push(geom->indices, indices[i*3+1] + nverts_prev); - sa_push(geom->indices, indices[i*3+2] + nverts_prev); - } - - geom_interf = sa_add(geom->interfaces, 1); - geom_interf->key = sa_size(geom->indices) / 3 - 1; - geom_interf->interf = interf; +static void +invalid_draw(struct sdis_scene* scn, struct sdis_camera* cam) +{ + struct sdis_solve_camera_args args = SDIS_SOLVE_CAMERA_ARGS_DEFAULT; + struct sdis_estimator_buffer* img = NULL; + + CHK(cam && scn); + + args.cam = cam; + args.time_range[0] = INF; + args.time_range[1] = INF; + args.image_definition[0] = IMG_WIDTH; + args.image_definition[1] = IMG_HEIGHT; + args.spp = SPP; + + BA(sdis_solve_camera(NULL, &args, &img)); + BA(sdis_solve_camera(scn, NULL, &img)); + BA(sdis_solve_camera(scn, &args, NULL)); + + /* Invalid camera */ + args.cam = NULL; + BA(sdis_solve_camera(scn, &args, &img)); + args.cam = cam; + + /* Invald time range */ + args.time_range[0] = args.time_range[1] = -1; + BA(sdis_solve_camera(scn, &args, &img)); + args.time_range[0] = 1; + BA(sdis_solve_camera(scn, &args, &img)); + args.time_range[1] = 0; + BA(sdis_solve_camera(scn, &args, &img)); + args.time_range[0] = args.time_range[1] = INF; + + /* Invalid image definition */ + args.image_definition[0] = 0; + BA(sdis_solve_camera(scn, &args, &img)); + args.image_definition[0] = IMG_WIDTH; + args.image_definition[1] = 0; + BA(sdis_solve_camera(scn, &args, &img)); + args.image_definition[1] = IMG_HEIGHT; + + /* Invalid number of samples per pixel */ + args.spp = 0; + BA(sdis_solve_camera(scn, &args, &img)); + args.spp = SPP; } static void -dump_image(const struct sdis_estimator_buffer* buf) +draw + (struct sdis_scene* scn, + struct sdis_camera* cam, + const int is_master_process) { - struct image img; - double* temps = NULL; - double Tmax = -DBL_MAX; - double Tmin = DBL_MAX; - double norm; - size_t definition[2]; - size_t ix, iy; - - CHK(buf != NULL); - OK(sdis_estimator_buffer_get_definition(buf, definition)); - - temps = mem_alloc(definition[0]*definition[1]*sizeof(double)); - CHK(temps != NULL); - - /* Check the results validity */ - FOR_EACH(iy, 0, definition[1]) { - FOR_EACH(ix, 0, definition[0]) { - const struct sdis_estimator* estimator; - struct sdis_mc T; - struct sdis_mc time; - size_t nreals; - size_t nfails; - - BA(sdis_estimator_buffer_at(NULL, ix, iy, &estimator)); - BA(sdis_estimator_buffer_at(buf, definition[0]+1, iy, &estimator)); - BA(sdis_estimator_buffer_at(buf, ix, definition[1]+1, &estimator)); - BA(sdis_estimator_buffer_at(buf, ix, iy, NULL)); - OK(sdis_estimator_buffer_at(buf, ix, iy, &estimator)); - - OK(sdis_estimator_get_realisation_count(estimator, &nreals)); - OK(sdis_estimator_get_failure_count(estimator, &nfails)); - OK(sdis_estimator_get_temperature(estimator, &T)); - OK(sdis_estimator_get_realisation_time(estimator, &time)); - - CHK(nreals + nfails == SPP); - CHK(T.E > 0); - CHK(time.E > 0); - } - } + struct sdis_solve_camera_args args = SDIS_SOLVE_CAMERA_ARGS_DEFAULT; + struct sdis_estimator_buffer* img0 = NULL; + struct sdis_estimator_buffer* img1 = NULL; + struct ssp_rng* rng = NULL; - /* Compute the per pixel temperature */ - FOR_EACH(iy, 0, definition[1]) { - double* row = temps + iy * definition[0]; - FOR_EACH(ix, 0, definition[0]) { - const struct sdis_estimator* estimator; - struct sdis_mc T; + args.cam = cam; + args.time_range[0] = INF; + args.time_range[1] = INF; + args.image_definition[0] = IMG_WIDTH; + args.image_definition[1] = IMG_HEIGHT; + args.spp = SPP; - OK(sdis_estimator_buffer_at(buf, ix, iy, &estimator)); - OK(sdis_estimator_get_temperature(estimator, &T)); + OK(sdis_solve_camera(scn, &args, &img0)); - row[ix] = T.E; - Tmax = MMAX(row[ix], Tmax); - Tmin = MMIN(row[ix], Tmin); - } - } - if(Tmax != Tmin) { - norm = Tmax - Tmin; + if(!is_master_process) { + CHK(img0 == NULL); } else { - Tmin = 0; - norm = 1; + check_image(img0); + write_image(stdout, img0); } - /* Allocate the image memory space */ - OK(image_init(NULL, &img)); - OK(image_setup(&img, IMG_WIDTH, IMG_HEIGHT, IMG_WIDTH*3, IMAGE_RGB8, NULL)); - - FOR_EACH(iy, 0, definition[1]) { - const double* src_row = temps + iy*definition[0]; - char* dst_row = img.pixels + iy*img.pitch; - FOR_EACH(ix, 0, definition[0]) { - unsigned char* pixels = (unsigned char*) - (dst_row + ix * sizeof_image_format(img.format)); - const unsigned char T = (unsigned char) - ((src_row[ix] - Tmin)/ norm * 255.0); - pixels[0] = T; - pixels[1] = T; - pixels[2] = T; - } + /* Provide a RNG state and check that the results, although compatible, are + * not the same */ + OK(ssp_rng_create(NULL, SSP_RNG_THREEFRY, &rng)); + OK(ssp_rng_discard(rng, 3141592653589)); /* Move the RNG state */ + args.rng_state = rng; + args.rng_type = SSP_RNG_TYPE_NULL; + OK(sdis_solve_camera(scn, &args, &img1)); + if(is_master_process) { + check_image_difference(img0, img1); + OK(sdis_estimator_buffer_ref_put(img1)); + } + OK(ssp_rng_ref_put(rng)); + + /* Change the RNG type and check that the results, although compatible, are + * not the same */ + args.rng_state = NULL; + args.rng_type = SDIS_SOLVE_CAMERA_ARGS_DEFAULT.rng_type == SSP_RNG_THREEFRY + ? SSP_RNG_MT19937_64 : SSP_RNG_THREEFRY; + OK(sdis_solve_camera(scn, &args, &img1)); + if(is_master_process) { + check_image_difference(img0, img1); + OK(sdis_estimator_buffer_ref_put(img1)); } - OK(image_write_ppm_stream(&img, 0/*binary?*/, stdout)); - image_release(&img); - mem_rm(temps); + + if(is_master_process) OK(sdis_estimator_buffer_ref_put(img0)); } /******************************************************************************* @@ -596,56 +769,44 @@ int main(int argc, char** argv) { struct geometry geom = GEOMETRY_NULL; - struct s3dut_mesh* msh = NULL; - struct s3dut_mesh_data msh_data; - struct sdis_mc T = SDIS_MC_NULL; - struct sdis_mc T2 = SDIS_MC_NULL; - struct sdis_mc time = SDIS_MC_NULL; struct sdis_camera* cam = NULL; struct sdis_device* dev = NULL; - struct sdis_estimator_buffer* buf = NULL; - struct sdis_estimator_buffer* buf2 = NULL; struct sdis_medium* solid = NULL; struct sdis_medium* fluid0 = NULL; struct sdis_medium* fluid1 = NULL; + struct sdis_medium* fluid2 = NULL; struct sdis_interface* interf0 = NULL; struct sdis_interface* interf1 = NULL; + struct sdis_interface* interf2 = NULL; struct sdis_radiative_env* radenv = NULL; struct sdis_scene* scn = NULL; - struct sdis_scene_create_args scn_args = SDIS_SCENE_CREATE_ARGS_DEFAULT; - struct sdis_solve_camera_args solve_args = SDIS_SOLVE_CAMERA_ARGS_DEFAULT; - struct ssp_rng* rng = NULL; - struct ssp_rng* rng_state = NULL; struct fluid fluid_args = FLUID_NULL; struct solid solid_args = SOLID_NULL; struct interf interface_args = INTERF_NULL; - struct fluid* pfluid_args = NULL; - struct radenv* pradenv_args = NULL; - size_t ntris, npos; - size_t nreals, nfails; - size_t definition[2]; - double pos[3]; - double tgt[3]; - double up[3]; int is_master_process; (void)argc, (void)argv; create_default_device(&argc, &argv, &is_master_process, &dev); radenv = create_radenv(dev, 300, 300); - pradenv_args = sdis_data_get(sdis_radiative_env_get_data(radenv)); /* Create the fluid0 */ fluid_args.temperature = 350; fluid_args.rho = 0; fluid_args.cp = 0; - create_fluid(dev, &fluid_args, &fluid0); + fluid0 = create_fluid(dev, &fluid_args); /* Create the fluid1 */ fluid_args.temperature = 300; fluid_args.rho = 0; fluid_args.cp = 0; - create_fluid(dev, &fluid_args, &fluid1); + fluid1 = create_fluid(dev, &fluid_args); + + /* Create the fluid2 */ + fluid_args.temperature = 280; + fluid_args.rho = 0; + fluid_args.cp = 0; + fluid2 = create_fluid(dev, &fluid_args); /* Create the solid medium */ solid_args.cp = 1.0; @@ -653,14 +814,14 @@ main(int argc, char** argv) solid_args.rho = 1.0; solid_args.delta = 1.0/20.0; solid_args.temperature = SDIS_TEMPERATURE_NONE; - create_solid(dev, &solid_args, &solid); + solid = create_solid(dev, &solid_args); /* Create the fluid0/solid interface */ interface_args.hc = 1; interface_args.epsilon = 0; interface_args.specular_fraction = 0; interface_args.temperature = SDIS_TEMPERATURE_NONE; - create_interface(dev, solid, fluid0, &interface_args, &interf0); + interf0 = create_interface(dev, solid, fluid0, &interface_args); /* Create the fluid1/solid interface */ interface_args.hc = 0.1; @@ -668,178 +829,45 @@ main(int argc, char** argv) interface_args.specular_fraction = 1; interface_args.temperature = SDIS_TEMPERATURE_NONE; interface_args.reference_temperature = 300; - create_interface(dev, fluid1, solid, &interface_args, &interf1); - - /* Setup the cube geometry */ - OK(s3dut_create_cuboid(NULL, 2, 2, 2, &msh)); - OK(s3dut_mesh_get_data(msh, &msh_data)); - geometry_add_shape(&geom, msh_data.positions, msh_data.nvertices, - msh_data.indices, msh_data.nprimitives, NULL, interf1); - OK(s3dut_mesh_ref_put(msh)); + interf1 = create_interface(dev, fluid1, solid, &interface_args); - /* Setup the sphere geometry */ - OK(s3dut_create_sphere(NULL, 0.5, 32, 16, &msh)); - OK(s3dut_mesh_get_data(msh, &msh_data)); - geometry_add_shape(&geom, msh_data.positions, msh_data.nvertices, - msh_data.indices, msh_data.nprimitives, NULL, interf0); - OK(s3dut_mesh_ref_put(msh)); + /* Create the fluid2/ground interface */ + interface_args.hc = 0.2; + interface_args.epsilon = 1; + interface_args.specular_fraction = 1; + interface_args.temperature = SDIS_TEMPERATURE_NONE; + interface_args.reference_temperature = 300; + interf2 = create_interface(dev, fluid2, solid, &interface_args); - /* Setup the scene */ - ntris = sa_size(geom.indices) / 3; /* #primitives */ - npos = sa_size(geom.positions) / 3; /* #positions */ - scn_args.get_indices = geometry_get_indices; - scn_args.get_interface = geometry_get_interface; - scn_args.get_position = geometry_get_position; - scn_args.nprimitives = ntris; - scn_args.nvertices = npos; - scn_args.t_range[0] = 300; - scn_args.t_range[1] = 350; - scn_args.radenv = radenv; - scn_args.context = &geom; - OK(sdis_scene_create(dev, &scn_args, &scn)); + add_cube(&geom, interf1); + add_sphere(&geom, interf0); + add_ground(&geom, interf2); #if 0 dump_mesh(stdout, geom.positions, sa_size(geom.positions)/3, geom.indices, sa_size(geom.indices)/3); #endif - /* Setup the camera */ - d3(pos, 3, 3, 3); - d3(tgt, 0, 0, 0); - d3(up, 0, 0, 1); - OK(sdis_camera_create(dev, &cam)); - OK(sdis_camera_set_proj_ratio(cam, (double)IMG_WIDTH/(double)IMG_HEIGHT)); - OK(sdis_camera_set_fov(cam, MDEG2RAD(70))); - OK(sdis_camera_look_at(cam, pos, tgt, up)); - -#if 0 - dump_mesh(stdout, geom.positions, npos, geom.indices, ntris); - exit(0); -#endif - solve_args.cam = cam; - solve_args.time_range[0] = INF; - solve_args.time_range[0] = INF; - solve_args.image_definition[0] = IMG_WIDTH; - solve_args.image_definition[1] = IMG_HEIGHT; - solve_args.spp = SPP; - - BA(sdis_solve_camera(NULL, &solve_args, &buf)); - BA(sdis_solve_camera(scn, NULL, &buf)); - BA(sdis_solve_camera(scn, &solve_args, NULL)); - solve_args.cam = NULL; - BA(sdis_solve_camera(scn, &solve_args, &buf)); - solve_args.cam = cam; - pradenv_args->temperature = SDIS_TEMPERATURE_NONE; - BA(sdis_solve_camera(scn, &solve_args, &buf)); - pradenv_args->temperature = 300; - solve_args.time_range[0] = solve_args.time_range[1] = -1; - BA(sdis_solve_camera(scn, &solve_args, &buf)); - solve_args.time_range[0] = 1; - BA(sdis_solve_camera(scn, &solve_args, &buf)); - solve_args.time_range[1] = 0; - BA(sdis_solve_camera(scn, &solve_args, &buf)); - solve_args.time_range[0] = solve_args.time_range[1] = INF; - - /* Launch the simulation */ - OK(sdis_solve_camera(scn, &solve_args, &buf)); + scn = create_scene(dev, radenv, &geom); + cam = create_camera(dev); - if(!is_master_process) { - CHK(buf == NULL); - } else { - BA(sdis_estimator_buffer_get_realisation_count(NULL, &nreals)); - BA(sdis_estimator_buffer_get_realisation_count(buf, NULL)); - OK(sdis_estimator_buffer_get_realisation_count(buf, &nreals)); - - BA(sdis_estimator_buffer_get_failure_count(NULL, &nfails)); - BA(sdis_estimator_buffer_get_failure_count(buf, NULL)); - OK(sdis_estimator_buffer_get_failure_count(buf, &nfails)); - - BA(sdis_estimator_buffer_get_temperature(NULL, &T)); - BA(sdis_estimator_buffer_get_temperature(buf, NULL)); - OK(sdis_estimator_buffer_get_temperature(buf, &T)); - - BA(sdis_estimator_buffer_get_realisation_time(NULL, &time)); - BA(sdis_estimator_buffer_get_realisation_time(buf, NULL)); - OK(sdis_estimator_buffer_get_realisation_time(buf, &time)); - - BA(sdis_estimator_buffer_get_rng_state(NULL, &rng_state)); - BA(sdis_estimator_buffer_get_rng_state(buf, NULL)); - OK(sdis_estimator_buffer_get_rng_state(buf, &rng_state)); - - CHK(nreals + nfails == IMG_WIDTH*IMG_HEIGHT*SPP); - - fprintf(stderr, "Overall temperature ~ %g +/- %g\n", T.E, T.SE); - fprintf(stderr, "Time per realisation (in usec) ~ %g +/- %g\n", time.E, time.SE); - fprintf(stderr, "#failures = %lu/%lu\n", - (unsigned long)nfails, (unsigned long)(IMG_WIDTH*IMG_HEIGHT*SPP)); - - BA(sdis_estimator_buffer_get_definition(NULL, definition)); - BA(sdis_estimator_buffer_get_definition(buf, NULL)); - OK(sdis_estimator_buffer_get_definition(buf, definition)); - CHK(definition[0] == IMG_WIDTH); - CHK(definition[1] == IMG_HEIGHT); - - /* Write the image */ - dump_image(buf); - OK(sdis_estimator_buffer_ref_put(buf)); - } - - /* Check RNG type */ - solve_args.rng_state = NULL; - solve_args.rng_type = SSP_RNG_TYPE_NULL; - BA(sdis_solve_camera(scn, &solve_args, &buf2)); - solve_args.rng_type = - SDIS_SOLVE_CAMERA_ARGS_DEFAULT.rng_type == SSP_RNG_THREEFRY - ? SSP_RNG_MT19937_64 : SSP_RNG_THREEFRY; - OK(sdis_solve_camera(scn, &solve_args, &buf2)); - if(is_master_process) { - OK(sdis_estimator_buffer_get_temperature(buf2, &T2)); - CHK(T.E != T2.E || (T2.SE == 0 && T.SE ==0)); - CHK(T2.E + 3*T2.SE >= T.E - 3*T.SE - && T2.E - 3*T2.SE <= T.E + 3*T.SE); - OK(sdis_estimator_buffer_ref_put(buf2)); - } - - /* Check the RNG state */ - OK(ssp_rng_create(NULL, SSP_RNG_THREEFRY, &rng)); - OK(ssp_rng_discard(rng, 3141592653589)); /* Move the RNG state */ - solve_args.rng_state = rng; - solve_args.rng_type = SSP_RNG_TYPE_NULL; - OK(sdis_solve_camera(scn, &solve_args, &buf2)); - OK(ssp_rng_ref_put(rng)); - if(is_master_process) { - OK(sdis_estimator_buffer_get_temperature(buf2, &T2)); - CHK(T.E != T2.E || (T2.SE == 0 && T.SE == 0)); - CHK(T2.E + 3*T2.SE >= T.E - 3*T.SE - && T2.E - 3*T2.SE <= T.E + 3*T.SE); - OK(sdis_estimator_buffer_ref_put(buf2)); - } - - /* Restore args */ - solve_args.rng_state = SDIS_SOLVE_CAMERA_ARGS_DEFAULT.rng_state; - solve_args.rng_type = SDIS_SOLVE_CAMERA_ARGS_DEFAULT.rng_type; - - pfluid_args = sdis_data_get(sdis_medium_get_data(fluid1)); - pfluid_args->temperature = SDIS_TEMPERATURE_NONE; - - /* Check simulation error handling */ - BA(sdis_solve_camera(scn, &solve_args, &buf)); - solve_args.register_paths = SDIS_HEAT_PATH_ALL; - BA(sdis_solve_camera(scn, &solve_args, &buf)); + invalid_draw(scn, cam); + draw(scn, cam, is_master_process); /* Release memory */ OK(sdis_medium_ref_put(solid)); OK(sdis_medium_ref_put(fluid0)); OK(sdis_medium_ref_put(fluid1)); + OK(sdis_medium_ref_put(fluid2)); OK(sdis_radiative_env_ref_put(radenv)); OK(sdis_scene_ref_put(scn)); OK(sdis_camera_ref_put(cam)); OK(sdis_interface_ref_put(interf0)); OK(sdis_interface_ref_put(interf1)); + OK(sdis_interface_ref_put(interf2)); free_default_device(dev); geometry_release(&geom); CHK(mem_allocated_size() == 0); return 0; } -