commit 51284033a44ed852765399fc26eda1efce1bd379
parent e59857a2ed0a5e7adebea69409704804411011c5
Author: Vincent Forest <vincent.forest@meso-star.com>
Date: Wed, 17 Jul 2024 11:19:19 +0200
Merge branch 'release_0.16'
Diffstat:
47 files changed, 4495 insertions(+), 1704 deletions(-)
diff --git a/Makefile b/Makefile
@@ -43,6 +43,7 @@ SRC =\
src/sdis_log.c\
src/sdis_medium.c\
src/sdis_misc.c\
+ src/sdis_primkey.c\
src/sdis_radiative_env.c\
src/sdis_realisation.c\
src/sdis_scene.c\
@@ -192,6 +193,8 @@ TEST_SRC =\
src/test_sdis_interface.c\
src/test_sdis_medium.c\
src/test_sdis_picard.c\
+ src/test_sdis_primkey.c\
+ src/test_sdis_primkey_2d.c\
src/test_sdis_radiative_env.c\
src/test_sdis_scene.c\
src/test_sdis_solid_random_walk_robustness.c\
@@ -216,6 +219,8 @@ TEST_SRC_LONG =\
TEST_SRC_MPI =\
src/test_sdis.c\
src/test_sdis_compute_power.c\
+ src/test_sdis_custom_solid_path_sampling.c\
+ src/test_sdis_custom_solid_path_sampling_2d.c\
src/test_sdis_device.c\
src/test_sdis_external_flux.c\
src/test_sdis_solve_camera.c\
@@ -396,6 +401,7 @@ test_sdis_volumic_power4 \
################################################################################
src/test_sdis_draw_external_flux.d \
src/test_sdis_external_flux_with_diffuse_radiance.d \
+src/test_sdis_primkey.d \
src/test_sdis_solid_random_walk_robustness.d \
src/test_sdis_solve_probe3.d \
src/test_sdis_unsteady_analytic_profile.d \
@@ -404,6 +410,7 @@ src/test_sdis_unsteady_analytic_profile.d \
src/test_sdis_draw_external_flux.o \
src/test_sdis_external_flux_with_diffuse_radiance.o \
+src/test_sdis_primkey.o \
src/test_sdis_solid_random_walk_robustness.o \
src/test_sdis_solve_probe3.o \
src/test_sdis_unsteady_analytic_profile.o \
@@ -412,6 +419,7 @@ src/test_sdis_unsteady_analytic_profile.o \
test_sdis_draw_external_flux \
test_sdis_external_flux_with_diffuse_radiance \
+test_sdis_primkey \
test_sdis_solid_random_walk_robustness \
test_sdis_solve_probe3 \
test_sdis_unsteady_analytic_profile \
@@ -419,6 +427,36 @@ test_sdis_unsteady_analytic_profile \
$(CC) $(TEST_CFLAGS) $(S3DUT_CFLAGS) -o $@ src/$@.o $(TEST_LIBS) $(S3DUT_LIBS)
################################################################################
+# Test based on Star-2D
+################################################################################
+src/test_sdis_primkey_2d.d \
+: config.mk sdis-local.pc
+ @$(CC) $(TEST_CFLAGS) $(S2D_CFLAGS) -MM -MT "$(@:.d=.o) $@" $(@:.d=.c) -MF $@
+
+src/test_sdis_primkey_2d.o \
+: config.mk sdis-local.pc
+ $(CC) $(TEST_CFLAGS) $(S2D_CFLAGS) -c $(@:.o=.c) -o $@
+
+test_sdis_primkey_2d \
+: config.mk sdis-local.pc $(LIBNAME) src/test_sdis_utils.o
+ $(CC) $(TEST_CFLAGS) $(S2D_CFLAGS) -o $@ src/$@.o $(TEST_LIBS) $(S2D_LIBS)
+
+################################################################################
+# Test based on Star-2D with (optional) MPI support
+################################################################################
+src/test_sdis_custom_solid_path_sampling_2d.d \
+: config.mk sdis-local.pc
+ @$(CC) $(TEST_CFLAGS_MPI) $(S2D_CFLAGS) -MM -MT "$(@:.d=.o) $@" $(@:.d=.c) -MF $@
+
+src/test_sdis_custom_solid_path_sampling_2d.o \
+: config.mk sdis-local.pc
+ $(CC) $(TEST_CFLAGS_MPI) $(S2D_CFLAGS) -c $(@:.o=.c) -o $@
+
+test_sdis_custom_solid_path_sampling_2d \
+: config.mk sdis-local.pc $(LIBNAME) src/test_sdis_utils.o
+ $(CC) $(TEST_CFLAGS_MPI) $(S2D_CFLAGS) -o $@ src/$@.o $(TEST_LIBS_MPI) $(S2D_LIBS)
+
+################################################################################
# Tests based on Star-Enclosures-<2|3>D
################################################################################
src/test_sdis_scene.d \
@@ -482,19 +520,24 @@ test_sdis_solve_probe_boundary_list \
$(CC) $(TEST_CFLAGS_MPI) $(S3DUT_CFLAGS) -o $@ src/$@.o $(TEST_LIBS_MPI) $(S3DUT_LIBS)
################################################################################
-# Tests based on Star-3D and Star-3DUT with (optional) MPI support
+# Tests based on Star-3D, Star-3DUT and Star-SP with (optional) MPI support
################################################################################
+src/test_sdis_custom_solid_path_sampling.d \
src/test_sdis_solve_probe_list.d \
: config.mk sdis-local.pc
- @$(CC) $(TEST_CFLAGS_MPI) $(S3D_CFLAGS) $(S3DUT_CFLAGS) -MM -MT "$(@:.d=.o) $@" $(@:.d=.c) -MF $@
+ @$(CC) $(TEST_CFLAGS_MPI) $(S3D_CFLAGS) $(S3DUT_CFLAGS) $(SSP_CFLAGS) \
+ -MM -MT "$(@:.d=.o) $@" $(@:.d=.c) -MF $@
+src/test_sdis_custom_solid_path_sampling.o \
src/test_sdis_solve_probe_list.o \
: config.mk sdis-local.pc
- $(CC) $(TEST_CFLAGS_MPI) $(S3D_CFLAGS) $(S3DUT_CFLAGS) -c $(@:.o=.c) -o $@
+ $(CC) $(TEST_CFLAGS_MPI) $(S3D_CFLAGS) $(S3DUT_CFLAGS) $(SSP_CFLAGS) -c $(@:.o=.c) -o $@
+test_sdis_custom_solid_path_sampling \
test_sdis_solve_probe_list \
: config.mk sdis-local.pc $(LIBNAME) src/test_sdis_utils.o
- $(CC) $(TEST_CFLAGS_MPI) $(S3D_CFLAGS) $(S3DUT_CFLAGS) -o $@ src/$@.o $(TEST_LIBS_MPI) $(S3D_LIBS) $(S3DUT_LIBS)
+ $(CC) $(TEST_CFLAGS_MPI) $(S3D_CFLAGS) $(S3DUT_CFLAGS) $(SSP_CFLAGS) \
+ -o $@ src/$@.o $(TEST_LIBS_MPI) $(S3D_LIBS) $(S3DUT_LIBS) $(SSP_CFLAGS)
################################################################################
# Tests based on Star-SP with (optional) MPI support
diff --git a/README.md b/README.md
@@ -158,6 +158,66 @@ Edit config.mk as needed, then run:
## Release notes
+### Version 0.16
+
+#### Add support for custom sampling of solid paths
+
+Add the `sample_path` functor as a member variable of the
+`sdis_solid_shader` data structure which, once defined, is called to
+sample a trajectory in this solid, instead of relying on the internal
+sampling procedures for unsteady conductive paths (i.e. walk on
+delta sphere or walk on sphere).
+
+Coupling takes place as usual, i.e. at the boundary. Only path sampling
+is delegated to the caller. In other words, the connection physics
+remain the same, and the user only has control over the physical model
+of the custom solid.
+
+Note that to help the user map the sampled path to the solver limits
+(i.e. the geometry reached by the path), we added the `sdis_primkey` API
+which constructs a unique key from the vertices of a segment/triangle.
+We can then use this key as input to the new functions
+`sdis_scene_get_s<2|3>d_primitive` to find the solver primitive which
+corresponds to this segment/triangle. It is therefore sufficient to know
+the *exact* coordinates of the boundary mesh to geometrically couple the
+paths sampled by the user with the boundaries of the geometries managed
+by the solver.
+
+#### Correcting the sampling of radiative paths
+
+Allows sampling of radiative paths in enclosures with multiple media.
+Multiple media are often used to define a set of Robin boundary
+conditions. And although sampling a convective path in such an enclosure
+is an error (since it is outside the space of convective paths), it is
+still possible to sample radiative paths in this enclosure (it is
+perfectly defined in the space of radiative paths).
+
+For example, it is now possible to render an infrared image of a system
+with a set of Robin boundary conditions defined from a set of fluids
+with fixed temperatures.
+
+#### Bug fixes
+
+- Fixes the `sdis_solve_probe_boundary_list` function. The calculation
+ did not use the expected number of threads, which could lead to an
+ invalid memory access.
+- Updated error handling when resolving temperatures for several probes.
+ The calculation of a probe no longer stops as soon as a realisation is
+ rejected. As with the calculation of a single probe, if a result is
+ rejected, it is simply not taken into account in the estimate.
+- Corrects numerical problems when sampling a conductive path with WoS.
+ The thresholds used to detect/manage numerical problems were
+ calculated from absolute distances in metres. This method was not
+ numerically robust when these distances were very small. They
+ are now calculated in relation to the delta of the solid, which must
+ be able to take account of spatio-temporal temperature gradients while
+ being large enough to allow numerical estimation.
+- Corrects the position of the path when the initial condition is
+ reached during the sampling of a conductive path with WoS. The unit
+ used to update the position was wrong when the `fp_to_meter`
+ variable was not set to 1. In addition, the position at which the
+ initial condition was reached could be outside the solid.
+
### Version 0.15.2
Correction of pkg-config file. A missing private dependency could lead
@@ -249,8 +309,8 @@ a Dirichlet boundary condition. In other words, the same data could
define totally different systems before or after this version.
The macro `SDIS_TEMPERATURE_NONE` is added to define the unknown
-temperature value. The two helper macros `SDIS_TEMPERATURE_IS_KNONW` and
-`SDIS_TEMPERATURE_IS_UNKNONW` are also provided to test whether the
+temperature value. The two helper macros `SDIS_TEMPERATURE_IS_KNOWN` and
+`SDIS_TEMPERATURE_IS_UNKNOWN` are also provided to test whether the
temperature is known or not.
#### Parallelize multiple probe resolutions
diff --git a/config.mk b/config.mk
@@ -1,6 +1,6 @@
VERSION_MAJOR = 0
-VERSION_MINOR = 15
-VERSION_PATCH = 2
+VERSION_MINOR = 16
+VERSION_PATCH = 0
VERSION = $(VERSION_MAJOR).$(VERSION_MINOR).$(VERSION_PATCH)
PREFIX = /usr/local
@@ -55,7 +55,7 @@ SENC2D_VERSION = 0.5
SENC2D_CFLAGS = $$($(PKG_CONFIG) $(PCFLAGS) --cflags senc2d)
SENC2D_LIBS = $$($(PKG_CONFIG) $(PCFLAGS) --libs senc2d)
-SENC3D_VERSION = 0.5
+SENC3D_VERSION = 0.7.2
SENC3D_CFLAGS = $$($(PKG_CONFIG) $(PCFLAGS) --cflags senc3d)
SENC3D_LIBS = $$($(PKG_CONFIG) $(PCFLAGS) --libs senc3d)
diff --git a/sdis.pc.in b/sdis.pc.in
@@ -8,8 +8,8 @@ Requires: \
s3d >= @S3D_VERSION@,\
star-sp >= @SSP_VERSION@
Requires.private:\
- senc2d >= @SENC3D_VERSION@,\
- senc3d >= @SENC3D_VERSION@, \
+ senc2d >= @SENC2D_VERSION@,\
+ senc3d >= @SENC3D_VERSION@,\
swf >= @SWF_VERSION@ @MPI@
Name: sdis
Description: Stardis Solver
diff --git a/src/sdis.h b/src/sdis.h
@@ -220,6 +220,51 @@ struct sdis_scene_find_closest_point_args {
static const struct sdis_scene_find_closest_point_args
SDIS_SCENE_FIND_CLOSEST_POINT_ARGS_NULL = SDIS_SCENE_FIND_CLOSEST_POINT_ARGS_NULL__;
+/* A sampled path */
+struct sdis_path {
+ struct sdis_rwalk_vertex vtx; /* Current position and time */
+
+ /* Surface intersected by the path. When defined, the path is on a border */
+ struct s2d_primitive prim_2d;
+ struct s3d_primitive prim_3d;
+
+ double weight; /* Monte Carlo weight update along the path */
+
+ /* Define whether the path has reached a boundary condition in time/space */
+ int at_limit;
+};
+#define SDIS_PATH_NULL__ { \
+ SDIS_RWALK_VERTEX_NULL__, \
+ S2D_PRIMITIVE_NULL__, \
+ S3D_PRIMITIVE_NULL__, \
+ 0, /* MC weight */ \
+ 0 /* At limit */ \
+}
+static const struct sdis_path SDIS_PATH_NULL = SDIS_PATH_NULL__;
+
+/* Type of functor used by the user to write the way in which the path is
+ * sampled. So it's no longer Stardis that samples the path, but the user
+ * through his own function. */
+typedef res_T
+(*sdis_sample_path_T)
+ (struct sdis_scene* scn,
+ struct ssp_rng* rng,
+ struct sdis_path* path,
+ struct sdis_data* data);
+
+/* Key to a geometric primitive, i.e its unique identifier. Its member variables
+ * must be treated as private variables, i.e. the caller must not access them
+ * directly but use the primkey API functions instead (see below) */
+struct sdis_primkey {
+ /* List of primitive nodes sorted in ascending order */
+ double nodes[9];
+
+ /* Overall number of coordinates (4 in 2D, 9 in 3D) */
+ unsigned ncoords;
+};
+#define SDIS_PRIMKEY_NULL__ {{0,0,0,0,0,0,0,0,0},0}
+static const struct sdis_primkey SDIS_PRIMKEY_NULL = SDIS_PRIMKEY_NULL__;
+
/*******************************************************************************
* Estimation data types
******************************************************************************/
@@ -294,12 +339,16 @@ struct sdis_solid_shader {
* This getter is always called at time >= t0 (see below). */
sdis_medium_getter_T temperature;
+ /* Function to be used to sample the path through the solid. If not defined,
+ * let stardis sample a conductive path */
+ sdis_sample_path_T sample_path;
+
/* 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}
+#define SDIS_SOLID_SHADER_NULL__ {NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0}
static const struct sdis_solid_shader SDIS_SOLID_SHADER_NULL =
SDIS_SOLID_SHADER_NULL__;
@@ -1311,18 +1360,30 @@ sdis_scene_boundary_project_position
const double pos[],
double uv[]);
-/* Get the 2D scene's enclosures. Only defined for a 2D scene. */
+/* Get Star-Enclosure-2D scene. Defined on 2D scene only */
SDIS_API res_T
sdis_scene_get_senc2d_scene
(struct sdis_scene* scn,
struct senc2d_scene** senc2d_scn);
-/* Get the 3D scene's enclosures. Only defined for a 3D scene. */
+/* Get Star-Enclosure-3D scene. Defined on 3D scene only */
SDIS_API res_T
sdis_scene_get_senc3d_scene
(struct sdis_scene* scn,
struct senc3d_scene** senc3d_scn);
+/* Get Star-2D scene view. Defined on 2D scene only */
+SDIS_API res_T
+sdis_scene_get_s2d_scene_view
+ (struct sdis_scene* scn,
+ struct s2d_scene_view** s2d_view);
+
+/* Get Star-3D scene view. Defined on 3D scene only */
+SDIS_API res_T
+sdis_scene_get_s3d_scene_view
+ (struct sdis_scene* scn,
+ struct s3d_scene_view** s3d_view);
+
SDIS_API res_T
sdis_scene_get_dimension
(const struct sdis_scene* scn,
@@ -1353,6 +1414,20 @@ sdis_scene_get_radiative_env
/* The returned pointer can be NULL, i.e. there is no radiative environement*/
struct sdis_radiative_env** radenv);
+/* Get the internal Star-2D primitive corresponding to the primitive key */
+SDIS_API res_T
+sdis_scene_get_s2d_primitive
+ (struct sdis_scene* scn,
+ const struct sdis_primkey* key,
+ struct s2d_primitive* primitive);
+
+/* Get the internal Star-3D primitive corresponding to the primitive key */
+SDIS_API res_T
+sdis_scene_get_s3d_primitive
+ (struct sdis_scene* scn,
+ const struct sdis_primkey* key,
+ struct s3d_primitive* primitive);
+
/*******************************************************************************
* An estimator stores the state of a simulation
******************************************************************************/
@@ -1717,6 +1792,31 @@ SDIS_API res_T
sdis_get_info
(struct sdis_info* info);
+/*******************************************************************************
+ * Primitive identifier
+ ******************************************************************************/
+SDIS_API void
+sdis_primkey_setup
+ (struct sdis_primkey* key,
+ const double node0[3],
+ const double node1[3],
+ const double node2[3]);
+
+SDIS_API void
+sdis_primkey_2d_setup
+ (struct sdis_primkey* key,
+ const double node0[2],
+ const double node1[2]);
+
+SDIS_API size_t
+sdis_primkey_hash
+ (const struct sdis_primkey* key);
+
+SDIS_API char
+sdis_primkey_eq
+ (const struct sdis_primkey* key0,
+ const struct sdis_primkey* key1);
+
END_DECLS
#endif /* SDIS_H */
diff --git a/src/sdis_Xd_begin.h b/src/sdis_Xd_begin.h
@@ -65,6 +65,7 @@
#define SXD_GET_PRIMITIVE CONCAT(CONCAT(S, DIM), D_GET_PRIMITIVE)
#define SXD_SAMPLE CONCAT(CONCAT(S, DIM), D_SAMPLE)
#define SXD_TRACE CONCAT(CONCAT(S, DIM), D_TRACE)
+#define SXD_PRIMITIVE_NULL CONCAT(CONCAT(S, DIM), D_PRIMITIVE_NULL)
#define SXD_PRIMITIVE_EQ CONCAT(CONCAT(S, DIM), D_PRIMITIVE_EQ)
/* Vector macros generic to SDIS_XD_DIMENSION */
@@ -76,44 +77,3 @@
/* Macro making generic its submitted name to SDIS_XD_DIMENSION */
#define XD(Name) CONCAT(CONCAT(CONCAT(Name, _), DIM), d)
-
-/* Generate the generic data structures and constants */
-#if (SDIS_XD_DIMENSION == 2 && !defined(SDIS_2D_H)) \
-|| (SDIS_XD_DIMENSION == 3 && !defined(SDIS_3D_H))
- #if SDIS_XD_DIMENSION == 2
- #define SDIS_2D_H
- #else
- #define SDIS_3D_H
- #endif
-
-struct rwalk_context;
-
-/* Current state of the random walk */
-struct XD(rwalk) {
- struct sdis_rwalk_vertex vtx; /* Position and time of the Random walk */
- struct sdis_medium* mdm; /* Medium in which the random walk lies */
- struct sXd(hit) hit; /* Hit of the random walk */
-
- /* Direction along which the random walk reached the radiative environment */
- double dir[3];
-
- double elapsed_time;
- enum sdis_side hit_side;
-};
-static const struct XD(rwalk) XD(RWALK_NULL) = {
- SDIS_RWALK_VERTEX_NULL__, NULL, SXD_HIT_NULL__, {0,0,0}, 0, SDIS_SIDE_NULL__
-};
-
-struct XD(temperature) {
- res_T (*func)/* Next function to invoke in order to compute the temperature */
- (struct sdis_scene* scn,
- struct rwalk_context* ctx,
- struct XD(rwalk)* rwalk,
- struct ssp_rng* rng,
- struct XD(temperature)* temp);
- double value; /* Current value of the temperature */
- int done;
-};
-static const struct XD(temperature) XD(TEMPERATURE_NULL) = { NULL, 0, 0 };
-
-#endif /* SDIX_<2|3>D_H */
diff --git a/src/sdis_Xd_end.h b/src/sdis_Xd_end.h
@@ -34,6 +34,8 @@
#undef SXD_GET_PRIMITIVE
#undef SXD_SAMPLE
#undef SXD_TRACE
+#undef SXD_PRIMITIVE_NULL
+#undef SXD_PRIMITIVE_EQ
#undef dX
#undef fX
diff --git a/src/sdis_heat_path.h b/src/sdis_heat_path.h
@@ -17,6 +17,7 @@
#define SDIS_HEAT_PATH_H
#include "sdis.h"
+#include "sdis_scene_c.h"
#include <rsys/dynamic_array.h>
#include <rsys/dynamic_array_size_t.h>
@@ -24,12 +25,8 @@
/* Forward declarations */
struct green_path_handle;
-struct rwalk_2d;
-struct rwalk_3d;
struct sdis_scene;
struct ssp_rng;
-struct temperature_2d;
-struct temperature_3d;
/*******************************************************************************
* Context of a random walk, i.e. its data concerning the current system and the
@@ -87,6 +84,46 @@ get_picard_order(const struct rwalk_context* ctx)
}
/*******************************************************************************
+ * 2D/3D random walk and associated temperature, i.e. current state of the
+ * sampled path
+ ******************************************************************************/
+struct rwalk {
+ struct sdis_rwalk_vertex vtx; /* Position and time of the Random walk */
+ unsigned enc_id; /* Id of the enclosure in which the random walk lies */
+ struct s2d_hit hit_2d;
+ struct s3d_hit hit_3d;
+
+ /* Direction along which the random walk reached the radiative environment */
+ double dir[3];
+
+ double elapsed_time;
+ enum sdis_side hit_side;
+};
+#define RWALK_NULL__ { \
+ SDIS_RWALK_VERTEX_NULL__, \
+ ENCLOSURE_ID_NULL, \
+ S2D_HIT_NULL__, \
+ S3D_HIT_NULL__, \
+ {0,0,0}, \
+ 0, \
+ SDIS_SIDE_NULL__ \
+}
+static const struct rwalk RWALK_NULL = RWALK_NULL__;
+
+struct temperature {
+ res_T (*func)/* Next function to invoke in order to compute the temperature */
+ (struct sdis_scene* scn,
+ struct rwalk_context* ctx,
+ struct rwalk* rwalk,
+ struct ssp_rng* rng,
+ struct temperature* temp);
+ double value; /* Current value of the temperature */
+ int done;
+};
+#define TEMPERATURE_NULL__ {NULL,0,0}
+static const struct temperature TEMPERATURE_NULL = TEMPERATURE_NULL__;
+
+/*******************************************************************************
* Heat path data structure used to record the geometry of sampled paths
******************************************************************************/
/* Generate the dynamic array of heat vertices */
@@ -261,34 +298,34 @@ trace_radiative_path_2d
(struct sdis_scene* scn,
const float ray_dir[3],
struct rwalk_context* ctx,
- struct rwalk_2d* rwalk,
+ struct rwalk* rwalk,
struct ssp_rng* rng,
- struct temperature_2d* temperature);
+ struct temperature* temperature);
extern LOCAL_SYM res_T
trace_radiative_path_3d
(struct sdis_scene* scn,
const float ray_dir[3],
struct rwalk_context* ctx,
- struct rwalk_3d* rwalk,
+ struct rwalk* rwalk,
struct ssp_rng* rng,
- struct temperature_3d* temperature);
+ struct temperature* temperature);
extern LOCAL_SYM res_T
radiative_path_2d
(struct sdis_scene* scn,
struct rwalk_context* ctx,
- struct rwalk_2d* rwalk,
+ struct rwalk* rwalk,
struct ssp_rng* rng,
- struct temperature_2d* temperature);
+ struct temperature* temperature);
extern LOCAL_SYM res_T
radiative_path_3d
(struct sdis_scene* scn,
struct rwalk_context* ctx,
- struct rwalk_3d* rwalk,
+ struct rwalk* rwalk,
struct ssp_rng* rng,
- struct temperature_3d* temperature);
+ struct temperature* temperature);
/*******************************************************************************
* Convective path
@@ -297,17 +334,17 @@ extern LOCAL_SYM res_T
convective_path_2d
(struct sdis_scene* scn,
struct rwalk_context* ctx,
- struct rwalk_2d* rwalk,
+ struct rwalk* rwalk,
struct ssp_rng* rng,
- struct temperature_2d* temperature);
+ struct temperature* temperature);
extern LOCAL_SYM res_T
convective_path_3d
(struct sdis_scene* scn,
struct rwalk_context* ctx,
- struct rwalk_3d* rwalk,
+ struct rwalk* rwalk,
struct ssp_rng* rng,
- struct temperature_3d* temperature);
+ struct temperature* temperature);
/*******************************************************************************
* Conductive path
@@ -316,17 +353,17 @@ extern LOCAL_SYM res_T
conductive_path_2d
(struct sdis_scene* scn,
struct rwalk_context* ctx,
- struct rwalk_2d* rwalk,
+ struct rwalk* rwalk,
struct ssp_rng* rng,
- struct temperature_2d* temperature);
+ struct temperature* temperature);
extern LOCAL_SYM res_T
conductive_path_3d
(struct sdis_scene* scn,
struct rwalk_context* ctx,
- struct rwalk_3d* rwalk,
+ struct rwalk* rwalk,
struct ssp_rng* rng,
- struct temperature_3d* temperature);
+ struct temperature* temperature);
/*******************************************************************************
* Boundary sub-path
@@ -335,16 +372,16 @@ extern LOCAL_SYM res_T
boundary_path_2d
(struct sdis_scene* scn,
struct rwalk_context* ctx,
- struct rwalk_2d* rwalk,
+ struct rwalk* rwalk,
struct ssp_rng* rng,
- struct temperature_2d* temperature);
+ struct temperature* temperature);
extern LOCAL_SYM res_T
boundary_path_3d
(struct sdis_scene* scn,
struct rwalk_context* ctx,
- struct rwalk_3d* rwalk,
+ struct rwalk* rwalk,
struct ssp_rng* rng,
- struct temperature_3d* temperature);
+ struct temperature* temperature);
#endif /* SDIS_HEAT_PATH_H */
diff --git a/src/sdis_heat_path_boundary_Xd.h b/src/sdis_heat_path_boundary_Xd.h
@@ -25,15 +25,67 @@
#include "sdis_Xd_begin.h"
/*******************************************************************************
+ * Helper functions
+ ******************************************************************************/
+/* This function checks whether the random walk is on a boundary and, if so,
+ * verifies that the temperature of the medium attached to the interface is
+ * known. This medium can be different from the medium of the enclosure. Indeed,
+ * the enclosure can contain several media used to set the temperatures of
+ * several boundary conditions. Hence this function, which queries the medium on
+ * the trajectory coming from a boundary */
+static res_T
+XD(handle_known_medium_temperature)
+ (struct sdis_scene* scn,
+ struct rwalk_context* ctx,
+ struct rwalk* rwalk,
+ struct temperature* T)
+{
+ struct sdis_interface* interf = NULL;
+ struct sdis_medium* mdm = NULL;
+ double temperature = SDIS_TEMPERATURE_NONE;
+ res_T res = RES_OK;
+ ASSERT(scn && ctx && rwalk && T);
+
+ /* Not at an interface */
+ if(SXD_HIT_NONE(&rwalk->XD(hit))) return RES_OK; /* Nothing to do */
+
+ interf = scene_get_interface(scn, rwalk->XD(hit).prim.prim_id);
+ mdm = rwalk->hit_side==SDIS_FRONT ? interf->medium_front: interf->medium_back;
+
+ temperature = medium_get_temperature(mdm, &rwalk->vtx);
+
+ /* Check if the temperature is known */
+ if(SDIS_TEMPERATURE_IS_UNKNOWN(temperature)) goto exit;
+
+ T->value += temperature;
+ T->done = 1;
+
+ if(ctx->green_path) {
+ res = green_path_set_limit_vertex
+ (ctx->green_path, mdm, &rwalk->vtx, rwalk->elapsed_time);
+ if(res != RES_OK) goto error;
+ }
+
+ if(ctx->heat_path) {
+ heat_path_get_last_vertex(ctx->heat_path)->weight = T->value;
+ }
+
+exit:
+ return res;
+error:
+ goto exit;
+}
+
+/*******************************************************************************
* Local functions
******************************************************************************/
res_T
XD(boundary_path)
(struct sdis_scene* scn,
struct rwalk_context* ctx,
- struct XD(rwalk)* rwalk,
+ struct rwalk* rwalk,
struct ssp_rng* rng,
- struct XD(temperature)* T)
+ struct temperature* T)
{
struct sdis_interface_fragment frag = SDIS_INTERFACE_FRAGMENT_NULL;
struct sdis_interface* interf = NULL;
@@ -42,15 +94,16 @@ XD(boundary_path)
double tmp;
res_T res = RES_OK;
ASSERT(scn && ctx && rwalk && rng && T);
- ASSERT(rwalk->mdm == NULL);
- ASSERT(!SXD_HIT_NONE(&rwalk->hit));
+ ASSERT(rwalk->enc_id == ENCLOSURE_ID_NULL);
+ ASSERT(!SXD_HIT_NONE(&rwalk->XD(hit)));
- XD(setup_interface_fragment)(&frag, &rwalk->vtx, &rwalk->hit, rwalk->hit_side);
+ XD(setup_interface_fragment)
+ (&frag, &rwalk->vtx, &rwalk->XD(hit), rwalk->hit_side);
- fX(normalize)(rwalk->hit.normal, rwalk->hit.normal);
+ fX(normalize)(rwalk->XD(hit).normal, rwalk->XD(hit).normal);
/* Retrieve the current interface */
- interf = scene_get_interface(scn, rwalk->hit.prim.prim_id);
+ interf = scene_get_interface(scn, rwalk->XD(hit).prim.prim_id);
/* Check if the boundary temperature is known */
tmp = interface_side_get_temperature(interf, &frag);
@@ -82,6 +135,32 @@ XD(boundary_path)
}
if(res != RES_OK) goto error;
+#if 1
+ if(T->done) goto exit;
+
+ /* Handling limit boundary condition, i.e. the trajectory originates from a
+ * boundary and the medium temperature is known (e.g. Robin's condition). To
+ * simplify data description, we allow in such a situation, to define several
+ * medium on the same enclosure, each with a fixed temperature, i.e. different
+ * conditions are defined for the different interfaces that detour the
+ * enclosure. As a result, no path can be sampled in this enclosure, which is
+ * beyond the system boundary. The boundary medium must therefore be
+ * interrogated from the interface.
+ *
+ * Note that we check this boundary condition with convective paths to handle
+ * Robin's boundary conditions. But we also make this check when passing
+ * through conduction when there's no reason why a solid should have a fixed
+ * temperature and not its boundary: it should be a Dirichlet condition.
+ * Although it's not physical, such systems can still be defined
+ * computationally, and in fact it's also a handy way of testing
+ * border cases */
+ if(T->func == XD(convective_path) || T->func == XD(conductive_path)) {
+ res = XD(handle_known_medium_temperature)(scn, ctx, rwalk, T);
+ if(res != RES_OK) goto error;
+ if(T->done) goto exit; /* That's all folks */
+ }
+#endif
+
exit:
return res;
error:
@@ -89,4 +168,3 @@ error:
}
#include "sdis_Xd_end.h"
-
diff --git a/src/sdis_heat_path_boundary_Xd_c.h b/src/sdis_heat_path_boundary_Xd_c.h
@@ -26,18 +26,18 @@
#include "sdis_Xd_begin.h"
struct XD(find_reinjection_ray_args) {
- const struct sdis_medium* solid; /* Medium into which the reinjection occurs */
- const struct XD(rwalk)* rwalk; /* Current random walk state */
+ const struct rwalk* rwalk; /* Current random walk state */
float dir0[DIM]; /* Challenged ray direction */
float dir1[DIM]; /* Challenged ray direction */
double distance; /* Maximum reinjection distance */
+ unsigned solid_enc_id; /* Enclosure id into which the reinjection occurs */
/* Define if the random walk position can be moved or not to find a valid
* reinjection direction */
int can_move;
};
static const struct XD(find_reinjection_ray_args)
-XD(FIND_REINJECTION_RAY_ARGS_NULL) = { NULL, NULL, {0}, {0}, 0, 0 };
+XD(FIND_REINJECTION_RAY_ARGS_NULL) = { NULL, {0}, {0}, 0, ENCLOSURE_ID_NULL, 0 };
struct XD(reinjection_ray) {
double org[DIM]; /* Origin of the reinjection */
@@ -55,80 +55,150 @@ XD(REINJECTION_RAY_NULL) = { {0}, {0}, 0, SXD_HIT_NULL__, 0 };
/*******************************************************************************
* Helper functions
******************************************************************************/
-static INLINE int
+static INLINE res_T
XD(check_find_reinjection_ray_args)
- (const struct XD(find_reinjection_ray_args)* args)
+ (struct sdis_scene* scn,
+ const struct XD(find_reinjection_ray_args)* args)
{
- return args
- && args->solid
- && args->rwalk
- && args->distance > 0
- && fX(is_normalized)(args->dir0)
- && fX(is_normalized)(args->dir1);
+ const struct enclosure* enc = NULL;
+ struct sdis_medium* mdm = NULL;
+ res_T res = RES_OK;
+ ASSERT(scn);
+
+ /* Check pointers */
+ if(!args || !args->rwalk) return RES_BAD_ARG;
+
+ /* Check distance */
+ if(args->distance <= 0) return RES_BAD_ARG;
+
+ /* Check directions */
+ if(!fX(is_normalized)(args->dir0) || !fX(is_normalized)(args->dir1)) {
+ return RES_BAD_ARG;
+ }
+
+ /* Check enclosure id */
+ if(args->solid_enc_id == ENCLOSURE_ID_NULL) {
+ return RES_BAD_ARG;
+ }
+ enc = scene_get_enclosure(scn, args->solid_enc_id);
+
+ /* Check the enclosure */
+ enc = scene_get_enclosure(scn, args->solid_enc_id);
+ if(enc->medium_id != MEDIUM_ID_MULTI) {
+ if((res = scene_get_enclosure_medium(scn, enc, &mdm)) != RES_OK) return res;
+ if(sdis_medium_get_type(mdm) != SDIS_SOLID) {
+ res = RES_BAD_ARG;
+ }
+ }
+
+ return RES_OK;
}
-static INLINE int
+static INLINE res_T
XD(check_sample_reinjection_step_args)
- (const struct XD(sample_reinjection_step_args)* args)
+ (struct sdis_scene* scn,
+ const struct sample_reinjection_step_args* args)
{
- return args
- && args->rng
- && args->solid
- && args->solid->type == SDIS_SOLID
- && args->rwalk
- && args->distance > 0
- && (unsigned)args->side < SDIS_SIDE_NULL__;
+ const struct enclosure* enc = NULL;
+ struct sdis_medium* mdm = NULL;
+ res_T res = RES_OK;
+ ASSERT(scn);
+
+ /* Check pointers */
+ if(!args || !args->rng || !args->rwalk) return RES_BAD_ARG;
+
+ /* Check distance */
+ if(args->distance <= 0) return RES_BAD_ARG;
+
+ /* Check side */
+ if((unsigned)args->side >= SDIS_SIDE_NULL__) return RES_BAD_ARG;
+
+ /* Check enclosure id */
+ if(args->solid_enc_id == ENCLOSURE_ID_NULL) {
+ return RES_BAD_ARG;
+ }
+
+ /* Check the enclosure */
+ enc = scene_get_enclosure(scn, args->solid_enc_id);
+ if(enc->medium_id != MEDIUM_ID_MULTI) {
+ if((res = scene_get_enclosure_medium(scn, enc, &mdm)) != RES_OK) return res;
+ if(sdis_medium_get_type(mdm) != SDIS_SOLID) {
+ return RES_BAD_ARG;
+ }
+ }
+
+ return RES_OK;
}
-static INLINE int
-XD(check_reinjection_step)(const struct XD(reinjection_step)* step)
+static INLINE res_T
+XD(check_reinjection_step)(const struct reinjection_step* step)
{
- return step
- && fX(is_normalized)(step->direction)
- && step->distance > 0;
+ /* Check pointer */
+ if(!step) return RES_BAD_ARG;
+
+ /* Check direction */
+ if(!fX(is_normalized)(step->direction)) return RES_BAD_ARG;
+
+ /* Check distance */
+ if(step->distance <= 0) return RES_BAD_ARG;
+
+ return RES_OK;
}
-static INLINE int
-XD(check_solid_reinjection_args)(const struct XD(solid_reinjection_args)* args)
+static INLINE res_T
+XD(check_solid_reinjection_args)(const struct solid_reinjection_args* args)
{
- return args
- && XD(check_reinjection_step)(args->reinjection)
- && args->rng
- && args->rwalk
- && args->rwalk_ctx
- && args->T
- && args->fp_to_meter > 0;
+ /* Check pointers */
+ if(!args || !args->rng || !args->rwalk || !args->rwalk_ctx || !args->T)
+ return RES_BAD_ARG;
+
+ /* Check unit */
+ if(args->fp_to_meter <= 0) return RES_BAD_ARG;
+
+ return XD(check_reinjection_step)(args->reinjection);
}
/* Check that the interface fragment is consistent with the current state of
* the random walk */
-static INLINE int
+static INLINE res_T
XD(check_rwalk_fragment_consistency)
- (const struct XD(rwalk)* rwalk,
+ (const struct rwalk* rwalk,
const struct sdis_interface_fragment* frag)
{
double N[DIM];
double uv[2] = {0, 0};
ASSERT(rwalk && frag);
- dX(normalize)(N, dX_set_fX(N, rwalk->hit.normal));
- if( SXD_HIT_NONE(&rwalk->hit)
- || !dX(eq_eps)(rwalk->vtx.P, frag->P, 1.e-6)
- || !dX(eq_eps)(N, frag->Ng, 1.e-6)
- || !( (IS_INF(rwalk->vtx.time) && IS_INF(frag->time))
- || eq_eps(rwalk->vtx.time, frag->time, 1.e-6))) {
- return 0;
+
+ /* Check intersection */
+ if(SXD_HIT_NONE(&rwalk->XD(hit))) return RES_BAD_ARG;
+
+ /* Check positions */
+ if(!dX(eq_eps)(rwalk->vtx.P, frag->P, 1.e-6)) return RES_BAD_ARG;
+
+ /* Check normals */
+ dX(normalize)(N, dX_set_fX(N, rwalk->XD(hit).normal));
+ if(!dX(eq_eps)(N, frag->Ng, 1.e-6)) return RES_BAD_ARG;
+
+ /* Check time */
+ if(!eq_eps(rwalk->vtx.time, frag->time, 1.e-6)
+ && !(IS_INF(rwalk->vtx.time) && IS_INF(frag->time))) {
+ return RES_BAD_ARG;
}
+
+ /* Check parametric coordinates */
#if (SDIS_XD_DIMENSION == 2)
- uv[0] = rwalk->hit.u;
+ uv[0] = rwalk->XD(hit).u;
#else
- d2_set_f2(uv, rwalk->hit.uv);
+ d2_set_f2(uv, rwalk->XD(hit).uv);
#endif
- return d2_eq_eps(uv, frag->uv, 1.e-6);
+ if(!d2_eq_eps(uv, frag->uv, 1.e-6)) return RES_BAD_ARG;
+
+ return RES_OK;
}
static void
XD(sample_reinjection_dir)
- (const struct XD(rwalk)* rwalk,
+ (const struct rwalk* rwalk,
struct ssp_rng* rng,
float dir[DIM])
{
@@ -145,15 +215,15 @@ XD(sample_reinjection_dir)
* discard the sqrt(2)/2 constant. */
const uint64_t r = ssp_rng_uniform_uint64(rng, 0, 1);
ASSERT(rwalk && rng && dir);
- ASSERT(!SXD_HIT_NONE(&rwalk->hit));
- ASSERT(!rwalk->mdm);
+ ASSERT(!SXD_HIT_NONE(&rwalk->XD(hit)));
+ ASSERT(rwalk->enc_id == ENCLOSURE_ID_NULL);
if(r) {
- dir[0] = rwalk->hit.normal[0] - rwalk->hit.normal[1];
- dir[1] = rwalk->hit.normal[0] + rwalk->hit.normal[1];
+ dir[0] = rwalk->XD(hit).normal[0] - rwalk->XD(hit).normal[1];
+ dir[1] = rwalk->XD(hit).normal[0] + rwalk->XD(hit).normal[1];
} else {
- dir[0] = rwalk->hit.normal[0] + rwalk->hit.normal[1];
- dir[1] =-rwalk->hit.normal[0] + rwalk->hit.normal[1];
+ dir[0] = rwalk->XD(hit).normal[0] + rwalk->XD(hit).normal[1];
+ dir[1] =-rwalk->XD(hit).normal[0] + rwalk->XD(hit).normal[1];
}
f2_normalize(dir, dir);
#else
@@ -162,17 +232,17 @@ XD(sample_reinjection_dir)
* radius of its base is 1. */
float frame[9];
ASSERT(rwalk && rng && dir);
- ASSERT(!SXD_HIT_NONE(&rwalk->hit));
- ASSERT(!rwalk->mdm);
- ASSERT(fX(is_normalized)(rwalk->hit.normal));
+ ASSERT(!SXD_HIT_NONE(&rwalk->XD(hit)));
+ ASSERT(rwalk->enc_id == ENCLOSURE_ID_NULL);
+ ASSERT(fX(is_normalized)(rwalk->XD(hit).normal));
ssp_ran_circle_uniform_float(rng, dir, NULL);
dir[2] = (float)(1.0/sqrt(2));
- f33_basis(frame, rwalk->hit.normal);
+ f33_basis(frame, rwalk->XD(hit).normal);
f33_mulf3(dir, frame, dir);
f3_normalize(dir, dir);
- ASSERT(eq_epsf(f3_dot(dir, rwalk->hit.normal), (float)(1.0/sqrt(3)), 1.e-4f));
+ ASSERT(eq_epsf(f3_dot(dir, rwalk->XD(hit).normal), (float)(1.0/sqrt(3)), 1.e-4f));
#endif
}
@@ -180,7 +250,7 @@ XD(sample_reinjection_dir)
#if DIM == 2
static void
XD(move_away_primitive_boundaries)
- (const struct XD(rwalk)* rwalk,
+ (const struct rwalk* rwalk,
const double delta,
double position[DIM]) /* Position to move */
{
@@ -189,9 +259,9 @@ XD(move_away_primitive_boundaries)
float dir[DIM];
float len;
const float st = 0.5f;
- ASSERT(rwalk && !SXD_HIT_NONE(&rwalk->hit) && delta > 0);
+ ASSERT(rwalk && !SXD_HIT_NONE(&rwalk->XD(hit)) && delta > 0);
- SXD(primitive_get_attrib(&rwalk->hit.prim, SXD_POSITION, st, &attr));
+ SXD(primitive_get_attrib(&rwalk->XD(hit).prim, SXD_POSITION, st, &attr));
fX_set_dX(pos, position);
fX(sub)(dir, attr.value, pos);
@@ -205,7 +275,7 @@ XD(move_away_primitive_boundaries)
* numerical issues leading to inconsistent random walks. */
static void
XD(move_away_primitive_boundaries)
- (const struct XD(rwalk)* rwalk,
+ (const struct rwalk* rwalk,
const double delta,
double position[DIM])
{
@@ -222,14 +292,14 @@ XD(move_away_primitive_boundaries)
int imin = 0;
int imid = 0;
int i;
- ASSERT(rwalk && delta > 0 && !S3D_HIT_NONE(&rwalk->hit));
+ ASSERT(rwalk && delta > 0 && !S3D_HIT_NONE(&rwalk->XD(hit)));
fX_set_dX(P, position);
/* Fetch triangle vertices */
- S3D(triangle_get_vertex_attrib(&rwalk->hit.prim, 0, S3D_POSITION, &v0));
- S3D(triangle_get_vertex_attrib(&rwalk->hit.prim, 1, S3D_POSITION, &v1));
- S3D(triangle_get_vertex_attrib(&rwalk->hit.prim, 2, S3D_POSITION, &v2));
+ S3D(triangle_get_vertex_attrib(&rwalk->XD(hit).prim, 0, S3D_POSITION, &v0));
+ S3D(triangle_get_vertex_attrib(&rwalk->XD(hit).prim, 1, S3D_POSITION, &v1));
+ S3D(triangle_get_vertex_attrib(&rwalk->XD(hit).prim, 2, S3D_POSITION, &v2));
/* Compute the edge vector */
f3_sub(E[0], v1.value, v0.value);
@@ -315,10 +385,10 @@ XD(find_reinjection_ray)
/* # attempts to find a ray direction */
int MAX_ATTEMPTS = 1;
- /* Physical properties */
- struct sdis_interface* interf;
- struct sdis_medium* mdm0;
- struct sdis_medium* mdm1;
+ /* Enclosures */
+ unsigned enc_ids[2] = {ENCLOSURE_ID_NULL, ENCLOSURE_ID_NULL};
+ unsigned enc0_id = ENCLOSURE_ID_NULL;
+ unsigned enc1_id = ENCLOSURE_ID_NULL;
struct hit_filter_data filter_data = HIT_FILTER_DATA_NULL;
struct sXd(hit) hit;
@@ -338,7 +408,7 @@ XD(find_reinjection_ray)
res_T res = RES_OK;
ASSERT(scn && args && ray);
- ASSERT(XD(check_find_reinjection_ray_args)(args));
+ ASSERT(XD(check_find_reinjection_ray_args)(scn, args) == RES_OK);
*ray = XD(REINJECTION_RAY_NULL);
MAX_ATTEMPTS = args->can_move ? 2 : 1;
@@ -350,39 +420,39 @@ XD(find_reinjection_ray)
do {
fX_set_dX(org, ray->org);
- filter_data.XD(hit) = args->rwalk->hit;
+ filter_data.XD(hit) = args->rwalk->XD(hit);
filter_data.epsilon = args->distance * 0.01;
SXD(scene_view_trace_ray
(scn->sXd(view), org, args->dir0, range, &filter_data, &hit0));
SXD(scene_view_trace_ray
(scn->sXd(view), org, args->dir1, range, &filter_data, &hit1));
- /* Retrieve the medium at the reinjection pos along dir0 */
- if(SXD_HIT_NONE(&hit0)) {
+ /* Retrieve the enclosure at the reinjection pos along dir0 */
+ if(!SXD_HIT_NONE(&hit0)) {
+ scene_get_enclosure_ids(scn, hit0.prim.prim_id, enc_ids);
+ side = fX(dot)(args->dir0, hit0.normal) < 0 ? SDIS_FRONT : SDIS_BACK;
+ enc0_id = enc_ids[side];
+ } else {
XD(move_pos)(dX(set)(tmp, ray->org), args->dir0, (float)args->distance);
- res = scene_get_medium_in_closed_boundaries(scn, tmp, &mdm0);
- if(res == RES_BAD_OP) { mdm0 = NULL; res = RES_OK; }
+ res = scene_get_enclosure_id_in_closed_boundaries(scn, tmp, &enc0_id);
+ if(res == RES_BAD_OP) { enc0_id = ENCLOSURE_ID_NULL; res = RES_OK; }
if(res != RES_OK) goto error;
- } else {
- interf = scene_get_interface(scn, hit0.prim.prim_id);
- side = fX(dot)(args->dir0, hit0.normal) < 0 ? SDIS_FRONT : SDIS_BACK;
- mdm0 = interface_get_medium(interf, side);
}
- /* Retrieve the medium at the reinjection pos along dir1 */
- if(SXD_HIT_NONE(&hit1)) {
+ /* Retrieve the enclosure at the reinjection pos along dir1 */
+ if(!SXD_HIT_NONE(&hit1)) {
+ scene_get_enclosure_ids(scn, hit1.prim.prim_id, enc_ids);
+ side = fX(dot)(args->dir1, hit1.normal) < 0 ? SDIS_FRONT : SDIS_BACK;
+ enc1_id = enc_ids[side];
+ } else {
XD(move_pos)(dX(set)(tmp, ray->org), args->dir1, (float)args->distance);
- res = scene_get_medium_in_closed_boundaries(scn, tmp, &mdm1);
- if(res == RES_BAD_OP) { mdm1 = NULL; res = RES_OK; }
+ res = scene_get_enclosure_id_in_closed_boundaries(scn, tmp, &enc1_id);
+ if(res == RES_BAD_OP) { enc1_id = ENCLOSURE_ID_NULL; res = RES_OK; }
if(res != RES_OK) goto error;
- } else {
- interf = scene_get_interface(scn, hit1.prim.prim_id);
- side = fX(dot)(args->dir1, hit1.normal) < 0 ? SDIS_FRONT : SDIS_BACK;
- mdm1 = interface_get_medium(interf, side);
}
dst0 = dst1 = -1;
- if(mdm0 == args->solid) { /* Check reinjection consistency */
+ if(enc0_id == args->solid_enc_id) { /* Check reinjection consistency */
if(hit0.distance <= dst_adjusted) {
dst0 = hit0.distance;
} else {
@@ -390,7 +460,7 @@ XD(find_reinjection_ray)
hit0 = SXD_HIT_NULL;
}
}
- if(mdm1 == args->solid) { /* Check reinjection consistency */
+ if(enc1_id == args->solid_enc_id) { /* Check reinjection consistency */
if(hit1.distance <= dst_adjusted) {
dst1 = hit1.distance;
} else {
@@ -503,23 +573,25 @@ XD(find_reinjection_ray_and_check_validity)
struct XD(reinjection_ray)* ray)
{
double pos[DIM];
- struct sdis_medium* reinject_mdm;
res_T res = RES_OK;
ASSERT(scn && args && ray);
- ASSERT(XD(check_find_reinjection_ray_args)(args));
+ ASSERT(XD(check_find_reinjection_ray_args)(scn, args) == RES_OK);
/* Select a reinjection direction */
res = XD(find_reinjection_ray)(scn, args, ray);
if(res != RES_OK) goto error;
if(SXD_HIT_NONE(&ray->hit)) {
- /* Check medium consistency at the reinjection position */
+ unsigned enc_id = ENCLOSURE_ID_NULL;
+
+ /* Obtain the enclosure in which the reinjection position lies */
XD(move_pos)(dX(set)(pos, ray->org), ray->dir, (float)ray->dst);
- res = scene_get_medium_in_closed_boundaries(scn, pos, &reinject_mdm);
+ res = scene_get_enclosure_id_in_closed_boundaries(scn, pos, &enc_id);
if(res != RES_OK) goto error;
- if(reinject_mdm != args->solid) {
+ /* Check enclosure consistency at the reinjection position */
+ if(enc_id != args->solid_enc_id) {
res = RES_BAD_OP;
goto error;
}
@@ -535,9 +607,9 @@ static res_T
XD(handle_volumic_power)
(struct sdis_medium* solid,
struct rwalk_context* rwalk_ctx,
- struct XD(rwalk)* rwalk,
+ struct rwalk* rwalk,
const double reinject_dst_m,
- struct XD(temperature)* T)
+ struct temperature* T)
{
double power;
double lambda;
@@ -592,22 +664,22 @@ error:
res_T
XD(sample_reinjection_step_solid_fluid)
(struct sdis_scene* scn,
- const struct XD(sample_reinjection_step_args)* args,
- struct XD(reinjection_step)* step)
+ const struct sample_reinjection_step_args* args,
+ struct reinjection_step* step)
{
/* Input/output data of the function finding a valid reinjection ray */
struct XD(find_reinjection_ray_args) find_reinject_ray_args =
XD(FIND_REINJECTION_RAY_ARGS_NULL);
struct XD(reinjection_ray) ray = XD(REINJECTION_RAY_NULL);
+ /* Enclosures */
+ const struct enclosure* solid_enc = NULL;
+ unsigned enc_ids[2] = {ENCLOSURE_ID_NULL, ENCLOSURE_ID_NULL};
+
/* In 2D it is useless to try to resample a reinjection direction since there
* is only one possible direction */
const int MAX_ATTEMPTS = DIM == 2 ? 1 : 10;
- /* Enclosure */
- const struct enclosure* solid_enclosure = NULL;
- unsigned enc_ids[2];
-
/* Miscellaneous variables */
float dir0[DIM]; /* Sampled direction */
float dir1[DIM]; /* Sampled direction reflected */
@@ -616,23 +688,23 @@ XD(sample_reinjection_step_solid_fluid)
/* Pre-conditions */
ASSERT(scn && args && step);
- ASSERT(XD(check_sample_reinjection_step_args)(args));
+ ASSERT(XD(check_sample_reinjection_step_args)(scn, args) == RES_OK);
/* Initialise the reinjection step */
- *step = XD(REINJECTION_STEP_NULL);
+ *step = REINJECTION_STEP_NULL;
/* Check whether the solid enclosure is part of the system, or whether it is
* only there to describe boundary conditions. In the latter case, the
* enclosure has no geometrical existence and it is sufficient to return a
* valid reinjection step which will be used to select the next step. Note
* that if the trajectory passes through the solid enclosure, it will stop,
- * i.e. the temperature of the solid should be fixed. If it doesn't, it's an
+ * i.e. the temperature of the solid should be fixed. If it doesn't, it's a
* error */
- scene_get_enclosure_ids(scn, args->rwalk->hit.prim.prim_id, enc_ids);
- solid_enclosure = scene_get_enclosure(scn, enc_ids[args->side]);
- if(solid_enclosure->medium_id == ENCLOSURE_MULTI_MEDIA) {
- step->hit = SXD_HIT_NULL;
- fX(normalize)(step->direction, args->rwalk->hit.normal);
+ scene_get_enclosure_ids(scn, args->rwalk->XD(hit).prim.prim_id, enc_ids);
+ solid_enc = scene_get_enclosure(scn, enc_ids[args->side]);
+ if(solid_enc->medium_id == MEDIUM_ID_MULTI) {
+ step->XD(hit) = SXD_HIT_NULL;
+ fX(normalize)(step->direction, args->rwalk->XD(hit).normal);
if(args->side == SDIS_BACK) fX(minus)(step->direction, step->direction);
step->distance = (float)args->distance;
goto exit; /* That's all folks! */
@@ -644,7 +716,7 @@ XD(sample_reinjection_step_solid_fluid)
XD(sample_reinjection_dir)(args->rwalk, args->rng, dir0);
/* Reflect the sampled direction around the normal */
- XD(reflect)(dir1, dir0, args->rwalk->hit.normal);
+ XD(reflect)(dir1, dir0, args->rwalk->XD(hit).normal);
/* Flip the sampled directions if one wants to reinject to back side */
if(args->side == SDIS_BACK) {
@@ -653,7 +725,7 @@ XD(sample_reinjection_step_solid_fluid)
}
/* Find the reinjection step */
- find_reinject_ray_args.solid = args->solid;
+ find_reinject_ray_args.solid_enc_id = args->solid_enc_id;
find_reinject_ray_args.rwalk = args->rwalk;
find_reinject_ray_args.distance = args->distance;
find_reinject_ray_args.can_move = 1;
@@ -676,7 +748,7 @@ XD(sample_reinjection_step_solid_fluid)
}
/* Setup the reinjection step */
- step->hit = ray.hit;
+ step->XD(hit) = ray.hit;
step->distance = ray.dst;
fX(set)(step->direction, ray.dir);
@@ -687,7 +759,7 @@ XD(sample_reinjection_step_solid_fluid)
/* Post-conditions */
ASSERT(dX(eq)(args->rwalk->vtx.P, ray.org));
- ASSERT(XD(check_reinjection_step)(step));
+ ASSERT(XD(check_reinjection_step)(step) == RES_OK);
exit:
return res;
@@ -698,10 +770,10 @@ error:
res_T
XD(sample_reinjection_step_solid_solid)
(struct sdis_scene* scn,
- const struct XD(sample_reinjection_step_args)* args_frt,
- const struct XD(sample_reinjection_step_args)* args_bck,
- struct XD(reinjection_step)* step_frt,
- struct XD(reinjection_step)* step_bck)
+ const struct sample_reinjection_step_args* args_frt,
+ const struct sample_reinjection_step_args* args_bck,
+ struct reinjection_step* step_frt,
+ struct reinjection_step* step_bck)
{
/* Input/output data of the function finding a valid reinjection ray */
struct XD(find_reinjection_ray_args) find_reinject_ray_frt_args =
@@ -715,7 +787,7 @@ XD(sample_reinjection_step_solid_solid)
double rwalk_pos_backup[DIM];
/* Variables shared by the two side */
- struct XD(rwalk)* rwalk = NULL;
+ struct rwalk* rwalk = NULL;
struct ssp_rng* rng = NULL;
/* In 2D it is useless to try to resample a reinjection direction since there
@@ -723,26 +795,26 @@ XD(sample_reinjection_step_solid_solid)
const int MAX_ATTEMPTS = DIM == 2 ? 1 : 10;
/* Enclosure */
- const struct enclosure* enclosure_bck = NULL;
- const struct enclosure* enclosure_frt = NULL;
- int multiple_media_bck = 0;
- int multiple_media_frt = 0;
unsigned enc_ids[2];
+ const struct enclosure* enc_frt = NULL;
+ const struct enclosure* enc_bck = NULL;
float dir_frt_samp[DIM]; /* Sampled direction */
float dir_frt_refl[DIM]; /* Sampled direction reflected */
float dir_bck_samp[DIM]; /* Negated sampled direction */
float dir_bck_refl[DIM]; /* Negated sampled direction reflected */
+ int multi_frt = 0;
+ int multi_bck = 0;
int iattempt = 0; /* #attempts to find a reinjection dir */
res_T res = RES_OK;
/* Pre-conditions */
ASSERT(scn && args_frt && args_bck && step_frt && step_bck);
- ASSERT(XD(check_sample_reinjection_step_args)(args_frt));
- ASSERT(XD(check_sample_reinjection_step_args)(args_bck));
+ ASSERT(XD(check_sample_reinjection_step_args)(scn, args_frt) == RES_OK);
+ ASSERT(XD(check_sample_reinjection_step_args)(scn, args_bck) == RES_OK);
ASSERT(args_frt->side == SDIS_FRONT);
ASSERT(args_bck->side == SDIS_BACK);
- ASSERT(SXD_PRIMITIVE_EQ(&args_frt->rwalk->hit.prim, &args_bck->rwalk->hit.prim));
+ ASSERT(SXD_PRIMITIVE_EQ(&args_frt->rwalk->XD(hit).prim, &args_bck->rwalk->XD(hit).prim));
rng = args_frt->rng;
rwalk = args_frt->rwalk;
@@ -750,8 +822,8 @@ XD(sample_reinjection_step_solid_solid)
ASSERT(args_bck->rwalk == rwalk);
/* Initialise the reinjection steps */
- *step_frt = XD(REINJECTION_STEP_NULL);
- *step_bck = XD(REINJECTION_STEP_NULL);
+ *step_frt = REINJECTION_STEP_NULL;
+ *step_bck = REINJECTION_STEP_NULL;
/* Check whether the solid enclosure is part of the system, or whether it is
* only there to describe boundary conditions. In the latter case, the
@@ -760,25 +832,23 @@ XD(sample_reinjection_step_solid_solid)
* that if the trajectory passes through the solid enclosure, it will stop,
* i.e. the temperature of the solid should be fixed. If it doesn't, it's an
* error */
- scene_get_enclosure_ids(scn, args_frt->rwalk->hit.prim.prim_id, enc_ids);
- enclosure_frt = scene_get_enclosure(scn, enc_ids[SDIS_FRONT]);
- enclosure_bck = scene_get_enclosure(scn, enc_ids[SDIS_BACK]);
- if(enclosure_frt->medium_id == ENCLOSURE_MULTI_MEDIA) {
- step_frt->hit = SXD_HIT_NULL;
- fX(normalize)(step_frt->direction, args_frt->rwalk->hit.normal);
+ scene_get_enclosure_ids(scn, args_frt->rwalk->XD(hit).prim.prim_id, enc_ids);
+ enc_frt = scene_get_enclosure(scn, enc_ids[SDIS_FRONT]);
+ enc_bck = scene_get_enclosure(scn, enc_ids[SDIS_BACK]);
+ if(enc_frt->medium_id == MEDIUM_ID_MULTI) {
+ step_frt->XD(hit) = SXD_HIT_NULL;
+ fX(normalize)(step_frt->direction, args_frt->rwalk->XD(hit).normal);
step_frt->distance = (float)args_frt->distance;
- multiple_media_frt = 1;
+ multi_frt = 1;
}
- if(enclosure_bck->medium_id == ENCLOSURE_MULTI_MEDIA) {
- step_bck->hit = SXD_HIT_NULL;
- fX(normalize)(step_bck->direction, args_bck->rwalk->hit.normal);
- fX(minus)(step_bck->direction, step_bck->direction);
+ if(enc_bck->medium_id == MEDIUM_ID_MULTI) {
+ step_bck->XD(hit) = SXD_HIT_NULL;
+ fX(normalize)(step_bck->direction, args_bck->rwalk->XD(hit).normal);
step_bck->distance = (float)args_bck->distance;
- multiple_media_bck = 1;
+ multi_bck = 1;
}
- if(multiple_media_frt && multiple_media_bck)
- goto exit; /* That's all folks! */
+ if(multi_frt && multi_bck) goto exit; /* That's all folks */
dX(set)(rwalk_pos_backup, rwalk->vtx.P);
iattempt = 0;
@@ -789,16 +859,15 @@ XD(sample_reinjection_step_solid_solid)
/* Sample a reinjection direction and reflect it around the normal. Then
* reflect them on the back side of the interface. */
XD(sample_reinjection_dir)(rwalk, rng, dir_frt_samp);
- XD(reflect)(dir_frt_refl, dir_frt_samp, rwalk->hit.normal);
+ XD(reflect)(dir_frt_refl, dir_frt_samp, rwalk->XD(hit).normal);
fX(minus)(dir_bck_samp, dir_frt_samp);
fX(minus)(dir_bck_refl, dir_frt_refl);
/* Reject the sampling of the re-injection step if it has already been
* defined, i.e. if the enclosure is a limit condition */
- if(!multiple_media_frt) {
-
+ if(!multi_frt) {
/* Find the reinjection ray for the front side */
- find_reinject_ray_frt_args.solid = args_frt->solid;
+ find_reinject_ray_frt_args.solid_enc_id = args_frt->solid_enc_id;
find_reinject_ray_frt_args.rwalk = args_frt->rwalk;
find_reinject_ray_frt_args.distance = args_frt->distance;
find_reinject_ray_frt_args.can_move = 1;
@@ -815,10 +884,9 @@ XD(sample_reinjection_step_solid_solid)
/* Reject the sampling of the re-injection step if it has already been
* defined, i.e. if the enclosure is a limit condition */
- if(!multiple_media_bck) {
-
+ if(!multi_bck) {
/* Select the reinjection direction and distance for the back side */
- find_reinject_ray_bck_args.solid = args_bck->solid;
+ find_reinject_ray_bck_args.solid_enc_id = args_bck->solid_enc_id;
find_reinject_ray_bck_args.rwalk = args_bck->rwalk;
find_reinject_ray_bck_args.distance = args_bck->distance;
find_reinject_ray_bck_args.can_move = 1;
@@ -834,7 +902,7 @@ XD(sample_reinjection_step_solid_solid)
/* If random walk was moved to find a valid rinjection ray on back side,
* one has to find a valid reinjection on front side from the new pos */
- if(ray_bck.position_was_moved && !multiple_media_frt) {
+ if(ray_bck.position_was_moved) {
find_reinject_ray_frt_args.can_move = 0;
res = XD(find_reinjection_ray_and_check_validity)
(scn, &find_reinject_ray_frt_args, &ray_frt);
@@ -858,17 +926,17 @@ XD(sample_reinjection_step_solid_solid)
}
/* Setup the front and back reinjection steps */
- if(!multiple_media_frt) {
- step_frt->hit = ray_frt.hit;
+ if(!multi_frt) {
+ step_frt->XD(hit) = ray_frt.hit;
step_frt->distance = ray_frt.dst;
fX(set)(step_frt->direction, ray_frt.dir);
- ASSERT(XD(check_reinjection_step)(step_frt)); /* Post-condition */
+ ASSERT(XD(check_reinjection_step)(step_frt) == RES_OK); /* Post-condition */
}
- if(!multiple_media_bck) {
- step_bck->hit = ray_bck.hit;
+ if(!multi_bck) {
+ step_bck->XD(hit) = ray_bck.hit;
step_bck->distance = ray_bck.dst;
fX(set)(step_bck->direction, ray_bck.dir);
- ASSERT(XD(check_reinjection_step)(step_bck)); /* Post-condition */
+ ASSERT(XD(check_reinjection_step)(step_bck) == RES_OK); /* Post-condition */
}
exit:
@@ -879,17 +947,28 @@ error:
res_T
XD(solid_reinjection)
- (struct sdis_medium* solid,
- struct XD(solid_reinjection_args)* args)
+ (struct sdis_scene* scn,
+ const unsigned solid_enc_id,
+ struct solid_reinjection_args* args)
{
+ /* Properties */
struct solid_props props = SOLID_PROPS_NULL;
+ struct sdis_medium* solid = NULL;
+ const struct enclosure* enc = NULL;
+
double reinject_dst_m; /* Reinjection distance in meters */
double mu;
res_T res = RES_OK;
- ASSERT(solid && XD(check_solid_reinjection_args)(args));
+ ASSERT(XD(check_solid_reinjection_args)(args) == RES_OK);
+ ASSERT(solid_enc_id != ENCLOSURE_ID_NULL);
reinject_dst_m = args->reinjection->distance * args->fp_to_meter;
+ /* Get the enclosure medium properties */
+ enc = scene_get_enclosure(scn, solid_enc_id);
+ res = scene_get_enclosure_medium(scn, enc, &solid);
+ if(res != RES_OK) goto error;
+ ASSERT(sdis_medium_get_type(solid) == SDIS_SOLID);
res = solid_get_properties(solid, &args->rwalk->vtx, &props);
if(res != RES_OK) goto error;
@@ -899,10 +978,10 @@ XD(solid_reinjection)
if(res != RES_OK) goto error;
/* Time rewind */
- args->rwalk->mdm = solid; /* Medium into which the time is rewind */
+ args->rwalk->enc_id = solid_enc_id; /* Enclosure into which the time is rewind */
mu = (2*DIM*props.lambda)/(props.rho*props.cp*reinject_dst_m*reinject_dst_m);
- res = XD(time_rewind)
- (mu, props.t0, args->rng, args->rwalk, args->rwalk_ctx, args->T);
+ res = time_rewind
+ (scn, mu, props.t0, args->rng, args->rwalk, args->rwalk_ctx, args->T);
if(res != RES_OK) goto error;
/* Test if a limit condition was reached */
@@ -915,18 +994,18 @@ XD(solid_reinjection)
args->reinjection->distance);
/* The random walk is in the solid */
- if(args->reinjection->hit.distance != args->reinjection->distance) {
+ if(args->reinjection->XD(hit).distance != args->reinjection->distance) {
args->T->func = XD(conductive_path);
- args->rwalk->mdm = solid;
- args->rwalk->hit = SXD_HIT_NULL;
+ args->rwalk->enc_id = solid_enc_id;
+ args->rwalk->XD(hit) = SXD_HIT_NULL;
args->rwalk->hit_side = SDIS_SIDE_NULL__;
/* The random walk is at a boundary */
} else {
args->T->func = XD(boundary_path);
- args->rwalk->mdm = NULL;
- args->rwalk->hit = args->reinjection->hit;
- if(fX(dot)(args->reinjection->hit.normal, args->reinjection->direction) < 0) {
+ args->rwalk->enc_id = ENCLOSURE_ID_NULL;
+ args->rwalk->XD(hit) = args->reinjection->XD(hit);
+ if(fX(dot)(args->reinjection->XD(hit).normal, args->reinjection->direction) < 0) {
args->rwalk->hit_side = SDIS_FRONT;
} else {
args->rwalk->hit_side = SDIS_BACK;
@@ -952,7 +1031,7 @@ res_T
XD(handle_net_flux)
(const struct sdis_scene* scn,
const struct handle_net_flux_args* args,
- struct XD(temperature)* T)
+ struct temperature* T)
{
double flux_term;
double phi;
@@ -1013,7 +1092,7 @@ XD(check_Tref)
if((Bound) < 0) { \
log_err(scn->dev, \
"%s: the "Name" temperature cannot be negative " \
- "to sample a radiative path (T"Name" = %g K).\n", \
+ "to sample a radiative path -- T"Name" = %g K\n", \
func_name, (Bound)); \
return RES_BAD_OP_IRRECOVERABLE; \
} \
@@ -1032,7 +1111,7 @@ XD(check_Tref)
if(SDIS_TEMPERATURE_IS_UNKNOWN(Tref)) {
log_err(scn->dev,
- "%s: the reference temperature is unknown at `"FORMAT_VECX". "
+ "%s: the reference temperature is unknown at ("FORMAT_VECX"). "
"Sampling a radiative path requires a valid reference temperature field.\n",
func_name, SPLITX(pos));
return RES_BAD_OP_IRRECOVERABLE;
@@ -1040,7 +1119,7 @@ XD(check_Tref)
if(Tref < 0) {
log_err(scn->dev,
- "%s: the reference temperature is negative at `"FORMAT_VECX" (Tref = %g K). "
+ "%s: the reference temperature is negative at ("FORMAT_VECX") and Tref = %g K. "
"Sampling a radiative path requires a known, positive reference "
"temperature field.\n",
func_name, SPLITX(pos), Tref);
@@ -1049,7 +1128,7 @@ XD(check_Tref)
if(Tref < scn->tmin || scn->tmax < Tref) {
log_err(scn->dev,
- "%s: invalid reference temperature at `"FORMAT_VECX"' (Tref = %g K). "
+ "%s: invalid reference temperature at ("FORMAT_VECX") and Tref=%g K. "
"It must be included in the provided temperature range "
"(Tmin = %g K; Tmax = %g K)\n",
func_name, SPLITX(pos), Tref, scn->tmin, scn->tmax);
diff --git a/src/sdis_heat_path_boundary_Xd_handle_external_net_flux.h b/src/sdis_heat_path_boundary_Xd_handle_external_net_flux.h
@@ -173,7 +173,7 @@ static INLINE res_T
XD(check_handle_external_net_flux_args)
(const struct sdis_scene* scn,
const char* func_name,
- const struct XD(handle_external_net_flux_args)* args)
+ const struct handle_external_net_flux_args* args)
{
int net_flux = 0;
res_T res = RES_OK;
@@ -181,7 +181,7 @@ XD(check_handle_external_net_flux_args)
/* Handle bugs */
ASSERT(scn && func_name && args);
ASSERT(args->interf && args->frag);
- ASSERT(!SXD_HIT_NONE(args->hit));
+ ASSERT(!SXD_HIT_NONE(args->XD(hit)));
ASSERT(args->h_cond >= 0 && args->h_conv >= 0 && args->h_radi >= 0);
ASSERT(args->h_cond + args->h_conv + args->h_radi > 0);
@@ -453,8 +453,8 @@ res_T
XD(handle_external_net_flux)
(const struct sdis_scene* scn,
struct ssp_rng* rng,
- const struct XD(handle_external_net_flux_args)* args,
- struct XD(temperature)* T)
+ const struct handle_external_net_flux_args* args,
+ struct temperature* T)
{
/* Terms to be registered in the green function */
struct sdis_green_external_flux_terms green =
@@ -516,13 +516,13 @@ XD(handle_external_net_flux)
* interface side */
cos_theta = d3_dot(N, src_sample.dir);
if(cos_theta > 0) {
- Ld = XD(direct_contribution)(scn, &src_sample, frag.P, args->hit);
+ Ld = XD(direct_contribution)(scn, &src_sample, frag.P, args->XD(hit));
incident_flux_direct = cos_theta * Ld / src_sample.pdf; /* [W/m^2] */
}
/* Calculate the incident diffuse flux [W/m^2] */
res = XD(compute_incident_diffuse_flux)
- (scn, rng, frag.P, N, frag.time, args->hit, &incident_flux_diffuse);
+ (scn, rng, frag.P, N, frag.time, args->XD(hit), &incident_flux_diffuse);
if(res != RES_OK) goto error;
/* Calculate the incident flux without the part scattered by the environment.
diff --git a/src/sdis_heat_path_boundary_Xd_solid_fluid_picard1.h b/src/sdis_heat_path_boundary_Xd_solid_fluid_picard1.h
@@ -31,8 +31,8 @@
static INLINE res_T
XD(rwalk_get_Tref)
(const struct sdis_scene* scn,
- const struct XD(rwalk)* rwalk,
- const struct XD(temperature)* T,
+ const struct rwalk* rwalk,
+ const struct temperature* T,
double* out_Tref)
{
double Tref = SDIS_TEMPERATURE_NONE;
@@ -52,16 +52,16 @@ XD(rwalk_get_Tref)
} else {
struct sdis_interface_fragment frag;
struct sdis_interface* interf = NULL;
- ASSERT(!SXD_HIT_NONE(&rwalk->hit));
+ ASSERT(!SXD_HIT_NONE(&rwalk->XD(hit)));
/* Fetch the interface where the random walk ends */
- interf = scene_get_interface(scn, rwalk->hit.prim.prim_id);
+ interf = scene_get_interface(scn, rwalk->XD(hit).prim.prim_id);
ASSERT(rwalk->hit_side!=SDIS_FRONT || interf->medium_front->type==SDIS_FLUID);
ASSERT(rwalk->hit_side!=SDIS_BACK || interf->medium_back->type==SDIS_FLUID);
/* Fragment on the fluid side of the boundary onto which the rwalk ends */
XD(setup_interface_fragment)
- (&frag, &rwalk->vtx, &rwalk->hit, rwalk->hit_side);
+ (&frag, &rwalk->vtx, &rwalk->XD(hit), rwalk->hit_side);
Tref = interface_side_get_reference_temperature(interf, &frag);
}
@@ -85,30 +85,32 @@ XD(solid_fluid_boundary_picard1_path)
(struct sdis_scene* scn,
struct rwalk_context* ctx,
const struct sdis_interface_fragment* frag,
- struct XD(rwalk)* rwalk,
+ struct rwalk* rwalk,
struct ssp_rng* rng,
- struct XD(temperature)* T)
+ struct temperature* T)
{
/* Input argument used to handle the net flux */
struct handle_net_flux_args handle_net_flux_args = HANDLE_NET_FLUX_ARGS_NULL;
/* Input argument used to handle the external net flux */
- struct XD(handle_external_net_flux_args) handle_external_net_flux_args =
- XD(HANDLE_EXTERNAL_NET_FLUX_ARGS_NULL);
+ struct handle_external_net_flux_args handle_external_net_flux_args =
+ HANDLE_EXTERNAL_NET_FLUX_ARGS_NULL;
/* Input/output arguments of the function used to sample a reinjection */
- struct XD(sample_reinjection_step_args) samp_reinject_step_args =
- XD(SAMPLE_REINJECTION_STEP_ARGS_NULL);
- struct XD(reinjection_step) reinject_step =
- XD(REINJECTION_STEP_NULL);
+ struct sample_reinjection_step_args samp_reinject_step_args =
+ SAMPLE_REINJECTION_STEP_ARGS_NULL;
+ struct reinjection_step reinject_step = REINJECTION_STEP_NULL;
/* Temperature and random walk state of the sampled radiative path */
- struct XD(temperature) T_s;
- struct XD(rwalk) rwalk_s;
+ struct temperature T_s;
+ struct rwalk rwalk_s;
/* Fragment on the fluid side of the boundary */
struct sdis_interface_fragment frag_fluid;
+ /* The enclosures split by the boundary */
+ unsigned enc_ids[2] = {ENCLOSURE_ID_NULL, ENCLOSURE_ID_NULL};
+
/* Data attached to the boundary */
struct sdis_interface* interf = NULL;
struct sdis_medium* solid = NULL;
@@ -136,10 +138,10 @@ XD(solid_fluid_boundary_picard1_path)
res_T res = RES_OK;
ASSERT(scn && rwalk && rng && T && ctx);
- ASSERT(XD(check_rwalk_fragment_consistency)(rwalk, frag));
+ ASSERT(XD(check_rwalk_fragment_consistency)(rwalk, frag) == RES_OK);
/* Retrieve the solid and the fluid split by the boundary */
- interf = scene_get_interface(scn, rwalk->hit.prim.prim_id);
+ interf = scene_get_interface(scn, rwalk->XD(hit).prim.prim_id);
solid = interface_get_medium(interf, SDIS_FRONT);
fluid = interface_get_medium(interf, SDIS_BACK);
solid_side = SDIS_FRONT;
@@ -150,6 +152,9 @@ XD(solid_fluid_boundary_picard1_path)
ASSERT(fluid->type == SDIS_FLUID);
}
+ /* Get the enclosures split by the boundary */
+ scene_get_enclosure_ids(scn, rwalk->XD(hit).prim.prim_id, enc_ids);
+
/* Setup a fragment for the fluid side */
frag_fluid = *frag;
frag_fluid.side = fluid_side;
@@ -178,7 +183,7 @@ XD(solid_fluid_boundary_picard1_path)
/* Sample a reinjection step */
samp_reinject_step_args.rng = rng;
- samp_reinject_step_args.solid = solid;
+ samp_reinject_step_args.solid_enc_id = enc_ids[solid_side];
samp_reinject_step_args.rwalk = rwalk;
samp_reinject_step_args.distance = delta_boundary;
samp_reinject_step_args.side = solid_side;
@@ -222,7 +227,7 @@ XD(solid_fluid_boundary_picard1_path)
/* Handle the external net flux if any */
handle_external_net_flux_args.interf = interf;
handle_external_net_flux_args.frag = frag;
- handle_external_net_flux_args.hit = &rwalk->hit;
+ handle_external_net_flux_args.XD(hit) = &rwalk->XD(hit);
handle_external_net_flux_args.green_path = ctx->green_path;
handle_external_net_flux_args.picard_order = get_picard_order(ctx);
handle_external_net_flux_args.h_cond = h_cond;
@@ -248,15 +253,15 @@ XD(solid_fluid_boundary_picard1_path)
/* Switch in convective path */
if(r < p_conv) {
T->func = XD(convective_path);
- rwalk->mdm = fluid;
+ rwalk->enc_id = enc_ids[fluid_side];
rwalk->hit_side = fluid_side;
break;
}
/* Switch in conductive path */
if(r < p_conv + p_cond) {
- struct XD(solid_reinjection_args) solid_reinject_args =
- XD(SOLID_REINJECTION_ARGS_NULL);
+ struct solid_reinjection_args solid_reinject_args =
+ SOLID_REINJECTION_ARGS_NULL;
/* Perform the reinjection into the solid */
solid_reinject_args.reinjection = &reinject_step;
@@ -265,7 +270,7 @@ XD(solid_fluid_boundary_picard1_path)
solid_reinject_args.rng = rng;
solid_reinject_args.T = T;
solid_reinject_args.fp_to_meter = scn->fp_to_meter;
- res = XD(solid_reinjection)(solid, &solid_reinject_args);
+ res = XD(solid_reinjection)(scn, enc_ids[solid_side], &solid_reinject_args);
if(res != RES_OK) goto error;
break;
}
@@ -282,7 +287,7 @@ XD(solid_fluid_boundary_picard1_path)
/* Sample a radiative path and get the Tref at its end. */
T_s = *T;
rwalk_s = *rwalk;
- rwalk_s.mdm = fluid;
+ rwalk_s.enc_id = enc_ids[fluid_side];
rwalk_s.hit_side = fluid_side;
res = XD(radiative_path)(scn, ctx, &rwalk_s, rng, &T_s);
if(res != RES_OK) goto error;
diff --git a/src/sdis_heat_path_boundary_Xd_solid_fluid_picardN.h b/src/sdis_heat_path_boundary_Xd_solid_fluid_picardN.h
@@ -66,23 +66,23 @@ error:
static INLINE res_T
XD(sample_path)
(struct sdis_scene* scn,
- const struct XD(rwalk)* rwalk_from,
+ const struct rwalk* rwalk_from,
struct rwalk_context* ctx,
struct ssp_rng* rng,
- struct XD(temperature)* T)
+ struct temperature* T)
{
- struct XD(rwalk) rwalk = XD(RWALK_NULL);
+ struct rwalk rwalk = RWALK_NULL;
res_T res = RES_OK;
ASSERT(rwalk_from && rng && T);
/* Clean-up the output variable */
- *T = XD(TEMPERATURE_NULL);
+ *T = TEMPERATURE_NULL;
T->func = XD(boundary_path);
/* Init the random walk */
rwalk.vtx = rwalk_from->vtx;
- rwalk.mdm = rwalk_from->mdm;
- rwalk.hit = rwalk_from->hit;
+ rwalk.enc_id = rwalk_from->enc_id;
+ rwalk.XD(hit) = rwalk_from->XD(hit);
rwalk.hit_side = rwalk_from->hit_side;
/* Start the registration of a new heat path */
@@ -128,15 +128,14 @@ XD(solid_fluid_boundary_picardN_path)
(struct sdis_scene* scn,
struct rwalk_context* ctx,
const struct sdis_interface_fragment* frag,
- struct XD(rwalk)* rwalk,
+ struct rwalk* rwalk,
struct ssp_rng* rng,
- struct XD(temperature)* T)
+ struct temperature* T)
{
/* Input/output arguments of the function used to sample a reinjection */
- struct XD(sample_reinjection_step_args) samp_reinject_step_args =
- XD(SAMPLE_REINJECTION_STEP_ARGS_NULL);
- struct XD(reinjection_step) reinject_step =
- XD(REINJECTION_STEP_NULL);
+ struct sample_reinjection_step_args samp_reinject_step_args =
+ SAMPLE_REINJECTION_STEP_ARGS_NULL;
+ struct reinjection_step reinject_step = REINJECTION_STEP_NULL;
/* Fragment on the fluid side of the boundary */
struct sdis_interface_fragment frag_fluid;
@@ -145,6 +144,9 @@ XD(solid_fluid_boundary_picardN_path)
struct sdis_heat_vertex hvtx = SDIS_HEAT_VERTEX_NULL;
struct sdis_heat_vertex hvtx_s = SDIS_HEAT_VERTEX_NULL;
+ /* The enclosures split by the boundary */
+ unsigned enc_ids[2] = {ENCLOSURE_ID_NULL, ENCLOSURE_ID_NULL};
+
/* Data attached to the boundary */
struct sdis_interface* interf = NULL;
struct sdis_medium* solid = NULL;
@@ -172,8 +174,7 @@ XD(solid_fluid_boundary_picardN_path)
res_T res = RES_OK;
ASSERT(scn && rwalk && rng && T && ctx);
- ASSERT(XD(check_rwalk_fragment_consistency)(rwalk, frag));
-
+ ASSERT(XD(check_rwalk_fragment_consistency)(rwalk, frag) == RES_OK);
/* Fetch the Min/max temperature */
Tmin = ctx->Tmin;
@@ -184,7 +185,7 @@ XD(solid_fluid_boundary_picardN_path)
That3 = ctx->That3;
/* Retrieve the solid and the fluid split by the boundary */
- interf = scene_get_interface(scn, rwalk->hit.prim.prim_id);
+ interf = scene_get_interface(scn, rwalk->XD(hit).prim.prim_id);
solid = interface_get_medium(interf, SDIS_FRONT);
fluid = interface_get_medium(interf, SDIS_BACK);
solid_side = SDIS_FRONT;
@@ -195,6 +196,9 @@ XD(solid_fluid_boundary_picardN_path)
ASSERT(fluid->type == SDIS_FLUID);
}
+ /* Get the enclosures split by the boundary */
+ scene_get_enclosure_ids(scn, rwalk->XD(hit).prim.prim_id, enc_ids);
+
/* Check that no net flux is set for this interface since the provided
* picardN algorithm does not handle it */
res = check_net_flux(scn, interf, frag, get_picard_order(ctx));
@@ -219,7 +223,7 @@ XD(solid_fluid_boundary_picardN_path)
/* Sample a reinjection step */
samp_reinject_step_args.rng = rng;
- samp_reinject_step_args.solid = solid;
+ samp_reinject_step_args.solid_enc_id = enc_ids[solid_side];
samp_reinject_step_args.rwalk = rwalk;
samp_reinject_step_args.distance = delta_boundary;
samp_reinject_step_args.side = solid_side;
@@ -256,8 +260,8 @@ XD(solid_fluid_boundary_picardN_path)
/* Null collision main loop */
for(;;) {
/* Temperature and random walk state of the sampled radiative path */
- struct XD(temperature) T_s;
- struct XD(rwalk) rwalk_s;
+ struct temperature T_s;
+ struct rwalk rwalk_s;
double h_radi, h_radi_min, h_radi_max; /* Radiative coefficients */
double p_radi, p_radi_min, p_radi_max; /* Radiative probas */
@@ -272,15 +276,15 @@ XD(solid_fluid_boundary_picardN_path)
/* Switch in convective path */
if(r < p_conv) {
T->func = XD(convective_path);
- rwalk->mdm = fluid;
+ rwalk->enc_id = enc_ids[fluid_side];
rwalk->hit_side = fluid_side;
break;
}
/* Switch in conductive path */
if(r < p_conv + p_cond) {
- struct XD(solid_reinjection_args) solid_reinject_args =
- XD(SOLID_REINJECTION_ARGS_NULL);
+ struct solid_reinjection_args solid_reinject_args =
+ SOLID_REINJECTION_ARGS_NULL;
/* Perform the reinjection into the solid */
solid_reinject_args.reinjection = &reinject_step;
@@ -289,7 +293,7 @@ XD(solid_fluid_boundary_picardN_path)
solid_reinject_args.rng = rng;
solid_reinject_args.T = T;
solid_reinject_args.fp_to_meter = scn->fp_to_meter;
- res = XD(solid_reinjection)(solid, &solid_reinject_args);
+ res = XD(solid_reinjection)(scn, enc_ids[solid_side], &solid_reinject_args);
if(res != RES_OK) goto error;
break;
}
@@ -303,7 +307,7 @@ XD(solid_fluid_boundary_picardN_path)
/* Sample a radiative path */
T_s = *T;
rwalk_s = *rwalk;
- rwalk_s.mdm = fluid;
+ rwalk_s.enc_id = enc_ids[fluid_side];
rwalk_s.hit_side = fluid_side;
res = XD(radiative_path)(scn, ctx, &rwalk_s, rng, &T_s);
if(res != RES_OK) goto error;
@@ -340,9 +344,9 @@ XD(solid_fluid_boundary_picardN_path)
} (void)0
#define COMPUTE_TEMPERATURE(Result, RWalk, Temp) { \
- struct XD(temperature) T_p; \
+ struct temperature T_p; \
if((Temp)->done) { /* Ambient radiative temperature */ \
- ASSERT(SXD_HIT_NONE(&(RWalk)->hit)); \
+ ASSERT(SXD_HIT_NONE(&(RWalk)->XD(hit))); \
T_p = *(Temp); \
} else { \
res = XD(sample_path)(scn, RWalk, ctx, rng, &T_p); \
diff --git a/src/sdis_heat_path_boundary_Xd_solid_solid.h b/src/sdis_heat_path_boundary_Xd_solid_solid.h
@@ -33,28 +33,29 @@ XD(solid_solid_boundary_path)
(struct sdis_scene* scn,
struct rwalk_context* ctx,
const struct sdis_interface_fragment* frag,
- struct XD(rwalk)* rwalk,
+ struct rwalk* rwalk,
struct ssp_rng* rng,
- struct XD(temperature)* T)
+ struct temperature* T)
{
/* Input/output arguments of the function used to sample a reinjection */
- struct XD(sample_reinjection_step_args) samp_reinject_step_frt_args =
- XD(SAMPLE_REINJECTION_STEP_ARGS_NULL);
- struct XD(sample_reinjection_step_args) samp_reinject_step_bck_args =
- XD(SAMPLE_REINJECTION_STEP_ARGS_NULL);
- struct XD(reinjection_step) reinject_step_frt = XD(REINJECTION_STEP_NULL);
- struct XD(reinjection_step) reinject_step_bck = XD(REINJECTION_STEP_NULL);
- struct XD(reinjection_step)* reinject_step = NULL;
+ struct sample_reinjection_step_args samp_reinject_step_frt_args =
+ SAMPLE_REINJECTION_STEP_ARGS_NULL;
+ struct sample_reinjection_step_args samp_reinject_step_bck_args =
+ SAMPLE_REINJECTION_STEP_ARGS_NULL;
+ struct reinjection_step reinject_step_frt = REINJECTION_STEP_NULL;
+ struct reinjection_step reinject_step_bck = REINJECTION_STEP_NULL;
+ struct reinjection_step* reinject_step = NULL;
/* Reinjection arguments */
- struct XD(solid_reinjection_args) solid_reinject_args =
- XD(SOLID_REINJECTION_ARGS_NULL);
+ struct solid_reinjection_args solid_reinject_args =
+ SOLID_REINJECTION_ARGS_NULL;
/* Data attached to the boundary */
+ unsigned enc_ids[2] = {ENCLOSURE_ID_NULL, ENCLOSURE_ID_NULL};
struct sdis_interface* interf = NULL;
struct sdis_medium* solid_frt = NULL;
struct sdis_medium* solid_bck = NULL;
- struct sdis_medium* solid = NULL;
+ unsigned solid_enc_id = ENCLOSURE_ID_NULL; /* Solid to re-inject */
double lambda_frt;
double lambda_bck;
@@ -67,11 +68,12 @@ XD(solid_solid_boundary_path)
res_T res = RES_OK;
ASSERT(scn && ctx && frag && rwalk && rng && T);
- ASSERT(XD(check_rwalk_fragment_consistency)(rwalk, frag));
+ ASSERT(XD(check_rwalk_fragment_consistency)(rwalk, frag) == RES_OK);
(void)frag, (void)ctx;
- /* Retrieve the two solids split by the boundary */
- interf = scene_get_interface(scn, rwalk->hit.prim.prim_id);
+ /* Retrieve the two enclosures and associated media split by the boundary */
+ scene_get_enclosure_ids(scn, rwalk->XD(hit).prim.prim_id, enc_ids);
+ interf = scene_get_interface(scn, rwalk->XD(hit).prim.prim_id);
solid_frt = interface_get_medium(interf, SDIS_FRONT);
solid_bck = interface_get_medium(interf, SDIS_BACK);
ASSERT(solid_frt->type == SDIS_SOLID);
@@ -93,8 +95,8 @@ XD(solid_solid_boundary_path)
/* Sample a front/back reinjection steps */
samp_reinject_step_frt_args.rng = rng;
samp_reinject_step_bck_args.rng = rng;
- samp_reinject_step_frt_args.solid = solid_frt;
- samp_reinject_step_bck_args.solid = solid_bck;
+ samp_reinject_step_frt_args.solid_enc_id = enc_ids[SDIS_FRONT];
+ samp_reinject_step_bck_args.solid_enc_id = enc_ids[SDIS_BACK];
samp_reinject_step_frt_args.rwalk = rwalk;
samp_reinject_step_bck_args.rwalk = rwalk;
samp_reinject_step_frt_args.distance = delta_boundary_frt;
@@ -102,7 +104,7 @@ XD(solid_solid_boundary_path)
samp_reinject_step_frt_args.side = SDIS_FRONT;
samp_reinject_step_bck_args.side = SDIS_BACK;
res = XD(sample_reinjection_step_solid_solid)
- (scn,
+ (scn,
&samp_reinject_step_frt_args,
&samp_reinject_step_bck_args,
&reinject_step_frt,
@@ -150,10 +152,10 @@ XD(solid_solid_boundary_path)
if(r < proba) { /* Reinject in front */
reinject_step = &reinject_step_frt;
- solid = solid_frt;
+ solid_enc_id = enc_ids[SDIS_FRONT];
} else { /* Reinject in back */
reinject_step = &reinject_step_bck;
- solid = solid_bck;
+ solid_enc_id = enc_ids[SDIS_BACK];
}
/* Perform the reinjection into the solid */
@@ -163,7 +165,7 @@ XD(solid_solid_boundary_path)
solid_reinject_args.rwalk_ctx = ctx;
solid_reinject_args.T = T;
solid_reinject_args.fp_to_meter = scn->fp_to_meter;
- res = XD(solid_reinjection)(solid, &solid_reinject_args);
+ res = XD(solid_reinjection)(scn, solid_enc_id, &solid_reinject_args);
if(res != RES_OK) goto error;
exit:
diff --git a/src/sdis_heat_path_boundary_c.h b/src/sdis_heat_path_boundary_c.h
@@ -21,123 +21,92 @@
#include <rsys/rsys.h>
/* Forward declarations */
-struct rwalk_2d;
-struct rwalk_3d;
+struct rwalk;
struct sdis_scene;
struct sdis_medium;
/*******************************************************************************
* Sample a reinjection step
******************************************************************************/
-struct sample_reinjection_step_args_2d {
+struct sample_reinjection_step_args {
struct ssp_rng* rng; /* Random number generator to use */
- const struct sdis_medium* solid; /* Solid in which to reinject */
- struct rwalk_2d* rwalk; /* Current state of the random walk */
+ struct rwalk* rwalk; /* Current state of the random walk */
double distance; /* Maximum Reinjection distance */
+ unsigned solid_enc_id; /* Enclosured Id of the solid in which to reinject */
enum sdis_side side; /* Side of the boundary to re-inject */
};
-struct sample_reinjection_step_args_3d {
- struct ssp_rng* rng; /* Random number generator to use */
- const struct sdis_medium* solid; /* Medium in which to reinject */
- struct rwalk_3d* rwalk; /* Current random walk state */
- double distance; /* Maximum Reinjection distance */
- enum sdis_side side; /* Side of the boundary to re-inject */
-};
-
-struct reinjection_step_2d {
- struct s2d_hit hit; /* Intersection along the reinjection direction */
- float direction[2]; /* Reinjection direction */
- float distance; /* Reinjection distance */
-};
+#define SAMPLE_REINJECTION_STEP_ARGS_NULL__ \
+ {NULL, NULL, -1, ENCLOSURE_ID_NULL, SDIS_SIDE_NULL__}
+static const struct sample_reinjection_step_args
+SAMPLE_REINJECTION_STEP_ARGS_NULL = SAMPLE_REINJECTION_STEP_ARGS_NULL__;
-struct reinjection_step_3d {
- struct s3d_hit hit; /* Intersection along the reinjection direction */
+struct reinjection_step {
+ struct s2d_hit hit_2d; /* 2D Intersection along the reinjection direction */
+ struct s3d_hit hit_3d; /* 3D Intersection along the reinjection direction */
float direction[3]; /* Reinjection direction */
float distance; /* Reinjection distance */
};
-#define SAMPLE_REINJECTION_STEP_ARGS_NULL___2d \
- {NULL, NULL, NULL, -1, SDIS_SIDE_NULL__}
-#define SAMPLE_REINJECTION_STEP_ARGS_NULL___3d \
- {NULL, NULL, NULL, -1, SDIS_SIDE_NULL__}
-static const struct sample_reinjection_step_args_2d
-SAMPLE_REINJECTION_STEP_ARGS_NULL_2d = SAMPLE_REINJECTION_STEP_ARGS_NULL___2d;
-static const struct sample_reinjection_step_args_3d
-SAMPLE_REINJECTION_STEP_ARGS_NULL_3d = SAMPLE_REINJECTION_STEP_ARGS_NULL___3d;
-
-#define REINJECTION_STEP_NULL___2d {S2D_HIT_NULL__, {0,0}, 0}
-#define REINJECTION_STEP_NULL___3d {S3D_HIT_NULL__, {0,0,0}, 0}
-static const struct reinjection_step_2d
-REINJECTION_STEP_NULL_2d = REINJECTION_STEP_NULL___2d;
-static const struct reinjection_step_3d
-REINJECTION_STEP_NULL_3d = REINJECTION_STEP_NULL___3d;
+#define REINJECTION_STEP_NULL__ {S2D_HIT_NULL__, S3D_HIT_NULL__, {0,0,0}, 0}
+static const struct reinjection_step REINJECTION_STEP_NULL =
+ REINJECTION_STEP_NULL__;
extern LOCAL_SYM res_T
sample_reinjection_step_solid_fluid_2d
(struct sdis_scene* scn,
- const struct sample_reinjection_step_args_2d* args,
- struct reinjection_step_2d* step);
+ const struct sample_reinjection_step_args* args,
+ struct reinjection_step* step);
extern LOCAL_SYM res_T
sample_reinjection_step_solid_fluid_3d
(struct sdis_scene* scn,
- const struct sample_reinjection_step_args_3d* args,
- struct reinjection_step_3d *step);
+ const struct sample_reinjection_step_args* args,
+ struct reinjection_step *step);
extern LOCAL_SYM res_T
sample_reinjection_step_solid_solid_2d
(struct sdis_scene* scn,
- const struct sample_reinjection_step_args_2d* args_front,
- const struct sample_reinjection_step_args_2d* args_back,
- struct reinjection_step_2d* step_front,
- struct reinjection_step_2d* step_back);
+ const struct sample_reinjection_step_args* args_front,
+ const struct sample_reinjection_step_args* args_back,
+ struct reinjection_step* step_front,
+ struct reinjection_step* step_back);
extern LOCAL_SYM res_T
sample_reinjection_step_solid_solid_3d
(struct sdis_scene* scn,
- const struct sample_reinjection_step_args_3d* args_front,
- const struct sample_reinjection_step_args_3d* args_back,
- struct reinjection_step_3d* step_front,
- struct reinjection_step_3d* step_back);
+ const struct sample_reinjection_step_args* args_front,
+ const struct sample_reinjection_step_args* args_back,
+ struct reinjection_step* step_front,
+ struct reinjection_step* step_back);
/*******************************************************************************
* Reinject the random walk into a solid
******************************************************************************/
-struct solid_reinjection_args_2d {
- const struct reinjection_step_2d* reinjection; /* Reinjection to do */
+struct solid_reinjection_args {
+ const struct reinjection_step* reinjection; /* Reinjection to do */
struct rwalk_context* rwalk_ctx;
- struct rwalk_2d* rwalk; /* Current state of the random walk */
+ struct rwalk* rwalk; /* Current state of the random walk */
struct ssp_rng* rng; /* Random number generator */
- struct temperature_2d* T;
+ struct temperature* T;
double fp_to_meter;
};
-struct solid_reinjection_args_3d {
- const struct reinjection_step_3d* reinjection; /* Reinjection to do */
- struct rwalk_context* rwalk_ctx;
- struct rwalk_3d* rwalk; /* Current state of the random walk */
- struct ssp_rng* rng; /* Random number generator */
- struct temperature_3d* T;
- double fp_to_meter;
-};
-
-#define SOLID_REINJECTION_ARGS_NULL___2d {NULL,NULL,NULL,NULL,NULL,0}
-#define SOLID_REINJECTION_ARGS_NULL___3d {NULL,NULL,NULL,NULL,NULL,0}
-static const struct solid_reinjection_args_2d SOLID_REINJECTION_ARGS_NULL_2d =
- SOLID_REINJECTION_ARGS_NULL___2d;
-static const struct solid_reinjection_args_3d SOLID_REINJECTION_ARGS_NULL_3d =
- SOLID_REINJECTION_ARGS_NULL___3d;
+#define SOLID_REINJECTION_ARGS_NULL__ {NULL,NULL,NULL,NULL,NULL,0}
+static const struct solid_reinjection_args SOLID_REINJECTION_ARGS_NULL =
+ SOLID_REINJECTION_ARGS_NULL__;
extern LOCAL_SYM res_T
solid_reinjection_2d
- (struct sdis_medium* solid,
- struct solid_reinjection_args_2d* args);
+ (struct sdis_scene* scn,
+ const unsigned solid_enc_id,
+ struct solid_reinjection_args* args);
extern LOCAL_SYM res_T
solid_reinjection_3d
- (struct sdis_medium* solid,
- struct solid_reinjection_args_3d* args);
+ (struct sdis_scene* scn,
+ const unsigned solid_enc_id,
+ struct solid_reinjection_args* args);
/*******************************************************************************
* Handle net flux
@@ -160,21 +129,22 @@ extern LOCAL_SYM res_T
handle_net_flux_2d
(const struct sdis_scene* scn,
const struct handle_net_flux_args* args,
- struct temperature_2d* T);
+ struct temperature* T);
extern LOCAL_SYM res_T
handle_net_flux_3d
(const struct sdis_scene* scn,
const struct handle_net_flux_args* args,
- struct temperature_3d* T);
+ struct temperature* T);
/*******************************************************************************
* Handle external flux
******************************************************************************/
-struct handle_external_net_flux_args_2d {
+struct handle_external_net_flux_args {
struct sdis_interface* interf;
const struct sdis_interface_fragment* frag;
- const struct s2d_hit* hit;
+ const struct s2d_hit* hit_2d;
+ const struct s3d_hit* hit_3d;
struct green_path_handle* green_path; /* Store the propagator */
struct sdis_heat_path* heat_path; /* Save paths */
@@ -199,26 +169,23 @@ struct handle_external_net_flux_args_3d {
double h_radi; /* Radiative coefficient */
};
-#define HANDLE_EXTERNAL_NET_FLUX_ARGS_NULL___2d {NULL,NULL,NULL,NULL,NULL,0,0,0,0}
-#define HANDLE_EXTERNAL_NET_FLUX_ARGS_NULL___3d {NULL,NULL,NULL,NULL,NULL,0,0,0,0}
-static const struct handle_external_net_flux_args_2d
-HANDLE_EXTERNAL_NET_FLUX_ARGS_NULL_2d = HANDLE_EXTERNAL_NET_FLUX_ARGS_NULL___2d;
-static const struct handle_external_net_flux_args_3d
-HANDLE_EXTERNAL_NET_FLUX_ARGS_NULL_3d = HANDLE_EXTERNAL_NET_FLUX_ARGS_NULL___3d;
+#define HANDLE_EXTERNAL_NET_FLUX_ARGS_NULL__ {NULL,NULL,NULL,NULL,NULL,NULL,0,0,0,0}
+static const struct handle_external_net_flux_args
+HANDLE_EXTERNAL_NET_FLUX_ARGS_NULL = HANDLE_EXTERNAL_NET_FLUX_ARGS_NULL__;
extern LOCAL_SYM res_T
handle_external_net_flux_2d
(const struct sdis_scene* scn,
struct ssp_rng* rng,
- const struct handle_external_net_flux_args_2d* args,
- struct temperature_2d* T);
+ const struct handle_external_net_flux_args* args,
+ struct temperature* T);
extern LOCAL_SYM res_T
handle_external_net_flux_3d
(const struct sdis_scene* scn,
struct ssp_rng* rng,
- const struct handle_external_net_flux_args_3d* args,
- struct temperature_3d* T);
+ const struct handle_external_net_flux_args* args,
+ struct temperature* T);
/*******************************************************************************
* Miscellaneous functions
@@ -246,9 +213,9 @@ solid_boundary_with_flux_path_2d
struct rwalk_context* ctx,
const struct sdis_interface_fragment* frag,
const double phi,
- struct rwalk_2d* rwalk,
+ struct rwalk* rwalk,
struct ssp_rng* rng,
- struct temperature_2d* T);
+ struct temperature* T);
extern LOCAL_SYM res_T
solid_boundary_with_flux_path_3d
@@ -256,62 +223,62 @@ solid_boundary_with_flux_path_3d
struct rwalk_context* ctx,
const struct sdis_interface_fragment* frag,
const double phi,
- struct rwalk_3d* rwalk,
+ struct rwalk* rwalk,
struct ssp_rng* rng,
- struct temperature_3d* T);
+ struct temperature* T);
extern LOCAL_SYM res_T
solid_fluid_boundary_picard1_path_2d
(struct sdis_scene* scn,
struct rwalk_context* ctx,
const struct sdis_interface_fragment* frag,
- struct rwalk_2d* rwalk,
+ struct rwalk* rwalk,
struct ssp_rng* rng,
- struct temperature_2d* T);
+ struct temperature* T);
extern LOCAL_SYM res_T
solid_fluid_boundary_picard1_path_3d
(struct sdis_scene* scn,
struct rwalk_context* ctx,
const struct sdis_interface_fragment* frag,
- struct rwalk_3d* rwalk,
+ struct rwalk* rwalk,
struct ssp_rng* rng,
- struct temperature_3d* T);
+ struct temperature* T);
extern LOCAL_SYM res_T
solid_fluid_boundary_picardN_path_2d
(struct sdis_scene* scn,
struct rwalk_context* ctx,
const struct sdis_interface_fragment* frag,
- struct rwalk_2d* rwalk,
+ struct rwalk* rwalk,
struct ssp_rng* rng,
- struct temperature_2d* T);
+ struct temperature* T);
extern LOCAL_SYM res_T
solid_fluid_boundary_picardN_path_3d
(struct sdis_scene* scn,
struct rwalk_context* ctx,
const struct sdis_interface_fragment* frag,
- struct rwalk_3d* rwalk,
+ struct rwalk* rwalk,
struct ssp_rng* rng,
- struct temperature_3d* T);
+ struct temperature* T);
extern LOCAL_SYM res_T
solid_solid_boundary_path_2d
(struct sdis_scene* scn,
struct rwalk_context* ctx,
const struct sdis_interface_fragment* frag,
- struct rwalk_2d* rwalk,
+ struct rwalk* rwalk,
struct ssp_rng* rng,
- struct temperature_2d* T);
+ struct temperature* T);
extern LOCAL_SYM res_T
solid_solid_boundary_path_3d
(struct sdis_scene* scn,
struct rwalk_context* ctx,
const struct sdis_interface_fragment* frag,
- struct rwalk_3d* rwalk,
+ struct rwalk* rwalk,
struct ssp_rng* rng,
- struct temperature_3d* T);
+ struct temperature* T);
#endif /* SDIS_HEAT_PATH_BOUNDARY_C_H */
diff --git a/src/sdis_heat_path_conductive.c b/src/sdis_heat_path_conductive.c
@@ -13,10 +13,10 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>. */
-#include "sdis_heat_path.h"
-#include "sdis_heat_path_conductive_c.h"
#include "sdis_log.h"
+#include "sdis_heat_path_conductive_c.h"
#include "sdis_medium_c.h"
+#include "sdis_scene_c.h"
/*******************************************************************************
* Local function
@@ -71,54 +71,16 @@ 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_Xd.h"
+#define SDIS_XD_DIMENSION 3
+#include "sdis_heat_path_conductive_Xd.h"
+#define SDIS_XD_DIMENSION 2
+#include "sdis_heat_path_conductive_custom_Xd.h"
+#define SDIS_XD_DIMENSION 3
+#include "sdis_heat_path_conductive_custom_Xd.h"
+#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"
diff --git a/src/sdis_heat_path_conductive_Xd.h b/src/sdis_heat_path_conductive_Xd.h
@@ -0,0 +1,73 @@
+/* Copyright (C) 2016-2024 |Méso|Star> (contact@meso-star.com)
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+#include "sdis.h"
+#include "sdis_heat_path.h"
+#include "sdis_heat_path_conductive_c.h"
+#include "sdis_log.h"
+#include "sdis_medium_c.h"
+#include "sdis_scene_c.h"
+
+#include <rsys/cstr.h>
+
+#include "sdis_Xd_begin.h"
+
+/*******************************************************************************
+ * Local functions
+ ******************************************************************************/
+res_T
+XD(conductive_path)
+ (struct sdis_scene* scn,
+ struct rwalk_context* ctx,
+ struct rwalk* rwalk,
+ struct ssp_rng* rng,
+ struct temperature* T)
+{
+ struct sdis_medium* mdm = NULL;
+ unsigned enc_id = ENCLOSURE_ID_NULL;
+ res_T res = RES_OK;
+ ASSERT(ctx && rwalk);
+
+ res = scene_get_enclosure_id_in_closed_boundaries(scn, rwalk->vtx.P, &enc_id);
+ if(res != RES_OK) goto error;
+ res = scene_get_enclosure_medium(scn, scene_get_enclosure(scn, enc_id), &mdm);
+ if(res != RES_OK) goto error;
+ ASSERT(sdis_medium_get_type(mdm) == SDIS_SOLID);
+
+ /* The caller defined a custom function to sample the solid path */
+ if(mdm->shader.solid.sample_path != NULL) {
+ res = XD(conductive_path_custom)(scn, enc_id, mdm, rwalk, rng, T);
+ if(res != RES_OK) goto error;
+
+ } else {
+ switch(ctx->diff_algo) {
+ case SDIS_DIFFUSION_DELTA_SPHERE:
+ res = XD(conductive_path_delta_sphere)(scn, ctx, rwalk, rng, T);
+ break;
+ case SDIS_DIFFUSION_WOS:
+ res = XD(conductive_path_wos)(scn, ctx, rwalk, rng, T);
+ break;
+ default: FATAL("Unreachable code.\n"); break;
+ }
+ if(res != RES_OK) goto error;
+ }
+
+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
@@ -19,15 +19,14 @@
#include <rsys/rsys.h>
/* Forward declarations */
-struct rwalk_2d;
-struct rwalk_3d;
+struct rwalk;
struct rwalk_context;
struct sdis_device;
+struct sdis_medium;
struct sdis_scene;
struct solid_props;
struct ssp_rng;
-struct temperature_2d;
-struct temperature_3d;
+struct temperature;
extern LOCAL_SYM res_T
check_solid_constant_properties
@@ -38,23 +37,44 @@ check_solid_constant_properties
const struct solid_props* props);
/*******************************************************************************
+ * Conductive paths using custom user algorithm
+ ******************************************************************************/
+extern LOCAL_SYM res_T
+conductive_path_custom_2d
+ (struct sdis_scene* scn,
+ const unsigned enc_id, /* Enclosure in which path is sampled */
+ const struct sdis_medium* mdm, /* Medium in which path is sampled */
+ struct rwalk* rwalk,
+ struct ssp_rng* rng,
+ struct temperature* T);
+
+extern LOCAL_SYM res_T
+conductive_path_custom_3d
+ (struct sdis_scene* scn,
+ const unsigned enc_id, /* Enclosure in which path is sampled */
+ const struct sdis_medium* mdm, /* Medium in which path is sampled */
+ struct rwalk* rwalk,
+ struct ssp_rng* rng,
+ struct temperature* T);
+
+/*******************************************************************************
* 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 rwalk* rwalk,
struct ssp_rng* rng,
- struct temperature_2d* T);
+ struct temperature* T);
extern LOCAL_SYM res_T
conductive_path_delta_sphere_3d
(struct sdis_scene* scn,
struct rwalk_context* ctx,
- struct rwalk_3d* rwalk,
+ struct rwalk* rwalk,
struct ssp_rng* rng,
- struct temperature_3d* T);
+ struct temperature* T);
/*******************************************************************************
* Conductive paths using the walk on sphere algorithm
@@ -63,16 +83,16 @@ extern LOCAL_SYM res_T
conductive_path_wos_2d
(struct sdis_scene* scn,
struct rwalk_context* ctx,
- struct rwalk_2d* rwalk,
+ struct rwalk* rwalk,
struct ssp_rng* rng,
- struct temperature_2d* T);
+ struct temperature* T);
extern LOCAL_SYM res_T
conductive_path_wos_3d
(struct sdis_scene* scn,
struct rwalk_context* ctx,
- struct rwalk_3d* rwalk,
+ struct rwalk* rwalk,
struct ssp_rng* rng,
- struct temperature_3d* T);
+ struct temperature* T);
#endif /* SDIS_HEAT_PATH_CONDUCTIVE_C_H */
diff --git a/src/sdis_heat_path_conductive_custom_Xd.h b/src/sdis_heat_path_conductive_custom_Xd.h
@@ -0,0 +1,211 @@
+/* Copyright (C) 2016-2024 |Méso|Star> (contact@meso-star.com)
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+#include "sdis.h"
+#include "sdis_log.h"
+#include "sdis_medium_c.h"
+#include "sdis_scene_c.h"
+
+#include <rsys/cstr.h>
+
+#include "sdis_Xd_begin.h"
+
+/*******************************************************************************
+ * Helper function
+ ******************************************************************************/
+static res_T
+XD(check_sampled_path)
+ (struct sdis_scene* scn,
+ const struct rwalk* rwalk,
+ const struct sdis_path* path)
+{
+ int null_prim = 0;
+ res_T res = RES_OK;
+ ASSERT(scn && path);
+
+ null_prim = SXD_PRIMITIVE_EQ(&path->XD(prim), &SXD_PRIMITIVE_NULL);
+
+ /* Check end of path */
+ if(!path->at_limit && null_prim) {
+ log_err(scn->dev,
+ "%s: the sampled path should have reached a limit condition or a boundary"
+ " -- pos=("FORMAT_VECX")\n",
+ FUNC_NAME, SPLITX(path->vtx.P));
+ res = RES_BAD_ARG;
+ goto error;
+ }
+
+ /* Check path time */
+ if(path->vtx.time > rwalk->vtx.time) {
+ log_err(scn->dev,
+ "%s: the sampled trajectory cannot be in the future. "
+ "It can only go back in time -- starting time=%g s; current time=%g s\n",
+ FUNC_NAME, rwalk->vtx.time, path->vtx.time);
+ res = RES_BAD_ARG;
+ goto error;
+ }
+
+ if(!null_prim) {
+ struct sXd(primitive) prim;
+ const unsigned iprim = path->XD(prim).prim_id;
+
+ /* Check intersected primitive */
+ res = sXd(scene_view_get_primitive)(scn->sXd(view), iprim, &prim);
+ if(res != RES_OK || !SXD_PRIMITIVE_EQ(&path->XD(prim), &prim)) {
+ log_err(scn->dev,
+ "%s: invalid intersected primitive on sampled path -- %s\n",
+ FUNC_NAME, res_to_cstr(res));
+ goto error;
+ }
+ }
+
+exit:
+ return res;
+error:
+ goto exit;
+}
+
+static int
+XD(keep_only_one_primitive)
+ (const struct sXd(hit)* hit,
+ const float org[DIM],
+ const float dir[DIM],
+ const float range[2],
+ void* query_data,
+ void* filter_data)
+{
+ const struct sXd(primitive)* prim = query_data;
+ (void)org, (void)dir, (void)range, (void)filter_data;
+ return !SXD_PRIMITIVE_EQ(prim, &hit->prim);
+}
+
+static res_T
+XD(get_path_hit)
+ (struct sdis_scene* scn,
+ struct sdis_path* path,
+ const struct sdis_medium* mdm,
+ struct sXd(hit)* hit)
+{
+ struct hit_filter_data filter_data = HIT_FILTER_DATA_NULL;
+ float query_radius = 0;
+ float query_pos[DIM] = {0};
+ double delta = 0;
+ res_T res = RES_OK;
+ ASSERT(scn && path && hit);
+
+ filter_data.XD(custom_filter) = XD(keep_only_one_primitive);
+ filter_data.custom_filter_data = &path->XD(prim);
+
+ /* Search for the hit corresponding to the path position on a primitive. Search
+ * at a maximum distance from the delta of the medium, as this hit should be
+ * very close to the submitted position, since it should represent the same
+ * point. */
+ delta = solid_get_delta(mdm, &path->vtx);
+ fX_set_dX(query_pos, path->vtx.P);
+ query_radius = (float)delta;
+ SXD(scene_view_closest_point(scn->sXd(view), query_pos, query_radius,
+ &filter_data, hit));
+ ASSERT(SXD_PRIMITIVE_EQ(&hit->prim, &path->XD(prim)));
+
+ if(SXD_HIT_NONE(hit)) {
+ log_warn(scn->dev,
+ "%s: the position returned by custom sampling of the conductive path "
+ "is too far from the primitive it should be on -- "
+ "query position=("FORMAT_VECX"); search distance=%g\n",
+ FUNC_NAME, SPLITX(path->vtx.P), delta);
+ res = RES_BAD_OP;
+ goto error;
+ }
+
+exit:
+ return res;
+error:
+ goto exit;
+}
+
+/*******************************************************************************
+ * Local function
+ ******************************************************************************/
+res_T
+XD(conductive_path_custom)
+ (struct sdis_scene* scn,
+ const unsigned enc_id,
+ const struct sdis_medium* mdm,
+ struct rwalk* rwalk,
+ struct ssp_rng* rng,
+ struct temperature* T)
+{
+ struct sdis_path path = SDIS_PATH_NULL;
+ res_T res = RES_OK;
+
+ /* Check pre-conditions */
+ ASSERT(scn && rwalk && rng && T);
+ ASSERT(sdis_medium_get_type(mdm) == SDIS_SOLID);
+ ASSERT(mdm->shader.solid.sample_path);
+
+ /* Sample a conductive path */
+ path.vtx = rwalk->vtx;
+ res = mdm->shader.solid.sample_path(scn, rng, &path, mdm->data);
+ if(res != RES_OK) {
+ log_err(scn->dev,
+ "%s: error in customized sampling of a conductive path "
+ "from pos=("FORMAT_VECX") -- %s\n",
+ FUNC_NAME, SPLITX(rwalk->vtx.P), res_to_cstr(res));
+ goto error;
+ }
+
+ res = XD(check_sampled_path)(scn, rwalk, &path);
+ if(res!= RES_OK) goto error;
+
+ /* Update random walk position and time from sampled path */
+ rwalk->elapsed_time += rwalk->vtx.time - path.vtx.time;
+ rwalk->vtx = path.vtx;
+
+ /* Calculate path intersection with geometry if it hasn't already reached a
+ * boundary condition */
+ if(!path.at_limit) {
+ res = XD(get_path_hit)(scn, &path, mdm, &rwalk->XD(hit));
+ if(res != RES_OK) goto error;
+ }
+
+
+ /* The path reached a boundary */
+ if(!SXD_HIT_NONE(&rwalk->XD(hit))) {
+ unsigned enc_ids[2] = {ENCLOSURE_ID_NULL, ENCLOSURE_ID_NULL};
+
+ rwalk->enc_id = ENCLOSURE_ID_NULL; /* Not in an enclosure */
+
+ /* Define which side of the interface the path is on */
+ scene_get_enclosure_ids(scn, rwalk->XD(hit).prim.prim_id, enc_ids);
+ if(enc_id == enc_ids[SDIS_FRONT]) rwalk->hit_side = SDIS_FRONT;
+ else if(enc_id == enc_ids[SDIS_BACK]) rwalk->hit_side = SDIS_BACK;
+ else FATAL("Unreachable code.\n");
+ }
+
+ /* Update Monte Carlo weight */
+ T->value += path.weight;
+ T->done = path.at_limit;
+
+ /* The path either reaches a boundary condition and will be stopped, or is
+ * on a boundary and a boundary path must be sampled */
+ T->func = XD(boundary_path);
+
+exit:
+ return res;
+error:
+ goto exit;
+}
+
+#include "sdis_Xd_end.h"
diff --git a/src/sdis_heat_path_conductive_delta_sphere_Xd.h b/src/sdis_heat_path_conductive_delta_sphere_Xd.h
@@ -111,7 +111,7 @@ XD(sample_next_step)
static res_T
XD(sample_next_step_robust)
(struct sdis_scene* scn,
- struct sdis_medium* current_mdm,
+ const unsigned current_enc_id,
struct ssp_rng* rng,
const double pos[DIM],
const float delta_solid,
@@ -121,13 +121,14 @@ XD(sample_next_step_robust)
struct sXd(hit)* hit1, /* Hit used to adjust delta */
float* out_delta)
{
- struct sdis_medium* mdm;
+ unsigned enc_id = ENCLOSURE_ID_NULL;
float delta;
float org[DIM];
const size_t MAX_ATTEMPTS = 100;
size_t iattempt = 0;
res_T res = RES_OK;
- ASSERT(scn && current_mdm && rng && pos && delta_solid > 0);
+ ASSERT(scn && rng && pos && delta_solid > 0);
+ ASSERT(current_enc_id != ENCLOSURE_ID_NULL);
ASSERT(dir0 && dir1 && hit0 && hit1 && out_delta);
fX_set_dX(org, pos);
@@ -141,44 +142,30 @@ XD(sample_next_step_robust)
/* Retrieve the medium of the next step */
if(hit0->distance > delta) {
XD(move_pos)(dX(set)(pos_next, pos), dir0, delta);
- res = scene_get_medium_in_closed_boundaries(scn, pos_next, &mdm);
- if(res == RES_BAD_OP) { mdm = NULL; res = RES_OK; }
+ res = scene_get_enclosure_id_in_closed_boundaries(scn, pos_next, &enc_id);
+ if(res == RES_BAD_OP) { enc_id = ENCLOSURE_ID_NULL; res = RES_OK; }
if(res != RES_OK) goto error;
} else {
- struct sdis_interface* interf;
- enum sdis_side side;
- interf = scene_get_interface(scn, hit0->prim.prim_id);
- side = fX(dot)(dir0, hit0->normal) < 0 ? SDIS_FRONT : SDIS_BACK;
- mdm = interface_get_medium(interf, side);
+ unsigned enc_ids[2] = {ENCLOSURE_ID_NULL, ENCLOSURE_ID_NULL};
+ scene_get_enclosure_ids(scn, hit0->prim.prim_id, enc_ids);
+ enc_id = fX(dot)(dir0, hit0->normal) < 0 ? enc_ids[0] : enc_ids[1];
}
/* Check medium consistency */
- if(current_mdm != mdm) {
+ if(current_enc_id != enc_id) {
#if 0
-#if DIM == 2
- log_warn(scn->dev,
- "%s: inconsistent medium during the solid random walk at {%g, %g}.\n",
- FUNC_NAME, SPLIT2(pos));
-#else
log_warn(scn->dev,
- "%s: inconsistent medium during the solid random walk at {%g, %g, %g}.\n",
- FUNC_NAME, SPLIT3(pos));
-#endif
+ "%s: inconsistent medium during the solid random walk -- "
+ "pos=("FORMAT_VECX")\n", FUNC_NAME, SPLITX(pos));
#endif
}
- } while(current_mdm != mdm && ++iattempt < MAX_ATTEMPTS);
+ } while(current_enc_id != enc_id && ++iattempt < MAX_ATTEMPTS);
/* Handle error */
if(iattempt >= MAX_ATTEMPTS) {
-#if DIM == 2
- log_warn(scn->dev,
- "%s: could not find a next valid conductive step at {%g, %g}.\n",
- FUNC_NAME, SPLIT2(pos));
-#else
log_warn(scn->dev,
- "%s: could not find a next valid conductive step at {%g, %g, %g}.\n",
- FUNC_NAME, SPLIT3(pos));
-#endif
+ "%s: could not find a next valid conductive -- pos=("FORMAT_VECX")\n",
+ FUNC_NAME, SPLITX(pos));
res = RES_BAD_OP;
goto error;
}
@@ -239,7 +226,7 @@ XD(handle_volumic_power)
(const struct sdis_scene* scn,
const struct XD(handle_volumic_power_args)* args,
double* out_power_term,
- struct XD(temperature)* T)
+ struct temperature* T)
{
double power_term = 0;
res_T res = RES_OK;
@@ -332,28 +319,43 @@ res_T
XD(conductive_path_delta_sphere)
(struct sdis_scene* scn,
struct rwalk_context* ctx,
- struct XD(rwalk)* rwalk,
+ struct rwalk* rwalk,
struct ssp_rng* rng,
- struct XD(temperature)* T)
+ struct temperature* T)
{
- double position_start[DIM];
+ /* Enclosure/medium in which the conductive path starts */
+ struct sdis_medium* mdm = NULL;
+ unsigned enc_id = ENCLOSURE_ID_NULL;
+
+ /* Physical properties */
struct solid_props props_ref = SOLID_PROPS_NULL;
double green_power_term = 0;
- struct sdis_medium* mdm;
+
+ /* Miscellaneous */
+ double position_start[DIM] = {0};
size_t istep = 0; /* Help for debug */
res_T res = RES_OK;
+
+ /* Check pre-conditions */
ASSERT(scn && rwalk && rng && T);
- ASSERT(rwalk->mdm->type == SDIS_SOLID);
- (void)ctx, (void)istep;
+
+ (void)ctx, (void)istep; /* Avoid "unsued variable" warnings */
+
+ res = scene_get_enclosure_id_in_closed_boundaries(scn, rwalk->vtx.P, &enc_id);
+ if(res != RES_OK) goto error;
+ res = scene_get_enclosure_medium(scn, scene_get_enclosure(scn, enc_id), &mdm);
+ if(res != RES_OK) goto error;
+ ASSERT(sdis_medium_get_type(mdm) == SDIS_SOLID);
/* Check the random walk consistency */
- res = scene_get_medium_in_closed_boundaries(scn, rwalk->vtx.P, &mdm);
- if(res != RES_OK || mdm != rwalk->mdm) {
+ if(enc_id != rwalk->enc_id) {
log_err(scn->dev, "%s: invalid solid random walk. "
- "Unexpected medium at {%g, %g, %g}.\n", FUNC_NAME, SPLIT3(rwalk->vtx.P));
+ "Unexpected enclosure -- pos=("FORMAT_VECX")\n",
+ FUNC_NAME, SPLITX(rwalk->vtx.P));
res = RES_BAD_OP_IRRECOVERABLE;
goto error;
}
+
/* Save the submitted position */
dX(set)(position_start, rwalk->vtx.P);
@@ -396,7 +398,7 @@ XD(conductive_path_delta_sphere)
if(ctx->green_path) {
res = green_path_set_limit_vertex
- (ctx->green_path, rwalk->mdm, &rwalk->vtx, rwalk->elapsed_time);
+ (ctx->green_path, mdm, &rwalk->vtx, rwalk->elapsed_time);
if(res != RES_OK) goto error;
}
@@ -410,7 +412,7 @@ XD(conductive_path_delta_sphere)
fX_set_dX(org, rwalk->vtx.P);
/* Sample the direction to walk toward and compute the distance to travel */
- res = XD(sample_next_step_robust)(scn, mdm, rng, rwalk->vtx.P,
+ res = XD(sample_next_step_robust)(scn, enc_id, rng, rwalk->vtx.P,
(float)props.delta, dir0, dir1, &hit0, &hit1, &delta);
if(res != RES_OK) goto error;
@@ -436,16 +438,16 @@ XD(conductive_path_delta_sphere)
/* Rewind the time */
delta_m = delta * scn->fp_to_meter;
mu = (2*DIM*props.lambda)/(props.rho*props.cp*delta_m*delta_m);
- res = XD(time_rewind)(mu, props.t0, rng, rwalk, ctx, T);
+ res = time_rewind(scn, mu, props.t0, rng, rwalk, ctx, T);
if(res != RES_OK) goto error;
if(T->done) break; /* Limit condition was reached */
/* Define if the random walk hits something along dir0 */
if(hit0.distance > delta) {
- rwalk->hit = SXD_HIT_NULL;
+ rwalk->XD(hit) = SXD_HIT_NULL;
rwalk->hit_side = SDIS_SIDE_NULL__;
} else {
- rwalk->hit = hit0;
+ rwalk->XD(hit) = hit0;
rwalk->hit_side = fX(dot)(hit0.normal, dir0) < 0 ? SDIS_FRONT : SDIS_BACK;
}
@@ -460,17 +462,17 @@ XD(conductive_path_delta_sphere)
++istep;
/* Keep going while the solid random walk does not hit an interface */
- } while(SXD_HIT_NONE(&rwalk->hit));
+ } while(SXD_HIT_NONE(&rwalk->XD(hit)));
/* Register the power term for the green function */
if(ctx->green_path && props_ref.power != SDIS_VOLUMIC_POWER_NONE) {
res = green_path_add_power_term
- (ctx->green_path, rwalk->mdm, &rwalk->vtx, green_power_term);
+ (ctx->green_path, mdm, &rwalk->vtx, green_power_term);
if(res != RES_OK) goto error;
}
T->func = XD(boundary_path);
- rwalk->mdm = NULL; /* The random walk is at an interface between 2 media */
+ rwalk->enc_id = ENCLOSURE_ID_NULL; /* At the interface between 2 media */
exit:
return res;
diff --git a/src/sdis_heat_path_conductive_wos_Xd.h b/src/sdis_heat_path_conductive_wos_Xd.h
@@ -23,24 +23,67 @@
#include "sdis_Xd_begin.h"
/*******************************************************************************
+ * Non generic helper functions
+ ******************************************************************************/
+#ifndef SDIS_HEAT_PATH_CONDUCTIVE_WOS_XD_H
+#define SDIS_HEAT_PATH_CONDUCTIVE_WOS_XD_H
+
+static res_T
+update_green_path
+ (struct green_path_handle* green_path,
+ struct rwalk* rwalk,
+ struct sdis_medium* mdm,
+ const struct solid_props* props,
+ const double power_term,
+ const struct temperature* T)
+{
+ res_T res = RES_OK;
+ ASSERT(mdm && props && T);
+
+ /* Is the green function estimated? */
+ if(!green_path) goto exit;
+
+ /* Save power term for green function if any */
+ if(props->power != SDIS_VOLUMIC_POWER_NONE) {
+ res = green_path_add_power_term(green_path, mdm, &rwalk->vtx, power_term);
+ if(res != RES_OK) goto error;
+ }
+
+ /* Set the green path limit to the current position if the initial condition
+ * has been reached */
+ if(T->done) {
+ res = green_path_set_limit_vertex
+ (green_path, mdm, &rwalk->vtx, rwalk->elapsed_time);
+ if(res != RES_OK) goto error;
+ }
+
+exit:
+ return res;
+error:
+ goto exit;
+}
+
+#endif /* SDIS_HEAT_PATH_CONDUCTIVE_WOS_XD_H */
+
+/*******************************************************************************
* Helper function
******************************************************************************/
static res_T
-XD(check_medium_consistency)
+XD(check_enclosure_consistency)
(struct sdis_scene* scn,
- const struct XD(rwalk)* rwalk)
+ const struct rwalk* rwalk)
{
- struct sdis_medium* mdm = NULL;
+ unsigned enc_id = ENCLOSURE_ID_NULL;
res_T res = RES_OK;
ASSERT(rwalk);
- res = scene_get_medium_in_closed_boundaries(scn, rwalk->vtx.P, &mdm);
+ res = scene_get_enclosure_id_in_closed_boundaries(scn, rwalk->vtx.P, &enc_id);
if(res != RES_OK) goto error;
- /* Check medium consistency */
- if(mdm != rwalk->mdm) {
+ /* Check enclosure consistency */
+ if(enc_id != rwalk->enc_id) {
log_err(scn->dev,
- "%s:%s: invalid solid walk. Unexpected medium (position: "FORMAT_VECX").\n",
+ "%s:%s: invalid solid walk. Unexpected enclosure -- pos=("FORMAT_VECX")\n",
__FILE__, FUNC_NAME, SPLITX(rwalk->vtx.P));
res = RES_BAD_OP_IRRECOVERABLE;
goto error;
@@ -55,12 +98,14 @@ error:
static res_T
XD(time_travel)
(struct sdis_scene* scn,
- struct XD(rwalk)* rwalk,
+ struct rwalk* rwalk,
struct ssp_rng* rng,
+ struct sdis_medium* mdm,
const double alpha, /* Diffusivity, i.e. lambda/(rho*cp) */
const double t0, /* Initial time [s] */
+ const double pos[3], /* Position before the diffusive step */
double* distance, /* Displacement [m/fp_to_meter] */
- struct XD(temperature)* T)
+ struct temperature* T)
{
double dir[DIM] = {0};
double dst = 0; /* Distance [m] */
@@ -70,13 +115,13 @@ XD(time_travel)
double temperature = 0; /* [k] */
double time = 0; /* [s] */
res_T res = RES_OK;
- ASSERT(scn && rwalk && rng && alpha > 0 && distance && T);
+ ASSERT(scn && rwalk && rng && alpha > 0 && pos && distance && T);
dst = *distance * scn->fp_to_meter;
ASSERT(dst >= 0);
/* No displacement => no time travel */
- if(distance == 0) goto exit;
+ if(dst == 0) goto exit;
/* Sample x = tau*alpha/distance^2 */
r = ssp_rng_canonical(rng);
@@ -107,27 +152,28 @@ XD(time_travel)
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 */
+ *distance = dst / scn->fp_to_meter; /* Update travel distance */
/* Uniformly sample a direction and move along it of the distance that
- * separate the current position ot its initial condition */
+ * separate the path position before diffusion position to 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);
+ dX(muld)(dir, dir, *distance);
+ dX(add)(rwalk->vtx.P, pos, dir);
/* Fetch the initial temperature */
- temperature = medium_get_temperature(rwalk->mdm, &rwalk->vtx);
+ temperature = medium_get_temperature(mdm, &rwalk->vtx);
if(SDIS_TEMPERATURE_IS_UNKNOWN(temperature)) {
log_err(scn->dev,
"%s:%s: the path reaches the initial condition but the "
- "%s temperature remains unknown -- position=%g, %g, %g\n",
+ "%s temperature remains unknown -- pos=("FORMAT_VECX")\n",
__FILE__, FUNC_NAME,
- medium_type_to_string(sdis_medium_get_type(rwalk->mdm)),
- SPLIT3(rwalk->vtx.P));
+ medium_type_to_string(sdis_medium_get_type(mdm)),
+ SPLITX(rwalk->vtx.P));
res = RES_BAD_ARG;
goto error;
}
@@ -142,6 +188,32 @@ error:
goto exit;
}
+static res_T
+XD(handle_volumic_power_wos)
+ (struct sdis_scene* scn,
+ const struct solid_props* props,
+ const double distance, /* [m/fp_to_meter] */
+ double* power_term,
+ struct temperature* T)
+{
+ double dst = distance * scn->fp_to_meter; /* [m] */
+ double term = 0;
+ res_T res = RES_OK;
+ ASSERT(scn && props && distance >= 0 && power_term && T);
+
+ if(props->power == SDIS_VOLUMIC_POWER_NONE) goto exit;
+
+ /* No displacement => no power density */
+ if(distance == 0) goto exit;
+
+ term = dst*dst / (2*DIM*props->lambda);
+ T->value += props->power * term;
+
+exit:
+ *power_term = term;
+ return res;
+}
+
#if DIM == 2
static INLINE enum sdis_side
compute_hit_side_2d
@@ -203,16 +275,16 @@ compute_hit_side_3d
}
#endif
-/* Verify that the submitted position is in the expected medium */
+/* Verify that the submitted position is in the expected enclosure */
static res_T
XD(check_diffusion_position)
(struct sdis_scene* scn,
- const struct sdis_medium* expected_medium,
+ const unsigned expected_enc_id,
+ const double delta, /* Used to adjust thresholds */
const double pos[DIM])
{
- struct sdis_interface* interf = NULL;
- struct sdis_medium* mdm = NULL;
- enum sdis_side side;
+ unsigned enc_ids[2] = {ENCLOSURE_ID_NULL, ENCLOSURE_ID_NULL};
+ enum sdis_side side = SDIS_SIDE_NULL__;
struct sXd(hit) hit = SXD_HIT_NULL;
float wos_pos[DIM] = {0};
@@ -220,30 +292,30 @@ XD(check_diffusion_position)
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);
+ ASSERT(scn && pos);
+ ASSERT(expected_enc_id != ENCLOSURE_ID_NULL);
+
+ /* Look for the nearest surface of the position to be checked. By limiting the
+ * search radius to delta 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)delta;
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);
+ /* Check path consistency */
+ scene_get_enclosure_ids(scn, hit.prim.prim_id, enc_ids);
side = XD(compute_hit_side)(&hit, pos);
- mdm = side == SDIS_FRONT ? interf->medium_front : interf->medium_back;
- if(mdm != expected_medium) {
+ if(enc_ids[side] != expected_enc_id) {
res = RES_BAD_ARG;
goto error;
}
@@ -258,15 +330,14 @@ static res_T
XD(setup_hit_wos)
(struct sdis_scene* scn,
const struct sXd(hit)* hit,
- struct XD(rwalk)* rwalk)
+ struct rwalk* rwalk)
{
/* Geometry */
struct sXd(primitive) prim;
struct sXd(attrib) attr;
/* Properties */
- struct sdis_interface* interf = NULL;
- struct sdis_medium* mdm = NULL;
+ unsigned enc_ids[2] = {ENCLOSURE_ID_NULL, ENCLOSURE_ID_NULL};
enum sdis_side side = SDIS_SIDE_NULL__;
/* Miscellaneous */
@@ -288,13 +359,12 @@ XD(setup_hit_wos)
dX_set_fX(tgt, attr.value);
side = XD(compute_hit_side)(hit, rwalk->vtx.P);
- /* Fetch interface properties and check path consistency */
- interf = scene_get_interface(scn, hit->prim.prim_id);
- mdm = side == SDIS_FRONT ? interf->medium_front : interf->medium_back;
- if(mdm != rwalk->mdm) {
+ /* Check path consistency */
+ scene_get_enclosure_ids(scn, hit->prim.prim_id, enc_ids);
+ if(enc_ids[side] != rwalk->enc_id) {
log_err(scn->dev,
- "%s:%s: the conductive path has reached an invalid interface; "
- "unexpected medium (position: "FORMAT_VECX"; side: %s).\n",
+ "%s:%s: the conductive path has reached an invalid interface. "
+ "Unexpected enclosure -- pos=("FORMAT_VECX"), side=%s\n",
__FILE__, FUNC_NAME, SPLITX(tgt), side == SDIS_FRONT ? "front" : "back");
res = RES_BAD_OP_IRRECOVERABLE;
goto error;
@@ -305,7 +375,7 @@ XD(setup_hit_wos)
* the interface. So we can't yet assume that the random walk has left the
* current medium */
dX(set)(rwalk->vtx.P, tgt);
- rwalk->hit = *hit;
+ rwalk->XD(hit) = *hit;
rwalk->hit_side = side;
exit:
@@ -320,11 +390,10 @@ XD(setup_hit_rt)
const double pos[DIM],
const double dir[DIM],
const struct sXd(hit)* hit,
- struct XD(rwalk)* rwalk)
+ struct rwalk* rwalk)
{
/* Properties */
- struct sdis_interface* interf = NULL;
- struct sdis_medium* mdm = NULL;
+ unsigned enc_ids[2] = {ENCLOSURE_ID_NULL, ENCLOSURE_ID_NULL};
enum sdis_side side = SDIS_SIDE_NULL__;
/* Miscellaneous */
@@ -344,12 +413,11 @@ XD(setup_hit_rt)
side = dX(dot)(N, dir) > 0 ? SDIS_BACK : SDIS_FRONT;
/* Fetch interface properties and check path consistency */
- interf = scene_get_interface(scn, hit->prim.prim_id);
- mdm = side == SDIS_FRONT ? interf->medium_front : interf->medium_back;
- if(mdm != rwalk->mdm) {
+ scene_get_enclosure_ids(scn, hit->prim.prim_id, enc_ids);
+ if(enc_ids[side] != rwalk->enc_id) {
log_err(scn->dev,
- "%s:%s: the conductive path has reached an invalid interface; "
- "unexpected medium (position: "FORMAT_VECX"; side: %s).\n",
+ "%s:%s: the conductive path has reached an invalid interface. "
+ "Unexpected enclosure -- pos=("FORMAT_VECX"), side=%s\n",
__FILE__, FUNC_NAME, SPLITX(tgt), side == SDIS_FRONT ? "front" : "back");
res = RES_BAD_OP_IRRECOVERABLE;
goto error;
@@ -360,7 +428,7 @@ XD(setup_hit_rt)
* the interface. So we can't yet assume that the random walk has left the
* current medium */
dX(set)(rwalk->vtx.P, tgt);
- rwalk->hit = *hit;
+ rwalk->XD(hit) = *hit;
rwalk->hit_side = side;
exit:
@@ -372,8 +440,9 @@ error:
static res_T
XD(sample_next_position)
(struct sdis_scene* scn,
- struct XD(rwalk)* rwalk,
+ struct rwalk* rwalk,
struct ssp_rng* rng,
+ const double delta, /* Used to adjust thresholds */
double* distance) /* Displacement distance */
{
/* Intersection */
@@ -396,9 +465,9 @@ XD(sample_next_position)
CHK(!SXD_HIT_NONE(&hit));
wos_distance = hit.distance;
- /* The current position is in the epsilon shell:
+ /* The current position is in the epsilon shell, i.e. 1% of delta:
* move it to the nearest interface position */
- wos_epsilon = scn->fp_to_meter*1.e-6;
+ wos_epsilon = delta*1.e-2;
if(wos_distance <= wos_epsilon) {
res = XD(setup_hit_wos)(scn, &hit, rwalk);
if(res != RES_OK) goto error;
@@ -425,7 +494,7 @@ XD(sample_next_position)
* The next diffusion step would then detect an error. This is why we use a
* new function based on the same geometric operator used in the present
* algorithm. */
- res = XD(check_diffusion_position)(scn, rwalk->mdm, pos);
+ res = XD(check_diffusion_position)(scn, rwalk->enc_id, delta, pos);
/* Diffusion position is valid => move the path to the new position */
if(res == RES_OK) {
@@ -459,8 +528,8 @@ XD(sample_next_position)
* we don't care to save it. */
if(SXD_HIT_NONE(&hit)) {
log_err(scn->dev,
- "%s:%s: unable to find the next diffusion position "
- "(position: "FORMAT_VECX"; direction: "FORMAT_VECX"; distance: %g\n",
+ "%s:%s: unable to find the next diffusion position -- "
+ "position=("FORMAT_VECX"), direction=("FORMAT_VECX"), distance=%g\n",
__FILE__, FUNC_NAME, SPLITX(pos), SPLITX(dir), wos_distance);
res = RES_BAD_OP_IRRECOVERABLE;
goto error;
@@ -478,67 +547,6 @@ error:
goto exit;
}
-static res_T
-XD(handle_volumic_power_wos)
- (struct sdis_scene* scn,
- const struct solid_props* props,
- const double distance, /* [m/fp_to_meter] */
- double* power_term,
- struct XD(temperature)* T)
-{
- double dst = distance * scn->fp_to_meter; /* [m] */
- double term = 0;
- res_T res = RES_OK;
- ASSERT(scn && props && distance >= 0 && power_term && T);
-
- if(props->power == SDIS_VOLUMIC_POWER_NONE) goto exit;
-
- /* No displacement => no power density */
- if(distance == 0) goto exit;
-
- term = dst*dst / (2*DIM*props->lambda);
- T->value += props->power * term;
-
-exit:
- *power_term = term;
- return res;
-}
-
-static res_T
-XD(update_green_path)
- (struct green_path_handle* green_path,
- struct XD(rwalk)* rwalk,
- struct sdis_medium* mdm,
- const struct solid_props* props,
- const double power_term,
- const struct XD(temperature)* T)
-{
- res_T res = RES_OK;
- ASSERT(mdm && props && T);
-
- /* Is the green function estimated? */
- if(!green_path) goto exit;
-
- /* Save power term for green function if any */
- if(props->power != SDIS_VOLUMIC_POWER_NONE) {
- res = green_path_add_power_term(green_path, mdm, &rwalk->vtx, power_term);
- if(res != RES_OK) goto error;
- }
-
- /* Set the green path limit to the current position if the initial condition
- * has been reached */
- if(T->done) {
- res = green_path_set_limit_vertex
- (green_path, mdm, &rwalk->vtx, rwalk->elapsed_time);
- if(res != RES_OK) goto error;
- }
-
-exit:
- return res;
-error:
- goto exit;
-}
-
/*******************************************************************************
* Local function
******************************************************************************/
@@ -546,11 +554,12 @@ res_T
XD(conductive_path_wos)
(struct sdis_scene* scn,
struct rwalk_context* ctx,
- struct XD(rwalk)* rwalk,
+ struct rwalk* rwalk,
struct ssp_rng* rng,
- struct XD(temperature)* T)
+ struct temperature* T)
{
/* Properties */
+ const struct enclosure* enc = NULL;
struct sdis_medium* mdm = NULL;
struct solid_props props_ref = SOLID_PROPS_NULL;
struct solid_props props = SOLID_PROPS_NULL;
@@ -566,18 +575,18 @@ XD(conductive_path_wos)
/* Check pre-conditions */
ASSERT(scn && ctx && rwalk && rng && T);
- ASSERT(sdis_medium_get_type(rwalk->mdm) == SDIS_SOLID);
/* Is green evaluated evaluated */
green = ctx->green_path != NULL;
- /* Keep track of the solid. After conduction, a boundary may have been
- * reached, so the random walk medium is NULL. However, this medium is still
- * needed to update the green path. Hence this backup */
- mdm = rwalk->mdm;
+ res = XD(check_enclosure_consistency)(scn, rwalk);
+ if(res != RES_OK) goto error;
- res = XD(check_medium_consistency)(scn, rwalk);
+ /* Get the enclosure medium */
+ enc = scene_get_enclosure(scn, rwalk->enc_id);
+ res = scene_get_enclosure_medium(scn, enc, &mdm);
if(res != RES_OK) goto error;
+ ASSERT(sdis_medium_get_type(mdm) == SDIS_SOLID);
/* Retrieve the solid properties at the current position. Use them to verify
* that those that are supposed to be constant by the conductive random walk
@@ -588,7 +597,7 @@ XD(conductive_path_wos)
* position. By comparing them to the properties along the random walk, we
* thus verify that the properties are constant throughout the random walk
* with respect to the properties of the reinjected position. */
- solid_get_properties(rwalk->mdm, &rwalk->vtx, &props_ref);
+ solid_get_properties(mdm, &rwalk->vtx, &props_ref);
props = props_ref;
/* The algorithm assumes that lambda, rho and cp are constants. The
@@ -598,6 +607,7 @@ XD(conductive_path_wos)
/* Sample a diffusive path */
for(;;) {
double power_term = 0; /* */
+ double pos[3] = {0,0,0}; /* Position before diffusive step */
double dst = 0; /* [m/fp_to_meter] */
/* Register the new vertex against the heat path */
@@ -615,12 +625,14 @@ XD(conductive_path_wos)
break;
}
+ d3_set(pos, rwalk->vtx.P);
+
/* Find the next position of the conductive path */
- res = XD(sample_next_position)(scn, rwalk, rng, &dst);
+ res = XD(sample_next_position)(scn, rwalk, rng, props.delta, &dst);
if(res != RES_OK) goto error;
/* Going back in time */
- res = XD(time_travel)(scn, rwalk, rng, alpha, props.t0, &dst, T);
+ res = XD(time_travel)(scn, rwalk, rng, mdm, alpha, props.t0, pos, &dst, T);
if(res != RES_OK) goto error;
/* Add the volumic power density */
@@ -639,16 +651,16 @@ XD(conductive_path_wos)
}
/* The path reaches a boundary */
- if(!SXD_HIT_NONE(&rwalk->hit)) {
+ if(!SXD_HIT_NONE(&rwalk->XD(hit))) {
T->func = XD(boundary_path);
- rwalk->mdm = NULL;
+ rwalk->enc_id = ENCLOSURE_ID_NULL;
break;
}
#undef REGISTER_VERTEX
/* Retreive and check solid properties at the new position */
- res = solid_get_properties(rwalk->mdm, &rwalk->vtx, &props);
+ res = solid_get_properties(mdm, &rwalk->vtx, &props);
if(res != RES_OK) goto error;
res = check_solid_constant_properties(scn->dev, green, wos, &props_ref, &props);
if(res != RES_OK) goto error;
@@ -657,7 +669,7 @@ XD(conductive_path_wos)
}
/* Save green function data */
- res = XD(update_green_path)
+ res = update_green_path
(ctx->green_path, rwalk, mdm, &props_ref, green_power_term, T);
exit:
diff --git a/src/sdis_heat_path_convective_Xd.h b/src/sdis_heat_path_convective_Xd.h
@@ -66,57 +66,19 @@ error:
* Helper functions
******************************************************************************/
static res_T
-XD(register_heat_vertex_in_fluid)
- (struct sdis_scene* scn,
- struct rwalk_context* ctx,
- struct XD(rwalk)* rwalk,
- const double weight)
-{
- struct sdis_rwalk_vertex vtx = SDIS_RWALK_VERTEX_NULL;
- struct hit_filter_data filter_data = HIT_FILTER_DATA_NULL;
- const float empirical_dst = 0.1f;
- const float range[2] = {0, FLT_MAX};
- float org[DIM];
- float dir[DIM];
- float pos[DIM];
- float dst;
- struct sXd(hit) hit;
-
- if(!ctx->heat_path) return RES_OK;
-
- ASSERT(!SXD_HIT_NONE(&rwalk->hit));
-
- fX_set_dX(org, rwalk->vtx.P);
- fX(set)(dir, rwalk->hit.normal);
- if(rwalk->hit_side == SDIS_BACK) fX(minus)(dir, dir);
-
- filter_data.XD(hit) = rwalk->hit;
- filter_data.epsilon = 1.e-6;
- SXD(scene_view_trace_ray(scn->sXd(view), org, dir, range, &filter_data, &hit));
- dst = SXD_HIT_NONE(&hit) ? empirical_dst : hit.distance * 0.5f;
-
- vtx = rwalk->vtx;
- fX(add)(pos, org, fX(mulf)(dir, dir, dst));
- dX_set_fX(vtx.P, pos);
-
- return register_heat_vertex(ctx->heat_path, &vtx, weight,
- SDIS_HEAT_VERTEX_CONVECTION, (int)ctx->nbranchings);
-}
-
-static res_T
XD(handle_known_fluid_temperature)
- (struct sdis_scene* scn,
- struct rwalk_context* ctx,
- struct XD(rwalk)* rwalk,
- struct XD(temperature)* T)
+ (struct rwalk_context* ctx,
+ struct rwalk* rwalk,
+ struct sdis_medium* mdm,
+ struct temperature* T)
{
double temperature;
int known_temperature;
res_T res = RES_OK;
- ASSERT(scn && ctx && rwalk && T);
- ASSERT(sdis_medium_get_type(rwalk->mdm) == SDIS_FLUID);
+ ASSERT(ctx && rwalk && T);
+ ASSERT(sdis_medium_get_type(mdm) == SDIS_FLUID);
- temperature = fluid_get_temperature(rwalk->mdm, &rwalk->vtx);
+ temperature = fluid_get_temperature(mdm, &rwalk->vtx);
/* Check if the temperature is known */
known_temperature = SDIS_TEMPERATURE_IS_KNOWN(temperature);
@@ -127,12 +89,13 @@ XD(handle_known_fluid_temperature)
if(ctx->green_path) {
res = green_path_set_limit_vertex
- (ctx->green_path, rwalk->mdm, &rwalk->vtx, rwalk->elapsed_time);
+ (ctx->green_path, mdm, &rwalk->vtx, rwalk->elapsed_time);
if(res != RES_OK) goto error;
}
- res = XD(register_heat_vertex_in_fluid)(scn, ctx, rwalk, T->value);
- if(res != RES_OK) goto error;
+ if(ctx->heat_path) {
+ heat_path_get_last_vertex(ctx->heat_path)->weight = T->value;
+ }
exit:
return res;
@@ -143,7 +106,7 @@ error:
static res_T
XD(handle_convective_path_startup)
(struct sdis_scene* scn,
- struct XD(rwalk)* rwalk,
+ struct rwalk* rwalk,
int* path_starts_in_fluid)
{
const float range[2] = {FLT_MIN, FLT_MAX};
@@ -151,9 +114,8 @@ XD(handle_convective_path_startup)
float org[DIM] = {0};
res_T res = RES_OK;
ASSERT(scn && rwalk && path_starts_in_fluid);
- ASSERT(sdis_medium_get_type(rwalk->mdm) == SDIS_FLUID);
- *path_starts_in_fluid = SXD_HIT_NONE(&rwalk->hit);
+ *path_starts_in_fluid = SXD_HIT_NONE(&rwalk->XD(hit));
if(*path_starts_in_fluid == 0) goto exit; /* Nothing to do */
dir[DIM-1] = 1;
@@ -161,8 +123,8 @@ XD(handle_convective_path_startup)
/* Init the path hit field required to define the current enclosure and
* fetch the interface data */
- SXD(scene_view_trace_ray(scn->sXd(view), org, dir, range, NULL, &rwalk->hit));
- if(SXD_HIT_NONE(&rwalk->hit)) {
+ SXD(scene_view_trace_ray(scn->sXd(view), org, dir, range, NULL, &rwalk->XD(hit)));
+ if(SXD_HIT_NONE(&rwalk->XD(hit))) {
log_err(scn->dev,
"%s: the position %g %g %g lies in the surrounding fluid whose "
"temperature must be known.\n", FUNC_NAME, SPLIT3(rwalk->vtx.P));
@@ -170,7 +132,8 @@ XD(handle_convective_path_startup)
goto error;
}
- rwalk->hit_side = fX(dot)(rwalk->hit.normal, dir) < 0 ? SDIS_FRONT : SDIS_BACK;
+ rwalk->hit_side = fX(dot)(rwalk->XD(hit).normal, dir) < 0
+ ? SDIS_FRONT : SDIS_BACK;
exit:
return res;
@@ -179,54 +142,28 @@ error:
}
static res_T
-XD(fetch_fluid_enclosure)
+XD(check_enclosure)
(struct sdis_scene* scn,
- struct XD(rwalk)* rwalk,
- const struct enclosure** out_enclosure)
+ const struct rwalk* rwalk,
+ const struct enclosure* enc)
{
- const struct sdis_interface* interf;
- const struct enclosure* enc;
- unsigned enc_ids[2];
- unsigned enc_id;
res_T res = RES_OK;
- ASSERT(scn && rwalk && out_enclosure);
- ASSERT(sdis_medium_get_type(rwalk->mdm) == SDIS_FLUID);
- ASSERT(!SXD_HIT_NONE(&rwalk->hit));
-
- /* Fetch the current interface and its associated enclosures */
- interf = scene_get_interface(scn, rwalk->hit.prim.prim_id);
- scene_get_enclosure_ids(scn, rwalk->hit.prim.prim_id, enc_ids);
-
- /* Find the enclosure identifier of the current medium */
- ASSERT(interf->medium_front != interf->medium_back);
- if(rwalk->mdm == interf->medium_front) {
- enc_id = enc_ids[0];
- ASSERT(rwalk->hit_side == SDIS_FRONT);
- } else {
- ASSERT(rwalk->mdm == interf->medium_back);
- enc_id = enc_ids[1];
- ASSERT(rwalk->hit_side == SDIS_BACK);
- }
+ ASSERT(scn && rwalk && enc);
- /* Fetch the enclosure data */
- enc = scene_get_enclosure(scn, enc_id);
- ASSERT(enc != NULL);
- if(enc->medium_id == ENCLOSURE_MULTI_MEDIA) {
+ if(enc->medium_id == MEDIUM_ID_MULTI) {
/* The enclosures with multiple media are used to describe limit
* conditions and therefore they cannot be fetched */
log_err(scn->dev,
- "%s: enclosure with multiple media at {%g, %g, %g}. "
- "Path should be reached a limit condition before.\n",
- FUNC_NAME, rwalk->vtx.P[0], rwalk->vtx.P[1], DIM==3 ? rwalk->vtx.P[2]:0);
+ "%s: enclosure with multiple media at ("FORMAT_VECX"). "
+ "The path should be reached a limit condition before.\n",
+ FUNC_NAME, SPLITX(rwalk->vtx.P));
res = RES_BAD_ARG;
goto error;
}
exit:
- *out_enclosure = enc;
return res;
error:
- enc = NULL;
goto exit;
}
@@ -237,14 +174,22 @@ res_T
XD(convective_path)
(struct sdis_scene* scn,
struct rwalk_context* ctx,
- struct XD(rwalk)* rwalk,
+ struct rwalk* rwalk,
struct ssp_rng* rng,
- struct XD(temperature)* T)
+ struct temperature* T)
{
- struct sXd(attrib) attr_P, attr_N;
+ /* Properties */
struct fluid_props props_ref = FLUID_PROPS_NULL;
- const struct sdis_interface* interf;
- const struct enclosure* enc;
+ const struct sdis_interface* interf = NULL;
+ struct sdis_medium* mdm = NULL;
+
+ /* Enclosure */
+ unsigned enc_ids[2] = {ENCLOSURE_ID_NULL, ENCLOSURE_ID_NULL};
+ const struct enclosure* enc = NULL;
+
+ /* Miscellaneous */
+ struct sXd(attrib) attr_P, attr_N;
+ struct sXd(hit)* rwalk_hit = NULL;
double r;
#if SDIS_XD_DIMENSION == 2
float st;
@@ -253,11 +198,19 @@ XD(convective_path)
#endif
int path_starts_in_fluid;
res_T res = RES_OK;
- (void)rng, (void)ctx;
+
ASSERT(scn && ctx && rwalk && rng && T);
- ASSERT(rwalk->mdm->type == SDIS_FLUID);
+ (void)rng, (void)ctx; /* Avoid "unsued variable" warnings */
- res = XD(handle_known_fluid_temperature)(scn, ctx, rwalk, T);
+ rwalk_hit = &rwalk->XD(hit);
+
+ /* Get the enclosure medium */
+ enc = scene_get_enclosure(scn, rwalk->enc_id);
+ if((res = XD(check_enclosure)(scn, rwalk, enc)) != RES_OK) goto error;
+ if((res = scene_get_enclosure_medium(scn, enc, &mdm)) != RES_OK) goto error;
+ ASSERT(sdis_medium_get_type(mdm) == SDIS_FLUID);
+
+ res = XD(handle_known_fluid_temperature)(ctx, rwalk, mdm, T);
if(res != RES_OK) goto error;
if(T->done) goto exit; /* The fluid temperature is known */
@@ -266,13 +219,10 @@ XD(convective_path)
res = XD(handle_convective_path_startup)(scn, rwalk, &path_starts_in_fluid);
if(res != RES_OK) goto error;
- res = XD(fetch_fluid_enclosure)(scn, rwalk, &enc);
- if(res != RES_OK) goto error;
-
/* Retrieve the fluid properties at the current position. Use them to verify
* that those that are supposed to be constant by the convective random walk
* remain the same. */
- res = fluid_get_properties(rwalk->mdm, &rwalk->vtx, &props_ref);
+ res = fluid_get_properties(mdm, &rwalk->vtx, &props_ref);
if(res != RES_OK) goto error;
/* The hc upper bound can be 0 if h is uniformly 0. In that case the result
@@ -280,7 +230,7 @@ XD(convective_path)
if(enc->hc_upper_bound == 0) {
ASSERT(path_starts_in_fluid); /* Cannot be in the fluid without starting there. */
rwalk->vtx.time = props_ref.t0;
- res = XD(handle_known_fluid_temperature)(scn, ctx, rwalk, T);
+ res = XD(handle_known_fluid_temperature)(ctx, rwalk, mdm, T);
if(res != RES_OK) goto error;
if(T->done) {
goto exit; /* Stop the random walk */
@@ -300,7 +250,7 @@ XD(convective_path)
double mu;
/* Fetch fluid properties */
- res = fluid_get_properties(rwalk->mdm, &rwalk->vtx, &props);
+ res = fluid_get_properties(mdm, &rwalk->vtx, &props);
if(res != RES_OK) goto error;
res = check_fluid_constant_properties(scn->dev, &props_ref, &props);
@@ -308,7 +258,7 @@ XD(convective_path)
/* Sample the time using the upper bound. */
mu = enc->hc_upper_bound / (props.rho * props.cp) * enc->S_over_V;
- res = XD(time_rewind)(mu, props.t0, rng, rwalk, ctx, T);
+ res = time_rewind(scn, mu, props.t0, rng, rwalk, ctx, T);
if(res != RES_OK) goto error;
if(T->done) break; /* Limit condition was reached */
@@ -318,44 +268,47 @@ XD(convective_path)
(enc->sXd(view),
ssp_rng_canonical_float(rng),
ssp_rng_canonical_float(rng),
- &prim, &rwalk->hit.u));
- st = rwalk->hit.u;
+ &prim, &rwalk_hit->u));
+ st = rwalk_hit->u;
#else
SXD(scene_view_sample
(enc->sXd(view),
ssp_rng_canonical_float(rng),
ssp_rng_canonical_float(rng),
ssp_rng_canonical_float(rng),
- &prim, rwalk->hit.uv));
- f2_set(st, rwalk->hit.uv);
+ &prim, rwalk_hit->uv));
+ f2_set(st, rwalk_hit->uv);
#endif
/* Map the sampled primitive id from the enclosure space to the scene
* space. Note that the overall scene has only one shape. As a consequence
* neither the geom_id nor the inst_id needs to be updated */
- rwalk->hit.prim.prim_id = enclosure_local2global_prim_id(enc, prim.prim_id);
+ rwalk_hit->prim.prim_id = enclosure_local2global_prim_id(enc, prim.prim_id);
- SXD(primitive_get_attrib(&rwalk->hit.prim, SXD_POSITION, st, &attr_P));
- SXD(primitive_get_attrib(&rwalk->hit.prim, SXD_GEOMETRY_NORMAL, st, &attr_N));
+ SXD(primitive_get_attrib(&rwalk_hit->prim, SXD_POSITION, st, &attr_P));
+ SXD(primitive_get_attrib(&rwalk_hit->prim, SXD_GEOMETRY_NORMAL, st, &attr_N));
dX_set_fX(rwalk->vtx.P, attr_P.value);
- fX(set)(rwalk->hit.normal, attr_N.value);
+ fX(set)(rwalk_hit->normal, attr_N.value);
- /* Fetch the interface of the sampled point. */
- interf = scene_get_interface(scn, rwalk->hit.prim.prim_id);
- if(rwalk->mdm == interf->medium_front) {
- rwalk->hit_side = SDIS_FRONT;
- } else if(rwalk->mdm == interf->medium_back) {
+ /* Define the interface side */
+ scene_get_enclosure_ids(scn, rwalk_hit->prim.prim_id, enc_ids);
+ if(rwalk->enc_id == enc_ids[SDIS_BACK]) {
rwalk->hit_side = SDIS_BACK;
+ } else if(rwalk->enc_id == enc_ids[SDIS_FRONT]) {
+ rwalk->hit_side = SDIS_FRONT;
} else {
- FATAL("Unexpected fluid interface.\n");
+ FATAL("Unexpected fluid interface\n");
}
+ /* Get the interface properties */
+ interf = scene_get_interface(scn, rwalk_hit->prim.prim_id);
+
/* Register the new vertex against the heat path */
res = register_heat_vertex(ctx->heat_path, &rwalk->vtx, T->value,
SDIS_HEAT_VERTEX_CONVECTION, (int)ctx->nbranchings);
if(res != RES_OK) goto error;
/* Setup the fragment of the sampled position into the enclosure. */
- XD(setup_interface_fragment)(&frag, &rwalk->vtx, &rwalk->hit, rwalk->hit_side);
+ XD(setup_interface_fragment)(&frag, &rwalk->vtx, rwalk_hit, rwalk->hit_side);
/* Fetch the convection coefficient of the sampled position */
hc = interface_get_convection_coef(interf, &frag);
@@ -374,9 +327,9 @@ XD(convective_path)
}
}
- rwalk->hit.distance = 0;
+ rwalk_hit->distance = 0;
T->func = XD(boundary_path);
- rwalk->mdm = NULL; /* The random walk is at an interface between 2 media */
+ rwalk->enc_id = ENCLOSURE_ID_NULL; /* Interface between 2 enclosures */
exit:
return res;
diff --git a/src/sdis_heat_path_radiative_Xd.h b/src/sdis_heat_path_radiative_Xd.h
@@ -35,9 +35,9 @@ XD(trace_radiative_path)
(struct sdis_scene* scn,
const float ray_dir[3],
struct rwalk_context* ctx,
- struct XD(rwalk)* rwalk,
+ struct rwalk* rwalk,
struct ssp_rng* rng,
- struct XD(temperature)* T)
+ struct temperature* T)
{
/* The radiative random walk is always performed in 3D. In 2D, the geometry
* are assumed to be extruded to the infinity along the Z dimension. */
@@ -56,9 +56,11 @@ XD(trace_radiative_path)
/* Launch the radiative random walk */
for(;;) {
const struct sdis_interface* interf = NULL;
+ struct sdis_medium* chk_mdm = NULL;
struct hit_filter_data filter_data = HIT_FILTER_DATA_NULL;
struct sdis_interface_fragment frag = SDIS_INTERFACE_FRAGMENT_NULL;
- struct sdis_medium* chk_mdm = NULL;
+ unsigned enc_ids[2] = {ENCLOSURE_ID_NULL, ENCLOSURE_ID_NULL};
+ unsigned chk_enc_id = ENCLOSURE_ID_NULL;
double alpha;
double epsilon;
double r;
@@ -68,16 +70,16 @@ XD(trace_radiative_path)
fX_set_dX(pos, rwalk->vtx.P);
/* Trace the radiative ray */
- filter_data.XD(hit) = rwalk->hit;
+ filter_data.XD(hit) = rwalk->XD(hit);
filter_data.epsilon = 1.e-6;
#if (SDIS_XD_DIMENSION == 2)
SXD(scene_view_trace_ray_3d
- (scn->sXd(view), pos, dir, range, &filter_data, &rwalk->hit));
+ (scn->sXd(view), pos, dir, range, &filter_data, &rwalk->XD(hit)));
#else
SXD(scene_view_trace_ray
- (scn->sXd(view), pos, dir, range, &filter_data, &rwalk->hit));
+ (scn->sXd(view), pos, dir, range, &filter_data, &rwalk->XD(hit)));
#endif
- if(SXD_HIT_NONE(&rwalk->hit)) { /* Fetch the ambient radiative temperature */
+ if(SXD_HIT_NONE(&rwalk->XD(hit))) { /* Fetch the ambient radiative temperature */
struct sdis_radiative_ray ray = SDIS_RADIATIVE_RAY_NULL;
double trad = 0; /* [K] */
@@ -127,11 +129,11 @@ XD(trace_radiative_path)
}
/* Define the hit side */
- rwalk->hit_side = fX(dot)(dir, rwalk->hit.normal) < 0
+ rwalk->hit_side = fX(dot)(dir, rwalk->XD(hit).normal) < 0
? SDIS_FRONT : SDIS_BACK;
/* Move the random walk to the hit position */
- XD(move_pos)(rwalk->vtx.P, dir, rwalk->hit.distance);
+ XD(move_pos)(rwalk->vtx.P, dir, rwalk->XD(hit).distance);
/* Register the random walk vertex against the heat path */
res = register_heat_vertex(ctx->heat_path, &rwalk->vtx, T->value,
@@ -139,8 +141,8 @@ XD(trace_radiative_path)
if(res != RES_OK) goto error;
/* Fetch the new interface and setup the hit fragment */
- interf = scene_get_interface(scn, rwalk->hit.prim.prim_id);
- XD(setup_interface_fragment)(&frag, &rwalk->vtx, &rwalk->hit, rwalk->hit_side);
+ interf = scene_get_interface(scn, rwalk->XD(hit).prim.prim_id);
+ XD(setup_interface_fragment)(&frag, &rwalk->vtx, &rwalk->XD(hit), rwalk->hit_side);
/* Fetch the interface emissivity */
epsilon = interface_side_get_emissivity(interf, SDIS_INTERN_SOURCE_ID, &frag);
@@ -156,35 +158,46 @@ XD(trace_radiative_path)
r = ssp_rng_canonical(rng);
if(r < epsilon) {
T->func = XD(boundary_path);
- rwalk->mdm = NULL; /* The random walk is at an interface between 2 media */
+ rwalk->enc_id = ENCLOSURE_ID_NULL; /* Interface between 2 enclosures */
break;
}
/* Normalize the normal of the interface and ensure that it points toward the
* current medium */
- fX(normalize)(N, rwalk->hit.normal);
- if(rwalk->hit_side == SDIS_BACK){
- chk_mdm = interf->medium_back;
- fX(minus)(N, N);
- } else {
- chk_mdm = interf->medium_front;
+ fX(normalize)(N, rwalk->XD(hit).normal);
+ if(rwalk->hit_side == SDIS_BACK) fX(minus)(N, N);
+
+ /* Check that the radiative path still lies in the same enclosure */
+ scene_get_enclosure_ids(scn, rwalk->XD(hit).prim.prim_id, enc_ids);
+ chk_enc_id = rwalk->hit_side == SDIS_FRONT ? enc_ids[0] : enc_ids[1];
+ if(chk_enc_id != rwalk->enc_id) {
+ log_warn(scn->dev,
+ "%s: the radiative path has escaped from its cavity -- pos=(%g, %g, %g)\n",
+ FUNC_NAME, SPLIT3(rwalk->vtx.P));
+ res = RES_BAD_OP;
+ goto error;
}
- if(chk_mdm != rwalk->mdm) {
- /* To ease the setting of models, the external enclosure is allowed to be
- * incoherent regarding media. Here a radiative path is allowed to join
- * 2 different fluids. */
- const int outside = scene_is_outside
- (scn, rwalk->hit_side, rwalk->hit.prim.prim_id);
- if(outside && chk_mdm->type == SDIS_FLUID) {
- rwalk->mdm = chk_mdm;
- } else {
- log_warn(scn->dev, "%s: inconsistent medium definition at `%g %g %g'.\n",
- FUNC_NAME, SPLIT3(rwalk->vtx.P));
- res = RES_BAD_OP;
- goto error;
- }
+ /* Verify that the intersection, although in the same enclosure, touches the
+ * interface of a fluid. We verify this by interface, since a radiative path
+ * can be traced in an enclosure containing several media used to describe a
+ * set of boundary conditions.
+ *
+ * If the enclosure is good but the media type is not, this means that the
+ * radiative path is sampled in the wrong media. This is not a numerical
+ * problem, but a user problem: trying to sample a radiative path in a solid
+ * when semi-transparent solids are not yet supported by Stardis. This error
+ * is therefore fatal for the calculation */
+ chk_mdm = rwalk->hit_side == SDIS_FRONT
+ ? interf->medium_front : interf->medium_back;
+ if(sdis_medium_get_type(chk_mdm) == SDIS_SOLID) {
+ log_err(scn->dev,
+ "%s: a radiative path cannot evolve in a solid -- pos=(%g, %g, %g)\n",
+ FUNC_NAME, SPLIT3(rwalk->vtx.P));
+ res = RES_BAD_OP_IRRECOVERABLE;
+ goto error;
}
+
alpha = interface_side_get_specular_fraction(interf, SDIS_INTERN_SOURCE_ID, &frag);
r = ssp_rng_canonical(rng);
if(r < alpha) { /* Sample specular part */
@@ -204,9 +217,9 @@ res_T
XD(radiative_path)
(struct sdis_scene* scn,
struct rwalk_context* ctx,
- struct XD(rwalk)* rwalk,
+ struct rwalk* rwalk,
struct ssp_rng* rng,
- struct XD(temperature)* T)
+ struct temperature* T)
{
/* The radiative random walk is always performed in 3D. In 2D, the geometry
* are assumed to be extruded to the infinity along the Z dimension. */
@@ -215,11 +228,11 @@ XD(radiative_path)
res_T res = RES_OK;
ASSERT(scn && ctx && rwalk && rng && T);
- ASSERT(!SXD_HIT_NONE(&rwalk->hit));
+ ASSERT(!SXD_HIT_NONE(&rwalk->XD(hit)));
/* Normalize the normal of the interface and ensure that it points toward the
* current medium */
- fX(normalize(N, rwalk->hit.normal));
+ fX(normalize(N, rwalk->XD(hit).normal));
if(rwalk->hit_side == SDIS_BACK) {
fX(minus(N, N));
}
diff --git a/src/sdis_log.h b/src/sdis_log.h
@@ -28,6 +28,8 @@
#define MSG_ERROR_PREFIX_PLAIN_TEXT "stardis-solver (error): "
#define MSG_WARNING_PREFIX_PLAIN_TEXT "stardis-solver (warning): "
+struct sdis_device;
+
extern LOCAL_SYM res_T
setup_log_default
(struct sdis_device* dev);
diff --git a/src/sdis_misc.c b/src/sdis_misc.c
@@ -14,12 +14,85 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>. */
#include "sdis.h"
+#include "sdis_heat_path.h"
+#include "sdis_log.h"
+#include "sdis_medium_c.h"
+#include "sdis_misc.h"
+#include "sdis_green.h"
-/* Generate the generic functions */
-#define SDIS_XD_DIMENSION 2
-#include "sdis_misc_Xd.h"
-#define SDIS_XD_DIMENSION 3
-#include "sdis_misc_Xd.h"
+#include <star/ssp.h>
+
+res_T
+time_rewind
+ (struct sdis_scene* scn,
+ const double mu,
+ const double t0,
+ struct ssp_rng* rng,
+ struct rwalk* rwalk,
+ const struct rwalk_context* ctx,
+ struct temperature* T)
+{
+ const struct enclosure* enc = NULL;
+ struct sdis_medium* mdm = NULL;
+ double temperature;
+ double tau;
+ res_T res = RES_OK;
+ ASSERT(scn && rwalk && ctx && rng && T);
+
+ /* Get the current medium */
+ enc = scene_get_enclosure(scn, rwalk->enc_id);
+ res = scene_get_enclosure_medium(scn, enc, &mdm);
+ if(res != RES_OK) goto error;
+
+ /* Sample the time using the upper bound. */
+ tau = ssp_ran_exp(rng, mu);
+
+ /* Increment the elapsed time */
+ ASSERT(rwalk->vtx.time >= t0);
+ rwalk->elapsed_time += MMIN(tau, rwalk->vtx.time - t0);
+
+ if(IS_INF(rwalk->vtx.time)) goto exit; /* Steady computation */
+
+ /* Time rewind */
+ rwalk->vtx.time = MMAX(rwalk->vtx.time - tau, t0); /* Time rewind */
+
+ /* The path does not reach the limit condition */
+ if(rwalk->vtx.time > t0) goto exit;
+
+ /* Fetch the initial temperature */
+ temperature = medium_get_temperature(mdm, &rwalk->vtx);
+ if(SDIS_TEMPERATURE_IS_UNKNOWN(temperature)) {
+ log_err(mdm->dev, "the path reaches the limit condition but the "
+ "%s temperature remains unknown -- position=%g, %g, %g\n",
+ medium_type_to_string(sdis_medium_get_type(mdm)),
+ SPLIT3(rwalk->vtx.P));
+ res = RES_BAD_ARG;
+ goto error;
+ }
+
+ /* Update temperature */
+ T->value += temperature;
+ T->done = 1;
+
+ if(ctx->heat_path) {
+ /* Update the registered vertex data */
+ struct sdis_heat_vertex* vtx;
+ vtx = heat_path_get_last_vertex(ctx->heat_path);
+ vtx->time = rwalk->vtx.time;
+ vtx->weight = T->value;
+ }
+
+ if(ctx->green_path) {
+ res = green_path_set_limit_vertex
+ (ctx->green_path, mdm, &rwalk->vtx, rwalk->elapsed_time);
+ if(res != RES_OK) goto error;
+ }
+
+exit:
+ return res;
+error:
+ goto exit;
+}
res_T
check_primitive_uv_2d(struct sdis_device* dev, const double param_coord[])
diff --git a/src/sdis_misc.h b/src/sdis_misc.h
@@ -93,6 +93,7 @@ reflect_3d(float res[3], const float V[3], const float N[3])
cos_V_N = f3_dot(V, N);
f3_mulf(tmp, N, 2*cos_V_N);
f3_sub(res, tmp, V);
+ f3_normalize(res, res); /* Handle numerical issue */
return res;
}
@@ -148,22 +149,14 @@ register_heat_vertex
}
extern LOCAL_SYM res_T
-time_rewind_2d
- (const double mu,
+time_rewind
+ (struct sdis_scene* scn,
+ const double mu,
const double t0, /* Initial time */
struct ssp_rng* rng,
- struct rwalk_2d* rwalk,
+ struct rwalk* rwalk,
const struct rwalk_context* ctx,
- struct temperature_2d* T);
-
-extern LOCAL_SYM res_T
-time_rewind_3d
- (const double mu,
- const double t0, /* Initial time */
- struct ssp_rng* rng,
- struct rwalk_3d* rwalk,
- const struct rwalk_context* ctx,
- struct temperature_3d* T);
+ struct temperature* T);
/* Check the validity of the parametric coordinate onto a 2D primitive. If it
* is invalid, the function prints an error message and return RES_BAD_ARG. */
diff --git a/src/sdis_misc_Xd.h b/src/sdis_misc_Xd.h
@@ -1,90 +0,0 @@
-/* Copyright (C) 2016-2024 |Méso|Star> (contact@meso-star.com)
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>. */
-
-#include "sdis_heat_path.h"
-#include "sdis_log.h"
-#include "sdis_medium_c.h"
-#include "sdis_misc.h"
-#include "sdis_green.h"
-
-#include <star/ssp.h>
-
-#include "sdis_Xd_begin.h"
-
-res_T
-XD(time_rewind)
- (const double mu,
- const double t0,
- struct ssp_rng* rng,
- struct XD(rwalk)* rwalk,
- const struct rwalk_context* ctx,
- struct XD(temperature)* T)
-{
- double temperature;
- double tau;
- res_T res = RES_OK;
- ASSERT(rwalk && rng && T);
-
- /* Sample the time using the upper bound. */
- tau = ssp_ran_exp(rng, mu);
-
- /* Increment the elapsed time */
- ASSERT(rwalk->vtx.time >= t0);
- rwalk->elapsed_time += MMIN(tau, rwalk->vtx.time - t0);
-
- if(IS_INF(rwalk->vtx.time)) goto exit; /* Steady computation */
-
- /* Time rewind */
- rwalk->vtx.time = MMAX(rwalk->vtx.time - tau, t0); /* Time rewind */
-
- /* The path does not reach the limit condition */
- if(rwalk->vtx.time > t0) goto exit;
-
- /* Fetch the initial temperature */
- temperature = medium_get_temperature(rwalk->mdm, &rwalk->vtx);
- if(SDIS_TEMPERATURE_IS_UNKNOWN(temperature)) {
- log_err(rwalk->mdm->dev, "the path reaches the limit condition but the "
- "%s temperature remains unknown -- position=%g, %g, %g\n",
- medium_type_to_string(sdis_medium_get_type(rwalk->mdm)),
- SPLIT3(rwalk->vtx.P));
- res = RES_BAD_ARG;
- goto error;
- }
-
- /* Update temperature */
- T->value += temperature;
- T->done = 1;
-
- if(ctx->heat_path) {
- /* Update the registered vertex data */
- struct sdis_heat_vertex* vtx;
- vtx = heat_path_get_last_vertex(ctx->heat_path);
- vtx->time = rwalk->vtx.time;
- vtx->weight = T->value;
- }
-
- if(ctx->green_path) {
- res = green_path_set_limit_vertex(ctx->green_path, rwalk->mdm,
- &rwalk->vtx, rwalk->elapsed_time);
- if(res != RES_OK) goto error;
- }
-
-exit:
- return res;
-error:
- goto exit;
-}
-
-#include "sdis_Xd_end.h"
diff --git a/src/sdis_primkey.c b/src/sdis_primkey.c
@@ -0,0 +1,113 @@
+/* Copyright (C) 2016-2024 |Méso|Star> (contact@meso-star.com)
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+#include "sdis.h"
+
+#include <rsys/double2.h>
+#include <rsys/double3.h>
+
+/*******************************************************************************
+ * Helper functions
+ ******************************************************************************/
+static INLINE int
+cmp_dbl2(const double v0[2], const double v1[2])
+{
+ if(v0[0] < v1[0]) return -1;
+ if(v0[0] > v1[0]) return +1;
+ if(v0[1] < v1[1]) return -1;
+ if(v0[1] > v1[1]) return +1;
+ return 0;
+}
+
+static INLINE int
+cmp_dbl3(const double v0[3], const double v1[3])
+{
+ if(v0[0] < v1[0]) return -1;
+ if(v0[0] > v1[0]) return +1;
+ if(v0[1] < v1[1]) return -1;
+ if(v0[1] > v1[1]) return +1;
+ if(v0[2] < v1[2]) return -1;
+ if(v0[2] > v1[2]) return +1;
+ return 0;
+}
+
+/*******************************************************************************
+ * Exported functions
+ ******************************************************************************/
+void
+sdis_primkey_2d_setup
+ (struct sdis_primkey* key,
+ const double node0[2],
+ const double node1[2])
+{
+ double *v0, *v1;
+ ASSERT(key && node0 && node1);
+ v0 = d2_set(key->nodes+0, node0);
+ v1 = d2_set(key->nodes+2, node1);
+ if(cmp_dbl2(v0, v1) > 0) {
+ SWAP(double, v0[0], v1[0]);
+ SWAP(double, v0[1], v1[1]);
+ }
+ key->ncoords = 4;
+}
+
+void
+sdis_primkey_setup
+ (struct sdis_primkey* key,
+ const double node0[3],
+ const double node1[3],
+ const double node2[3])
+{
+ double *v0, *v1, *v2;
+ ASSERT(key && node0 && node1 && node2);
+ v0 = d3_set(key->nodes+0, node0);
+ v1 = d3_set(key->nodes+3, node1);
+ v2 = d3_set(key->nodes+6, node2);
+
+ /* Bubble sort */
+ #define SWAP_DBL3(V0, V1) { \
+ SWAP(double, (V0)[0], (V1)[0]); \
+ SWAP(double, (V0)[1], (V1)[1]); \
+ SWAP(double, (V0)[2], (V1)[2]); \
+ } (void)0
+ if(cmp_dbl3(v0, v1) > 0) SWAP_DBL3(v0, v1);
+ if(cmp_dbl3(v1, v2) > 0) SWAP_DBL3(v1, v2);
+ if(cmp_dbl3(v0, v1) > 0) SWAP_DBL3(v0, v1);
+ #undef SWAP_DBL3
+ key->ncoords = 9;
+}
+
+size_t
+sdis_primkey_hash(const struct sdis_primkey* key)
+{
+ return hash_fnv64(key->nodes, sizeof(double)*key->ncoords);
+}
+
+char
+sdis_primkey_eq
+ (const struct sdis_primkey* key0,
+ const struct sdis_primkey* key1)
+{
+ unsigned i = 0;
+ ASSERT(key0 && key1);
+
+ if(key0->ncoords != key1->ncoords) return 0;
+ if(key0->ncoords != 4 && key0->ncoords != 9) return 0;
+ if(key1->ncoords != 4 && key1->ncoords != 9) return 0;
+ FOR_EACH(i, 0, key0->ncoords) {
+ if(key0->nodes[i] != key1->nodes[i]) return 0;
+ }
+ return 1;
+}
diff --git a/src/sdis_realisation.c b/src/sdis_realisation.c
@@ -19,16 +19,30 @@
/*******************************************************************************
* Helper functions
******************************************************************************/
-static INLINE int
+static INLINE res_T
check_ray_realisation_args(const struct ray_realisation_args* args)
{
- return args
- && args->rng
- && args->medium
- && args->medium->type == SDIS_FLUID
- && args->time >= 0
- && args->picard_order > 0
- && (unsigned)args->diff_algo < SDIS_DIFFUSION_ALGORITHMS_COUNT__;
+ /* Check pointers */
+ if(!args || !args->rng) return RES_BAD_ARG;
+
+ if(args->time < 0) return RES_BAD_ARG;
+ if(args->picard_order <= 0) return RES_BAD_ARG;
+
+ if((unsigned)args->diff_algo >= SDIS_DIFFUSION_ALGORITHMS_COUNT__) {
+ return RES_BAD_ARG;
+ }
+
+ /* Check the enclosure identifier. Only its validity is checked, not the fact
+ * that the enclosure is a fluid. Even though Stardis doesn't allow you to
+ * sample a radiative path in a solid, we don't query the medium of the
+ * enclosure since it may contain several: querying the medium will therefore
+ * return an error. The type of medium is checked later, when sampling the
+ * radiative path, when it reaches an interface whose medium must be a fluid*/
+ if(args->enc_id == ENCLOSURE_ID_NULL) {
+ return RES_BAD_ARG;
+ }
+
+ return RES_OK;
}
/*******************************************************************************
@@ -47,17 +61,17 @@ ray_realisation_3d
double* weight)
{
struct rwalk_context ctx = RWALK_CONTEXT_NULL;
- struct rwalk_3d rwalk = RWALK_NULL_3d;
- struct temperature_3d T = TEMPERATURE_NULL_3d;
+ struct rwalk rwalk = RWALK_NULL;
+ struct temperature T = TEMPERATURE_NULL;
float dir[3];
res_T res = RES_OK;
- ASSERT(scn && weight && check_ray_realisation_args(args));
+ ASSERT(scn && weight && check_ray_realisation_args(args) == RES_OK);
d3_set(rwalk.vtx.P, args->position);
rwalk.vtx.time = args->time;
- rwalk.hit = S3D_HIT_NULL;
+ rwalk.hit_3d = S3D_HIT_NULL;
rwalk.hit_side = SDIS_SIDE_NULL__;
- rwalk.mdm = args->medium;
+ rwalk.enc_id = args->enc_id;
ctx.heat_path = args->heat_path;
ctx.Tmin = scn->tmin;
@@ -69,7 +83,7 @@ ray_realisation_3d
ctx.max_branchings = args->picard_order - 1;
ctx.irealisation = args->irealisation;
ctx.diff_algo = args->diff_algo;
-
+
f3_set_d3(dir, args->direction);
/* Register the starting position against the heat path */
diff --git a/src/sdis_realisation.h b/src/sdis_realisation.h
@@ -22,11 +22,13 @@
#include <rsys/rsys.h>
/* Forward declarations */
+struct bound_flux_result;
struct green_path_handle;
+struct rwalk;
struct sdis_heat_path;
struct sdis_scene;
struct ssp_rng;
-struct bound_flux_result;
+struct temperature;
enum flux_flag {
FLUX_FLAG_CONVECTIVE = BIT(FLUX_CONVECTIVE),
@@ -41,24 +43,24 @@ extern LOCAL_SYM res_T
sample_coupled_path_2d
(struct sdis_scene* scn,
struct rwalk_context* ctx,
- struct rwalk_2d* rwalk,
+ struct rwalk* rwalk,
struct ssp_rng* rng,
- struct temperature_2d* T);
+ struct temperature* T);
extern LOCAL_SYM res_T
sample_coupled_path_3d
(struct sdis_scene* scn,
struct rwalk_context* ctx,
- struct rwalk_3d* rwalk,
+ struct rwalk* rwalk,
struct ssp_rng* rng,
- struct temperature_3d* T);
+ struct temperature* T);
/*******************************************************************************
* Realisation at a given position and time IN a medium
******************************************************************************/
struct probe_realisation_args {
struct ssp_rng* rng;
- struct sdis_medium* medium; /* Medium into which the realisation starts */
+ unsigned enc_id; /* Enclosure into which the realisation starts */
double position[3]; /* Probe position */
double time; /* Observation time */
size_t picard_order; /* Picard order to estimate radiative temperature */
@@ -69,7 +71,7 @@ struct probe_realisation_args {
};
#define PROBE_REALISATION_ARGS_NULL__ { \
NULL, /* RNG */ \
- NULL, /* Medium */ \
+ ENCLOSURE_ID_NULL, /* Enclosure */ \
{0,0,0}, /* Position */ \
-1, /* Observation time */ \
0, /* Picard order */ \
@@ -180,7 +182,7 @@ boundary_flux_realisation_3d
******************************************************************************/
struct ray_realisation_args {
struct ssp_rng* rng;
- struct sdis_medium* medium; /* Medium into which the realisation starts */
+ unsigned enc_id; /* Enclosure into which the realisation starts */
double position[3]; /* Ray position */
double direction[3]; /* Ray direction */
double time; /* Observation time */
@@ -191,7 +193,7 @@ struct ray_realisation_args {
};
#define RAY_REALISATION_ARGS_NULL__ { \
NULL, /* RNG */ \
- NULL, /* Medium */ \
+ ENCLOSURE_ID_NULL, /* Enclosure */ \
{0,0,0}, /* Position */ \
{0,0,0}, /* Direction */ \
-1, /* Observation time */ \
diff --git a/src/sdis_realisation_Xd.h b/src/sdis_realisation_Xd.h
@@ -32,18 +32,19 @@
#ifndef SDIS_REALISATION_XD_H
#define SDIS_REALISATION_XD_H
-static INLINE int
+static INLINE res_T
check_probe_realisation_args(const struct probe_realisation_args* args)
{
return args
&& args->rng
- && args->medium
+ && args->enc_id != ENCLOSURE_ID_NULL
&& args->time >= 0
&& args->picard_order > 0
- && (unsigned)args->diff_algo < SDIS_DIFFUSION_ALGORITHMS_COUNT__;
+ && (unsigned)args->diff_algo < SDIS_DIFFUSION_ALGORITHMS_COUNT__
+ ? RES_OK : RES_BAD_ARG;
}
-static INLINE int
+static INLINE res_T
check_boundary_realisation_args(const struct boundary_realisation_args* args)
{
return args
@@ -55,10 +56,11 @@ check_boundary_realisation_args(const struct boundary_realisation_args* args)
&& args->time >= 0
&& args->picard_order > 0
&& (args->side == SDIS_FRONT || args->side == SDIS_BACK)
- && (unsigned)args->diff_algo < SDIS_DIFFUSION_ALGORITHMS_COUNT__;
+ && (unsigned)args->diff_algo < SDIS_DIFFUSION_ALGORITHMS_COUNT__
+ ? RES_OK : RES_BAD_ARG;
}
-static INLINE int
+static INLINE res_T
check_boundary_flux_realisation_args
(const struct boundary_flux_realisation_args* args)
{
@@ -71,7 +73,8 @@ check_boundary_flux_realisation_args
&& args->time >= 0
&& args->picard_order > 0
&& (args->solid_side == SDIS_FRONT || args->solid_side == SDIS_BACK)
- && (unsigned)args->diff_algo < SDIS_DIFFUSION_ALGORITHMS_COUNT__;
+ && (unsigned)args->diff_algo < SDIS_DIFFUSION_ALGORITHMS_COUNT__
+ ? RES_OK : RES_BAD_ARG;
}
#endif /* SDIS_REALISATION_XD_H */
@@ -82,15 +85,15 @@ res_T
XD(sample_coupled_path)
(struct sdis_scene* scn,
struct rwalk_context* ctx,
- struct XD(rwalk)* rwalk,
+ struct rwalk* rwalk,
struct ssp_rng* rng,
- struct XD(temperature)* T)
+ struct temperature* T)
{
#ifndef NDEBUG
/* Stack that saves the state of each recursion steps. */
struct entry {
- struct XD(temperature) temperature;
- struct XD(rwalk) rwalk;
+ struct temperature temperature;
+ struct rwalk rwalk;
}* stack = NULL;
size_t istack = 0;
#endif
@@ -109,8 +112,8 @@ XD(sample_coupled_path)
while(!T->done) {
/* Save the current random walk state */
- const struct XD(rwalk) rwalk_bkp = *rwalk;
- const struct XD(temperature) T_bkp = *T;
+ const struct rwalk rwalk_bkp = *rwalk;
+ const struct temperature T_bkp = *T;
size_t nfails = 0; /* #failures */
#ifndef NDEBUG
@@ -171,27 +174,39 @@ XD(probe_realisation)
struct probe_realisation_args* args,
double* weight)
{
+ /* Starting enclosure/medium */
+ const struct enclosure* enc = NULL;
+ struct sdis_medium* mdm = NULL;
+
+ /* Random walk */
struct rwalk_context ctx = RWALK_CONTEXT_NULL;
- struct XD(rwalk) rwalk = XD(RWALK_NULL);
- struct XD(temperature) T = XD(TEMPERATURE_NULL);
+ struct rwalk rwalk = RWALK_NULL;
+ struct temperature T = TEMPERATURE_NULL;
+
+ /* Miscellaneous */
enum sdis_heat_vertex_type type;
double t0;
double (*get_initial_temperature)
(const struct sdis_medium* mdm,
const struct sdis_rwalk_vertex* vtx);
res_T res = RES_OK;
- ASSERT(scn && weight && check_probe_realisation_args(args));
+ ASSERT(scn && weight && check_probe_realisation_args(args) == RES_OK);
- switch(args->medium->type) {
+ /* Get the enclosure medium */
+ enc = scene_get_enclosure(scn, args->enc_id);
+ res = scene_get_enclosure_medium(scn, enc, &mdm);
+ if(res != RES_OK) goto error;
+
+ switch(sdis_medium_get_type(mdm)) {
case SDIS_FLUID:
T.func = XD(convective_path);
get_initial_temperature = fluid_get_temperature;
- t0 = fluid_get_t0(args->medium);
+ t0 = fluid_get_t0(mdm);
break;
case SDIS_SOLID:
T.func = XD(conductive_path);
get_initial_temperature = solid_get_temperature;
- t0 = solid_get_t0(args->medium);
+ t0 = solid_get_t0(mdm);
break;
default: FATAL("Unreachable code\n"); break;
}
@@ -200,7 +215,7 @@ XD(probe_realisation)
rwalk.vtx.time = args->time;
/* Register the starting position against the heat path */
- type = args->medium->type == SDIS_SOLID
+ type = sdis_medium_get_type(mdm) == SDIS_SOLID
? SDIS_HEAT_VERTEX_CONDUCTION
: SDIS_HEAT_VERTEX_CONVECTION;
res = register_heat_vertex(args->heat_path, &rwalk.vtx, 0, type, 0);
@@ -210,7 +225,7 @@ XD(probe_realisation)
double tmp;
/* Check the initial condition. */
rwalk.vtx.time = t0;
- tmp = get_initial_temperature(args->medium, &rwalk.vtx);
+ tmp = get_initial_temperature(mdm, &rwalk.vtx);
if(SDIS_TEMPERATURE_IS_KNOWN(tmp)) {
*weight = tmp;
goto exit;
@@ -224,8 +239,8 @@ XD(probe_realisation)
goto error;
}
- rwalk.hit = SXD_HIT_NULL;
- rwalk.mdm = args->medium;
+ rwalk.XD(hit) = SXD_HIT_NULL;
+ rwalk.enc_id = args->enc_id;
ctx.green_path = args->green_path;
ctx.heat_path = args->heat_path;
@@ -258,8 +273,8 @@ XD(boundary_realisation)
double* weight)
{
struct rwalk_context ctx = RWALK_CONTEXT_NULL;
- struct XD(rwalk) rwalk = XD(RWALK_NULL);
- struct XD(temperature) T = XD(TEMPERATURE_NULL);
+ struct rwalk rwalk = RWALK_NULL;
+ struct temperature T = TEMPERATURE_NULL;
struct sXd(attrib) attr;
#if SDIS_XD_DIMENSION == 2
float st;
@@ -267,13 +282,13 @@ XD(boundary_realisation)
float st[2];
#endif
res_T res = RES_OK;
- ASSERT(scn && weight && check_boundary_realisation_args(args));
+ ASSERT(scn && weight && check_boundary_realisation_args(args) == RES_OK);
T.func = XD(boundary_path);
rwalk.hit_side = args->side;
- rwalk.hit.distance = 0;
+ rwalk.XD(hit).distance = 0;
rwalk.vtx.time = args->time;
- rwalk.mdm = NULL; /* The random walk is at an interface between 2 media */
+ rwalk.enc_id = ENCLOSURE_ID_NULL; /* At an interface between 2 enclosures */
#if SDIS_XD_DIMENSION == 2
st = (float)args->uv[0];
@@ -283,20 +298,20 @@ XD(boundary_realisation)
/* Fetch the primitive */
SXD(scene_view_get_primitive
- (scn->sXd(view), (unsigned int)args->iprim, &rwalk.hit.prim));
+ (scn->sXd(view), (unsigned int)args->iprim, &rwalk.XD(hit).prim));
/* Retrieve the world space position of the probe onto the primitive */
- SXD(primitive_get_attrib(&rwalk.hit.prim, SXD_POSITION, st, &attr));
+ SXD(primitive_get_attrib(&rwalk.XD(hit).prim, SXD_POSITION, st, &attr));
dX_set_fX(rwalk.vtx.P, attr.value);
/* Retrieve the primitive normal */
- SXD(primitive_get_attrib(&rwalk.hit.prim, SXD_GEOMETRY_NORMAL, st, &attr));
- fX(set)(rwalk.hit.normal, attr.value);
+ SXD(primitive_get_attrib(&rwalk.XD(hit).prim, SXD_GEOMETRY_NORMAL, st, &attr));
+ fX(set)(rwalk.XD(hit).normal, attr.value);
#if SDIS_XD_DIMENSION==2
- rwalk.hit.u = st;
+ rwalk.XD(hit).u = st;
#else
- f2_set(rwalk.hit.uv, st);
+ f2_set(rwalk.XD(hit).uv, st);
#endif
res = register_heat_vertex(args->heat_path, &rwalk.vtx, 0/*weight*/,
@@ -332,14 +347,14 @@ XD(boundary_flux_realisation)
struct boundary_flux_realisation_args* args,
struct bound_flux_result* result)
{
+ /* Random walk */
struct rwalk_context ctx = RWALK_CONTEXT_NULL;
- struct XD(rwalk) rwalk;
- struct XD(temperature) T;
+ struct rwalk rwalk = RWALK_NULL;
+ struct temperature T = TEMPERATURE_NULL;
+
+ /* Boundary */
struct sXd(attrib) attr;
struct sXd(primitive) prim;
- struct sdis_interface* interf = NULL;
- struct sdis_medium* fluid_mdm = NULL;
-
#if SDIS_XD_DIMENSION == 2
float st;
#else
@@ -347,13 +362,17 @@ XD(boundary_flux_realisation)
#endif
double P[SDIS_XD_DIMENSION];
float N[SDIS_XD_DIMENSION];
+ unsigned enc_ids[2] = {ENCLOSURE_ID_NULL, ENCLOSURE_ID_NULL};
+ enum sdis_side fluid_side;
+
+ /* Miscellaneous */
double Tmin, Tmin2, Tmin3;
double That, That2, That3;
- enum sdis_side fluid_side;
res_T res = RES_OK;
char compute_radiative;
char compute_convective;
- ASSERT(scn && result && check_boundary_flux_realisation_args(args));
+
+ ASSERT(scn && result && check_boundary_flux_realisation_args(args) == RES_OK);
#if SDIS_XD_DIMENSION == 2
#define SET_PARAM(Dest, Src) (Dest).u = (Src);
@@ -386,14 +405,14 @@ XD(boundary_flux_realisation)
SXD(primitive_get_attrib(&prim, SXD_GEOMETRY_NORMAL, st, &attr));
fX(set)(N, attr.value);
- #define RESET_WALK(Side, Mdm) { \
- rwalk = XD(RWALK_NULL); \
+ #define RESET_WALK(Side, EncId) { \
+ rwalk = RWALK_NULL; \
rwalk.hit_side = (Side); \
- rwalk.hit.distance = 0; \
+ rwalk.XD(hit).distance = 0; \
rwalk.vtx.time = args->time; \
- rwalk.mdm = (Mdm); \
- rwalk.hit.prim = prim; \
- SET_PARAM(rwalk.hit, st); \
+ rwalk.enc_id = (EncId); \
+ rwalk.XD(hit).prim = prim; \
+ SET_PARAM(rwalk.XD(hit), st); \
ctx.Tmin = Tmin; \
ctx.Tmin3 = Tmin3; \
ctx.That = That; \
@@ -403,24 +422,23 @@ XD(boundary_flux_realisation)
ctx.irealisation = args->irealisation; \
ctx.diff_algo = args->diff_algo; \
dX(set)(rwalk.vtx.P, P); \
- fX(set)(rwalk.hit.normal, N); \
- T = XD(TEMPERATURE_NULL); \
+ fX(set)(rwalk.XD(hit).normal, N); \
+ T = TEMPERATURE_NULL; \
} (void)0
/* Compute boundary temperature */
- RESET_WALK(args->solid_side, NULL);
+ RESET_WALK(args->solid_side, ENCLOSURE_ID_NULL);
T.func = XD(boundary_path);
res = XD(sample_coupled_path)(scn, &ctx, &rwalk, args->rng, &T);
if(res != RES_OK) return res;
result->Tboundary = T.value;
- /* Fetch the fluid medium */
- interf = scene_get_interface(scn, (unsigned)args->iprim);
- fluid_mdm = interface_get_medium(interf, fluid_side);
+ /* Get the enclosures */
+ scene_get_enclosure_ids(scn, (unsigned)args->iprim, enc_ids);
/* Compute radiative temperature */
if(compute_radiative) {
- RESET_WALK(fluid_side, fluid_mdm);
+ RESET_WALK(fluid_side, enc_ids[fluid_side]);
T.func = XD(radiative_path);
res = XD(sample_coupled_path)(scn, &ctx, &rwalk, args->rng, &T);
if(res != RES_OK) return res;
@@ -430,7 +448,7 @@ XD(boundary_flux_realisation)
/* Compute fluid temperature */
if(compute_convective) {
- RESET_WALK(fluid_side, fluid_mdm);
+ RESET_WALK(fluid_side, enc_ids[fluid_side]);
T.func = XD(convective_path);
res = XD(sample_coupled_path)(scn, &ctx, &rwalk, args->rng, &T);
if(res != RES_OK) return res;
diff --git a/src/sdis_scene.c b/src/sdis_scene.c
@@ -103,6 +103,8 @@ scene_release(ref_T * ref)
darray_prim_prop_release(&scn->prim_props);
htable_enclosure_release(&scn->enclosures);
htable_d_release(&scn->tmp_hc_ub);
+ htable_key2prim2d_release(&scn->key2prim2d);
+ htable_key2prim3d_release(&scn->key2prim3d);
if(scn->s2d_view) S2D(scene_view_ref_put(scn->s2d_view));
if(scn->s3d_view) S3D(scene_view_ref_put(scn->s3d_view));
if(scn->senc2d_scn) SENC2D(scene_ref_put(scn->senc2d_scn));
@@ -332,7 +334,6 @@ sdis_scene_get_senc2d_scene
{
if(!scn || !senc2d_scn) return RES_BAD_ARG;
if(!scn->senc2d_scn) return RES_BAD_ARG; /* Scene is 3D */
- SENC2D(scene_ref_get(scn->senc2d_scn));
*senc2d_scn = scn->senc2d_scn;
return RES_OK;
}
@@ -344,12 +345,33 @@ sdis_scene_get_senc3d_scene
{
if(!scn || !senc3d_scn) return RES_BAD_ARG;
if(!scn->senc3d_scn) return RES_BAD_ARG; /* Scene is 2D */
- SENC3D(scene_ref_get(scn->senc3d_scn));
*senc3d_scn = scn->senc3d_scn;
return RES_OK;
}
res_T
+sdis_scene_get_s2d_scene_view
+ (struct sdis_scene* scn,
+ struct s2d_scene_view** s2d_view)
+{
+ if(!scn || !s2d_view) return RES_BAD_ARG;
+ if(!scn->s2d_view) return RES_BAD_ARG; /* Scene is 3D */
+ *s2d_view = scn->s2d_view;
+ return RES_OK;
+}
+
+res_T
+sdis_scene_get_s3d_scene_view
+ (struct sdis_scene* scn,
+ struct s3d_scene_view** s3d_view)
+{
+ if(!scn || !s3d_view) return RES_BAD_ARG;
+ if(!scn->s3d_view) return RES_BAD_ARG; /* Scene is 2D */
+ *s3d_view = scn->s3d_view;
+ return RES_OK;
+}
+
+res_T
sdis_scene_get_dimension
(const struct sdis_scene* scn, enum sdis_scene_dimension* dim)
{
@@ -416,6 +438,38 @@ sdis_scene_get_radiative_env
return RES_OK;
}
+res_T
+sdis_scene_get_s2d_primitive
+ (struct sdis_scene* scn,
+ const struct sdis_primkey* key,
+ struct s2d_primitive* out_prim)
+{
+ struct s2d_primitive* prim = NULL;
+
+ if(!scn || !key || !out_prim || !scene_is_2d(scn)) return RES_BAD_ARG;
+
+ if((prim = htable_key2prim2d_find(&scn->key2prim2d, key)) == NULL)
+ return RES_BAD_ARG;
+ *out_prim = *prim;
+ return RES_OK;
+}
+
+res_T
+sdis_scene_get_s3d_primitive
+ (struct sdis_scene* scn,
+ const struct sdis_primkey* key,
+ struct s3d_primitive* out_prim)
+{
+ struct s3d_primitive* prim = NULL;
+
+ if(!scn || !key || !out_prim || scene_is_2d(scn)) return RES_BAD_ARG;
+
+ if((prim = htable_key2prim3d_find(&scn->key2prim3d, key)) == NULL)
+ return RES_BAD_ARG;
+ *out_prim = *prim;
+ return RES_OK;
+}
+
/*******************************************************************************
* Local miscellaneous function
******************************************************************************/
@@ -427,26 +481,57 @@ scene_get_interface(const struct sdis_scene* scn, const unsigned iprim)
}
res_T
-scene_get_medium
+scene_get_enclosure_id
(struct sdis_scene* scn,
const double pos[],
- struct get_medium_info* info,
- struct sdis_medium** out_medium)
+ unsigned* enc_id)
{
return scene_is_2d(scn)
- ? scene_get_medium_2d(scn, pos, info, out_medium)
- : scene_get_medium_3d(scn, pos, info, out_medium);
+ ? scene_get_enclosure_id_2d(scn, pos, enc_id)
+ : scene_get_enclosure_id_3d(scn, pos, enc_id);
}
res_T
-scene_get_medium_in_closed_boundaries
+scene_get_enclosure_id_in_closed_boundaries
(struct sdis_scene* scn,
const double pos[],
- struct sdis_medium** out_medium)
+ unsigned* enc_id)
{
return scene_is_2d(scn)
- ? scene_get_medium_in_closed_boundaries_2d(scn, pos, out_medium)
- : scene_get_medium_in_closed_boundaries_3d(scn, pos, out_medium);
+ ? scene_get_enclosure_id_in_closed_boundaries_2d(scn, pos, enc_id)
+ : scene_get_enclosure_id_in_closed_boundaries_3d(scn, pos, enc_id);
+}
+
+res_T
+scene_get_enclosure_medium
+ (struct sdis_scene* scn,
+ const struct enclosure* enc,
+ struct sdis_medium** out_mdm)
+{
+ struct sdis_medium* mdm = NULL;
+ res_T res = RES_OK;
+
+ ASSERT(scn && enc && out_mdm);
+
+ /* Check that the enclosure doesn't surround multiple media */
+ if(enc->medium_id == MEDIUM_ID_MULTI) {
+ log_warn(scn->dev,
+ "%s: invalid medium request. The enclosure includes several media.\n",
+ FUNC_NAME);
+ res = RES_BAD_OP;
+ goto error;
+ }
+
+ /* Obtain enclosure medium */
+ ASSERT(enc->medium_id < darray_medium_size_get(&scn->media));
+ mdm = darray_medium_data_get(&scn->media)[enc->medium_id];
+
+error:
+ *out_mdm = mdm;
+ goto exit;
+exit:
+ mdm = NULL;
+ return res;
}
res_T
diff --git a/src/sdis_scene_Xd.h b/src/sdis_scene_Xd.h
@@ -823,7 +823,7 @@ XD(register_enclosure)(struct sdis_scene* scn, struct sencXd(enclosure)* enc)
/* Setup the medium id of the enclosure */
if(header.enclosed_media_count > 1) {
- enc_data->medium_id = ENCLOSURE_MULTI_MEDIA;
+ enc_data->medium_id = MEDIUM_ID_MULTI;
} else {
SENCXD(enclosure_get_medium(enc, 0, &enc_data->medium_id));
}
@@ -938,6 +938,89 @@ error:
goto exit;
}
+#if DIM == 2
+static res_T
+setup_primitive_keys_2d(struct sdis_scene* scn, struct senc2d_scene* senc_scn)
+{
+ unsigned iprim = 0;
+ unsigned nprims = 0;
+ res_T res = RES_OK;
+ ASSERT(scn && senc_scn);
+
+ SENC2D(scene_get_primitives_count(senc_scn, &nprims));
+
+ FOR_EACH(iprim, 0, nprims) {
+ struct s2d_primitive prim = S2D_PRIMITIVE_NULL;
+ struct sdis_primkey key = SDIS_PRIMKEY_NULL;
+ unsigned ids[2] = {0,0};
+ double v0[2] = {0,0};
+ double v1[2] = {0,0};
+
+ /* Retrieve positions from Star-Enclosre, not Star-2D. Star-Enclosure keeps
+ * the positions submitted by the user as they are, without any
+ * transformation or conversion (Star-2D converts them to float). This
+ * ensures that the caller can construct the same key from his data */
+ SENC2D(scene_get_primitive(senc_scn, iprim, ids));
+ SENC2D(scene_get_vertex(senc_scn, ids[0], v0));
+ SENC2D(scene_get_vertex(senc_scn, ids[1], v1));
+ S2D(scene_view_get_primitive(scn->s2d_view, iprim, &prim));
+
+ sdis_primkey_2d_setup(&key, v0, v1);
+
+ res = htable_key2prim2d_set(&scn->key2prim2d, &key, &prim);
+ if(res != RES_OK) goto error;
+ }
+
+exit:
+ return res;
+error:
+ htable_key2prim2d_purge(&scn->key2prim2d);
+ goto exit;
+}
+
+#elif DIM == 3
+static res_T
+setup_primitive_keys_3d(struct sdis_scene* scn, struct senc3d_scene* senc_scn)
+{
+ unsigned iprim = 0;
+ unsigned nprims = 0;
+ res_T res = RES_OK;
+ ASSERT(scn && senc_scn);
+
+ SENC3D(scene_get_primitives_count(senc_scn, &nprims));
+
+ FOR_EACH(iprim, 0, nprims) {
+ struct s3d_primitive prim = S3D_PRIMITIVE_NULL;
+ struct sdis_primkey key = SDIS_PRIMKEY_NULL;
+ unsigned ids[3] = {0};
+ double v0[3] = {0};
+ double v1[3] = {0};
+ double v2[3] = {0};
+
+ /* Retrieve positions from Star-Enclosre, not Star-3D. Star-Enclosure keeps
+ * the positions submitted by the user as they are, without any
+ * transformation or conversion (Star-3D converts them to float). This
+ * ensures that the caller can construct the same key from his data */
+ SENC3D(scene_get_primitive(senc_scn, iprim, ids));
+ SENC3D(scene_get_vertex(senc_scn, ids[0], v0));
+ SENC3D(scene_get_vertex(senc_scn, ids[1], v1));
+ SENC3D(scene_get_vertex(senc_scn, ids[2], v2));
+ S3D(scene_view_get_primitive(scn->s3d_view, iprim, &prim));
+
+ sdis_primkey_setup(&key, v0, v1, v2);
+
+ res = htable_key2prim3d_set(&scn->key2prim3d, &key, &prim);
+ if(res != RES_OK) goto error;
+ }
+
+exit:
+ return res;
+error:
+ htable_key2prim3d_purge(&scn->key2prim3d);
+ goto exit;
+}
+#endif
+
/* Create a Stardis scene */
static res_T
XD(scene_create)
@@ -956,8 +1039,9 @@ XD(scene_create)
scn = MEM_CALLOC(dev->allocator, 1, sizeof(struct sdis_scene));
if(!scn) {
- log_err(dev, "%s: could not allocate the Stardis scene.\n", FUNC_NAME);
res = RES_MEM_ERR;
+ log_err(dev, "%s: unabale to allocate the scene -- %s\n",
+ FUNC_NAME, res_to_cstr(res));
goto error;
}
@@ -973,6 +1057,8 @@ XD(scene_create)
darray_prim_prop_init(dev->allocator, &scn->prim_props);
htable_enclosure_init(dev->allocator, &scn->enclosures);
htable_d_init(dev->allocator, &scn->tmp_hc_ub);
+ htable_key2prim2d_init(dev->allocator, &scn->key2prim2d);
+ htable_key2prim3d_init(dev->allocator, &scn->key2prim3d);
if(args->source) {
SDIS(source_ref_get(args->source));
@@ -994,23 +1080,32 @@ XD(scene_create)
args->context,
&senc_scn);
if(res != RES_OK) {
- log_err(dev, "%s: error during the scene analysis.\n", FUNC_NAME);
+ log_err(dev, "%s: unable to analyze the scene -- %s\n",
+ FUNC_NAME, res_to_cstr(res));
goto error;
}
res = XD(setup_properties)(scn, senc_scn, args->get_interface, args->context);
if(res != RES_OK) {
- log_err(dev, "%s: could not setup the scene interfaces and their media.\n",
- FUNC_NAME);
+ log_err(dev, "%s: unable to configure interfaces and media -- %s\n",
+ FUNC_NAME, res_to_cstr(res));
goto error;
}
res = XD(setup_scene_geometry)(scn, senc_scn);
if(res != RES_OK) {
- log_err(dev, "%s: could not setup the scene geometry.\n", FUNC_NAME);
+ log_err(dev, "%s: unable to configure scene geometry -- %s\n",
+ FUNC_NAME, res_to_cstr(res));
goto error;
}
res = XD(setup_enclosures)(scn, senc_scn);
if(res != RES_OK) {
- log_err(dev, "%s: could not setup the enclosures.\n", FUNC_NAME);
+ log_err(dev, "%s: unable to configure enclosures -- %s\n",
+ FUNC_NAME, res_to_cstr(res));
+ goto error;
+ }
+ res = XD(setup_primitive_keys)(scn, senc_scn);
+ if(res != RES_OK) {
+ log_err(dev, "%s: unable to configure primitive keys -- %s\n",
+ FUNC_NAME, res_to_cstr(res));
goto error;
}
scn->sencXd(scn) = senc_scn;
@@ -1094,14 +1189,12 @@ error:
/*******************************************************************************
* Local functions
******************************************************************************/
-static INLINE res_T
-XD(scene_get_medium)
+static res_T
+XD(scene_get_enclosure_id)
(struct sdis_scene* scn,
const double pos[DIM],
- struct get_medium_info* info, /* May be NULL */
- struct sdis_medium** out_medium)
+ unsigned* out_enc_id)
{
- struct sdis_medium* medium = NULL;
size_t iprim, nprims;
float P[DIM];
/* Range of the parametric coordinate into which positions are challenged */
@@ -1111,6 +1204,7 @@ XD(scene_get_medium)
float st[3][2];
#endif
size_t nsteps = 3;
+ unsigned enc_id = ENCLOSURE_ID_NULL;
res_T res = RES_OK;
ASSERT(scn && pos);
@@ -1163,8 +1257,8 @@ XD(scene_get_medium)
} while((SXD_HIT_NONE(&hit) || HIT_ON_BOUNDARY(&hit, P, dir))
&& ++istep < nsteps);
- /* No valid intersection is found on the current primitive. Challenge
- * another. */
+ /* No valid intersection is found on the current primitive.
+ * Challenge another. */
if(istep >= nsteps) continue;
fX(normalize)(N, hit.normal);
@@ -1172,44 +1266,17 @@ XD(scene_get_medium)
/* Not too close and not roughly orthognonal */
if(hit.distance > 1.e-6 && absf(cos_N_dir) > 1.e-2f) {
- const struct enclosure* enclosure = NULL;
unsigned enc_ids[2];
- const struct sdis_interface* interf;
-
- interf = scene_get_interface(scn, hit.prim.prim_id);
scene_get_enclosure_ids(scn, hit.prim.prim_id, enc_ids);
+ enc_id = cos_N_dir < 0 ? enc_ids[0] : enc_ids[1];
- if(cos_N_dir < 0) {
- medium = interface_get_medium(interf, SDIS_FRONT);
- enclosure = scene_get_enclosure(scn, enc_ids[0]);
- } else {
- medium = interface_get_medium(interf, SDIS_BACK);
- enclosure = scene_get_enclosure(scn, enc_ids[1]);
- }
-
- if(enclosure->medium_id == ENCLOSURE_MULTI_MEDIA) {
- log_warn
- (scn->dev,
- "%s: invalid medium request at {%g, %g, %g}. "
- "The position is located in an enclosure comprising several media.\n",
- FUNC_NAME, P[0], P[1], DIM == 3 ? P[2] : 0);
- res = RES_BAD_OP;
- goto error;
- }
-
- /* Register the get_medium_info */
- if(info) {
- fX(set)(info->pos_tgt, attr.value);
- fX(set)(info->ray_org, P);
- fX(set)(info->ray_dir, dir);
- info->XD(hit) = hit;
- }
- break;
+ break; /* That's all folks */
}
}
if(iprim >= nprims) {
- log_warn(scn->dev, "%s: could not retrieve the medium at {%g, %g, %g}.\n",
+ log_warn(scn->dev,
+ "%s: cannot retrieve current enclosure at {%g, %g, %g}.\n",
FUNC_NAME, P[0], P[1], DIM == 3 ? P[2] : 0);
res = RES_BAD_OP;
goto error;
@@ -1217,31 +1284,32 @@ XD(scene_get_medium)
if(iprim > 10 && iprim > (size_t)((double)nprims * 0.05)) {
log_warn(scn->dev,
- "%s: performance issue. Up to %lu primitives were tested to define the "
- "current medium at {%g, %g, %g}.\n",
+ "%s: performance issue. Up to %lu primitives were tested to find "
+ "current enclosure at {%g, %g, %g}.\n",
FUNC_NAME, (unsigned long)iprim, P[0], P[1], DIM == 3 ? P[2] : 0);
}
exit:
- *out_medium = medium;
+ *out_enc_id = enc_id;
return res;
error:
+ enc_id = ENCLOSURE_ID_NULL;
goto exit;
}
-static INLINE res_T
-XD(scene_get_medium_in_closed_boundaries)
+static res_T
+XD(scene_get_enclosure_id_in_closed_boundaries)
(struct sdis_scene* scn,
const double pos[DIM],
- struct sdis_medium** out_medium)
+ unsigned* out_enc_id)
{
- struct sdis_medium* medium = NULL;
- float P[DIM];
- float frame[DIM*DIM];
float dirs[6][3] = {{1,0,0},{-1,0,0},{0,1,0},{0,-1,0},{0,0,1},{0,0,-1}};
+ float frame[DIM*DIM];
+ float P[DIM];
+ unsigned enc_id = ENCLOSURE_ID_NULL;
int idir;
res_T res = RES_OK;
- ASSERT(scn && pos);
+ ASSERT(scn && pos && out_enc_id);
/* Build a frame that will be used to rotate the main axis by PI/4 around
* each axis. This can avoid numerical issues when geometry is discretized
@@ -1249,8 +1317,6 @@ XD(scene_get_medium_in_closed_boundaries)
#if DIM == 2
f22_rotation(frame, (float)PI/4);
#else
-/* N[0] = N[1] = N[2] = (float)(1.0 / sqrt(3.0));*/
-/* f33_basis(frame, N);*/
f33_rotation(frame, (float)PI/4, (float)PI/4, (float)PI/4);
#endif
@@ -1279,22 +1345,23 @@ XD(scene_get_medium_in_closed_boundaries)
/* Not too close and not roughly orthogonal */
if(hit.distance > 1.e-6 && absf(cos_N_dir) > 1.e-2f) {
- const struct sdis_interface* interf;
- interf = scene_get_interface(scn, hit.prim.prim_id);
- medium = interface_get_medium
- (interf, cos_N_dir < 0 ? SDIS_FRONT : SDIS_BACK);
- break;
+ unsigned enc_ids[2];
+ scene_get_enclosure_ids(scn, hit.prim.prim_id, enc_ids);
+ enc_id = cos_N_dir < 0 ? enc_ids[0] : enc_ids[1];
+
+ break; /* That's all folks */
}
}
- if(idir >= 2*DIM) {
- res = XD(scene_get_medium)(scn, pos, NULL, &medium);
+ if(idir >= 2*DIM) { /* Fallback to scene_get_enclosure_id function */
+ res = XD(scene_get_enclosure_id)(scn, pos, &enc_id);
if(res != RES_OK) goto error;
}
exit:
- *out_medium = medium;
+ *out_enc_id = enc_id;
return res;
error:
+ enc_id = ENCLOSURE_ID_NULL;
goto exit;
}
diff --git a/src/sdis_scene_c.h b/src/sdis_scene_c.h
@@ -26,6 +26,9 @@
#include <limits.h>
+#define MEDIUM_ID_MULTI UINT_MAX
+#define ENCLOSURE_ID_NULL UINT_MAX
+
struct prim_prop {
struct sdis_interface* interf;
unsigned front_enclosure; /* Id of the front facing enclosure */
@@ -48,21 +51,6 @@ struct hit_filter_data {
static const struct hit_filter_data HIT_FILTER_DATA_NULL =
HIT_FILTER_DATA_NULL__;
-struct get_medium_info {
- /* Targeted position */
- float pos_tgt[3];
- /* Ray trace to the targeted position in order to define the current medium */
- float ray_org[3];
- float ray_dir[3];
- /* Hit encouters along the ray and used to define the current medium */
- struct s2d_hit hit_2d;
- struct s3d_hit hit_3d;
-};
-#define GET_MEDIUM_INFO_NULL__ \
- {{0,0,0}, {0,0,0}, {0,0,0}, S2D_HIT_NULL__, S3D_HIT_NULL__}
-static const struct get_medium_info GET_MEDIUM_INFO_NULL =
- GET_MEDIUM_INFO_NULL__;
-
static INLINE void
prim_prop_init(struct mem_allocator* allocator, struct prim_prop* prim)
{
@@ -86,8 +74,6 @@ medium_init(struct mem_allocator* allocator, struct sdis_medium** medium)
*medium = NULL;
}
-#define ENCLOSURE_MULTI_MEDIA UINT_MAX
-
struct enclosure {
struct s2d_scene_view* s2d_view;
struct s3d_scene_view* s3d_view;
@@ -112,7 +98,7 @@ enclosure_init(struct mem_allocator* allocator, struct enclosure* enc)
enc->S_over_V = 0;
enc->V = 0;
enc->hc_upper_bound = 0;
- enc->medium_id = ENCLOSURE_MULTI_MEDIA;
+ enc->medium_id = MEDIUM_ID_MULTI;
}
static INLINE void
@@ -173,6 +159,16 @@ enclosure_local2global_prim_id
return darray_uint_cdata_get(&enc->local2global)[local_prim_id];
}
+static INLINE void
+primkey_init
+ (const struct mem_allocator* allocator,
+ struct sdis_primkey* key)
+{
+ ASSERT(allocator && key);
+ (void)allocator;
+ *key = SDIS_PRIMKEY_NULL;
+}
+
/* Declare the array of interfaces */
#define DARRAY_NAME interf
#define DARRAY_DATA struct sdis_interface*
@@ -207,6 +203,24 @@ enclosure_local2global_prim_id
#define HTABLE_DATA double
#include <rsys/hash_table.h>
+/* Declare the hash table that maps the primitive key to its 2D primitve */
+#define HTABLE_NAME key2prim2d
+#define HTABLE_KEY struct sdis_primkey
+#define HTABLE_KEY_FUNCTOR_INIT primkey_init
+#define HTABLE_KEY_FUNCTOR_HASH sdis_primkey_hash
+#define HTABLE_KEY_FUNCTOR_EQ sdis_primkey_eq
+#define HTABLE_DATA struct s2d_primitive
+#include <rsys/hash_table.h>
+
+/* Declare the hash table that maps the primitive key to its 3D primitive */
+#define HTABLE_NAME key2prim3d
+#define HTABLE_KEY struct sdis_primkey
+#define HTABLE_KEY_FUNCTOR_INIT primkey_init
+#define HTABLE_KEY_FUNCTOR_HASH sdis_primkey_hash
+#define HTABLE_KEY_FUNCTOR_EQ sdis_primkey_eq
+#define HTABLE_DATA struct s3d_primitive
+#include <rsys/hash_table.h>
+
struct sdis_scene {
struct darray_interf interfaces; /* List of interfaces own by the scene */
struct darray_medium media; /* List of media own by the scene */
@@ -220,6 +234,10 @@ struct sdis_scene {
struct htable_enclosure enclosures; /* Map an enclosure id to its data */
unsigned outer_enclosure_id;
+ /* Map a primivei key to its Star-2D/Star-3D primitive */
+ struct htable_key2prim2d key2prim2d;
+ struct htable_key2prim3d key2prim3d;
+
double fp_to_meter;
double tmin; /* Minimum temperature of the system (In Kelvin) */
double tmax; /* Maximum temperature of the system (In Kelvin) */
@@ -244,26 +262,31 @@ scene_get_interface
const unsigned iprim);
extern LOCAL_SYM res_T
-scene_get_medium
+scene_get_enclosure_id
(struct sdis_scene* scene,
const double position[],
- struct get_medium_info* info, /* May be NULL */
- struct sdis_medium** medium);
+ unsigned* enclosure_id);
-/* This function assumes that the tested position lies into finite enclosure.
- * The medium into which it lies is thus retrieved by tracing a random ray
- * around the current position. For possible infinite enclosure, one has to use
- * the `scene_get_medium' function instead that, in counterpart, can be more
- * time consuming.
+/* This function assumes that the position under test lies within a finite
+ * enclosure. The enclosure in which it is located is therefore retrieved by
+ * tracing a random ray around the current position. For infinite enclosures,
+ * you need to use the `scene_get_enclosure_id' function, which in turn may take
+ * longer.
*
- * Note that actually, the function internally calls scene_get_medium if no
- * valid medium is found with the regular procedure. This may be due to
- * numerical issues or wrong assumptions on the current medium (its boundaries
- * are opened to infinity). */
+ * Note that the function actually calls scene_get_enclosure internally if no
+ * valid enclosure is found with the normal procedure. This may be due to
+ * numerical problems or incorrect assumptions about the current enclosure (its
+ * limits are open to infinity). */
extern LOCAL_SYM res_T
-scene_get_medium_in_closed_boundaries
- (struct sdis_scene* scn,
+scene_get_enclosure_id_in_closed_boundaries
+ (struct sdis_scene* scene,
const double position[],
+ unsigned* enclosure_id);
+
+extern LOCAL_SYM res_T
+scene_get_enclosure_medium
+ (struct sdis_scene* scene,
+ const struct enclosure* enclosure,
struct sdis_medium** medium);
extern LOCAL_SYM res_T
diff --git a/src/sdis_solve_camera.c b/src/sdis_solve_camera.c
@@ -84,7 +84,7 @@ static res_T
solve_pixel
(struct sdis_scene* scn,
struct ssp_rng* rng,
- struct sdis_medium* mdm,
+ const unsigned enc_id,
const struct sdis_camera* cam,
const double time_range[2], /* Observation time */
const size_t ipix[2], /* Pixel coordinate in the image space */
@@ -99,7 +99,7 @@ solve_pixel
struct sdis_heat_path* pheat_path = NULL;
size_t irealisation;
res_T res = RES_OK;
- ASSERT(scn && mdm && rng && cam && ipix && nrealisations);
+ ASSERT(scn && rng && cam && ipix && nrealisations);
ASSERT(pix_sz && pix_sz[0] > 0 && pix_sz[1] > 0);
ASSERT(pixel && time_range);
@@ -136,7 +136,7 @@ solve_pixel
/* Launch the realisation */
realis_args.rng = rng;
- realis_args.medium = mdm;
+ realis_args.enc_id = enc_id;
realis_args.time = time;
realis_args.picard_order = picard_order;
realis_args.heat_path = pheat_path;
@@ -195,7 +195,7 @@ static res_T
solve_tile
(struct sdis_scene* scn,
struct ssp_rng* rng,
- struct sdis_medium* mdm,
+ const unsigned enc_id,
const struct sdis_camera* cam,
const double time_range[2],
const size_t tile_org[2], /* Origin of the tile in pixel space */
@@ -211,7 +211,7 @@ solve_tile
size_t mcode; /* Morton code of the tile pixel */
size_t npixels;
res_T res = RES_OK;
- ASSERT(scn && rng && mdm && cam && spp);
+ ASSERT(scn && rng && cam && spp);
ASSERT(tile_size && tile_size[0] && tile_size[1]);
ASSERT(pix_sz && pix_sz[0] > 0 && pix_sz[1] > 0 && time_range);
@@ -241,8 +241,8 @@ solve_tile
estimator = estimator_buffer_grab(buf, ipix_image[0], ipix_image[1]);
}
res = solve_pixel
- (scn, rng, mdm, cam, time_range, ipix_image, spp, register_paths, pix_sz,
- picard_order, diff_algo, estimator, pixel);
+ (scn, rng, enc_id, cam, time_range, ipix_image, spp, register_paths,
+ pix_sz, picard_order, diff_algo, estimator, pixel);
if(res != RES_OK) goto error;
}
@@ -504,12 +504,14 @@ sdis_solve_camera
/* Stardis variables */
struct sdis_estimator_buffer* buf = NULL;
- struct sdis_medium* medium = NULL;
/* Random number generators */
struct ssp_rng_proxy* rng_proxy = NULL;
struct ssp_rng** per_thread_rng = NULL;
+ /* Enclosure & medium in which the probe lies */
+ unsigned enc_id = ENCLOSURE_ID_NULL;
+
/* Miscellaneous */
size_t ntiles_x, ntiles_y, ntiles, ntiles_adjusted;
size_t ntiles_proc; /* #tiles for the current proc */
@@ -537,17 +539,9 @@ sdis_solve_camera
}
/* Retrieve the medium in which the submitted position lies */
- res = scene_get_medium(scn, args->cam->position, NULL, &medium);
+ res = scene_get_enclosure_id(scn, args->cam->position, &enc_id);
if(res != RES_OK) goto error;
- if(medium->type != SDIS_FLUID) {
- log_err(scn->dev,
- "%s: the camera position `%g %g %g' must be in a fluid medium.\n",
- FUNC_NAME, SPLIT3(args->cam->position));
- res = RES_BAD_ARG;
- goto error;
- }
-
/* Create the per thread RNGs */
res = create_per_thread_rng
(scn->dev, args->rng_state, args->rng_type, &rng_proxy, &per_thread_rng);
@@ -658,7 +652,7 @@ sdis_solve_camera
/* Draw the tile */
res_local = solve_tile
- (scn, rng, medium, args->cam, args->time_range, tile_org, tile_sz,
+ (scn, rng, enc_id, args->cam, args->time_range, tile_org, tile_sz,
args->spp, register_paths, pix_sz, args->picard_order, args->diff_algo,
buf, tile);
if(res_local != RES_OK) {
diff --git a/src/sdis_solve_medium_Xd.h b/src/sdis_solve_medium_Xd.h
@@ -39,7 +39,7 @@
*/
struct enclosure_cumul {
- const struct enclosure* enc;
+ unsigned enc_id;
double cumul;
};
@@ -79,12 +79,13 @@ compute_medium_enclosure_cumulative
while(!htable_enclosure_iterator_eq(&it, &end)) {
struct enclosure_cumul enc_cumul;
const struct enclosure* enc = htable_enclosure_iterator_data_get(&it);
+ const unsigned* enc_id = htable_enclosure_iterator_key_get(&it);
htable_enclosure_iterator_next(&it);
if(sdis_medium_get_id(mdm) != enc->medium_id) continue;
accum += enc->V;
- enc_cumul.enc = enc;
+ enc_cumul.enc_id = *enc_id;
enc_cumul.cumul = accum;
res = darray_enclosure_cumul_push_back(cumul, &enc_cumul);
if(res != RES_OK) goto error;
@@ -105,7 +106,7 @@ error:
goto exit;
}
-static const struct enclosure*
+static unsigned
sample_medium_enclosure
(const struct darray_enclosure_cumul* cumul, struct ssp_rng* rng)
{
@@ -137,7 +138,7 @@ sample_medium_enclosure
enc_cumul_found = enc_cumuls + i;
}
- return enc_cumul_found->enc;
+ return enc_cumul_found->enc_id;
}
static INLINE res_T
@@ -217,17 +218,22 @@ check_compute_power_args(const struct sdis_compute_power_args* args)
******************************************************************************/
static res_T
XD(sample_enclosure_position)
- (const struct enclosure* enc,
+ (struct sdis_scene* scn,
+ const unsigned enc_id,
struct ssp_rng* rng,
double pos[DIM])
{
const size_t MAX_NCHALLENGES = 1000;
+
+ const struct enclosure* enc = NULL;
float lower[DIM], upper[DIM];
size_t ichallenge;
size_t i;
res_T res = RES_OK;
- ASSERT(enc && rng && pos);
+ ASSERT(scn && rng && pos);
+ ASSERT(enc_id != ENCLOSURE_ID_NULL);
+ enc = scene_get_enclosure(scn, enc_id);
SXD(scene_view_get_aabb(enc->sXd(view), lower, upper));
FOR_EACH(i, 0, DIM) {
@@ -396,13 +402,13 @@ XD(solve_medium)
struct accum* acc_time = &per_thread_acc_time[ithread];
struct green_path_handle* pgreen_path = NULL;
struct green_path_handle green_path = GREEN_PATH_HANDLE_NULL;
- const struct enclosure* enc = NULL;
struct sdis_heat_path* pheat_path = NULL;
struct sdis_heat_path heat_path;
double weight;
double time;
double pos[DIM];
size_t n;
+ unsigned enc_id = ENCLOSURE_ID_NULL;
int pcent;
res_T res_local = RES_OK;
res_T res_simul = RES_OK;
@@ -425,8 +431,8 @@ XD(solve_medium)
/* Uniformly Sample an enclosure that surround the submitted medium and
* uniformly sample a position into it */
- enc = sample_medium_enclosure(&cumul, rng);
- res_local = XD(sample_enclosure_position)(enc, rng, pos);
+ enc_id = sample_medium_enclosure(&cumul, rng);
+ res_local = XD(sample_enclosure_position)(scn, enc_id, rng, pos);
if(res_local != RES_OK) {
log_err(scn->dev, "%s: could not sample a medium position.\n", FUNC_NAME);
ATOMIC_SET(&res, res_local);
@@ -435,7 +441,7 @@ XD(solve_medium)
/* Run a probe realisation */
realis_args.rng = rng;
- realis_args.medium = args->medium;
+ realis_args.enc_id = enc_id;
realis_args.time = time;
realis_args.picard_order = args->picard_order;
realis_args.green_path = pgreen_path;
@@ -685,10 +691,10 @@ XD(compute_power)
struct ssp_rng* rng = per_thread_rng[ithread];
struct accum* acc_mpow = &per_thread_acc_mpow[ithread];
struct accum* acc_time = &per_thread_acc_time[ithread];
- const struct enclosure* enc = NULL;
double power = 0;
double usec = 0;
size_t n = 0;
+ unsigned enc_id = ENCLOSURE_ID_NULL;
int pcent = 0;
res_T res_local = RES_OK;
@@ -702,8 +708,8 @@ XD(compute_power)
/* Uniformly Sample an enclosure that surround the submitted medium and
* uniformly sample a position into it */
- enc = sample_medium_enclosure(&cumul, rng);
- res_local = XD(sample_enclosure_position)(enc, rng, vtx.P);
+ enc_id = sample_medium_enclosure(&cumul, rng);
+ res_local = XD(sample_enclosure_position)(scn, enc_id, rng, vtx.P);
if(res_local != RES_OK) {
log_err(scn->dev, "%s: could not sample a medium position.\n", FUNC_NAME);
ATOMIC_SET(&res, res_local);
diff --git a/src/sdis_solve_probe_Xd.h b/src/sdis_solve_probe_Xd.h
@@ -116,7 +116,9 @@ XD(solve_one_probe)
struct accum* acc_temp,
struct accum* acc_time)
{
- struct sdis_medium* medium = NULL; /* Medium in which the probe lies */
+ /* Enclosure in which the probe lies */
+ unsigned enc_id = ENCLOSURE_ID_NULL;
+
size_t irealisation = 0;
res_T res = RES_OK;
ASSERT(scn && rng && check_solve_probe_args(args) == RES_OK);
@@ -126,7 +128,7 @@ XD(solve_one_probe)
*acc_time = ACCUM_NULL;
/* Retrieve the medium in which the submitted position lies */
- res = scene_get_medium(scn, args->position, NULL, &medium);
+ res = scene_get_enclosure_id(scn, args->position, &enc_id);
if(res != RES_OK) goto error;
FOR_EACH(irealisation, 0, args->nrealisations) {
@@ -144,26 +146,38 @@ XD(solve_one_probe)
/* Run a realisation */
realis_args.rng = rng;
- realis_args.medium = medium;
+ realis_args.enc_id = enc_id;
realis_args.time = time;
realis_args.picard_order = args->picard_order;
realis_args.irealisation = irealisation;
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;
-
- /* Stop time registration */
- time_sub(&t0, time_current(&t1), &t0);
- usec = (double)time_val(&t0, TIME_NSEC) * 0.001;
-
- /* Update MC weights */
- acc_temp->sum += w;
- acc_temp->sum2 += w*w;
- acc_temp->count += 1;
- acc_time->sum += usec;
- acc_time->sum2 += usec*usec;
- acc_time->count += 1;
+ if(res != RES_OK && res != RES_BAD_OP) goto error;
+
+ switch(res) {
+ /* Reject the realisation */
+ case RES_BAD_OP:
+ res = RES_OK;
+ break;
+
+ /* Update the accumulators */
+ case RES_OK:
+ /* Stop time registration */
+ time_sub(&t0, time_current(&t1), &t0);
+ usec = (double)time_val(&t0, TIME_NSEC) * 0.001;
+
+ /* Update MC weights */
+ acc_temp->sum += w;
+ acc_temp->sum2 += w*w;
+ acc_temp->count += 1;
+ acc_time->sum += usec;
+ acc_time->sum2 += usec*usec;
+ acc_time->count += 1;
+ break;
+
+ default: FATAL("Unreachable code\n"); break;
+ }
}
exit:
@@ -191,7 +205,6 @@ XD(solve_probe)
size_t nthreads = 0;
/* Stardis variables */
- struct sdis_medium* medium = NULL;
struct sdis_estimator* estimator = NULL;
struct sdis_green_function* green = NULL;
struct sdis_green_function** per_thread_green = NULL;
@@ -200,6 +213,10 @@ XD(solve_probe)
struct ssp_rng_proxy* rng_proxy = NULL;
struct ssp_rng** per_thread_rng = NULL;
+ /* Enclosure in which the probe lies */
+ const struct enclosure* enc = NULL;
+ unsigned enc_id = ENCLOSURE_ID_NULL;
+
/* Miscellaneous */
struct accum* per_thread_acc_temp = NULL;
struct accum* per_thread_acc_time = NULL;
@@ -255,10 +272,19 @@ XD(solve_probe)
if(!per_thread_acc_temp) { res = RES_MEM_ERR; goto error; }
if(!per_thread_acc_time) { res = RES_MEM_ERR; goto error; }
- /* Retrieve the medium in which the submitted position lies */
- res = scene_get_medium(scn, args->position, NULL, &medium);
+ /* Retrieve the enclosure in which the submitted position lies */
+ res = scene_get_enclosure_id(scn, args->position, &enc_id);
if(res != RES_OK) goto error;
+ /* Check that the enclosure does not contain multiple materials */
+ enc = scene_get_enclosure(scn, enc_id);
+ if(enc->medium_id == MEDIUM_ID_MULTI) {
+ log_err(scn->dev, "%s: probe is in an enclosure with several media "
+ "-- pos=("FORMAT_VECX")\n", FUNC_NAME, SPLITX(args->position));
+ res = RES_BAD_OP;
+ goto error;
+ }
+
/* Create the per thread green function */
if(out_green) {
res = create_per_thread_green_function
@@ -327,7 +353,7 @@ XD(solve_probe)
/* Invoke the probe realisation */
realis_args.rng = rng;
- realis_args.medium = medium;
+ realis_args.enc_id = enc_id;
realis_args.time = time;
realis_args.picard_order = args->picard_order;
realis_args.green_path = pgreen_path;
diff --git a/src/sdis_solve_probe_boundary_Xd.h b/src/sdis_solve_probe_boundary_Xd.h
@@ -195,20 +195,33 @@ XD(solve_one_probe_boundary)
realis_args.uv[1] = args->uv[1];
#endif
res = XD(boundary_realisation)(scn, &realis_args, &w);
- if(res != RES_OK) goto error;
-
- /* Stop time registration */
- time_sub(&t0, time_current(&t1), &t0);
- usec = (double)time_val(&t0, TIME_NSEC) * 0.001;
-
- /* Update MC weights */
- acc_temp->sum += w;
- acc_temp->sum2 += w*w;
- acc_temp->count += 1;
- acc_time->sum += usec;
- acc_time->sum2 += usec*usec;
- acc_time->count += 1;
+ if(res != RES_OK && res != RES_BAD_OP) goto error;
+
+ switch(res) {
+ /* Reject the realisation */
+ case RES_BAD_OP:
+ res = RES_OK;
+ break;
+
+ /* Update the accumulators */
+ case RES_OK:
+ /* Stop time registration */
+ time_sub(&t0, time_current(&t1), &t0);
+ usec = (double)time_val(&t0, TIME_NSEC) * 0.001;
+
+ /* Update MC weights */
+ acc_temp->sum += w;
+ acc_temp->sum2 += w*w;
+ acc_temp->count += 1;
+ acc_time->sum += usec;
+ acc_time->sum2 += usec*usec;
+ acc_time->count += 1;
+ break;
+
+ default: FATAL("Unreachable code\n"); break;
+ }
}
+
exit:
return res;
error:
@@ -613,6 +626,7 @@ XD(solve_probe_boundary_list)
time_current(&time0);
/* Calculation of probe list */
+ omp_set_num_threads((int)scn->dev->nthreads);
#pragma omp parallel for schedule(static)
for(i = 0; i < (int64_t)process_nprobes; ++i) {
/* Thread */
diff --git a/src/test_sdis_custom_solid_path_sampling.c b/src/test_sdis_custom_solid_path_sampling.c
@@ -0,0 +1,580 @@
+/* Copyright (C) 2016-2024 |Méso|Star> (contact@meso-star.com)
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+#include "sdis.h"
+#include "test_sdis_mesh.h"
+#include "test_sdis_utils.h"
+
+#include <star/s3d.h>
+#include <star/s3dut.h>
+#include <star/ssp.h>
+
+#include <rsys/double3.h>
+
+/*
+ * The system is a trilinear profile of the temperature at steady state, i.e. at
+ * each point of the system we can calculate the temperature analytically. Two
+ * forms are immersed in this temperature field: a super shape and a sphere
+ * included in the super shape. On the Monte Carlo side, the temperature is
+ * unknown everywhere except on the surface of the super shape whose
+ * temperature is defined from the aformentionned trilinear profile.
+ *
+ * We will estimate the temperature at the position of a probe in solids by
+ * providing a user-side function to sample the conductive path in the sphere.
+ * We should find the temperature of the trilinear profile at the probe position
+ * by Monte Carlo, independently of this coupling with an external path sampling
+ * routine.
+ *
+ *
+ * /\ <-- T(x,y,z)
+ * ___/ \___
+ * T(z) \ __ /
+ * | T(y) T=?/. \ /
+ * |/ / \__/ \
+ * o--- T(x) /_ __ _\
+ * \/ \/
+ */
+
+#define NREALISATIONS 10000
+#define SPHERE_RADIUS 1
+
+/*******************************************************************************
+ * Helper functions
+ ******************************************************************************/
+static double
+trilinear_profile(const double pos[3])
+{
+ /* Range in X, Y and Z in which the trilinear profile is defined */
+ const double lower = -4;
+ const double upper = +4;
+
+ /* Upper temperature limit in X, Y and Z [K]. Lower temperature limit is
+ * implicitly 0 */
+ const double a = 333; /* Upper temperature limit in X [K] */
+ const double b = 432; /* Upper temperature limit in Y [K] */
+ const double c = 579; /* Upper temperature limit in Z [K] */
+
+ double x, y, z;
+
+ /* Check pre-conditions */
+ CHK(pos);
+ CHK(lower <= pos[0] && pos[0] <= upper);
+ CHK(lower <= pos[1] && pos[1] <= upper);
+ CHK(lower <= pos[2] && pos[2] <= upper);
+
+ x = (pos[0] - lower) / (upper - lower);
+ y = (pos[1] - lower) / (upper - lower);
+ z = (pos[2] - lower) / (upper - lower);
+ return a*x + b*y + c*z;
+}
+
+/*******************************************************************************
+ * Scene view
+ ******************************************************************************/
+/* Parameter for get_inidices/get_vertices functions. Although its layout is the
+ * same as that of the mesh data structure, we have deliberately defined a new
+ * data type since mesh functions cannot be invoked. This is because the form's
+ * member variables are not necessarily extensible arrays, as is the case with
+ * mesh */
+struct shape {
+ double* pos;
+ size_t* ids;
+ size_t npos;
+ size_t ntri;
+};
+#define SHAPE_NULL__ {NULL, NULL, 0, 0}
+static const struct shape SHAPE_NULL = SHAPE_NULL__;
+
+static void
+get_position(const unsigned ivert, float pos[3], void* ctx)
+{
+ const struct shape* shape = ctx;
+ CHK(shape && pos && ivert < shape->npos);
+ f3_set_d3(pos, shape->pos + ivert*3);
+}
+
+static void
+get_indices(const unsigned itri, unsigned ids[3], void* ctx)
+{
+ const struct shape* shape = ctx;
+ CHK(shape && ids && itri < shape->ntri);
+ ids[0] = (unsigned)shape->ids[itri*3+0];
+ ids[1] = (unsigned)shape->ids[itri*3+1];
+ ids[2] = (unsigned)shape->ids[itri*3+2];
+}
+
+static struct s3d_scene_view*
+create_view(struct shape* shape_data)
+{
+ /* Star3D */
+ struct s3d_vertex_data vdata = S3D_VERTEX_DATA_NULL;
+ struct s3d_device* dev = NULL;
+ struct s3d_scene* scn = NULL;
+ struct s3d_shape* shape = NULL;
+ struct s3d_scene_view* view = NULL;
+
+ OK(s3d_device_create(NULL, NULL, 0, &dev));
+
+ /* Shape */
+ vdata.usage = S3D_POSITION;
+ vdata.type = S3D_FLOAT3;
+ vdata.get = get_position;
+ OK(s3d_shape_create_mesh(dev, &shape));
+ OK(s3d_mesh_setup_indexed_vertices(shape, (unsigned)shape_data->ntri,
+ get_indices, (unsigned)shape_data->npos, &vdata, 1, shape_data));
+
+ /* Scene view */
+ OK(s3d_scene_create(dev, &scn));
+ OK(s3d_scene_attach_shape(scn, shape));
+ OK(s3d_scene_view_create(scn, S3D_TRACE|S3D_GET_PRIMITIVE, &view));
+
+ /* Clean up */
+ OK(s3d_device_ref_put(dev));
+ OK(s3d_scene_ref_put(scn));
+ OK(s3d_shape_ref_put(shape));
+
+ return view;
+}
+
+/*******************************************************************************
+ * Mesh, i.e. supershape and sphere
+ ******************************************************************************/
+static void
+mesh_add_super_shape(struct mesh* mesh)
+{
+ struct s3dut_mesh* sshape = NULL;
+ struct s3dut_mesh_data sshape_data;
+ struct s3dut_super_formula f0 = S3DUT_SUPER_FORMULA_NULL;
+ struct s3dut_super_formula f1 = S3DUT_SUPER_FORMULA_NULL;
+ const double radius = 2;
+ 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, &sshape));
+ OK(s3dut_mesh_get_data(sshape, &sshape_data));
+ mesh_append(mesh, sshape_data.positions, sshape_data.nvertices,
+ sshape_data.indices, sshape_data.nprimitives, NULL);
+ OK(s3dut_mesh_ref_put(sshape));
+}
+
+static void
+mesh_add_sphere(struct mesh* mesh)
+{
+ struct s3dut_mesh* sphere = NULL;
+ struct s3dut_mesh_data sphere_data;
+ const double radius = SPHERE_RADIUS;
+ const unsigned nslices = 128;
+
+ OK(s3dut_create_sphere(NULL, radius, nslices, nslices/2, &sphere));
+ OK(s3dut_mesh_get_data(sphere, &sphere_data));
+ mesh_append(mesh, sphere_data.positions, sphere_data.nvertices,
+ sphere_data.indices, sphere_data.nprimitives, NULL);
+ OK(s3dut_mesh_ref_put(sphere));
+}
+
+/*******************************************************************************
+ * Custom conductive path
+ ******************************************************************************/
+struct custom_solid {
+ struct s3d_scene_view* view; /* Star-3D view of the shape */
+ const struct shape* shape; /* Raw data */
+};
+
+static void
+setup_solver_primitive
+ (struct sdis_scene* scn,
+ const struct shape* shape,
+ const struct s3d_hit* user_hit,
+ struct s3d_primitive* prim)
+{
+ struct sdis_primkey key = SDIS_PRIMKEY_NULL;
+ const double *v0, *v1, *v2;
+ float v0f[3], v1f[3], v2f[3];
+ struct s3d_attrib attr0, attr1, attr2;
+
+ v0 = shape->pos + shape->ids[user_hit->prim.prim_id*3+0]*3;
+ v1 = shape->pos + shape->ids[user_hit->prim.prim_id*3+1]*3;
+ v2 = shape->pos + shape->ids[user_hit->prim.prim_id*3+2]*3;
+ sdis_primkey_setup(&key, v0, v1, v2);
+ OK(sdis_scene_get_s3d_primitive(scn, &key, prim));
+
+ /* Check that the primitive on the solver side is the same as that on the
+ * user side. On the solver side, vertices are stored in simple precision in
+ * Star-3D view. We therefore need to take care of this conversion to check
+ * that the vertices are the same */
+ OK(s3d_triangle_get_vertex_attrib(prim, 0, S3D_POSITION, &attr0));
+ OK(s3d_triangle_get_vertex_attrib(prim, 1, S3D_POSITION, &attr1));
+ OK(s3d_triangle_get_vertex_attrib(prim, 2, S3D_POSITION, &attr2));
+ f3_set_d3(v0f, v0);
+ f3_set_d3(v1f, v1);
+ f3_set_d3(v2f, v2);
+
+ /* The vertices have been inverted on the user's side to reverse the normal
+ * orientation. Below it is taken into account */
+ CHK(f3_eq(v0f, attr0.value));
+ CHK(f3_eq(v1f, attr2.value));
+ CHK(f3_eq(v2f, attr1.value));
+}
+
+/* Implementation of a Walk on Sphere algorithm for an origin-centered spherical
+ * geometry of radius SPHERE_RADIUS */
+static res_T
+sample_steady_diffusive_path
+ (struct sdis_scene* scn,
+ struct ssp_rng* rng,
+ struct sdis_path* path,
+ struct sdis_data* data)
+{
+ struct custom_solid* solid = NULL;
+ struct s3d_hit hit = S3D_HIT_NULL;
+
+ double pos[3];
+ const double epsilon = SPHERE_RADIUS * 1.e-6; /* Epsilon shell */
+
+ CHK(scn && rng && path && data);
+
+ solid = sdis_data_get(data);
+
+ d3_set(pos, path->vtx.P);
+
+ do {
+ /* Distance from the geometry center to the current position */
+ const double dst = d3_len(pos);
+
+ double dir[3] = {0,0,0};
+ double r = 0; /* Radius */
+
+ r = SPHERE_RADIUS - dst;
+ CHK(dst > 0);
+
+ if(r > epsilon) {
+ /* Uniformly sample a new position on the surrounding sphere */
+ ssp_ran_sphere_uniform(rng, dir, NULL);
+
+ /* Move to the new position */
+ d3_muld(dir, dir, r);
+ d3_add(pos, pos, dir);
+
+ /* The current position is in the epsilon shell:
+ * move it to the nearest interface position */
+ } else {
+ float posf[3];
+
+ d3_set(dir, pos);
+ d3_normalize(dir, dir);
+ d3_muld(pos, dir, SPHERE_RADIUS);
+
+ /* Map the position to the sphere geometry */
+ f3_set_d3(posf, pos);
+ OK(s3d_scene_view_closest_point(solid->view, posf, (float)INF, NULL, &hit));
+ }
+
+ /* The calculation is performed in steady state, so the path necessarily stops
+ * at a boundary */
+ } while(S3D_HIT_NONE(&hit));
+
+ /* Setup the path state */
+ d3_set(path->vtx.P, pos);
+ path->weight = 0;
+ path->at_limit = 0;
+ path->prim_2d = S2D_PRIMITIVE_NULL;
+ setup_solver_primitive(scn, solid->shape, &hit, &path->prim_3d);
+
+ return RES_OK;
+}
+
+/*******************************************************************************
+ * The solids, i.e. media of the super shape and the sphere
+ ******************************************************************************/
+#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, 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, SDIS_TEMPERATURE_NONE/*<=> unknown*/) /* [K] */
+SOLID_PROP(delta, 1.0/40.0) /* [m] */
+
+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;
+}
+
+static struct sdis_medium*
+create_custom
+ (struct sdis_device* sdis,
+ struct s3d_scene_view* view,
+ const struct shape* shape)
+{
+ /* Stardis variables */
+ struct sdis_solid_shader shader = SDIS_SOLID_SHADER_NULL;
+ struct sdis_medium* solid = NULL;
+ struct sdis_data* data = NULL;
+
+ /* Mesh variables */
+ struct custom_solid* custom_solid = NULL;
+ const size_t sz = sizeof(struct custom_solid);
+ const size_t al = ALIGNOF(struct custom_solid);
+
+ OK(sdis_data_create(sdis, sz, al, NULL, &data));
+ custom_solid = sdis_data_get(data);
+ custom_solid->view = view;
+ custom_solid->shape = shape;
+
+ 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.sample_path = sample_steady_diffusive_path;
+
+ OK(sdis_solid_create(sdis, &shader, data, &solid));
+ OK(sdis_data_ref_put(data));
+
+ 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 trilinear profile
+ ******************************************************************************/
+static double
+interface_get_temperature
+ (const struct sdis_interface_fragment* frag,
+ struct sdis_data* data)
+{
+ (void)data; /* Avoid the "unused variable" warning */
+ return trilinear_profile(frag->P);
+}
+
+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;
+
+ /* Fluid/solid interface: fix the temperature to the temperature profile */
+ if(sdis_medium_get_type(front) != sdis_medium_get_type(back)) {
+ shader.front.temperature = interface_get_temperature;
+ shader.back.temperature = interface_get_temperature;
+ }
+
+ OK(sdis_interface_create(sdis, front, back, &shader, NULL, &interf));
+ return interf;
+}
+
+/*******************************************************************************
+ * Scene, i.e. the system to simulate
+ ******************************************************************************/
+struct scene_context {
+ const struct mesh* mesh;
+ size_t sshape_end_id; /* Last triangle index of the super shape */
+ struct sdis_interface* sshape;
+ struct sdis_interface* sphere;
+};
+#define SCENE_CONTEXT_NULL__ {NULL, 0, 0, 0}
+static const struct scene_context SCENE_CONTEXT_NULL = SCENE_CONTEXT_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 < mesh_ntriangles(context->mesh));
+ /* Flip the indices to ensure that the normal points into the super shape */
+ ids[0] = (unsigned)context->mesh->indices[itri*3+0];
+ ids[1] = (unsigned)context->mesh->indices[itri*3+2];
+ ids[2] = (unsigned)context->mesh->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 < mesh_ntriangles(context->mesh));
+ if(itri < context->sshape_end_id) {
+ *interf = context->sshape;
+ } else {
+ *interf = context->sphere;
+ }
+}
+
+static void
+scene_get_position(const size_t ivert, double pos[3], void* ctx)
+{
+ struct scene_context* context = ctx;
+ CHK(pos && context && ivert < mesh_nvertices(context->mesh));
+ pos[0] = context->mesh->positions[ivert*3+0];
+ pos[1] = context->mesh->positions[ivert*3+1];
+ pos[2] = context->mesh->positions[ivert*3+2];
+}
+
+static struct sdis_scene*
+create_scene(struct sdis_device* sdis, struct scene_context* ctx)
+{
+ struct sdis_scene* scn = NULL;
+ struct sdis_scene_create_args scn_args = SDIS_SCENE_CREATE_ARGS_DEFAULT;
+
+ scn_args.get_indices = scene_get_indices;
+ scn_args.get_interface = scene_get_interface;
+ scn_args.get_position = scene_get_position;
+ scn_args.nprimitives = mesh_ntriangles(ctx->mesh);
+ scn_args.nvertices = mesh_nvertices(ctx->mesh);
+ scn_args.context = ctx;
+ OK(sdis_scene_create(sdis, &scn_args, &scn));
+ return scn;
+}
+
+/*******************************************************************************
+ * Validations
+ ******************************************************************************/
+static void
+check_probe(struct sdis_scene* scn, const int is_master_process)
+{
+ 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.position[0] = SPHERE_RADIUS*0.125;
+ args.position[1] = SPHERE_RADIUS*0.250;
+ args.position[2] = SPHERE_RADIUS*0.375;
+ args.nrealisations = NREALISATIONS;
+
+ OK(sdis_solve_probe(scn, &args, &estimator));
+
+ if(!is_master_process) return;
+
+ OK(sdis_estimator_get_temperature(estimator, &T));
+
+ ref = trilinear_profile(args.position);
+
+ printf("T(%g, %g, %g) = %g ~ %g +/- %g\n",
+ SPLIT3(args.position), ref, T.E, T.SE);
+
+ CHK(eq_eps(ref, T.E, T.SE*3));
+ OK(sdis_estimator_ref_put(estimator));
+}
+
+/*******************************************************************************
+ * The test
+ ******************************************************************************/
+int
+main(int argc, char** argv)
+{
+ /* Stardis */
+ struct sdis_device* dev = NULL;
+ struct sdis_interface* solid_dummy = NULL;
+ struct sdis_interface* custom_solid = NULL;
+ struct sdis_medium* solid = NULL;
+ struct sdis_medium* custom = NULL;
+ struct sdis_medium* dummy = NULL; /* Medium surrounding the solid */
+ struct sdis_scene* scn = NULL;
+
+ /* Star3D */
+ struct shape shape = SHAPE_NULL;
+ struct s3d_scene_view* sphere_view = NULL;
+
+ /* Miscellaneous */
+ struct scene_context ctx = SCENE_CONTEXT_NULL;
+ struct mesh mesh = MESH_NULL;
+ size_t sshape_end_id = 0; /* Last index of the super shape */
+ int is_master_process = 1;
+ (void)argc, (void)argv;
+
+ create_default_device(&argc, &argv, &is_master_process, &dev);
+
+ /* Mesh */
+ mesh_init(&mesh);
+ mesh_add_super_shape(&mesh);
+ sshape_end_id = mesh_ntriangles(&mesh);
+ mesh_add_sphere(&mesh);
+
+ /* Create a view of the sphere's geometry. This will be used to couple custom
+ * solid path sampling to the solver */
+ shape.pos = mesh.positions;
+ shape.ids = mesh.indices + sshape_end_id*3;
+ shape.npos = mesh_nvertices(&mesh);
+ shape.ntri = mesh_ntriangles(&mesh) - sshape_end_id/* #sshape triangles*/;
+ sphere_view = create_view(&shape);
+
+ /* Physical properties */
+ dummy = create_dummy(dev);
+ solid = create_solid(dev);
+ custom = create_custom(dev, sphere_view, &shape);
+ solid_dummy = create_interface(dev, solid, dummy);
+ custom_solid = create_interface(dev, custom, solid);
+
+ /* Scene */
+ ctx.mesh = &mesh;
+ ctx.sshape_end_id = sshape_end_id;
+ ctx.sshape = solid_dummy;
+ ctx.sphere = custom_solid;
+ scn = create_scene(dev, &ctx);
+
+ check_probe(scn, is_master_process);
+
+ mesh_release(&mesh);
+
+ OK(s3d_scene_view_ref_put(sphere_view));
+ OK(sdis_interface_ref_put(solid_dummy));
+ OK(sdis_interface_ref_put(custom_solid));
+ OK(sdis_medium_ref_put(custom));
+ OK(sdis_medium_ref_put(dummy));
+ OK(sdis_medium_ref_put(solid));
+ OK(sdis_scene_ref_put(scn));
+
+ free_default_device(dev);
+
+ CHK(mem_allocated_size() == 0);
+ return 0;
+}
diff --git a/src/test_sdis_custom_solid_path_sampling_2d.c b/src/test_sdis_custom_solid_path_sampling_2d.c
@@ -0,0 +1,600 @@
+/* Copyright (C) 2016-2024 |Méso|Star> (contact@meso-star.com)
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+#include "sdis.h"
+#include "test_sdis_mesh.h"
+#include "test_sdis_utils.h"
+
+#include <rsys/double2.h>
+#include <rsys/float2.h>
+
+#include <star/s2d.h>
+
+/*
+ * The system is a bilinear profile of the temperature at steady state, i.e. at
+ * each point of the system we can calculate the temperature analytically. Two
+ * forms are immersed in this temperature field: a super shape and a circle
+ * included in the super shape. On the Monte Carlo side, the temperature is
+ * unknown everywhere except on the surface of the super shape whose
+ * temperature is defined from the aformentionned bilinear profile.
+ *
+ * We will estimate the temperature at the position of a probe in solids by
+ * providing a user-side function to sample the conductive path in the circle.
+ * We should find the temperature of the bilinear profile at the probe position
+ * by Monte Carlo, independently of this coupling with an external path sampling
+ * routine.
+ *
+ *
+ * /\ <-- T(x,y,z)
+ * ___/ \___
+ * T(y) \ __ /
+ * | T(y) \ / \ /
+ * |/ T=? *__/ \
+ * o--- T(x) /_ __ _\
+ * \/ \/
+ */
+
+#define NREALISATIONS 10000
+#define CIRCLE_RADIUS 1
+
+/*******************************************************************************
+ * Helper functions
+ ******************************************************************************/
+static double
+bilinear_profile(const double pos[2])
+{
+ /* Range in X, Y in which the trilinear profile is defined */
+ const double lower = -4;
+ const double upper = +4;
+
+ /* Upper temperature limit in X, Y and Z [K]. Lower temperature limit is
+ * implicitly 0 */
+ const double a = 333; /* Upper temperature limit in X [K] */
+ const double b = 432; /* Upper temperature limit in Y [K] */
+
+ double x, y;
+
+ /* Check pre-conditions */
+ CHK(pos);
+ CHK(lower <= pos[0] && pos[0] <= upper);
+ CHK(lower <= pos[1] && pos[1] <= upper);
+
+ x = (pos[0] - lower) / (upper - lower);
+ y = (pos[1] - lower) / (upper - lower);
+ return a*x + b*y;
+}
+
+/*******************************************************************************
+ * Scene view
+ ******************************************************************************/
+/* Parameter for get_inidices/get_vertices functions. Although its layout is the
+ * same as that of the mesh data structure, we have deliberately defined a new
+ * data type since mesh functions cannot be invoked. This is because the form's
+ * member variables are not necessarily extensible arrays, as is the case with
+ * mesh */
+struct shape {
+ double* pos;
+ size_t* ids;
+ size_t npos;
+ size_t nseg;
+};
+#define SHAPE_NULL__ {NULL, NULL, 0, 0}
+static const struct shape SHAPE_NULL = SHAPE_NULL__;
+
+static void
+get_position(const unsigned ivert, float pos[2], void* ctx)
+{
+ const struct shape* shape = ctx;
+ CHK(shape && pos && ivert < shape->npos);
+ f2_set_d2(pos, shape->pos + ivert*2);
+}
+
+static void
+get_indices(const unsigned iseg, unsigned ids[2], void* ctx)
+{
+ const struct shape* shape = ctx;
+ CHK(shape && ids && iseg < shape->nseg);
+ ids[0] = (unsigned)shape->ids[iseg*2+0];
+ ids[1] = (unsigned)shape->ids[iseg*2+1];
+}
+
+static struct s2d_scene_view*
+create_view(struct shape* shape_data)
+{
+ /* Star2D */
+ struct s2d_vertex_data vdata = S2D_VERTEX_DATA_NULL;
+ struct s2d_device* dev = NULL;
+ struct s2d_scene* scn = NULL;
+ struct s2d_shape* shape = NULL;
+ struct s2d_scene_view* view = NULL;
+
+ OK(s2d_device_create(NULL, NULL, 0, &dev));
+
+ /* Shape */
+ vdata.usage = S2D_POSITION;
+ vdata.type = S2D_FLOAT2;
+ vdata.get = get_position;
+ OK(s2d_shape_create_line_segments(dev, &shape));
+ OK(s2d_line_segments_setup_indexed_vertices(shape, (unsigned)shape_data->nseg,
+ get_indices, (unsigned)shape_data->npos, &vdata, 1, shape_data));
+
+ /* Scene view */
+ OK(s2d_scene_create(dev, &scn));
+ OK(s2d_scene_attach_shape(scn, shape));
+ OK(s2d_scene_view_create(scn, S2D_TRACE|S2D_GET_PRIMITIVE, &view));
+
+ /* Clean up */
+ OK(s2d_device_ref_put(dev));
+ OK(s2d_scene_ref_put(scn));
+ OK(s2d_shape_ref_put(shape));
+
+ return view;
+}
+
+/*******************************************************************************
+ * Mesh, i.e. supershape and sphere
+ ******************************************************************************/
+static void
+mesh_add_super_shape(struct mesh* mesh)
+{
+ double* pos = NULL;
+ size_t* ids = 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;
+
+ CHK(mesh);
+
+ 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 * CIRCLE_RADIUS*2;
+ const double y = sin(theta) * r * CIRCLE_RADIUS*2;
+ const size_t j = (i + 1) % nslices;
+
+ sa_push(pos, x);
+ sa_push(pos, y);
+ sa_push(ids, i);
+ sa_push(ids, j);
+ }
+
+ mesh_2d_append(mesh, pos, sa_size(pos)/2, ids, sa_size(ids)/2, NULL);
+
+ sa_release(pos);
+ sa_release(ids);
+}
+
+static void
+mesh_add_circle(struct mesh* mesh)
+{
+ double* pos = NULL;
+ size_t* ids = NULL;
+
+ const size_t nverts = 64;
+ size_t i = 0;
+
+ CHK(mesh);
+
+ FOR_EACH(i, 0, nverts) {
+ const double theta = (double)i * (2*PI)/(double)nverts;
+ const double x = cos(theta)*CIRCLE_RADIUS;
+ const double y = sin(theta)*CIRCLE_RADIUS;
+ const size_t j = (i+1)%nverts;
+
+ sa_push(pos, x);
+ sa_push(pos, y);
+ sa_push(ids, i);
+ sa_push(ids, j);
+ }
+
+ mesh_2d_append(mesh, pos, sa_size(pos)/2, ids, sa_size(ids)/2, NULL);
+
+ sa_release(pos);
+ sa_release(ids);
+}
+
+/*******************************************************************************
+ * Custom conductive path
+ ******************************************************************************/
+struct custom_solid {
+ struct s2d_scene_view* view; /* Star-2D view of the shape */
+ const struct shape* shape; /* Raw data */
+};
+
+static void
+setup_solver_primitive
+ (struct sdis_scene* scn,
+ const struct shape* shape,
+ const struct s2d_hit* user_hit,
+ struct s2d_primitive* prim)
+{
+ struct sdis_primkey key = SDIS_PRIMKEY_NULL;
+ const double *v0, *v1;
+ float v0f[2], v1f[2];
+ struct s2d_attrib attr0, attr1;
+
+ v0 = shape->pos + shape->ids[user_hit->prim.prim_id*2+0]*2;
+ v1 = shape->pos + shape->ids[user_hit->prim.prim_id*2+1]*2;
+ sdis_primkey_2d_setup(&key, v0, v1);
+ OK(sdis_scene_get_s2d_primitive(scn, &key, prim));
+
+ /* Check that the primitive on the solver side is the same as that on the
+ * user side. On the solver side, vertices are stored in simple precision in
+ * Star-3D view. We therefore need to take care of this conversion to check
+ * that the vertices are the same */
+ OK(s2d_segment_get_vertex_attrib(prim, 0, S2D_POSITION, &attr0));
+ OK(s2d_segment_get_vertex_attrib(prim, 1, S2D_POSITION, &attr1));
+ f2_set_d2(v0f, v0);
+ f2_set_d2(v1f, v1);
+
+ /* The vertices have been inverted on the user's side to reverse the normal
+ * orientation. Below it is taken into account */
+ CHK(f2_eq(v0f, attr0.value));
+ CHK(f2_eq(v1f, attr1.value));
+}
+
+/* Implementation of a Walk on Sphere algorithm for an origin-centered spherical
+ * geometry of radius SPHERE_RADIUS */
+static res_T
+sample_steady_diffusive_path
+ (struct sdis_scene* scn,
+ struct ssp_rng* rng,
+ struct sdis_path* path,
+ struct sdis_data* data)
+{
+ struct custom_solid* solid = NULL;
+ struct s2d_hit hit = S2D_HIT_NULL;
+
+ double pos[2];
+ const double epsilon = CIRCLE_RADIUS * 1.e-6; /* Epsilon shell */
+
+ CHK(scn && rng && path && data);
+
+ solid = sdis_data_get(data);
+
+ d2_set(pos, path->vtx.P);
+
+ do {
+ /* Distance from the geometry center to the current position */
+ const double dst = d2_len(pos);
+
+ double dir[3] = {0,0,0};
+ double r = 0; /* Radius */
+
+ r = CIRCLE_RADIUS - dst;
+ CHK(dst > 0);
+
+ if(r > epsilon) {
+ /* Uniformly sample a new position on the surrounding sphere */
+ ssp_ran_circle_uniform(rng, dir, NULL);
+
+ /* Move to the new position */
+ d2_muld(dir, dir, r);
+ d2_add(pos, pos, dir);
+
+ /* The current position is in the epsilon shell:
+ * move it to the nearest interface position */
+ } else {
+ float posf[2];
+
+ d2_set(dir, pos);
+ d2_normalize(dir, dir);
+ d2_muld(pos, dir, CIRCLE_RADIUS);
+
+ /* Map the position to the sphere geometry */
+ f2_set_d2(posf, pos);
+ OK(s2d_scene_view_closest_point(solid->view, posf, (float)INF, NULL, &hit));
+ }
+
+ /* The calculation is performed in steady state, so the path necessarily stops
+ * at a boundary */
+ } while(S2D_HIT_NONE(&hit));
+
+ /* Setup the path state */
+ d2_set(path->vtx.P, pos);
+ path->weight = 0;
+ path->at_limit = 0;
+ path->prim_3d = S3D_PRIMITIVE_NULL;
+ setup_solver_primitive(scn, solid->shape, &hit, &path->prim_2d);
+
+ return RES_OK;
+}
+/*******************************************************************************
+ * The solids, i.e. media of the super shape and the sphere
+ ******************************************************************************/
+#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, 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, SDIS_TEMPERATURE_NONE/*<=> unknown*/) /* [K] */
+SOLID_PROP(delta, 1.0/40.0) /* [m] */
+
+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;
+}
+
+static struct sdis_medium*
+create_custom
+ (struct sdis_device* sdis,
+ struct s2d_scene_view* view,
+ const struct shape* shape)
+{
+ /* Stardis variables */
+ struct sdis_solid_shader shader = SDIS_SOLID_SHADER_NULL;
+ struct sdis_medium* solid = NULL;
+ struct sdis_data* data = NULL;
+
+ /* Mesh variables */
+ struct custom_solid* custom_solid = NULL;
+ const size_t sz = sizeof(struct custom_solid);
+ const size_t al = ALIGNOF(struct custom_solid);
+
+ OK(sdis_data_create(sdis, sz, al, NULL, &data));
+ custom_solid = sdis_data_get(data);
+ custom_solid->view = view;
+ custom_solid->shape = shape;
+
+ 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.sample_path = sample_steady_diffusive_path;
+
+ OK(sdis_solid_create(sdis, &shader, data, &solid));
+ OK(sdis_data_ref_put(data));
+
+ 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 trilinear profile
+ ******************************************************************************/
+static double
+interface_get_temperature
+ (const struct sdis_interface_fragment* frag,
+ struct sdis_data* data)
+{
+ (void)data; /* Avoid the "unused variable" warning */
+ return bilinear_profile(frag->P);
+}
+
+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;
+
+ /* Fluid/solid interface: fix the temperature to the temperature profile */
+ if(sdis_medium_get_type(front) != sdis_medium_get_type(back)) {
+ shader.front.temperature = interface_get_temperature;
+ shader.back.temperature = interface_get_temperature;
+ }
+
+ OK(sdis_interface_create(sdis, front, back, &shader, NULL, &interf));
+ return interf;
+}
+
+/*******************************************************************************
+ * Scene, i.e. the system to simulate
+ ******************************************************************************/
+struct scene_context {
+ const struct mesh* mesh;
+ size_t sshape_end_id; /* Last segment index of the super shape */
+ struct sdis_interface* sshape;
+ struct sdis_interface* sphere;
+};
+#define SCENE_CONTEXT_NULL__ {NULL, 0, 0, 0}
+static const struct scene_context SCENE_CONTEXT_NULL = SCENE_CONTEXT_NULL__;
+
+static void
+scene_get_indices(const size_t iseg, size_t ids[2], void* ctx)
+{
+ struct scene_context* context = ctx;
+ CHK(ids && context && iseg < mesh_2d_nsegments(context->mesh));
+ ids[0] = (unsigned)context->mesh->indices[iseg*2+0];
+ ids[1] = (unsigned)context->mesh->indices[iseg*2+1];
+}
+
+static void
+scene_get_interface(const size_t iseg, struct sdis_interface** interf, void* ctx)
+{
+ struct scene_context* context = ctx;
+ CHK(interf && context && iseg < mesh_2d_nsegments(context->mesh));
+ if(iseg < context->sshape_end_id) {
+ *interf = context->sshape;
+ } else {
+ *interf = context->sphere;
+ }
+}
+
+static void
+scene_get_position(const size_t ivert, double pos[2], void* ctx)
+{
+ struct scene_context* context = ctx;
+ CHK(pos && context && ivert < mesh_2d_nvertices(context->mesh));
+ pos[0] = context->mesh->positions[ivert*2+0];
+ pos[1] = context->mesh->positions[ivert*2+1];
+}
+
+static struct sdis_scene*
+create_scene(struct sdis_device* sdis, struct scene_context* ctx)
+{
+ struct sdis_scene* scn = NULL;
+ struct sdis_scene_create_args scn_args = SDIS_SCENE_CREATE_ARGS_DEFAULT;
+
+ scn_args.get_indices = scene_get_indices;
+ scn_args.get_interface = scene_get_interface;
+ scn_args.get_position = scene_get_position;
+ scn_args.nprimitives = mesh_2d_nsegments(ctx->mesh);
+ scn_args.nvertices = mesh_2d_nvertices(ctx->mesh);
+ scn_args.context = ctx;
+ OK(sdis_scene_2d_create(sdis, &scn_args, &scn));
+ return scn;
+}
+
+/*******************************************************************************
+ * Validations
+ ******************************************************************************/
+static void
+check_probe(struct sdis_scene* scn, const int is_master_process)
+{
+ 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.position[0] = CIRCLE_RADIUS*0.125;
+ args.position[1] = CIRCLE_RADIUS*0.250;
+ args.nrealisations = NREALISATIONS;
+
+ OK(sdis_solve_probe(scn, &args, &estimator));
+
+ if(!is_master_process) return;
+
+ OK(sdis_estimator_get_temperature(estimator, &T));
+
+ ref = bilinear_profile(args.position);
+
+ printf("T(%g, %g) = %g ~ %g +/- %g\n",
+ SPLIT2(args.position), ref, T.E, T.SE);
+
+ CHK(eq_eps(ref, T.E, T.SE*3));
+ OK(sdis_estimator_ref_put(estimator));
+}
+
+/*******************************************************************************
+ * The test
+ ******************************************************************************/
+int
+main(int argc, char** argv)
+{
+ /* Stardis */
+ struct sdis_device* dev = NULL;
+ struct sdis_interface* solid_dummy = NULL;
+ struct sdis_interface* custom_solid = NULL;
+ struct sdis_medium* solid = NULL;
+ struct sdis_medium* custom = NULL;
+ struct sdis_medium* dummy = NULL; /* Medium surrounding the solid */
+ struct sdis_scene* scn = NULL;
+
+ /* Star 2D */
+ struct shape shape = SHAPE_NULL;
+ struct s2d_scene_view* circle_view = NULL;
+
+ /* Miscellaneous */
+ struct scene_context ctx = SCENE_CONTEXT_NULL;
+ struct mesh mesh = MESH_NULL;
+ size_t sshape_end_id = 0; /* Last index of the super shape */
+ int is_master_process = 1;
+ (void)argc, (void)argv;
+
+ create_default_device(&argc, &argv, &is_master_process, &dev);
+
+ /* Mesh */
+ mesh_init(&mesh);
+ mesh_add_super_shape(&mesh);
+ sshape_end_id = mesh_2d_nsegments(&mesh);
+ mesh_add_circle(&mesh);
+
+ /* Create a view of the circle's geometry. This will be used to couple custom
+ * solid path sampling to the solver */
+ shape.pos = mesh.positions;
+ shape.ids = mesh.indices + sshape_end_id*2;
+ shape.npos = mesh_2d_nvertices(&mesh);
+ shape.nseg = mesh_2d_nsegments(&mesh) - sshape_end_id;
+ circle_view = create_view(&shape);
+
+ /* Physical properties */
+ dummy = create_dummy(dev);
+ solid = create_solid(dev);
+ custom = create_custom(dev, circle_view, &shape);
+ solid_dummy = create_interface(dev, dummy, solid);
+ custom_solid = create_interface(dev, solid, custom);
+
+ /* Scene */
+ ctx.mesh = &mesh;
+ ctx.sshape_end_id = sshape_end_id;
+ ctx.sshape = solid_dummy;
+ ctx.sphere = custom_solid;
+ scn = create_scene(dev, &ctx);
+
+ check_probe(scn, is_master_process);
+
+ mesh_release(&mesh);
+
+ OK(s2d_scene_view_ref_put(circle_view));
+ OK(sdis_interface_ref_put(solid_dummy));
+ OK(sdis_interface_ref_put(custom_solid));
+ OK(sdis_medium_ref_put(custom));
+ OK(sdis_medium_ref_put(dummy));
+ OK(sdis_medium_ref_put(solid));
+ OK(sdis_scene_ref_put(scn));
+
+ free_default_device(dev);
+
+ CHK(mem_allocated_size() == 0);
+ return 0;
+}
diff --git a/src/test_sdis_mesh.h b/src/test_sdis_mesh.h
@@ -49,6 +49,13 @@ mesh_nvertices(const struct mesh* mesh)
return sa_size(mesh->positions) / 3/* #coords per vertex */;
}
+static INLINE size_t
+mesh_2d_nvertices(const struct mesh* mesh)
+{
+ CHK(mesh);
+ return sa_size(mesh->positions) / 2/* #coords per vertex */;
+}
+
/* Number of triangles */
static INLINE size_t
mesh_ntriangles(const struct mesh* mesh)
@@ -57,6 +64,13 @@ mesh_ntriangles(const struct mesh* mesh)
return sa_size(mesh->indices) / 3/* #indices per triangle */;
}
+static INLINE size_t
+mesh_2d_nsegments(const struct mesh* mesh)
+{
+ CHK(mesh);
+ return sa_size(mesh->indices) / 2/* #indices per segment */;
+}
+
static INLINE void
mesh_append
(struct mesh* mesh,
@@ -97,6 +111,42 @@ mesh_append
}
static INLINE void
+mesh_2d_append
+ (struct mesh* mesh,
+ const double* in_positions,
+ const size_t in_nvertices,
+ const size_t* in_indices,
+ const size_t in_nsegments,
+ const double in_translate[2]) /* May be NULL */
+{
+ double translate[2] = {0, 0};
+ double* positions = NULL;
+ size_t* indices = NULL;
+ size_t ivert = 0;
+ size_t i = 0;
+ CHK(mesh != NULL);
+
+ ivert = mesh_2d_nvertices(mesh);
+ positions = sa_add(mesh->positions, in_nvertices*2);
+ indices = sa_add(mesh->indices, in_nsegments*2);
+
+ if(in_translate) {
+ translate[0] = in_translate[0];
+ translate[1] = in_translate[1];
+ }
+
+ FOR_EACH(i, 0, in_nvertices) {
+ positions[i*2 + 0] = in_positions[i*2 + 0] + translate[0];
+ positions[i*2 + 1] = in_positions[i*2 + 1] + translate[1];
+ }
+
+ FOR_EACH(i, 0, in_nsegments) {
+ indices[i*2 + 0] = in_indices[i*2 + 0] + ivert;
+ indices[i*2 + 1] = in_indices[i*2 + 1] + ivert;
+ }
+}
+
+static INLINE void
mesh_dump(const struct mesh* mesh, FILE* stream)
{
size_t i, n;
@@ -117,4 +167,24 @@ mesh_dump(const struct mesh* mesh, FILE* stream)
fflush(stream);
}
+static INLINE void
+mesh_2d_dump(const struct mesh* mesh, FILE* stream)
+{
+ size_t i, n;
+ CHK(mesh != NULL);
+
+ n = mesh_2d_nvertices(mesh);
+ FOR_EACH(i, 0, n) {
+ fprintf(stream, "v %g %g\n", SPLIT2(mesh->positions+i*2));
+ }
+
+ n = mesh_2d_nsegments(mesh);
+ FOR_EACH(i, 0, n) {
+ fprintf(stream, "l %lu %lu\n",
+ (unsigned long)(mesh->indices[i*2+0] + 1),
+ (unsigned long)(mesh->indices[i*2+1] + 1));
+ }
+ fflush(stream);
+}
+
#endif /* TEST_SDIS_MESH_H */
diff --git a/src/test_sdis_primkey.c b/src/test_sdis_primkey.c
@@ -0,0 +1,281 @@
+/* Copyright (C) 2016-2024 |Méso|Star> (contact@meso-star.com)
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+#include "sdis.h"
+#include "test_sdis_utils.h"
+
+#include <star/s3dut.h>
+#include <rsys/float3.h>
+
+/*
+ * The system is a solid supershape whose boundary temperature is set to a
+ * constant. The temperature of the solid is therefore this same temperature.
+ * This simplistic test case is not used to verify a Monte Carlo estimate, but
+ * to ensure that the caller can recover the internal representation of the
+ * geometric primitives from his own data.
+ *
+ * /\
+ * ___/ \___
+ * \ /
+ * /_ __ _\
+ * \/ \/
+ *
+ */
+
+/*******************************************************************************
+ * Super shape
+ ******************************************************************************/
+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;
+}
+
+/*******************************************************************************
+ * 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, 1) /* [J/K/Kg] */
+SOLID_PROP(thermal_conductivity, 1) /* [W/m/K] */
+SOLID_PROP(volumic_mass, 1) /* [kg/m^3] */
+SOLID_PROP(temperature, SDIS_TEMPERATURE_NONE) /* [K] */
+SOLID_PROP(delta, 1.0/20.0) /* [m/fp_to_meter] */
+#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;
+ 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
+ ******************************************************************************/
+static double
+interface_get_temperature
+ (const struct sdis_interface_fragment* frag,
+ struct sdis_data* data)
+{
+ (void)frag, (void)data; /* Avoid the "unused variable" warning */
+ return 300; /* [K] */
+}
+
+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;
+}
+
+/*******************************************************************************
+ * 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;
+}
+
+/*******************************************************************************
+ * Validation
+ ******************************************************************************/
+static void
+check(struct sdis_scene* scn, const struct s3dut_mesh* mesh)
+{
+ struct s3d_primitive prim = S3D_PRIMITIVE_NULL;
+ struct s3dut_mesh_data mesh_data;
+ struct sdis_primkey key = SDIS_PRIMKEY_NULL;
+ size_t iprim = 0;
+
+ OK(s3dut_mesh_get_data(mesh, &mesh_data));
+
+ BA(sdis_scene_get_s3d_primitive(NULL, &key, &prim));
+ BA(sdis_scene_get_s3d_primitive(scn, NULL, &prim));
+ BA(sdis_scene_get_s3d_primitive(scn, &key, NULL));
+ BA(sdis_scene_get_s3d_primitive(scn, &key, &prim));
+
+ FOR_EACH(iprim, 0, mesh_data.nprimitives) {
+ const double *v0, *v1, *v2;
+ float v0f[3], v1f[3], v2f[3];
+ struct s3d_attrib attr0, attr1, attr2;
+
+ /* Check that a primitive can be obtained from the key constructed on the
+ * user side */
+ v0 = mesh_data.positions + mesh_data.indices[iprim*3 + 0]*3;
+ v1 = mesh_data.positions + mesh_data.indices[iprim*3 + 1]*3;
+ v2 = mesh_data.positions + mesh_data.indices[iprim*3 + 2]*3;
+ sdis_primkey_setup(&key, v0, v1, v2);
+ OK(sdis_scene_get_s3d_primitive(scn, &key, &prim));
+
+ /* Check that the primitive on the solver side is the same as that on the
+ * user side. On the solver side, vertices are stored in simple precision in
+ * Star-3D view. We therefore need to take care of this conversion to check
+ * that the vertices are the same */
+ OK(s3d_triangle_get_vertex_attrib(&prim, 0, S3D_POSITION, &attr0));
+ OK(s3d_triangle_get_vertex_attrib(&prim, 1, S3D_POSITION, &attr1));
+ OK(s3d_triangle_get_vertex_attrib(&prim, 2, S3D_POSITION, &attr2));
+ f3_set_d3(v0f, v0);
+ f3_set_d3(v1f, v1);
+ f3_set_d3(v2f, v2);
+
+ /* The vertices have been inverted on the user's side to reverse the normal
+ * orientation. Below it is taken into account */
+ CHK(f3_eq(v0f, attr0.value));
+ CHK(f3_eq(v1f, attr2.value));
+ CHK(f3_eq(v2f, attr1.value));
+ }
+}
+
+/*******************************************************************************
+ * The test
+ ******************************************************************************/
+int
+main(int argc, char** argv)
+{
+ /* Stardis variables */
+ struct sdis_device* sdis = NULL;
+ struct sdis_interface* interf = NULL;
+ struct sdis_medium* solid = NULL;
+ struct sdis_medium* dummy = NULL;
+ struct sdis_scene* scn = NULL;
+
+ struct s3dut_mesh* super_shape = NULL;
+ (void)argc, (void)argv;
+
+ OK(sdis_device_create(&SDIS_DEVICE_CREATE_ARGS_DEFAULT, &sdis));
+
+ super_shape = create_super_shape();
+ solid = create_solid(sdis);
+ dummy = create_dummy(sdis);
+ interf = create_interface(sdis, solid, dummy);
+ scn = create_scene(sdis, super_shape, interf);
+
+ check(scn, super_shape);
+
+ 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_primkey_2d.c b/src/test_sdis_primkey_2d.c
@@ -0,0 +1,295 @@
+/* Copyright (C) 2016-2024 |Méso|Star> (contact@meso-star.com)
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+#include "sdis.h"
+#include "test_sdis_utils.h"
+#include "test_sdis_mesh.h"
+
+#include <star/s2d.h>
+
+#include <rsys/float2.h>
+
+/*
+ * The system is a solid supershape whose boundary temperature is set to a
+ * constant. The temperature of the solid is therefore this same temperature.
+ * This simplistic test case is not used to verify a Monte Carlo estimate, but
+ * to ensure that the caller can recover the internal representation of the
+ * geometric primitives from his own data.
+ *
+ * /\
+ * ___/ \___
+ * \ /
+ * /_ __ _\
+ * \/ \/
+ *
+ */
+
+/*******************************************************************************
+ * Super shape
+ ******************************************************************************/
+static struct mesh
+create_super_shape(void)
+{
+ struct mesh sshape = MESH_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;
+}
+
+/*******************************************************************************
+ * 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, 1) /* [J/K/Kg] */
+SOLID_PROP(thermal_conductivity, 1) /* [W/m/K] */
+SOLID_PROP(volumic_mass, 1) /* [kg/m^3] */
+SOLID_PROP(temperature, SDIS_TEMPERATURE_NONE) /* [K] */
+SOLID_PROP(delta, 1.0/20.0) /* [m/fp_to_meter] */
+#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;
+ 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
+ ******************************************************************************/
+static double
+interface_get_temperature
+ (const struct sdis_interface_fragment* frag,
+ struct sdis_data* data)
+{
+ (void)frag, (void)data; /* Avoid the "unused variable" warning */
+ return 300; /* [K] */
+}
+
+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;
+}
+
+/*******************************************************************************
+ * Scene, i.e. the system to simulate
+ ******************************************************************************/
+struct scene_context {
+ const struct mesh* 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 mesh* 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 = mesh_2d_nsegments(sshape);
+ scn_args.nvertices = mesh_2d_nvertices(sshape);
+ scn_args.context = &context;
+ OK(sdis_scene_2d_create(sdis, &scn_args, &scn));
+ return scn;
+}
+
+/*******************************************************************************
+ * Validation
+ ******************************************************************************/
+static void
+check(struct sdis_scene* scn, const struct mesh* mesh)
+{
+ struct s2d_primitive prim = S2D_PRIMITIVE_NULL;
+ struct sdis_primkey key = SDIS_PRIMKEY_NULL;
+ size_t iprim = 0;
+ size_t nprims = 0;
+
+ BA(sdis_scene_get_s2d_primitive(NULL, &key, &prim));
+ BA(sdis_scene_get_s2d_primitive(scn, NULL, &prim));
+ BA(sdis_scene_get_s2d_primitive(scn, &key, NULL));
+ BA(sdis_scene_get_s2d_primitive(scn, &key, &prim));
+
+ nprims = mesh_2d_nsegments(mesh);
+ FOR_EACH(iprim, 0, nprims) {
+ const double *v0, *v1;
+ float v0f[2], v1f[2];
+ struct s2d_attrib attr0, attr1;
+
+ /* Check that a primitive can be obtained from the key constructed on the
+ * user side */
+ v0 = mesh->positions + mesh->indices[iprim*2 + 0]*2;
+ v1 = mesh->positions + mesh->indices[iprim*2 + 1]*2;
+ sdis_primkey_2d_setup(&key, v0, v1);
+ OK(sdis_scene_get_s2d_primitive(scn, &key, &prim));
+
+ /* Check that the primitive on the solver side is the same as that on the
+ * user side. On the solver side, vertices are stored in simple precision in
+ * Star-3D view. We therefore need to take care of this conversion to check
+ * that the vertices are the same */
+ OK(s2d_segment_get_vertex_attrib(&prim, 0, S2D_POSITION, &attr0));
+ OK(s2d_segment_get_vertex_attrib(&prim, 1, S2D_POSITION, &attr1));
+ f2_set_d2(v0f, v0);
+ f2_set_d2(v1f, v1);
+
+ /* The vertices have been inverted on the user's side to reverse the normal
+ * orientation. Below it is taken into account */
+ CHK(f2_eq(v0f, attr1.value));
+ CHK(f2_eq(v1f, attr0.value));
+ }
+}
+
+/*******************************************************************************
+ * 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 */
+ struct mesh sshape = MESH_NULL;
+ (void)argc, (void)argv;
+
+ OK(sdis_device_create(&SDIS_DEVICE_CREATE_ARGS_DEFAULT, &sdis));
+
+ sshape = create_super_shape();
+ solid = create_solid(sdis);
+ dummy = create_dummy(sdis);
+ interf = create_interface(sdis, solid, dummy);
+ scn = create_scene(sdis, &sshape, interf);
+
+ check(scn, &sshape);
+
+ mesh_release(&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_scene.c b/src/test_sdis_scene.c
@@ -100,6 +100,8 @@ test_scene_3d
struct context ctx;
struct senc2d_scene* scn2d;
struct senc3d_scene* scn3d;
+ struct s2d_scene_view* view2d;
+ struct s3d_scene_view* view3d;
struct sdis_scene_create_args scn_args = SDIS_SCENE_CREATE_ARGS_DEFAULT;
struct sdis_scene_find_closest_point_args closest_pt_args =
SDIS_SCENE_FIND_CLOSEST_POINT_ARGS_NULL;
@@ -266,9 +268,13 @@ test_scene_3d
BA(sdis_scene_get_senc3d_scene(scn, NULL));
BA(sdis_scene_get_senc3d_scene(NULL, &scn3d));
OK(sdis_scene_get_senc3d_scene(scn, &scn3d));
- OK(senc3d_scene_ref_put(scn3d));
- /* No 2D available */
- BA(sdis_scene_get_senc2d_scene(scn, &scn2d));
+ BA(sdis_scene_get_senc2d_scene(scn, &scn2d)); /* No 2D available */
+
+ BA(sdis_scene_get_s3d_scene_view(NULL, NULL));
+ BA(sdis_scene_get_s3d_scene_view(NULL, &view3d));
+ BA(sdis_scene_get_s3d_scene_view(scn, NULL));
+ OK(sdis_scene_get_s3d_scene_view(scn, &view3d));
+ BA(sdis_scene_get_s2d_scene_view(scn, &view2d)); /* No 2D available */
BA(sdis_scene_get_radiative_env(NULL, &radenv));
BA(sdis_scene_get_radiative_env(scn, NULL));
@@ -311,6 +317,8 @@ test_scene_2d
struct context ctx;
struct senc2d_scene* scn2d;
struct senc3d_scene* scn3d;
+ struct s2d_scene_view* view2d;
+ struct s3d_scene_view* view3d;
size_t nsegs, npos;
size_t i;
size_t iprim;
@@ -502,9 +510,13 @@ test_scene_2d
BA(sdis_scene_get_senc2d_scene(scn, NULL));
BA(sdis_scene_get_senc2d_scene(NULL, &scn2d));
OK(sdis_scene_get_senc2d_scene(scn, &scn2d));
- OK(senc2d_scene_ref_put(scn2d));
- /* No 3D available */
- BA(sdis_scene_get_senc3d_scene(scn, &scn3d));
+ BA(sdis_scene_get_senc3d_scene(scn, &scn3d)); /* No 3D available */
+
+ BA(sdis_scene_get_s2d_scene_view(NULL, NULL));
+ BA(sdis_scene_get_s2d_scene_view(NULL, &view2d));
+ BA(sdis_scene_get_s2d_scene_view(scn, NULL));
+ OK(sdis_scene_get_s2d_scene_view(scn, &view2d));
+ BA(sdis_scene_get_s3d_scene_view(scn, &view3d)); /* No 3D available */
BA(sdis_scene_get_radiative_env(NULL, NULL));
BA(sdis_scene_get_radiative_env(scn, NULL));
diff --git a/src/test_sdis_solve_camera.c b/src/test_sdis_solve_camera.c
@@ -33,27 +33,38 @@
#define SPP 32 /* #Samples per pixel, i.e. #realisations per pixel */
/*
- * The scene is composed of a solid cube whose temperature is unknown. The
- * emissivity of the cube is 1 and its convection coefficient with the
- * surrounding fluid at 300K is 0.1. At the center of the cube there is a spherical
- * fluid cavity whose temperature is 350K. The convection coefficient between
- * the solid and the cavity is 1 and the emissivity of this interface is null.
- * The ambient radiative temperature of the system is 300K.
+ * The scene consists of a solid cube whose temperature is unknown. The
+ * emissivity of the cube is 1 and the convection coefficient with the
+ * surrounding fluid at 300 K is 0.1. At the center of the cube is a spherical
+ * cavity of fluid with a temperature of 350 K. The convection coefficient
+ * between the solid and the cavity is 1, and the emissivity of this interface
+ * is zero. The ambient radiative temperature of the system is 300 K.
*
- * In this test, we compute the radiative temperature that reaches a camera
- * that looks the cube and we `dump' a normalized image of the result.
+ * Finally, a parallelepiped below the cube symbolizes the ground. The
+ * temperature of its Robin condition is 280 K. This geometry verifies that a
+ * camera can draw a scene in an enclosure containing several media, such as
+ * those used to define several boundary conditions.
*
- * (1,1,1)
- * +----------------+
- * /' # # /|
- * +----*--------*--+ |
- * | ' # # | |
- * | ' # 350K # | |
- * | ' # # | |
- * | +.....#..#.....|.+
- * |/ |/
- * +----------------+
- * (-1,-1,-1)
+ * In this test, we calculate the radiative temperature that reaches a camera
+ * looking at the cube and produce an image of the result written to the
+ * standard output in htrdr-image(5) format.
+ *
+ *
+ * +----------------+
+ * /' # # /|
+ * +----*--------*--+ | __\ 300 K
+ * | ' # # | | / /
+ * | ' # 350K # | | \__/
+ * | ' # # | |
+ * | +.....#..#.....|.+
+ * |/ |/
+ * +----------------+ 280K
+ * +---------------------------------__\------+
+ * / / / /|
+ * / \__/ / +
+ * +------------------------------------------+ /
+ * | |/
+ * +------------------------------------------+
*/
/*******************************************************************************
@@ -82,6 +93,52 @@ struct geometry {
static const struct geometry GEOMETRY_NULL = {NULL, NULL, NULL};
static void
+geometry_add_shape
+ (struct geometry* geom,
+ const double* positions,
+ const size_t nverts,
+ const size_t* indices,
+ const size_t nprims,
+ const double transform[12], /* May be NULL <=> no transformation */
+ struct sdis_interface* interf)
+{
+ struct map_interf* geom_interf = NULL;
+ size_t nverts_prev = 0;
+ size_t i;
+
+ CHK(geom != NULL);
+ CHK(positions != NULL);
+ CHK(indices != NULL);
+ CHK(nverts != 0);
+ CHK(nprims != 0);
+ CHK(interf != NULL);
+
+ /* Save the previous number of vertices/primitives of the geometry */
+ nverts_prev = sa_size(geom->positions) / 3;
+
+ /* Add the vertices */
+ FOR_EACH(i, 0, nverts) {
+ double* pos = sa_add(geom->positions, 3);
+ d3_set(pos, positions + i*3);
+ if(transform) {
+ d33_muld3(pos, transform, pos);
+ d3_add(pos, transform+9, pos);
+ }
+ }
+
+ /* Add the indices */
+ FOR_EACH(i, 0, nprims) {
+ sa_push(geom->indices, indices[i*3+0] + nverts_prev);
+ sa_push(geom->indices, indices[i*3+1] + nverts_prev);
+ sa_push(geom->indices, indices[i*3+2] + nverts_prev);
+ }
+
+ geom_interf = sa_add(geom->interfaces, 1);
+ geom_interf->key = sa_size(geom->indices) / 3 - 1;
+ geom_interf->interf = interf;
+}
+
+static void
geometry_release(struct geometry* geom)
{
CHK(geom != NULL);
@@ -143,43 +200,59 @@ geometry_get_interface
*bound = interf->interf;
}
-/*******************************************************************************
- * Fluid medium
- ******************************************************************************/
-struct fluid {
- double cp;
- double rho;
- double temperature;
-};
-static const struct fluid FLUID_NULL = {0, 0, SDIS_TEMPERATURE_NONE};
-
-static double
-fluid_get_calorific_capacity
- (const struct sdis_rwalk_vertex* vtx, struct sdis_data* data)
+static void
+add_cube(struct geometry* geom, struct sdis_interface* interf)
{
- CHK(data != NULL && vtx != NULL);
- return ((const struct fluid*)sdis_data_cget(data))->cp;
+ struct s3dut_mesh_data msh_data;
+ struct s3dut_mesh* msh = NULL;
+ CHK(geom);
+
+ OK(s3dut_create_cuboid(NULL, 2, 2, 2, &msh));
+ OK(s3dut_mesh_get_data(msh, &msh_data));
+ geometry_add_shape(geom, msh_data.positions, msh_data.nvertices,
+ msh_data.indices, msh_data.nprimitives, NULL, interf);
+ OK(s3dut_mesh_ref_put(msh));
}
-static double
-fluid_get_volumic_mass
- (const struct sdis_rwalk_vertex* vtx, struct sdis_data* data)
+static void
+add_sphere(struct geometry* geom, struct sdis_interface* interf)
{
- CHK(data != NULL && vtx != NULL);
- return ((const struct fluid*)sdis_data_cget(data))->rho;
+ struct s3dut_mesh_data msh_data;
+ struct s3dut_mesh* msh = NULL;
+ CHK(geom);
+
+ OK(s3dut_create_sphere(NULL, 0.5, 32, 16, &msh));
+ OK(s3dut_mesh_get_data(msh, &msh_data));
+ geometry_add_shape(geom, msh_data.positions, msh_data.nvertices,
+ msh_data.indices, msh_data.nprimitives, NULL, interf);
+ OK(s3dut_mesh_ref_put(msh));
}
-static double
-fluid_get_temperature
- (const struct sdis_rwalk_vertex* vtx, struct sdis_data* data)
+static void
+add_ground(struct geometry* geom, struct sdis_interface* interf)
{
- CHK(data != NULL && vtx != NULL);
- return ((const struct fluid*)sdis_data_cget(data))->temperature;
+ struct s3dut_mesh_data msh_data;
+ struct s3dut_mesh* msh = NULL;
+ const double transform[12] = {1,0,0, 0,1,0, 0,0,1, 0,0,-4};
+ CHK(geom);
+
+ OK(s3dut_create_cuboid(NULL, 10, 10, 2, &msh));
+ OK(s3dut_mesh_get_data(msh, &msh_data));
+ geometry_add_shape(geom, msh_data.positions, msh_data.nvertices,
+ msh_data.indices, msh_data.nprimitives, transform, interf);
+ OK(s3dut_mesh_ref_put(msh));
}
/*******************************************************************************
- * Solid medium
+ * Media
******************************************************************************/
+struct fluid {
+ double cp;
+ double rho;
+ double temperature;
+};
+static const struct fluid FLUID_NULL = {0, 0, SDIS_TEMPERATURE_NONE};
+
struct solid {
double cp;
double lambda;
@@ -189,48 +262,87 @@ struct solid {
};
static const struct solid SOLID_NULL = {0, 0, 0, 0, SDIS_TEMPERATURE_NONE};
-static double
-solid_get_calorific_capacity
- (const struct sdis_rwalk_vertex* vtx, struct sdis_data* data)
+#define MEDIUM_GETTER(Type, Prop) \
+ static double \
+ Type##_get_##Prop \
+ (const struct sdis_rwalk_vertex* vtx, \
+ struct sdis_data* data) \
+ { \
+ CHK(data && vtx); \
+ return ((const struct Type*)sdis_data_cget(data))->Prop; \
+ }
+/* Fluid getters */
+MEDIUM_GETTER(fluid, cp)
+MEDIUM_GETTER(fluid, rho)
+MEDIUM_GETTER(fluid, temperature)
+/* Solid getters */
+MEDIUM_GETTER(solid, cp)
+MEDIUM_GETTER(solid, lambda)
+MEDIUM_GETTER(solid, rho)
+MEDIUM_GETTER(solid, delta)
+MEDIUM_GETTER(solid, temperature)
+#undef MEDIUM_GETTER
+
+static struct sdis_medium*
+create_fluid
+ (struct sdis_device* dev,
+ const struct fluid* param)
{
- CHK(data != NULL && vtx != NULL);
- return ((const struct solid*)sdis_data_cget(data))->cp;
-}
+ struct sdis_fluid_shader fluid_shader = DUMMY_FLUID_SHADER;
+ struct sdis_data* data = NULL;
+ struct sdis_medium* fluid = NULL;
-static double
-solid_get_thermal_conductivity
- (const struct sdis_rwalk_vertex* vtx, struct sdis_data* data)
-{
- CHK(data != NULL && vtx != NULL);
- return ((const struct solid*)sdis_data_cget(data))->lambda;
-}
+ CHK(param != NULL);
-static double
-solid_get_volumic_mass
- (const struct sdis_rwalk_vertex* vtx, struct sdis_data* data)
-{
- CHK(data != NULL && vtx != NULL);
- return ((const struct solid*)sdis_data_cget(data))->rho;
-}
+ /* Copy the fluid parameters into the Stardis memory space */
+ OK(sdis_data_create
+ (dev, sizeof(struct fluid), ALIGNOF(struct fluid), NULL, &data));
+ memcpy(sdis_data_get(data), param, sizeof(struct fluid));
-static double
-solid_get_delta
- (const struct sdis_rwalk_vertex* vtx, struct sdis_data* data)
-{
- CHK(data != NULL && vtx != NULL);
- return ((const struct solid*)sdis_data_cget(data))->delta;
+ /* Setup the fluid shader */
+ fluid_shader.calorific_capacity = fluid_get_cp;
+ fluid_shader.volumic_mass = fluid_get_rho;
+ fluid_shader.temperature = fluid_get_temperature;
+
+ /* Create the fluid medium */
+ OK(sdis_fluid_create(dev, &fluid_shader, data, &fluid));
+ OK(sdis_data_ref_put(data));
+
+ return fluid;
}
-static double
-solid_get_temperature
- (const struct sdis_rwalk_vertex* vtx, struct sdis_data* data)
+static struct sdis_medium*
+create_solid
+ (struct sdis_device* dev,
+ const struct solid* param)
{
- CHK(data != NULL && vtx != NULL);
- return ((const struct solid*)sdis_data_cget(data))->temperature;
+ struct sdis_solid_shader solid_shader = DUMMY_SOLID_SHADER;
+ struct sdis_data* data = NULL;
+ struct sdis_medium* solid = NULL;
+
+ CHK(param != NULL);
+
+ /* Copy the solid parameters into the Stardis memory space */
+ OK(sdis_data_create
+ (dev, sizeof(struct solid), ALIGNOF(struct solid), NULL, &data));
+ memcpy(sdis_data_get(data), param, sizeof(struct solid));
+
+ /* Setup the solid shader */
+ solid_shader.calorific_capacity = solid_get_cp;
+ solid_shader.thermal_conductivity = solid_get_lambda;
+ solid_shader.volumic_mass = solid_get_rho;
+ solid_shader.delta = solid_get_delta;
+ solid_shader.temperature = solid_get_temperature;
+
+ /* Create the solid medium */
+ OK(sdis_solid_create(dev, &solid_shader, data, &solid));
+ OK(sdis_data_ref_put(data));
+
+ return solid;
}
/*******************************************************************************
- * Interface
+ * Interfaces
******************************************************************************/
struct interf {
double hc;
@@ -243,50 +355,76 @@ static const struct interf INTERF_NULL = {
0, 0, 0, SDIS_TEMPERATURE_NONE, SDIS_TEMPERATURE_NONE
};
-static double
-interface_get_convection_coef
- (const struct sdis_interface_fragment* frag, struct sdis_data* data)
-{
- CHK(data != NULL && frag != NULL);
- return ((const struct interf*)sdis_data_cget(data))->hc;
-}
+#define INTERFACE_GETTER(Prop) \
+ static double \
+ interface_get_##Prop \
+ (const struct sdis_interface_fragment* frag, \
+ struct sdis_data* data) \
+ { \
+ CHK(data && frag); \
+ return ((const struct interf*)sdis_data_cget(data))->Prop; \
+ }
+INTERFACE_GETTER(hc)
+INTERFACE_GETTER(temperature)
+INTERFACE_GETTER(reference_temperature)
+#undef INTERFACE_GETTER
+
+#define INTERFACE_GETTER(Prop) \
+ static double \
+ interface_get_##Prop \
+ (const struct sdis_interface_fragment* frag, \
+ const unsigned source_id, \
+ struct sdis_data* data) \
+ { \
+ CHK(data && frag); \
+ (void)source_id; \
+ return ((const struct interf*)sdis_data_cget(data))->Prop; \
+ }
+INTERFACE_GETTER(epsilon)
+INTERFACE_GETTER(specular_fraction)
+#undef INTERFACE_GETTER
-static double
-interface_get_emissivity
- (const struct sdis_interface_fragment* frag,
- const unsigned source_id,
- struct sdis_data* data)
+static struct sdis_interface*
+create_interface
+ (struct sdis_device* dev,
+ struct sdis_medium* mdm_front,
+ struct sdis_medium* mdm_back,
+ const struct interf* param)
{
- (void)source_id;
- CHK(data != NULL && frag != NULL);
- return ((const struct interf*)sdis_data_cget(data))->epsilon;
-}
+ struct sdis_interface_shader interface_shader = SDIS_INTERFACE_SHADER_NULL;
+ struct sdis_data* data = NULL;
+ struct sdis_interface* interf = NULL;
-static double
-interface_get_specular_fraction
- (const struct sdis_interface_fragment* frag,
- const unsigned source_id,
- struct sdis_data* data)
-{
- (void)source_id;
- CHK(data != NULL && frag != NULL);
- return ((const struct interf*)sdis_data_cget(data))->specular_fraction;
-}
+ CHK(mdm_front != NULL);
+ CHK(mdm_back != NULL);
-static double
-interface_get_temperature
- (const struct sdis_interface_fragment* frag, struct sdis_data* data)
-{
- CHK(data != NULL && frag != NULL);
- return ((const struct interf*)sdis_data_cget(data))->temperature;
-}
+ /* Copy the interface parameters into the Stardis memory space */
+ OK(sdis_data_create
+ (dev, sizeof(struct interf), ALIGNOF(struct interf), NULL, &data));
+ memcpy(sdis_data_get(data), param, sizeof(struct interf));
-static double
-interface_get_reference_temperature
- (const struct sdis_interface_fragment* frag, struct sdis_data* data)
-{
- CHK(data != NULL && frag != NULL);
- return ((const struct interf*)sdis_data_cget(data))->reference_temperature;
+ /* Setup the interface shader */
+ interface_shader.convection_coef = interface_get_hc;
+ interface_shader.front.temperature = interface_get_temperature;
+ interface_shader.back.temperature = interface_get_temperature;
+ if(sdis_medium_get_type(mdm_front) == SDIS_FLUID) {
+ interface_shader.front.emissivity = interface_get_epsilon;
+ interface_shader.front.specular_fraction = interface_get_specular_fraction;
+ interface_shader.front.reference_temperature =
+ interface_get_reference_temperature;
+ }
+ if(sdis_medium_get_type(mdm_back) == SDIS_FLUID) {
+ interface_shader.back.emissivity = interface_get_epsilon;
+ interface_shader.back.specular_fraction = interface_get_specular_fraction;
+ interface_shader.back.reference_temperature =
+ interface_get_reference_temperature;
+ }
+ /* Create the interface */
+ OK(sdis_interface_create
+ (dev, mdm_front, mdm_back, &interface_shader, data, &interf));
+ OK(sdis_data_ref_put(data));
+
+ return interf;
}
/*******************************************************************************
@@ -339,254 +477,289 @@ create_radenv
}
/*******************************************************************************
- * Helper functions
+ * Scene
******************************************************************************/
-static void
-create_solid
+static struct sdis_scene*
+create_scene
(struct sdis_device* dev,
- const struct solid* param,
- struct sdis_medium** solid)
+ struct sdis_radiative_env* radenv,
+ struct geometry* geom)
{
- struct sdis_data* data = NULL;
- struct solid* solid_args = NULL;
- struct sdis_solid_shader solid_shader = DUMMY_SOLID_SHADER;
+ struct sdis_scene_create_args scn_args = SDIS_SCENE_CREATE_ARGS_DEFAULT;
+ struct sdis_scene* scn = NULL;
+ size_t ntris = 0;
+ size_t npos = 0;
+ CHK(geom);
- CHK(param != NULL);
- CHK(solid != NULL);
+ ntris = sa_size(geom->indices) / 3; /* #primitives */
+ npos = sa_size(geom->positions) / 3; /* #positions */
- /* Copy the solid parameters into the Stardis memory space */
- OK(sdis_data_create
- (dev, sizeof(struct solid), ALIGNOF(struct solid), NULL, &data));
- solid_args = sdis_data_get(data);
- memcpy(solid_args, param, sizeof(struct solid));
+ scn_args.get_indices = geometry_get_indices;
+ scn_args.get_interface = geometry_get_interface;
+ scn_args.get_position = geometry_get_position;
+ scn_args.nprimitives = ntris;
+ scn_args.nvertices = npos;
+ scn_args.t_range[0] = 300;
+ scn_args.t_range[1] = 350;
+ scn_args.radenv = radenv;
+ scn_args.context = geom;
- /* Setup the solid shader */
- solid_shader.calorific_capacity = solid_get_calorific_capacity;
- solid_shader.calorific_capacity = solid_get_calorific_capacity;
- solid_shader.thermal_conductivity = solid_get_thermal_conductivity;
- solid_shader.volumic_mass = solid_get_volumic_mass;
- solid_shader.delta = solid_get_delta;
- solid_shader.temperature = solid_get_temperature;
+ OK(sdis_scene_create(dev, &scn_args, &scn));
+ return scn;
+}
- /* Create the solid medium */
- OK(sdis_solid_create(dev, &solid_shader, data, solid));
+/*******************************************************************************
+ * Rendering point of view
+ ******************************************************************************/
+static struct sdis_camera*
+create_camera(struct sdis_device* dev)
+{
+ const double pos[3] = {3, 3, 3};
+ const double tgt[3] = {0, 0, 0};
+ const double up[3] = {0, 0, 1};
+ struct sdis_camera* cam = NULL;
- /* Release the ownership onto the Stardis memory space storing the solid
- * parameters */
- OK(sdis_data_ref_put(data));
+ OK(sdis_camera_create(dev, &cam));
+ OK(sdis_camera_set_proj_ratio(cam, (double)IMG_WIDTH/(double)IMG_HEIGHT));
+ OK(sdis_camera_set_fov(cam, MDEG2RAD(70)));
+ OK(sdis_camera_look_at(cam, pos, tgt, up));
+ return cam;
}
+/*******************************************************************************
+ * Draw the scene
+ ******************************************************************************/
static void
-create_fluid
- (struct sdis_device* dev,
- const struct fluid* param,
- struct sdis_medium** fluid)
+check_pixel(const struct sdis_estimator* pixel)
{
- struct sdis_data* data = NULL;
- struct fluid* fluid_args = NULL;
- struct sdis_fluid_shader fluid_shader = DUMMY_FLUID_SHADER;
-
- CHK(param != NULL);
- CHK(fluid != NULL);
-
- /* Copy the fluid parameters into the Stardis memory space */
- OK(sdis_data_create
- (dev, sizeof(struct fluid), ALIGNOF(struct fluid), NULL, &data));
- fluid_args = sdis_data_get(data);
- memcpy(fluid_args, param, sizeof(struct fluid));
-
- /* Setup the fluid shader */
- fluid_shader.calorific_capacity = fluid_get_calorific_capacity;
- fluid_shader.volumic_mass = fluid_get_volumic_mass;
- fluid_shader.temperature = fluid_get_temperature;
+ struct sdis_mc T = SDIS_MC_NULL;
+ struct sdis_mc time = SDIS_MC_NULL;
+ size_t nfails = 0;
+ size_t nreals = 0;
- /* Create the fluid medium */
- OK(sdis_fluid_create(dev, &fluid_shader, data, fluid));
+ OK(sdis_estimator_get_realisation_count(pixel, &nreals));
+ OK(sdis_estimator_get_failure_count(pixel, &nfails));
+ OK(sdis_estimator_get_temperature(pixel, &T));
+ OK(sdis_estimator_get_realisation_time(pixel, &time));
- /* Release the ownership onto the Stardis memory space storing the fluid
- * parameters */
- OK(sdis_data_ref_put(data));
+ CHK(nreals + nfails == SPP);
+ CHK(T.E > 0);
+ CHK(time.E > 0);
}
static void
-create_interface
- (struct sdis_device* dev,
- struct sdis_medium* mdm_front,
- struct sdis_medium* mdm_back,
- const struct interf* param,
- struct sdis_interface** interf)
+check_image(const struct sdis_estimator_buffer* img)
{
- struct sdis_data* data = NULL;
- struct interf* interface_args = NULL;
- struct sdis_interface_shader interface_shader = SDIS_INTERFACE_SHADER_NULL;
-
- CHK(mdm_front != NULL);
- CHK(mdm_back != NULL);
- CHK(param != NULL);
- CHK(interf != NULL);
-
- /* Copy the interface parameters into the Stardis memory space */
- OK(sdis_data_create
- (dev, sizeof(struct interf), ALIGNOF(struct interf), NULL, &data));
- interface_args = sdis_data_get(data);
- memcpy(interface_args, param, sizeof(struct interf));
-
- /* Setup the interface shader */
- interface_shader.convection_coef = interface_get_convection_coef;
- interface_shader.front.temperature = interface_get_temperature;
- interface_shader.back.temperature = interface_get_temperature;
- if(sdis_medium_get_type(mdm_front) == SDIS_FLUID) {
- interface_shader.front.emissivity = interface_get_emissivity;
- interface_shader.front.specular_fraction = interface_get_specular_fraction;
- interface_shader.front.reference_temperature =
- interface_get_reference_temperature;
- }
- if(sdis_medium_get_type(mdm_back) == SDIS_FLUID) {
- interface_shader.back.emissivity = interface_get_emissivity;
- interface_shader.back.specular_fraction = interface_get_specular_fraction;
- interface_shader.back.reference_temperature =
- interface_get_reference_temperature;
+ struct sdis_mc T = SDIS_MC_NULL;
+ struct sdis_mc time = SDIS_MC_NULL;
+ const struct sdis_estimator* pixel = NULL;
+ struct ssp_rng* rng_state = NULL;
+ size_t definition[2];
+ size_t nreals, nfails;
+ size_t x, y;
+
+ BA(sdis_estimator_buffer_get_realisation_count(NULL, &nreals));
+ BA(sdis_estimator_buffer_get_realisation_count(img, NULL));
+ OK(sdis_estimator_buffer_get_realisation_count(img, &nreals));
+
+ BA(sdis_estimator_buffer_get_failure_count(NULL, &nfails));
+ BA(sdis_estimator_buffer_get_failure_count(img, NULL));
+ OK(sdis_estimator_buffer_get_failure_count(img, &nfails));
+
+ BA(sdis_estimator_buffer_get_temperature(NULL, &T));
+ BA(sdis_estimator_buffer_get_temperature(img, NULL));
+ OK(sdis_estimator_buffer_get_temperature(img, &T));
+
+ BA(sdis_estimator_buffer_get_realisation_time(NULL, &time));
+ BA(sdis_estimator_buffer_get_realisation_time(img, NULL));
+ OK(sdis_estimator_buffer_get_realisation_time(img, &time));
+
+ BA(sdis_estimator_buffer_get_rng_state(NULL, &rng_state));
+ BA(sdis_estimator_buffer_get_rng_state(img, NULL));
+ OK(sdis_estimator_buffer_get_rng_state(img, &rng_state));
+
+ CHK(nreals + nfails == IMG_WIDTH*IMG_HEIGHT*SPP);
+
+ fprintf(stderr, "Overall temperature ~ %g +/- %g\n", T.E, T.SE);
+ fprintf(stderr, "Time per realisation (in usec) ~ %g +/- %g\n", time.E, time.SE);
+ fprintf(stderr, "#failures = %lu/%lu\n",
+ (unsigned long)nfails, (unsigned long)(IMG_WIDTH*IMG_HEIGHT*SPP));
+
+ BA(sdis_estimator_buffer_get_definition(NULL, definition));
+ BA(sdis_estimator_buffer_get_definition(img, NULL));
+ OK(sdis_estimator_buffer_get_definition(img, definition));
+ CHK(definition[0] == IMG_WIDTH);
+ CHK(definition[1] == IMG_HEIGHT);
+
+ BA(sdis_estimator_buffer_at(NULL, 0, 0, &pixel));
+ BA(sdis_estimator_buffer_at(img, IMG_WIDTH+1,0 , &pixel));
+ BA(sdis_estimator_buffer_at(img, 0, IMG_HEIGHT+1, &pixel));
+ BA(sdis_estimator_buffer_at(img, 0, 0, NULL));
+
+ /* Pixels ordered by row */
+ FOR_EACH(y, 0, IMG_HEIGHT) {
+ FOR_EACH(x, 0, IMG_WIDTH) {
+ OK(sdis_estimator_buffer_at(img, x, y, &pixel));
+ check_pixel(pixel);
+ }
}
- /* Create the interface */
- OK(sdis_interface_create
- (dev, mdm_front, mdm_back, &interface_shader, data, interf));
+}
- /* Release the ownership onto the Stardis memory space storing the interface
- * parameters */
- OK(sdis_data_ref_put(data));
+/* Check that the images, although compatible from an estimation point of view,
+ * are not the same. This should be the case if different random sequences are
+ * used for each image */
+static void
+check_image_difference
+ (const struct sdis_estimator_buffer* img0,
+ const struct sdis_estimator_buffer* img1)
+{
+ struct sdis_mc T0 = SDIS_MC_NULL;
+ struct sdis_mc T1 = SDIS_MC_NULL;
+ size_t definition0[2];
+ size_t definition1[2];
+ size_t nreals0, nfails0;
+ size_t nreals1, nfails1;
+
+ OK(sdis_estimator_buffer_get_realisation_count(img0, &nreals0));
+ OK(sdis_estimator_buffer_get_realisation_count(img1, &nreals1));
+
+ OK(sdis_estimator_buffer_get_failure_count(img0, &nfails0));
+ OK(sdis_estimator_buffer_get_failure_count(img1, &nfails1));
+ CHK(nreals0 + nfails0 == nreals1 + nfails1);
+
+ OK(sdis_estimator_buffer_get_definition(img0, definition0));
+ OK(sdis_estimator_buffer_get_definition(img1, definition1));
+ CHK(definition0[0] == definition1[0]);
+ CHK(definition0[1] == definition1[1]);
+
+ OK(sdis_estimator_buffer_get_temperature(img0, &T0));
+ OK(sdis_estimator_buffer_get_temperature(img1, &T1));
+ CHK(T0.E != T1.E || (T0.SE == 0 && T1.SE == 0));
+ CHK(T0.E + 3*T0.SE >= T1.E - 3*T1.SE);
+ CHK(T0.E - 3*T0.SE <= T1.E + 3*T1.SE);
}
+/* Write an image in htrdr-image(5) format */
static void
-geometry_add_shape
- (struct geometry* geom,
- const double* positions,
- const size_t nverts,
- const size_t* indices,
- const size_t nprims,
- const double transform[12], /* May be NULL <=> no transformation */
- struct sdis_interface* interf)
+write_image(FILE* stream, struct sdis_estimator_buffer* img)
{
- struct map_interf* geom_interf = NULL;
- size_t nverts_prev = 0;
- size_t i;
+ size_t x, y;
- CHK(geom != NULL);
- CHK(positions != NULL);
- CHK(indices != NULL);
- CHK(nverts != 0);
- CHK(nprims != 0);
- CHK(interf != NULL);
+ /* Header */
+ fprintf(stream, "%d %d\n", IMG_WIDTH, IMG_HEIGHT);
- /* Save the previous number of vertices/primitives of the geometry */
- nverts_prev = sa_size(geom->positions) / 3;
+ /* Pixels ordered by row */
+ FOR_EACH(y, 0, IMG_HEIGHT) {
+ FOR_EACH(x, 0, IMG_WIDTH) {
+ struct sdis_mc T = SDIS_MC_NULL;
+ const struct sdis_estimator* pixel = NULL;
- /* Add the vertices */
- FOR_EACH(i, 0, nverts) {
- double* pos = sa_add(geom->positions, 3);
- d3_set(pos, positions + i*3);
- if(transform) {
- d33_muld3(pos, transform, pos);
- d3_add(pos, transform+9, pos);
+ OK(sdis_estimator_buffer_at(img, x, y, &pixel));
+ OK(sdis_estimator_get_temperature(pixel, &T));
+ fprintf(stream, "%g %g 0 0 0 0 0 0\n", T.E, T.SE);
}
}
+}
- /* Add the indices */
- FOR_EACH(i, 0, nprims) {
- sa_push(geom->indices, indices[i*3+0] + nverts_prev);
- sa_push(geom->indices, indices[i*3+1] + nverts_prev);
- sa_push(geom->indices, indices[i*3+2] + nverts_prev);
- }
-
- geom_interf = sa_add(geom->interfaces, 1);
- geom_interf->key = sa_size(geom->indices) / 3 - 1;
- geom_interf->interf = interf;
+static void
+invalid_draw(struct sdis_scene* scn, struct sdis_camera* cam)
+{
+ struct sdis_solve_camera_args args = SDIS_SOLVE_CAMERA_ARGS_DEFAULT;
+ struct sdis_estimator_buffer* img = NULL;
+
+ CHK(cam && scn);
+
+ args.cam = cam;
+ args.time_range[0] = INF;
+ args.time_range[1] = INF;
+ args.image_definition[0] = IMG_WIDTH;
+ args.image_definition[1] = IMG_HEIGHT;
+ args.spp = SPP;
+
+ BA(sdis_solve_camera(NULL, &args, &img));
+ BA(sdis_solve_camera(scn, NULL, &img));
+ BA(sdis_solve_camera(scn, &args, NULL));
+
+ /* Invalid camera */
+ args.cam = NULL;
+ BA(sdis_solve_camera(scn, &args, &img));
+ args.cam = cam;
+
+ /* Invald time range */
+ args.time_range[0] = args.time_range[1] = -1;
+ BA(sdis_solve_camera(scn, &args, &img));
+ args.time_range[0] = 1;
+ BA(sdis_solve_camera(scn, &args, &img));
+ args.time_range[1] = 0;
+ BA(sdis_solve_camera(scn, &args, &img));
+ args.time_range[0] = args.time_range[1] = INF;
+
+ /* Invalid image definition */
+ args.image_definition[0] = 0;
+ BA(sdis_solve_camera(scn, &args, &img));
+ args.image_definition[0] = IMG_WIDTH;
+ args.image_definition[1] = 0;
+ BA(sdis_solve_camera(scn, &args, &img));
+ args.image_definition[1] = IMG_HEIGHT;
+
+ /* Invalid number of samples per pixel */
+ args.spp = 0;
+ BA(sdis_solve_camera(scn, &args, &img));
+ args.spp = SPP;
}
static void
-dump_image(const struct sdis_estimator_buffer* buf)
+draw
+ (struct sdis_scene* scn,
+ struct sdis_camera* cam,
+ const int is_master_process)
{
- struct image img;
- double* temps = NULL;
- double Tmax = -DBL_MAX;
- double Tmin = DBL_MAX;
- double norm;
- size_t definition[2];
- size_t ix, iy;
-
- CHK(buf != NULL);
- OK(sdis_estimator_buffer_get_definition(buf, definition));
-
- temps = mem_alloc(definition[0]*definition[1]*sizeof(double));
- CHK(temps != NULL);
-
- /* Check the results validity */
- FOR_EACH(iy, 0, definition[1]) {
- FOR_EACH(ix, 0, definition[0]) {
- const struct sdis_estimator* estimator;
- struct sdis_mc T;
- struct sdis_mc time;
- size_t nreals;
- size_t nfails;
-
- BA(sdis_estimator_buffer_at(NULL, ix, iy, &estimator));
- BA(sdis_estimator_buffer_at(buf, definition[0]+1, iy, &estimator));
- BA(sdis_estimator_buffer_at(buf, ix, definition[1]+1, &estimator));
- BA(sdis_estimator_buffer_at(buf, ix, iy, NULL));
- OK(sdis_estimator_buffer_at(buf, ix, iy, &estimator));
-
- OK(sdis_estimator_get_realisation_count(estimator, &nreals));
- OK(sdis_estimator_get_failure_count(estimator, &nfails));
- OK(sdis_estimator_get_temperature(estimator, &T));
- OK(sdis_estimator_get_realisation_time(estimator, &time));
-
- CHK(nreals + nfails == SPP);
- CHK(T.E > 0);
- CHK(time.E > 0);
- }
- }
+ struct sdis_solve_camera_args args = SDIS_SOLVE_CAMERA_ARGS_DEFAULT;
+ struct sdis_estimator_buffer* img0 = NULL;
+ struct sdis_estimator_buffer* img1 = NULL;
+ struct ssp_rng* rng = NULL;
- /* Compute the per pixel temperature */
- FOR_EACH(iy, 0, definition[1]) {
- double* row = temps + iy * definition[0];
- FOR_EACH(ix, 0, definition[0]) {
- const struct sdis_estimator* estimator;
- struct sdis_mc T;
+ args.cam = cam;
+ args.time_range[0] = INF;
+ args.time_range[1] = INF;
+ args.image_definition[0] = IMG_WIDTH;
+ args.image_definition[1] = IMG_HEIGHT;
+ args.spp = SPP;
- OK(sdis_estimator_buffer_at(buf, ix, iy, &estimator));
- OK(sdis_estimator_get_temperature(estimator, &T));
+ OK(sdis_solve_camera(scn, &args, &img0));
- row[ix] = T.E;
- Tmax = MMAX(row[ix], Tmax);
- Tmin = MMIN(row[ix], Tmin);
- }
- }
- if(Tmax != Tmin) {
- norm = Tmax - Tmin;
+ if(!is_master_process) {
+ CHK(img0 == NULL);
} else {
- Tmin = 0;
- norm = 1;
+ check_image(img0);
+ write_image(stdout, img0);
}
- /* Allocate the image memory space */
- OK(image_init(NULL, &img));
- OK(image_setup(&img, IMG_WIDTH, IMG_HEIGHT, IMG_WIDTH*3, IMAGE_RGB8, NULL));
-
- FOR_EACH(iy, 0, definition[1]) {
- const double* src_row = temps + iy*definition[0];
- char* dst_row = img.pixels + iy*img.pitch;
- FOR_EACH(ix, 0, definition[0]) {
- unsigned char* pixels = (unsigned char*)
- (dst_row + ix * sizeof_image_format(img.format));
- const unsigned char T = (unsigned char)
- ((src_row[ix] - Tmin)/ norm * 255.0);
- pixels[0] = T;
- pixels[1] = T;
- pixels[2] = T;
- }
+ /* Provide a RNG state and check that the results, although compatible, are
+ * not the same */
+ OK(ssp_rng_create(NULL, SSP_RNG_THREEFRY, &rng));
+ OK(ssp_rng_discard(rng, 3141592653589)); /* Move the RNG state */
+ args.rng_state = rng;
+ args.rng_type = SSP_RNG_TYPE_NULL;
+ OK(sdis_solve_camera(scn, &args, &img1));
+ if(is_master_process) {
+ check_image_difference(img0, img1);
+ OK(sdis_estimator_buffer_ref_put(img1));
+ }
+ OK(ssp_rng_ref_put(rng));
+
+ /* Change the RNG type and check that the results, although compatible, are
+ * not the same */
+ args.rng_state = NULL;
+ args.rng_type = SDIS_SOLVE_CAMERA_ARGS_DEFAULT.rng_type == SSP_RNG_THREEFRY
+ ? SSP_RNG_MT19937_64 : SSP_RNG_THREEFRY;
+ OK(sdis_solve_camera(scn, &args, &img1));
+ if(is_master_process) {
+ check_image_difference(img0, img1);
+ OK(sdis_estimator_buffer_ref_put(img1));
}
- OK(image_write_ppm_stream(&img, 0/*binary?*/, stdout));
- image_release(&img);
- mem_rm(temps);
+
+ if(is_master_process) OK(sdis_estimator_buffer_ref_put(img0));
}
/*******************************************************************************
@@ -596,56 +769,44 @@ int
main(int argc, char** argv)
{
struct geometry geom = GEOMETRY_NULL;
- struct s3dut_mesh* msh = NULL;
- struct s3dut_mesh_data msh_data;
- struct sdis_mc T = SDIS_MC_NULL;
- struct sdis_mc T2 = SDIS_MC_NULL;
- struct sdis_mc time = SDIS_MC_NULL;
struct sdis_camera* cam = NULL;
struct sdis_device* dev = NULL;
- struct sdis_estimator_buffer* buf = NULL;
- struct sdis_estimator_buffer* buf2 = NULL;
struct sdis_medium* solid = NULL;
struct sdis_medium* fluid0 = NULL;
struct sdis_medium* fluid1 = NULL;
+ struct sdis_medium* fluid2 = NULL;
struct sdis_interface* interf0 = NULL;
struct sdis_interface* interf1 = NULL;
+ struct sdis_interface* interf2 = NULL;
struct sdis_radiative_env* radenv = NULL;
struct sdis_scene* scn = NULL;
- struct sdis_scene_create_args scn_args = SDIS_SCENE_CREATE_ARGS_DEFAULT;
- struct sdis_solve_camera_args solve_args = SDIS_SOLVE_CAMERA_ARGS_DEFAULT;
- struct ssp_rng* rng = NULL;
- struct ssp_rng* rng_state = NULL;
struct fluid fluid_args = FLUID_NULL;
struct solid solid_args = SOLID_NULL;
struct interf interface_args = INTERF_NULL;
- struct fluid* pfluid_args = NULL;
- struct radenv* pradenv_args = NULL;
- size_t ntris, npos;
- size_t nreals, nfails;
- size_t definition[2];
- double pos[3];
- double tgt[3];
- double up[3];
int is_master_process;
(void)argc, (void)argv;
create_default_device(&argc, &argv, &is_master_process, &dev);
radenv = create_radenv(dev, 300, 300);
- pradenv_args = sdis_data_get(sdis_radiative_env_get_data(radenv));
/* Create the fluid0 */
fluid_args.temperature = 350;
fluid_args.rho = 0;
fluid_args.cp = 0;
- create_fluid(dev, &fluid_args, &fluid0);
+ fluid0 = create_fluid(dev, &fluid_args);
/* Create the fluid1 */
fluid_args.temperature = 300;
fluid_args.rho = 0;
fluid_args.cp = 0;
- create_fluid(dev, &fluid_args, &fluid1);
+ fluid1 = create_fluid(dev, &fluid_args);
+
+ /* Create the fluid2 */
+ fluid_args.temperature = 280;
+ fluid_args.rho = 0;
+ fluid_args.cp = 0;
+ fluid2 = create_fluid(dev, &fluid_args);
/* Create the solid medium */
solid_args.cp = 1.0;
@@ -653,14 +814,14 @@ main(int argc, char** argv)
solid_args.rho = 1.0;
solid_args.delta = 1.0/20.0;
solid_args.temperature = SDIS_TEMPERATURE_NONE;
- create_solid(dev, &solid_args, &solid);
+ solid = create_solid(dev, &solid_args);
/* Create the fluid0/solid interface */
interface_args.hc = 1;
interface_args.epsilon = 0;
interface_args.specular_fraction = 0;
interface_args.temperature = SDIS_TEMPERATURE_NONE;
- create_interface(dev, solid, fluid0, &interface_args, &interf0);
+ interf0 = create_interface(dev, solid, fluid0, &interface_args);
/* Create the fluid1/solid interface */
interface_args.hc = 0.1;
@@ -668,178 +829,45 @@ main(int argc, char** argv)
interface_args.specular_fraction = 1;
interface_args.temperature = SDIS_TEMPERATURE_NONE;
interface_args.reference_temperature = 300;
- create_interface(dev, fluid1, solid, &interface_args, &interf1);
-
- /* Setup the cube geometry */
- OK(s3dut_create_cuboid(NULL, 2, 2, 2, &msh));
- OK(s3dut_mesh_get_data(msh, &msh_data));
- geometry_add_shape(&geom, msh_data.positions, msh_data.nvertices,
- msh_data.indices, msh_data.nprimitives, NULL, interf1);
- OK(s3dut_mesh_ref_put(msh));
+ interf1 = create_interface(dev, fluid1, solid, &interface_args);
- /* Setup the sphere geometry */
- OK(s3dut_create_sphere(NULL, 0.5, 32, 16, &msh));
- OK(s3dut_mesh_get_data(msh, &msh_data));
- geometry_add_shape(&geom, msh_data.positions, msh_data.nvertices,
- msh_data.indices, msh_data.nprimitives, NULL, interf0);
- OK(s3dut_mesh_ref_put(msh));
+ /* Create the fluid2/ground interface */
+ interface_args.hc = 0.2;
+ interface_args.epsilon = 1;
+ interface_args.specular_fraction = 1;
+ interface_args.temperature = SDIS_TEMPERATURE_NONE;
+ interface_args.reference_temperature = 300;
+ interf2 = create_interface(dev, fluid2, solid, &interface_args);
- /* Setup the scene */
- ntris = sa_size(geom.indices) / 3; /* #primitives */
- npos = sa_size(geom.positions) / 3; /* #positions */
- scn_args.get_indices = geometry_get_indices;
- scn_args.get_interface = geometry_get_interface;
- scn_args.get_position = geometry_get_position;
- scn_args.nprimitives = ntris;
- scn_args.nvertices = npos;
- scn_args.t_range[0] = 300;
- scn_args.t_range[1] = 350;
- scn_args.radenv = radenv;
- scn_args.context = &geom;
- OK(sdis_scene_create(dev, &scn_args, &scn));
+ add_cube(&geom, interf1);
+ add_sphere(&geom, interf0);
+ add_ground(&geom, interf2);
#if 0
dump_mesh(stdout, geom.positions, sa_size(geom.positions)/3, geom.indices,
sa_size(geom.indices)/3);
#endif
- /* Setup the camera */
- d3(pos, 3, 3, 3);
- d3(tgt, 0, 0, 0);
- d3(up, 0, 0, 1);
- OK(sdis_camera_create(dev, &cam));
- OK(sdis_camera_set_proj_ratio(cam, (double)IMG_WIDTH/(double)IMG_HEIGHT));
- OK(sdis_camera_set_fov(cam, MDEG2RAD(70)));
- OK(sdis_camera_look_at(cam, pos, tgt, up));
-
-#if 0
- dump_mesh(stdout, geom.positions, npos, geom.indices, ntris);
- exit(0);
-#endif
- solve_args.cam = cam;
- solve_args.time_range[0] = INF;
- solve_args.time_range[0] = INF;
- solve_args.image_definition[0] = IMG_WIDTH;
- solve_args.image_definition[1] = IMG_HEIGHT;
- solve_args.spp = SPP;
-
- BA(sdis_solve_camera(NULL, &solve_args, &buf));
- BA(sdis_solve_camera(scn, NULL, &buf));
- BA(sdis_solve_camera(scn, &solve_args, NULL));
- solve_args.cam = NULL;
- BA(sdis_solve_camera(scn, &solve_args, &buf));
- solve_args.cam = cam;
- pradenv_args->temperature = SDIS_TEMPERATURE_NONE;
- BA(sdis_solve_camera(scn, &solve_args, &buf));
- pradenv_args->temperature = 300;
- solve_args.time_range[0] = solve_args.time_range[1] = -1;
- BA(sdis_solve_camera(scn, &solve_args, &buf));
- solve_args.time_range[0] = 1;
- BA(sdis_solve_camera(scn, &solve_args, &buf));
- solve_args.time_range[1] = 0;
- BA(sdis_solve_camera(scn, &solve_args, &buf));
- solve_args.time_range[0] = solve_args.time_range[1] = INF;
-
- /* Launch the simulation */
- OK(sdis_solve_camera(scn, &solve_args, &buf));
+ scn = create_scene(dev, radenv, &geom);
+ cam = create_camera(dev);
- if(!is_master_process) {
- CHK(buf == NULL);
- } else {
- BA(sdis_estimator_buffer_get_realisation_count(NULL, &nreals));
- BA(sdis_estimator_buffer_get_realisation_count(buf, NULL));
- OK(sdis_estimator_buffer_get_realisation_count(buf, &nreals));
-
- BA(sdis_estimator_buffer_get_failure_count(NULL, &nfails));
- BA(sdis_estimator_buffer_get_failure_count(buf, NULL));
- OK(sdis_estimator_buffer_get_failure_count(buf, &nfails));
-
- BA(sdis_estimator_buffer_get_temperature(NULL, &T));
- BA(sdis_estimator_buffer_get_temperature(buf, NULL));
- OK(sdis_estimator_buffer_get_temperature(buf, &T));
-
- BA(sdis_estimator_buffer_get_realisation_time(NULL, &time));
- BA(sdis_estimator_buffer_get_realisation_time(buf, NULL));
- OK(sdis_estimator_buffer_get_realisation_time(buf, &time));
-
- BA(sdis_estimator_buffer_get_rng_state(NULL, &rng_state));
- BA(sdis_estimator_buffer_get_rng_state(buf, NULL));
- OK(sdis_estimator_buffer_get_rng_state(buf, &rng_state));
-
- CHK(nreals + nfails == IMG_WIDTH*IMG_HEIGHT*SPP);
-
- fprintf(stderr, "Overall temperature ~ %g +/- %g\n", T.E, T.SE);
- fprintf(stderr, "Time per realisation (in usec) ~ %g +/- %g\n", time.E, time.SE);
- fprintf(stderr, "#failures = %lu/%lu\n",
- (unsigned long)nfails, (unsigned long)(IMG_WIDTH*IMG_HEIGHT*SPP));
-
- BA(sdis_estimator_buffer_get_definition(NULL, definition));
- BA(sdis_estimator_buffer_get_definition(buf, NULL));
- OK(sdis_estimator_buffer_get_definition(buf, definition));
- CHK(definition[0] == IMG_WIDTH);
- CHK(definition[1] == IMG_HEIGHT);
-
- /* Write the image */
- dump_image(buf);
- OK(sdis_estimator_buffer_ref_put(buf));
- }
-
- /* Check RNG type */
- solve_args.rng_state = NULL;
- solve_args.rng_type = SSP_RNG_TYPE_NULL;
- BA(sdis_solve_camera(scn, &solve_args, &buf2));
- solve_args.rng_type =
- SDIS_SOLVE_CAMERA_ARGS_DEFAULT.rng_type == SSP_RNG_THREEFRY
- ? SSP_RNG_MT19937_64 : SSP_RNG_THREEFRY;
- OK(sdis_solve_camera(scn, &solve_args, &buf2));
- if(is_master_process) {
- OK(sdis_estimator_buffer_get_temperature(buf2, &T2));
- CHK(T.E != T2.E || (T2.SE == 0 && T.SE ==0));
- CHK(T2.E + 3*T2.SE >= T.E - 3*T.SE
- && T2.E - 3*T2.SE <= T.E + 3*T.SE);
- OK(sdis_estimator_buffer_ref_put(buf2));
- }
-
- /* Check the RNG state */
- OK(ssp_rng_create(NULL, SSP_RNG_THREEFRY, &rng));
- OK(ssp_rng_discard(rng, 3141592653589)); /* Move the RNG state */
- solve_args.rng_state = rng;
- solve_args.rng_type = SSP_RNG_TYPE_NULL;
- OK(sdis_solve_camera(scn, &solve_args, &buf2));
- OK(ssp_rng_ref_put(rng));
- if(is_master_process) {
- OK(sdis_estimator_buffer_get_temperature(buf2, &T2));
- CHK(T.E != T2.E || (T2.SE == 0 && T.SE == 0));
- CHK(T2.E + 3*T2.SE >= T.E - 3*T.SE
- && T2.E - 3*T2.SE <= T.E + 3*T.SE);
- OK(sdis_estimator_buffer_ref_put(buf2));
- }
-
- /* Restore args */
- solve_args.rng_state = SDIS_SOLVE_CAMERA_ARGS_DEFAULT.rng_state;
- solve_args.rng_type = SDIS_SOLVE_CAMERA_ARGS_DEFAULT.rng_type;
-
- pfluid_args = sdis_data_get(sdis_medium_get_data(fluid1));
- pfluid_args->temperature = SDIS_TEMPERATURE_NONE;
-
- /* Check simulation error handling */
- BA(sdis_solve_camera(scn, &solve_args, &buf));
- solve_args.register_paths = SDIS_HEAT_PATH_ALL;
- BA(sdis_solve_camera(scn, &solve_args, &buf));
+ invalid_draw(scn, cam);
+ draw(scn, cam, is_master_process);
/* Release memory */
OK(sdis_medium_ref_put(solid));
OK(sdis_medium_ref_put(fluid0));
OK(sdis_medium_ref_put(fluid1));
+ OK(sdis_medium_ref_put(fluid2));
OK(sdis_radiative_env_ref_put(radenv));
OK(sdis_scene_ref_put(scn));
OK(sdis_camera_ref_put(cam));
OK(sdis_interface_ref_put(interf0));
OK(sdis_interface_ref_put(interf1));
+ OK(sdis_interface_ref_put(interf2));
free_default_device(dev);
geometry_release(&geom);
CHK(mem_allocated_size() == 0);
return 0;
}
-
diff --git a/src/test_sdis_solve_probe_boundary_list.c b/src/test_sdis_solve_probe_boundary_list.c
@@ -33,6 +33,7 @@
* estimate the temperature at the sphere boundary at several probe points. We
* should find by Monte Carlo the temperature of the trilinear profile at the
* position of the probe. It's the test.
+ *
* /\ <-- T(x,y,z)
* ___/ \___
* T(z) \ __ /
diff --git a/src/test_sdis_utils.h b/src/test_sdis_utils.h
@@ -195,6 +195,7 @@ static const struct sdis_solid_shader DUMMY_SOLID_SHADER = {
dummy_medium_getter, /* Delta */
dummy_medium_getter, /* Volumic power */
dummy_medium_getter, /* Temperature */
+ NULL, /* sample path */
0 /* Initial time */
};