stardis-solver

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

commit 922ac5303c1794806926f5a83b9355e01a63d9ef
parent c994286e89e10ac7cbfbb9b78162a581328e4308
Author: Vincent Forest <vincent.forest@meso-star.com>
Date:   Fri,  5 Apr 2024 10:49:11 +0200

Merge remote-tracking branch 'origin/feature_wos' into develop

Diffstat:
M.gitignore | 2++
MMakefile | 21+++++++++++++++++++++
Mconfig.mk | 6++++++
Msrc/sdis.h | 69++++++++++++++++++++++++++++++++++++++++++++++++++++++---------------
Msrc/sdis_Xd_begin.h | 58+++-------------------------------------------------------
Msrc/sdis_device.c | 36++++++++++++++++++++++++++++++++++++
Msrc/sdis_device_c.h | 4++++
Msrc/sdis_heat_path.c | 6------
Msrc/sdis_heat_path.h | 64+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-----
Msrc/sdis_heat_path_boundary_Xd.h | 2+-
Msrc/sdis_heat_path_boundary_Xd_c.h | 36++++++++++++++++++++++++++++++++++++
Msrc/sdis_heat_path_boundary_Xd_solid_fluid_picard1.h | 42++++++++++++++----------------------------
Msrc/sdis_heat_path_boundary_Xd_solid_fluid_picardN.h | 10+++++++++-
Msrc/sdis_heat_path_boundary_c.h | 17+++++++++++++++++
Asrc/sdis_heat_path_conductive.c | 128+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Dsrc/sdis_heat_path_conductive_Xd.h | 541-------------------------------------------------------------------------------
Asrc/sdis_heat_path_conductive_c.h | 78++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/sdis_heat_path_conductive_delta_sphere_Xd.h | 481+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/sdis_heat_path_conductive_wos_Xd.h | 669+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Msrc/sdis_heat_path_convective_Xd.h | 2+-
Msrc/sdis_heat_path_radiative_Xd.h | 2+-
Msrc/sdis_interface_c.h | 7+++++--
Msrc/sdis_medium.c | 50++++++++++++++++++++++++--------------------------
Msrc/sdis_medium_c.h | 34++--------------------------------
Msrc/sdis_misc_Xd.h | 2+-
Msrc/sdis_realisation.c | 8+++++---
Msrc/sdis_realisation.h | 45+++++++++++++++++++++++++++++++++++++++++----
Msrc/sdis_realisation_Xd.h | 18++++++++++++------
Msrc/sdis_scene.c | 38++++++++++++++++++++++++++++++++++++++
Msrc/sdis_scene_c.h | 8++++++++
Msrc/sdis_solve_boundary_Xd.h | 26++++++++++++++++++++------
Msrc/sdis_solve_camera.c | 13+++++++++++--
Msrc/sdis_solve_medium_Xd.h | 6++++++
Msrc/sdis_solve_probe_Xd.h | 7+++++++
Msrc/sdis_solve_probe_boundary_Xd.h | 50++++++++++++++++++++++++++++++++++++--------------
Msrc/test_sdis_compute_power.c | 1-
Msrc/test_sdis_conducto_radiative.c | 14++++++--------
Msrc/test_sdis_conducto_radiative_2d.c | 14++++++--------
Msrc/test_sdis_contact_resistance.c | 9++++-----
Msrc/test_sdis_contact_resistance_2.c | 9++++-----
Msrc/test_sdis_convection.c | 5++---
Msrc/test_sdis_convection_non_uniform.c | 5++---
Msrc/test_sdis_draw_external_flux.c | 4++--
Msrc/test_sdis_enclosure_limit_conditions.c | 3+--
Msrc/test_sdis_external_flux.c | 4++--
Msrc/test_sdis_flux.c | 9++++-----
Msrc/test_sdis_flux2.c | 12+++++-------
Msrc/test_sdis_flux_with_h.c | 2+-
Msrc/test_sdis_medium.c | 16++++++++++------
Msrc/test_sdis_picard.c | 9++++-----
Msrc/test_sdis_scene.c | 28++++++++++++++++++++++------
Msrc/test_sdis_solid_random_walk_robustness.c | 5++---
Msrc/test_sdis_solve_boundary.c | 13++++++-------
Msrc/test_sdis_solve_boundary_flux.c | 7+++----
Msrc/test_sdis_solve_camera.c | 17++++++++---------
Msrc/test_sdis_solve_medium.c | 6+++---
Msrc/test_sdis_solve_medium_2d.c | 4++--
Msrc/test_sdis_solve_probe.c | 9++++++---
Msrc/test_sdis_solve_probe2.c | 4++--
Msrc/test_sdis_solve_probe2_2d.c | 3++-
Msrc/test_sdis_solve_probe3.c | 2+-
Msrc/test_sdis_solve_probe3_2d.c | 2+-
Msrc/test_sdis_solve_probe_2d.c | 4++--
Msrc/test_sdis_solve_probe_boundary_list.c | 2+-
Msrc/test_sdis_solve_probe_list.c | 2+-
Msrc/test_sdis_transcient.c | 6++----
Msrc/test_sdis_unstationary_atm.c | 18++++++++----------
Asrc/test_sdis_unsteady.c | 275+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/test_sdis_unsteady_1d.c | 268+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/test_sdis_unsteady_analytic_profile.c | 380+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/test_sdis_unsteady_analytic_profile_2d.c | 410+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Msrc/test_sdis_utils.h | 1-
Msrc/test_sdis_volumic_power.c | 166+++++++++++++++++++++++++++++++++----------------------------------------------
Msrc/test_sdis_volumic_power2.c | 17++++++++---------
Msrc/test_sdis_volumic_power2_2d.c | 9++++-----
Msrc/test_sdis_volumic_power3_2d.c | 17++++++++---------
Msrc/test_sdis_volumic_power4.c | 8++++----
77 files changed, 3388 insertions(+), 997 deletions(-)

diff --git a/.gitignore b/.gitignore @@ -13,3 +13,5 @@ rng_state tags *.pc src/sdis_version.h +*.vtk +*.obj diff --git a/Makefile b/Makefile @@ -38,6 +38,7 @@ SRC =\ src/sdis_green.c\ src/sdis_heat_path.c\ src/sdis_heat_path_boundary.c\ + src/sdis_heat_path_conductive.c\ src/sdis_interface.c\ src/sdis_log.c\ src/sdis_medium.c\ @@ -89,6 +90,8 @@ libsdis.o: $(OBJ) echo "senc3d $(SENC3D_VERSION) not found" >&2; exit 1; fi @if ! $(PKG_CONFIG) --atleast-version $(SSP_VERSION) star-sp; then \ echo "star-sp $(SSP_VERSION) not found" >&2; exit 1; fi + @if ! $(PKG_CONFIG) --atleast-version $(SWF_VERSION) swf; then \ + echo "swf $(SWF_VERSION) not found" >&2; exit 1; fi @echo "config done" > $@ .SUFFIXES: .c .d .o @@ -195,6 +198,10 @@ TEST_SRC =\ src/test_sdis_source.c\ src/test_sdis_transcient.c\ src/test_sdis_unstationary_atm.c\ + src/test_sdis_unsteady.c\ + src/test_sdis_unsteady_1d.c\ + src/test_sdis_unsteady_analytic_profile.c\ + src/test_sdis_unsteady_analytic_profile_2d.c\ src/test_sdis_volumic_power.c\ src/test_sdis_volumic_power4.c TEST_SRC_LONG =\ @@ -268,6 +275,8 @@ test_all: test clean_test: @$(SHELL) make.sh clean_test $(TEST_SRC) $(TEST_SRC_MPI) $(TEST_SRC_LONG) + rm -f super_shape_2d.obj paths_wos_2d.vtk paths_delta_sphere_2d.vtk + rm -f super_shape_3d.obj paths_wos_3d.vtk paths_delta_sphere_3d.vtk rm -f rng_state ################################################################################ @@ -295,6 +304,9 @@ src/test_sdis_solve_probe3_2d \ src/test_sdis_source.d \ src/test_sdis_transcient.d \ src/test_sdis_unstationary_atm.d \ +src/test_sdis_unsteady.d \ +src/test_sdis_unsteady_1d.d \ +src/test_sdis_unsteady_analytic_profile_2d.d \ src/test_sdis_utils.d \ src/test_sdis_volumic_power.d \ src/test_sdis_volumic_power2.d \ @@ -326,6 +338,9 @@ src/test_sdis_solve_probe3_2d.o \ src/test_sdis_source.o \ src/test_sdis_transcient.o \ src/test_sdis_unstationary_atm.o \ +src/test_sdis_unsteady.o \ +src/test_sdis_unsteady_1d.o \ +src/test_sdis_unsteady_analytic_profile_2d.o \ src/test_sdis_utils.o \ src/test_sdis_volumic_power.o \ src/test_sdis_volumic_power2.o \ @@ -357,6 +372,9 @@ test_sdis_solve_probe3_2d \ test_sdis_source \ test_sdis_transcient \ test_sdis_unstationary_atm \ +test_sdis_unsteady \ +test_sdis_unsteady_1d \ +test_sdis_unsteady_analytic_profile_2d \ test_sdis_volumic_power \ test_sdis_volumic_power2 \ test_sdis_volumic_power2_2d \ @@ -371,18 +389,21 @@ test_sdis_volumic_power4 \ src/test_sdis_draw_external_flux.d \ src/test_sdis_solid_random_walk_robustness.d \ src/test_sdis_solve_probe3.d \ +src/test_sdis_unsteady_analytic_profile.d \ : config.mk sdis-local.pc @$(CC) $(TEST_CFLAGS) $(S3DUT_CFLAGS) -MM -MT "$(@:.d=.o) $@" $(@:.d=.c) -MF $@ src/test_sdis_draw_external_flux.o \ src/test_sdis_solid_random_walk_robustness.o \ src/test_sdis_solve_probe3.o \ +src/test_sdis_unsteady_analytic_profile.o \ : config.mk sdis-local.pc $(CC) $(TEST_CFLAGS) $(S3DUT_CFLAGS) -c $(@:.o=.c) -o $@ test_sdis_draw_external_flux \ test_sdis_solid_random_walk_robustness \ test_sdis_solve_probe3 \ +test_sdis_unsteady_analytic_profile \ : config.mk sdis-local.pc $(LIBNAME) src/test_sdis_utils.o $(CC) $(TEST_CFLAGS) $(S3DUT_CFLAGS) -o $@ src/$@.o $(TEST_LIBS) $(S3DUT_LIBS) diff --git a/config.mk b/config.mk @@ -63,6 +63,10 @@ SSP_VERSION = 0.14 SSP_CFLAGS = $$($(PKG_CONFIG) $(PCFLAGS) --cflags star-sp) SSP_LIBS = $$($(PKG_CONFIG) $(PCFLAGS) --libs star-sp) +SWF_VERSION = 0.0 +SWF_CFLAGS = $$($(PKG_CONFIG) $(PCFLAGS) --cflags swf) +SWF_LIBS = $$($(PKG_CONFIG) $(PCFLAGS) --libs swf) + # For tests only S3DUT_VERSION = 0.4 S3DUT_CFLAGS = $$($(PKG_CONFIG) $(PCFLAGS) --cflags s3dut) @@ -75,6 +79,7 @@ DPDC_CFLAGS =\ $(SENC2D_CFLAGS)\ $(SENC3D_CFLAGS)\ $(SSP_CFLAGS)\ + $(SWF_CFLAGS)\ $($(DISTRIB_PARALLELISM)_CFLAGS)\ -fopenmp DPDC_LIBS =\ @@ -84,6 +89,7 @@ DPDC_LIBS =\ $(SENC2D_LIBS)\ $(SENC3D_LIBS)\ $(SSP_LIBS)\ + $(SWF_LIBS)\ $($(DISTRIB_PARALLELISM)_LIBS)\ -lm\ -fopenmp diff --git a/src/sdis.h b/src/sdis.h @@ -50,6 +50,11 @@ #define SDIS_FLUX_NONE DBL_MAX /* <=> No flux */ #define SDIS_PRIMITIVE_NONE SIZE_MAX /* Invalid primitive */ +/* Syntactic sugar used to define whether a temperature is known or not */ +#define SDIS_TEMPERATURE_NONE NaN /* Unknown temperature */ +#define SDIS_TEMPERATURE_IS_KNOWN(Temp) (!IS_NaN(Temp)) +#define SDIS_TEMPERATURE_IS_UNKNOWN(Temp) (IS_NaN(Temp)) + /* Forward declaration of external opaque data types */ struct logger; struct mem_allocator; @@ -91,6 +96,13 @@ enum sdis_scene_dimension { SDIS_SCENE_3D }; +enum sdis_diffusion_algorithm { + SDIS_DIFFUSION_DELTA_SPHERE, + SDIS_DIFFUSION_WOS, /* Walk on Sphere */ + SDIS_DIFFUSION_ALGORITHMS_COUNT__, + SDIS_DIFFUSION_NONE = SDIS_DIFFUSION_ALGORITHMS_COUNT__ +}; + /* Random walk vertex, i.e. a spatiotemporal position at a given step of the * random walk. */ struct sdis_rwalk_vertex { @@ -235,13 +247,14 @@ struct sdis_solid_shader { * submitted position and time */ sdis_medium_getter_T volumic_power; /* In W.m^-3 */ - /* Initial/limit condition. A temperature < 0 means that the temperature is - * unknown for the submitted random walk vertex. + /* Initial/limit condition. A temperature set to SDIS_TEMPERATURE_NONE + * means that the temperature is unknown for the submitted random walk vertex. * This getter is always called at time >= t0 (see below). */ sdis_medium_getter_T temperature; - /* The time until the initial condition is maintained for this solid; - * can neither be negative nor infinity, default is 0. */ + /* The time until the initial condition is maintained for this solid. + * Can be negative or set to +/- infinity to simulate a system that is always + * in the initial state or never reaches it, respectively. */ double t0; }; #define SDIS_SOLID_SHADER_NULL__ {NULL, NULL, NULL, NULL, NULL, NULL, 0} @@ -254,12 +267,14 @@ struct sdis_fluid_shader { sdis_medium_getter_T calorific_capacity; /* In J.K^-1.kg^-1 */ sdis_medium_getter_T volumic_mass; /* In kg.m^-3 */ - /* Initial/limit condition. A temperature < 0 means that the temperature is - * unknown for the submitted random walk vertex. + /* Initial/limit condition. A temperature set to SDIS_TEMPERATURE_NONE + * means that the temperature is unknown for the submitted random walk vertex. * This getter is always called at time >= t0 (see below). */ sdis_medium_getter_T temperature; - /* The time until the initial condition is maintained for this fluid; - * can neither be negative nor infinity, default is 0. */ + + /* The time until the initial condition is maintained for this fluid. + * Can be negative or set to +/- infinity to simulate a system that is always + * in the initial state or never reaches it, respectively. */ double t0; }; #define SDIS_FLUID_SHADER_NULL__ {NULL, NULL, NULL, 0} @@ -270,8 +285,8 @@ static const struct sdis_fluid_shader SDIS_FLUID_SHADER_NULL = struct sdis_interface_side_shader { /* Fixed temperature/flux. May be NULL if the temperature/flux is unknown * onto the whole interface */ - sdis_interface_getter_T temperature; /* In Kelvin. < 0 <=> Unknown temp */ - sdis_interface_getter_T flux; /* In W.m^-2. SDIS_FLUX_NONE <=> no flux */ + sdis_interface_getter_T temperature; /* [K]. SDIS_TEMPERATURE_NONE = Unknown */ + sdis_interface_getter_T flux; /* [W.m^-2]. SDIS_FLUX_NONE = no flux */ /* Control the emissivity of the interface. May be NULL for solid/solid * interface or if the emissivity is 0 onto the whole interface. */ @@ -439,7 +454,10 @@ struct sdis_ambient_radiative_temperature { double temperature; /* In Kelvin */ double reference; /* Used to linearise the radiative transfer */ }; -#define SDIS_AMBIENT_RADIATIVE_TEMPERATURE_NULL__ {-1, -1} +#define SDIS_AMBIENT_RADIATIVE_TEMPERATURE_NULL__ { \ + SDIS_TEMPERATURE_NONE, \ + SDIS_TEMPERATURE_NONE \ +} static const struct sdis_ambient_radiative_temperature SDIS_AMBIENT_RADIATIVE_TEMPERATURE_NULL = SDIS_AMBIENT_RADIATIVE_TEMPERATURE_NULL__; @@ -475,7 +493,7 @@ struct sdis_scene_create_args { 0, /* #vertices */ \ 1.0, /* #Floating point to meter scale factor */ \ SDIS_AMBIENT_RADIATIVE_TEMPERATURE_NULL__,/* Ambient radiative temperature */\ - {0.0, -1.0}, /* Temperature range */ \ + {SDIS_TEMPERATURE_NONE, SDIS_TEMPERATURE_NONE}, /* Temperature range */ \ NULL /* source */ \ } static const struct sdis_scene_create_args SDIS_SCENE_CREATE_ARGS_DEFAULT = @@ -498,6 +516,8 @@ struct sdis_solve_probe_args { struct ssp_rng* rng_state; /* Initial RNG state. May be NULL */ enum ssp_rng_type rng_type; /* RNG type to use if `rng_state' is NULL */ + enum sdis_diffusion_algorithm diff_algo; /* Diffusion algorithm to be used */ + /* Signature of the estimated green function. The signature is ignored in an * ordinary probe estimation. The signature of the green function can be * queried to verify that it is the expected one with respect to the caller's @@ -512,6 +532,7 @@ struct sdis_solve_probe_args { SDIS_HEAT_PATH_NONE, /* Register paths mask */ \ NULL, /* RNG state */ \ SSP_RNG_THREEFRY, /* RNG type */ \ + SDIS_DIFFUSION_DELTA_SPHERE, /* Diffusion algorithm */ \ {0} /* Signature */ \ } static const struct sdis_solve_probe_args SDIS_SOLVE_PROBE_ARGS_DEFAULT = @@ -552,6 +573,8 @@ struct sdis_solve_probe_boundary_args { struct ssp_rng* rng_state; /* Initial RNG state. May be NULL */ enum ssp_rng_type rng_type; /* RNG type to use if `rng_state' is NULL */ + enum sdis_diffusion_algorithm diff_algo; /* Diffusion algorithm to be used */ + /* Signature of the estimated green function. The signature is ignored in an * ordinary probe estimation. The signature of the green function can be * queried to verify that it is the expected one with respect to the caller's @@ -568,6 +591,7 @@ struct sdis_solve_probe_boundary_args { SDIS_HEAT_PATH_NONE, \ NULL, /* RNG state */ \ SSP_RNG_THREEFRY, /* RNG type */ \ + SDIS_DIFFUSION_DELTA_SPHERE, /* Diffusion algorithm */ \ {0} /* Signature */ \ } static const struct sdis_solve_probe_boundary_args @@ -611,6 +635,8 @@ struct sdis_solve_boundary_args { struct ssp_rng* rng_state; /* Initial RNG state. May be NULL */ enum ssp_rng_type rng_type; /* RNG type to use if `rng_state' is NULL */ + enum sdis_diffusion_algorithm diff_algo; /* Diffusion algorithm to be used */ + /* Signature of the estimated green function. The signature is ignored in an * ordinary probe estimation. The signature of the green function can be * queried to verify that it is the expected one with respect to the caller's @@ -627,6 +653,7 @@ struct sdis_solve_boundary_args { SDIS_HEAT_PATH_NONE, \ NULL, /* RNG state */ \ SSP_RNG_THREEFRY, /* RNG type */ \ + SDIS_DIFFUSION_DELTA_SPHERE, /* Diffusion algorithm */ \ {0} /* Signature */ \ } static const struct sdis_solve_boundary_args SDIS_SOLVE_BOUNDARY_ARGS_DEFAULT = @@ -646,6 +673,8 @@ struct sdis_solve_medium_args { struct ssp_rng* rng_state; /* Initial RNG state. May be NULL */ enum ssp_rng_type rng_type; /* RNG type to use if `rng_state' is NULL */ + enum sdis_diffusion_algorithm diff_algo; /* Diffusion algorithm to be used */ + /* Signature of the estimated green function. The signature is ignored in an * ordinary probe estimation. The signature of the green function can be * queried to verify that it is the expected one with respect to the caller's @@ -660,6 +689,7 @@ struct sdis_solve_medium_args { SDIS_HEAT_PATH_NONE, \ NULL, /* RNG state */ \ SSP_RNG_THREEFRY, /* RNG type */ \ + SDIS_DIFFUSION_DELTA_SPHERE, /* Diffusion algorithm */ \ {0} /* Signature */ \ } static const struct sdis_solve_medium_args SDIS_SOLVE_MEDIUM_ARGS_DEFAULT = @@ -678,6 +708,8 @@ struct sdis_solve_probe_boundary_flux_args { struct ssp_rng* rng_state; /* Initial RNG state. May be NULL */ enum ssp_rng_type rng_type; /* RNG type to use if `rng_state' is NULL */ + + enum sdis_diffusion_algorithm diff_algo; /* Diffusion algorithm to be used */ }; #define SDIS_SOLVE_PROBE_BOUNDARY_FLUX_ARGS_DEFAULT__ { \ 10000, /* #realisations */ \ @@ -686,7 +718,8 @@ struct sdis_solve_probe_boundary_flux_args { {DBL_MAX,DBL_MAX}, /* Time range */ \ 1, /* Picard order */ \ NULL, /* RNG state */ \ - SSP_RNG_THREEFRY /* RNG type */ \ + SSP_RNG_THREEFRY, /* RNG type */ \ + SDIS_DIFFUSION_DELTA_SPHERE /* Diffusion algorithm */ \ } static const struct sdis_solve_probe_boundary_flux_args SDIS_SOLVE_PROBE_BOUNDARY_FLUX_ARGS_DEFAULT = @@ -705,6 +738,8 @@ struct sdis_solve_boundary_flux_args { struct ssp_rng* rng_state; /* Initial RNG state. May be NULL */ enum ssp_rng_type rng_type; /* RNG type to use if `rng_state' is NULL */ + + enum sdis_diffusion_algorithm diff_algo; /* Diffusion algorithm to be used */ }; #define SDIS_SOLVE_BOUNDARY_FLUX_ARGS_DEFAULT__ { \ 10000, /* #realisations */ \ @@ -713,7 +748,8 @@ struct sdis_solve_boundary_flux_args { {DBL_MAX,DBL_MAX}, /* Time range */ \ 1, /* Picard order */ \ NULL, /* RNG state */ \ - SSP_RNG_THREEFRY /* RNG type */ \ + SSP_RNG_THREEFRY, /* RNG type */ \ + SDIS_DIFFUSION_DELTA_SPHERE /* Diffusion algorithm */ \ } static const struct sdis_solve_boundary_flux_args SDIS_SOLVE_BOUNDARY_FLUX_ARGS_DEFAULT = @@ -734,6 +770,8 @@ struct sdis_solve_camera_args { struct ssp_rng* rng_state; /* Initial RNG state. May be NULL */ enum ssp_rng_type rng_type; /* RNG type to use */ + + enum sdis_diffusion_algorithm diff_algo; /* Diffusion algorithm to be used */ }; #define SDIS_SOLVE_CAMERA_ARGS_DEFAULT__ { \ NULL, /* Camera */ \ @@ -743,7 +781,8 @@ struct sdis_solve_camera_args { 256, /* #realisations per pixel */ \ SDIS_HEAT_PATH_NONE, \ NULL, /* RNG state */ \ - SSP_RNG_THREEFRY /* RNG type */ \ + SSP_RNG_THREEFRY, /* RNG type */ \ + SDIS_DIFFUSION_DELTA_SPHERE /* Diffusion algorithm */ \ } static const struct sdis_solve_camera_args SDIS_SOLVE_CAMERA_ARGS_DEFAULT = SDIS_SOLVE_CAMERA_ARGS_DEFAULT__; diff --git a/src/sdis_Xd_begin.h b/src/sdis_Xd_begin.h @@ -13,63 +13,9 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ -#ifndef SDIS_XD_BEGIN_H -#define SDIS_XD_BEGIN_H - +#include "sdis.h" #include <rsys/rsys.h> -/* Forward declaration */ -struct green_path_handle; -struct sdis_heat_path; - -struct rwalk_context { - struct green_path_handle* green_path; - struct sdis_heat_path* heat_path; - - double Tmin; /* Lower bound temperature */ - double Tmin2; /* Tmin^2 */ - double Tmin3; /* Tmin^3 */ - - double That; /* Upper bound temperature */ - double That2; /* That^2 */ - double That3; /* That^3 */ - - /* Maximum branchings i.e. the maximum number of times XD(sample_coupled_path) - * can be called. It controls the number of ramifications of the heat path and - * currently is correlated to the Picard order used to estimate the radiative - * temperature. max_branchings == picard_order-1 */ - size_t max_branchings; - - /* Number of heat path branchings */ - size_t nbranchings; - - /* Id of the realisation (for debug) */ - size_t irealisation; -}; -#define RWALK_CONTEXT_NULL__ { \ - NULL, /* Green path */ \ - NULL, /* Heat path */ \ - 0, /* Tmin */ \ - 0, /* Tmin^2 */ \ - 0, /* Tmin^3 */ \ - 0, /* That */ \ - 0, /* That^2 */ \ - 0, /* That^3 */ \ - 0, /* Max #branchings */ \ - SIZE_MAX, /* #branchings */ \ - SIZE_MAX /* realisation id */ \ -} -static const struct rwalk_context RWALK_CONTEXT_NULL = RWALK_CONTEXT_NULL__; - -static INLINE size_t -get_picard_order(const struct rwalk_context* ctx) -{ - ASSERT(ctx); - return ctx->max_branchings + 1; -} - -#endif /* SDIS_XD_BEGIN_H */ - #ifdef SDIS_XD_BEGIN_H__ #error "This header is already included without its associated sdis_Xd_end.h file." #endif @@ -140,6 +86,8 @@ get_picard_order(const struct rwalk_context* ctx) #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 */ diff --git a/src/sdis_device.c b/src/sdis_device.c @@ -25,6 +25,7 @@ #include <star/s2d.h> #include <star/s3d.h> #include <star/ssp.h> +#include <star/swf.h> #include <omp.h> @@ -251,6 +252,37 @@ error: } static INLINE res_T +setup_starwf(struct sdis_device* dev) +{ + struct swf_H_tabulate_args H2d_args = SWF_H2D_TABULATE_ARGS_DEFAULT; + struct swf_H_tabulate_args H3d_args = SWF_H3D_TABULATE_ARGS_DEFAULT; + res_T res = RES_OK; + ASSERT(dev); + + H2d_args.allocator = dev->allocator; + H3d_args.allocator = dev->allocator; + + res = swf_H2d_tabulate(&H2d_args, &dev->H_2d); + if(res != RES_OK) { + log_err(dev, "Unable to tabulate H2d function -- %s.\n", + res_to_cstr(res)); + goto error; + } + + res = swf_H3d_tabulate(&H3d_args, &dev->H_3d); + if(res != RES_OK) { + log_err(dev, "Unable to tabulate H3d function -- %s.\n", + res_to_cstr(res)); + goto error; + } + +exit: + return res; +error: + goto exit; +} + +static INLINE res_T setup_mpi(struct sdis_device* dev, const struct sdis_device_create_args* args) { ASSERT(dev && args); @@ -279,6 +311,8 @@ device_release(ref_T* ref) dev = CONTAINER_OF(ref, struct sdis_device, ref); if(dev->s2d_dev) S2D(device_ref_put(dev->s2d_dev)); if(dev->s3d_dev) S3D(device_ref_put(dev->s3d_dev)); + if(dev->H_2d) SWF(tabulation_ref_put(dev->H_2d)); + if(dev->H_3d) SWF(tabulation_ref_put(dev->H_3d)); if(dev->logger == &dev->logger__) logger_release(&dev->logger__); ASSERT(flist_name_is_empty(&dev->interfaces_names)); ASSERT(flist_name_is_empty(&dev->media_names)); @@ -342,6 +376,8 @@ sdis_device_create if(res != RES_OK) goto error; res = setup_star3d(dev); if(res != RES_OK) goto error; + res = setup_starwf(dev); + if(res != RES_OK) goto error; res = setup_mpi(dev, args); if(res != RES_OK) goto error; diff --git a/src/sdis_device_c.h b/src/sdis_device_c.h @@ -36,6 +36,7 @@ struct mutex; struct ssp_rng; struct ssp_rng_proxy; +struct swf_tabulation; struct name { FITEM; void* mem; }; #define FITEM_TYPE name @@ -64,6 +65,9 @@ struct sdis_device { struct s2d_device* s2d_dev; struct s3d_device* s3d_dev; + struct swf_tabulation* H_2d; + struct swf_tabulation* H_3d; + ref_T ref; }; diff --git a/src/sdis_heat_path.c b/src/sdis_heat_path.c @@ -27,12 +27,6 @@ #define SDIS_XD_DIMENSION 3 #include "sdis_heat_path_convective_Xd.h" -/* Generate the conductive path routines */ -#define SDIS_XD_DIMENSION 2 -#include "sdis_heat_path_conductive_Xd.h" -#define SDIS_XD_DIMENSION 3 -#include "sdis_heat_path_conductive_Xd.h" - /******************************************************************************* * Local functions ******************************************************************************/ diff --git a/src/sdis_heat_path.h b/src/sdis_heat_path.h @@ -23,22 +23,77 @@ #include <rsys/rsys.h> /* Forward declarations */ +struct green_path_handle; struct rwalk_2d; struct rwalk_3d; -struct rwalk_context; 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 + * solve parameters. + ******************************************************************************/ + struct rwalk_context { + struct green_path_handle* green_path; + struct sdis_heat_path* heat_path; + + double Tmin; /* Lower bound temperature */ + double Tmin2; /* Tmin^2 */ + double Tmin3; /* Tmin^3 */ + + double That; /* Upper bound temperature */ + double That2; /* That^2 */ + double That3; /* That^3 */ + + /* Maximum branchings i.e. the maximum number of times XD(sample_coupled_path) + * can be called. It controls the number of ramifications of the heat path and + * currently is correlated to the Picard order used to estimate the radiative + * temperature. max_branchings == picard_order-1 */ + size_t max_branchings; + + /* Number of heat path branchings */ + size_t nbranchings; + + /* Id of the realisation (for debug) */ + size_t irealisation; + + /* Algorithm used for the diffusive random walks, + * i.e. for sampling conductive paths */ + enum sdis_diffusion_algorithm diff_algo; +}; +#define RWALK_CONTEXT_NULL__ { \ + NULL, /* Green path */ \ + NULL, /* Heat path */ \ + 0, /* Tmin */ \ + 0, /* Tmin^2 */ \ + 0, /* Tmin^3 */ \ + 0, /* That */ \ + 0, /* That^2 */ \ + 0, /* That^3 */ \ + 0, /* Max #branchings */ \ + SIZE_MAX, /* #branchings */ \ + SIZE_MAX, /* realisation id */ \ + SDIS_DIFFUSION_NONE /* Diffusion algorithm */ \ +} +static const struct rwalk_context RWALK_CONTEXT_NULL = RWALK_CONTEXT_NULL__; + +static INLINE size_t +get_picard_order(const struct rwalk_context* ctx) +{ + ASSERT(ctx); + return ctx->max_branchings + 1; +} + +/******************************************************************************* + * Heat path data structure used to record the geometry of sampled paths + ******************************************************************************/ /* Generate the dynamic array of heat vertices */ #define DARRAY_NAME heat_vertex #define DARRAY_DATA struct sdis_heat_vertex #include <rsys/dynamic_array.h> -/******************************************************************************* - * Heat path data structure - ******************************************************************************/ struct sdis_heat_path { /* List of the path vertices */ struct darray_heat_vertex vertices; @@ -293,4 +348,3 @@ boundary_path_3d struct temperature_3d* temperature); #endif /* SDIS_HEAT_PATH_H */ - diff --git a/src/sdis_heat_path_boundary_Xd.h b/src/sdis_heat_path_boundary_Xd.h @@ -54,7 +54,7 @@ XD(boundary_path) /* Check if the boundary temperature is known */ tmp = interface_side_get_temperature(interf, &frag); - if(tmp >= 0) { + if(SDIS_TEMPERATURE_IS_KNOWN(tmp)) { T->value += tmp; T->done = 1; diff --git a/src/sdis_heat_path_boundary_Xd_c.h b/src/sdis_heat_path_boundary_Xd_c.h @@ -992,4 +992,40 @@ error: goto exit; } +res_T +XD(check_Tref) + (const struct sdis_scene* scn, + const double pos[DIM], + const double Tref, + const char* func_name) +{ + ASSERT(scn && pos && func_name); + + if(SDIS_TEMPERATURE_IS_UNKNOWN(Tref)) { + log_err(scn->dev, + "%s: invalid reference temperature at the position `"FORMAT_VECX"'.\n", + func_name, SPLITX(pos)); + return RES_BAD_OP_IRRECOVERABLE; + } + + if(SDIS_TEMPERATURE_IS_UNKNOWN(scn->tmin) + || SDIS_TEMPERATURE_IS_UNKNOWN(scn->tmax)) { + log_err(scn->dev, + "%s: invalid scene temperature range. " + "At least one boundary is unknown.\n", + func_name); + return RES_BAD_OP_IRRECOVERABLE; + } + + if(Tref > scn->tmax) { + log_err(scn->dev, + "%s: invalid maximum temperature `%gK'. The reference temperature `%gK' " + "at the position `"FORMAT_VECX"' is greater than this temperature.\n", + func_name, scn->tmax, Tref, SPLITX(pos)); + return RES_BAD_OP_IRRECOVERABLE; + } + + return RES_OK; +} + #include "sdis_Xd_end.h" diff --git a/src/sdis_heat_path_boundary_Xd_solid_fluid_picard1.h b/src/sdis_heat_path_boundary_Xd_solid_fluid_picard1.h @@ -28,39 +28,13 @@ * Helper functions ******************************************************************************/ static INLINE res_T -XD(check_Tref) - (const struct sdis_scene* scn, - const double pos[DIM], - const double Tref, - const char* func_name) -{ - ASSERT(scn && pos && func_name); - - if(Tref < 0) { - log_err(scn->dev, - "%s: invalid reference temperature `%gK' at the position `"FORMAT_VECX"'.\n", - func_name, Tref, SPLITX(pos)); - return RES_BAD_OP_IRRECOVERABLE; - } - if(Tref > scn->tmax) { - log_err(scn->dev, - "%s: invalid maximum temperature `%gK'. The reference temperature `%gK' " - "at the position `"FORMAT_VECX"' is greater than this temperature.\n", - func_name, scn->tmax, Tref, SPLITX(pos)); - return RES_BAD_OP_IRRECOVERABLE; - } - - return RES_OK; -} - -static INLINE res_T XD(rwalk_get_Tref) (const struct sdis_scene* scn, const struct XD(rwalk)* rwalk, const struct XD(temperature)* T, double* out_Tref) { - double Tref = -1; + double Tref = SDIS_TEMPERATURE_NONE; res_T res = RES_OK; ASSERT(rwalk && T && out_Tref); @@ -213,7 +187,13 @@ XD(solid_fluid_boundary_picard1_path) /* Compute the convective, conductive and the upper bound radiative coef */ h_conv = interface_get_convection_coef(interf, frag); h_cond = lambda / delta_m; - h_radi_hat = 4.0 * BOLTZMANN_CONSTANT * ctx->That3 * epsilon; + if(epsilon <= 0) { + h_radi_hat = 0; /* No radiative transfert */ + } else { + res = scene_check_temperature_range(scn); + if(res != RES_OK) { res = RES_BAD_OP_IRRECOVERABLE; goto error; } + h_radi_hat = 4.0 * BOLTZMANN_CONSTANT * ctx->That3 * epsilon; + } /* Compute a global upper bound coefficient */ h_hat = h_conv + h_cond + h_radi_hat; @@ -305,6 +285,12 @@ XD(solid_fluid_boundary_picard1_path) res = XD(rwalk_get_Tref)(scn, &rwalk_s, &T_s, &Tref_s); if(res != RES_OK) goto error; + /* The reference temperatures must be known, as this is a radiative path. + * If this is not the case, an error should be reported before this point. + * Hence these assertions to detect unexpected behavior */ + ASSERT(SDIS_TEMPERATURE_IS_KNOWN(Tref)); + ASSERT(SDIS_TEMPERATURE_IS_KNOWN(Tref_s)); + h_radi = BOLTZMANN_CONSTANT * epsilon * ( Tref*Tref*Tref + Tref*Tref * Tref_s diff --git a/src/sdis_heat_path_boundary_Xd_solid_fluid_picardN.h b/src/sdis_heat_path_boundary_Xd_solid_fluid_picardN.h @@ -232,7 +232,15 @@ XD(solid_fluid_boundary_picardN_path) /* Compute the convective, conductive and the upper bound radiative coef */ h_conv = interface_get_convection_coef(interf, frag); h_cond = lambda / (delta * scn->fp_to_meter); - h_radi_hat = 4.0 * BOLTZMANN_CONSTANT * That3 * epsilon; + h_radi_hat = epsilon > 0 ? 4.0 * BOLTZMANN_CONSTANT * That3 * epsilon : 0; + + if(epsilon <= 0) { + h_radi_hat = 0; /* No radiative transfert */ + } else { + res = scene_check_temperature_range(scn); + if(res != RES_OK) { res = RES_BAD_OP_IRRECOVERABLE; goto error; } + h_radi_hat = 4.0 * BOLTZMANN_CONSTANT * That3 * epsilon; + } /* Compute a global upper bound coefficient */ h_hat = h_conv + h_cond + h_radi_hat; diff --git a/src/sdis_heat_path_boundary_c.h b/src/sdis_heat_path_boundary_c.h @@ -221,6 +221,23 @@ handle_external_net_flux_3d struct temperature_3d* T); /******************************************************************************* + * Miscellaneous functions + ******************************************************************************/ +extern LOCAL_SYM res_T +check_Tref_2d + (const struct sdis_scene* scn, + const double pos[2], + const double Tref, + const char* call_func_name); + +extern LOCAL_SYM res_T +check_Tref_3d + (const struct sdis_scene* scn, + const double pos[3], + const double Tref, + const char* call_func_name); + +/******************************************************************************* * Boundary sub-paths ******************************************************************************/ extern LOCAL_SYM res_T diff --git a/src/sdis_heat_path_conductive.c b/src/sdis_heat_path_conductive.c @@ -0,0 +1,128 @@ +/* Copyright (C) 2016-2023 |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_heat_path_conductive_c.h" +#include "sdis_log.h" +#include "sdis_medium_c.h" + +/******************************************************************************* + * Local function + ******************************************************************************/ +res_T +check_solid_constant_properties + (struct sdis_device* dev, + const int evaluate_green, + const int use_wos_diffusion, + const struct solid_props* props_ref, + const struct solid_props* props) +{ + res_T res = RES_OK; + ASSERT(dev && props_ref && props); + + if(props_ref->lambda != props->lambda) { + log_err(dev, + "%s: invalid thermal conductivity. One assumes a constant conductivity " + "for the whole solid.\n", FUNC_NAME); + res = RES_BAD_ARG; + goto error; + } + + if(props_ref->rho != props->rho) { + log_err(dev, + "%s: invalid volumic mass. One assumes a constant volumic mass for " + "the whole solid.\n", FUNC_NAME); + res = RES_BAD_ARG; + goto error; + } + + if(props_ref->cp != props->cp) { + log_err(dev, + "%s: invalid calorific capacity. One assumes a constant calorific " + "capacity for the whole solid.\n", FUNC_NAME); + res = RES_BAD_ARG; + goto error; + } + + if((evaluate_green || use_wos_diffusion) && props_ref->power != props->power) { + log_err(dev, + "%s: invalid variable power density. Stardis expects a constant power " + "density per solid when using WoS diffusion and/or green function " + "evaluation.", FUNC_NAME); + res = RES_BAD_ARG; + goto error; + } + +exit: + return res; +error: + goto exit; +} + +res_T +conductive_path_2d + (struct sdis_scene* scn, + struct rwalk_context* ctx, + struct rwalk_2d* rwalk, + struct ssp_rng* rng, + struct temperature_2d* T) +{ + res_T res = RES_OK; + ASSERT(ctx); + + switch(ctx->diff_algo) { + case SDIS_DIFFUSION_DELTA_SPHERE: + res = conductive_path_delta_sphere_2d(scn, ctx, rwalk, rng, T); + break; + case SDIS_DIFFUSION_WOS: + res = conductive_path_wos_2d(scn, ctx, rwalk, rng, T); + break; + default: FATAL("Unreachable code.\n"); break; + } + return res; +} + +res_T +conductive_path_3d + (struct sdis_scene* scn, + struct rwalk_context* ctx, + struct rwalk_3d* rwalk, + struct ssp_rng* rng, + struct temperature_3d* T) +{ + res_T res = RES_OK; + ASSERT(ctx); + + switch(ctx->diff_algo) { + case SDIS_DIFFUSION_DELTA_SPHERE: + res = conductive_path_delta_sphere_3d(scn, ctx, rwalk, rng, T); + break; + case SDIS_DIFFUSION_WOS: + res = conductive_path_wos_3d(scn, ctx, rwalk, rng, T); + break; + default: FATAL("Unreachable code.\n"); break; + } + return res; +} + +/* Generate the conductive path functions */ +#define SDIS_XD_DIMENSION 2 +#include "sdis_heat_path_conductive_delta_sphere_Xd.h" +#define SDIS_XD_DIMENSION 3 +#include "sdis_heat_path_conductive_delta_sphere_Xd.h" +#define SDIS_XD_DIMENSION 2 +#include "sdis_heat_path_conductive_wos_Xd.h" +#define SDIS_XD_DIMENSION 3 +#include "sdis_heat_path_conductive_wos_Xd.h" diff --git a/src/sdis_heat_path_conductive_Xd.h b/src/sdis_heat_path_conductive_Xd.h @@ -1,541 +0,0 @@ -/* Copyright (C) 2016-2023 |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_device_c.h" -#include "sdis_green.h" -#include "sdis_heat_path.h" -#include "sdis_medium_c.h" -#include "sdis_misc.h" -#include "sdis_scene_c.h" - -#include <star/ssp.h> - -#include "sdis_Xd_begin.h" - -/******************************************************************************* - * Non generic helper functions - ******************************************************************************/ -#ifndef SDIS_HEAT_PATH_CONDUCTIVE_XD_H -#define SDIS_HEAT_PATH_CONDUCTIVE_XD_H - -static res_T -check_solid_constant_properties - (struct sdis_device* dev, - const int evaluate_green, - const struct solid_props* props_ref, - const struct solid_props* props) -{ - res_T res = RES_OK; - ASSERT(dev && props_ref && props); - - if(props_ref->lambda != props->lambda) { - log_err(dev, - "%s: invalid thermal conductivity. One assumes a constant conductivity " - "for the whole solid.\n", FUNC_NAME); - res = RES_BAD_ARG; - goto error; - } - - if(props_ref->rho != props->rho) { - log_err(dev, - "%s: invalid volumic mass. One assumes a constant volumic mass for " - "the whole solid.\n", FUNC_NAME); - res = RES_BAD_ARG; - goto error; - } - - if(props_ref->cp != props->cp) { - log_err(dev, - "%s: invalid calorific capacity. One assumes a constant calorific " - "capacity for the whole solid.\n", FUNC_NAME); - res = RES_BAD_ARG; - goto error; - } - - if(evaluate_green && props_ref->power != props->power) { - log_err(dev, - "%s: invalid volumic power. When estimating the green function, a " - "constant volumic power is assumed for the whole solid.\n", - FUNC_NAME); - res = RES_BAD_ARG; - goto error; - } - -exit: - return res; -error: - goto exit; -} - -#endif /* SDIS_HEAT_PATH_CONDUCTIVE_XD_H */ - -/******************************************************************************* - * Helper functions - ******************************************************************************/ -/* Sample the next direction to walk toward and compute the distance to travel. - * Return the sampled direction `dir0', the distance to travel along this - * direction, the hit `hit0' along `dir0' wrt to the returned distance, the - * direction `dir1' used to adjust the displacement distance, and the hit - * `hit1' along `dir1' used to adjust the displacement distance. */ -static float -XD(sample_next_step) - (struct sdis_scene* scn, - struct ssp_rng* rng, - const float pos[DIM], - const float delta_solid, - float dir0[DIM], /* Sampled direction */ - float dir1[DIM], /* Direction used to adjust delta */ - struct sXd(hit)* hit0, /* Hit along the sampled direction */ - struct sXd(hit)* hit1) /* Hit used to adjust delta */ -{ - struct sXd(hit) hits[2]; - float dirs[2][DIM]; - float range[2]; - float delta; - ASSERT(scn && rng && pos && delta_solid>0 && dir0 && dir1 && hit0 && hit1); - - *hit0 = SXD_HIT_NULL; - *hit1 = SXD_HIT_NULL; - -#if DIM == 2 - /* Sample a main direction around 2PI */ - ssp_ran_circle_uniform_float(rng, dirs[0], NULL); -#else - /* Sample a main direction around 4PI */ - ssp_ran_sphere_uniform_float(rng, dirs[0], NULL); -#endif - - /* Negate the sampled dir */ - fX(minus)(dirs[1], dirs[0]); - - /* Use the previously sampled direction to estimate the minimum distance from - * `pos' to the scene boundary */ - f2(range, FLT_MIN, delta_solid*RAY_RANGE_MAX_SCALE); - SXD(scene_view_trace_ray(scn->sXd(view), pos, dirs[0], range, NULL, &hits[0])); - SXD(scene_view_trace_ray(scn->sXd(view), pos, dirs[1], range, NULL, &hits[1])); - if(SXD_HIT_NONE(&hits[0]) && SXD_HIT_NONE(&hits[1])) { - delta = delta_solid; - } else { - delta = MMIN(hits[0].distance, hits[1].distance); - } - - if(!SXD_HIT_NONE(&hits[0]) - && delta != hits[0].distance - && eq_eps(hits[0].distance, delta, delta_solid*0.1)) { - /* Set delta to the main hit distance if it is roughly equal to it in order - * to avoid numerical issues on moving along the main direction. */ - delta = hits[0].distance; - } - - /* Setup outputs */ - if(delta <= delta_solid*0.1 && hits[1].distance == delta) { - /* Snap the random walk to the boundary if delta is too small */ - fX(set)(dir0, dirs[1]); - *hit0 = hits[1]; - fX(splat)(dir1, (float)INF); - *hit1 = SXD_HIT_NULL; - } else { - fX(set)(dir0, dirs[0]); - *hit0 = hits[0]; - if(delta == hits[0].distance) { - fX(set)(dir1, dirs[0]); - *hit1 = hits[0]; - } else if(delta == hits[1].distance) { - fX(set)(dir1, dirs[1]); - *hit1 = hits[1]; - } else { - fX(splat)(dir1, 0); - *hit1 = SXD_HIT_NULL; - } - } - - return delta; -} - -/* Sample the next direction to walk toward and compute the distance to travel. - * If the targeted position does not lie inside the current medium, reject it - * and sample a new next step. */ -static res_T -XD(sample_next_step_robust) - (struct sdis_scene* scn, - struct sdis_medium* current_mdm, - struct ssp_rng* rng, - const double pos[DIM], - const float delta_solid, - float dir0[DIM], /* Sampled direction */ - float dir1[DIM], /* Direction used to adjust delta */ - struct sXd(hit)* hit0, /* Hit along the sampled direction */ - struct sXd(hit)* hit1, /* Hit used to adjust delta */ - float* out_delta) -{ - struct sdis_medium* mdm; - 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(dir0 && dir1 && hit0 && hit1 && out_delta); - - fX_set_dX(org, pos); - do { - double pos_next[DIM]; - - /* Compute the next step */ - delta = XD(sample_next_step) - (scn, rng, org, delta_solid, dir0, dir1, hit0, hit1); - - /* 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; } - 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); - } - - /* Check medium consistency */ - if(current_mdm != mdm) { -#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 -#endif - } - } while(current_mdm != mdm && ++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 - res = RES_BAD_OP; - goto error; - } - - *out_delta = delta; - -exit: - return res; -error: - goto exit; -} - - -/******************************************************************************* - * Handle the volumic power at a given diffusive step - ******************************************************************************/ -struct XD(handle_volumic_power_args) { - /* Forward/backward direction of the sampled diffusive step */ - const float* dir0; - const float* dir1; - - /* Forward/backward intersections along the sampled diffusive step */ - const struct sXd(hit)* hit0; - const struct sXd(hit)* hit1; - - /* Physical properties */ - double power; /* Volumic power */ - double lambda; /* Conductivity */ - - float delta_solid; /* Challenged length of a diffusive step */ - float delta; /* Current length of the current diffusive step */ - - size_t picard_order; -}; -static const struct XD(handle_volumic_power_args) -XD(HANDLE_VOLUMIC_POWER_ARGS_NULL) = { - NULL, NULL, NULL, NULL, -1, -1, -1, -1, 0 -}; - -static INLINE int -XD(check_handle_volumic_power_args) - (const struct XD(handle_volumic_power_args)* args) -{ - ASSERT(args); - return args - && args->dir0 - && args->dir1 - && args->hit0 - && args->hit1 - && args->lambda >= 0 - && args->delta_solid > 0 - && args->delta >= 0 - && args->delta_solid >= 0 - && args->picard_order > 0; -} - -static res_T -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) -{ - double power_term = 0; - res_T res = RES_OK; - ASSERT(scn && out_power_term && T && XD(check_handle_volumic_power_args)(args)); - - /* No volumic power. Do nothing */ - if(args->power == SDIS_VOLUMIC_POWER_NONE) goto exit; - - /* Check that picardN is not enabled when a volumic power is set since in - * this situation the upper bound of the Monte-Carlo weight required by - * picardN cannot be known */ - if(args->picard_order > 1) { - log_err(scn->dev, - "%s: invalid not null volumic power '%g' kg/m^3. Could not manage a " - "volumic power when the picard order is not equal to 1; Picard order is " - "currently set to %lu.\n", - FUNC_NAME, args->power, (unsigned long)args->picard_order); - res = RES_BAD_ARG; - goto error; - } - - /* No forward/backward intersection along the sampled direction */ - if(SXD_HIT_NONE(args->hit0) && SXD_HIT_NONE(args->hit1)) { - const double delta_in_meter = args->delta * scn->fp_to_meter; - power_term = delta_in_meter * delta_in_meter / (2.0 * DIM * args->lambda); - T->value += args->power * power_term; - - /* An intersection along this diffusive step is find. Use it to statically - * correct the power term currently registered */ - } else { - const double delta_s_adjusted = args->delta_solid * RAY_RANGE_MAX_SCALE; - const double delta_s_in_meter = args->delta_solid * scn->fp_to_meter; - double h; - double h_in_meter; - double cos_U_N; - float N[DIM] = {0}; - - if(args->delta == args->hit0->distance) { - fX(normalize)(N, args->hit0->normal); - cos_U_N = fX(dot)(args->dir0, N); - - } else { - ASSERT(args->delta == args->hit1->distance); - fX(normalize)(N, args->hit1->normal); - cos_U_N = fX(dot)(args->dir1, N); - } - - h = args->delta * fabs(cos_U_N); - h_in_meter = h * scn->fp_to_meter; - - /* The regular power term */ - power_term = h_in_meter * h_in_meter / (2.0*args->lambda); - - /* Add the power corrective term. Be careful to use the adjusted - * delta_solid to correctly handle the RAY_RANGE_MAX_SCALE factor in the - * computation of the limit angle. But keep going with the unmodified - * delta_solid in the corrective term since it was the one that was - * "wrongly" used in the previous step and that must be corrected. */ - if(h == delta_s_adjusted) { - power_term += - -(delta_s_in_meter * delta_s_in_meter) / (2.0*DIM*args->lambda); - - } else if(h < delta_s_adjusted) { - const double sin_a = h / delta_s_adjusted; -#if DIM==2 - /* tmp = sin(2a) / (PI - 2*a) */ - const double tmp = sin_a * sqrt(1 - sin_a*sin_a) / acos(sin_a); - power_term += - -(delta_s_in_meter * delta_s_in_meter) / (4.0*args->lambda) * tmp; -#else - const double tmp = (sin_a*sin_a*sin_a - sin_a) / (1-sin_a); - power_term += - (delta_s_in_meter * delta_s_in_meter) / (6.0*args->lambda) * tmp; -#endif - } - T->value += args->power * power_term; - } - -exit: - *out_power_term = power_term; - return res; -error: - goto exit; -} - -/******************************************************************************* - * Local function - ******************************************************************************/ -res_T -XD(conductive_path) - (struct sdis_scene* scn, - struct rwalk_context* ctx, - struct XD(rwalk)* rwalk, - struct ssp_rng* rng, - struct XD(temperature)* T) -{ - double position_start[DIM]; - struct solid_props props_ref = SOLID_PROPS_NULL; - double green_power_term = 0; - struct sdis_medium* mdm; - size_t istep = 0; /* Help for debug */ - res_T res = RES_OK; - ASSERT(scn && rwalk && rng && T); - ASSERT(rwalk->mdm->type == SDIS_SOLID); - (void)ctx, (void)istep; - - /* Check the random walk consistency */ - res = scene_get_medium_in_closed_boundaries(scn, rwalk->vtx.P, &mdm); - if(res != RES_OK || mdm != rwalk->mdm) { - log_err(scn->dev, "%s: invalid solid random walk. " - "Unexpected medium at {%g, %g, %g}.\n", FUNC_NAME, SPLIT3(rwalk->vtx.P)); - res = RES_BAD_OP_IRRECOVERABLE; - goto error; - } - /* Save the submitted position */ - dX(set)(position_start, rwalk->vtx.P); - - /* 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 - * remain the same. Note that we take care of the same constraints on the - * solid reinjection since once reinjected, the position of the random walk - * is that at the beginning of the conductive random walk. Thus, after a - * reinjection, the next line retrieves the properties of the reinjection - * 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(mdm, &rwalk->vtx, &props_ref); - - do { /* Solid random walk */ - struct XD(handle_volumic_power_args) handle_volpow_args = - XD(HANDLE_VOLUMIC_POWER_ARGS_NULL); - struct sXd(hit) hit0, hit1; - struct solid_props props = SOLID_PROPS_NULL; - double power_term = 0; - double mu; - float delta; /* Random walk numerical parameter */ - double delta_m; - float dir0[DIM], dir1[DIM]; - float org[DIM]; - - /* Fetch solid properties */ - res = solid_get_properties(mdm, &rwalk->vtx, &props); - if(res != RES_OK) goto error; - - res = check_solid_constant_properties - (scn->dev, ctx->green_path != NULL, &props_ref, &props); - if(res != RES_OK) goto error; - - /* Check the limit condition - * REVIEW Rfo: This can be a bug if the random walk comes from a boundary */ - if(props.temperature >= 0) { - T->value += props.temperature; - T->done = 1; - - 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; - } - - if(ctx->heat_path) { - heat_path_get_last_vertex(ctx->heat_path)->weight = T->value; - } - - break; - } - - 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, - (float)props.delta, dir0, dir1, &hit0, &hit1, &delta); - if(res != RES_OK) goto error; - - /* Add the volumic power density to the measured temperature */ - handle_volpow_args.dir0 = dir0; - handle_volpow_args.dir1 = dir1; - handle_volpow_args.hit0 = &hit0; - handle_volpow_args.hit1 = &hit1; - handle_volpow_args.power = props.power; - handle_volpow_args.lambda = props.lambda; - handle_volpow_args.delta_solid = (float)props.delta; - handle_volpow_args.delta = delta; - handle_volpow_args.picard_order = get_picard_order(ctx); - res = XD(handle_volumic_power)(scn, &handle_volpow_args, &power_term, T); - if(res != RES_OK) goto error; - - /* Register the power term for the green function. Delay its registration - * until the end of the conductive path, i.e. the path is valid */ - if(ctx->green_path && props.power != SDIS_VOLUMIC_POWER_NONE) { - green_power_term += power_term; - } - - /* 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); - 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->hit_side = SDIS_SIDE_NULL__; - } else { - rwalk->hit = hit0; - rwalk->hit_side = fX(dot)(hit0.normal, dir0) < 0 ? SDIS_FRONT : SDIS_BACK; - } - - /* Update the random walk position */ - XD(move_pos)(rwalk->vtx.P, dir0, delta); - - /* Register the new vertex against the heat path */ - res = register_heat_vertex(ctx->heat_path, &rwalk->vtx, T->value, - SDIS_HEAT_VERTEX_CONDUCTION, (int)ctx->nbranchings); - if(res != RES_OK) goto error; - - ++istep; - - /* Keep going while the solid random walk does not hit an interface */ - } while(SXD_HIT_NONE(&rwalk->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); - if(res != RES_OK) goto error; - } - - T->func = XD(boundary_path); - rwalk->mdm = NULL; /* The random walk is at an interface between 2 media */ - -exit: - return res; -error: - goto exit; -} - -#include "sdis_Xd_end.h" diff --git a/src/sdis_heat_path_conductive_c.h b/src/sdis_heat_path_conductive_c.h @@ -0,0 +1,78 @@ +/* Copyright (C) 2016-2023 |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/>. */ + +#ifndef SDIS_HEAT_PATH_CONDUCTIVE_C_H +#define SDIS_HEAT_PATH_CONDUCTIVE_C_H + +#include <rsys/rsys.h> + +/* Forward declarations */ +struct rwalk_2d; +struct rwalk_3d; +struct rwalk_context; +struct sdis_device; +struct sdis_scene; +struct solid_props; +struct ssp_rng; +struct temperature_2d; +struct temperature_3d; + +extern LOCAL_SYM res_T +check_solid_constant_properties + (struct sdis_device* dev, + const int evaluate_green, + const int use_wos_diffusion, + const struct solid_props* props_ref, + const struct solid_props* props); + +/******************************************************************************* + * Conductive paths using the delta sphere algorithm + ******************************************************************************/ +extern LOCAL_SYM res_T +conductive_path_delta_sphere_2d + (struct sdis_scene* scn, + struct rwalk_context* ctx, + struct rwalk_2d* rwalk, + struct ssp_rng* rng, + struct temperature_2d* T); + +extern LOCAL_SYM res_T +conductive_path_delta_sphere_3d + (struct sdis_scene* scn, + struct rwalk_context* ctx, + struct rwalk_3d* rwalk, + struct ssp_rng* rng, + struct temperature_3d* T); + +/******************************************************************************* + * Conductive paths using the walk on sphere algorithm + ******************************************************************************/ +extern LOCAL_SYM res_T +conductive_path_wos_2d + (struct sdis_scene* scn, + struct rwalk_context* ctx, + struct rwalk_2d* rwalk, + struct ssp_rng* rng, + struct temperature_2d* T); + +extern LOCAL_SYM res_T +conductive_path_wos_3d + (struct sdis_scene* scn, + struct rwalk_context* ctx, + struct rwalk_3d* rwalk, + struct ssp_rng* rng, + struct temperature_3d* 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 @@ -0,0 +1,481 @@ +/* Copyright (C) 2016-2023 |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_log.h" +#include "sdis_green.h" +#include "sdis_interface_c.h" +#include "sdis_medium_c.h" +#include "sdis_misc.h" +#include "sdis_scene_c.h" + +#include "sdis_Xd_begin.h" + +/******************************************************************************* + * Helper functions + ******************************************************************************/ +/* Sample the next direction to walk toward and compute the distance to travel. + * Return the sampled direction `dir0', the distance to travel along this + * direction, the hit `hit0' along `dir0' wrt to the returned distance, the + * direction `dir1' used to adjust the displacement distance, and the hit + * `hit1' along `dir1' used to adjust the displacement distance. */ +static float +XD(sample_next_step) + (struct sdis_scene* scn, + struct ssp_rng* rng, + const float pos[DIM], + const float delta_solid, + float dir0[DIM], /* Sampled direction */ + float dir1[DIM], /* Direction used to adjust delta */ + struct sXd(hit)* hit0, /* Hit along the sampled direction */ + struct sXd(hit)* hit1) /* Hit used to adjust delta */ +{ + struct sXd(hit) hits[2]; + float dirs[2][DIM]; + float range[2]; + float delta; + ASSERT(scn && rng && pos && delta_solid>0 && dir0 && dir1 && hit0 && hit1); + + *hit0 = SXD_HIT_NULL; + *hit1 = SXD_HIT_NULL; + +#if DIM == 2 + /* Sample a main direction around 2PI */ + ssp_ran_circle_uniform_float(rng, dirs[0], NULL); +#else + /* Sample a main direction around 4PI */ + ssp_ran_sphere_uniform_float(rng, dirs[0], NULL); +#endif + + /* Negate the sampled dir */ + fX(minus)(dirs[1], dirs[0]); + + /* Use the previously sampled direction to estimate the minimum distance from + * `pos' to the scene boundary */ + f2(range, FLT_MIN, delta_solid*RAY_RANGE_MAX_SCALE); + SXD(scene_view_trace_ray(scn->sXd(view), pos, dirs[0], range, NULL, &hits[0])); + SXD(scene_view_trace_ray(scn->sXd(view), pos, dirs[1], range, NULL, &hits[1])); + if(SXD_HIT_NONE(&hits[0]) && SXD_HIT_NONE(&hits[1])) { + delta = delta_solid; + } else { + delta = MMIN(hits[0].distance, hits[1].distance); + } + + if(!SXD_HIT_NONE(&hits[0]) + && delta != hits[0].distance + && eq_eps(hits[0].distance, delta, delta_solid*0.1)) { + /* Set delta to the main hit distance if it is roughly equal to it in order + * to avoid numerical issues on moving along the main direction. */ + delta = hits[0].distance; + } + + /* Setup outputs */ + if(delta <= delta_solid*0.1 && hits[1].distance == delta) { + /* Snap the random walk to the boundary if delta is too small */ + fX(set)(dir0, dirs[1]); + *hit0 = hits[1]; + fX(splat)(dir1, (float)INF); + *hit1 = SXD_HIT_NULL; + } else { + fX(set)(dir0, dirs[0]); + *hit0 = hits[0]; + if(delta == hits[0].distance) { + fX(set)(dir1, dirs[0]); + *hit1 = hits[0]; + } else if(delta == hits[1].distance) { + fX(set)(dir1, dirs[1]); + *hit1 = hits[1]; + } else { + fX(splat)(dir1, 0); + *hit1 = SXD_HIT_NULL; + } + } + + return delta; +} + +/* Sample the next direction to walk toward and compute the distance to travel. + * If the targeted position does not lie inside the current medium, reject it + * and sample a new next step. */ +static res_T +XD(sample_next_step_robust) + (struct sdis_scene* scn, + struct sdis_medium* current_mdm, + struct ssp_rng* rng, + const double pos[DIM], + const float delta_solid, + float dir0[DIM], /* Sampled direction */ + float dir1[DIM], /* Direction used to adjust delta */ + struct sXd(hit)* hit0, /* Hit along the sampled direction */ + struct sXd(hit)* hit1, /* Hit used to adjust delta */ + float* out_delta) +{ + struct sdis_medium* mdm; + 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(dir0 && dir1 && hit0 && hit1 && out_delta); + + fX_set_dX(org, pos); + do { + double pos_next[DIM]; + + /* Compute the next step */ + delta = XD(sample_next_step) + (scn, rng, org, delta_solid, dir0, dir1, hit0, hit1); + + /* 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; } + 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); + } + + /* Check medium consistency */ + if(current_mdm != mdm) { +#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 +#endif + } + } while(current_mdm != mdm && ++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 + res = RES_BAD_OP; + goto error; + } + + *out_delta = delta; + +exit: + return res; +error: + goto exit; +} + +/******************************************************************************* + * Handle the volumic power at a given diffusive step + ******************************************************************************/ +struct XD(handle_volumic_power_args) { + /* Forward/backward direction of the sampled diffusive step */ + const float* dir0; + const float* dir1; + + /* Forward/backward intersections along the sampled diffusive step */ + const struct sXd(hit)* hit0; + const struct sXd(hit)* hit1; + + /* Physical properties */ + double power; /* Volumic power */ + double lambda; /* Conductivity */ + + float delta_solid; /* Challenged length of a diffusive step */ + float delta; /* Current length of the current diffusive step */ + + size_t picard_order; +}; +static const struct XD(handle_volumic_power_args) +XD(HANDLE_VOLUMIC_POWER_ARGS_NULL) = { + NULL, NULL, NULL, NULL, -1, -1, -1, -1, 0 +}; + +static INLINE int +XD(check_handle_volumic_power_args) + (const struct XD(handle_volumic_power_args)* args) +{ + ASSERT(args); + return args + && args->dir0 + && args->dir1 + && args->hit0 + && args->hit1 + && args->lambda >= 0 + && args->delta_solid > 0 + && args->delta >= 0 + && args->delta_solid >= 0 + && args->picard_order > 0; +} + +static res_T +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) +{ + double power_term = 0; + res_T res = RES_OK; + ASSERT(scn && out_power_term && T && XD(check_handle_volumic_power_args)(args)); + + /* No volumic power. Do nothing */ + if(args->power == SDIS_VOLUMIC_POWER_NONE) goto exit; + + /* Check that picardN is not enabled when a volumic power is set since in + * this situation the upper bound of the Monte-Carlo weight required by + * picardN cannot be known */ + if(args->picard_order > 1) { + log_err(scn->dev, + "%s: invalid not null volumic power '%g' kg/m^3. Could not manage a " + "volumic power when the picard order is not equal to 1; Picard order is " + "currently set to %lu.\n", + FUNC_NAME, args->power, (unsigned long)args->picard_order); + res = RES_BAD_ARG; + goto error; + } + + /* No forward/backward intersection along the sampled direction */ + if(SXD_HIT_NONE(args->hit0) && SXD_HIT_NONE(args->hit1)) { + const double delta_in_meter = args->delta * scn->fp_to_meter; + power_term = delta_in_meter * delta_in_meter / (2.0 * DIM * args->lambda); + T->value += args->power * power_term; + + /* An intersection along this diffusive step is find. Use it to statically + * correct the power term currently registered */ + } else { + const double delta_s_adjusted = args->delta_solid * RAY_RANGE_MAX_SCALE; + const double delta_s_in_meter = args->delta_solid * scn->fp_to_meter; + double h; + double h_in_meter; + double cos_U_N; + float N[DIM] = {0}; + + if(args->delta == args->hit0->distance) { + fX(normalize)(N, args->hit0->normal); + cos_U_N = fX(dot)(args->dir0, N); + + } else { + ASSERT(args->delta == args->hit1->distance); + fX(normalize)(N, args->hit1->normal); + cos_U_N = fX(dot)(args->dir1, N); + } + + h = args->delta * fabs(cos_U_N); + h_in_meter = h * scn->fp_to_meter; + + /* The regular power term */ + power_term = h_in_meter * h_in_meter / (2.0*args->lambda); + + /* Add the power corrective term. Be careful to use the adjusted + * delta_solid to correctly handle the RAY_RANGE_MAX_SCALE factor in the + * computation of the limit angle. But keep going with the unmodified + * delta_solid in the corrective term since it was the one that was + * "wrongly" used in the previous step and that must be corrected. */ + if(h == delta_s_adjusted) { + power_term += + -(delta_s_in_meter * delta_s_in_meter) / (2.0*DIM*args->lambda); + + } else if(h < delta_s_adjusted) { + const double sin_a = h / delta_s_adjusted; +#if DIM==2 + /* tmp = sin(2a) / (PI - 2*a) */ + const double tmp = sin_a * sqrt(1 - sin_a*sin_a) / acos(sin_a); + power_term += + -(delta_s_in_meter * delta_s_in_meter) / (4.0*args->lambda) * tmp; +#else + const double tmp = (sin_a*sin_a*sin_a - sin_a) / (1-sin_a); + power_term += + (delta_s_in_meter * delta_s_in_meter) / (6.0*args->lambda) * tmp; +#endif + } + T->value += args->power * power_term; + } + +exit: + *out_power_term = power_term; + return res; +error: + goto exit; +} + +/******************************************************************************* + * Local function + ******************************************************************************/ +res_T +XD(conductive_path_delta_sphere) + (struct sdis_scene* scn, + struct rwalk_context* ctx, + struct XD(rwalk)* rwalk, + struct ssp_rng* rng, + struct XD(temperature)* T) +{ + double position_start[DIM]; + struct solid_props props_ref = SOLID_PROPS_NULL; + double green_power_term = 0; + struct sdis_medium* mdm; + size_t istep = 0; /* Help for debug */ + res_T res = RES_OK; + ASSERT(scn && rwalk && rng && T); + ASSERT(rwalk->mdm->type == SDIS_SOLID); + (void)ctx, (void)istep; + + /* Check the random walk consistency */ + res = scene_get_medium_in_closed_boundaries(scn, rwalk->vtx.P, &mdm); + if(res != RES_OK || mdm != rwalk->mdm) { + log_err(scn->dev, "%s: invalid solid random walk. " + "Unexpected medium at {%g, %g, %g}.\n", FUNC_NAME, SPLIT3(rwalk->vtx.P)); + res = RES_BAD_OP_IRRECOVERABLE; + goto error; + } + /* Save the submitted position */ + dX(set)(position_start, rwalk->vtx.P); + + /* 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 + * remain the same. Note that we take care of the same constraints on the + * solid reinjection since once reinjected, the position of the random walk + * is that at the beginning of the conductive random walk. Thus, after a + * reinjection, the next line retrieves the properties of the reinjection + * 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(mdm, &rwalk->vtx, &props_ref); + + do { /* Solid random walk */ + struct XD(handle_volumic_power_args) handle_volpow_args = + XD(HANDLE_VOLUMIC_POWER_ARGS_NULL); + struct sXd(hit) hit0, hit1; + struct solid_props props = SOLID_PROPS_NULL; + double power_term = 0; + double mu; + float delta; /* Random walk numerical parameter */ + double delta_m; + float dir0[DIM], dir1[DIM]; + float org[DIM]; + + /* Fetch solid properties */ + res = solid_get_properties(mdm, &rwalk->vtx, &props); + if(res != RES_OK) goto error; + + res = check_solid_constant_properties + (scn->dev, ctx->green_path != NULL, 0/*use WoS?*/, &props_ref, &props); + if(res != RES_OK) goto error; + + /* Check the limit condition + * REVIEW Rfo: This can be a bug if the random walk comes from a boundary */ + if(SDIS_TEMPERATURE_IS_KNOWN(props.temperature)) { + T->value += props.temperature; + T->done = 1; + + 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; + } + + if(ctx->heat_path) { + heat_path_get_last_vertex(ctx->heat_path)->weight = T->value; + } + + break; + } + + 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, + (float)props.delta, dir0, dir1, &hit0, &hit1, &delta); + if(res != RES_OK) goto error; + + /* Add the volumic power density to the measured temperature */ + handle_volpow_args.dir0 = dir0; + handle_volpow_args.dir1 = dir1; + handle_volpow_args.hit0 = &hit0; + handle_volpow_args.hit1 = &hit1; + handle_volpow_args.power = props.power; + handle_volpow_args.lambda = props.lambda; + handle_volpow_args.delta_solid = (float)props.delta; + handle_volpow_args.delta = delta; + handle_volpow_args.picard_order = get_picard_order(ctx); + res = XD(handle_volumic_power)(scn, &handle_volpow_args, &power_term, T); + if(res != RES_OK) goto error; + + /* Register the power term for the green function. Delay its registration + * until the end of the conductive path, i.e. the path is valid */ + if(ctx->green_path && props.power != SDIS_VOLUMIC_POWER_NONE) { + green_power_term += power_term; + } + + /* 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); + 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->hit_side = SDIS_SIDE_NULL__; + } else { + rwalk->hit = hit0; + rwalk->hit_side = fX(dot)(hit0.normal, dir0) < 0 ? SDIS_FRONT : SDIS_BACK; + } + + /* Update the random walk position */ + XD(move_pos)(rwalk->vtx.P, dir0, delta); + + /* Register the new vertex against the heat path */ + res = register_heat_vertex(ctx->heat_path, &rwalk->vtx, T->value, + SDIS_HEAT_VERTEX_CONDUCTION, (int)ctx->nbranchings); + if(res != RES_OK) goto error; + + ++istep; + + /* Keep going while the solid random walk does not hit an interface */ + } while(SXD_HIT_NONE(&rwalk->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); + if(res != RES_OK) goto error; + } + + T->func = XD(boundary_path); + rwalk->mdm = NULL; /* The random walk is at an interface between 2 media */ + +exit: + return res; +error: + goto exit; +} + +#include "sdis_Xd_end.h" diff --git a/src/sdis_heat_path_conductive_wos_Xd.h b/src/sdis_heat_path_conductive_wos_Xd.h @@ -0,0 +1,669 @@ +/* Copyright (C) 2016-2023 |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_device_c.h" +#include "sdis_heat_path_conductive_c.h" +#include "sdis_medium_c.h" +#include "sdis_scene_c.h" + +#include <star/swf.h> + +#include "sdis_Xd_begin.h" + +/******************************************************************************* + * Helper function + ******************************************************************************/ +static res_T +XD(check_medium_consistency) + (struct sdis_scene* scn, + const struct XD(rwalk)* rwalk) +{ + struct sdis_medium* mdm = NULL; + res_T res = RES_OK; + ASSERT(rwalk); + + res = scene_get_medium_in_closed_boundaries(scn, rwalk->vtx.P, &mdm); + if(res != RES_OK) goto error; + + /* Check medium consistency */ + if(mdm != rwalk->mdm) { + log_err(scn->dev, + "%s:%s: invalid solid walk. Unexpected medium (position: "FORMAT_VECX").\n", + __FILE__, FUNC_NAME, SPLITX(rwalk->vtx.P)); + res = RES_BAD_OP_IRRECOVERABLE; + goto error; + } + +exit: + return res; +error: + goto exit; +} + +static res_T +XD(time_travel) + (struct sdis_scene* scn, + struct XD(rwalk)* rwalk, + struct ssp_rng* rng, + 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) +{ + double dir[DIM] = {0}; + double dst = 0; /* Distance [m] */ + double tau = 0; /* Time [s] */ + double x = 0; + double r = 0; + double temperature = 0; /* [k] */ + double time = 0; /* [s] */ + res_T res = RES_OK; + ASSERT(scn && rwalk && rng && alpha > 0 && distance && T); + + dst = *distance * scn->fp_to_meter; + ASSERT(dst >= 0); + + /* No displacement => no time travel */ + if(distance == 0) goto exit; + + /* Sample x = tau*alpha/distance^2 */ + r = ssp_rng_canonical(rng); + x = swf_tabulation_inverse(XD(scn->dev->H), SWF_QUADRATIC, r); + + /* Retrieve the time to travel */ + tau = x / alpha * dst * dst; + time = MMIN(tau, rwalk->vtx.time - t0); + + /* Increment the elapsed time */ + rwalk->elapsed_time += time; + + if(IS_INF(rwalk->vtx.time)) goto exit; /* Steady computation */ + + /* Let's take a trip back in time */ + rwalk->vtx.time = MMAX(t0, rwalk->vtx.time - tau); + + /* The path does not reach the initial condition */ + if(rwalk->vtx.time > t0) goto exit; + + /* The path reaches the initial condition. Sample a distance corresponding to + * the travel time to the initial condition. + * + * TODO while we use the H function to sample the distance, one should use the + * U function. For the moment, this function is not available, hence the use + * of H. This is not a problem, since we currently assume that the initial + * condition is uniform. Position is only used for path geometry */ + r = ssp_rng_canonical(rng); + x = swf_tabulation_inverse(XD(scn->dev->H), SWF_QUADRATIC, r); + dst = sqrt(alpha * time / x); + *distance = dst; /* Update travel distance */ + + /* Uniformly sample a direction and move along it of the distance that + * separate the current position ot its initial condition */ +#if DIM == 2 + ssp_ran_circle_uniform(rng, dir, NULL); +#else + ssp_ran_sphere_uniform(rng, dir, NULL); +#endif + dX(muld)(dir, dir, dst); + dX(add)(rwalk->vtx.P, rwalk->vtx.P, dir); + + /* Fetch the initial temperature */ + temperature = medium_get_temperature(rwalk->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", + __FILE__, FUNC_NAME, + medium_type_to_string(sdis_medium_get_type(rwalk->mdm)), + SPLIT3(rwalk->vtx.P)); + res = RES_BAD_ARG; + goto error; + } + + /* Update the temperature */ + T->value += temperature; + T->done = 1; + +exit: + return res; +error: + goto exit; +} + +#if DIM == 2 +static INLINE enum sdis_side +compute_hit_side_2d + (const struct s2d_hit* hit, + const double pos[2]) /* Position from which intersection occurs */ +{ + struct s2d_attrib p0, p1; /* Segment positions */ + double v0[2] = {0}; /* Vector from segment vertex 0 to segment vertex 1 */ + double v1[2] = {0}; /* Vector from segment vertex 0 to input position */ + double z = 0; + + /* Check pre-conditions */ + ASSERT(hit && pos && !S2D_HIT_NONE(hit)); + + /* Retrieve the positions of the intersected segment */ + S2D(segment_get_vertex_attrib(&hit->prim, 0, S2D_POSITION, &p0)); + S2D(segment_get_vertex_attrib(&hit->prim, 1, S2D_POSITION, &p1)); + + v0[0] = p1.value[0] - p0.value[0]; + v0[1] = p1.value[1] - p0.value[1]; + v1[0] = pos[0] - p0.value[0]; + v1[1] = pos[1] - p0.value[1]; + + /* Z coordinate of the cross product between v0 and v1. Its sign indicates on + * which side of the segment the position lies. */ + z = d2_cross(v1, v0); + return z > 0 ? SDIS_FRONT : SDIS_BACK; +} +#endif + +#if DIM == 3 +static INLINE enum sdis_side +compute_hit_side_3d + (const struct s3d_hit* hit, + const double pos[3]) /* Position from which intersection occurs */ +{ + struct s3d_attrib v0; /* Position of the 1st triangle vertex */ + double p[3] = {0}; /* Position of the 1st triangle vertex in double */ + double N[3] = {0}; /* Normalized triangle normal */ + double D = 0; /* Last parameter of the plane triangle plane equation */ + double dst = 0; /* Distance of pos to the plane */ + + /* Check pre-conditions */ + ASSERT(hit && pos && !S3D_HIT_NONE(hit)); + + /* Retrieve the positions of the intersected triangle */ + S3D(triangle_get_vertex_attrib(&hit->prim, 0, S3D_POSITION, &v0)); + d3_set_f3(p, v0.value); + + /* Compute the plane equation of the triangle */ + d3_set_f3(N, hit->normal); + d3_normalize(N, N); + D = -d3_dot(N, p); + + /* Calculate the distance of the input position from the plane of the triangle + * and use the sign to define which side of the triangle the position is on */ + dst = d3_dot(N, pos) + D; + return dst > 0 ? SDIS_FRONT : SDIS_BACK; +} +#endif + +/* Verify that the submitted position is in the expected medium */ +static res_T +XD(check_diffusion_position) + (struct sdis_scene* scn, + const struct sdis_medium* expected_medium, + const double pos[DIM]) +{ + struct sdis_interface* interf = NULL; + struct sdis_medium* mdm = NULL; + enum sdis_side side; + + struct sXd(hit) hit = SXD_HIT_NULL; + float wos_pos[DIM] = {0}; + float wos_radius = 0; + res_T res = RES_OK; + + /* Check pre-conditions */ + ASSERT(scn && expected_medium && pos); + + /* 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 + * surface is found, we assume that the position is in the intended medium. + * We rely on this assumption because this function is used to verify + * positions during diffusive random walks. Diffusion algorithms ensure that + * positions are in the current medium. This function is only concerned with + * numerical problems which, once the new position has been calculated, + * position the random walk beyond the medium. In other words, the path jumps + * a boundary that lies within the numerical imprecision of the calculation, + * i.e. very close to the position to be verified. So, if no surface is found + * close to this position, it means that there is no nearby boundary and, + * consequently, no numerical problem of this kind could have arisen. */ + wos_radius = (float)(scn->fp_to_meter * 1.0e-3); + fX_set_dX(wos_pos, pos); + 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); + side = XD(compute_hit_side)(&hit, pos); + mdm = side == SDIS_FRONT ? interf->medium_front : interf->medium_back; + if(mdm != expected_medium) { + res = RES_BAD_ARG; + goto error; + } + +exit: + return res; +error: + goto exit; +} + +static res_T +XD(setup_hit_wos) + (struct sdis_scene* scn, + const struct sXd(hit)* hit, + struct XD(rwalk)* rwalk) +{ + /* Geometry */ + struct sXd(primitive) prim; + struct sXd(attrib) attr; + + /* Properties */ + struct sdis_interface* interf = NULL; + struct sdis_medium* mdm = NULL; + enum sdis_side side = SDIS_SIDE_NULL__; + + /* Miscellaneous */ + double tgt[DIM] = {0}; /* Target point, i.e. hit position */ + res_T res = RES_OK; + + /* Check pre-conditions */ + ASSERT(rwalk && hit); + + /* Find intersected position */ + SXD(scene_view_get_primitive(scn->sXd(view), hit->prim.prim_id, &prim)); +#if DIM == 2 + SXD(primitive_get_attrib(&prim, SXD_POSITION, hit->u, &attr)); +#else + SXD(primitive_get_attrib(&prim, SXD_POSITION, hit->uv, &attr)); +#endif + + /* Calculate on which side the intersection occurs */ + 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) { + log_err(scn->dev, + "%s:%s: the conductive path has reached an invalid interface; " + "unexpected medium (position: "FORMAT_VECX"; side: %s).\n", + __FILE__, FUNC_NAME, SPLITX(tgt), side == SDIS_FRONT ? "front" : "back"); + res = RES_BAD_OP_IRRECOVERABLE; + goto error; + } + + /* Random walk update. Do not set the medium to NULL as the intersection is + * found regardless of time, so the initial condition could be reached before + * 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->hit_side = side; + +exit: + return res; +error: + goto exit; +} + +static res_T +XD(setup_hit_rt) + (struct sdis_scene* scn, + const double pos[DIM], + const double dir[DIM], + const struct sXd(hit)* hit, + struct XD(rwalk)* rwalk) +{ + /* Properties */ + struct sdis_interface* interf = NULL; + struct sdis_medium* mdm = NULL; + enum sdis_side side = SDIS_SIDE_NULL__; + + /* Miscellaneous */ + double tgt[DIM] = {0}; /* Target point, i.e. hit position */ + double N[DIM] = {0}; + res_T res = RES_OK; + + /* Check pre-conditions */ + ASSERT(pos && dir && rwalk && hit); + ASSERT(dX(is_normalized)(dir)); + + /* Calculate on which side the intersection occurs */ + dX(muld)(tgt, dir, hit->distance); + dX(add)(tgt, tgt, pos); + dX_set_fX(N, hit->normal); + dX(normalize)(N, N); + 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) { + log_err(scn->dev, + "%s:%s: the conductive path has reached an invalid interface; " + "unexpected medium (position: "FORMAT_VECX"; side: %s).\n", + __FILE__, FUNC_NAME, SPLITX(tgt), side == SDIS_FRONT ? "front" : "back"); + res = RES_BAD_OP_IRRECOVERABLE; + goto error; + } + + /* Random walk update. Do not set the medium to NULL as the intersection is + * found regardless of time, so the initial condition could be reached before + * 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->hit_side = side; + +exit: + return res; +error: + goto exit; +} + +static res_T +XD(sample_next_position) + (struct sdis_scene* scn, + struct XD(rwalk)* rwalk, + struct ssp_rng* rng, + double* distance) /* Displacement distance */ +{ + /* Intersection */ + struct sXd(hit) hit = SXD_HIT_NULL; + + /* Walk on sphere */ + double wos_distance = 0; + double wos_epsilon = 0; + float wos_pos[DIM] = {0}; + float wos_radius = 0; + + /* Miscellaneous */ + res_T res = RES_OK; + ASSERT(rwalk && rng && distance); + + /* Find the closest distance from the current position to the geometry */ + wos_radius = (float)INF; + fX_set_dX(wos_pos, rwalk->vtx.P); + SXD(scene_view_closest_point(scn->sXd(view), wos_pos, wos_radius, NULL, &hit)); + CHK(!SXD_HIT_NONE(&hit)); + wos_distance = hit.distance; + + /* The current position is in the epsilon shell: + * move it to the nearest interface position */ + wos_epsilon = scn->fp_to_meter*1.e-6; + if(wos_distance <= wos_epsilon) { + res = XD(setup_hit_wos)(scn, &hit, rwalk); + if(res != RES_OK) goto error; + + /* Uniformly sample a new position on the surrounding sphere */ + } else { + double pos[DIM] = {0}; + double dir[DIM] = {0}; + +#if DIM == 2 + ssp_ran_circle_uniform(rng, dir, NULL); +#else + ssp_ran_sphere_uniform(rng, dir, NULL); +#endif + dX(muld)(pos, dir, (double)hit.distance); + dX(add)(pos, pos, rwalk->vtx.P); + + /* Check that the new position is in the intended medium. Please note that + * we do not use the scene_get_medium_in_closed_boundaries function. It uses + * the ray-tracing operator, which has its own numerical uncertainty that is + * not the same as that of the closest point operator used by this + * scattering algorithm. It can therefore return the expected medium, + * whereas the nearest point operator would return an inconsistent medium. + * 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); + + /* Diffusion position is valid => move the path to the new position */ + if(res == RES_OK) { + dX(set)(rwalk->vtx.P, pos); + + /* As a result, the new position is detected as being in the wrong medium. + * This means that there has been a numerical problem in moving the + * position, which has therefore jumped the solid boundary. To solve this + * problem, we can move the trajectory on the solid interface along the + * direction of displacement. Indeed, we can assume that the position we + * want to move to is actually inside the epsilon shell. In this case, the + * trajectory will be moved to this interface in the next step anyway. */ + } else { + float rt_pos[DIM] = {0}; + float rt_dir[DIM] = {0}; + float rt_range[2] = {0, 0}; + + fX_set_dX(rt_pos, rwalk->vtx.P); + fX_set_dX(rt_dir, dir); + rt_range[0] = 0; + rt_range[1] = (float)INF; + SXD(scene_view_trace_ray(scn->sXd(view), rt_pos, rt_dir, rt_range, NULL, &hit)); + + /* An intersection should be found. If not, we can do nothing and simply + * reject the path. + * + * TODO: we could take the treatment of numerical problems a step further + * by sampling other directions and trying to move in them again. But at + * present, and until we have proof to the contrary, we assume that the + * rejection of a path should not occur, or that it will be so rare that + * 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", + __FILE__, FUNC_NAME, SPLITX(pos), SPLITX(dir), wos_distance); + res = RES_BAD_OP_IRRECOVERABLE; + goto error; + } + + res = XD(setup_hit_rt)(scn, rwalk->vtx.P, dir, &hit, rwalk); + if(res != RES_OK) goto error; + } + } + +exit: + *distance = hit.distance; + return res; +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 + ******************************************************************************/ +res_T +XD(conductive_path_wos) + (struct sdis_scene* scn, + struct rwalk_context* ctx, + struct XD(rwalk)* rwalk, + struct ssp_rng* rng, + struct XD(temperature)* T) +{ + /* Properties */ + struct sdis_medium* mdm = NULL; + struct solid_props props_ref = SOLID_PROPS_NULL; + struct solid_props props = SOLID_PROPS_NULL; + double alpha = 0; /* diffusivity, i.e. lambda/(rho*cp) */ + + /* Miscellaneous */ + size_t ndiffusion_steps = 0; /* For debug */ + double green_power_term = 0; + int green = 0; + const int wos = 1; + res_T res = RES_OK; + (void)ctx; /* Avoid the "unused variable" warning */ + + /* 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_medium_consistency)(scn, rwalk); + if(res != RES_OK) goto error; + + /* 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 + * remain the same. Note that we take care of the same constraints on the + * solid reinjection since once reinjected, the position of the random walk + * is that at the beginning of the conductive random walk. Thus, after a + * reinjection, the next line retrieves the properties of the reinjection + * 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); + props = props_ref; + + /* The algorithm assumes that lambda, rho and cp are constants. The + * diffusivity of the material (alpha) can therefore be calculated once */ + alpha = props_ref.lambda / (props_ref.rho * props_ref.cp); + + /* Sample a diffusive path */ + for(;;) { + double power_term = 0; /* */ + double dst = 0; /* [m/fp_to_meter] */ + + /* Register the new vertex against the heat path */ + #define REGISTER_HEAT_VERTEX { \ + res = register_heat_vertex(ctx->heat_path, &rwalk->vtx, T->value, \ + SDIS_HEAT_VERTEX_CONDUCTION, (int)ctx->nbranchings); \ + if(res != RES_OK) goto error; \ + } (void)0 + + /* The temperature is known */ + if(SDIS_TEMPERATURE_IS_KNOWN(props.temperature)) { + REGISTER_HEAT_VERTEX; + T->value += props.temperature; + T->done = 1; + break; + } + + /* Find the next position of the conductive path */ + res = XD(sample_next_position)(scn, rwalk, rng, &dst); + if(res != RES_OK) goto error; + + /* Going back in time */ + res = XD(time_travel)(scn, rwalk, rng, alpha, props.t0, &dst, T); + if(res != RES_OK) goto error; + + /* Add the volumic power density */ + res = XD(handle_volumic_power_wos)(scn, &props, dst, &power_term, T); + if(res != RES_OK) goto error; + + REGISTER_HEAT_VERTEX; + + /* Accumulate the power term */ + if(green) green_power_term += power_term; + + /* The path reaches the initial condition */ + if(T->done) { + T->func = NULL; + break; + } + + /* The path reaches a boundary */ + if(!SXD_HIT_NONE(&rwalk->hit)) { + T->func = XD(boundary_path); + rwalk->mdm = NULL; + break; + } + + #undef REGISTER_VERTEX + + /* Retreive and check solid properties at the new position */ + res = solid_get_properties(rwalk->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; + + ++ndiffusion_steps; /* For debug */ + } + + /* Save green function data */ + res = XD(update_green_path) + (ctx->green_path, rwalk, mdm, &props_ref, green_power_term, T); + +exit: + return res; +error: + goto exit; +} + +#include "sdis_Xd_end.h" diff --git a/src/sdis_heat_path_convective_Xd.h b/src/sdis_heat_path_convective_Xd.h @@ -119,7 +119,7 @@ XD(handle_known_fluid_temperature) temperature = fluid_get_temperature(rwalk->mdm, &rwalk->vtx); /* Check if the temperature is known */ - known_temperature = temperature >= 0; + known_temperature = SDIS_TEMPERATURE_IS_KNOWN(temperature); if(!known_temperature) goto exit; T->value += temperature; diff --git a/src/sdis_heat_path_radiative_Xd.h b/src/sdis_heat_path_radiative_Xd.h @@ -78,7 +78,7 @@ XD(trace_radiative_path) #endif if(SXD_HIT_NONE(&rwalk->hit)) { /* Fetch the ambient radiative temperature */ rwalk->hit_side = SDIS_SIDE_NULL__; - if(scn->trad.temperature >= 0) { + if(SDIS_TEMPERATURE_IS_KNOWN(scn->trad.temperature)) { T->value += scn->trad.temperature; T->done = 1; diff --git a/src/sdis_interface_c.h b/src/sdis_interface_c.h @@ -120,7 +120,9 @@ interface_side_get_temperature case SDIS_BACK: shader = &interf->shader.back; break; default: FATAL("Unreachable code.\n"); } - return shader->temperature ? shader->temperature(frag, interf->data) : -1; + return shader->temperature + ? shader->temperature(frag, interf->data) + : SDIS_TEMPERATURE_NONE; } static INLINE double @@ -182,7 +184,8 @@ interface_side_get_reference_temperature default: FATAL("Unreachable code\n"); break; } return shader->reference_temperature - ? shader->reference_temperature(frag, interf->data) : -1; + ? shader->reference_temperature(frag, interf->data) + : SDIS_TEMPERATURE_NONE; } static INLINE int diff --git a/src/sdis_medium.c b/src/sdis_medium.c @@ -23,26 +23,30 @@ /******************************************************************************* * Helper functions ******************************************************************************/ -static int +static res_T check_fluid_shader(const struct sdis_fluid_shader* shader) { - ASSERT(shader); - return shader->calorific_capacity - && shader->volumic_mass - && shader->temperature - && 0 <= shader->t0 && shader->t0 < INF; + if(!shader + || !shader->calorific_capacity + || !shader->volumic_mass + || !shader->temperature) + return RES_BAD_ARG; + + return RES_OK; } -static int +static res_T check_solid_shader(const struct sdis_solid_shader* shader) { - ASSERT(shader); - return shader->calorific_capacity - && shader->thermal_conductivity - && shader->volumic_mass - && shader->delta - && shader->temperature - && 0 <= shader->t0 && shader->t0 < INF; + if(!shader + || !shader->calorific_capacity + || !shader->thermal_conductivity + || !shader->volumic_mass + || !shader->delta + || !shader->temperature) + return RES_BAD_ARG; + + return RES_OK; } static res_T @@ -108,14 +112,11 @@ sdis_fluid_create struct sdis_medium* medium = NULL; res_T res = RES_OK; - if(!dev || !shader || !out_medium) { - res = RES_BAD_ARG; - goto error; - } + if(!dev || !out_medium) { res = RES_BAD_ARG; goto error; } - if(!check_fluid_shader(shader)) { + res = check_fluid_shader(shader); + if(res != RES_OK) { log_err(dev, "%s: invalid fluid shader.\n", FUNC_NAME); - res = RES_BAD_ARG; goto error; } @@ -162,14 +163,11 @@ sdis_solid_create struct sdis_medium* medium = NULL; res_T res = RES_OK; - if(!dev || !shader || !out_medium) { - res = RES_BAD_ARG; - goto error; - } + if(!dev || !out_medium) { res = RES_BAD_ARG; goto error; } - if(!check_solid_shader(shader)) { + res = check_solid_shader(shader); + if(res != RES_OK) { log_err(dev, "%s: invalid solid shader.\n", FUNC_NAME); - res = RES_BAD_ARG; goto error; } diff --git a/src/sdis_medium_c.h b/src/sdis_medium_c.h @@ -109,17 +109,7 @@ static const struct solid_props SOLID_PROPS_NULL = SOLID_PROPS_NULL__; ******************************************************************************/ DEFINE_MDM_CHK_PROP_FUNC(fluid, calorific_capacity, 0, INF, 0, 1) DEFINE_MDM_CHK_PROP_FUNC(fluid, volumic_mass, 0, INF, 0, 1) -DEFINE_MDM_CHK_PROP_FUNC(fluid, temperature, 0, INF, 1, 1) - -static INLINE res_T -fluid_check_t0(struct sdis_device* dev, const double t0) -{ - if(t0 < 0) { - log_err(dev, "invalid negative initial time '%g'.\n", t0); - return RES_BAD_ARG; - } - return RES_OK; -} +DEFINE_MDM_CHK_PROP_FUNC(fluid, temperature, -INF, INF, 1, 1) DEFINE_MDM_GET_PROP_FUNC(fluid, calorific_capacity) DEFINE_MDM_GET_PROP_FUNC(fluid, volumic_mass) @@ -151,12 +141,6 @@ fluid_check_properties CHK_PROP(calorific_capacity, props->cp); #undef CHK_PROP - /* Do not check the temperature. An invalid temperature means that the - * temperature is unknown */ - - res = fluid_check_t0(dev, props->t0); - if(res != RES_OK) return res; - return RES_OK; } @@ -181,17 +165,7 @@ DEFINE_MDM_CHK_PROP_FUNC(solid, thermal_conductivity, 0, INF, 0, 1) DEFINE_MDM_CHK_PROP_FUNC(solid, volumic_mass, 0, INF, 0, 1) DEFINE_MDM_CHK_PROP_FUNC(solid, delta, 0, INF, 0, 1) DEFINE_MDM_CHK_PROP_FUNC(solid, volumic_power, -INF, INF, 1, 1) -DEFINE_MDM_CHK_PROP_FUNC(solid, temperature, 0, INF, 1, 1) - -static INLINE res_T -solid_check_t0(struct sdis_device* dev, const double t0) -{ - if(t0 < 0) { - log_err(dev, "invalid negative initial time '%g'.\n", t0); - return RES_BAD_ARG; - } - return RES_OK; -} +DEFINE_MDM_CHK_PROP_FUNC(solid, temperature, -INF, INF, 1, 1) DEFINE_MDM_GET_PROP_FUNC(solid, calorific_capacity) DEFINE_MDM_GET_PROP_FUNC(solid, thermal_conductivity) @@ -214,7 +188,6 @@ static INLINE double solid_get_t0(const struct sdis_medium* mdm) { ASSERT(mdm && mdm->type == SDIS_SOLID); - ASSERT(0 <= mdm->shader.solid.t0 && mdm->shader.solid.t0 < INF); return mdm->shader.solid.t0; } @@ -242,9 +215,6 @@ solid_check_properties /* Do not check the temperature. An invalid temperature means that the * temperature is unknown */ - res = solid_check_t0(dev, props->t0); - if(res != RES_OK) return res; - return RES_OK; } diff --git a/src/sdis_misc_Xd.h b/src/sdis_misc_Xd.h @@ -54,7 +54,7 @@ XD(time_rewind) /* Fetch the initial temperature */ temperature = medium_get_temperature(rwalk->mdm, &rwalk->vtx); - if(temperature < 0) { + 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)), diff --git a/src/sdis_realisation.c b/src/sdis_realisation.c @@ -20,14 +20,15 @@ * Helper functions ******************************************************************************/ static INLINE int -check_ray_realisatio_args(const struct ray_realisation_args* args) +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; + && args->picard_order > 0 + && (unsigned)args->diff_algo < SDIS_DIFFUSION_ALGORITHMS_COUNT__; } /******************************************************************************* @@ -50,7 +51,7 @@ ray_realisation_3d struct temperature_3d T = TEMPERATURE_NULL_3d; float dir[3]; res_T res = RES_OK; - ASSERT(scn && weight && check_ray_realisatio_args(args)); + ASSERT(scn && weight && check_ray_realisation_args(args)); d3_set(rwalk.vtx.P, args->position); rwalk.vtx.time = args->time; @@ -67,6 +68,7 @@ ray_realisation_3d ctx.That3 = ctx.That * ctx.That2; ctx.max_branchings = args->picard_order - 1; ctx.irealisation = args->irealisation; + ctx.diff_algo = args->diff_algo; f3_set_d3(dir, args->direction); diff --git a/src/sdis_realisation.h b/src/sdis_realisation.h @@ -65,9 +65,18 @@ struct probe_realisation_args { struct green_path_handle* green_path; /* May be NULL */ struct sdis_heat_path* heat_path; /* May be NULL */ size_t irealisation; /* Id of the realisation (for debug) */ + enum sdis_diffusion_algorithm diff_algo; /* Diffusion algorithm to be used */ }; #define PROBE_REALISATION_ARGS_NULL__ { \ - NULL, NULL, {0,0,0}, -1, 0, NULL, NULL, SIZE_MAX \ + NULL, /* RNG */ \ + NULL, /* Medium */ \ + {0,0,0}, /* Position */ \ + -1, /* Observation time */ \ + 0, /* Picard order */ \ + NULL, /* Green path */ \ + NULL, /* Heat path */ \ + SIZE_MAX, /* Realisation ID */ \ + SDIS_DIFFUSION_NONE /* Diffusion algorithm */ \ } static const struct probe_realisation_args PROBE_REALISATION_ARGS_NULL = PROBE_REALISATION_ARGS_NULL__; @@ -97,9 +106,19 @@ struct boundary_realisation_args { struct green_path_handle* green_path; /* May be NULL */ struct sdis_heat_path* heat_path; /* May be NULL */ size_t irealisation; /* Id of the realisation (for debug) */ + enum sdis_diffusion_algorithm diff_algo; /* Diffusion algorithm to be used */ }; #define BOUNDARY_REALISATION_ARGS_NULL__ { \ - NULL, SIZE_MAX, {0,0}, -1, 0, SDIS_SIDE_NULL__, NULL, NULL, SIZE_MAX \ + NULL, /* RNG */ \ + SIZE_MAX, /* Primitive ID */ \ + {0,0}, /* Parametric coordinates */ \ + -1, /* Observation time */ \ + 0, /* Picard order */ \ + SDIS_SIDE_NULL__, /* Interface side */ \ + NULL, /* Green path */ \ + NULL, /* Heat path */ \ + SIZE_MAX, /* Realisation ID */ \ + SDIS_DIFFUSION_NONE /* Diffusion algorithm */ \ } static const struct boundary_realisation_args BOUNDARY_REALISATION_ARGS_NULL = BOUNDARY_REALISATION_ARGS_NULL__; @@ -128,9 +147,18 @@ struct boundary_flux_realisation_args { enum sdis_side solid_side; /* Side of the geometric primitive */ int flux_mask; /* Combination of enum flux_flag */ size_t irealisation; /* Id of the realisation (for debug) */ + enum sdis_diffusion_algorithm diff_algo; /* Diffusion algorithm to be used */ }; #define BOUNDARY_FLUX_REALISATION_ARGS_NULL__ { \ - NULL, SIZE_MAX, {0,0}, -1, 0, SDIS_SIDE_NULL__, 0, SIZE_MAX \ + NULL, /* RNG */ \ + SIZE_MAX, /* Primitive ID */ \ + {0,0}, /* Parametric coordinates */ \ + -1, /* Observation time */ \ + 0, /* Picard order */ \ + SDIS_SIDE_NULL__, /* Interface side */ \ + 0, /* Flux mask */ \ + SIZE_MAX, /* Realisation ID */ \ + SDIS_DIFFUSION_NONE /* Diffusion algorithm */ \ } static const struct boundary_flux_realisation_args BOUNDARY_FLUX_REALISATION_ARGS_NULL = BOUNDARY_FLUX_REALISATION_ARGS_NULL__; @@ -159,9 +187,18 @@ struct ray_realisation_args { size_t picard_order; /* Picard order to estimate radiative temperature */ struct sdis_heat_path* heat_path; /* May be NULL */ size_t irealisation; /* Id of the realisation (for debug) */ + enum sdis_diffusion_algorithm diff_algo; /* Diffusion algorithm to be used */ }; #define RAY_REALISATION_ARGS_NULL__ { \ - NULL, NULL, {0,0,0}, {0,0,0}, -1, 0, NULL, SIZE_MAX \ + NULL, /* RNG */ \ + NULL, /* Medium */ \ + {0,0,0}, /* Position */ \ + {0,0,0}, /* Direction */ \ + -1, /* Observation time */ \ + 0, /* Picard order */ \ + NULL, /* Heat path */ \ + SIZE_MAX, /* Realisation ID */ \ + SDIS_DIFFUSION_NONE /* Diffusion algorithm */ \ } static const struct ray_realisation_args RAY_REALISATION_ARGS_NULL = RAY_REALISATION_ARGS_NULL__; diff --git a/src/sdis_realisation_Xd.h b/src/sdis_realisation_Xd.h @@ -39,7 +39,8 @@ check_probe_realisation_args(const struct probe_realisation_args* args) && args->rng && args->medium && args->time >= 0 - && args->picard_order > 0; + && args->picard_order > 0 + && (unsigned)args->diff_algo < SDIS_DIFFUSION_ALGORITHMS_COUNT__; } static INLINE int @@ -53,7 +54,8 @@ check_boundary_realisation_args(const struct boundary_realisation_args* args) && args->uv[1] <= 1 && args->time >= 0 && args->picard_order > 0 - && (args->side == SDIS_FRONT || args->side == SDIS_BACK); + && (args->side == SDIS_FRONT || args->side == SDIS_BACK) + && (unsigned)args->diff_algo < SDIS_DIFFUSION_ALGORITHMS_COUNT__; } static INLINE int @@ -68,7 +70,8 @@ check_boundary_flux_realisation_args && args->uv[1] <= 1 && args->time >= 0 && args->picard_order > 0 - && (args->solid_side == SDIS_FRONT || args->solid_side == SDIS_BACK); + && (args->solid_side == SDIS_FRONT || args->solid_side == SDIS_BACK) + && (unsigned)args->diff_algo < SDIS_DIFFUSION_ALGORITHMS_COUNT__; } #endif /* SDIS_REALISATION_XD_H */ @@ -208,7 +211,7 @@ XD(probe_realisation) /* Check the initial condition. */ rwalk.vtx.time = t0; tmp = get_initial_temperature(args->medium, &rwalk.vtx); - if(tmp >= 0) { + if(SDIS_TEMPERATURE_IS_KNOWN(tmp)) { *weight = tmp; goto exit; } @@ -234,11 +237,12 @@ XD(probe_realisation) ctx.That3 = ctx.That * ctx.That2; ctx.max_branchings = args->picard_order - 1; ctx.irealisation = args->irealisation; + ctx.diff_algo = args->diff_algo; res = XD(sample_coupled_path)(scn, &ctx, &rwalk, args->rng, &T); if(res != RES_OK) goto error; - ASSERT(T.value >= 0); + ASSERT(SDIS_TEMPERATURE_IS_KNOWN(T.value)); *weight = T.value; exit: @@ -309,6 +313,7 @@ XD(boundary_realisation) ctx.That3 = ctx.That * ctx.That2; ctx.max_branchings = args->picard_order - 1; ctx.irealisation = args->irealisation; + ctx.diff_algo = args->diff_algo; res = XD(sample_coupled_path)(scn, &ctx, &rwalk, args->rng, &T); if(res != RES_OK) goto error; @@ -396,6 +401,7 @@ XD(boundary_flux_realisation) ctx.That3 = That3; \ ctx.max_branchings = args->picard_order - 1; \ 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); \ @@ -418,7 +424,7 @@ XD(boundary_flux_realisation) T.func = XD(radiative_path); res = XD(sample_coupled_path)(scn, &ctx, &rwalk, args->rng, &T); if(res != RES_OK) return res; - ASSERT(T.value >= 0); + ASSERT(SDIS_TEMPERATURE_IS_KNOWN(T.value)); result->Tradiative = T.value; } diff --git a/src/sdis_scene.c b/src/sdis_scene.c @@ -578,3 +578,41 @@ exit: error: goto exit; } + +res_T +scene_check_temperature_range(const struct sdis_scene* scn) +{ + res_T res = RES_OK; + ASSERT(scn); + + if(SDIS_TEMPERATURE_IS_UNKNOWN(scn->tmin)) { + log_err(scn->dev, + "%s the defined minimum temperature is unknown " + "when it is expected to be known.\n", + FUNC_NAME); + res = RES_BAD_ARG; + goto error; + } + + if(SDIS_TEMPERATURE_IS_UNKNOWN(scn->tmax)) { + log_err(scn->dev, + "%s the defined maximum temperature is unknown " + "when it is expected to be known.\n", + FUNC_NAME); + res = RES_BAD_ARG; + goto error; + } + + if(scn->tmin > scn->tmax) { + log_err(scn->dev, + "%s: defined temperature range degenerated -- [%g, %g] K\n", + FUNC_NAME, scn->tmin, scn->tmax); + res = RES_BAD_ARG; + goto error; + } + +exit: + return res; +error: + goto exit; +} diff --git a/src/sdis_scene_c.h b/src/sdis_scene_c.h @@ -290,6 +290,14 @@ extern LOCAL_SYM res_T scene_check_dimensionality_3d (const struct sdis_scene* scn); +/* Check that the temperature range of the scene is well defined, i.e. that the + * minimum and maximum temperatures are known and that they define a valid + * range. If this is not the case, the function displays an error message and + * returns RES_BAD_ARG */ +extern LOCAL_SYM res_T +scene_check_temperature_range + (const struct sdis_scene* scn); + static INLINE void scene_get_enclosure_ids (const struct sdis_scene* scn, diff --git a/src/sdis_solve_boundary_Xd.h b/src/sdis_solve_boundary_Xd.h @@ -23,6 +23,7 @@ #include "sdis_misc.h" #include "sdis_realisation.h" #include "sdis_scene_c.h" +#include "sdis_heat_path_boundary_c.h" /* check_Tref_<2d|3d> */ #include <rsys/clock_time.h> #include <star/ssp.h> @@ -78,6 +79,11 @@ check_solve_boundary_args(const struct sdis_solve_boundary_args* args) return RES_BAD_ARG; } + /* Check the diffusion algorithm */ + if((unsigned)args->diff_algo >= SDIS_DIFFUSION_ALGORITHMS_COUNT__) { + return RES_BAD_ARG; + } + return RES_OK; } @@ -405,6 +411,7 @@ XD(solve_boundary) realis_args.green_path = pgreen_path; realis_args.heat_path = pheat_path; realis_args.irealisation = (size_t)irealisation; + realis_args.diff_algo = args->diff_algo; realis_args.uv[0] = uv[0]; #if SDIS_XD_DIMENSION == 3 realis_args.uv[1] = uv[1]; @@ -778,13 +785,20 @@ XD(solve_boundary_flux) /* Fetch interface parameters */ epsilon = interface_side_get_emissivity(interf, &frag); - Tref = interface_side_get_reference_temperature(interf, &frag); hc = interface_get_convection_coef(interf, &frag); - hr = 4.0 * BOLTZMANN_CONSTANT * Tref * Tref * Tref * epsilon; + Tref = interface_side_get_reference_temperature(interf, &frag); + if(epsilon <= 0) { + hr = 0; + } else { + res_local = XD(check_Tref)(scn, frag.P, Tref, FUNC_NAME); + if(res_local != RES_OK) { ATOMIC_SET(&res, &res_local); continue; } + hr = 4.0 * BOLTZMANN_CONSTANT * Tref * Tref * Tref * epsilon; + } + frag.side = solid_side; imposed_flux = interface_side_get_flux(interf, &frag); imposed_temp = interface_side_get_temperature(interf, &frag); - if(imposed_temp >= 0) { + if(SDIS_TEMPERATURE_IS_KNOWN(imposed_temp)) { /* Flux computation on T boundaries is not supported yet */ log_err(scn->dev, "%s: Attempt to compute a flux at a Dirichlet boundary " "(not available yet).\n", FUNC_NAME); @@ -805,6 +819,7 @@ XD(solve_boundary_flux) realis_args.solid_side = solid_side; realis_args.flux_mask = flux_mask; realis_args.irealisation = (size_t)irealisation; + realis_args.diff_algo = args->diff_algo; realis_args.uv[0] = uv[0]; #if SDIS_XD_DIMENSION == 3 realis_args.uv[1] = uv[1]; @@ -820,10 +835,9 @@ XD(solve_boundary_flux) } else if(res_simul == RES_OK) { /* Update accumulators */ const double usec = (double)time_val(&t0, TIME_NSEC) * 0.001; /* Convective flux from fluid to solid */ - const double w_conv = hc * (result.Tfluid - result.Tboundary); + const double w_conv = hc > 0 ? hc * (result.Tfluid - result.Tboundary) : 0; /* Radiative flux from ambient to solid */ - const double w_rad = (result.Tradiative < 0) ? - 0 : hr * (result.Tradiative - result.Tboundary); + const double w_rad = hr > 0 ? hr * (result.Tradiative - result.Tboundary) : 0; /* Imposed flux that goes _into_ the solid */ const double w_imp = (imposed_flux != SDIS_FLUX_NONE) ? imposed_flux : 0; const double w_total = w_conv + w_rad + w_imp; diff --git a/src/sdis_solve_camera.c b/src/sdis_solve_camera.c @@ -72,6 +72,11 @@ check_solve_camera_args(const struct sdis_solve_camera_args* args) return RES_BAD_ARG; } + /* Check the diffusion algorithm */ + if((unsigned)args->diff_algo >= SDIS_DIFFUSION_ALGORITHMS_COUNT__) { + return RES_BAD_ARG; + } + return RES_OK; } @@ -87,6 +92,7 @@ solve_pixel const int register_paths, /* Combination of enum sdis_heat_path_flag */ const double pix_sz[2], /* Pixel size in the normalized image plane */ const size_t picard_order, + const enum sdis_diffusion_algorithm diff_algo, struct sdis_estimator* estimator, struct pixel* pixel) { @@ -135,6 +141,7 @@ solve_pixel realis_args.picard_order = picard_order; realis_args.heat_path = pheat_path; realis_args.irealisation = (size_t)irealisation; + realis_args.diff_algo = diff_algo; d3_set(realis_args.position, ray_pos); d3_set(realis_args.direction, ray_dir); res_simul = ray_realisation_3d(scn, &realis_args, &w); @@ -197,6 +204,7 @@ solve_tile const int register_paths, /* Combination of enum sdis_heat_path_flag */ const double pix_sz[2], /* Pixel size in the normalized image plane */ const size_t picard_order, + const enum sdis_diffusion_algorithm diff_algo, struct sdis_estimator_buffer* buf, struct tile* tile) { @@ -234,7 +242,7 @@ solve_tile } res = solve_pixel (scn, rng, mdm, cam, time_range, ipix_image, spp, register_paths, pix_sz, - picard_order, estimator, pixel); + picard_order, diff_algo, estimator, pixel); if(res != RES_OK) goto error; } @@ -651,7 +659,8 @@ sdis_solve_camera /* Draw the tile */ res_local = solve_tile (scn, rng, medium, args->cam, args->time_range, tile_org, tile_sz, - args->spp, register_paths, pix_sz, args->picard_order, buf, tile); + args->spp, register_paths, pix_sz, args->picard_order, args->diff_algo, + buf, tile); if(res_local != RES_OK) { ATOMIC_SET(&res, res_local); continue; diff --git a/src/sdis_solve_medium_Xd.h b/src/sdis_solve_medium_Xd.h @@ -172,6 +172,11 @@ check_solve_medium_args(const struct sdis_solve_medium_args* args) return RES_BAD_ARG; } + /* Check the diffusion algorithm */ + if((unsigned)args->diff_algo >= SDIS_DIFFUSION_ALGORITHMS_COUNT__) { + return RES_BAD_ARG; + } + return RES_OK; } @@ -436,6 +441,7 @@ XD(solve_medium) realis_args.green_path = pgreen_path; realis_args.heat_path = pheat_path; realis_args.irealisation = (size_t)irealisation; + realis_args.diff_algo = args->diff_algo; dX(set)(realis_args.position, pos); res_simul = XD(probe_realisation)(scn, &realis_args, &weight); if(res_simul != RES_OK && res_simul != RES_BAD_OP) { diff --git a/src/sdis_solve_probe_Xd.h b/src/sdis_solve_probe_Xd.h @@ -64,6 +64,11 @@ check_solve_probe_args(const struct sdis_solve_probe_args* args) return RES_BAD_ARG; } + /* Check the diffusion algorithm */ + if((unsigned)args->diff_algo >= SDIS_DIFFUSION_ALGORITHMS_COUNT__) { + return RES_BAD_ARG; + } + return RES_OK; } @@ -143,6 +148,7 @@ XD(solve_one_probe) realis_args.time = time; realis_args.picard_order = args->picard_order; realis_args.irealisation = irealisation; + realis_args.diff_algo = args->diff_algo; dX(set)(realis_args.position, args->position); res = XD(probe_realisation)(scn, &realis_args, &w); if(res != RES_OK) goto error; @@ -327,6 +333,7 @@ XD(solve_probe) realis_args.green_path = pgreen_path; realis_args.heat_path = pheat_path; realis_args.irealisation = (size_t)irealisation; + realis_args.diff_algo = args->diff_algo; dX(set)(realis_args.position, args->position); res_simul = XD(probe_realisation)(scn, &realis_args, &w); diff --git a/src/sdis_solve_probe_boundary_Xd.h b/src/sdis_solve_probe_boundary_Xd.h @@ -23,6 +23,7 @@ #include "sdis_misc.h" #include "sdis_realisation.h" #include "sdis_scene_c.h" +#include "sdis_heat_path_boundary_c.h" /* check_Tref_<2d|3d> */ #include <rsys/clock_time.h> #include <star/ssp.h> @@ -71,6 +72,11 @@ check_solve_probe_boundary_args return RES_BAD_ARG; } + /* Check the diffusion algorithm */ + if((unsigned)args->diff_algo >= SDIS_DIFFUSION_ALGORITHMS_COUNT__) { + return RES_BAD_ARG; + } + return RES_OK; } @@ -138,6 +144,11 @@ check_solve_probe_boundary_flux_args return RES_BAD_ARG; } + /* Check the diffusion algorithm */ + if((unsigned)args->diff_algo >= SDIS_DIFFUSION_ALGORITHMS_COUNT__) { + return RES_BAD_ARG; + } + return RES_OK; } @@ -178,6 +189,7 @@ XD(solve_one_probe_boundary) realis_args.picard_order = args->picard_order; realis_args.side = args->side; realis_args.irealisation = irealisation; + realis_args.diff_algo = args->diff_algo; realis_args.uv[0] = args->uv[0]; #if SDIS_XD_DIMENSION == 3 realis_args.uv[1] = args->uv[1]; @@ -363,6 +375,7 @@ XD(solve_probe_boundary) realis_args.green_path = pgreen_path; realis_args.heat_path = pheat_path; realis_args.irealisation = (size_t)irealisation; + realis_args.diff_algo = args->diff_algo; realis_args.uv[0] = args->uv[0]; #if SDIS_XD_DIMENSION == 3 realis_args.uv[1] = args->uv[1]; @@ -840,6 +853,7 @@ XD(solve_probe_boundary_flux) BOUNDARY_FLUX_REALISATION_ARGS_NULL; struct time t0, t1; const int ithread = omp_get_thread_num(); + struct sdis_interface_fragment frag_local = frag; struct ssp_rng* rng = per_thread_rng[ithread]; struct accum* acc_temp = &per_thread_acc_tp[ithread]; struct accum* acc_time = &per_thread_acc_ti[ithread]; @@ -850,9 +864,10 @@ XD(solve_probe_boundary_flux) double time, epsilon, hc, hr, imposed_flux, imposed_temp; int flux_mask = 0; struct bound_flux_result result = BOUND_FLUX_RESULT_NULL__; - double Tref = -1; + double Tref = SDIS_TEMPERATURE_NONE; size_t n; int pcent; + res_T res_local = RES_OK; res_T res_simul = RES_OK; if(ATOMIC_GET(&res) != RES_OK) continue; /* An error occurred */ @@ -863,16 +878,23 @@ XD(solve_probe_boundary_flux) time = sample_time(rng, args->time_range); /* Compute hr and hc */ - frag.time = time; - frag.side = fluid_side; - epsilon = interface_side_get_emissivity(interf, &frag); - Tref = interface_side_get_reference_temperature(interf, &frag); - hc = interface_get_convection_coef(interf, &frag); - hr = 4.0 * BOLTZMANN_CONSTANT * Tref * Tref * Tref * epsilon; - frag.side = solid_side; - imposed_flux = interface_side_get_flux(interf, &frag); - imposed_temp = interface_side_get_temperature(interf, &frag); - if(imposed_temp >= 0) { + frag_local.time = time; + frag_local.side = fluid_side; + epsilon = interface_side_get_emissivity(interf, &frag_local); + Tref = interface_side_get_reference_temperature(interf, &frag_local); + hc = interface_get_convection_coef(interf, &frag_local); + if(epsilon <= 0) { + hr = 0; + } else { + res_local = XD(check_Tref)(scn, frag_local.P, Tref, FUNC_NAME); + if(res_local != RES_OK) { ATOMIC_SET(&res, &res_local); continue; } + hr = 4.0 * BOLTZMANN_CONSTANT * Tref * Tref * Tref * epsilon; + } + + frag_local.side = solid_side; + imposed_flux = interface_side_get_flux(interf, &frag_local); + imposed_temp = interface_side_get_temperature(interf, &frag_local); + if(SDIS_TEMPERATURE_IS_KNOWN(imposed_temp)) { /* Flux computation on T boundaries is not supported yet */ log_err(scn->dev, "%s: Attempt to compute a flux at a Dirichlet boundary " @@ -894,6 +916,7 @@ XD(solve_probe_boundary_flux) realis_args.solid_side = solid_side; realis_args.flux_mask = flux_mask; realis_args.irealisation = (size_t)irealisation; + realis_args.diff_algo = args->diff_algo; realis_args.uv[0] = args->uv[0]; #if SDIS_XD_DIMENSION == 3 realis_args.uv[1] = args->uv[1]; @@ -909,10 +932,9 @@ XD(solve_probe_boundary_flux) } else if(res_simul == RES_OK) { /* Update accumulators */ const double usec = (double)time_val(&t0, TIME_NSEC) * 0.001; /* Convective flux from fluid to solid */ - const double w_conv = hc * (result.Tfluid - result.Tboundary); + const double w_conv = hc > 0 ? hc * (result.Tfluid - result.Tboundary) : 0; /* Radiative flux from ambient to solid */ - const double w_rad = (result.Tradiative < 0) ? - 0 : hr * (result.Tradiative - result.Tboundary); + const double w_rad = hr > 0 ? hr * (result.Tradiative - result.Tboundary) : 0; /* Imposed flux that goes _into_ the solid */ const double w_imp = (imposed_flux != SDIS_FLUX_NONE) ? imposed_flux : 0; /* Total flux */ diff --git a/src/test_sdis_compute_power.c b/src/test_sdis_compute_power.c @@ -19,7 +19,6 @@ #include <rsys/stretchy_array.h> #include <star/s3dut.h> -#define UNKOWN_TEMPERATURE -1 #define N 100000ul /* #realisations */ #define POWER0 10 #define POWER1 5 diff --git a/src/test_sdis_conducto_radiative.c b/src/test_sdis_conducto_radiative.c @@ -19,8 +19,6 @@ #include <rsys/math.h> #include <star/ssp.h> -#define UNKNOWN_TEMPERATURE -1 - /* The scene is composed of a solid cube whose temperature is unknown. The cube * faces on +/-X are in contact with a fluid and their convection coefficient * is null while their emissivity is 1. The left and right fluids are enclosed @@ -134,7 +132,7 @@ static double temperature_unknown(const struct sdis_rwalk_vertex* vtx, struct sdis_data* data) { CHK(vtx != NULL); (void)data; - return -1; + return SDIS_TEMPERATURE_NONE; } static double @@ -179,7 +177,7 @@ solid_get_temperature CHK(data != NULL); t0 = ((const struct solid*)sdis_data_cget(data))->t0; if(vtx->time > t0) { - return UNKNOWN_TEMPERATURE; + return SDIS_TEMPERATURE_NONE; } else { return ((const struct solid*)sdis_data_cget(data))->initial_temperature; } @@ -395,7 +393,7 @@ main(int argc, char** argv) OK(sdis_data_ref_put(data)); /* Create the interface that forces to keep in conduction */ - interf.temperature = UNKNOWN_TEMPERATURE; + interf.temperature = SDIS_TEMPERATURE_NONE; interf.convection_coef = -1; interf.emissivity = -1; interf.specular_fraction = -1; @@ -403,7 +401,7 @@ main(int argc, char** argv) create_interface(dev, solid, solid2, &interf, interfaces+0); /* Create the interface that emits radiative heat from the solid */ - interf.temperature = UNKNOWN_TEMPERATURE; + interf.temperature = SDIS_TEMPERATURE_NONE; interf.convection_coef = 0; interf.emissivity = emissivity; interf.specular_fraction = 1; @@ -411,7 +409,7 @@ main(int argc, char** argv) create_interface(dev, solid, fluid, &interf, interfaces+1); /* Create the interface that forces the radiative heat to bounce */ - interf.temperature = UNKNOWN_TEMPERATURE; + interf.temperature = SDIS_TEMPERATURE_NONE; interf.convection_coef = 0; interf.emissivity = 0; interf.specular_fraction = 1; @@ -483,7 +481,7 @@ main(int argc, char** argv) struct sdis_estimator* estimator2; struct sdis_green_function* green; struct sdis_solve_probe_args solve_args = SDIS_SOLVE_PROBE_ARGS_DEFAULT; - double ref = -1; + double ref = SDIS_TEMPERATURE_NONE; size_t nreals = 0; size_t nfails = 0; const size_t N = 10000; diff --git a/src/test_sdis_conducto_radiative_2d.c b/src/test_sdis_conducto_radiative_2d.c @@ -18,8 +18,6 @@ #include <star/ssp.h> -#define UNKNOWN_TEMPERATURE -1 - /* The scene is composed of a solid square whose temperature is unknown. The * square segments on +/-X are in contact with a fluid and their convection * coefficient is null while their emissivity is 1. The left and right fluids @@ -113,7 +111,7 @@ static double temperature_unknown(const struct sdis_rwalk_vertex* vtx, struct sdis_data* data) { CHK(vtx != NULL); (void)data; - return -1; + return SDIS_TEMPERATURE_NONE; } static double @@ -163,7 +161,7 @@ struct interfac { }; static const struct interfac INTERFACE_NULL = { - 0, {-1, -1, -1, -1}, {-1, -1, -1, -1} + 0, {SDIS_TEMPERATURE_NONE, -1, -1, -1}, {-1, -1, -1, -1} }; static double @@ -171,7 +169,7 @@ interface_get_temperature (const struct sdis_interface_fragment* frag, struct sdis_data* data) { const struct interfac* interf; - double T = -1; + double T = SDIS_TEMPERATURE_NONE; CHK(data != NULL && frag != NULL); interf = sdis_data_cget(data); switch(frag->side) { @@ -229,7 +227,7 @@ interface_get_reference_temperature (const struct sdis_interface_fragment* frag, struct sdis_data* data) { const struct interfac* interf; - double T = -1; + double T = SDIS_TEMPERATURE_NONE; CHK(data != NULL && frag != NULL); interf = sdis_data_cget(data); switch(frag->side) { @@ -398,7 +396,7 @@ main(int argc, char** argv) /* Create the interface that emits radiative heat from the solid */ interf = INTERFACE_NULL; - interf.back.temperature = UNKNOWN_TEMPERATURE; + interf.back.temperature = SDIS_TEMPERATURE_NONE; interf.back.emissivity = emissivity; interf.back.specular_fraction = -1; /* Should not be fetched */ interf.back.reference_temperature = Tref; @@ -406,7 +404,7 @@ main(int argc, char** argv) /* Create the interface that forces the radiative heat to bounce */ interf = INTERFACE_NULL; - interf.front.temperature = UNKNOWN_TEMPERATURE; + interf.front.temperature = SDIS_TEMPERATURE_NONE; interf.front.emissivity = 0; interf.front.specular_fraction = 1; interf.front.reference_temperature = Tref; diff --git a/src/test_sdis_contact_resistance.c b/src/test_sdis_contact_resistance.c @@ -52,7 +52,6 @@ * (0,0,0)///x=X0/// */ -#define UNKNOWN_TEMPERATURE -1 #define N 10000 /* #realisations */ #define T0 0.0 @@ -80,7 +79,7 @@ fluid_get_temperature { (void)data; CHK(vtx); - return UNKNOWN_TEMPERATURE; + return SDIS_TEMPERATURE_NONE; } static double @@ -120,7 +119,7 @@ solid_get_temperature (const struct sdis_rwalk_vertex* vtx, struct sdis_data* data) { CHK(vtx && data); - return UNKNOWN_TEMPERATURE; + return SDIS_TEMPERATURE_NONE; } /******************************************************************************* @@ -314,7 +313,7 @@ main(int argc, char** argv) /* Create the adiabatic interfaces */ OK(sdis_data_create(dev, sizeof(struct interf), 16, NULL, &data)); interf_props = sdis_data_get(data); - interf_props->temperature = UNKNOWN_TEMPERATURE; + interf_props->temperature = SDIS_TEMPERATURE_NONE; OK(sdis_interface_create (dev, solid1, fluid, &interf_shader, data, &interf_adiabatic1)); OK(sdis_interface_create @@ -342,7 +341,7 @@ main(int argc, char** argv) interf_shader.thermal_contact_resistance = interface_get_contact_resistance; OK(sdis_data_create(dev, sizeof(struct interf), 16, NULL, &data)); interf_props = sdis_data_get(data); - interf_props->temperature = UNKNOWN_TEMPERATURE; + interf_props->temperature = SDIS_TEMPERATURE_NONE; OK(sdis_interface_create (dev, solid1, solid2, &interf_shader, data, &interf_R)); OK(sdis_data_ref_put(data)); diff --git a/src/test_sdis_contact_resistance_2.c b/src/test_sdis_contact_resistance_2.c @@ -45,7 +45,6 @@ * (0,0,0)///x=X0/// */ -#define UNKNOWN_TEMPERATURE -1 #define N 10000 /* #realisations */ #define T0 0.0 @@ -73,7 +72,7 @@ fluid_get_temperature { (void)data; CHK(vtx); - return UNKNOWN_TEMPERATURE; + return SDIS_TEMPERATURE_NONE; } static double @@ -113,7 +112,7 @@ solid_get_temperature (const struct sdis_rwalk_vertex* vtx, struct sdis_data* data) { CHK(vtx && data); - return UNKNOWN_TEMPERATURE; + return SDIS_TEMPERATURE_NONE; } /******************************************************************************* @@ -408,7 +407,7 @@ main(int argc, char** argv) /* Create the adiabatic interfaces */ OK(sdis_data_create(dev, sizeof(struct interf), 16, NULL, &data)); interf_props = sdis_data_get(data); - interf_props->temperature = UNKNOWN_TEMPERATURE; + interf_props->temperature = SDIS_TEMPERATURE_NONE; OK(sdis_interface_create (dev, solid1, fluid, &interf_shader, data, &interf_adiabatic1)); OK(sdis_interface_create @@ -436,7 +435,7 @@ main(int argc, char** argv) interf_shader.thermal_contact_resistance = interface_get_contact_resistance; OK(sdis_data_create(dev, sizeof(struct interf), 16, NULL, &data)); interf_props = sdis_data_get(data); - interf_props->temperature = UNKNOWN_TEMPERATURE; + interf_props->temperature = SDIS_TEMPERATURE_NONE; OK(sdis_interface_create (dev, solid1, solid2, &interf_shader, data, &interf_R)); OK(sdis_data_ref_put(data)); diff --git a/src/test_sdis_convection.c b/src/test_sdis_convection.c @@ -48,7 +48,6 @@ * (0,0,0) */ -#define UNKNOWN_TEMPERATURE -1 #define N 100000 /* #realisations */ #define Tf_0 280.0 @@ -73,9 +72,9 @@ fluid_get_temperature { CHK(vtx != NULL); if(*((int*)sdis_data_cget(is_stationary))) { - return UNKNOWN_TEMPERATURE; + return SDIS_TEMPERATURE_NONE; } else { - return vtx->time <= 0 ? Tf_0 : UNKNOWN_TEMPERATURE; + return vtx->time <= 0 ? Tf_0 : SDIS_TEMPERATURE_NONE; } } diff --git a/src/test_sdis_convection_non_uniform.c b/src/test_sdis_convection_non_uniform.c @@ -48,7 +48,6 @@ * (0,0,0) */ -#define UNKNOWN_TEMPERATURE -1 #define N 100000 /* #realisations */ #define Tf_0 280.0 @@ -80,9 +79,9 @@ fluid_get_temperature CHK(vtx != NULL); CHK(is_stationary != NULL); if(*((int*)sdis_data_cget(is_stationary))) { - return UNKNOWN_TEMPERATURE; + return SDIS_TEMPERATURE_NONE; } else { - return vtx->time <= 0 ? Tf_0 : UNKNOWN_TEMPERATURE; + return vtx->time <= 0 ? Tf_0 : SDIS_TEMPERATURE_NONE; } } diff --git a/src/test_sdis_draw_external_flux.c b/src/test_sdis_draw_external_flux.c @@ -92,7 +92,7 @@ MEDIUM_PROP(solid, temperature, 310) /* [K] */ MEDIUM_PROP(solid, delta, 1.0/20.0) /* [m] */ MEDIUM_PROP(fluid, calorific_capacity, 2.0) /* [J/K/Kg] */ MEDIUM_PROP(fluid, volumic_mass, 25.0) /* |kg/m^3] */ -MEDIUM_PROP(fluid, temperature, -1/*<=> unknown*/) /* [K] */ +MEDIUM_PROP(fluid, temperature, SDIS_TEMPERATURE_NONE) /* [K] */ #undef MEDIUM_PROP static struct sdis_medium* @@ -138,7 +138,7 @@ interface_get_temperature struct sdis_data* data) { (void)frag, (void)data;/* Avoid the "unused variable" warning */ - return -1; + return SDIS_TEMPERATURE_NONE; } static double diff --git a/src/test_sdis_enclosure_limit_conditions.c b/src/test_sdis_enclosure_limit_conditions.c @@ -39,7 +39,6 @@ #define CONVECTION_COEF 10 #define DELTA 0.00625 -#define UNKNOWN_TEMPERATURE -1 #define NREALISATIONS 10000 #define Text 360.0 @@ -57,7 +56,7 @@ DEFINE_MEDIUM_GETTER(solid_get_calorific_capacity, 1) DEFINE_MEDIUM_GETTER(solid_get_thermal_conductivity, 1) DEFINE_MEDIUM_GETTER(solid_get_volumic_mass, 1) DEFINE_MEDIUM_GETTER(solid_get_delta, DELTA) -DEFINE_MEDIUM_GETTER(solid_get_temperature, UNKNOWN_TEMPERATURE) +DEFINE_MEDIUM_GETTER(solid_get_temperature, SDIS_TEMPERATURE_NONE) DEFINE_MEDIUM_GETTER(fluid_get_temperature, *((double*)sdis_data_cget(data))) #undef DEFINE_MEDIUM_GETTER diff --git a/src/test_sdis_external_flux.c b/src/test_sdis_external_flux.c @@ -138,7 +138,7 @@ MEDIUM_PROP(medium, volumic_mass, 1700) /* [kj/m^3] */ MEDIUM_PROP(medium, calorific_capacity, 800) /* [J/K/Kg] */ MEDIUM_PROP(solid, thermal_conductivity, 1.15) /* [W/m/K] */ MEDIUM_PROP(solid, delta, 0.1/20.0) /* [m] */ -MEDIUM_PROP(solid, temperature, -1/*<=> unknown*/) /* [K] */ +MEDIUM_PROP(solid, temperature, SDIS_TEMPERATURE_NONE/*<=> unknown*/) /* [K] */ MEDIUM_PROP(fluid, temperature, T_FLUID) /* [K] */ #undef MEDIUM_PROP @@ -188,7 +188,7 @@ struct interface { (void)frag, (void)data; /* Avoid the "unused variable" warning */ \ return Val; \ } -INTERF_PROP(temperature, -1/*<=> unknown*/) /* [K] */ +INTERF_PROP(temperature, SDIS_TEMPERATURE_NONE/*<=> unknown*/) /* [K] */ INTERF_PROP(reference_temperature, T_REF) /* [K] */ #undef INTERF_PROP diff --git a/src/test_sdis_flux.c b/src/test_sdis_flux.c @@ -43,7 +43,6 @@ * (0,0,0) ///// */ -#define UNKNOWN_TEMPERATURE -1 #define N 10000 #define PHI 10.0 @@ -96,7 +95,7 @@ solid_get_temperature (void)data; CHK(vtx != NULL); if(vtx->time > 0) - return UNKNOWN_TEMPERATURE; + return SDIS_TEMPERATURE_NONE; else return T0; } @@ -146,7 +145,7 @@ solve struct sdis_solve_probe_args solve_args = SDIS_SOLVE_PROBE_ARGS_DEFAULT; size_t nreals; size_t nfails; - double ref = -1; + double ref = SDIS_TEMPERATURE_NONE; const int nsimuls = 4; int isimul; enum sdis_scene_dimension dim; @@ -392,7 +391,7 @@ main(int argc, char** argv) /* Create the adiabatic interface */ OK(sdis_data_create(dev, sizeof(struct interf), 16, NULL, &data)); interf_props = sdis_data_get(data); - interf_props->temperature = UNKNOWN_TEMPERATURE; + interf_props->temperature = SDIS_TEMPERATURE_NONE; interf_props->phi = 0; OK(sdis_interface_create (dev, solid, fluid, &interf_shader, data, &interf_adiabatic)); @@ -409,7 +408,7 @@ main(int argc, char** argv) /* Create the PHI interface */ OK(sdis_data_create(dev, sizeof(struct interf), 16, NULL, &data)); interf_props = sdis_data_get(data); - interf_props->temperature = UNKNOWN_TEMPERATURE; + interf_props->temperature = SDIS_TEMPERATURE_NONE; interf_props->phi = PHI; OK(sdis_interface_create (dev, solid, fluid, &interf_shader, data, &interf_phi)); diff --git a/src/test_sdis_flux2.c b/src/test_sdis_flux2.c @@ -16,8 +16,6 @@ #include "sdis.h" #include "test_sdis_utils.h" -#define UNKNOWN_TEMPERATURE -1 - /* This test consists in solving the temperature profile in a solid slab * surrounded by two different convective and radiative temperatures. The * conductivity of the solid material is known, as well as its thickness. A net @@ -175,7 +173,7 @@ solid_get_temperature CHK(vtx && solid); if(vtx->time > 0) { - return UNKNOWN_TEMPERATURE; + return SDIS_TEMPERATURE_NONE; } else { /* The initial temperature is a linear profile between T1 and T2, where T1 * and T2 are the temperature on the left and right slab boundary, @@ -489,8 +487,8 @@ main(int argc, char** argv) interf_props.h = 0; interf_props.emissivity = 0; interf_props.phi = SDIS_FLUX_NONE; - interf_props.temperature = UNKNOWN_TEMPERATURE; - interf_props.Tref = UNKNOWN_TEMPERATURE; + interf_props.temperature = SDIS_TEMPERATURE_NONE; + interf_props.Tref = SDIS_TEMPERATURE_NONE; create_interface(dev, solid, dummy, &interf_props, &interfaces[ADIABATIC]); /* Interfaces with a fixed temperature */ @@ -506,7 +504,7 @@ main(int argc, char** argv) interf_props.h = 2; interf_props.emissivity = 1; interf_props.phi = 10000; - interf_props.temperature = UNKNOWN_TEMPERATURE; + interf_props.temperature = SDIS_TEMPERATURE_NONE; interf_props.Tref = 300; create_interface (dev, solid, fluid1, &interf_props, &interfaces[SOLID_FLUID_WITH_FLUX]); @@ -514,7 +512,7 @@ main(int argc, char** argv) interf_props.h = 8; interf_props.emissivity = 1; interf_props.phi = SDIS_FLUX_NONE; - interf_props.temperature = UNKNOWN_TEMPERATURE; + interf_props.temperature = SDIS_TEMPERATURE_NONE; interf_props.Tref = 300; create_interface (dev, solid, fluid2, &interf_props, &interfaces[SOLID_FLUID]); diff --git a/src/test_sdis_flux_with_h.c b/src/test_sdis_flux_with_h.c @@ -107,7 +107,7 @@ solid_get_temperature struct sdis_data* data) { (void)data, (void)vtx; - return -1; + return SDIS_TEMPERATURE_NONE; } static double diff --git a/src/test_sdis_medium.c b/src/test_sdis_medium.c @@ -63,10 +63,12 @@ main(int argc, char** argv) BA(sdis_fluid_create(dev, &fluid_shader, NULL, &fluid)); fluid_shader.temperature = DUMMY_FLUID_SHADER.temperature; - fluid_shader.t0 = -1; - BA(sdis_fluid_create(dev, &fluid_shader, NULL, &fluid)); + fluid_shader.t0 = -INF; + OK(sdis_fluid_create(dev, &fluid_shader, NULL, &fluid)); + OK(sdis_medium_ref_put(fluid)); fluid_shader.t0 = INF; - BA(sdis_fluid_create(dev, &fluid_shader, NULL, &fluid)); + OK(sdis_fluid_create(dev, &fluid_shader, NULL, &fluid)); + OK(sdis_medium_ref_put(fluid)); fluid_shader.t0 = DUMMY_FLUID_SHADER.t0; BA(sdis_fluid_create(dev, &SDIS_FLUID_SHADER_NULL, NULL, &fluid)); @@ -106,10 +108,12 @@ main(int argc, char** argv) BA(sdis_solid_create(dev, &solid_shader, NULL, &solid)); solid_shader.temperature = DUMMY_SOLID_SHADER.temperature; - solid_shader.t0 = -1; - BA(sdis_solid_create(dev, &solid_shader, NULL, &solid)); + solid_shader.t0 = -INF; + OK(sdis_solid_create(dev, &solid_shader, NULL, &solid)); + OK(sdis_medium_ref_put(solid)); solid_shader.t0 = INF; - BA(sdis_solid_create(dev, &solid_shader, NULL, &solid)); + OK(sdis_solid_create(dev, &solid_shader, NULL, &solid)); + OK(sdis_medium_ref_put(solid)); solid_shader.t0 = DUMMY_SOLID_SHADER.t0; OK(sdis_fluid_create(dev, &fluid_shader, NULL, &fluid)); diff --git a/src/test_sdis_picard.c b/src/test_sdis_picard.c @@ -18,7 +18,6 @@ #include <string.h> -#define UNKNOWN_TEMPERATURE -1 #define N 10000 /* This test consists in solving the stationary temperature profile in a solid @@ -234,7 +233,7 @@ solid_get_temperature (const struct sdis_rwalk_vertex* vtx, struct sdis_data* data) { CHK(vtx && data); - return UNKNOWN_TEMPERATURE; + return SDIS_TEMPERATURE_NONE; } static double @@ -607,15 +606,15 @@ main(int argc, char** argv) create_fluid(dev, &fluid); /* Create the adiabatic interface for the solid */ - interf_props.temperature = UNKNOWN_TEMPERATURE; + interf_props.temperature = SDIS_TEMPERATURE_NONE; interf_props.h = -1; interf_props.emissivity = -1; interf_props.specular_fraction = -1; - interf_props.Tref = UNKNOWN_TEMPERATURE; + interf_props.Tref = SDIS_TEMPERATURE_NONE; create_interface(dev, solid, dummy, &interf_props, interfaces+ADIABATIC); /* Create the interface between the solid and the fluid */ - interf_props.temperature = UNKNOWN_TEMPERATURE; + interf_props.temperature = SDIS_TEMPERATURE_NONE; interf_props.h = 0; interf_props.emissivity = 1; interf_props.specular_fraction = 0; diff --git a/src/test_sdis_scene.c b/src/test_sdis_scene.c @@ -383,8 +383,16 @@ test_scene_2d(struct sdis_device* dev, struct sdis_interface* interf) BA(sdis_scene_get_ambient_radiative_temperature(scn, NULL)); BA(sdis_scene_get_ambient_radiative_temperature(NULL, &trad)); OK(sdis_scene_get_ambient_radiative_temperature(scn, &trad)); - CHK(trad.temperature == SDIS_SCENE_CREATE_ARGS_DEFAULT.trad.temperature); - CHK(trad.reference == SDIS_SCENE_CREATE_ARGS_DEFAULT.trad.reference); + if(SDIS_TEMPERATURE_IS_KNOWN(trad.temperature)) { + CHK(trad.temperature == SDIS_SCENE_CREATE_ARGS_DEFAULT.trad.temperature); + } else { + CHK(SDIS_TEMPERATURE_IS_UNKNOWN(SDIS_SCENE_CREATE_ARGS_DEFAULT.trad.temperature)); + } + if(SDIS_TEMPERATURE_IS_KNOWN(trad.reference)) { + CHK(trad.reference == SDIS_SCENE_CREATE_ARGS_DEFAULT.trad.reference); + } else { + CHK(SDIS_TEMPERATURE_IS_UNKNOWN(SDIS_SCENE_CREATE_ARGS_DEFAULT.trad.reference)); + } trad.temperature = 100; trad.reference = 110; @@ -399,8 +407,16 @@ test_scene_2d(struct sdis_device* dev, struct sdis_interface* interf) BA(sdis_scene_get_temperature_range(scn, NULL)); BA(sdis_scene_get_temperature_range(NULL, t_range)); OK(sdis_scene_get_temperature_range(scn, t_range)); - CHK(t_range[0] == SDIS_SCENE_CREATE_ARGS_DEFAULT.t_range[0]); - CHK(t_range[1] == SDIS_SCENE_CREATE_ARGS_DEFAULT.t_range[1]); + if(SDIS_TEMPERATURE_IS_KNOWN(t_range[0])) { + CHK(t_range[0] == SDIS_SCENE_CREATE_ARGS_DEFAULT.t_range[0]); + } else { + CHK(SDIS_TEMPERATURE_IS_UNKNOWN(SDIS_SCENE_CREATE_ARGS_DEFAULT.t_range[0])); + } + if(SDIS_TEMPERATURE_IS_KNOWN(t_range[1])) { + CHK(t_range[1] == SDIS_SCENE_CREATE_ARGS_DEFAULT.t_range[1]); + } else { + CHK(SDIS_TEMPERATURE_IS_UNKNOWN(SDIS_SCENE_CREATE_ARGS_DEFAULT.t_range[0])); + } t_range[0] = 1; t_range[1] = 100; @@ -408,8 +424,8 @@ test_scene_2d(struct sdis_device* dev, struct sdis_interface* interf) BA(sdis_scene_set_temperature_range(NULL, t_range)); BA(sdis_scene_set_temperature_range(scn, NULL)); OK(sdis_scene_set_temperature_range(scn, t_range)); - t_range[0] = -1; - t_range[1] = -1; + t_range[0] = SDIS_TEMPERATURE_NONE; + t_range[1] = SDIS_TEMPERATURE_NONE; OK(sdis_scene_get_temperature_range(scn, t_range)); CHK(t_range[0] == 1); CHK(t_range[1] == 100); diff --git a/src/test_sdis_solid_random_walk_robustness.c b/src/test_sdis_solid_random_walk_robustness.c @@ -24,7 +24,6 @@ #define Hcoef 1.0 /* Convection coefficient */ #define Pw 10000.0 /* Volumetric power */ #define Nreals 10000 /* #realisations */ -#define UNKNOWN -1 /******************************************************************************* * Helper functions @@ -160,7 +159,7 @@ interface_get_temperature interf = sdis_data_cget(data); switch(interf->profile) { case PROFILE_UNKNOWN: - temperature = UNKNOWN; + temperature = SDIS_TEMPERATURE_NONE; break; case PROFILE_VOLUMETRIC_POWER: temperature = volumetric_temperature(frag->P, interf->upper); @@ -305,7 +304,7 @@ main(int argc, char** argv) solid_param->lambda = 10; solid_param->cp = 1.0; solid_param->rho = 1.0; - solid_param->temperature = -1; + solid_param->temperature = SDIS_TEMPERATURE_NONE; solid_param->power = SDIS_VOLUMIC_POWER_NONE; OK(sdis_solid_create(dev, &solid_shader, data, &solid)); OK(sdis_data_ref_put(data)); diff --git a/src/test_sdis_solve_boundary.c b/src/test_sdis_solve_boundary.c @@ -42,7 +42,6 @@ * (0,0,0) ///// */ -#define UNKNOWN_TEMPERATURE -1 #define N 10000 /* #realisations */ #define N_dump 10 /* #dumped paths */ @@ -108,7 +107,7 @@ solid_get_temperature { (void)data; CHK(vtx != NULL); - if(vtx->time > 0) return UNKNOWN_TEMPERATURE; + if(vtx->time > 0) return SDIS_TEMPERATURE_NONE; return Tf; } @@ -237,7 +236,7 @@ main(int argc, char** argv) OK(sdis_data_create(dev, sizeof(struct interf), 16, NULL, &data)); interf_props = sdis_data_get(data); interf_props->hc = 0; - interf_props->temperature = UNKNOWN_TEMPERATURE; + interf_props->temperature = SDIS_TEMPERATURE_NONE; OK(sdis_interface_create (dev, solid, fluid, &interf_shader, data, &interf_adiabatic)); OK(sdis_data_ref_put(data)); @@ -255,7 +254,7 @@ main(int argc, char** argv) OK(sdis_data_create(dev, sizeof(struct interf), 16, NULL, &data)); interf_props = sdis_data_get(data); interf_props->hc = H; - interf_props->temperature = UNKNOWN_TEMPERATURE; + interf_props->temperature = SDIS_TEMPERATURE_NONE; OK(sdis_interface_create (dev, solid, fluid, &interf_shader, data, &interf_H)); OK(sdis_data_ref_put(data)); @@ -419,7 +418,7 @@ main(int argc, char** argv) } /* The external fluid cannot have an unknown temperature */ - fluid_param->temperature = UNKNOWN_TEMPERATURE; + fluid_param->temperature = SDIS_TEMPERATURE_NONE; BA(SOLVE(box_scn, &probe_args, &estimator)); fluid_param->temperature = Tf; @@ -445,7 +444,7 @@ main(int argc, char** argv) } /* The external fluid cannot have an unknown temperature */ - fluid_param->temperature = UNKNOWN_TEMPERATURE; + fluid_param->temperature = SDIS_TEMPERATURE_NONE; BA(SOLVE(square_scn, &probe_args, &estimator)); fluid_param->temperature = Tf; @@ -606,7 +605,7 @@ main(int argc, char** argv) bound_args.register_paths = SDIS_HEAT_PATH_ALL; /* Check simulation error handling when paths are registered */ - fluid_param->temperature = UNKNOWN_TEMPERATURE; + fluid_param->temperature = SDIS_TEMPERATURE_NONE; BA(SOLVE(box_scn, &bound_args, &estimator)); /* Dump path */ diff --git a/src/test_sdis_solve_boundary_flux.c b/src/test_sdis_solve_boundary_flux.c @@ -62,7 +62,6 @@ * (0,0)/////// */ -#define UNKNOWN_TEMPERATURE -1 #define N 100000 /* #realisations */ #define Tf 300.0 @@ -133,7 +132,7 @@ solid_get_temperature { (void) data; CHK(vtx != NULL); - return UNKNOWN_TEMPERATURE; + return SDIS_TEMPERATURE_NONE; } /******************************************************************************* @@ -289,7 +288,7 @@ main(int argc, char** argv) OK(sdis_data_create(dev, sizeof(struct interf), 16, NULL, &data)); interf_props = sdis_data_get(data); interf_props->hc = 0; - interf_props->temperature = UNKNOWN_TEMPERATURE; + interf_props->temperature = SDIS_TEMPERATURE_NONE; interf_props->emissivity = 0; OK(sdis_interface_create (dev, solid, fluid, &interf_shader, data, &interf_adiabatic)); @@ -313,7 +312,7 @@ main(int argc, char** argv) OK(sdis_data_create(dev, sizeof(struct interf), 16, NULL, &data)); interf_props = sdis_data_get(data); interf_props->hc = H; - interf_props->temperature = UNKNOWN_TEMPERATURE; + interf_props->temperature = SDIS_TEMPERATURE_NONE; interf_props->emissivity = EPSILON; interf_props->reference_temperature = Tref; interf_shader.back.emissivity = interface_get_emissivity; diff --git a/src/test_sdis_solve_camera.c b/src/test_sdis_solve_camera.c @@ -28,7 +28,6 @@ #include <string.h> -#define UNKOWN_TEMPERATURE -1 #define IMG_WIDTH 157 #define IMG_HEIGHT 53 #define SPP 30 /* #Samples per pixel, i.e. #realisations per pixel */ @@ -152,7 +151,7 @@ struct fluid { double rho; double temperature; }; -static const struct fluid FLUID_NULL = {0, 0, UNKOWN_TEMPERATURE}; +static const struct fluid FLUID_NULL = {0, 0, SDIS_TEMPERATURE_NONE}; static double fluid_get_calorific_capacity @@ -188,7 +187,7 @@ struct solid { double delta; double temperature; }; -static const struct solid SOLID_NULL = {0, 0, 0, 0, UNKOWN_TEMPERATURE}; +static const struct solid SOLID_NULL = {0, 0, 0, 0, SDIS_TEMPERATURE_NONE}; static double solid_get_calorific_capacity @@ -241,7 +240,7 @@ struct interf { double reference_temperature; }; static const struct interf INTERF_NULL = { - 0, 0, 0, UNKOWN_TEMPERATURE, UNKOWN_TEMPERATURE + 0, 0, 0, SDIS_TEMPERATURE_NONE, SDIS_TEMPERATURE_NONE }; static double @@ -595,21 +594,21 @@ main(int argc, char** argv) solid_param.lambda = 0.1; solid_param.rho = 1.0; solid_param.delta = 1.0/20.0; - solid_param.temperature = UNKOWN_TEMPERATURE; + solid_param.temperature = SDIS_TEMPERATURE_NONE; create_solid(dev, &solid_param, &solid); /* Create the fluid0/solid interface */ interface_param.hc = 1; interface_param.epsilon = 0; interface_param.specular_fraction = 0; - interface_param.temperature = UNKOWN_TEMPERATURE; + interface_param.temperature = SDIS_TEMPERATURE_NONE; create_interface(dev, solid, fluid0, &interface_param, &interf0); /* Create the fluid1/solid interface */ interface_param.hc = 0.1; interface_param.epsilon = 1; interface_param.specular_fraction = 1; - interface_param.temperature = UNKOWN_TEMPERATURE; + interface_param.temperature = SDIS_TEMPERATURE_NONE; interface_param.reference_temperature = 300; create_interface(dev, fluid1, solid, &interface_param, &interf1); @@ -674,7 +673,7 @@ main(int argc, char** argv) BA(sdis_solve_camera(scn, &solve_args, &buf)); solve_args.cam = cam; OK(sdis_scene_get_ambient_radiative_temperature(scn, &trad)); - trad.temperature = -1; + trad.temperature = SDIS_TEMPERATURE_NONE; OK(sdis_scene_set_ambient_radiative_temperature(scn, &trad)); BA(sdis_solve_camera(scn, &solve_args, &buf)); trad.temperature = 300; @@ -767,7 +766,7 @@ main(int argc, char** argv) solve_args.rng_type = SDIS_SOLVE_CAMERA_ARGS_DEFAULT.rng_type; pfluid_param = sdis_data_get(sdis_medium_get_data(fluid1)); - pfluid_param->temperature = UNKOWN_TEMPERATURE; + pfluid_param->temperature = SDIS_TEMPERATURE_NONE; /* Check simulation error handling */ BA(sdis_solve_camera(scn, &solve_args, &buf)); diff --git a/src/test_sdis_solve_medium.c b/src/test_sdis_solve_medium.c @@ -272,7 +272,7 @@ main(int argc, char** argv) solid_param->lambda = 0.1; solid_param->rho = 1.0; solid_param->delta = 1.0/20.0; - solid_param->temperature = -1; /* Unknown temperature */ + solid_param->temperature = SDIS_TEMPERATURE_NONE; /* Unknown temperature */ OK(sdis_solid_create(dev, &solid_shader, data, &solid0)); OK(sdis_data_ref_put(data)); @@ -284,7 +284,7 @@ main(int argc, char** argv) solid_param->lambda = 1.0; solid_param->rho = 1.0; solid_param->delta = 1.0/20.0; - solid_param->temperature = -1; /* Unknown temperature */ + solid_param->temperature = SDIS_TEMPERATURE_NONE; /* Unknown temperature */ OK(sdis_solid_create(dev, &solid_shader, data, &solid1)); OK(sdis_data_ref_put(data)); @@ -403,7 +403,7 @@ main(int argc, char** argv) /* Check simulation error handling when paths are registered */ solve_args.nrealisations = 10; solve_args.register_paths = SDIS_HEAT_PATH_ALL; - fluid_param->temperature = -1; + fluid_param->temperature = SDIS_TEMPERATURE_NONE; BA(sdis_solve_medium(scn, &solve_args, &estimator)); fluid_param->temperature = Tf1; OK(sdis_solve_medium(scn, &solve_args, &estimator)); diff --git a/src/test_sdis_solve_medium_2d.c b/src/test_sdis_solve_medium_2d.c @@ -256,7 +256,7 @@ main(int argc, char** argv) solid_param->lambda = 0.1; solid_param->rho = 1.0; solid_param->delta = 1.0/20.0; - solid_param->temperature = -1; /* Unknown temperature */ + solid_param->temperature = SDIS_TEMPERATURE_NONE; OK(sdis_solid_create(dev, &solid_shader, data, &solid0)); OK(sdis_data_ref_put(data)); @@ -268,7 +268,7 @@ main(int argc, char** argv) solid_param->lambda = 1.0; solid_param->rho = 1.0; solid_param->delta = 1.0/20.0; - solid_param->temperature = -1; /* Unknown temperature */ + solid_param->temperature = SDIS_TEMPERATURE_NONE; OK(sdis_solid_create(dev, &solid_shader, data, &solid1)); OK(sdis_data_ref_put(data)); diff --git a/src/test_sdis_solve_probe.c b/src/test_sdis_solve_probe.c @@ -329,7 +329,7 @@ main(int argc, char** argv) solid_param->lambda = 0.1; solid_param->rho = 1.0; solid_param->delta = 1.0/20.0; - solid_param->temperature = -1; /* Unknown temperature */ + solid_param->temperature = SDIS_TEMPERATURE_NONE; /* Unknown temperature */ solid_shader.calorific_capacity = solid_get_calorific_capacity; solid_shader.thermal_conductivity = solid_get_thermal_conductivity; solid_shader.volumic_mass = solid_get_volumic_mass; @@ -397,6 +397,9 @@ main(int argc, char** argv) solve_args.picard_order = 0; BA(sdis_solve_probe(scn, &solve_args, &estimator)); solve_args.picard_order = 1; + solve_args.diff_algo = SDIS_DIFFUSION_NONE; + BA(sdis_solve_probe(scn, &solve_args, &estimator)); + solve_args.diff_algo = SDIS_DIFFUSION_DELTA_SPHERE; OK(sdis_solve_probe(scn, &solve_args, &estimator)); BA(sdis_estimator_get_type(estimator, NULL)); @@ -454,7 +457,7 @@ main(int argc, char** argv) OK(sdis_estimator_ref_put(estimator)); /* The external fluid cannot have an unknown temperature */ - fluid_param->temperature = -1; + fluid_param->temperature = SDIS_TEMPERATURE_NONE; BA(sdis_solve_probe(scn, &solve_args, &estimator)); fluid_param->temperature = 300; @@ -568,7 +571,7 @@ main(int argc, char** argv) solve_args.register_paths = SDIS_HEAT_PATH_ALL; /* Check simulation error handling when paths are registered */ - fluid_param->temperature = -1; + fluid_param->temperature = SDIS_TEMPERATURE_NONE; BA(sdis_solve_probe(scn, &solve_args, &estimator)); fluid_param->temperature = 300; diff --git a/src/test_sdis_solve_probe2.c b/src/test_sdis_solve_probe2.c @@ -78,7 +78,7 @@ temperature_unknown(const struct sdis_rwalk_vertex* vtx, struct sdis_data* data) { (void)data; CHK(vtx != NULL && IS_INF(vtx->time)); - return -1; + return SDIS_TEMPERATURE_NONE; } static double @@ -255,7 +255,7 @@ main(int argc, char** argv) solve_args.position[2] = 0.5; solve_args.time_range[0] = INF; solve_args.time_range[1] = INF; - + solve_args.diff_algo = SDIS_DIFFUSION_WOS; OK(sdis_solve_probe(scn, &solve_args, &estimator)); ref = 350 * solve_args.position[2] + (1-solve_args.position[2]) * 300; diff --git a/src/test_sdis_solve_probe2_2d.c b/src/test_sdis_solve_probe2_2d.c @@ -72,7 +72,7 @@ temperature_unknown(const struct sdis_rwalk_vertex* vtx, struct sdis_data* data) { (void)data; CHK(vtx != NULL); - return -1; + return SDIS_TEMPERATURE_NONE; } static double @@ -246,6 +246,7 @@ main(int argc, char** argv) solve_args.position[1] = 0.5; solve_args.time_range[0] = INF; solve_args.time_range[1] = INF; + solve_args.diff_algo = SDIS_DIFFUSION_WOS; OK(sdis_solve_probe(scn, &solve_args, &estimator)); diff --git a/src/test_sdis_solve_probe3.c b/src/test_sdis_solve_probe3.c @@ -97,7 +97,7 @@ temperature_unknown(const struct sdis_rwalk_vertex* vtx, struct sdis_data* data) { (void)data; CHK(vtx != NULL); - return -1; + return SDIS_TEMPERATURE_NONE; } static double diff --git a/src/test_sdis_solve_probe3_2d.c b/src/test_sdis_solve_probe3_2d.c @@ -94,7 +94,7 @@ temperature_unknown(const struct sdis_rwalk_vertex* vtx, struct sdis_data* data) { (void)data; CHK(vtx != NULL); - return -1; + return SDIS_TEMPERATURE_NONE; } static double diff --git a/src/test_sdis_solve_probe_2d.c b/src/test_sdis_solve_probe_2d.c @@ -116,7 +116,7 @@ solid_get_temperature (const struct sdis_rwalk_vertex* vtx, struct sdis_data* data) { (void)vtx, (void)data; - return -1; + return SDIS_TEMPERATURE_NONE; } static double @@ -234,7 +234,7 @@ main(int argc, char** argv) OK(sdis_green_function_ref_put(green)); /* The external fluid cannot have an unknown temperature */ - fluid_param->temperature = -1; + fluid_param->temperature = SDIS_TEMPERATURE_NONE; BA(sdis_solve_probe(scn, &solve_args, &estimator)); diff --git a/src/test_sdis_solve_probe_boundary_list.c b/src/test_sdis_solve_probe_boundary_list.c @@ -157,7 +157,7 @@ mesh_add_sphere(struct mesh* mesh) SOLID_PROP(calorific_capacity, 500.0) /* [J/K/Kg] */ SOLID_PROP(thermal_conductivity, 25.0) /* [W/m/K] */ SOLID_PROP(volumic_mass, 7500.0) /* [kg/m^3] */ -SOLID_PROP(temperature, -1/*<=> unknown*/) /* [K] */ +SOLID_PROP(temperature, SDIS_TEMPERATURE_NONE/*<=> unknown*/) /* [K] */ SOLID_PROP(delta, 1.0/20.0) /* [m] */ static struct sdis_medium* diff --git a/src/test_sdis_solve_probe_list.c b/src/test_sdis_solve_probe_list.c @@ -310,7 +310,7 @@ create_scene SOLID_PROP(calorific_capacity, 500.0) /* [J/K/Kg] */ SOLID_PROP(thermal_conductivity, 25.0) /* [W/m/K] */ SOLID_PROP(volumic_mass, 7500.0) /* [kg/m^3] */ -SOLID_PROP(temperature, -1/*<=> unknown*/) /* [K] */ +SOLID_PROP(temperature, SDIS_TEMPERATURE_NONE) /* [K] */ #undef SOLID_PROP static double diff --git a/src/test_sdis_transcient.c b/src/test_sdis_transcient.c @@ -18,8 +18,6 @@ #include <string.h> -#define UNKNOWN_TEMPERATURE -1 - /* * The scene is composed of a solid cuboid whose temperature is fixed on its 6 * faces. The test consist in checking that the estimated temperature at a @@ -225,7 +223,7 @@ solid_get_temperature if(vtx->time <= 0) { return ((const struct solid*)sdis_data_cget(data))->init_temperature; } else { - return UNKNOWN_TEMPERATURE; + return SDIS_TEMPERATURE_NONE; } } @@ -542,7 +540,7 @@ main(int argc, char** argv) interfs[3] = create_interface(dev, solid, fluid, &interf_shader, Tbounds[3]); interfs[4] = create_interface(dev, solid, fluid, &interf_shader, Tbounds[4]); interfs[5] = create_interface(dev, solid, fluid, &interf_shader, Tbounds[5]); - interfs[6] = create_interface(dev, solid, solid, &interf_shader, UNKNOWN_TEMPERATURE); + interfs[6] = create_interface(dev, solid, solid, &interf_shader, SDIS_TEMPERATURE_NONE); /* Setup the box scene context */ ctx.indices = box_indices; diff --git a/src/test_sdis_unstationary_atm.c b/src/test_sdis_unstationary_atm.c @@ -26,7 +26,7 @@ * The physical configuration is the following: a slab of fluid with known * thermophysical properties but unknown temperature is located between a * "ground" and a slab of solid, with also a unknown temperature profile. On - * the other side of the solid slab, is a "atmosphere" with known temperature, + * the other side of the solid slab, is an "atmosphere" with known temperature, * and known radiative temperature. * * Solving the system means: finding the temperature of the ground, of the @@ -35,7 +35,7 @@ * reference) * * The reference for this system comes from a numerical method and is not - * analytic. Thus the compliance test MC VS reference is not the usual |MC - + * analytic. Thus the compliance test MC VS reference is not the usual |MC - * ref| <= 3*sigma but is |MC -ref| <= (Tmax -Tmin) * 0.01. * * 3D 2D @@ -60,8 +60,6 @@ #define T0_SOLID 300 #define T0_FLUID 300 -#define UNKNOWN_TEMPERATURE -1 - #define N 10000 /* #realisations */ #define TG 310 @@ -275,7 +273,7 @@ solid_get_temperature solid = ((struct solid*)sdis_data_cget(data)); if(vtx->time <= solid->t0) return solid->temperature; - return UNKNOWN_TEMPERATURE; + return SDIS_TEMPERATURE_NONE; } struct fluid { @@ -294,7 +292,7 @@ fluid_get_temperature fluid = ((struct fluid*)sdis_data_cget(data)); if(vtx->time <= fluid->t0) return fluid->temperature; - return UNKNOWN_TEMPERATURE; + return SDIS_TEMPERATURE_NONE; } static double @@ -756,7 +754,7 @@ main(int argc, char** argv) solid_props->rho = 1; solid_props->delta = 1; solid_props->t0 = INF; - solid_props->temperature = UNKNOWN_TEMPERATURE; + solid_props->temperature = SDIS_TEMPERATURE_NONE; OK(sdis_solid_create(dev, &solid_shader, data, &dummy_solid)); OK(sdis_data_ref_put(data)); @@ -786,7 +784,7 @@ main(int argc, char** argv) OK(sdis_data_ref_put(data)); /* Create the adiabatic interfaces */ - interf_props.temperature = UNKNOWN_TEMPERATURE; + interf_props.temperature = SDIS_TEMPERATURE_NONE; interf_props.h = 0; interf_props.emissivity = 0; interf_props.Tref = TREF; @@ -794,7 +792,7 @@ main(int argc, char** argv) create_interface(dev, solid, dummy_solid, &interf_props, &interf_adiabatic_2); /* Create the P interface */ - interf_props.temperature = UNKNOWN_TEMPERATURE; + interf_props.temperature = SDIS_TEMPERATURE_NONE; interf_props.h = HC; interf_props.emissivity = 1; interf_props.Tref = TREF; @@ -808,7 +806,7 @@ main(int argc, char** argv) create_interface(dev, fluid, dummy_solid, &interf_props, &interf_TG); /* Create the TA interface */ - interf_props.temperature = UNKNOWN_TEMPERATURE; + interf_props.temperature = SDIS_TEMPERATURE_NONE; interf_props.h = HA; interf_props.emissivity = 1; interf_props.Tref = TREF; diff --git a/src/test_sdis_unsteady.c b/src/test_sdis_unsteady.c @@ -0,0 +1,275 @@ +/* Copyright (C) 2016-2023 |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.h" +#include "test_sdis_utils.h" + +/* + * The scene is a solid cube whose temperature is fixed on its faces. The test + * calculates its temperature at a given position at different observation times + * and validates the result against the calculated values by analytically + * solving the green functions. + * + * T3 (0.1,0.1,0.1) + * +-------+ + * /' T4 /| + * +-------+ | T1 + * T0 | +.....|.+ + * |, T5 |/ + * +-------+ + * (0,0,0) T2 + */ + +#define T_INIT 280 /* [K] */ +#define T0 310 /* [K] */ +#define T1 320 /* [K] */ +#define T2 330 /* [K] */ +#define T3 310 /* [K] */ +#define T4 320 /* [K] */ +#define T5 300 /* [K] */ + +#define NREALISATIONS 10000 +#define FP_TO_METER 0.1 + +struct reference { + double pos[3]; /* [m/FP_TO_METER] */ + double time; /* [s] */ + double temp; /* [K] */ +}; + +static const struct reference references[] = { + {{0.3, 0.4, 0.6}, 1000.0000, 281.33455593977152}, + {{0.3, 0.4, 0.6}, 2000.0000, 286.90151817350699}, + {{0.3, 0.4, 0.6}, 3000.0000, 292.84330866161531}, + {{0.3, 0.4, 0.6}, 4000.0000, 297.81444160746452}, + {{0.3, 0.4, 0.6}, 5000.0000, 301.70787295764546}, + {{0.3, 0.4, 0.6}, 10000.000, 310.78920179442139}, + {{0.3, 0.4, 0.6}, 20000.000, 313.37629443163121}, + {{0.3, 0.4, 0.6}, 30000.000, 313.51064004438581}, + {{0.3, 0.4, 0.6}, 1000000.0, 313.51797642855502} +}; +static const size_t nreferences = sizeof(references)/sizeof(*references); + +/******************************************************************************* + * Solid, i.e. medium of the cube + ******************************************************************************/ +#define SOLID_PROP(Prop, Val) \ + static double \ + solid_get_##Prop \ + (const struct sdis_rwalk_vertex* vtx, \ + struct sdis_data* data) \ + { \ + (void)vtx, (void)data; /* Avoid the "unused variable" warning */ \ + return Val; \ + } +SOLID_PROP(calorific_capacity, 2000.0) /* [J/K/kg] */ +SOLID_PROP(thermal_conductivity, 0.5) /* [W/m/K] */ +SOLID_PROP(volumic_mass, 2500.0) /* [kg/m^3] */ +SOLID_PROP(delta, 1.0/60.0) +#undef SOLID_PROP + +static double /* [K] */ +solid_get_temperature + (const struct sdis_rwalk_vertex* vtx, + struct sdis_data* data) +{ + (void)data; + ASSERT(vtx); + if(vtx->time <= 0) return T_INIT; /* Initial temperature [K] */ + return SDIS_TEMPERATURE_NONE; +} + +static struct sdis_medium* +create_solid(struct sdis_device* sdis) +{ + struct sdis_solid_shader shader = SDIS_SOLID_SHADER_NULL; + struct sdis_medium* solid = NULL; + + shader.calorific_capacity = solid_get_calorific_capacity; + shader.thermal_conductivity = solid_get_thermal_conductivity; + shader.volumic_mass = solid_get_volumic_mass; + shader.delta = solid_get_delta; + shader.temperature = solid_get_temperature; + OK(sdis_solid_create(sdis, &shader, NULL, &solid)); + return solid; +} + +/******************************************************************************* + * Dummy environment, i.e. environment surrounding the cube. It is defined only + * for Stardis compliance: in Stardis, an interface must divide 2 media. + ******************************************************************************/ +static struct sdis_medium* +create_dummy(struct sdis_device* sdis) +{ + struct sdis_fluid_shader shader = SDIS_FLUID_SHADER_NULL; + struct sdis_medium* dummy = NULL; + + shader.calorific_capacity = dummy_medium_getter; + shader.volumic_mass = dummy_medium_getter; + shader.temperature = dummy_medium_getter; + OK(sdis_fluid_create(sdis, &shader, NULL, &dummy)); + return dummy; +} + +/******************************************************************************* + * Interface: its temperature is known + ******************************************************************************/ +static double /* [K] */ +interface_get_temperature + (const struct sdis_interface_fragment* frag, + struct sdis_data* data) +{ + (void)data; + ASSERT(frag); + + if(frag->Ng[0] == 1) return T0; + else if(frag->Ng[0] == -1) return T1; + else if(frag->Ng[1] == 1) return T2; + else if(frag->Ng[1] == -1) return T3; + else if(frag->Ng[2] == 1) return T4; + else if(frag->Ng[2] == -1) return T5; + else FATAL("Unreachable code\n"); +} + +static struct sdis_interface* +create_interface + (struct sdis_device* sdis, + struct sdis_medium* front, + struct sdis_medium* back) +{ + struct sdis_interface* interf = NULL; + struct sdis_interface_shader shader = SDIS_INTERFACE_SHADER_NULL; + + shader.front.temperature = interface_get_temperature; + shader.back.temperature = interface_get_temperature; + OK(sdis_interface_create(sdis, front, back, &shader, NULL, &interf)); + return interf; +} + +/******************************************************************************* + * The scene + ******************************************************************************/ +static void +get_interface(const size_t itri, struct sdis_interface** interf, void* ctx) +{ + (void)itri; + ASSERT(interf && ctx); + *interf = ctx; +} + +static struct sdis_scene* +create_scene + (struct sdis_device* sdis, + struct sdis_interface* interf) +{ + struct sdis_scene_create_args scn_args = SDIS_SCENE_CREATE_ARGS_DEFAULT; + struct sdis_scene* scn = NULL; + + scn_args.get_indices = box_get_indices; + scn_args.get_interface = get_interface; + scn_args.get_position = box_get_position; + scn_args.nprimitives = box_ntriangles; + scn_args.nvertices = box_nvertices; + scn_args.context = interf; + scn_args.fp_to_meter = FP_TO_METER; + OK(sdis_scene_create(sdis, &scn_args, &scn)); + + return scn; +} + +/******************************************************************************* + * Validations + ******************************************************************************/ +static void +check_probe + (struct sdis_scene* scn, + const struct reference* ref, + const enum sdis_diffusion_algorithm diff_algo) +{ + struct sdis_solve_probe_args args = SDIS_SOLVE_PROBE_ARGS_DEFAULT; + struct sdis_mc T = SDIS_MC_NULL; + struct sdis_estimator* estimator = NULL; + CHK(ref); + + args.position[0] = ref->pos[0]; + args.position[1] = ref->pos[1]; + args.position[2] = ref->pos[2]; + args.time_range[0] = + args.time_range[1] = ref->time; /* [s] */ + args.diff_algo = diff_algo; + args.nrealisations = NREALISATIONS; + OK(sdis_solve_probe(scn, &args, &estimator)); + OK(sdis_estimator_get_temperature(estimator, &T)); + + printf("T(%g, %g, %g) at %g s = %g ~ %g +/- %g\n", + ref->pos[0]*FP_TO_METER, ref->pos[1]*FP_TO_METER, ref->pos[2]*FP_TO_METER, + ref->time, ref->temp, T.E, T.SE); + CHK(eq_eps(ref->temp, T.E, 3*T.SE)); + + OK(sdis_estimator_ref_put(estimator)); +} + +static void +check + (struct sdis_scene* scn, + const enum sdis_diffusion_algorithm diff_algo) +{ + const char* str_algo = NULL; + size_t i = 0; + + switch(diff_algo) { + case SDIS_DIFFUSION_WOS: str_algo = "Walk on Sphere"; break; + case SDIS_DIFFUSION_DELTA_SPHERE: str_algo = "Delta sphere"; break; + default: FATAL("Unreachable code.\n"); break; + } + + printf("\n\x1b[1m\x1b[35m%s\x1b[0m\n", str_algo); + FOR_EACH(i, 0, nreferences) { + check_probe(scn, references + i, diff_algo); + } +} + +/******************************************************************************* + * The test + ******************************************************************************/ +int +main(int argc, char** argv) +{ + struct sdis_device* sdis = NULL; + struct sdis_interface* interf = NULL; + struct sdis_medium* solid = NULL; + struct sdis_medium* dummy = NULL; + struct sdis_scene* scene = NULL; + (void)argc, (void)argv; + + OK(sdis_device_create(&SDIS_DEVICE_CREATE_ARGS_DEFAULT, &sdis)); + + solid = create_solid(sdis); + dummy = create_dummy(sdis); + interf = create_interface(sdis, solid, dummy); + scene = create_scene(sdis, interf); + + check(scene, SDIS_DIFFUSION_DELTA_SPHERE); + check(scene, SDIS_DIFFUSION_WOS); + + OK(sdis_interface_ref_put(interf)); + OK(sdis_medium_ref_put(solid)); + OK(sdis_medium_ref_put(dummy)); + OK(sdis_scene_ref_put(scene)); + OK(sdis_device_ref_put(sdis)); + + CHK(mem_allocated_size() == 0); + return 0; +} diff --git a/src/test_sdis_unsteady_1d.c b/src/test_sdis_unsteady_1d.c @@ -0,0 +1,268 @@ +/* Copyright (C) 2016-2023 |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.h" +#include "test_sdis_utils.h" + +/* + * The scene is a solid 1d slab simulated by square whose temperature is fixed + * on two of its faces, the two others are adiabatic. The test calculates its + * temperature at a given position at different observation times and validates + * the result against the calculated values by analytically solving the green + * functions. + * + * ///////(0.1,0.1) + * +-------+ + * | | T1 + * | | + * T0 | | + * +-------+ + * (0,0)/////// + */ + +#define T_INIT 280 /* [K] */ +#define T0 310 /* [K] */ +#define T1 320 /* [K] */ + +#define NREALISATIONS 10000 +#define FP_TO_METER 0.1 + +struct reference { + double pos[2]; /* [m/FP_TO_METER] */ + double time; /* [s] */ + double temp; /* [K] */ +}; + +static const struct reference references[] = { + {{0.5, 0.5}, 1000.0000, 280.02848664122115}, + {{0.5, 0.5}, 2000.0000, 280.86935314560424}, + {{0.5, 0.5}, 3000.0000, 282.88587826961236}, + {{0.5, 0.5}, 4000.0000, 285.39698306113996}, + {{0.5, 0.5}, 5000.0000, 287.96909375994932}, + {{0.5, 0.5}, 10000.000, 298.39293888670881}, + {{0.5, 0.5}, 20000.000, 308.80965010883347}, + {{0.5, 0.5}, 30000.000, 312.69280796373141}, + {{0.5, 0.5}, 1000000.0, 315.00000000000000} +}; +static const size_t nreferences = sizeof(references)/sizeof(*references); + +/******************************************************************************* + * Solid, i.e. medium of the cube + ******************************************************************************/ +#define SOLID_PROP(Prop, Val) \ + static double \ + solid_get_##Prop \ + (const struct sdis_rwalk_vertex* vtx, \ + struct sdis_data* data) \ + { \ + (void)vtx, (void)data; /* Avoid the "unused variable" warning */ \ + return Val; \ + } +SOLID_PROP(calorific_capacity, 2000.0) /* [J/K/kg] */ +SOLID_PROP(thermal_conductivity, 0.5) /* [W/m/K] */ +SOLID_PROP(volumic_mass, 2500.0) /* [kg/m^3] */ +SOLID_PROP(delta, 1.0/60.0) +#undef SOLID_PROP + +static double /* [K] */ +solid_get_temperature + (const struct sdis_rwalk_vertex* vtx, + struct sdis_data* data) +{ + (void)data; + ASSERT(vtx); + if(vtx->time <= 0) return T_INIT; /* Initial temperature [K] */ + return SDIS_TEMPERATURE_NONE; /* Unknown temperature */ +} + +static struct sdis_medium* +create_solid(struct sdis_device* sdis) +{ + struct sdis_solid_shader shader = SDIS_SOLID_SHADER_NULL; + struct sdis_medium* solid = NULL; + + shader.calorific_capacity = solid_get_calorific_capacity; + shader.thermal_conductivity = solid_get_thermal_conductivity; + shader.volumic_mass = solid_get_volumic_mass; + shader.delta = solid_get_delta; + shader.temperature = solid_get_temperature; + OK(sdis_solid_create(sdis, &shader, NULL, &solid)); + return solid; +} + +/******************************************************************************* + * Dummy environment, i.e. environment surrounding the cube. It is defined only + * for Stardis compliance: in Stardis, an interface must divide 2 media. + ******************************************************************************/ +static struct sdis_medium* +create_dummy(struct sdis_device* sdis) +{ + struct sdis_fluid_shader shader = SDIS_FLUID_SHADER_NULL; + struct sdis_medium* dummy = NULL; + + shader.calorific_capacity = dummy_medium_getter; + shader.volumic_mass = dummy_medium_getter; + shader.temperature = dummy_medium_getter; + OK(sdis_fluid_create(sdis, &shader, NULL, &dummy)); + return dummy; +} + +/******************************************************************************* + * Interface of the system + ******************************************************************************/ +static double /* [K] */ +interface_get_temperature + (const struct sdis_interface_fragment* frag, + struct sdis_data* data) +{ + (void)data; + ASSERT(frag); + + if(frag->Ng[0] == 1) return T0; + else if(frag->Ng[0] == -1) return T1; + else if(frag->Ng[1] == 1) return SDIS_TEMPERATURE_NONE; + else if(frag->Ng[1] == -1) return SDIS_TEMPERATURE_NONE; + else FATAL("Unreachable code\n"); +} + +static struct sdis_interface* +create_interface + (struct sdis_device* sdis, + struct sdis_medium* front, + struct sdis_medium* back) +{ + struct sdis_interface* interf = NULL; + struct sdis_interface_shader shader = SDIS_INTERFACE_SHADER_NULL; + + shader.front.temperature = interface_get_temperature; + shader.back.temperature = interface_get_temperature; + OK(sdis_interface_create(sdis, front, back, &shader, NULL, &interf)); + return interf; +} + +/******************************************************************************* + * The scene + ******************************************************************************/ +static void +get_interface(const size_t itri, struct sdis_interface** interf, void* ctx) +{ + (void)itri; + ASSERT(interf && ctx); + *interf = ctx; +} + +static struct sdis_scene* +create_scene + (struct sdis_device* sdis, + struct sdis_interface* interf) +{ + struct sdis_scene_create_args scn_args = SDIS_SCENE_CREATE_ARGS_DEFAULT; + struct sdis_scene* scn = NULL; + + scn_args.get_indices = square_get_indices; + scn_args.get_interface = get_interface; + scn_args.get_position = square_get_position; + scn_args.nprimitives = square_nsegments; + scn_args.nvertices = square_nvertices; + scn_args.context = interf; + scn_args.fp_to_meter = FP_TO_METER; + OK(sdis_scene_2d_create(sdis, &scn_args, &scn)); + + return scn; +} + +/******************************************************************************* + * Validations + ******************************************************************************/ +static void +check_probe + (struct sdis_scene* scn, + const struct reference* ref, + const enum sdis_diffusion_algorithm diff_algo) +{ + struct sdis_solve_probe_args args = SDIS_SOLVE_PROBE_ARGS_DEFAULT; + struct sdis_mc T = SDIS_MC_NULL; + struct sdis_estimator* estimator = NULL; + CHK(ref); + + args.position[0] = ref->pos[0]; + args.position[1] = ref->pos[1]; + args.time_range[0] = + args.time_range[1] = ref->time; /* [s] */ + args.diff_algo = diff_algo; + args.nrealisations = NREALISATIONS; + OK(sdis_solve_probe(scn, &args, &estimator)); + OK(sdis_estimator_get_temperature(estimator, &T)); + + printf("T(%g, %g) at %g s = %g ~ %g +/- %g\n", + ref->pos[0]*FP_TO_METER, ref->pos[1]*FP_TO_METER, + ref->time, ref->temp, T.E, T.SE); + CHK(eq_eps(ref->temp, T.E, 3*T.SE)); + + OK(sdis_estimator_ref_put(estimator)); +} + +static void +check + (struct sdis_scene* scn, + const enum sdis_diffusion_algorithm diff_algo) +{ + const char* str_algo = NULL; + size_t i = 0; + + switch(diff_algo) { + case SDIS_DIFFUSION_WOS: str_algo = "Walk on Sphere"; break; + case SDIS_DIFFUSION_DELTA_SPHERE: str_algo = "Delta sphere"; break; + default: FATAL("Unreachable code.\n"); break; + } + + printf("\n\x1b[1m\x1b[35m%s\x1b[0m\n", str_algo); + FOR_EACH(i, 0, nreferences) { + check_probe(scn, references + i, diff_algo); + } +} + +/******************************************************************************* + * The test + ******************************************************************************/ +int +main(int argc, char** argv) +{ + struct sdis_device* sdis = NULL; + struct sdis_interface* interf = NULL; + struct sdis_medium* solid = NULL; + struct sdis_medium* dummy = NULL; + struct sdis_scene* scene = NULL; + (void)argc, (void)argv; + + OK(sdis_device_create(&SDIS_DEVICE_CREATE_ARGS_DEFAULT, &sdis)); + + solid = create_solid(sdis); + dummy = create_dummy(sdis); + interf = create_interface(sdis, solid, dummy); + scene = create_scene(sdis, interf); + + check(scene, SDIS_DIFFUSION_DELTA_SPHERE); + check(scene, SDIS_DIFFUSION_WOS); + + OK(sdis_device_ref_put(sdis)); + OK(sdis_interface_ref_put(interf)); + OK(sdis_medium_ref_put(solid)); + OK(sdis_medium_ref_put(dummy)); + OK(sdis_scene_ref_put(scene)); + + CHK(mem_allocated_size() == 0); + return 0; +} diff --git a/src/test_sdis_unsteady_analytic_profile.c b/src/test_sdis_unsteady_analytic_profile.c @@ -0,0 +1,380 @@ +/* Copyright (C) 2016-2023 |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.h" +#include "test_sdis_utils.h" + +#include <star/s3dut.h> + +#include <rsys/mem_allocator.h> + +/* + * The system is an unsteady-state temperature profile, meaning that at any + * point, at any: time, we can analytically calculate the temperature. We + * immerse in this temperature field a supershape representing a solid in which + * we want to evaluate the temperature by Monte Carlo at a given position and + * observation time. On the Monte Carlo side, the temperature of the supershape + * is unknown. Only the boundary temperature is fixed at the temperature of the + * unsteady trilinear profile mentioned above. Monte Carlo would then have to + * find the temperature defined by the unsteady profile. + * + * T(z) /\ <-- T(x,y,z,t) + * | T(y) ___/ \___ + * |/ \ . T=? / + * o--- T(x) /_ __ _\ + * \/ \/ + */ + +#define LAMBDA 0.1 /* [W/(m.K)] */ +#define RHO 25.0 /* [kg/m^3] */ +#define CP 2.0 /* [J/K/kg)] */ +#define DELTA 1.0/20.0 /* [m/fp_to_meter] */ + +#define NREALISATIONS 100000 + +/******************************************************************************* + * Helper functions + ******************************************************************************/ +static double +temperature(const double pos[3], const double time) +{ + const double kx = PI/4.0; + const double ky = PI/4.0; + const double kz = PI/4.0; + const double alpha = LAMBDA / (RHO*CP); /* Diffusivity */ + + const double A = 0; /* No termal source */ + const double B1 = 10; + const double B2 = 1000; + + double x, y, z, t; + double a, b, c; + double temp; + + ASSERT(pos); + + x = pos[0]; + y = pos[1]; + z = pos[2]; + t = time; + + a = B1*(x*x*x*z-3*x*y*y*z); + b = B2*sin(kx*x)*sin(ky*y)*sin(kz*z)*exp(-alpha*(kx*kx + ky*ky + kz*kz)*t); + c = A * x*x*x*x * y*y*y * z*z; + + temp = (a + b - c) / LAMBDA; + return temp; +} + +static INLINE void +dump_s3dut_mesh(FILE* fp, const struct s3dut_mesh* mesh) +{ + struct s3dut_mesh_data mesh_data; + + OK(s3dut_mesh_get_data(mesh, &mesh_data)); + dump_mesh(fp, mesh_data .positions, mesh_data.nvertices, + mesh_data.indices, mesh_data.nprimitives); +} + +static void +dump_paths + (FILE* fp, + struct sdis_scene* scn, + const enum sdis_diffusion_algorithm diff_algo, + const double pos[3], + const double time, + const size_t npaths) +{ + struct sdis_solve_probe_args args = SDIS_SOLVE_PROBE_ARGS_DEFAULT; + struct sdis_estimator* estimator = NULL; + + args.nrealisations = npaths; + args.position[0] = pos[0]; + args.position[1] = pos[1]; + args.position[2] = pos[2]; + args.time_range[0] = time; + args.time_range[1] = time; + args.diff_algo = diff_algo; + args.register_paths = SDIS_HEAT_PATH_ALL; + OK(sdis_solve_probe(scn, &args, &estimator)); + + dump_heat_paths(fp, estimator); + + OK(sdis_estimator_ref_put(estimator)); +} + +/******************************************************************************* + * Geometry + ******************************************************************************/ +static struct s3dut_mesh* +create_super_shape(void) +{ + struct s3dut_mesh* mesh = NULL; + struct s3dut_super_formula f0 = S3DUT_SUPER_FORMULA_NULL; + struct s3dut_super_formula f1 = S3DUT_SUPER_FORMULA_NULL; + const double radius = 1; + const unsigned nslices = 256; + + f0.A = 1.5; f0.B = 1; f0.M = 11.0; f0.N0 = 1; f0.N1 = 1; f0.N2 = 2.0; + f1.A = 1.0; f1.B = 2; f1.M = 3.6; f1.N0 = 1; f1.N1 = 2; f1.N2 = 0.7; + OK(s3dut_create_super_shape(NULL, &f0, &f1, radius, nslices, nslices/2, &mesh)); + + return mesh; +} + +/******************************************************************************* + * Scene, i.e. the system to simulate + ******************************************************************************/ +struct scene_context { + struct s3dut_mesh_data mesh_data; + struct sdis_interface* interf; +}; +static const struct scene_context SCENE_CONTEXT_NULL = {{0}, NULL}; + +static void +scene_get_indices(const size_t itri, size_t ids[3], void* ctx) +{ + struct scene_context* context = ctx; + CHK(ids && context && itri < context->mesh_data.nprimitives); + /* Flip the indices to ensure that the normal points into the super shape */ + ids[0] = (unsigned)context->mesh_data.indices[itri*3+0]; + ids[1] = (unsigned)context->mesh_data.indices[itri*3+2]; + ids[2] = (unsigned)context->mesh_data.indices[itri*3+1]; +} + +static void +scene_get_interface(const size_t itri, struct sdis_interface** interf, void* ctx) +{ + struct scene_context* context = ctx; + CHK(interf && context && itri < context->mesh_data.nprimitives); + *interf = context->interf; +} + +static void +scene_get_position(const size_t ivert, double pos[3], void* ctx) +{ + struct scene_context* context = ctx; + CHK(pos && context && ivert < context->mesh_data.nvertices); + pos[0] = context->mesh_data.positions[ivert*3+0]; + pos[1] = context->mesh_data.positions[ivert*3+1]; + pos[2] = context->mesh_data.positions[ivert*3+2]; +} + +static struct sdis_scene* +create_scene + (struct sdis_device* sdis, + const struct s3dut_mesh* mesh, + struct sdis_interface* interf) +{ + struct sdis_scene* scn = NULL; + struct sdis_scene_create_args scn_args = SDIS_SCENE_CREATE_ARGS_DEFAULT; + struct scene_context context = SCENE_CONTEXT_NULL; + + OK(s3dut_mesh_get_data(mesh, &context.mesh_data)); + context.interf = interf; + + scn_args.get_indices = scene_get_indices; + scn_args.get_interface = scene_get_interface; + scn_args.get_position = scene_get_position; + scn_args.nprimitives = context.mesh_data.nprimitives; + scn_args.nvertices = context.mesh_data.nvertices; + scn_args.context = &context; + OK(sdis_scene_create(sdis, &scn_args, &scn)); + return scn; +} + +/******************************************************************************* + * Solid, i.e. medium of the super shape + ******************************************************************************/ +#define SOLID_PROP(Prop, Val) \ + static double \ + solid_get_##Prop \ + (const struct sdis_rwalk_vertex* vtx, \ + struct sdis_data* data) \ + { \ + (void)vtx, (void)data; /* Avoid the "unused variable" warning */ \ + return Val; \ + } +SOLID_PROP(calorific_capacity, CP) /* [J/K/kg] */ +SOLID_PROP(thermal_conductivity, LAMBDA) /* [W/m/K] */ +SOLID_PROP(volumic_mass, RHO) /* [kg/m^3] */ +SOLID_PROP(delta, DELTA) /* [m/fp_to_meter] */ +SOLID_PROP(temperature, SDIS_TEMPERATURE_NONE/*<=> unknown*/) /* [K] */ +#undef SOLID_PROP + +static struct sdis_medium* +create_solid(struct sdis_device* sdis) +{ + struct sdis_solid_shader shader = SDIS_SOLID_SHADER_NULL; + struct sdis_medium* solid = NULL; + + shader.calorific_capacity = solid_get_calorific_capacity; + shader.thermal_conductivity = solid_get_thermal_conductivity; + shader.volumic_mass = solid_get_volumic_mass; + shader.delta = solid_get_delta; + shader.temperature = solid_get_temperature; + shader.t0 = -INF; + OK(sdis_solid_create(sdis, &shader, NULL, &solid)); + return solid; +} + +/******************************************************************************* + * Dummy environment, i.e. environment surrounding the super shape. It is + * defined only for Stardis compliance: in Stardis, an interface must divide 2 + * media. + ******************************************************************************/ +static struct sdis_medium* +create_dummy(struct sdis_device* sdis) +{ + struct sdis_fluid_shader shader = SDIS_FLUID_SHADER_NULL; + struct sdis_medium* dummy = NULL; + + shader.calorific_capacity = dummy_medium_getter; + shader.volumic_mass = dummy_medium_getter; + shader.temperature = dummy_medium_getter; + OK(sdis_fluid_create(sdis, &shader, NULL, &dummy)); + return dummy; +} + +/******************************************************************************* + * Interface: its temperature is fixed to the unsteady-state profile + ******************************************************************************/ +static double +interface_get_temperature + (const struct sdis_interface_fragment* frag, + struct sdis_data* data) +{ + (void)data; + return temperature(frag->P, frag->time); +} + +static struct sdis_interface* +create_interface + (struct sdis_device* sdis, + struct sdis_medium* front, + struct sdis_medium* back) +{ + struct sdis_interface* interf = NULL; + struct sdis_interface_shader shader = SDIS_INTERFACE_SHADER_NULL; + + shader.front.temperature = interface_get_temperature; + shader.back.temperature = interface_get_temperature; + OK(sdis_interface_create(sdis, front, back, &shader, NULL, &interf)); + return interf; +} + +/******************************************************************************* + * Validations + ******************************************************************************/ +static void +check_probe + (struct sdis_scene* scn, + const enum sdis_diffusion_algorithm diff_algo, + const double pos[3], + const double time, /* [s] */ + const int green) +{ + struct sdis_solve_probe_args args = SDIS_SOLVE_PROBE_ARGS_DEFAULT; + struct sdis_mc T = SDIS_MC_NULL; + struct sdis_estimator* estimator = NULL; + double ref = 0; + + args.nrealisations = NREALISATIONS; + args.position[0] = pos[0]; + args.position[1] = pos[1]; + args.position[2] = pos[2]; + args.time_range[0] = time; + args.time_range[1] = time; + args.diff_algo = diff_algo; + + if(!green) { + OK(sdis_solve_probe(scn, &args, &estimator)); + } else { + struct sdis_green_function* greenfn = NULL; + + OK(sdis_solve_probe_green_function(scn, &args, &greenfn)); + OK(sdis_green_function_solve(greenfn, &estimator)); + OK(sdis_green_function_ref_put(greenfn)); + } + + OK(sdis_estimator_get_temperature(estimator, &T)); + + ref = temperature(pos, time); + printf("T(%g, %g, %g, %g) = %g ~ %g +/- %g\n", + SPLIT3(pos), time, ref, T.E, T.SE); + CHK(eq_eps(ref, T.E, 3*T.SE)); + + OK(sdis_estimator_ref_put(estimator)); +} + +/******************************************************************************* + * The test + ******************************************************************************/ +int +main(int argc, char** argv) +{ + /* Stardis */ + struct sdis_device* sdis = NULL; + struct sdis_interface* interf = NULL; + struct sdis_medium* solid = NULL; + struct sdis_medium* dummy = NULL; /* Medium surrounding the solid */ + struct sdis_scene* scn = NULL; + + /* Miscellaneous */ + FILE* fp = NULL; + struct s3dut_mesh* super_shape = NULL; + const double pos[3] = {0.2,0.3,0.4}; /* [m/fp_to_meter] */ + const double time = 5; /* [s] */ + + (void)argc, (void)argv; + + OK(sdis_device_create(&SDIS_DEVICE_CREATE_ARGS_DEFAULT, &sdis)); + + super_shape = create_super_shape(); + + /* Save the super shape geometry for debug and visualisation */ + CHK(fp = fopen("super_shape_3d.obj", "w")); + dump_s3dut_mesh(fp, super_shape); + CHK(fclose(fp) == 0); + + solid = create_solid(sdis); + dummy = create_dummy(sdis); + interf = create_interface(sdis, solid, dummy); + scn = create_scene(sdis, super_shape, interf); + + check_probe(scn, SDIS_DIFFUSION_DELTA_SPHERE, pos, time, 0/*green*/); + check_probe(scn, SDIS_DIFFUSION_WOS, pos, time, 0/*green*/); + check_probe(scn, SDIS_DIFFUSION_WOS, pos, time, 1/*green*/); + + /* Write 10 heat paths sampled by the delta sphere algorithm */ + CHK(fp = fopen("paths_delta_sphere_3d.vtk", "w")); + dump_paths(fp, scn, SDIS_DIFFUSION_DELTA_SPHERE, pos, time, 10); + CHK(fclose(fp) == 0); + + /* Write 10 heat paths sampled by the WoS algorithm */ + CHK(fp = fopen("paths_wos_3d.vtk", "w")); + dump_paths(fp, scn, SDIS_DIFFUSION_WOS, pos, time, 10); + CHK(fclose(fp) == 0); + + OK(s3dut_mesh_ref_put(super_shape)); + OK(sdis_device_ref_put(sdis)); + OK(sdis_interface_ref_put(interf)); + OK(sdis_medium_ref_put(solid)); + OK(sdis_medium_ref_put(dummy)); + OK(sdis_scene_ref_put(scn)); + + CHK(mem_allocated_size() == 0); + return 0; +} diff --git a/src/test_sdis_unsteady_analytic_profile_2d.c b/src/test_sdis_unsteady_analytic_profile_2d.c @@ -0,0 +1,410 @@ +/* Copyright (C) 2016-2023 |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.h" +#include "test_sdis_utils.h" + +#include <rsys/mem_allocator.h> +#include <rsys/stretchy_array.h> + +/* + * The system is an unsteady-state temperature profile, meaning that at any + * point, at any: time, we can analytically calculate the temperature. We + * immerse in this temperature field a supershape representing a solid in which + * we want to evaluate the temperature by Monte Carlo at a given position and + * observation time. On the Monte Carlo side, the temperature of the supershape + * is unknown. Only the boundary temperature is fixed at the temperature of the + * unsteady trilinear profile mentioned above. Monte Carlo would then have to + * find the temperature defined by the unsteady profile. + * + * T(y) /\ <-- T(x,y,t) + * | ___/ \___ + * | \ . T=? / + * o--- T(x) /_ __ _\ + * \/ \/ + * + */ + +#define LAMBDA 0.1 /* [W/(m.K)] */ +#define RHO 25.0 /* [kg/m^3] */ +#define CP 2.0 /* [J/K/kg)] */ +#define DELTA 1.0/20.0 /* [m/fp_to_meter] */ + +#define NREALISATIONS 100000 + +struct super_shape { + double* positions; + size_t* indices; +}; +#define SUPER_SHAPE_NULL__ {NULL, NULL} +static const struct super_shape SUPER_SHAPE_NULL = SUPER_SHAPE_NULL__; + +/******************************************************************************* + * Helper functions + ******************************************************************************/ +/* Unsteady-state temperature profile. Its corresponding power term is : + * P(x, y) = A*[12*x^2*y^3 + 5*x^4*y] */ +static double temperature(const double pos[2], const double time) +{ + const double kx = PI/4; + const double ky = PI/4; + const double alpha = LAMBDA / (RHO*CP); /* Diffusivity */ + + const double A = 0; /* No termal source */ + const double B1 = 0; + const double B2 = 1000; + + double x, y, t; + double a, b, c; + double temp; + ASSERT(pos); + + x = pos[0]; + y = pos[1]; + t = time; + + a = B1*(x*x*x - 3*x*y*y); + b = B2*sin(kx*x)*sin(ky*y)*exp(-alpha*(kx*kx + ky*ky)*t); + c = A * x*x*x*x + y*y*y; + + temp = (a + b - c) / LAMBDA; + return temp; +} + +static void +dump_paths + (FILE* fp, + struct sdis_scene* scn, + const enum sdis_diffusion_algorithm diff_algo, + const double pos[2], + const double time, + const size_t npaths) +{ + struct sdis_solve_probe_args args = SDIS_SOLVE_PROBE_ARGS_DEFAULT; + struct sdis_estimator* estimator = NULL; + + args.nrealisations = npaths; + args.position[0] = pos[0]; + args.position[1] = pos[1]; + args.time_range[0] = time; + args.time_range[1] = time; + args.diff_algo = diff_algo; + args.register_paths = SDIS_HEAT_PATH_ALL; + OK(sdis_solve_probe(scn, &args, &estimator)); + + dump_heat_paths(fp, estimator); + + OK(sdis_estimator_ref_put(estimator)); +} + +/******************************************************************************* + * Solid, i.e. medium of the super shape + ******************************************************************************/ +#define SOLID_PROP(Prop, Val) \ + static double \ + solid_get_##Prop \ + (const struct sdis_rwalk_vertex* vtx, \ + struct sdis_data* data) \ + { \ + (void)vtx, (void)data; /* Avoid the "unused variable" warning */ \ + return Val; \ + } +SOLID_PROP(calorific_capacity, CP) /* [J/K/kg] */ +SOLID_PROP(thermal_conductivity, LAMBDA) /* [W/m/K] */ +SOLID_PROP(volumic_mass, RHO) /* [kg/m^3] */ +SOLID_PROP(delta, DELTA) /* [m/fp_to_meter] */ +SOLID_PROP(temperature, SDIS_TEMPERATURE_NONE/*<=> unknown*/) /* [K] */ +#undef SOLID_PROP + +static struct sdis_medium* +create_solid(struct sdis_device* sdis) +{ + struct sdis_solid_shader shader = SDIS_SOLID_SHADER_NULL; + struct sdis_medium* solid = NULL; + + shader.calorific_capacity = solid_get_calorific_capacity; + shader.thermal_conductivity = solid_get_thermal_conductivity; + shader.volumic_mass = solid_get_volumic_mass; + shader.delta = solid_get_delta; + shader.temperature = solid_get_temperature; + shader.t0 = -INF; + OK(sdis_solid_create(sdis, &shader, NULL, &solid)); + return solid; +} + +/******************************************************************************* + * Dummy environment, i.e. environment surrounding the super shape. It is + * defined only for Stardis compliance: in Stardis, an interface must divide 2 + * media. + ******************************************************************************/ +static struct sdis_medium* +create_dummy(struct sdis_device* sdis) +{ + struct sdis_fluid_shader shader = SDIS_FLUID_SHADER_NULL; + struct sdis_medium* dummy = NULL; + + shader.calorific_capacity = dummy_medium_getter; + shader.volumic_mass = dummy_medium_getter; + shader.temperature = dummy_medium_getter; + OK(sdis_fluid_create(sdis, &shader, NULL, &dummy)); + return dummy; +} + +/******************************************************************************* + * Interface: its temperature is fixed to the unsteady-state profile + ******************************************************************************/ +static double +interface_get_temperature + (const struct sdis_interface_fragment* frag, + struct sdis_data* data) +{ + (void)data; + return temperature(frag->P, frag->time); +} + +static struct sdis_interface* +create_interface + (struct sdis_device* sdis, + struct sdis_medium* front, + struct sdis_medium* back) +{ + struct sdis_interface* interf = NULL; + struct sdis_interface_shader shader = SDIS_INTERFACE_SHADER_NULL; + + shader.front.temperature = interface_get_temperature; + shader.back.temperature = interface_get_temperature; + OK(sdis_interface_create(sdis, front, back, &shader, NULL, &interf)); + return interf; +} + +/******************************************************************************* + * Super shape + ******************************************************************************/ +static struct super_shape +create_super_shape(void) +{ + struct super_shape sshape = SUPER_SHAPE_NULL; + + const unsigned nslices = 128; + const double a = 1.0; + const double b = 1.0; + const double n1 = 1.0; + const double n2 = 1.0; + const double n3 = 1.0; + const double m = 6.0; + size_t i = 0; + + FOR_EACH(i, 0, nslices) { + const double theta = (double)i * (2.0*PI / (double)nslices); + const double tmp0 = pow(fabs(1.0/a * cos(m/4.0*theta)), n2); + const double tmp1 = pow(fabs(1.0/b * sin(m/4.0*theta)), n3); + const double tmp2 = pow(tmp0 + tmp1, 1.0/n1); + const double r = 1.0 / tmp2; + const double x = cos(theta) * r; + const double y = sin(theta) * r; + const size_t j = (i + 1) % nslices; + + sa_push(sshape.positions, x); + sa_push(sshape.positions, y); + sa_push(sshape.indices, i); + sa_push(sshape.indices, j); + } + + return sshape; +} + +static void +release_super_shape(struct super_shape* sshape) +{ + CHK(sshape); + sa_release(sshape->positions); + sa_release(sshape->indices); +} + +static INLINE size_t +super_shape_nsegments(const struct super_shape* sshape) +{ + CHK(sshape); + return sa_size(sshape->indices) / 2/*#indices per segment*/; +} + +static INLINE size_t +super_shape_nvertices(const struct super_shape* sshape) +{ + CHK(sshape); + return sa_size(sshape->positions) / 2/*#coords per vertex*/; +} + +/******************************************************************************* + * Scene, i.e. the system to simulate + ******************************************************************************/ +struct scene_context { + const struct super_shape* sshape; + struct sdis_interface* interf; +}; +static const struct scene_context SCENE_CONTEXT_NULL = {NULL, NULL}; + +static void +scene_get_indices(const size_t iseg, size_t ids[2], void* ctx) +{ + struct scene_context* context = ctx; + CHK(ids && context); + /* Flip the indices to ensure that the normal points into the super shape */ + ids[0] = (unsigned)context->sshape->indices[iseg*2+1]; + ids[1] = (unsigned)context->sshape->indices[iseg*2+0]; +} + +static void +scene_get_interface(const size_t iseg, struct sdis_interface** interf, void* ctx) +{ + struct scene_context* context = ctx; + (void)iseg; + CHK(interf && context); + *interf = context->interf; +} + +static void +scene_get_position(const size_t ivert, double pos[2], void* ctx) +{ + struct scene_context* context = ctx; + CHK(pos && context); + pos[0] = context->sshape->positions[ivert*2+0]; + pos[1] = context->sshape->positions[ivert*2+1]; +} + +static struct sdis_scene* +create_scene + (struct sdis_device* sdis, + const struct super_shape* sshape, + struct sdis_interface* interf) +{ + struct sdis_scene* scn = NULL; + struct sdis_scene_create_args scn_args = SDIS_SCENE_CREATE_ARGS_DEFAULT; + struct scene_context context = SCENE_CONTEXT_NULL; + + context.interf = interf; + context.sshape = sshape; + + scn_args.get_indices = scene_get_indices; + scn_args.get_interface = scene_get_interface; + scn_args.get_position = scene_get_position; + scn_args.nprimitives = super_shape_nsegments(sshape); + scn_args.nvertices = super_shape_nvertices(sshape); + scn_args.context = &context; + OK(sdis_scene_2d_create(sdis, &scn_args, &scn)); + return scn; +} + +/******************************************************************************* + * Validations + ******************************************************************************/ +static void +check_probe + (struct sdis_scene* scn, + const enum sdis_diffusion_algorithm diff_algo, + const double pos[2], + const double time, /* [s] */ + const int green) +{ + struct sdis_solve_probe_args args = SDIS_SOLVE_PROBE_ARGS_DEFAULT; + struct sdis_mc T = SDIS_MC_NULL; + struct sdis_estimator* estimator = NULL; + double ref = 0; + + args.nrealisations = NREALISATIONS; + args.position[0] = pos[0]; + args.position[1] = pos[1]; + args.time_range[0] = time; + args.time_range[1] = time; + args.diff_algo = diff_algo; + + if(!green) { + OK(sdis_solve_probe(scn, &args, &estimator)); + } else { + struct sdis_green_function* greenfn = NULL; + + OK(sdis_solve_probe_green_function(scn, &args, &greenfn)); + OK(sdis_green_function_solve(greenfn, &estimator)); + OK(sdis_green_function_ref_put(greenfn)); + } + OK(sdis_estimator_get_temperature(estimator, &T)); + + ref = temperature(pos, time); + printf("T(%g, %g, %g) = %g ~ %g +/- %g\n", + SPLIT2(pos), time, ref, T.E, T.SE); + CHK(eq_eps(ref, T.E, 3*T.SE)); + + OK(sdis_estimator_ref_put(estimator)); +} + +/******************************************************************************* + * The test + ******************************************************************************/ +int +main(int argc, char** argv) +{ + /* Stardis */ + struct sdis_device* sdis = NULL; + struct sdis_interface* interf = NULL; + struct sdis_medium* solid = NULL; + struct sdis_medium* dummy = NULL; /* Medium surrounding the solid */ + struct sdis_scene* scn = NULL; + + /* Miscellaneous */ + FILE* fp = NULL; + struct super_shape sshape = SUPER_SHAPE_NULL; + const double pos[3] = {0.2,0.3}; /* [m/fp_to_meter] */ + const double time = 5; /* [s] */ + (void)argc, (void)argv; + + OK(sdis_device_create(&SDIS_DEVICE_CREATE_ARGS_DEFAULT, &sdis)); + + sshape = create_super_shape(); + + /* Save the super shape geometry for debug and visualisation */ + CHK(fp = fopen("super_shape_2d.obj", "w")); + dump_segments(fp, sshape.positions, super_shape_nvertices(&sshape), + sshape.indices, super_shape_nsegments(&sshape)); + CHK(fclose(fp) == 0); + + solid = create_solid(sdis); + dummy = create_dummy(sdis); + interf = create_interface(sdis, solid, dummy); + scn = create_scene(sdis, &sshape, interf); + + check_probe(scn, SDIS_DIFFUSION_DELTA_SPHERE, pos, time, 0/*green*/); + check_probe(scn, SDIS_DIFFUSION_WOS, pos, time, 0/*green*/); + check_probe(scn, SDIS_DIFFUSION_WOS, pos, time, 1/*green*/); + + /* Write 10 heat paths sampled by the delta sphere algorithm */ + CHK(fp = fopen("paths_delta_sphere_2d.vtk", "w")); + dump_paths(fp, scn, SDIS_DIFFUSION_DELTA_SPHERE, pos, time, 10); + CHK(fclose(fp) == 0); + + /* Write 10 heat paths sampled by the WoS algorithm */ + CHK(fp = fopen("paths_wos_2d.vtk", "w")); + dump_paths(fp, scn, SDIS_DIFFUSION_WOS, pos, time, 10); + CHK(fclose(fp) == 0); + + release_super_shape(&sshape); + OK(sdis_device_ref_put(sdis)); + OK(sdis_interface_ref_put(interf)); + OK(sdis_medium_ref_put(solid)); + OK(sdis_medium_ref_put(dummy)); + OK(sdis_scene_ref_put(scn)); + + CHK(mem_allocated_size() == 0); + return 0; +} diff --git a/src/test_sdis_utils.h b/src/test_sdis_utils.h @@ -428,4 +428,3 @@ check_green_serialization struct sdis_scene* scn); #endif /* TEST_SDIS_UTILS_H */ - diff --git a/src/test_sdis_volumic_power.c b/src/test_sdis_volumic_power.c @@ -45,7 +45,6 @@ * (0,0,0) ///// */ -#define UNKNOWN_TEMPERATURE -1 #define N 10000 /* #realisations */ #define T0 320 @@ -54,6 +53,22 @@ #define DELTA 1.0/55.0 /******************************************************************************* + * Helper functions + ******************************************************************************/ +static const char* +algo_cstr(const enum sdis_diffusion_algorithm diff_algo) +{ + const char* cstr = "none"; + + switch(diff_algo) { + case SDIS_DIFFUSION_DELTA_SPHERE: cstr = "delta sphere"; break; + case SDIS_DIFFUSION_WOS: cstr = "WoS"; break; + default: FATAL("Unreachable code.\n"); break; + } + return cstr; +} + +/******************************************************************************* * Media ******************************************************************************/ struct solid { @@ -72,7 +87,7 @@ fluid_get_temperature { (void)data; CHK(vtx != NULL); - return UNKNOWN_TEMPERATURE; + return SDIS_TEMPERATURE_NONE; } static double @@ -116,7 +131,7 @@ solid_get_temperature CHK(data != NULL); t0 = ((const struct solid*)sdis_data_cget(data))->t0; if(vtx->time > t0) { - return UNKNOWN_TEMPERATURE; + return SDIS_TEMPERATURE_NONE; } else { return ((const struct solid*)sdis_data_cget(data))->initial_temperature; } @@ -174,7 +189,6 @@ solve struct sdis_mc time = SDIS_MC_NULL; size_t nreals; size_t nfails; - double ref = -1; enum sdis_scene_dimension dim; const int nsimuls = 4; int isimul; @@ -182,11 +196,16 @@ solve OK(sdis_scene_get_dimension(scn, &dim)); FOR_EACH(isimul, 0, nsimuls) { - int steady = (isimul % 2) == 0; + const enum sdis_diffusion_algorithm algo = (isimul / 2) % 2 + ? SDIS_DIFFUSION_WOS + : SDIS_DIFFUSION_DELTA_SPHERE; + const int steady = (isimul % 2) == 0; + double power = P0 == SDIS_VOLUMIC_POWER_NONE ? 0 : P0; /* Restore power value */ solid->vpower = P0; + solve_args.diff_algo = algo; solve_args.position[0] = ssp_rng_uniform_double(rng, 0.1, 0.9); solve_args.position[1] = ssp_rng_uniform_double(rng, 0.1, 0.9); solve_args.position[2] = @@ -210,42 +229,28 @@ solve OK(sdis_estimator_get_temperature(estimator, &T)); OK(sdis_estimator_get_realisation_time(estimator, &time)); - switch(dim) { - case SDIS_SCENE_2D: - if(steady) { - double x = solve_args.position[0] - 0.5; - ref = solid->vpower / (2 * LAMBDA) * (1.0 / 4.0 - x * x) + T0; - printf("Steady temperature at (%g, %g) with Power=%g = %g ~ %g +/- %g\n", - SPLIT2(solve_args.position), solid->vpower, ref, T.E, T.SE); - } else { - printf("Mean temperature at (%g, %g) with t in [%g %g] and Power=%g" - " ~ %g +/- %g\n", - SPLIT2(solve_args.position), SPLIT2(solve_args.time_range), - solid->vpower, T.E, T.SE); - } - break; - case SDIS_SCENE_3D: - if(steady) { - double x = solve_args.position[0] - 0.5; - ref = solid->vpower / (2 * LAMBDA) * (1.0 / 4.0 - x * x) + T0; - printf("Steady temperature at (%g, %g, %g) with Power=%g = %g ~ %g +/- %g\n", - SPLIT3(solve_args.position), solid->vpower, ref, T.E, T.SE); - } else { - printf("Mean temperature at (%g, %g, %g) with t in [%g %g] and Power=%g" - " ~ %g +/- %g\n", - SPLIT3(solve_args.position), SPLIT2(solve_args.time_range), - solid->vpower, T.E, T.SE); - } - break; - default: FATAL("Unreachable code.\n"); break; + if(steady) { + const double x = solve_args.position[0] - 0.5; + const double ref = power / (2 * LAMBDA) * (1.0 / 4.0 - x * x) + T0; + printf + ("Steady temperature - pos: %g, %g, %g; Power: %g algo: %s " + "= %g ~ %g +/- %g\n", + SPLIT3(solve_args.position), power, algo_cstr(algo), ref, T.E, T.SE); + CHK(eq_eps(T.E, ref, T.SE * 3)); + } else { + printf( + "Mean temperature - pos: %g, %g, %g; t in [%g %g]; power: %g; algo: %s " + "~ %g +/- %g\n", + SPLIT3(solve_args.position), SPLIT2(solve_args.time_range), + power, algo_cstr(algo), T.E, T.SE); } + printf("#failures = %lu/%lu\n", (unsigned long)nfails, (unsigned long)N); printf("Elapsed time = %s\n", dump); printf("Time per realisation (in usec) = %g +/- %g\n\n", time.E, time.SE); CHK(nfails + nreals == N); CHK(nfails <= N/1000); - if(steady) CHK(eq_eps(T.E, ref, T.SE * 3)); /* Check green function */ time_current(&t0); @@ -258,37 +263,21 @@ solve OK(sdis_estimator_get_failure_count(estimator2, &nfails)); OK(sdis_estimator_get_temperature(estimator2, &T)); - switch(dim) { - case SDIS_SCENE_2D: - if(steady) { - double x = solve_args.position[0] - 0.5; - ref = solid->vpower / (2 * LAMBDA) * (1.0 / 4.0 - x * x) + T0; - printf("Green Steady temperature at (%g, %g) with Power=%g = %g" - " ~ %g +/- %g\n", - SPLIT2(solve_args.position), solid->vpower, ref, T.E, T.SE); - } else { - printf("Green Mean temperature at (%g, %g) with t in [%g %g] and" - " Power=%g ~ %g +/- %g\n", - SPLIT2(solve_args.position), SPLIT2(solve_args.time_range), - solid->vpower, T.E, T.SE); - } - break; - case SDIS_SCENE_3D: - if(steady) { - double x = solve_args.position[0] - 0.5; - ref = solid->vpower / (2 * LAMBDA) * (1.0 / 4.0 - x * x) + T0; - printf("Green Steady temperature at (%g, %g, %g) with Power=%g = %g" - " ~ %g +/- %g\n", - SPLIT3(solve_args.position), solid->vpower, ref, T.E, T.SE); - } else { - printf("Green Mean temperature at (%g, %g, %g) with t in [%g %g] and" - " Power=%g ~ %g +/- %g\n", - SPLIT3(solve_args.position), SPLIT2(solve_args.time_range), - solid->vpower, T.E, T.SE); - } - break; - default: FATAL("Unreachable code.\n"); break; + if(steady) { + const double x = solve_args.position[0] - 0.5; + const double ref = power / (2 * LAMBDA) * (1.0 / 4.0 - x * x) + T0; + printf + ("Green steady temperature - pos: %g, %g, %g; Power: %g algo: %s" + "= %g ~ %g +/- %g\n", + SPLIT3(solve_args.position), power, algo_cstr(algo), ref, T.E, T.SE); + } else { + printf( + "Green mean temperature - pos: %g, %g, %g; t: [%g %g]; power: %g; algo: %s " + "~ %g +/- %g\n", + SPLIT3(solve_args.position), SPLIT2(solve_args.time_range), + power, algo_cstr(algo), T.E, T.SE); } + printf("#failures = %lu/%lu\n", (unsigned long)nfails, (unsigned long)N); time_sub(&t0, &t1, &t0); time_dump(&t0, TIME_ALL, NULL, dump, sizeof(dump)); @@ -306,7 +295,7 @@ solve printf("\n"); /* Check same green used at a different power level */ - solid->vpower = 3 * P0; + solid->vpower = power = 3 * P0; time_current(&t0); OK(sdis_solve_probe(scn, &solve_args, &estimator)); @@ -318,43 +307,28 @@ solve OK(sdis_estimator_get_temperature(estimator, &T)); OK(sdis_estimator_get_realisation_time(estimator, &time)); - switch(dim) { - case SDIS_SCENE_2D: - if(steady) { - double x = solve_args.position[0] - 0.5; - ref = solid->vpower / (2 * LAMBDA) * (1.0 / 4.0 - x * x) + T0; - printf("Steady temperature at (%g, %g) with Power=%g = %g ~ %g +/- %g\n", - SPLIT2(solve_args.position), solid->vpower, ref, T.E, T.SE); - } else { - printf("Mean temperature at (%g, %g) with t in [%g %g] and Power=%g" - " ~ %g +/- %g\n", - SPLIT2(solve_args.position), SPLIT2(solve_args.time_range), - solid->vpower, T.E, T.SE); - } - break; - case SDIS_SCENE_3D: - if(steady) { - double x = solve_args.position[0] - 0.5; - ref = solid->vpower / (2 * LAMBDA) * (1.0 / 4.0 - x * x) + T0; - printf("Steady temperature at (%g, %g, %g) with Power=%g = %g" - " ~ %g +/- %g\n", - SPLIT3(solve_args.position), solid->vpower, ref, T.E, T.SE); - } else { - printf("Mean temperature at (%g, %g, %g) with t in [%g %g] and" - " Power=%g ~ %g +/- %g\n", - SPLIT3(solve_args.position), SPLIT2(solve_args.time_range), - solid->vpower, T.E, T.SE); - } - break; - default: FATAL("Unreachable code.\n"); break; + if(steady) { + const double x = solve_args.position[0] - 0.5; + const double ref = power / (2 * LAMBDA) * (1.0 / 4.0 - x * x) + T0; + printf + ("Steady temperature - pos: %g, %g, %g; Power: %g algo: %s " + "= %g ~ %g +/- %g\n", + SPLIT3(solve_args.position), power, algo_cstr(algo), ref, T.E, T.SE); + CHK(eq_eps(T.E, ref, T.SE * 3)); + } else { + printf( + "Mean temperature - pos: %g, %g, %g; t in [%g %g]; power: %g; algo: %s " + "~ %g +/- %g\n", + SPLIT3(solve_args.position), SPLIT2(solve_args.time_range), + power, algo_cstr(algo), T.E, T.SE); } + printf("#failures = %lu/%lu\n", (unsigned long)nfails, (unsigned long)N); printf("Elapsed time = %s\n", dump); printf("Time per realisation (in usec) = %g +/- %g\n", time.E, time.SE); CHK(nfails + nreals == N); CHK(nfails <= N/1000); - if(steady) CHK(eq_eps(T.E, ref, T.SE * 3)); time_current(&t0); OK(sdis_green_function_solve(green, &estimator2)); @@ -466,7 +440,7 @@ main(int argc, char** argv) /* Create the adiabatic interface */ OK(sdis_data_create(dev, sizeof(struct interf), 16, NULL, &data)); interf_props = sdis_data_get(data); - interf_props->temperature = UNKNOWN_TEMPERATURE; + interf_props->temperature = SDIS_TEMPERATURE_NONE; OK(sdis_interface_create (dev, solid, fluid, &interf_shader, data, &interf_adiabatic)); OK(sdis_data_ref_put(data)); diff --git a/src/test_sdis_volumic_power2.c b/src/test_sdis_volumic_power2.c @@ -19,7 +19,6 @@ #define N 10000 /* #realisations */ #define Pw 10000 /* Volumic power */ -#define NONE -1 #define DELTA 0.01 #define DELTA_PSQUARE 0.01 @@ -294,10 +293,10 @@ main(int argc, char** argv) {{0,-0.55, 0}, 90.250, 90.040} }; const struct reference refs2[] = { /* Lambda1=0.1, Lambda2=10, Pw=10000 */ - {{0, 0.85}, 678.170, -1}, - {{0, 0.65}, 1520.84, -1}, - {{0, 0.45}, 1794.57, -1}, - {{0, 0.25}, 1429.74, -1} + {{0, 0.85}, 678.170, 0}, + {{0, 0.65}, 1520.84, 0}, + {{0, 0.45}, 1794.57, 0}, + {{0, 0.25}, 1429.74, 0} }; (void)argc, (void)argv; @@ -341,7 +340,7 @@ main(int argc, char** argv) solid_param->lambda = 1; solid_param->delta = DELTA; solid_param->P = SDIS_VOLUMIC_POWER_NONE; - solid_param->T = -1; + solid_param->T = SDIS_TEMPERATURE_NONE; OK(sdis_solid_create(dev, &solid_shader, data, &solid1)); OK(sdis_data_ref_put(data)); @@ -354,7 +353,7 @@ main(int argc, char** argv) solid_param->lambda = 10; solid_param->delta = DELTA_PSQUARE; solid_param->P = Pw; - solid_param->T = -1; + solid_param->T = SDIS_TEMPERATURE_NONE; OK(sdis_solid_create(dev, &solid_shader, data, &solid2)); OK(sdis_data_ref_put(data)); @@ -387,7 +386,7 @@ main(int argc, char** argv) NULL, &data)); interf_param = sdis_data_get(data); interf_param->h = 5; - interf_param->temperature = NONE; + interf_param->temperature = SDIS_TEMPERATURE_NONE; OK(sdis_interface_create(dev, solid1, fluid1, &interf_shader, data, &interf_solid1_fluid1)); OK(sdis_data_ref_put(data)); @@ -397,7 +396,7 @@ main(int argc, char** argv) NULL, &data)); interf_param = sdis_data_get(data); interf_param->h = 10; - interf_param->temperature = NONE; + interf_param->temperature = SDIS_TEMPERATURE_NONE; OK(sdis_interface_create(dev, solid1, fluid2, &interf_shader, data, &interf_solid1_fluid2)); OK(sdis_data_ref_put(data)); diff --git a/src/test_sdis_volumic_power2_2d.c b/src/test_sdis_volumic_power2_2d.c @@ -19,11 +19,10 @@ #define N 10000 /* #realisations */ #define Pw 10000 /* Volumic power */ -#define NONE -1 /* H delta T */ -#define Tboundary1 NONE -#define Tboundary2 NONE +#define Tboundary1 SDIS_TEMPERATURE_NONE +#define Tboundary2 SDIS_TEMPERATURE_NONE #define DELTA 0.01 #define Tref 286.83 /* In Celsius. Computed with Syrthes at the position 0.5 */ @@ -373,7 +372,7 @@ main(int argc, char** argv) solid_param->lambda = 1; solid_param->delta = DELTA; solid_param->P = SDIS_VOLUMIC_POWER_NONE; - solid_param->T = -1; + solid_param->T = SDIS_TEMPERATURE_NONE; OK(sdis_solid_create(dev, &solid_shader, data, &solid1)); OK(sdis_data_ref_put(data)); @@ -386,7 +385,7 @@ main(int argc, char** argv) solid_param->lambda = 10; solid_param->delta = DELTA; solid_param->P = Pw; - solid_param->T = -1; + solid_param->T = SDIS_TEMPERATURE_NONE; OK(sdis_solid_create(dev, &solid_shader, data, &solid2)); OK(sdis_data_ref_put(data)); diff --git a/src/test_sdis_volumic_power3_2d.c b/src/test_sdis_volumic_power3_2d.c @@ -41,11 +41,10 @@ #define Tb 1207.1122 /* Fixed temperatures */ -#define UNKNOWN_TEMPERATURE -1 -#define Tsolid1_fluid UNKNOWN_TEMPERATURE /*Tp1*/ -#define Tsolid2_fluid UNKNOWN_TEMPERATURE /*Tp2*/ -#define Tsolid_solid1 UNKNOWN_TEMPERATURE /*Ta*/ -#define Tsolid_solid2 UNKNOWN_TEMPERATURE /*Tb*/ +#define Tsolid1_fluid SDIS_TEMPERATURE_NONE /*Tp1*/ +#define Tsolid2_fluid SDIS_TEMPERATURE_NONE /*Tp2*/ +#define Tsolid_solid1 SDIS_TEMPERATURE_NONE /*Ta*/ +#define Tsolid_solid2 SDIS_TEMPERATURE_NONE /*Tb*/ #define PROBE_POS 1.8 @@ -304,7 +303,7 @@ main(int argc, char** argv) solid_param->lambda = LAMBDA1; solid_param->delta = DELTA1; solid_param->volumic_power = SDIS_VOLUMIC_POWER_NONE; - solid_param->temperature = -1; + solid_param->temperature = SDIS_TEMPERATURE_NONE; OK(sdis_solid_create(dev, &solid_shader, data, &solid1)); OK(sdis_data_ref_put(data)); @@ -317,7 +316,7 @@ main(int argc, char** argv) solid_param->lambda = LAMBDA2; solid_param->delta = DELTA2; solid_param->volumic_power = SDIS_VOLUMIC_POWER_NONE; - solid_param->temperature = -1; + solid_param->temperature = SDIS_TEMPERATURE_NONE; OK(sdis_solid_create(dev, &solid_shader, data, &solid2)); OK(sdis_data_ref_put(data)); @@ -330,7 +329,7 @@ main(int argc, char** argv) solid_param->lambda = LAMBDA; solid_param->delta = DELTA; solid_param->volumic_power = Pw; - solid_param->temperature = -1; + solid_param->temperature = SDIS_TEMPERATURE_NONE; OK(sdis_solid_create(dev, &solid_shader, data, &solid)); OK(sdis_data_ref_put(data)); @@ -363,7 +362,7 @@ main(int argc, char** argv) NULL, &data)); interf_param = sdis_data_get(data); interf_param->h = 0; - interf_param->temperature = -1; + interf_param->temperature = SDIS_TEMPERATURE_NONE; OK(sdis_interface_create(dev, solid, fluid, &interf_shader, data, &interf_solid_adiabatic)); OK(sdis_interface_create(dev, solid1, fluid, &interf_shader, data, diff --git a/src/test_sdis_volumic_power4.c b/src/test_sdis_volumic_power4.c @@ -270,7 +270,7 @@ main(int argc, char** argv) solid_param->lambda = LAMBDA; solid_param->delta = DELTA; solid_param->volumic_power = Power; - solid_param->temperature = -1; + solid_param->temperature = SDIS_TEMPERATURE_NONE; OK(sdis_solid_create(dev, &solid_shader, data, &solid)); OK(sdis_data_ref_put(data)); @@ -283,7 +283,7 @@ main(int argc, char** argv) NULL, &data)); interf_param = sdis_data_get(data); interf_param->h = 0; - interf_param->temperature = -1; + interf_param->temperature = SDIS_TEMPERATURE_NONE; OK(sdis_interface_create(dev, solid, fluid1, &interf_shader, data, &interf_adiabatic)); OK(sdis_data_ref_put(data)); @@ -293,7 +293,7 @@ main(int argc, char** argv) NULL, &data)); interf_param = sdis_data_get(data); interf_param->h = H; - interf_param->temperature = -1; + interf_param->temperature = SDIS_TEMPERATURE_NONE; OK(sdis_interface_create(dev, solid, fluid1, &interf_shader, data, &interf_solid_fluid1)); OK(sdis_data_ref_put(data)); @@ -303,7 +303,7 @@ main(int argc, char** argv) NULL, &data)); interf_param = sdis_data_get(data); interf_param->h = H; - interf_param->temperature = -1; + interf_param->temperature = SDIS_TEMPERATURE_NONE; OK(sdis_interface_create(dev, solid, fluid2, &interf_shader, data, &interf_solid_fluid2)); OK(sdis_data_ref_put(data));