commit 65da61bc8ff2d761285fa22fb269edbcc0d71617
parent 4a4b2e47445621dcce2ceff0f06d3bf3fb0fe417
Author: Vincent Forest <vincent.forest@meso-star.com>
Date: Fri, 4 Mar 2022 10:06:19 +0100
Merge branch 'release_0.13'
Diffstat:
95 files changed, 9809 insertions(+), 3755 deletions(-)
diff --git a/README.md b/README.md
@@ -20,13 +20,16 @@ The hypothesis these algorithms are based upon are the following:
- *convection*: fluid media are supposed to be isothermal, even if their
temperature may vary with time. This hypothesis relies on the assumption of
perfectly agitated fluids.
-- *radiation*: local radiative transfer is linearised, i.e. instead of writing
- the spectrally integrated net flux as a difference of temperatures to the
- power 4, it is assumed of the same form as the convective flux (as a
- difference of temperatures, multiplied by a radiative exchange coefficient).
- In order to be valid, this representation of radiative transfer exchanges
- requires that the temperature at any position and time is close to a known
- reference temperature.
+- *radiation*: local radiative transfer is solved by an [iterative numerical
+ method](https://hal.archives-ouvertes.fr/tel-03266863/) (Picard algorithm)
+ that requires the knowledge of a reference temperature field. At the basic
+ level (one level of recursion), and using a uniform reference temperature
+ field, this algorithm translates into the hypothesis of a linearized
+ radiative transfer. Using a higher order or recursion makes possible to
+ converge the result closer to the solution of a rigorous
+ spectrally-integrated radiative transfer (a difference of temperatures to the
+ power 4 when integrated over the whole spectrum). The higher the recursion
+ order, to better will be the convergence of the algorithm.
In Stardis-Solver the system to simulate is represented by a *scene* whose
geometry defines the contour of the object only: in contrast to legacy thermal
@@ -58,7 +61,7 @@ The main features of the solver are currently:
been reached; when internal power sources or imposed fluxes are taken into
account, additional contributions to the weight must be continuously
evaluated by the thermal conduction algorithm, but these contributions are
- proportional to the local dissipated power/imposed flux. In any case, the
+ proportional to the local dissipated power/imposed flux. In any case, the
position and date at the end of each thermal path (and also accumulation
coefficients) can be stored during a first complete Monte-Carlo simulation.
This information, known as the Green function, can then be used in (very
@@ -67,7 +70,8 @@ The main features of the solver are currently:
flux). Note that when using the Green function, only boundary and initial
conditions (as well as internal power sources) can be modified: in
particular, the geometry, thermal properties and exchange coefficients have
- to remain identical.
+ to remain identical. Furthermore, the green function is only valid under the
+ assumption of linearized radiative transfer.
- *path visualization*: Stardis-Solver can store the complete spatial and
temporal position along a set of thermal paths, for latter visualization. In
addition of their position and, each thermal path vertex register additional
@@ -79,7 +83,7 @@ Stardis-Solver is currently used in two frameworks. The
tools is the reference workflow of Stardis-Solver. It proposes a complete
toolchain from fileformats describing the scene (geometry, thermal properties,
limit and boundary conditions) to computations and post-treatments of the
-results ([Stardis-Green](https://gitlab.com/meso-star/stardis-green.git).
+results ([Stardis-Green](https://gitlab.com/meso-star/stardis-green.git)).
Stardis-Solver is also integrated into
[SYRTHES](https://www.edf.fr/en/the-edf-group/world-s-largest-power-company/activities/research-and-development/scientific-communities/simulation-softwares?logiciel=10818),
the general thermal free software developed by Electricité De France (EDF).
@@ -101,7 +105,9 @@ It also depends on the
[Star-Enclosures-2D](https://gitlab.com/meso-star/star-enclosures-2d/) and
[Star-SP](https://gitlab.com/meso-star/star-sp/) libraries as well as on the
[OpenMP](http://www.openmp.org) 2.0 specification to parallelize its
-computations.
+computations. It may depend on [OpenMPI](https://www.open-mpi.org/) 2.0 if
+distributed memory parallelism is enabled via the `ENABLE_MPI` variable of the
+CMake file
First ensure that CMake and a C compiler that implements the OpenMP 2.0
specification are installed on your system. Then install the RCMake package as
@@ -111,6 +117,38 @@ variable the install directories of its dependencies.
## Release notes
+### Version 0.13
+
+#### Non linear radiative transfer
+
+Uses a new [iterative numerical
+method](https://hal.archives-ouvertes.fr/tel-03266863/) to estimate radiative
+transfer. With a recursion level of 1, this is equivalent to a linearization of
+the radiative transfer but with a reference temperature that can vary in time
+and space. By using a higher-order recursion, one can converge towards a
+rigorous estimate that takes into account the non-linearity of the radiative
+transfer; the higher the recursion order, the better the convergence, but with
+the counterpart of an increase in calculation time.
+
+#### Distributed memory parallelism
+
+Uses message passing interface to distribute computation across multiple
+computers. Stardis-Solver now, uses a mixed parallelism: on one computer (i.e. a
+node), it uses a shared memory parallelism and relies on the message passing
+interface to parallelize calculations between several nodes.
+
+#### Type and state of the random number generator
+
+Adds the member input variable `rng_type` to the solve functions. It
+defines the type of random number generator to use when no generator is
+defined. Note that the `sdis_solve_camera` function does not have a random
+number generator as an input variable and has therefore been updated to support
+it.
+
+#### Reading the source code
+
+Refactoring and deep rewriting of the source code to simplify its reading.
+
### Version 0.12.3
Fix green paths ending in a fluid (transcient computation): The path's end was
@@ -374,7 +412,7 @@ First version and implementation of the Stardis-Solver API.
## License
-Copyright (C) 2016-2021 |Meso|Star> (<contact@meso-star.com>). Stardis-Solver
+Copyright (C) 2016-2022 |Méso|Star> (<contact@meso-star.com>). Stardis-Solver
is free software released under the GPLv3+ license: GNU GPL version 3 or later.
You are welcome to redistribute it under certain conditions; refer to the
COPYING files for details.
diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt
@@ -1,4 +1,4 @@
-# Copyright (C) 2016-2021 |Meso|Star> (contact@meso-star.com)
+# Copyright (C) 2016-2022 |Meso|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
@@ -21,6 +21,9 @@ include(CMakeDependentOption)
set(SDIS_SOURCE_DIR ${PROJECT_SOURCE_DIR}/../src)
option(NO_TEST "Do not build tests" OFF)
+option(ENABLE_MPI
+ "Enable the support of distributed parallelism \
+using the Message Passing Interface specification." ON)
CMAKE_DEPENDENT_OPTION(ALL_TESTS
"Perform basic and advanced tests" OFF "NOT NO_TEST" OFF)
@@ -31,7 +34,7 @@ CMAKE_DEPENDENT_OPTION(ALL_TESTS
find_package(RCMake 0.4 REQUIRED)
find_package(Star2D 0.5 REQUIRED)
find_package(Star3D 0.8 REQUIRED)
-find_package(StarSP 0.12 REQUIRED)
+find_package(StarSP 0.13 REQUIRED)
find_package(StarEnc2D 0.5 REQUIRED)
find_package(StarEnc3D 0.5 REQUIRED)
find_package(RSys 0.12 REQUIRED)
@@ -49,6 +52,12 @@ include_directories(
${StarEnc3D_INCLUDE_DIR}
${RSys_INCLUDE_DIR})
+if(ENABLE_MPI)
+ find_package(MPI 2 REQUIRED)
+ set(CMAKE_C_COMPILER ${MPI_C_COMPILER})
+ include_directories(${MPI_INCLUDE_PATH})
+endif()
+
rcmake_append_runtime_dirs(_runtime_dirs
RSys Star2D Star3D StarSP StarEnc2D StarEnc3D)
@@ -56,11 +65,12 @@ rcmake_append_runtime_dirs(_runtime_dirs
# Configure and define targets
###############################################################################
set(VERSION_MAJOR 0)
-set(VERSION_MINOR 12)
-set(VERSION_PATCH 3)
+set(VERSION_MINOR 13)
+set(VERSION_PATCH 0)
set(VERSION ${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_PATCH})
set(SDIS_FILES_SRC
+ sdis.c
sdis_camera.c
sdis_data.c
sdis_device.c
@@ -68,24 +78,32 @@ set(SDIS_FILES_SRC
sdis_estimator_buffer.c
sdis_green.c
sdis_heat_path.c
+ sdis_heat_path_boundary.c
sdis_interface.c
sdis_log.c
sdis_medium.c
sdis_misc.c
sdis_realisation.c
sdis_scene.c
- sdis_solve.c)
+ sdis_solve.c
+ sdis_solve_camera.c
+ sdis_tile.c)
set(SDIS_FILES_INC_API
sdis.h)
set(SDIS_FILES_INC
+ sdis_c.h
sdis_camera.h
sdis_device_c.h
sdis_estimator_c.h
sdis_green.h
sdis_heat_path.h
+ sdis_heat_path_boundary_c.h
sdis_heat_path_boundary_Xd.h
+ sdis_heat_path_boundary_Xd_fixed_flux.h
+ sdis_heat_path_boundary_Xd_solid_fluid_picard1.h
+ sdis_heat_path_boundary_Xd_solid_solid.h
sdis_heat_path_conductive_Xd.h
sdis_heat_path_convective_Xd.h
sdis_heat_path_radiative_Xd.h
@@ -102,9 +120,15 @@ set(SDIS_FILES_INC
sdis_solve_medium_Xd.h
sdis_solve_probe_Xd.h
sdis_solve_probe_boundary_Xd.h
+ sdis_tile.h
sdis_Xd_begin.h
sdis_Xd_end.h)
+if(ENABLE_MPI)
+ set(SDIS_FILES_SRC ${SDIS_FILES_SRC} sdis_mpi.c)
+ set(SDIS_FILES_INC ${SDIS_FILES_INC} sdis_mpi.h)
+endif()
+
set(SDIS_FILES_DOC COPYING README.md)
# Prepend each file by `SDIS_SOURCE_DIR'
@@ -147,6 +171,10 @@ if(CMAKE_COMPILER_IS_GNUCC)
set_target_properties(sdis PROPERTIES LINK_FLAGS "${OpenMP_C_FLAGS}")
endif()
+if(ENABLE_MPI)
+ set_target_properties(sdis PROPERTIES COMPILE_DEFINITIONS "SDIS_ENABLE_MPI")
+endif()
+
rcmake_setup_devel(sdis Stardis ${VERSION} sdis_version.h)
###############################################################################
@@ -175,7 +203,6 @@ if(NOT NO_TEST)
endfunction()
new_test(test_sdis_camera)
- new_test(test_sdis_compute_power)
new_test(test_sdis_conducto_radiative)
new_test(test_sdis_conducto_radiative_2d)
new_test(test_sdis_contact_resistance)
@@ -187,24 +214,28 @@ if(NOT NO_TEST)
new_test(test_sdis_flux)
new_test(test_sdis_interface)
new_test(test_sdis_medium)
+ new_test(test_sdis_picard)
new_test(test_sdis_scene)
new_test(test_sdis_solid_random_walk_robustness)
- new_test(test_sdis_solve_camera)
new_test(test_sdis_solve_probe)
- new_test(test_sdis_solve_probe2)
new_test(test_sdis_solve_probe3)
new_test(test_sdis_solve_probe_2d)
new_test(test_sdis_solve_probe2_2d)
new_test(test_sdis_solve_probe3_2d)
- new_test(test_sdis_solve_boundary)
- new_test(test_sdis_solve_boundary_flux)
- new_test(test_sdis_solve_medium)
- new_test(test_sdis_solve_medium_2d)
new_test(test_sdis_transcient)
new_test(test_sdis_unstationary_atm)
new_test(test_sdis_volumic_power)
new_test(test_sdis_volumic_power4)
+ build_test(test_sdis)
+ build_test(test_sdis_compute_power)
+ build_test(test_sdis_solve_camera)
+ build_test(test_sdis_solve_medium)
+ build_test(test_sdis_solve_medium_2d)
+ build_test(test_sdis_solve_boundary)
+ build_test(test_sdis_solve_boundary_flux)
+ build_test(test_sdis_solve_probe2)
+
# Additionnal tests
build_test(test_sdis_volumic_power2)
build_test(test_sdis_volumic_power2_2d)
@@ -222,7 +253,40 @@ if(NOT NO_TEST)
target_link_libraries(test_sdis_solve_probe3 Star3DUT)
target_link_libraries(test_sdis_solve_probe3_2d ${MATH_LIB})
target_link_libraries(test_sdis_solve_camera Star3DUT)
-
+
+ target_link_libraries(test_sdis_solve_boundary StarSP)
+ target_link_libraries(test_sdis_solve_boundary_flux StarSP)
+ target_link_libraries(test_sdis_solve_probe2 StarSP)
+ target_link_libraries(test_sdis_solve_medium StarSP)
+
+ set(_mpi_tests
+ test_sdis
+ test_sdis_compute_power
+ test_sdis_solve_camera
+ test_sdis_solve_medium
+ test_sdis_solve_medium_2d
+ test_sdis_solve_boundary
+ test_sdis_solve_boundary_flux
+ test_sdis_solve_probe2)
+
+ if(NOT ENABLE_MPI)
+ foreach(_test ${_mpi_tests})
+ add_test(${_test} ${_test})
+ endforeach()
+ else()
+ set_target_properties(test_sdis PROPERTIES
+ COMPILE_DEFINITIONS "SDIS_ENABLE_MPI")
+ set_target_properties(test_sdis_device PROPERTIES
+ COMPILE_DEFINITIONS "SDIS_ENABLE_MPI")
+
+ foreach(_test ${_mpi_tests})
+ set_target_properties(${_test} PROPERTIES
+ COMPILE_DEFINITIONS "SDIS_ENABLE_MPI")
+ add_test(${_test}_mpi_on mpirun -n 2 ${_test} mpi)
+ add_test(${_test}_no_mpi ${_test})
+ endforeach()
+ endif()
+
rcmake_copy_runtime_libraries(test_sdis_solid_random_walk_robustness)
endif()
@@ -236,4 +300,3 @@ install(TARGETS sdis
RUNTIME DESTINATION bin)
install(FILES ${SDIS_FILES_INC_API} DESTINATION include/)
install(FILES ${SDIS_FILES_DOC} DESTINATION share/doc/stardis-solver)
-
diff --git a/src/sdis.c b/src/sdis.c
@@ -0,0 +1,870 @@
+/* Copyright (C) 2016-2022 |Meso|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/>. */
+
+#define _POSIX_C_SOURCE 200112L
+
+#include "sdis.h"
+#include "sdis_c.h"
+#include "sdis_device_c.h"
+#include "sdis_estimator_c.h"
+#include "sdis_green.h"
+#include "sdis_log.h"
+#include "sdis_misc.h"
+#include "sdis_scene_c.h"
+#ifdef SDIS_ENABLE_MPI
+ #include "sdis_mpi.h"
+#endif
+
+#include <star/ssp.h>
+
+#include <rsys/cstr.h>
+#include <rsys/clock_time.h>
+#include <rsys/mem_allocator.h>
+
+#include <errno.h>
+
+/* Number random numbers in a sequence, i.e. number of consecutive random
+ * numbers that can be used by a thread */
+#define RNG_SEQUENCE_SIZE 100000
+
+/*******************************************************************************
+ * Helper functions
+ ******************************************************************************/
+static INLINE int
+check_accum_message(const enum mpi_sdis_message msg)
+{
+ return msg == MPI_SDIS_MSG_ACCUM_TEMP
+ || msg == MPI_SDIS_MSG_ACCUM_TIME
+ || msg == MPI_SDIS_MSG_ACCUM_FLUX_CONVECTIVE
+ || msg == MPI_SDIS_MSG_ACCUM_FLUX_IMPOSED
+ || msg == MPI_SDIS_MSG_ACCUM_FLUX_RADIATIVE
+ || msg == MPI_SDIS_MSG_ACCUM_FLUX_TOTAL
+ || msg == MPI_SDIS_MSG_ACCUM_MEAN_POWER;
+}
+
+static res_T
+gather_green_functions_no_mpi
+ (struct sdis_scene* scn,
+ struct ssp_rng_proxy* rng_proxy,
+ struct sdis_green_function* per_thread_green[],
+ const struct accum* per_thread_acc_time,
+ struct sdis_green_function** out_green)
+{
+ struct sdis_green_function* green = NULL;
+ struct accum acc_time = ACCUM_NULL;
+ res_T res = RES_OK;
+ ASSERT(scn && rng_proxy && per_thread_green && per_thread_acc_time);
+ ASSERT(out_green);
+
+ /* Redux the per thread green function into the green function of the 1st
+ * thread */
+ res = green_function_redux_and_clear
+ (per_thread_green[0], per_thread_green+1, scn->dev->nthreads-1);
+ if(res != RES_OK) goto error;
+
+ /* Return the green of the 1st thread */
+ SDIS(green_function_ref_get(per_thread_green[0]));
+ green = per_thread_green[0];
+
+ res = gather_accumulators
+ (scn->dev, MPI_SDIS_MSG_ACCUM_TIME, per_thread_acc_time, &acc_time);
+ if(res != RES_OK) goto error;
+
+ /* Finalize the estimated green */
+ res = green_function_finalize(green, rng_proxy, &acc_time);
+ if(res != RES_OK) goto error;
+
+exit:
+ *out_green = green;
+ return res;
+error:
+ if(green) { SDIS(green_function_ref_put(green)); green = NULL; }
+ goto exit;
+}
+
+#ifdef SDIS_ENABLE_MPI
+static void
+rewind_progress_printing(struct sdis_device* dev)
+{
+ size_t i;
+ if(!dev->use_mpi || dev->mpi_nprocs == 1) return;
+ FOR_EACH(i, 0, dev->mpi_nprocs-1) {
+ log_info(dev, "\033[1A\r"); /* Move up */
+ }
+}
+
+static res_T
+send_green_function_to_master_process
+ (struct sdis_device* dev,
+ struct sdis_green_function* green)
+{
+ char buf[128];
+ FILE* stream = NULL; /* Temp file that stores the serialized green function */
+ void* data = NULL; /* Pointer to serialized green function data */
+ long sz = 0; /* Size in Bytes of the serialized green function data */
+ res_T res = RES_OK;
+ ASSERT(dev && green && dev->mpi_rank != 0);
+
+ /* Open a stream to store the serialized green function */
+ stream = tmpfile();
+ if(!stream) {
+ log_err(dev,
+ "Could not open the stream used to temporary store the green function "
+ "before it is sent to the master process.\n");
+ res = RES_IO_ERR;
+ goto error;
+ }
+
+ /* Write the green function into the stream */
+ res = sdis_green_function_write(green, stream);
+ if(res != RES_OK) goto error;
+
+ /* Fetch the size of the serialized data */
+ sz = ftell(stream);
+ if(sz == -1) {
+ strerror_r(errno, buf, sizeof(buf));
+ log_err(dev,
+ "Could not query the size of the serialized green function data to sent "
+ "to the master process -- %s.\n", buf);
+ res = RES_IO_ERR;
+ goto error;
+ }
+ if(sz > INT_MAX) {
+ log_err(dev,
+ "The size of the green function data is too large. It must be less than "
+ "%d Mebabytes while it is of %ld MegabBytes.\n",
+ INT_MAX / (1024*1024), sz/(1024*1024));
+ res = RES_MEM_ERR;
+ goto error;
+ }
+
+ data = MEM_CALLOC(dev->allocator, 1, (size_t)sz);
+ if(!data) {
+ log_err(dev, "Could not allocate the memory to store the serialized green "
+ "function before it is sent to the master process.\n");
+ res = RES_MEM_ERR;
+ goto error;
+ }
+
+ /* Load in memory the serialized data */
+ rewind(stream);
+ if(fread(data, (size_t)sz, 1, stream) != 1) {
+ log_err(dev,
+ "Could not read the serialized green function data from the temporary "
+ "stream before it is sent to the master process.\n");
+ res = RES_IO_ERR;
+ goto error;
+ }
+
+ /* Send the serialized data to the master process */
+ mutex_lock(dev->mpi_mutex);
+ MPI(Send(data, (int)sz, MPI_CHAR, 0/*Dst*/, MPI_SDIS_MSG_GREEN_FUNCTION,
+ MPI_COMM_WORLD));
+ mutex_unlock(dev->mpi_mutex);
+
+exit:
+ if(stream) CHK(fclose(stream) == 0);
+ if(data) MEM_RM(dev->allocator, data);
+ return RES_OK;
+error:
+ goto exit;
+}
+
+static res_T
+gather_green_functions_from_non_master_process
+ (struct sdis_scene* scn,
+ struct sdis_green_function* greens[])
+{
+ void* data = NULL; /* Pointer to gathered serialized green function data */
+ FILE* stream = NULL; /* Temp file that stores the serialized green function */
+ int iproc;
+ res_T res = RES_OK;
+ ASSERT(scn->dev && greens && scn->dev->mpi_rank == 0);
+
+ FOR_EACH(iproc, 1, scn->dev->mpi_nprocs) {
+ MPI_Request req;
+ MPI_Status status;
+ int count;
+
+ /* Waiting for the serialized green function sent by the process `iproc'*/
+ mpi_waiting_for_message
+ (scn->dev, iproc, MPI_SDIS_MSG_GREEN_FUNCTION, &status);
+
+ /* Fetch the sizeof the green function sent by the process `iproc' */
+ mutex_lock(scn->dev->mpi_mutex);
+ MPI(Get_count(&status, MPI_CHAR, &count));
+ mutex_unlock(scn->dev->mpi_mutex);
+
+ /* Allocate the memory to store the serialized green function sent by the
+ * process `iproc' */
+ data = MEM_REALLOC(scn->dev->allocator, data, (size_t)count);
+ if(!data) {
+ log_err(scn->dev,
+ "Could not allocate %d bytes to store the serialized green function "
+ "sent by the process %d.\n",
+ count, iproc);
+ res = RES_MEM_ERR;
+ goto error;
+ }
+
+ /* Asynchronously receive the green function */
+ mutex_lock(scn->dev->mpi_mutex);
+ MPI(Irecv(data, count, MPI_CHAR, iproc, MPI_SDIS_MSG_GREEN_FUNCTION,
+ MPI_COMM_WORLD, &req));
+ mutex_unlock(scn->dev->mpi_mutex);
+ mpi_waiting_for_request(scn->dev, &req);
+
+ /* Open a stream to store the serialized green function */
+ stream = tmpfile();
+ if(!stream) {
+ log_err(scn->dev,
+ "Could not open the stream used to temporary store the green function "
+ "sent by the process %d.\n", iproc);
+ res = RES_IO_ERR;
+ goto error;
+ }
+
+ if(fwrite(data, (size_t)count, 1, stream) != 1) {
+ log_err(scn->dev,
+ "Could not write the green function sent by the process %d into the "
+ "temporary stream.\n", iproc);
+ res = RES_IO_ERR;
+ goto error;
+ }
+
+ /* Deserialized the green function of the process `iproc'. Note that the
+ * number of green functions to output is #procs - 1. Since we
+ * iterate over the indices of non master processes in [1, #procs],
+ * the index the green function to deserialized is iproc - 1 */
+ rewind(stream);
+ res = sdis_green_function_create_from_stream(scn, stream, &greens[iproc-1]);
+ if(res != RES_OK) {
+ log_err(scn->dev,
+ "Error deserializing the green function sent by the process %d -- %s.\n",
+ iproc, res_to_cstr(res));
+ goto error;
+ }
+
+ CHK(fclose(stream) == 0);
+ stream = NULL;
+ }
+
+exit:
+ if(data) MEM_RM(scn->dev->allocator, data);
+ if(stream) CHK(fclose(stream) == 0);
+ return res;
+error:
+ goto exit;
+}
+#endif
+
+/*******************************************************************************
+ * Exported function
+ ******************************************************************************/
+res_T
+sdis_get_info(struct sdis_info* info)
+{
+ if(!info) return RES_BAD_ARG;
+ *info = SDIS_INFO_NULL;
+#ifdef SDIS_ENABLE_MPI
+ info->mpi_enabled = 1;
+#else
+ info->mpi_enabled = 0;
+#endif
+ return RES_OK;
+}
+
+/*******************************************************************************
+ * Local functions
+ ******************************************************************************/
+res_T
+create_per_thread_rng
+ (struct sdis_device* dev,
+ struct ssp_rng* rng_state,
+ const enum ssp_rng_type rng_type,
+ struct ssp_rng_proxy** out_proxy,
+ struct ssp_rng** out_rngs[])
+{
+ struct ssp_rng_proxy_create2_args proxy_args = SSP_RNG_PROXY_CREATE2_ARGS_NULL;
+ struct ssp_rng_proxy* proxy = NULL;
+ struct ssp_rng** rngs = NULL;
+ size_t i;
+ res_T res = RES_OK;
+ ASSERT(dev && out_proxy && out_rngs);
+
+ rngs = MEM_CALLOC(dev->allocator, dev->nthreads, sizeof(*rngs));
+ if(!rngs) {
+ log_err(dev, "Could not allocate the list of per thread RNG.\n");
+ res = RES_MEM_ERR;
+ goto error;
+ }
+
+ /* Create the RNG proxy */
+ proxy_args.rng= rng_state;
+ proxy_args.type = rng_type;
+ proxy_args.nbuckets = dev->nthreads;
+#ifdef SDIS_ENABLE_MPI
+ if(dev->use_mpi) {
+ proxy_args.sequence_size = RNG_SEQUENCE_SIZE;
+ proxy_args.sequence_offset = RNG_SEQUENCE_SIZE * (size_t)dev->mpi_rank;
+ proxy_args.sequence_pitch = RNG_SEQUENCE_SIZE * (size_t)dev->mpi_nprocs;
+ } else
+#endif
+ {
+ proxy_args.sequence_size = RNG_SEQUENCE_SIZE;
+ proxy_args.sequence_offset = 0;
+ proxy_args.sequence_pitch = RNG_SEQUENCE_SIZE;
+ }
+ res = ssp_rng_proxy_create2(dev->allocator, &proxy_args, &proxy);
+ if(res != RES_OK) goto error;
+
+ /* Query the RNG proxy to create the per thread RNGs */
+ FOR_EACH(i, 0, dev->nthreads) {
+ res = ssp_rng_proxy_create_rng(proxy, i, &rngs[i]);
+ if(res != RES_OK) goto error;
+ }
+
+exit:
+ *out_rngs = rngs;
+ *out_proxy = proxy;
+ return res;
+error:
+ if(rngs) { release_per_thread_rng(dev, rngs); rngs = NULL; }
+ if(proxy) { SSP(rng_proxy_ref_put(proxy)); proxy = NULL; }
+ goto exit;
+}
+
+void
+release_per_thread_rng(struct sdis_device* dev, struct ssp_rng* rngs[])
+{
+ size_t i;
+ ASSERT(dev);
+ if(!rngs) return;
+ FOR_EACH(i, 0, dev->nthreads) { if(rngs[i]) SSP(rng_ref_put(rngs[i])); }
+ MEM_RM(dev->allocator, rngs);
+}
+
+res_T
+create_per_thread_green_function
+ (struct sdis_scene* scn,
+ struct sdis_green_function** out_greens[])
+{
+ struct sdis_green_function** greens = NULL;
+ size_t i;
+ res_T res = RES_OK;
+ ASSERT(scn && out_greens);
+
+ greens = MEM_CALLOC(scn->dev->allocator, scn->dev->nthreads, sizeof(*greens));
+ if(!greens) {
+ log_err(scn->dev,
+ "Could not allocate the list of per thread green function.\n");
+ res = RES_MEM_ERR;
+ goto error;
+ }
+
+ FOR_EACH(i, 0, scn->dev->nthreads) {
+ res = green_function_create(scn, &greens[i]);
+ if(res != RES_OK) goto error;
+ }
+
+exit:
+ *out_greens = greens;
+ return res;
+error:
+ if(greens) {
+ release_per_thread_green_function(scn, greens);
+ greens = NULL;
+ }
+ goto exit;
+}
+
+void
+release_per_thread_green_function
+ (struct sdis_scene* scn,
+ struct sdis_green_function* greens[])
+{
+ size_t i;
+ ASSERT(greens);
+ FOR_EACH(i, 0, scn->dev->nthreads) {
+ if(greens[i]) SDIS(green_function_ref_put(greens[i]));
+ }
+ MEM_RM(scn->dev->allocator, greens);
+}
+
+res_T
+alloc_process_progress(struct sdis_device* dev, int32_t** out_progress)
+{
+ int32_t* progress = NULL;
+ size_t nprocs;
+ res_T res = RES_OK;
+ ASSERT(dev && out_progress);
+
+#ifdef SDIS_ENABLE_MPI
+ if(dev->use_mpi) {
+ nprocs = (size_t)dev->mpi_nprocs;
+ } else
+#endif
+ {
+ nprocs = 1;
+ }
+ progress = MEM_CALLOC(dev->allocator, nprocs, sizeof(*progress));
+ if(!progress) {
+ log_err(dev,"Could not allocate the list of per process progress status.\n");
+ res = RES_MEM_ERR;
+ goto error;
+ }
+
+exit:
+ *out_progress = progress;
+ return res;
+error:
+ if(progress) { MEM_RM(dev->allocator, progress); progress = NULL; }
+ goto exit;
+}
+
+void
+free_process_progress(struct sdis_device* dev, int32_t progress[])
+{
+ ASSERT(dev && progress);
+ MEM_RM(dev->allocator, progress);
+}
+
+size_t
+compute_process_realisations_count
+ (const struct sdis_device* dev,
+ const size_t nrealisations)
+{
+#ifndef SDIS_ENABLE_MPI
+ (void)dev, (void)nrealisations;
+ return nrealisations;
+#else
+ size_t per_process_nrealisations = 0;
+ size_t remaining_nrealisations = 0;
+ ASSERT(dev);
+
+ if(!dev->use_mpi) return nrealisations;
+
+ /* Compute minimum the number of realisations on each process */
+ per_process_nrealisations = nrealisations / (size_t)dev->mpi_nprocs;
+
+ /* Define the remaining number of realisations that are not handle by one
+ * process */
+ remaining_nrealisations =
+ nrealisations
+ - per_process_nrealisations * (size_t)dev->mpi_nprocs;
+
+ /* Distribute the remaining realisations onto the processes */
+ if((size_t)dev->mpi_rank >= remaining_nrealisations) {
+ return per_process_nrealisations;
+ } else {
+ return per_process_nrealisations + 1;
+ }
+#endif
+}
+
+#ifndef SDIS_ENABLE_MPI
+res_T
+gather_accumulators
+ (struct sdis_device* dev,
+ const enum mpi_sdis_message msg,
+ const struct accum* per_thread_acc,
+ struct accum* acc)
+{
+ (void)msg;
+ ASSERT(dev);
+ /* Gather thread accumulators */
+ sum_accums(per_thread_acc, dev->nthreads, acc);
+ return RES_OK;
+}
+#endif
+
+#ifdef SDIS_ENABLE_MPI
+res_T
+gather_accumulators
+ (struct sdis_device* dev,
+ const enum mpi_sdis_message msg,
+ const struct accum* per_thread_acc,
+ struct accum* acc)
+{
+ struct accum* per_proc_acc = NULL;
+ size_t nprocs = 0;
+ res_T res = RES_OK;
+ ASSERT(dev && per_thread_acc && acc && check_accum_message(msg));
+
+ if(!dev->use_mpi) {
+ /* Gather thread accumulators */
+ sum_accums(per_thread_acc, dev->nthreads, acc);
+ goto exit;
+ }
+
+ nprocs = dev->mpi_rank == 0 ? (size_t)dev->mpi_nprocs : 1;
+ per_proc_acc = MEM_CALLOC(dev->allocator, nprocs, sizeof(struct accum));
+ if(!per_proc_acc) { res = RES_MEM_ERR; goto error; }
+
+ /* Gather thread accumulators */
+ sum_accums(per_thread_acc, dev->nthreads, &per_proc_acc[0]);
+
+ /* Non master process */
+ if(dev->mpi_rank != 0) {
+
+ /* Send the accumulator to the master process */
+ mutex_lock(dev->mpi_mutex);
+ MPI(Send(&per_proc_acc[0], sizeof(per_proc_acc[0]), MPI_CHAR, 0/*Dst*/,
+ msg, MPI_COMM_WORLD));
+ mutex_unlock(dev->mpi_mutex);
+
+ *acc = per_proc_acc[0];
+
+ /* Master process */
+ } else {
+ int iproc;
+
+ /* Gather process accumulators */
+ FOR_EACH(iproc, 1, dev->mpi_nprocs) {
+ MPI_Request req;
+
+ /* Asynchronously receive the accumulator of `iproc' */
+ mutex_lock(dev->mpi_mutex);
+ MPI(Irecv(&per_proc_acc[iproc], sizeof(per_proc_acc[iproc]), MPI_CHAR,
+ iproc, msg, MPI_COMM_WORLD, &req));
+ mutex_unlock(dev->mpi_mutex);
+ mpi_waiting_for_request(dev, &req);
+ }
+
+ /* Sum the process accumulators */
+ sum_accums(per_proc_acc, (size_t)dev->mpi_nprocs, acc);
+ }
+
+exit:
+ if(per_proc_acc) MEM_RM(dev->allocator, per_proc_acc);
+ return res;
+error:
+ goto exit;
+}
+#endif /* SDIS_ENABLE_MPI */
+
+#ifndef SDIS_ENABLE_MPI
+res_T
+gather_green_functions
+ (struct sdis_scene* scn,
+ struct ssp_rng_proxy* rng_proxy,
+ struct sdis_green_function* per_thread_green[],
+ const struct accum* per_thread_acc_time,
+ struct sdis_green_function** out_green)
+{
+ return gather_green_functions_no_mpi
+ (scn, rng_proxy, per_thread_green, per_thread_acc_time, out_green);
+}
+#else
+res_T
+gather_green_functions
+ (struct sdis_scene* scn,
+ struct ssp_rng_proxy* rng_proxy,
+ struct sdis_green_function* per_thread_green[],
+ const struct accum* per_thread_acc_time,
+ struct sdis_green_function** out_green)
+{
+ struct accum acc_time = ACCUM_NULL;
+ struct sdis_green_function* green = NULL;
+ struct sdis_green_function** per_proc_green = NULL;
+ unsigned ithread;
+ int iproc;
+ res_T res = RES_OK;
+ ASSERT(scn && per_thread_green && out_green);
+
+ if(!scn->dev->use_mpi) {
+ return gather_green_functions_no_mpi
+ (scn, rng_proxy, per_thread_green, per_thread_acc_time, out_green);
+ goto exit;
+ }
+
+ /* Redux the per thread green function into the green function of the 1st
+ * thread */
+ res = green_function_redux_and_clear
+ (per_thread_green[0], per_thread_green+1, scn->dev->nthreads-1);
+ if(res != RES_OK) goto error;
+
+ /* Gather the accumulators. The master process gathers all accumulators and
+ * non master process gather their per thread accumulators only that is
+ * sent to the master process */
+ res = gather_accumulators
+ (scn->dev, MPI_SDIS_MSG_ACCUM_TIME, per_thread_acc_time, &acc_time);
+ if(res != RES_OK) goto error;
+
+ /* Non master process */
+ if(scn->dev->mpi_rank != 0) {
+ /* Return the green of the 1st thread */
+ SDIS(green_function_ref_get(per_thread_green[0]));
+ green = per_thread_green[0];
+
+ /* We have to finalize the green function priorly to its sent to the master
+ * process. Its serialization failed without it. */
+ res = green_function_finalize(green, rng_proxy, &acc_time);
+ if(res != RES_OK) goto error;
+
+ res = send_green_function_to_master_process(scn->dev, green);
+ if(res != RES_OK) goto error;
+
+ /* Master process */
+ } else {
+ /* Allocate the list of per process green functions */
+ per_proc_green = MEM_CALLOC(scn->dev->allocator,
+ (size_t)scn->dev->mpi_nprocs, sizeof(*per_proc_green));
+ if(!per_proc_green) {
+ log_err(scn->dev,
+ "Could not allocate the temporary list of per process "
+ "green functions.\n");
+ res = RES_MEM_ERR;
+ goto error;
+ }
+
+ /* Set the gathered per thread green function stores on thread 0 at the
+ * green function for master process */
+ SDIS(green_function_ref_get(per_thread_green[0]));
+ per_proc_green[0] = per_thread_green[0];
+
+ /* Release per thread green functions */
+ FOR_EACH(ithread, 0, scn->dev->nthreads) {
+ SDIS(green_function_ref_put(per_thread_green[ithread]));
+ per_thread_green[ithread] = NULL;
+ }
+
+ res = gather_green_functions_from_non_master_process(scn, per_proc_green+1);
+ if(res != RES_OK) goto error;
+
+ /* Redux the per proc green function into the green function of the master
+ * process */
+ res = green_function_redux_and_clear
+ (per_proc_green[0], per_proc_green+1, (size_t)scn->dev->mpi_nprocs-1);
+ if(res != RES_OK) goto error;
+
+ /* Return the gatherd green function of the master process */
+ SDIS(green_function_ref_get(per_proc_green[0]));
+ green = per_proc_green[0];
+
+ /* Finalize the green function */
+ res = green_function_finalize(green, rng_proxy, &acc_time);
+ if(res != RES_OK) goto error;
+ }
+
+exit:
+ if(per_proc_green) {
+ FOR_EACH(iproc, 0, scn->dev->mpi_nprocs) {
+ if(per_proc_green[iproc]) {
+ SDIS(green_function_ref_put(per_proc_green[iproc]));
+ }
+ }
+ MEM_RM(scn->dev->allocator, per_proc_green);
+ }
+ *out_green = green;
+ return res;
+error:
+ if(green) { SDIS(green_function_ref_put(green)); green = NULL; }
+ goto exit;
+}
+
+#endif
+
+#ifndef SDIS_ENABLE_MPI
+res_T
+gather_rng_proxy_sequence_id
+ (struct sdis_device* dev,
+ struct ssp_rng_proxy* proxy)
+{
+ ASSERT(dev && proxy);
+ (void)dev, (void)proxy;
+ return RES_OK;
+}
+#else
+
+res_T
+gather_rng_proxy_sequence_id
+ (struct sdis_device* dev,
+ struct ssp_rng_proxy* proxy)
+{
+ unsigned long proc_seq_id = 0;
+ size_t seq_id = SSP_SEQUENCE_ID_NONE;
+ res_T res = RES_OK;
+ ASSERT(dev && proxy);
+
+ if(!dev->use_mpi) goto exit;
+
+ /* Retrieve the sequence id of the process */
+ SSP(rng_proxy_get_sequence_id(proxy, &seq_id));
+ CHK(seq_id <= ULONG_MAX);
+ proc_seq_id = (unsigned long)seq_id;
+
+ /* Non master process */
+ if(dev->mpi_rank != 0) {
+
+ /* Send the sequence id to the master process */
+ mutex_lock(dev->mpi_mutex);
+ MPI(Send(&proc_seq_id, 1, MPI_UNSIGNED_LONG, 0/*Dst*/,
+ MPI_SDIS_MSG_RNG_PROXY_SEQUENCE_ID, MPI_COMM_WORLD));
+ mutex_unlock(dev->mpi_mutex);
+
+ /* Master process */
+ } else {
+ size_t nseqs_to_flush = 0;
+ unsigned long max_seq_id = 0;
+ int iproc;
+
+ max_seq_id = proc_seq_id;
+
+ /* Gather per process sequence id and defined the maximum sequence id */
+ FOR_EACH(iproc, 1, dev->mpi_nprocs) {
+ MPI_Request req;
+ unsigned long tmp_seq_id;
+
+ /* Asynchronously receive the sequence id of `iproc' */
+ mutex_lock(dev->mpi_mutex);
+ MPI(Irecv(&tmp_seq_id, 1, MPI_UNSIGNED_LONG, iproc,
+ MPI_SDIS_MSG_RNG_PROXY_SEQUENCE_ID, MPI_COMM_WORLD, &req));
+ mutex_unlock(dev->mpi_mutex);
+ mpi_waiting_for_request(dev, &req);
+
+ /* Define the maximum sequence id between all processes */
+ max_seq_id = MMAX(max_seq_id, tmp_seq_id);
+ }
+
+ /* Flush the current sequence that is already consumed in addition to the
+ * sequences queried by the other processes */
+ nseqs_to_flush = 1/*Current sequence*/ + max_seq_id - proc_seq_id;
+ res = ssp_rng_proxy_flush_sequences(proxy, nseqs_to_flush);
+ if(res != RES_OK) goto error;
+ }
+
+exit:
+ return res;
+error:
+ goto exit;
+}
+#endif
+
+#ifndef SDIS_ENABLE_MPI
+res_T
+gather_res_T(struct sdis_device* dev, const res_T res)
+{
+ (void)dev;
+ return res;
+}
+#else
+res_T
+gather_res_T(struct sdis_device* dev, const res_T proc_res)
+{
+ int32_t status;
+ res_T res = proc_res;
+ int iproc;
+ ASSERT(dev);
+
+ if(!dev->use_mpi) return proc_res;
+
+ status = (int32_t)(proc_res);
+
+ /* Send the local res status to all other processes */
+ FOR_EACH(iproc, 0, dev->mpi_nprocs) {
+ /* Do not send the res status to yourself */
+ if(iproc == dev->mpi_rank) continue;
+
+ mutex_lock(dev->mpi_mutex);
+ MPI(Send(&status, 1, MPI_INT32_T, iproc, MPI_SDIS_MSG_RES_T,
+ MPI_COMM_WORLD));
+ mutex_unlock(dev->mpi_mutex);
+ }
+
+ /* Receive the res status of all other processes */
+ res = proc_res;
+ FOR_EACH(iproc, 0, dev->mpi_nprocs) {
+ MPI_Request req;
+
+ /* Do not receive the res status from yourself */
+ if(iproc == dev->mpi_rank) continue;
+
+ mutex_lock(dev->mpi_mutex);
+ MPI(Irecv(&status, 1, MPI_INT32_T, iproc, MPI_SDIS_MSG_RES_T,
+ MPI_COMM_WORLD, &req));
+ mutex_unlock(dev->mpi_mutex);
+ mpi_waiting_for_request(dev, &req);
+
+ if(res == RES_OK && status != RES_OK) {
+ res = (res_T)status;
+ }
+ }
+
+ return res;
+}
+
+#endif
+
+void
+print_progress
+ (struct sdis_device* dev,
+ int32_t progress[],
+ const char* label)
+{
+ ASSERT(dev && label);
+#ifndef SDIS_ENABLE_MPI
+ log_info(dev, "%s%3d%%\r", label, progress[0]);
+#else
+ if(!dev->use_mpi) {
+ log_info(dev, "%s%3d%%\r", label, progress[0]);
+ } else {
+ int i;
+ if(dev->mpi_rank != 0) return;
+ mpi_fetch_progress(dev, progress);
+ FOR_EACH(i, 0, dev->mpi_nprocs) {
+ log_info(dev, "Process %d -- %s%3d%%%c",
+ i, label, progress[i], i == dev->mpi_nprocs - 1 ? '\r' : '\n');
+ }
+ }
+#endif
+}
+
+void
+print_progress_update
+ (struct sdis_device* dev,
+ int32_t progress[],
+ const char* label)
+{
+ ASSERT(dev);
+#ifndef SDIS_ENABLE_MPI
+ print_progress(dev, progress, label);
+#else
+ if(!dev->use_mpi) {
+ print_progress(dev, progress, label);
+ } else {
+ if(dev->mpi_rank != 0) {
+ mpi_send_progress(dev, progress[0]);
+ } else {
+ mpi_fetch_progress(dev, progress);
+ rewind_progress_printing(dev);
+ print_progress(dev, progress, label);
+ }
+ }
+#endif
+}
+
+void
+process_barrier(struct sdis_device* dev)
+{
+#ifndef SDIS_ENABLE_MPI
+ (void)dev;
+ return;
+#else
+ if(dev->use_mpi) {
+ mpi_barrier(dev);
+ }
+#endif
+}
diff --git a/src/sdis.h b/src/sdis.h
@@ -1,4 +1,4 @@
-/* Copyright (C) 2016-2021 |Meso|Star> (contact@meso-star.com)
+/* Copyright (C) 2016-2022 |Meso|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
@@ -16,6 +16,8 @@
#ifndef SDIS_H
#define SDIS_H
+#include <star/ssp.h>
+
#include <rsys/rsys.h>
#include <float.h>
@@ -50,7 +52,6 @@ struct logger;
struct mem_allocator;
struct senc2d_scene;
struct senc3d_scene;
-struct ssp_rng;
/* Forward declaration of the Stardis opaque data types. These data types are
* ref counted. Once created the caller implicitly owns the created data, i.e.
@@ -130,6 +131,31 @@ struct sdis_mc {
#define SDIS_MC_NULL__ {0, 0, 0}
static const struct sdis_mc SDIS_MC_NULL = SDIS_MC_NULL__;
+/* Input arguments of the sdis_device_create function */
+struct sdis_device_create_args {
+ struct logger* logger; /* NULL <=> default logger */
+ struct mem_allocator* allocator; /* NULL <=> default allocator */
+ unsigned nthreads_hint; /* Hint on the number of threads to use */
+ int verbosity; /* Verbosity level */
+
+ /* Use the Message Passing Interface to distribute work between processes.
+ * This option is taken into account only if Stardis-Solver is compiled with
+ * MPI support */
+ int use_mpi;
+};
+#define SDIS_DEVICE_CREATE_ARGS_DEFAULT__ { \
+ NULL, NULL, SDIS_NTHREADS_DEFAULT, 1, 0 \
+}
+static const struct sdis_device_create_args SDIS_DEVICE_CREATE_ARGS_DEFAULT =
+ SDIS_DEVICE_CREATE_ARGS_DEFAULT__;
+
+/* Informations on the Stardis-Solver library */
+struct sdis_info {
+ int mpi_enabled; /* Define if Stardis-Solver was built with MPI support */
+};
+#define SDIS_INFO_NULL__ {0}
+static const struct sdis_info SDIS_INFO_NULL = SDIS_INFO_NULL__;
+
/*******************************************************************************
* Data type used to describe physical properties
******************************************************************************/
@@ -159,7 +185,7 @@ struct sdis_solid_shader {
sdis_medium_getter_T calorific_capacity; /* In J.K^-1.kg^-1 */
sdis_medium_getter_T thermal_conductivity; /* In W.m^-1.K^-1 */
sdis_medium_getter_T volumic_mass; /* In kg.m^-3 */
- sdis_medium_getter_T delta_solid;
+ sdis_medium_getter_T delta;
/* May be NULL if there is no volumic power. One can also return
* SDIS_VOLUMIC_POWER_NONE to define that there is no volumic power at the
@@ -207,8 +233,11 @@ struct sdis_interface_side_shader {
* interface or if the emissivity is 0 onto the whole interface. */
sdis_interface_getter_T emissivity; /* Overall emissivity. */
sdis_interface_getter_T specular_fraction; /* Specular part in [0,1] */
+
+ /* Reference temperature used in Picard 1 */
+ sdis_interface_getter_T reference_temperature;
};
-#define SDIS_INTERFACE_SIDE_SHADER_NULL__ { NULL, NULL, NULL, NULL }
+#define SDIS_INTERFACE_SIDE_SHADER_NULL__ { NULL, NULL, NULL, NULL, NULL }
static const struct sdis_interface_side_shader SDIS_INTERFACE_SIDE_SHADER_NULL =
SDIS_INTERFACE_SIDE_SHADER_NULL__;
@@ -256,8 +285,9 @@ struct sdis_heat_vertex {
double time;
double weight;
enum sdis_heat_vertex_type type;
+ int branch_id;
};
-#define SDIS_HEAT_VERTEX_NULL__ {{0,0,0}, 0, 0, SDIS_HEAT_VERTEX_CONDUCTION}
+#define SDIS_HEAT_VERTEX_NULL__ {{0,0,0}, 0, 0, SDIS_HEAT_VERTEX_CONDUCTION, 0}
static const struct sdis_heat_vertex SDIS_HEAT_VERTEX_NULL =
SDIS_HEAT_VERTEX_NULL__;
@@ -357,20 +387,31 @@ typedef void
double pos[], /* Output list of vertex coordinates */
void* ctx);
+struct sdis_ambient_radiative_temperature {
+ double temperature; /* In Kelvin */
+ double reference; /* Used to linearise the radiative transfer */
+};
+#define SDIS_AMBIENT_RADIATIVE_TEMPERATURE_NULL__ {-1, -1}
+static const struct sdis_ambient_radiative_temperature
+SDIS_AMBIENT_RADIATIVE_TEMPERATURE_NULL =
+ SDIS_AMBIENT_RADIATIVE_TEMPERATURE_NULL__;
+
struct sdis_scene_create_args {
/* Functors to retrieve the geometric description */
sdis_get_primitive_indices_T get_indices;
sdis_get_primitive_interface_T get_interface;
sdis_get_vertex_position_T get_position;
- /* Pointer toward client side sent as the last argument of the callbacks */
+ /* Pointer toward client side sent as the last argument of the callbacks */
void* context;
size_t nprimitives; /* #primitives, i.e. #segments or #triangles */
size_t nvertices; /* #vertices */
double fp_to_meter; /* Scale factor used to convert 1.0 in 1 meter */
- double trad; /* Ambiant radiative temperature */
- double tref; /* Temperature used to linearize the radiative temperature */
+ struct sdis_ambient_radiative_temperature trad; /* Ambient radiative temp */
+
+ /* Min/max temperature used to linearise the radiative temperature */
+ double t_range[2];
};
#define SDIS_SCENE_CREATE_ARGS_DEFAULT__ { \
@@ -381,8 +422,8 @@ struct sdis_scene_create_args {
0, /* #primitives */ \
0, /* #vertices */ \
1.0, /* #Floating point to meter scale factor */ \
- -1.0, /* Ambient radiative temperature */ \
- -1.0 /* Reference temperature */ \
+ SDIS_AMBIENT_RADIATIVE_TEMPERATURE_NULL__,/* Ambient radiative temperature */\
+ {0.0, -1.0} /* Temperature range */ \
}
static const struct sdis_scene_create_args SDIS_SCENE_CREATE_ARGS_DEFAULT =
SDIS_SCENE_CREATE_ARGS_DEFAULT__;
@@ -394,15 +435,24 @@ struct sdis_solve_probe_args {
size_t nrealisations; /* #realisations */
double position[3]; /* Probe position */
double time_range[2]; /* Observation time */
+
+ /* Set the Picard recursion order to estimate the radiative temperature. An
+ * order of one means that the radiative temperature is linearized, while
+ * higher orders allow the estimation of the T4 radiative transfer. */
+ size_t picard_order;
+
int register_paths; /* Combination of enum sdis_heat_path_flag */
struct ssp_rng* rng_state; /* Initial RNG state. May be NULL */
+ enum ssp_rng_type rng_type; /* RNG type to use if `rng_state' is NULL */
};
#define SDIS_SOLVE_PROBE_ARGS_DEFAULT__ { \
10000, /* #realisations */ \
{0,0,0}, /* Position */ \
{DBL_MAX,DBL_MAX}, /* Time range */ \
+ 1, /* Picard order */ \
SDIS_HEAT_PATH_NONE, /* Register paths mask */ \
- NULL /* RNG state */ \
+ NULL, /* RNG state */ \
+ SSP_RNG_THREEFRY /* RNG type */ \
}
static const struct sdis_solve_probe_args SDIS_SOLVE_PROBE_ARGS_DEFAULT =
SDIS_SOLVE_PROBE_ARGS_DEFAULT__;
@@ -413,18 +463,27 @@ struct sdis_solve_probe_boundary_args {
size_t iprim; /* Identifier of the primitive on which the probe lies */
double uv[2]; /* Parametric coordinates of the probe onto the primitve */
double time_range[2]; /* Observation time */
+
+ /* Set the Picard recursion order to estimate the radiative temperature. An
+ * order of one means that the radiative temperature is linearized, while
+ * higher orders allow the estimation of the T4 radiative transfer. */
+ size_t picard_order;
+
enum sdis_side side; /* Side of iprim on which the probe lies */
int register_paths; /* Combination of enum sdis_heat_path_flag */
struct ssp_rng* rng_state; /* Initial RNG state. May be NULL */
+ enum ssp_rng_type rng_type; /* RNG type to use if `rng_state' is NULL */
};
#define SDIS_SOLVE_PROBE_BOUNDARY_ARGS_DEFAULT__ { \
10000, /* #realisations */ \
0, /* Primitive identifier */ \
{0,0}, /* UV */ \
{DBL_MAX,DBL_MAX}, /* Time range */ \
+ 1, /* Picard order */ \
SDIS_SIDE_NULL__, \
SDIS_HEAT_PATH_NONE, \
- NULL /* RNG state */ \
+ NULL, /* RNG state */ \
+ SSP_RNG_THREEFRY /* RNG type */ \
}
static const struct sdis_solve_probe_boundary_args
SDIS_SOLVE_PROBE_BOUNDARY_ARGS_DEFAULT =
@@ -436,8 +495,15 @@ struct sdis_solve_boundary_args {
const enum sdis_side* sides; /* Per primitive side to consider */
size_t nprimitives; /* #primitives */
double time_range[2]; /* Observation time */
+
+ /* Set the Picard recursion order to estimate the radiative temperature. An
+ * order of one means that the radiative temperature is linearized, while
+ * higher orders allow the estimation of the T4 radiative transfer. */
+ size_t picard_order;
+
int register_paths; /* Combination of enum sdis_heat_path_flag */
struct ssp_rng* rng_state; /* Initial RNG state. May be NULL */
+ enum ssp_rng_type rng_type; /* RNG type to use if `rng_state' is NULL */
};
#define SDIS_SOLVE_BOUNDARY_ARGS_DEFAULT__ { \
10000, /* #realisations */ \
@@ -445,8 +511,10 @@ struct sdis_solve_boundary_args {
NULL, /* Per primitive side */ \
0, /* #primitives */ \
{DBL_MAX,DBL_MAX}, /* Time range */ \
+ 1, /* Picard order */ \
SDIS_HEAT_PATH_NONE, \
- NULL /* RNG state */ \
+ NULL, /* RNG state */ \
+ SSP_RNG_THREEFRY /* RNG type */ \
}
static const struct sdis_solve_boundary_args SDIS_SOLVE_BOUNDARY_ARGS_DEFAULT =
SDIS_SOLVE_BOUNDARY_ARGS_DEFAULT__;
@@ -455,15 +523,24 @@ struct sdis_solve_medium_args {
size_t nrealisations; /* #realisations */
struct sdis_medium* medium; /* Medium to solve */
double time_range[2]; /* Observation time */
+
+ /* Set the Picard recursion order to estimate the radiative temperature. An
+ * order of one means that the radiative temperature is linearized, while
+ * higher orders allow the estimation of the T4 radiative transfer. */
+ size_t picard_order;
+
int register_paths; /* Combination of enum sdis_heat_path_flag */
struct ssp_rng* rng_state; /* Initial RNG state. May be NULL */
+ enum ssp_rng_type rng_type; /* RNG type to use if `rng_state' is NULL */
};
#define SDIS_SOLVE_MEDIUM_ARGS_DEFAULT__ { \
10000, /* #realisations */ \
NULL, /* Medium */ \
{DBL_MAX,DBL_MAX}, /* Time range */ \
+ 1, /* Picard order */ \
SDIS_HEAT_PATH_NONE, \
- NULL /* RNG state */ \
+ NULL, /* RNG state */ \
+ SSP_RNG_THREEFRY /* RNG type */ \
}
static const struct sdis_solve_medium_args SDIS_SOLVE_MEDIUM_ARGS_DEFAULT =
SDIS_SOLVE_MEDIUM_ARGS_DEFAULT__;
@@ -473,14 +550,23 @@ struct sdis_solve_probe_boundary_flux_args {
size_t iprim; /* Identifier of the primitive on which the probe lies */
double uv[2]; /* Parametric coordinates of the probe onto the primitve */
double time_range[2]; /* Observation time */
+
+ /* Set the Picard recursion order to estimate the radiative temperature. An
+ * order of one means that the radiative temperature is linearized, while
+ * higher orders allow the estimation of the T4 radiative transfer. */
+ size_t picard_order;
+
struct ssp_rng* rng_state; /* Initial RNG state. May be NULL */
+ enum ssp_rng_type rng_type; /* RNG type to use if `rng_state' is NULL */
};
#define SDIS_SOLVE_PROBE_BOUNDARY_FLUX_ARGS_DEFAULT__ { \
10000, /* #realisations */ \
0, /* Primitive identifier */ \
{0,0}, /* UV */ \
{DBL_MAX,DBL_MAX}, /* Time range */ \
- NULL /* RNG state */ \
+ 1, /* Picard order */ \
+ NULL, /* RNG state */ \
+ SSP_RNG_THREEFRY /* RNG type */ \
}
static const struct sdis_solve_probe_boundary_flux_args
SDIS_SOLVE_PROBE_BOUNDARY_FLUX_ARGS_DEFAULT =
@@ -491,14 +577,23 @@ struct sdis_solve_boundary_flux_args {
const size_t* primitives; /* List of boundary primitives to handle */
size_t nprimitives; /* #primitives */
double time_range[2]; /* Observation time */
+
+ /* Set the Picard recursion order to estimate the radiative temperature. An
+ * order of one means that the radiative temperature is linearized, while
+ * higher orders allow the estimation of the T4 radiative transfer. */
+ size_t picard_order;
+
struct ssp_rng* rng_state; /* Initial RNG state. May be NULL */
+ enum ssp_rng_type rng_type; /* RNG type to use if `rng_state' is NULL */
};
#define SDIS_SOLVE_BOUNDARY_FLUX_ARGS_DEFAULT__ { \
10000, /* #realisations */ \
NULL, /* List or primitive ids */ \
0, /* #primitives */ \
{DBL_MAX,DBL_MAX}, /* Time range */ \
- NULL /* RNG state */ \
+ 1, /* Picard order */ \
+ NULL, /* RNG state */ \
+ SSP_RNG_THREEFRY /* RNG type */ \
}
static const struct sdis_solve_boundary_flux_args
SDIS_SOLVE_BOUNDARY_FLUX_ARGS_DEFAULT =
@@ -507,16 +602,28 @@ SDIS_SOLVE_BOUNDARY_FLUX_ARGS_DEFAULT =
struct sdis_solve_camera_args {
struct sdis_camera* cam; /* Point of view */
double time_range[2]; /* Observation time */
- size_t image_resolution[2]; /* Image resolution */
+
+ /* Set the Picard recursion order to estimate the radiative temperature. An
+ * order of one means that the radiative temperature is linearized, while
+ * higher orders allow the estimation of the T4 radiative transfer. */
+ size_t picard_order;
+
+ size_t image_definition[2]; /* Image definition */
size_t spp; /* #samples per pixel */
int register_paths; /* Combination of enum sdis_heat_path_flag */
+
+ struct ssp_rng* rng_state; /* Initial RNG state. May be NULL */
+ enum ssp_rng_type rng_type; /* RNG type to use */
};
#define SDIS_SOLVE_CAMERA_ARGS_DEFAULT__ { \
NULL, /* Camera */ \
{DBL_MAX,DBL_MAX}, /* Time range */ \
+ 1, /* Picard order */ \
{512,512}, /* Image resolution */ \
256, /* #realisations per pixel */ \
- SDIS_HEAT_PATH_NONE \
+ SDIS_HEAT_PATH_NONE, \
+ NULL, /* RNG state */ \
+ SSP_RNG_THREEFRY /* RNG type */ \
}
static const struct sdis_solve_camera_args SDIS_SOLVE_CAMERA_ARGS_DEFAULT =
SDIS_SOLVE_CAMERA_ARGS_DEFAULT__;
@@ -526,12 +633,14 @@ struct sdis_compute_power_args {
struct sdis_medium* medium; /* Medium to solve */
double time_range[2]; /* Observation time */
struct ssp_rng* rng_state; /* Initial RNG state. May be NULL */
+ enum ssp_rng_type rng_type; /* RNG type to use if `rng_state' is NULL */
};
#define SDIS_COMPUTE_POWER_ARGS_DEFAULT__ { \
10000, /* #realisations */ \
NULL, /* Medium */ \
{DBL_MAX,DBL_MAX}, /* Time range */ \
- NULL /* RNG state */ \
+ NULL, /* RNG state */ \
+ SSP_RNG_THREEFRY /* RNG type */ \
}
static const struct sdis_compute_power_args
SDIS_COMPUTE_POWER_ARGS_DEFAULT = SDIS_COMPUTE_POWER_ARGS_DEFAULT__;
@@ -544,10 +653,7 @@ BEGIN_DECLS
******************************************************************************/
SDIS_API res_T
sdis_device_create
- (struct logger* logger, /* May be NULL <=> use default logger */
- struct mem_allocator* allocator, /* May be NULL <=> use default allocator */
- const unsigned nthreads_hint, /* Hint on the number of threads to use */
- const int verbose, /* Verbosity level */
+ (const struct sdis_device_create_args* args,
struct sdis_device** dev);
SDIS_API res_T
@@ -558,6 +664,11 @@ SDIS_API res_T
sdis_device_ref_put
(struct sdis_device* dev);
+SDIS_API res_T
+sdis_device_get_mpi_rank
+ (struct sdis_device* dev,
+ int* rank);
+
/*******************************************************************************
* A data stores in the Stardis memory space a set of user defined data. It can
* be seen as a ref counted memory space allocated by Stardis. It is used to
@@ -826,27 +937,27 @@ sdis_scene_set_fp_to_meter
SDIS_API res_T
sdis_scene_get_ambient_radiative_temperature
(const struct sdis_scene* scn,
- double* trad);
+ struct sdis_ambient_radiative_temperature* trad);
/* Set scene's ambient radiative temperature. If set negative, any sample
* ending in ambient radiative temperature will fail */
SDIS_API res_T
sdis_scene_set_ambient_radiative_temperature
(struct sdis_scene* scn,
- const double trad);
+ const struct sdis_ambient_radiative_temperature* trad);
-/* Get scene's reference temperature */
+/* Get scene's minimum/maximum temperature */
SDIS_API res_T
-sdis_scene_get_reference_temperature
+sdis_scene_get_temperature_range
(const struct sdis_scene* scn,
- double* tref);
+ double t_range[2]);
-/* Set scene's reference temperature. If set to 0, there is no radiative
- * transfert in the whole system */
+/* Set scene's minimum/maximum temperature. Must be correctly defined if there
+ * is any radiative transfer in the scene */
SDIS_API res_T
-sdis_scene_set_reference_temperature
+sdis_scene_set_temperature_range
(struct sdis_scene* scn,
- const double tref);
+ const double t_range[2]);
/* Search the point onto the scene geometry that is the closest of `pos'. The
* `radius' parameter controls the maximum search distance around `pos'. The
@@ -1130,24 +1241,32 @@ sdis_green_path_for_each_flux_term
* Heat path API
******************************************************************************/
SDIS_API res_T
-sdis_heat_path_get_vertices_count
+sdis_heat_path_get_status
(const struct sdis_heat_path* path,
- size_t* nvertices);
+ enum sdis_heat_path_flag* status);
SDIS_API res_T
-sdis_heat_path_get_status
+sdis_heat_path_get_line_strips_count
(const struct sdis_heat_path* path,
- enum sdis_heat_path_flag* status);
+ size_t* nstrips);
+
+SDIS_API res_T
+sdis_heat_path_line_strip_get_vertices_count
+ (const struct sdis_heat_path* path,
+ const size_t istrip,
+ size_t* nvertices);
SDIS_API res_T
-sdis_heat_path_get_vertex
+sdis_heat_path_line_strip_get_vertex
(const struct sdis_heat_path* path,
- const size_t ivertex,
+ const size_t istrip,
+ const size_t ivert,
struct sdis_heat_vertex* vertex);
SDIS_API res_T
-sdis_heat_path_for_each_vertex
+sdis_heat_path_line_strip_for_each_vertex
(const struct sdis_heat_path* path,
+ const size_t istrip,
sdis_process_heat_vertex_T func,
void* context);
@@ -1245,6 +1364,13 @@ sdis_solve_medium_green_function
const struct sdis_solve_medium_args* args,
struct sdis_green_function** green);
+/*******************************************************************************
+ * Retrieve infos from the Stardis-Solver library
+ ******************************************************************************/
+SDIS_API res_T
+sdis_get_info
+ (struct sdis_info* info);
+
END_DECLS
#endif /* SDIS_H */
diff --git a/src/sdis_Xd_begin.h b/src/sdis_Xd_begin.h
@@ -1,4 +1,4 @@
-/* Copyright (C) 2016-2021 |Meso|Star> (contact@meso-star.com)
+/* Copyright (C) 2016-2022 |Meso|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
@@ -25,17 +25,52 @@ struct sdis_heat_path;
struct rwalk_context {
struct green_path_handle* green_path;
struct sdis_heat_path* heat_path;
- double Tarad; /* Ambient radiative temperature */
- double Tref3; /* Reference temperature ^ 3 */
+
+ double Tmin; /* Lower bound temperature */
+ double Tmin2; /* Tmin^2 */
+ double Tmin3; /* Tmin^3 */
+
+ double That; /* Upper bound temperature */
+ double That2; /* That^2 */
+ double That3; /* That^3 */
+
+ /* Maximum branchings i.e. the maximum number of times
+ * XD(compute_temperature) can be called. It controls the number of
+ * ramifications of the heat path and currently is correlated to the Picard
+ * order used to estimate the radiative temperature. max_branchings ==
+ * picard_order-1 */
+ size_t max_branchings;
+
+ /* Number of heat path branchings */
+ size_t nbranchings;
};
-#define RWALK_CONTEXT_NULL__ {NULL, NULL, 0, 0}
+#define RWALK_CONTEXT_NULL__ { \
+ NULL, /* Green path */ \
+ NULL, /* Heat path */ \
+ 0, /* Tmin */ \
+ 0, /* Tmin^2 */ \
+ 0, /* Tmin^3 */ \
+ 0, /* That */ \
+ 0, /* That^2 */ \
+ 0, /* That^3 */ \
+ 0, /* Max #branchings */ \
+ SIZE_MAX, /* #branchings */ \
+}
static const struct rwalk_context RWALK_CONTEXT_NULL = RWALK_CONTEXT_NULL__;
+static INLINE size_t
+get_picard_order(const struct rwalk_context* ctx)
+{
+ ASSERT(ctx);
+ return ctx->max_branchings + 1;
+}
+
#endif /* SDIS_XD_BEGIN_H */
#ifdef SDIS_XD_BEGIN_H__
#error "This header is already included without its associated sdis_Xd_end.h file."
#endif
+
#define SDIS_XD_BEGIN_H__
/* Check prerequisite */
@@ -105,7 +140,7 @@ static const struct XD(rwalk) XD(RWALK_NULL) = {
struct XD(temperature) {
res_T (*func)/* Next function to invoke in order to compute the temperature */
(struct sdis_scene* scn,
- const struct rwalk_context* ctx,
+ struct rwalk_context* ctx,
struct XD(rwalk)* rwalk,
struct ssp_rng* rng,
struct XD(temperature)* temp);
diff --git a/src/sdis_Xd_end.h b/src/sdis_Xd_end.h
@@ -1,4 +1,4 @@
-/* Copyright (C) 2016-2021 |Meso|Star> (contact@meso-star.com)
+/* Copyright (C) 2016-2022 |Meso|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
diff --git a/src/sdis_c.h b/src/sdis_c.h
@@ -0,0 +1,158 @@
+/* Copyright (C) 2016-2022 |Meso|Star> (contact@meso-star.com)
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+#ifndef SDIS_C_H
+#define SDIS_C_H
+
+#include <star/ssp.h>
+#include <rsys/rsys.h>
+
+/* Id of the messages sent between processes */
+enum mpi_sdis_message {
+ MPI_SDIS_MSG_ACCUM_TEMP, /* Temperature accumulator */
+ MPI_SDIS_MSG_ACCUM_TIME, /* Time accumulator */
+ MPI_SDIS_MSG_ACCUM_FLUX_CONVECTIVE, /* Convective flux accumulator */
+ MPI_SDIS_MSG_ACCUM_FLUX_IMPOSED, /* Imposed flux accumulator */
+ MPI_SDIS_MSG_ACCUM_FLUX_RADIATIVE, /* Radiative flux accumulator */
+ MPI_SDIS_MSG_ACCUM_FLUX_TOTAL, /* Total flux accumulator */
+ MPI_SDIS_MSG_ACCUM_MEAN_POWER, /* Mean power accumulator */
+ MPI_SDIS_MSG_GREEN_FUNCTION, /* Serialized green function */
+ MPI_SDIS_MSG_PROGRESS, /* Progress status */
+ MPI_SDIS_MSG_RES_T, /* Result status */
+ MPI_SDIS_MSG_RNG_PROXY_SEQUENCE_ID, /* Index of the current RNG sequence */
+ MPI_SDIS_MSG_TILE, /* 2D Tile of row ordered accumulators */
+ MPI_SDIS_MSG_COUNT__
+};
+
+/* Forward declarations */
+struct accum;
+struct sdis_device;
+struct sdis_estimator;
+struct sdis_green_function;
+struct sdis_scene;
+struct ssp_rng;
+struct ssp_rng_proxy;
+
+extern LOCAL_SYM res_T
+create_per_thread_rng
+ (struct sdis_device* dev,
+ struct ssp_rng* rng_state, /* May be NULL */
+ const enum ssp_rng_type rng_type, /* RNG type when `rng_state' is NULL */
+ struct ssp_rng_proxy** rng_proxy,
+ struct ssp_rng** rngs[]);
+
+extern LOCAL_SYM void
+release_per_thread_rng
+ (struct sdis_device* dev,
+ struct ssp_rng* rngs[]);
+
+extern LOCAL_SYM res_T
+create_per_thread_green_function
+ (struct sdis_scene* scene,
+ struct sdis_green_function** greens[]);
+
+extern LOCAL_SYM void
+release_per_thread_green_function
+ (struct sdis_scene* scn,
+ struct sdis_green_function* greens[]);
+
+/* Allocate the progress status list for the current process. Without MPI, the
+ * length of the progress list is 1. With MPI, the length is also 1 except for
+ * the master process for which the length of the list is equal to the number
+ * of MPI processes. For this process the list will be used to gather the
+ * progress status of the other processes. */
+extern LOCAL_SYM res_T
+alloc_process_progress
+ (struct sdis_device* dev,
+ int32_t* progress[]);
+
+extern LOCAL_SYM void
+free_process_progress
+ (struct sdis_device* dev,
+ int32_t progress[]);
+
+/* Compute the number of realisations for the current process */
+extern LOCAL_SYM size_t
+compute_process_realisations_count
+ (const struct sdis_device* dev,
+ const size_t overall_realisations_count);
+
+/* Gather the accumulators and sum them in acc. With MPI, non master processes
+ * store in acc the gathering of their per thread accumulators that are sent to
+ * the master process. The master process gathers the per thread accumulators
+ * and the per process ones and save the result in acc */
+extern LOCAL_SYM res_T
+gather_accumulators
+ (struct sdis_device* dev,
+ const enum mpi_sdis_message msg,
+ const struct accum* per_thread_acc,
+ struct accum* acc);
+
+/* Gather the green functions. With MPI, non master processes store in green
+ * the gathering of their per thread green functions and sent the result to the
+ * master process. The master process gathers both per thread green functions
+ * and per process ones and finally save the result in green */
+extern LOCAL_SYM res_T
+gather_green_functions
+ (struct sdis_scene* scn,
+ struct ssp_rng_proxy* proxy,
+ struct sdis_green_function* per_thread_green[],
+ const struct accum* acc_time,
+ struct sdis_green_function** green);
+
+/* Gather the sequence IDs of the proxy RNGs. Without MPI, nothing happens.
+ * With MPI, non-master processes send the sequence ID of their proxy RNG to
+ * the master process. The master process updates its proxy RNG to ensure that
+ * its state is greater than the state of all other proxies, that is, its
+ * sequence ID is greater than the sequence IDs received. */
+extern LOCAL_SYM res_T
+gather_rng_proxy_sequence_id
+ (struct sdis_device* dev,
+ struct ssp_rng_proxy* proxy);
+
+/* Gather `res' from all other processes. Without MPI, the function simply
+ * returns `res'. With MPI, each process sends `res' to the other processes and
+ * retrieves the `res' sent by the other processes. The function then returns
+ * RES_OK if all the results collected are RES_OK. Otherwise, it returns the
+ * first error received. */
+extern LOCAL_SYM res_T
+gather_res_T
+ (struct sdis_device* dev,
+ const res_T res);
+
+/* Print the progress status. With MPI, the master process print the progress
+ * of all processes stored in the progress list. Non master processes do not
+ * print anything */
+extern LOCAL_SYM void
+print_progress
+ (struct sdis_device* dev,
+ int32_t progress[],
+ const char* label); /* Text preceding the progress status */
+
+/* Update the printed progress status, i.e. rewind the printing and print the
+ * new status */
+extern LOCAL_SYM void
+print_progress_update
+ (struct sdis_device* dev,
+ int32_t progress[],
+ const char* label); /* Text preceding the progress status */
+
+/* Waiting for all processes. Without MPI this function does nothing. With MPI
+ * it waits for MPI process synchronisation */
+extern LOCAL_SYM void
+process_barrier
+ (struct sdis_device* dev);
+
+#endif /* SDIS_C_H */
diff --git a/src/sdis_camera.c b/src/sdis_camera.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 2016-2021 |Meso|Star> (contact@meso-star.com)
+/* Copyright (C) 2016-2022 |Meso|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
diff --git a/src/sdis_camera.h b/src/sdis_camera.h
@@ -1,4 +1,4 @@
-/* Copyright (C) 2016-2021 |Meso|Star> (contact@meso-star.com)
+/* Copyright (C) 2016-2022 |Meso|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
diff --git a/src/sdis_data.c b/src/sdis_data.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 2016-2021 |Meso|Star> (contact@meso-star.com)
+/* Copyright (C) 2016-2022 |Meso|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
diff --git a/src/sdis_device.c b/src/sdis_device.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 2016-2021 |Meso|Star> (contact@meso-star.com)
+/* Copyright (C) 2016-2022 |Meso|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
@@ -20,6 +20,7 @@
#include <rsys/cstr.h>
#include <rsys/logger.h>
#include <rsys/mem_allocator.h>
+#include <rsys/mutex.h>
#include <star/s2d.h>
#include <star/s3d.h>
@@ -27,9 +28,249 @@
#include <omp.h>
+#ifdef SDIS_ENABLE_MPI
+ #include <mpi.h>
+#endif
+
/*******************************************************************************
* Helper functions
******************************************************************************/
+#ifdef SDIS_ENABLE_MPI
+
+static const char*
+mpi_error_string(struct sdis_device* dev, const int mpi_err)
+{
+ int res_mpi = MPI_SUCCESS;
+ int len;
+ ASSERT(dev);
+
+ res_mpi = MPI_Error_string(mpi_err, str_get(&dev->mpi_err_str), &len);
+ return res_mpi == MPI_SUCCESS
+ ? str_get(&dev->mpi_err_str) : "Invalid MPI error";
+}
+
+static const char*
+mpi_thread_support_string(const int val)
+{
+ switch(val) {
+ case MPI_THREAD_SINGLE: return "MPI_THREAD_SINGLE";
+ case MPI_THREAD_FUNNELED: return "MPI_THREAD_FUNNELED";
+ case MPI_THREAD_SERIALIZED: return "MPI_THREAD_SERIALIZED";
+ case MPI_THREAD_MULTIPLE: return "MPI_THREAD_MULTIPLE";
+ default: FATAL("Unreachable code.\n"); break;
+ }
+}
+
+static res_T
+mpi_print_proc_info(struct sdis_device* dev)
+{
+ char proc_name[MPI_MAX_PROCESSOR_NAME];
+ int proc_name_len;
+ char* proc_names = NULL;
+ uint32_t* proc_nthreads = NULL;
+ uint32_t nthreads = 0;
+ int iproc;
+ res_T res = RES_OK;
+ ASSERT(dev);
+
+ /* On process 0, allocate the arrays to stored gathered data */
+ if(dev->mpi_rank == 0) {
+
+ /* Allocate the array to store the per process name */
+ proc_names = MEM_CALLOC(dev->allocator, (size_t)dev->mpi_nprocs,
+ MPI_MAX_PROCESSOR_NAME*sizeof(*proc_names));
+ if(!proc_names) {
+ res = RES_MEM_ERR;
+ log_err(dev,
+ "Could not allocate the temporary memory for MPI process names -- "
+ "%s.\n", res_to_cstr(res));
+ goto error;
+ }
+
+ /* Allocate the array to store the per process #threads */
+ proc_nthreads = MEM_CALLOC(dev->allocator, (size_t)dev->mpi_nprocs,
+ sizeof(*proc_nthreads));
+ if(!proc_nthreads) {
+ res = RES_MEM_ERR;
+ log_err(dev,
+ "Could not allocate the temporary memory for the #threads of the MPI "
+ "processes -- %s.\n", res_to_cstr(res));
+ goto error;
+ }
+ }
+
+ /* Gather the process name to the process 0 */
+ MPI(Get_processor_name(proc_name, &proc_name_len));
+ MPI(Gather(proc_name, MPI_MAX_PROCESSOR_NAME, MPI_CHAR, proc_names,
+ MPI_MAX_PROCESSOR_NAME, MPI_CHAR, 0, MPI_COMM_WORLD));
+
+ /* Gather the #threads to process 0*/
+ nthreads = (uint32_t)dev->nthreads;
+ MPI(Gather(&nthreads, 1, MPI_UINT32_T, proc_nthreads, 1, MPI_UINT32_T, 0,
+ MPI_COMM_WORLD));
+
+ if(dev->mpi_rank == 0) {
+ FOR_EACH(iproc, 0, dev->mpi_nprocs) {
+ log_info(dev, "Process %d -- %s; #threads: %u\n",
+ iproc, proc_names + iproc*MPI_MAX_PROCESSOR_NAME, proc_nthreads[iproc]);
+ }
+ }
+
+exit:
+ if(proc_names) MEM_RM(dev->allocator, proc_names);
+ if(proc_nthreads) MEM_RM(dev->allocator, proc_nthreads);
+ return res;
+error:
+ goto exit;
+}
+
+static res_T
+mpi_init(struct sdis_device* dev)
+{
+ int res_mpi = MPI_SUCCESS;
+ int is_init = 0;
+ int thread_support = 0;
+ res_T res = RES_OK;
+ ASSERT(dev);
+
+ #define CALL_MPI(Func, ErrMsg) { \
+ res_mpi = MPI_##Func; \
+ if(res_mpi != MPI_SUCCESS) { \
+ log_err(dev, ErrMsg" - %s\n", mpi_error_string(dev, res_mpi)); \
+ res = RES_UNKNOWN_ERR; \
+ goto error; \
+ } \
+ } (void)0
+
+ CALL_MPI(Initialized(&is_init),
+ "Error querying the MPI init state");
+
+ if(!is_init) {
+ log_err(dev,
+ "MPI is not initialized. The MPI_Init[_thread] function must be called "
+ "priorly to the creation of the Stardis device.\n");
+ res = RES_BAD_OP;
+ goto error;
+ }
+
+ CALL_MPI(Query_thread(&thread_support),
+ "Error querying the MPI thread support");
+
+ if(thread_support < MPI_THREAD_SERIALIZED) {
+ log_err(dev,
+ "The provided MPI implementation does not support serialized API calls "
+ "from multiple threads. The thread support is limited to %s.\n",
+ mpi_thread_support_string(thread_support));
+ res = RES_BAD_OP;
+ goto error;
+ }
+
+ CALL_MPI(Comm_rank(MPI_COMM_WORLD, &dev->mpi_rank),
+ "Error retrieving the MPI rank");
+ CALL_MPI(Comm_size(MPI_COMM_WORLD, &dev->mpi_nprocs),
+ "Error retrieving the size of the MPI group");
+
+ #undef CALL_MPI
+
+ dev->mpi_mutex = mutex_create();
+ if(!dev->mpi_mutex) {
+ log_err(dev,
+ "Error creating the mutex used to protect the MPI calls.\n");
+ res = RES_MEM_ERR;
+ goto error;
+ }
+
+ mpi_print_proc_info(dev);
+
+exit:
+ return res;
+error:
+ if(dev->mpi_mutex) {
+ mutex_destroy(dev->mpi_mutex);
+ dev->mpi_mutex = NULL;
+ }
+ goto exit;
+}
+
+#endif /* SDIS_ENABLE_MPI */
+
+static INLINE int
+check_sdis_device_create_args(const struct sdis_device_create_args* args)
+{
+ return args && args->nthreads_hint != 0;
+}
+
+static INLINE res_T
+setup_logger
+ (struct sdis_device* dev,
+ const struct sdis_device_create_args* args)
+{
+ ASSERT(dev && args);
+ if(args->logger) {
+ dev->logger = args->logger;
+ } else {
+ setup_log_default(dev);
+ }
+ return RES_OK;
+}
+
+static INLINE res_T
+setup_star2d(struct sdis_device* dev)
+{
+ res_T res = RES_OK;
+ ASSERT(dev);
+ res = s2d_device_create(dev->logger, dev->allocator, 0, &dev->s2d_dev);
+ if(res != RES_OK) {
+ log_err(dev,
+ "Could not create the Star-2D device for Stardis-Solver -- %s.\n",
+ res_to_cstr(res));
+ goto error;
+ }
+exit:
+ return res;
+error:
+ goto exit;
+}
+
+static INLINE res_T
+setup_star3d(struct sdis_device* dev)
+{
+ res_T res = RES_OK;
+ ASSERT(dev);
+ res = s3d_device_create(dev->logger, dev->allocator, 0, &dev->s3d_dev);
+ if(res != RES_OK) {
+ log_err(dev,
+ "Could not create the Star-3D device for Stardis-Solver -- %s.\n",
+ res_to_cstr(res));
+ goto error;
+ }
+exit:
+ return res;
+error:
+ goto exit;
+}
+
+static INLINE res_T
+setup_mpi(struct sdis_device* dev, const struct sdis_device_create_args* args)
+{
+ ASSERT(dev && args);
+#ifdef SDIS_ENABLE_MPI
+ dev->use_mpi = args->use_mpi;
+ if(args->use_mpi) {
+ const res_T res = mpi_init(dev);
+ if(res != RES_OK) return res;
+ }
+#else
+ if(args->use_mpi) {
+ log_warn(dev,
+ "Stardis-Solver is built without the support of the Message Passing "
+ "Interface. MPI cannot be used for parallel computations.\n");
+ }
+#endif
+ return RES_OK;
+
+}
+
static void
device_release(ref_T* ref)
{
@@ -43,6 +284,10 @@ device_release(ref_T* ref)
ASSERT(flist_name_is_empty(&dev->media_names));
flist_name_release(&dev->interfaces_names);
flist_name_release(&dev->media_names);
+#ifdef SDIS_ENABLE_MPI
+ if(dev->mpi_mutex) mutex_destroy(dev->mpi_mutex);
+ str_release(&dev->mpi_err_str);
+#endif
MEM_RM(dev->allocator, dev);
}
@@ -51,29 +296,26 @@ device_release(ref_T* ref)
******************************************************************************/
res_T
sdis_device_create
- (struct logger* logger,
- struct mem_allocator* mem_allocator,
- const unsigned nthreads_hint,
- const int verbose,
+ (const struct sdis_device_create_args* args,
struct sdis_device** out_dev)
{
- struct logger* log = NULL;
struct sdis_device* dev = NULL;
struct mem_allocator* allocator = NULL;
+ unsigned nthreads_max = 0;
res_T res = RES_OK;
- if(nthreads_hint == 0 || !out_dev) {
+ if(!check_sdis_device_create_args(args) || !out_dev) {
res = RES_BAD_ARG;
goto error;
}
- allocator = mem_allocator ? mem_allocator : &mem_default_allocator;
+ allocator = args->allocator ? args->allocator : &mem_default_allocator;
dev = MEM_CALLOC(allocator, 1, sizeof(struct sdis_device));
if(!dev) {
- if(verbose) {
+ if(args->verbosity) {
#define ERR_STR STR(FUNC_NAME)": could not allocate the Stardis device -- %s."
- if(logger) {
- logger_print(logger, LOG_ERROR, ERR_STR, res_to_cstr(res));
+ if(args->logger) {
+ logger_print(args->logger, LOG_ERROR, ERR_STR, res_to_cstr(res));
} else {
fprintf(stderr, MSG_ERROR_PREFIX ERR_STR, res_to_cstr(res));
}
@@ -82,44 +324,34 @@ sdis_device_create
res = RES_MEM_ERR;
goto error;
}
+ nthreads_max = (unsigned)MMAX(omp_get_max_threads(), omp_get_num_procs());
dev->allocator = allocator;
- dev->verbose = verbose;
- dev->nthreads = MMIN(nthreads_hint, (unsigned)omp_get_num_procs());
+ dev->verbose = args->verbosity;
+ dev->nthreads = MMIN(args->nthreads_hint, nthreads_max);
ref_init(&dev->ref);
flist_name_init(allocator, &dev->interfaces_names);
flist_name_init(allocator, &dev->media_names);
+#ifdef SDIS_ENABLE_MPI
+ str_init(allocator, &dev->mpi_err_str);
+#endif
- if(logger) {
- dev->logger = logger;
- } else {
- setup_log_default(dev);
- }
- log_info(dev, "Use %lu %s.\n", (unsigned long)dev->nthreads,
- dev->nthreads == 1 ? "thread" : "threads");
-
- res = s2d_device_create(log, allocator, 0, &dev->s2d_dev);
- if(res != RES_OK) {
- log_err(dev,
- "%s: could not create the Star-2D device on Stardis -- %s.\n",
- FUNC_NAME, res_to_cstr(res));
- }
+ res = setup_logger(dev, args);
+ if(res != RES_OK) goto error;
+ res = setup_star2d(dev);
+ if(res != RES_OK) goto error;
+ res = setup_star3d(dev);
+ if(res != RES_OK) goto error;
+ res = setup_mpi(dev, args);
+ if(res != RES_OK) goto error;
- res = s3d_device_create(log, allocator, 0, &dev->s3d_dev);
- if(res != RES_OK) {
- log_err(dev,
- "%s: could not create the Star-3D device on Stardis -- %s.\n",
- FUNC_NAME, res_to_cstr(res));
- goto error;
- }
+ log_info(dev, "Using %lu %s.\n", (unsigned long)dev->nthreads,
+ dev->nthreads == 1 ? "thread" : "threads");
exit:
if(out_dev) *out_dev = dev;
return res;
error:
- if(dev) {
- SDIS(device_ref_put(dev));
- dev = NULL;
- }
+ if(dev) { SDIS(device_ref_put(dev)); dev = NULL; }
goto exit;
}
@@ -139,6 +371,21 @@ sdis_device_ref_put(struct sdis_device* dev)
return RES_OK;
}
+res_T
+sdis_device_get_mpi_rank(struct sdis_device* dev, int* rank)
+{
+#ifndef SDIS_ENABLE_MPI
+ (void)dev, (void)rank;
+ return RES_BAD_OP;
+#else
+ if(!dev || !rank) return RES_BAD_ARG;
+ if(!dev->use_mpi) return RES_BAD_OP;
+ ASSERT(dev->mpi_rank >= 0);
+ *rank = dev->mpi_rank;
+ return RES_OK;
+#endif
+}
+
/*******************************************************************************
* Local functions
******************************************************************************/
diff --git a/src/sdis_device_c.h b/src/sdis_device_c.h
@@ -1,4 +1,4 @@
-/* Copyright (C) 2016-2021 |Meso|Star> (contact@meso-star.com)
+/* Copyright (C) 2016-2022 |Meso|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
@@ -22,8 +22,18 @@
#include <rsys/free_list.h>
#include <rsys/logger.h>
#include <rsys/ref_count.h>
+#include <rsys/str.h>
+
+#ifdef SDIS_ENABLE_MPI
+ #ifndef NDEBUG
+ #define MPI(Func) ASSERT(MPI_##Func == MPI_SUCCESS)
+ #else
+ #define MPI(Func) MPI_##Func
+ #endif
+#endif
/* Forward declarations */
+struct mutex;
struct ssp_rng;
struct ssp_rng_proxy;
@@ -38,6 +48,15 @@ struct sdis_device {
unsigned nthreads;
int verbose;
+#ifdef SDIS_ENABLE_MPI
+ int mpi_rank; /* Rank of the process in the MPI group */
+ int mpi_nprocs; /* Overall #processes in the MPI group */
+ struct str mpi_err_str; /* String used to store the MPI error string */
+
+ struct mutex* mpi_mutex; /* Protect MPI calls from concurrent threads */
+ int use_mpi;
+#endif
+
struct flist_name interfaces_names;
struct flist_name media_names;
diff --git a/src/sdis_estimator.c b/src/sdis_estimator.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 2016-2021 |Meso|Star> (contact@meso-star.com)
+/* Copyright (C) 2016-2022 |Meso|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
diff --git a/src/sdis_estimator_buffer.c b/src/sdis_estimator_buffer.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 2016-2021 |Meso|Star> (contact@meso-star.com)
+/* Copyright (C) 2016-2022 |Meso|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
@@ -22,7 +22,7 @@
#include <star/ssp.h>
struct sdis_estimator_buffer {
- struct sdis_estimator** estimators; /* Row major per pixe lestimators */
+ struct sdis_estimator** estimators; /* Row major per pixel estimators */
size_t width;
size_t height;
diff --git a/src/sdis_estimator_buffer_c.h b/src/sdis_estimator_buffer_c.h
@@ -1,4 +1,4 @@
-/* Copyright (C) 2016-2021 |Meso|Star> (contact@meso-star.com)
+/* Copyright (C) 2016-2022 |Meso|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
diff --git a/src/sdis_estimator_c.h b/src/sdis_estimator_c.h
@@ -1,4 +1,4 @@
-/* Copyright (C) 2016-2021 |Meso|Star> (contact@meso-star.com)
+/* Copyright (C) 2016-2022 |Meso|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
diff --git a/src/sdis_green.c b/src/sdis_green.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 2016-2021 |Meso|Star> (contact@meso-star.com)
+/* Copyright (C) 2016-2022 |Meso|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
@@ -387,6 +387,8 @@ green_function_solve_path
const size_t ipath,
double* weight)
{
+ struct sdis_ambient_radiative_temperature trad =
+ SDIS_AMBIENT_RADIATIVE_TEMPERATURE_NULL;
const struct power_term* power_terms = NULL;
const struct flux_term* flux_terms = NULL;
const struct green_path* path = NULL;
@@ -443,7 +445,8 @@ green_function_solve_path
break;
case SDIS_GREEN_PATH_END_RADIATIVE:
SDIS(green_function_get_scene(green, &scn));
- SDIS(scene_get_ambient_radiative_temperature(scn, &end_temperature));
+ SDIS(scene_get_ambient_radiative_temperature(scn, &trad));
+ end_temperature = trad.temperature;
if(end_temperature < 0) { /* Cannot be negative if used */
res = RES_BAD_ARG;
goto error;
@@ -1549,6 +1552,15 @@ green_path_set_limit_radiative
}
res_T
+green_path_reset_limit(struct green_path_handle* handle)
+{
+ ASSERT(handle);
+ handle->path->elapsed_time = -INF;
+ handle->path->end_type = SDIS_GREEN_PATH_END_TYPES_COUNT__;
+ return RES_OK;
+}
+
+res_T
green_path_add_power_term
(struct green_path_handle* handle,
struct sdis_medium* mdm,
diff --git a/src/sdis_green.h b/src/sdis_green.h
@@ -1,4 +1,4 @@
-/* Copyright (C) 2016-2021 |Meso|Star> (contact@meso-star.com)
+/* Copyright (C) 2016-2022 |Meso|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
@@ -87,6 +87,10 @@ green_path_set_limit_radiative
const double elapsed_time);
extern LOCAL_SYM res_T
+green_path_reset_limit
+ (struct green_path_handle* handle);
+
+extern LOCAL_SYM res_T
green_path_add_power_term
(struct green_path_handle* path,
struct sdis_medium* mdm,
diff --git a/src/sdis_heat_path.c b/src/sdis_heat_path.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 2016-2021 |Meso|Star> (contact@meso-star.com)
+/* Copyright (C) 2016-2022 |Meso|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
@@ -33,24 +33,28 @@
#define SDIS_XD_DIMENSION 3
#include "sdis_heat_path_conductive_Xd.h"
-/* Generate the boundary path routines */
-#define SDIS_XD_DIMENSION 2
-#include "sdis_heat_path_boundary_Xd.h"
-#define SDIS_XD_DIMENSION 3
-#include "sdis_heat_path_boundary_Xd.h"
-
/*******************************************************************************
- * Exported functions
+ * Local functions
******************************************************************************/
-res_T
-sdis_heat_path_get_vertices_count
- (const struct sdis_heat_path* path, size_t* nvertices)
+/* Return the offset into the list of vertices toward the first vertex of the
+ * line strip */
+static INLINE size_t
+line_strip_vertex_offset(const struct sdis_heat_path* path, const size_t istrip)
{
- if(!path || !nvertices) return RES_BAD_ARG;
- *nvertices = darray_heat_vertex_size_get(&path->vertices);
- return RES_OK;
+ ASSERT(path);
+#ifndef NDEBUG
+ {
+ size_t nstrips;
+ SDIS(heat_path_get_line_strips_count(path, &nstrips));
+ ASSERT(istrip < nstrips);
+ }
+#endif
+ return istrip == 0 ? 0 : darray_size_t_cdata_get(&path->breaks)[istrip-1] + 1;
}
+/*******************************************************************************
+ * Exported functions
+ ******************************************************************************/
res_T
sdis_heat_path_get_status
(const struct sdis_heat_path* path, enum sdis_heat_path_flag* status)
@@ -61,28 +65,112 @@ sdis_heat_path_get_status
}
res_T
-sdis_heat_path_get_vertex
+sdis_heat_path_get_line_strips_count
+ (const struct sdis_heat_path* path,
+ size_t* nstrips)
+{
+ if(!path || !nstrips) return RES_BAD_ARG;
+ /* #strips == #breaks + 1 */
+ *nstrips = darray_size_t_size_get(&path->breaks) + 1;
+ return RES_OK;
+}
+
+res_T
+sdis_heat_path_line_strip_get_vertices_count
+ (const struct sdis_heat_path* path,
+ const size_t istrip,
+ size_t* out_nvertices)
+{
+ size_t nstrips = 0;
+ size_t ivert_begin = 0;
+ size_t ivert_end = 0;
+ res_T res = RES_OK;
+
+ if(!path || !out_nvertices) {
+ res = RES_BAD_ARG;
+ goto error;
+ }
+
+ res = sdis_heat_path_get_line_strips_count(path, &nstrips);
+ if(res != RES_OK) goto error;
+
+ /* Check the indices of the strip */
+ if(istrip >= nstrips) {
+ res = RES_BAD_ARG;
+ goto error;
+ }
+
+ if(istrip == 0) { /* First strip */
+ ivert_begin = 0;
+ } else {
+ ivert_begin = line_strip_vertex_offset(path, istrip);
+ }
+
+ if(istrip == nstrips-1) { /* Last strip */
+ ivert_end = darray_heat_vertex_size_get(&path->vertices);
+ } else {
+ ivert_end = line_strip_vertex_offset(path, istrip+1);
+ }
+
+ ASSERT(ivert_begin <= ivert_end);
+ *out_nvertices = ivert_end - ivert_begin;
+
+exit:
+ return res;
+error:
+ goto exit;
+}
+
+res_T
+sdis_heat_path_line_strip_get_vertex
(const struct sdis_heat_path* path,
- const size_t ivertex,
+ const size_t istrip,
+ const size_t ivert,
struct sdis_heat_vertex* vertex)
{
- if(!path || !vertex
- || ivertex >= darray_heat_vertex_size_get(&path->vertices)) {
- return RES_BAD_ARG;
+ size_t nverts = 0;
+ size_t ivert_adjusted = 0;
+ res_T res = RES_OK;
+
+ if(!path || !vertex) {
+ res = RES_BAD_ARG;
+ goto error;
}
- *vertex = darray_heat_vertex_cdata_get(&path->vertices)[ivertex];
- return RES_OK;
+ /* By retrieving the number of vertices, we also check the validity of
+ * istrip: the function will return an error if istrip is invalid */
+ res = sdis_heat_path_line_strip_get_vertices_count(path, istrip, &nverts);
+ if(res != RES_OK) goto error;
+
+ if(ivert >= nverts) {
+ res = RES_BAD_ARG;
+ goto error;
+ }
+
+ /* Compute the index into the overall list of vertices */
+ ivert_adjusted = ivert + line_strip_vertex_offset(path, istrip);
+ ASSERT(ivert_adjusted < darray_heat_vertex_size_get(&path->vertices));
+
+ /* Fetch the vertex */
+ *vertex = darray_heat_vertex_cdata_get(&path->vertices)[ivert_adjusted];
+
+exit:
+ return res;
+error:
+ goto exit;
}
res_T
-sdis_heat_path_for_each_vertex
+sdis_heat_path_line_strip_for_each_vertex
(const struct sdis_heat_path* path,
+ const size_t istrip,
sdis_process_heat_vertex_T func,
void* context)
{
- const struct sdis_heat_vertex* vertices;
- size_t i, n;
+ const struct sdis_heat_vertex* vertices = NULL;
+ size_t ivert = 0;
+ size_t offset = 0;
+ size_t nverts = 0;
res_T res = RES_OK;
if(!path || !func) {
@@ -90,10 +178,14 @@ sdis_heat_path_for_each_vertex
goto error;
}
- SDIS(heat_path_get_vertices_count(path, &n));
+ res = sdis_heat_path_line_strip_get_vertices_count(path, istrip, &nverts);
+ if(res != RES_OK) goto error;
+
+ offset = line_strip_vertex_offset(path, istrip);
+
vertices = darray_heat_vertex_cdata_get(&path->vertices);
- FOR_EACH(i, 0, n) {
- res = func(vertices+i, context);
+ FOR_EACH(ivert, 0, nverts) {
+ res = func(vertices+ivert+offset, context);
if(res != RES_OK) goto error;
}
@@ -102,4 +194,3 @@ exit:
error:
goto exit;
}
-
diff --git a/src/sdis_heat_path.h b/src/sdis_heat_path.h
@@ -1,4 +1,4 @@
-/* Copyright (C) 2016-2021 |Meso|Star> (contact@meso-star.com)
+/* Copyright (C) 2016-2022 |Meso|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
@@ -19,6 +19,7 @@
#include "sdis.h"
#include <rsys/dynamic_array.h>
+#include <rsys/dynamic_array_size_t.h>
#include <rsys/rsys.h>
/* Forward declarations */
@@ -39,7 +40,12 @@ struct temperature_3d;
* Heat path data structure
******************************************************************************/
struct sdis_heat_path {
+ /* List of the path vertices */
struct darray_heat_vertex vertices;
+
+ /* Indices of the vertices that mark a break in the path */
+ struct darray_size_t breaks;
+
enum sdis_heat_path_flag status;
};
@@ -49,6 +55,7 @@ heat_path_init(struct mem_allocator* allocator, struct sdis_heat_path* path)
ASSERT(path);
path->status = SDIS_HEAT_PATH_NONE;
darray_heat_vertex_init(allocator, &path->vertices);
+ darray_size_t_init(allocator, &path->breaks);
}
static INLINE void
@@ -56,30 +63,46 @@ heat_path_release(struct sdis_heat_path* path)
{
ASSERT(path);
darray_heat_vertex_release(&path->vertices);
+ darray_size_t_release(&path->breaks);
}
static INLINE res_T
heat_path_copy(struct sdis_heat_path* dst, const struct sdis_heat_path* src)
{
+ res_T res = RES_OK;
ASSERT(dst && src);
dst->status = src->status;
- return darray_heat_vertex_copy(&dst->vertices, &src->vertices);
+ res = darray_heat_vertex_copy(&dst->vertices, &src->vertices);
+ if(res != RES_OK) return res;
+ res = darray_size_t_copy(&dst->breaks, &src->breaks);
+ if(res != RES_OK) return res;
+ return RES_OK;
}
static INLINE res_T
heat_path_copy_and_release(struct sdis_heat_path* dst, struct sdis_heat_path* src)
{
+ res_T res = RES_OK;
ASSERT(dst && src);
dst->status = src->status;
- return darray_heat_vertex_copy_and_release(&dst->vertices, &src->vertices);
+ res = darray_heat_vertex_copy_and_release(&dst->vertices, &src->vertices);
+ if(res != RES_OK) return res;
+ res = darray_size_t_copy_and_release(&dst->breaks, &src->breaks);
+ if(res != RES_OK) return res;
+ return RES_OK;
}
static INLINE res_T
heat_path_copy_and_clear(struct sdis_heat_path* dst, struct sdis_heat_path* src)
{
+ res_T res = RES_OK;
ASSERT(dst && src);
dst->status = src->status;
- return darray_heat_vertex_copy_and_clear(&dst->vertices, &src->vertices);
+ res = darray_heat_vertex_copy_and_clear(&dst->vertices, &src->vertices);
+ if(res != RES_OK) return res;
+ res = darray_size_t_copy_and_clear(&dst->breaks, &src->breaks);
+ if(res != RES_OK) return res;
+ return RES_OK;
}
static INLINE res_T
@@ -89,14 +112,81 @@ heat_path_add_vertex(struct sdis_heat_path* path, const struct sdis_heat_vertex*
return darray_heat_vertex_push_back(&path->vertices, vtx);
}
+static INLINE size_t
+heat_path_get_vertices_count(const struct sdis_heat_path* path)
+{
+ ASSERT(path);
+ return darray_heat_vertex_size_get(&path->vertices);
+}
+
+static INLINE struct sdis_heat_vertex*
+heat_path_get_vertex(struct sdis_heat_path* path, const size_t ivert)
+{
+ ASSERT(path && ivert < heat_path_get_vertices_count(path));
+ return darray_heat_vertex_data_get(&path->vertices) + ivert;
+}
+
static INLINE struct sdis_heat_vertex*
heat_path_get_last_vertex(struct sdis_heat_path* path)
{
size_t sz;
ASSERT(path);
- sz = darray_heat_vertex_size_get(&path->vertices);
+ sz = heat_path_get_vertices_count(path);
ASSERT(sz);
- return darray_heat_vertex_data_get(&path->vertices) + (sz-1);
+ return heat_path_get_vertex(path, sz-1);
+}
+
+static INLINE res_T
+heat_path_add_break(struct sdis_heat_path* path)
+{
+ size_t id;
+ size_t sz;
+ ASSERT(path);
+ sz = darray_heat_vertex_size_get(&path->vertices);
+ if(sz == 0) return RES_OK; /* Nothing to do */
+ id = sz-1;
+ return darray_size_t_push_back(&path->breaks, &id);
+}
+
+static INLINE res_T
+heat_path_restart
+ (struct sdis_heat_path* path,
+ const struct sdis_heat_vertex* vtx) /* Vertex to restart from */
+{
+ size_t nverts = 0;
+ size_t nbreaks = 0;
+ res_T res = RES_OK;
+
+ if(!path) goto exit;
+ ASSERT(vtx);
+
+ nbreaks = darray_size_t_size_get(&path->breaks);
+ nverts = darray_heat_vertex_size_get(&path->vertices);
+
+ res = heat_path_add_break(path);
+ if(res != RES_OK) goto error;
+ res = heat_path_add_vertex(path, vtx);
+ if(res != RES_OK) goto error;
+
+exit:
+ return res;
+error:
+ CHK(darray_size_t_resize(&path->breaks, nbreaks) == RES_OK);
+ CHK(darray_heat_vertex_resize(&path->vertices, nverts) == RES_OK);
+ goto exit;
+}
+
+static INLINE void
+heat_path_increment_sub_path_branch_id
+ (struct sdis_heat_path* path,
+ const size_t ivtx_begin,
+ const size_t ivtx_end)
+{
+ size_t ivtx;
+ FOR_EACH(ivtx, ivtx_begin, ivtx_end) {
+ struct sdis_heat_vertex* vtx = heat_path_get_vertex(path, ivtx);
+ vtx->branch_id += 1;
+ }
}
/* Generate the dynamic array of heat paths */
@@ -115,7 +205,7 @@ extern LOCAL_SYM res_T
trace_radiative_path_2d
(struct sdis_scene* scn,
const float ray_dir[3],
- const struct rwalk_context* ctx,
+ struct rwalk_context* ctx,
struct rwalk_2d* rwalk,
struct ssp_rng* rng,
struct temperature_2d* temperature);
@@ -124,7 +214,7 @@ extern LOCAL_SYM res_T
trace_radiative_path_3d
(struct sdis_scene* scn,
const float ray_dir[3],
- const struct rwalk_context* ctx,
+ struct rwalk_context* ctx,
struct rwalk_3d* rwalk,
struct ssp_rng* rng,
struct temperature_3d* temperature);
@@ -132,7 +222,7 @@ trace_radiative_path_3d
extern LOCAL_SYM res_T
radiative_path_2d
(struct sdis_scene* scn,
- const struct rwalk_context* ctx,
+ struct rwalk_context* ctx,
struct rwalk_2d* rwalk,
struct ssp_rng* rng,
struct temperature_2d* temperature);
@@ -140,7 +230,7 @@ radiative_path_2d
extern LOCAL_SYM res_T
radiative_path_3d
(struct sdis_scene* scn,
- const struct rwalk_context* ctx,
+ struct rwalk_context* ctx,
struct rwalk_3d* rwalk,
struct ssp_rng* rng,
struct temperature_3d* temperature);
@@ -151,7 +241,7 @@ radiative_path_3d
extern LOCAL_SYM res_T
convective_path_2d
(struct sdis_scene* scn,
- const struct rwalk_context* ctx,
+ struct rwalk_context* ctx,
struct rwalk_2d* rwalk,
struct ssp_rng* rng,
struct temperature_2d* temperature);
@@ -159,7 +249,7 @@ convective_path_2d
extern LOCAL_SYM res_T
convective_path_3d
(struct sdis_scene* scn,
- const struct rwalk_context* ctx,
+ struct rwalk_context* ctx,
struct rwalk_3d* rwalk,
struct ssp_rng* rng,
struct temperature_3d* temperature);
@@ -170,7 +260,7 @@ convective_path_3d
extern LOCAL_SYM res_T
conductive_path_2d
(struct sdis_scene* scn,
- const struct rwalk_context* ctx,
+ struct rwalk_context* ctx,
struct rwalk_2d* rwalk,
struct ssp_rng* rng,
struct temperature_2d* temperature);
@@ -178,7 +268,7 @@ conductive_path_2d
extern LOCAL_SYM res_T
conductive_path_3d
(struct sdis_scene* scn,
- const struct rwalk_context* ctx,
+ struct rwalk_context* ctx,
struct rwalk_3d* rwalk,
struct ssp_rng* rng,
struct temperature_3d* temperature);
@@ -189,7 +279,7 @@ conductive_path_3d
extern LOCAL_SYM res_T
boundary_path_2d
(struct sdis_scene* scn,
- const struct rwalk_context* ctx,
+ struct rwalk_context* ctx,
struct rwalk_2d* rwalk,
struct ssp_rng* rng,
struct temperature_2d* temperature);
@@ -197,7 +287,7 @@ boundary_path_2d
extern LOCAL_SYM res_T
boundary_path_3d
(struct sdis_scene* scn,
- const struct rwalk_context* ctx,
+ struct rwalk_context* ctx,
struct rwalk_3d* rwalk,
struct ssp_rng* rng,
struct temperature_3d* temperature);
diff --git a/src/sdis_heat_path_boundary.c b/src/sdis_heat_path_boundary.c
@@ -0,0 +1,47 @@
+/* Copyright (C) 2016-2022 |Meso|Star> (contact@meso-star.com)
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+#include "sdis_heat_path.h"
+#include "sdis_heat_path_boundary_c.h"
+
+/* Generate the helper routines */
+#define SDIS_XD_DIMENSION 2
+#include "sdis_heat_path_boundary_Xd_c.h"
+#define SDIS_XD_DIMENSION 3
+#include "sdis_heat_path_boundary_Xd_c.h"
+
+/* Generate the boundary path sub-routines */
+#define SDIS_XD_DIMENSION 2
+#include "sdis_heat_path_boundary_Xd_fixed_flux.h"
+#define SDIS_XD_DIMENSION 3
+#include "sdis_heat_path_boundary_Xd_fixed_flux.h"
+#define SDIS_XD_DIMENSION 2
+#include "sdis_heat_path_boundary_Xd_solid_fluid_picard1.h"
+#define SDIS_XD_DIMENSION 3
+#include "sdis_heat_path_boundary_Xd_solid_fluid_picard1.h"
+#define SDIS_XD_DIMENSION 2
+#include "sdis_heat_path_boundary_Xd_solid_fluid_picardN.h"
+#define SDIS_XD_DIMENSION 3
+#include "sdis_heat_path_boundary_Xd_solid_fluid_picardN.h"
+#define SDIS_XD_DIMENSION 2
+#include "sdis_heat_path_boundary_Xd_solid_solid.h"
+#define SDIS_XD_DIMENSION 3
+#include "sdis_heat_path_boundary_Xd_solid_solid.h"
+
+/* Generate the boundary path routines */
+#define SDIS_XD_DIMENSION 2
+#include "sdis_heat_path_boundary_Xd.h"
+#define SDIS_XD_DIMENSION 3
+#include "sdis_heat_path_boundary_Xd.h"
diff --git a/src/sdis_heat_path_boundary_Xd.h b/src/sdis_heat_path_boundary_Xd.h
@@ -1,4 +1,4 @@
-/* Copyright (C) 2016-2021 |Meso|Star> (contact@meso-star.com)
+/* Copyright (C) 2016-2022 |Meso|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
@@ -16,962 +16,21 @@
#include "sdis_device_c.h"
#include "sdis_green.h"
#include "sdis_heat_path.h"
+#include "sdis_heat_path_boundary_c.h"
#include "sdis_interface_c.h"
#include "sdis_medium_c.h"
-#include "sdis_scene_c.h"
#include <star/ssp.h>
#include "sdis_Xd_begin.h"
-/* Emperical scale factor applied to the challenged reinjection distance. If
- * the distance to reinject is less than this adjusted value, the solver will
- * try to discard the reinjection distance if possible in order to avoid
- * numerical issues. */
-#define REINJECT_DST_MIN_SCALE 0.125f
-
-/*******************************************************************************
- * Helper functions
- ******************************************************************************/
-static void
-XD(sample_reinjection_dir)
- (const struct XD(rwalk)* rwalk, struct ssp_rng* rng, float dir[DIM])
-{
-#if DIM == 2
- /* The sampled directions is defined by rotating the normal around the Z axis
- * of an angle of PI/4 or -PI/4. Let the rotation matrix defined as
- * | cos(a) -sin(a) |
- * | sin(a) cos(a) |
- * with a = PI/4, dir = sqrt(2)/2 * | 1 -1 | . N
- * | 1 1 |
- * with a =-PI/4, dir = sqrt(2)/2 * | 1 1 | . N
- * |-1 1 |
- * Note that since the sampled direction is finally normalized, we can
- * discard the sqrt(2)/2 constant. */
- const uint64_t r = ssp_rng_uniform_uint64(rng, 0, 1);
- ASSERT(rwalk && dir);
- if(r) {
- dir[0] = rwalk->hit.normal[0] - rwalk->hit.normal[1];
- dir[1] = rwalk->hit.normal[0] + rwalk->hit.normal[1];
- } else {
- dir[0] = rwalk->hit.normal[0] + rwalk->hit.normal[1];
- dir[1] =-rwalk->hit.normal[0] + rwalk->hit.normal[1];
- }
- f2_normalize(dir, dir);
-#else
- /* Sample a random direction around the normal whose cosine is 1/sqrt(3). To
- * do so we sample a position onto a cone whose height is 1/sqrt(2) and the
- * radius of its base is 1. */
- float frame[9];
- ASSERT(fX(is_normalized)(rwalk->hit.normal));
-
- ssp_ran_circle_uniform_float(rng, dir, NULL);
- dir[2] = (float)(1.0/sqrt(2));
-
- f33_basis(frame, rwalk->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));
-#endif
-}
-
-#if DIM == 2
-static void
-XD(move_away_primitive_boundaries)
- (struct XD(rwalk)* rwalk,
- const double delta)
-{
- struct sXd(attrib) attr;
- float pos[DIM];
- float dir[DIM];
- float len;
- const float st = 0.5f;
- ASSERT(rwalk && !SXD_HIT_NONE(&rwalk->hit) && delta > 0);
-
- SXD(primitive_get_attrib(&rwalk->hit.prim, SXD_POSITION, st, &attr));
-
- fX_set_dX(pos, rwalk->vtx.P);
- fX(sub)(dir, attr.value, pos);
- len = fX(normalize)(dir, dir);
- len = MMIN(len, (float)(delta*0.1));
-
- XD(move_pos)(rwalk->vtx.P, dir, len);
-}
-#else
-/* Move the random walk away from the primitive boundaries to avoid numerical
- * issues leading to inconsistent random walks. */
-static void
-XD(move_away_primitive_boundaries)
- (struct XD(rwalk)* rwalk,
- const double delta)
-{
- struct s3d_attrib v0, v1, v2; /* Triangle vertices */
- float E[3][4]; /* 3D edge equations */
- float dst[3]; /* Distance from current position to edge equation */
- float N[3]; /* Triangle normal */
- float P[3]; /* Random walk position */
- float tmp[3];
- float min_dst, max_dst;
- float cos_a1, cos_a2;
- float len;
- int imax = 0;
- int imin = 0;
- int imid = 0;
- int i;
- ASSERT(rwalk && delta > 0 && !S3D_HIT_NONE(&rwalk->hit));
-
- fX_set_dX(P, rwalk->vtx.P);
-
- /* 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));
-
- /* Compute the edge vector */
- f3_sub(E[0], v1.value, v0.value);
- f3_sub(E[1], v2.value, v1.value);
- f3_sub(E[2], v0.value, v2.value);
-
- /* Compute the triangle normal */
- f3_cross(N, E[1], E[0]);
-
- /* Compute the 3D edge equation */
- f3_normalize(E[0], f3_cross(E[0], E[0], N));
- f3_normalize(E[1], f3_cross(E[1], E[1], N));
- f3_normalize(E[2], f3_cross(E[2], E[2], N));
- E[0][3] = -f3_dot(E[0], v0.value);
- E[1][3] = -f3_dot(E[1], v1.value);
- E[2][3] = -f3_dot(E[2], v2.value);
-
- /* Compute the distance from current position to the edges */
- dst[0] = f3_dot(E[0], P) + E[0][3];
- dst[1] = f3_dot(E[1], P) + E[1][3];
- dst[2] = f3_dot(E[2], P) + E[2][3];
-
- /* Retrieve the min and max distance from random walk position to triangle
- * edges */
- min_dst = MMIN(MMIN(dst[0], dst[1]), dst[2]);
- max_dst = MMAX(MMAX(dst[0], dst[1]), dst[2]);
-
- /* Sort the edges with respect to their distance to the random walk position */
- FOR_EACH(i, 0, 3) {
- if(dst[i] == min_dst) {
- imin = i;
- } else if(dst[i] == max_dst) {
- imax = i;
- } else {
- imid = i;
- }
- }
- (void)imax;
-
- /* TODO if the current position is near a vertex, one should move toward the
- * farthest edge along its normal to avoid too small displacement */
-
- /* Compute the distance `dst' from the current position to the edges to move
- * to, along the normal of the edge from which the random walk is the nearest
- *
- * +. cos(a) = d / dst => dst = d / cos_a
- * / `*.
- * / | `*.
- * / dst| a /`*.
- * / | / `*.
- * / | / d `*.
- * / |/ `*.
- * +---------o----------------+ */
- cos_a1 = f3_dot(E[imin], f3_minus(tmp, E[imid]));
- cos_a2 = f3_dot(E[imin], f3_minus(tmp, E[imax]));
- dst[imid] = cos_a1 > 0 ? dst[imid] / cos_a1 : FLT_MAX;
- dst[imax] = cos_a2 > 0 ? dst[imax] / cos_a2 : FLT_MAX;
-
- /* Compute the maximum displacement distance into the triangle along the
- * normal of the edge from which the random walk is the nearest */
- len = MMIN(dst[imid], dst[imax]);
- ASSERT(len != FLT_MAX);
-
- /* Define the displacement distance as the minimum between 10 percent of
- * delta and len / 2. */
- len = MMIN(len*0.5f, (float)(delta*0.1));
- XD(move_pos)(rwalk->vtx.P, E[imin], len);
-}
-#endif
-
-static res_T
-XD(select_reinjection_dir)
- (const struct sdis_scene* scn,
- const struct sdis_medium* mdm, /* Medium into which the reinjection occurs */
- struct XD(rwalk)* rwalk, /* Current random walk state */
- const float dir0[DIM], /* Challenged direction */
- const float dir1[DIM], /* Challanged direction */
- const double delta, /* Max reinjection distance */
- float reinject_dir[DIM], /* Selected direction */
- float* reinject_dst, /* Effective reinjection distance */
- int can_move, /* Define of the random wal pos can be moved or not */
- int* move_pos, /* Define if the current random walk was moved. May be NULL */
- struct sXd(hit)* reinject_hit) /* Hit along the reinjection dir */
-{
- struct sdis_interface* interf;
- struct sdis_medium* mdm0;
- struct sdis_medium* mdm1;
- struct hit_filter_data filter_data;
- struct sXd(hit) hit;
- struct sXd(hit) hit0;
- struct sXd(hit) hit1;
- double tmp[DIM];
- double dst;
- double dst0;
- double dst1;
- const double delta_adjusted = delta * RAY_RANGE_MAX_SCALE;
- const float* dir;
- const float reinject_threshold = (float)delta * REINJECT_DST_MIN_SCALE;
- float org[DIM];
- float range[2];
- enum sdis_side side;
- int iattempt = 0;
- const int MAX_ATTEMPTS = can_move ? 2 : 1;
- res_T res = RES_OK;
- ASSERT(scn && mdm && rwalk && dir0 && dir1 && delta > 0);
- ASSERT(reinject_dir && reinject_dst && reinject_hit);
-
- if(move_pos) *move_pos = 0;
-
- do {
- f2(range, 0, FLT_MAX);
- fX_set_dX(org, rwalk->vtx.P);
- filter_data.XD(hit) = rwalk->hit;
- filter_data.epsilon = delta * 0.01;
- SXD(scene_view_trace_ray(scn->sXd(view), org, dir0, range, &filter_data, &hit0));
- SXD(scene_view_trace_ray(scn->sXd(view), org, dir1, range, &filter_data, &hit1));
-
- /* Retrieve the medium at the reinjection pos along dir0 */
- if(SXD_HIT_NONE(&hit0)) {
- XD(move_pos)(dX(set)(tmp, rwalk->vtx.P), dir0, (float)delta);
- res = scene_get_medium_in_closed_boundaries(scn, tmp, &mdm0);
- if(res == RES_BAD_OP) { mdm0 = NULL; res = RES_OK; }
- if(res != RES_OK) goto error;
- } else {
- interf = scene_get_interface(scn, hit0.prim.prim_id);
- side = fX(dot)(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)) {
- XD(move_pos)(dX(set)(tmp, rwalk->vtx.P), dir1, (float)delta);
- res = scene_get_medium_in_closed_boundaries(scn, tmp, &mdm1);
- if(res == RES_BAD_OP) { mdm1 = NULL; res = RES_OK; }
- if(res != RES_OK) goto error;
- } else {
- interf = scene_get_interface(scn, hit1.prim.prim_id);
- side = fX(dot)(dir1, hit1.normal) < 0 ? SDIS_FRONT : SDIS_BACK;
- mdm1 = interface_get_medium(interf, side);
- }
-
- dst0 = dst1 = -1;
- if(mdm0 == mdm) { /* Check reinjection consistency */
- if(hit0.distance <= delta_adjusted) {
- dst0 = hit0.distance;
- } else {
- dst0 = delta;
- hit0 = SXD_HIT_NULL;
- }
- }
- if(mdm1 == mdm) {/* Check reinjection consistency */
- if(hit1.distance <= delta_adjusted) {
- dst1 = hit1.distance;
- } else {
- dst1 = delta;
- hit1 = SXD_HIT_NULL;
- }
- }
-
- /* No valid reinjection. Maybe the random walk is near a sharp corner and
- * thus the ray-tracing misses the enclosure geometry. Another possibility
- * is that the random walk lies roughly on an edge. In this case, sampled
- * reinjecton dirs can intersect the primitive on the other side of the
- * edge. Normally, this primitive should be filtered by the "hit_filter"
- * function but this may be not the case due to a "threshold effect". In
- * both situations, try to slightly move away from the primitive boundaries
- * and retry to find a valid reinjection. */
- if(dst0 == -1 && dst1 == -1) {
- XD(move_away_primitive_boundaries)(rwalk, delta);
- if(move_pos) *move_pos = 1;
- }
- } while(dst0 == -1 && dst1 == -1 && ++iattempt < MAX_ATTEMPTS);
-
- if(dst0 == -1 && dst1 == -1) { /* No valid reinjection */
- log_warn(scn->dev, "%s: no valid reinjection direction at {%g, %g, %g}.\n",
- FUNC_NAME, SPLIT3(rwalk->vtx.P));
- res = RES_BAD_OP_IRRECOVERABLE;
- goto error;
- }
-
- if(dst0 == -1) {
- /* Invalid dir0 -> move along dir1 */
- dir = dir1;
- dst = dst1;
- hit = hit1;
- } else if(dst1 == -1) {
- /* Invalid dir1 -> move along dir0 */
- dir = dir0;
- dst = dst0;
- hit = hit0;
- } else if(dst0 < reinject_threshold && dst1 < reinject_threshold) {
- /* The displacement along dir0 and dir1 are both below the reinjection
- * threshold that defines a distance under which the temperature gradients
- * are ignored. Move along the direction that allows the maximum
- * displacement. */
- if(dst0 > dst1) {
- dir = dir0;
- dst = dst0;
- hit = hit0;
- } else {
- dir = dir1;
- dst = dst1;
- hit = hit1;
- }
- } else if(dst0 < reinject_threshold) {
- /* Ingore dir0 that is bellow the reinject threshold */
- dir = dir1;
- dst = dst1;
- hit = hit1;
- } else if(dst1 < reinject_threshold) {
- /* Ingore dir1 that is bellow the reinject threshold */
- dir = dir0;
- dst = dst0;
- hit = hit0;
- } else {
- /* All reinjection directions are valid. Choose the first 1 that was
- * randomly selected by the sample_reinjection_dir procedure and adjust
- * the displacement distance. */
- dir = dir0;
-
- /* Define the reinjection distance along dir0 and its corresponding hit */
- if(dst0 <= dst1) {
- dst = dst0;
- hit = hit0;
- } else {
- dst = dst1;
- hit = SXD_HIT_NULL;
- }
-
- /* If the displacement distance is too close of a boundary, move to the
- * boundary in order to avoid numerical uncertainty. */
- if(!SXD_HIT_NONE(&hit0)
- && dst0 != dst
- && eq_eps(dst0, dst, dst0*0.1)) {
- dst = dst0;
- hit = hit0;
- }
- }
-
- /* Setup output variable */
- fX(set)(reinject_dir, dir);
- *reinject_dst = (float)dst;
- *reinject_hit = hit;
-
-exit:
- return res;
-error:
- goto exit;
-}
-
-static res_T
-XD(select_reinjection_dir_and_check_validity)
- (const struct sdis_scene* scn,
- const struct sdis_medium* mdm, /* Medium into which the reinjection occurs */
- struct XD(rwalk)* rwalk, /* Current random walk state */
- const float dir0[DIM], /* Challenged direction */
- const float dir1[DIM], /* Challanged direction */
- const double delta, /* Max reinjection distance */
- float out_reinject_dir[DIM], /* Selected direction */
- float* out_reinject_dst, /* Effective reinjection distance */
- int can_move, /* Define of the random wal pos can be moved or not */
- int* move_pos, /* Define if the current random walk was moved. May be NULL */
- int* is_valid, /* Define if the reinjection defines a valid pos */
- struct sXd(hit)* out_reinject_hit) /* Hit along the reinjection dir */
-{
- double pos[DIM];
- struct sdis_medium* reinject_mdm;
- struct sXd(hit) reinject_hit;
- float reinject_dir[DIM];
- float reinject_dst;
- res_T res = RES_OK;
- ASSERT(is_valid && out_reinject_dir && out_reinject_dst && out_reinject_hit);
-
- /* Select a reinjection direction */
- res = XD(select_reinjection_dir)(scn, mdm, rwalk, dir0, dir1, delta,
- reinject_dir, &reinject_dst, can_move, move_pos, &reinject_hit);
- if(res != RES_OK) goto error;
-
- if(!SXD_HIT_NONE(&reinject_hit)) {
- *is_valid = 1;
- } else {
- /* Check medium consistency at the reinjection position */
- XD(move_pos)(dX(set)(pos, rwalk->vtx.P), reinject_dir, reinject_dst);
- res = scene_get_medium_in_closed_boundaries
- (scn, pos, &reinject_mdm);
- if(res == RES_BAD_OP) { reinject_mdm = NULL; res = RES_OK; }
- if(res != RES_OK) goto error;
-
- *is_valid = reinject_mdm == mdm;
- }
-
- if(*is_valid) {
- fX(set)(out_reinject_dir, reinject_dir);
- *out_reinject_dst = reinject_dst;
- *out_reinject_hit = reinject_hit;
- }
-
-exit:
- return res;
-error:
- goto exit;
-}
-
-/* Check that the interface fragment is consistent with the current state of
- * the random walk */
-static INLINE int
-XD(check_rwalk_fragment_consistency)
- (const struct XD(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;
- }
-#if (SDIS_XD_DIMENSION == 2)
- uv[0] = rwalk->hit.u;
-#else
- d2_set_f2(uv, rwalk->hit.uv);
-#endif
- return d2_eq_eps(uv, frag->uv, 1.e-6);
-}
-
-static res_T
-XD(solid_solid_boundary_path)
- (const struct sdis_scene* scn,
- const struct rwalk_context* ctx,
- const struct sdis_interface_fragment* frag,
- struct XD(rwalk)* rwalk,
- struct ssp_rng* rng,
- struct XD(temperature)* T)
-{
- struct sXd(hit) hit0, hit1;
- struct sXd(hit)* hit;
- struct XD(rwalk) rwalk_saved;
- struct sdis_interface* interf = NULL;
- struct sdis_medium* solid_front = NULL;
- struct sdis_medium* solid_back = NULL;
- struct sdis_medium* mdm;
- double lambda_front, lambda_back;
- double delta_front, delta_back;
- double delta_boundary_front, delta_boundary_back;
- double proba;
- double tmp;
- double r;
- double power;
- double tcr;
- float dir0[DIM], dir1[DIM], dir2[DIM], dir3[DIM];
- float dir_front[DIM], dir_back[DIM];
- float* dir;
- float reinject_dst_front = 0, reinject_dst_back = 0;
- float reinject_dst;
- /* 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;
- int iattempt;
- int move;
- int reinjection_is_valid;
- res_T res = RES_OK;
- ASSERT(scn && ctx && frag && rwalk && rng && T);
- ASSERT(XD(check_rwalk_fragment_consistency)(rwalk, frag));
- (void)frag, (void)ctx;
-
- /* Retrieve the current boundary media */
- interf = scene_get_interface(scn, rwalk->hit.prim.prim_id);
- solid_front = interface_get_medium(interf, SDIS_FRONT);
- solid_back = interface_get_medium(interf, SDIS_BACK);
- ASSERT(solid_front->type == SDIS_SOLID);
- ASSERT(solid_back->type == SDIS_SOLID);
-
- /* Retrieve the thermal contact resistance */
- tcr = interface_get_thermal_contact_resistance(interf, frag);
-
- /* Fetch the properties of the media */
- lambda_front = solid_get_thermal_conductivity(solid_front, &rwalk->vtx);
- lambda_back = solid_get_thermal_conductivity(solid_back, &rwalk->vtx);
-
- /* Note that reinjection distance is *FIXED*. It MUST ensure that the orthogonal
- * distance from the boundary to the point to challenge is equal to delta. */
- delta_front = solid_get_delta(solid_front, &rwalk->vtx);
- delta_back = solid_get_delta(solid_back, &rwalk->vtx);
- delta_boundary_front = delta_front*sqrt(DIM);
- delta_boundary_back = delta_back *sqrt(DIM);
-
- rwalk_saved = *rwalk;
- reinjection_is_valid = 0;
- iattempt = 0;
- do {
- if(iattempt != 0) *rwalk = rwalk_saved;
-
- /* 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, dir0);
- XD(reflect)(dir2, dir0, rwalk->hit.normal);
- fX(minus)(dir1, dir0);
- fX(minus)(dir3, dir2);
-
- /* Select the reinjection direction and distance for the front side */
- res = XD(select_reinjection_dir_and_check_validity)(scn, solid_front, rwalk,
- dir0, dir2, delta_boundary_front, dir_front, &reinject_dst_front, 1, &move,
- &reinjection_is_valid, &hit0);
- if(res != RES_OK) goto error;
- if(!reinjection_is_valid) continue;
-
- /* Select the reinjection direction and distance for the back side */
- res = XD(select_reinjection_dir_and_check_validity)(scn, solid_back, rwalk,
- dir1, dir3, delta_boundary_back, dir_back, &reinject_dst_back, 1, &move,
- &reinjection_is_valid, &hit1);
- if(res != RES_OK) goto error;
- if(!reinjection_is_valid) continue;
-
- /* If random walk was moved by the select_reinjection_dir on back side, one
- * has to rerun the select_reinjection_dir on front side at the new pos */
- if(move) {
- res = XD(select_reinjection_dir_and_check_validity)(scn, solid_front,
- rwalk, dir0, dir2, delta_boundary_front, dir_front, &reinject_dst_front,
- 0, NULL, &reinjection_is_valid, &hit0);
- if(res != RES_OK) goto error;
- if(!reinjection_is_valid) continue;
- }
- } while(!reinjection_is_valid && ++iattempt < MAX_ATTEMPTS);
-
- /* Could not find a valid reinjection */
- if(iattempt >= MAX_ATTEMPTS) {
- *rwalk = rwalk_saved;
- log_warn(scn->dev,
- "%s: could not find a valid solid/solid reinjection at {%g, %g, %g}.\n",
- FUNC_NAME, SPLIT3(rwalk->vtx.P));
- res = RES_BAD_OP_IRRECOVERABLE;
- goto error;
- }
-
- r = ssp_rng_canonical(rng);
- if(tcr == 0) { /* No thermal contact resistance */
- /* Define the reinjection side. Note that the proba should be : Lf/Df' /
- * (Lf/Df' + Lb/Db')
- *
- * with L<f|b> the lambda of the <front|back> side and D<f|b>' the adjusted
- * delta of the <front|back> side, i.e. : D<f|b>' =
- * reinject_dst_<front|back> / sqrt(DIM)
- *
- * Anyway, one can avoid to compute the adjusted delta by directly using the
- * adjusted reinjection distance since the resulting proba is strictly the
- * same; sqrt(DIM) can be simplified. */
- proba = (lambda_front/reinject_dst_front)
- / (lambda_front/reinject_dst_front + lambda_back/reinject_dst_back);
- } else {
- const double df = reinject_dst_front/sqrt(DIM);
- const double db = reinject_dst_back/sqrt(DIM);
- const double tmp_front = lambda_front/df;
- const double tmp_back = lambda_back/db;
- const double tmp_r = tcr*tmp_front*tmp_back;
- switch(rwalk->hit_side) {
- case SDIS_BACK:
- /* When coming from the BACK side, the probability to be reinjected on
- * the FRONT side depends on the thermal contact resistance: it
- * decreases when the TCR increases (and tends to 0 when TCR -> +inf) */
- proba = (tmp_front) / (tmp_front + tmp_back + tmp_r);
- break;
- case SDIS_FRONT:
- /* Same thing when coming from the FRONT side: the probability of
- * reinjection on the FRONT side depends on the thermal contact
- * resistance: it increases when the TCR increases (and tends to 1 when
- * the TCR -> +inf) */
- proba = (tmp_front + tmp_r) / (tmp_front + tmp_back + tmp_r);
- break;
- default: FATAL("Unreachable code.\n"); break;
- }
- }
-
- if(r < proba) { /* Reinject in front */
- dir = dir_front;
- hit = &hit0;
- mdm = solid_front;
- reinject_dst = reinject_dst_front;
- } else { /* Reinject in back */
- dir = dir_back;
- hit = &hit1;
- mdm = solid_back;
- reinject_dst = reinject_dst_back;
- }
-
- /* Handle the volumic power */
- power = solid_get_volumic_power(mdm, &rwalk->vtx);
- if(power != SDIS_VOLUMIC_POWER_NONE) {
- const double delta_in_meter = reinject_dst * scn->fp_to_meter;
- const double lambda = solid_get_thermal_conductivity(mdm, &rwalk->vtx);
- tmp = delta_in_meter * delta_in_meter / (2.0 * DIM * lambda);
- T->value += power * tmp;
-
- if(ctx->green_path) {
- res = green_path_add_power_term(ctx->green_path, mdm, &rwalk->vtx, tmp);
- if(res != RES_OK) goto error;
- }
- }
-
- /* Time rewind */
- res = XD(time_rewind)(mdm, rng, reinject_dst * scn->fp_to_meter, ctx, rwalk, T);
- if(res != RES_OK) goto error;
- if(T->done) goto exit; /* Limit condition was reached */
-
- /* Perform reinjection. */
- XD(move_pos)(rwalk->vtx.P, dir, (float)reinject_dst);
- if(hit->distance == reinject_dst) {
- T->func = XD(boundary_path);
- rwalk->mdm = NULL;
- rwalk->hit = *hit;
- rwalk->hit_side = fX(dot)(hit->normal, dir) < 0 ? SDIS_FRONT : SDIS_BACK;
- } else {
- T->func = XD(conductive_path);
- rwalk->mdm = mdm;
- rwalk->hit = SXD_HIT_NULL;
- rwalk->hit_side = SDIS_SIDE_NULL__;
- }
-
- /* Register the new vertex against the heat path */
- res = register_heat_vertex
- (ctx->heat_path, &rwalk->vtx, T->value, SDIS_HEAT_VERTEX_CONDUCTION);
- if(res != RES_OK) goto error;
-
-exit:
- return res;
-error:
- goto exit;
-}
-
-static res_T
-XD(solid_fluid_boundary_path)
- (const struct sdis_scene* scn,
- const struct rwalk_context* ctx,
- const struct sdis_interface_fragment* frag,
- struct XD(rwalk)* rwalk,
- struct ssp_rng* rng,
- struct XD(temperature)* T)
-{
- struct sdis_interface* interf = NULL;
- struct sdis_medium* mdm_front = NULL;
- struct sdis_medium* mdm_back = NULL;
- struct sdis_medium* solid = NULL;
- struct sdis_medium* fluid = NULL;
- struct XD(rwalk) rwalk_saved;
- struct sXd(hit) hit = SXD_HIT_NULL;
- struct sdis_interface_fragment frag_fluid;
- double hc;
- double hr;
- double epsilon; /* Interface emissivity */
- double lambda;
- double fluid_proba;
- double radia_proba;
- double delta;
- double delta_boundary;
- double r;
- double tmp;
- float dir0[DIM], dir1[DIM];
- float reinject_dst;
- /* 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;
- int iattempt;
- int reinjection_is_valid = 0;
- res_T res = RES_OK;
- ASSERT(scn && rwalk && rng && T && ctx);
- ASSERT(XD(check_rwalk_fragment_consistency)(rwalk, frag));
-
- /* Retrieve the solid and the fluid split by the boundary */
- interf = scene_get_interface(scn, rwalk->hit.prim.prim_id);
- mdm_front = interface_get_medium(interf, SDIS_FRONT);
- mdm_back = interface_get_medium(interf, SDIS_BACK);
- ASSERT(mdm_front->type != mdm_back->type);
-
- frag_fluid = *frag;
- if(mdm_front->type == SDIS_SOLID) {
- solid = mdm_front;
- fluid = mdm_back;
- frag_fluid.side = SDIS_BACK;
- } else {
- solid = mdm_back;
- fluid = mdm_front;
- frag_fluid.side = SDIS_FRONT;
- }
-
- /* Fetch the solid properties */
- lambda = solid_get_thermal_conductivity(solid, &rwalk->vtx);
- delta = solid_get_delta(solid, &rwalk->vtx);
-
- /* Note that the reinjection distance is *FIXED*. It MUST ensure that the
- * orthogonal distance from the boundary to the point to chalenge is equal to
- * delta. */
- delta_boundary = sqrt(DIM) * delta;
-
- rwalk_saved = *rwalk;
- reinjection_is_valid = 0;
- iattempt = 0;
- do {
- if(iattempt != 0) *rwalk = rwalk_saved;
-
- /* Sample a reinjection direction */
- XD(sample_reinjection_dir)(rwalk, rng, dir0);
-
- /* Reflect the sampled direction around the normal */
- XD(reflect)(dir1, dir0, rwalk->hit.normal);
-
- if(solid == mdm_back) {
- fX(minus)(dir0, dir0);
- fX(minus)(dir1, dir1);
- }
-
- /* Select the solid reinjection direction and distance */
- res = XD(select_reinjection_dir_and_check_validity)(scn, solid, rwalk,
- dir0, dir1, delta_boundary, dir0, &reinject_dst, 1, NULL,
- &reinjection_is_valid, &hit);
- if(res != RES_OK) goto error;
-
- } while(!reinjection_is_valid && ++iattempt < MAX_ATTEMPTS);
-
- /* Could not find a valid reinjecton */
- if(iattempt >= MAX_ATTEMPTS) {
- *rwalk = rwalk_saved;
- log_warn(scn->dev,
- "%s: could not find a valid solid/fluid reinjection at {%g, %g %g}.\n",
- FUNC_NAME, SPLIT3(rwalk->vtx.P));
- res = RES_BAD_OP_IRRECOVERABLE;
- goto error;
- }
-
- /* Define the orthogonal dst from the reinjection pos to the interface */
- delta = reinject_dst / sqrt(DIM);
-
- /* Fetch the boundary properties */
- epsilon = interface_side_get_emissivity(interf, &frag_fluid);
- hc = interface_get_convection_coef(interf, frag);
-
- /* Compute the radiative coefficient */
- hr = 4.0 * BOLTZMANN_CONSTANT * ctx->Tref3 * epsilon;
-
- /* Compute the probas to switch in solid, fluid or radiative random walk */
- tmp = lambda / (delta * scn->fp_to_meter);
- fluid_proba = hc / (tmp + hr + hc);
- radia_proba = hr / (tmp + hr + hc);
- /*solid_proba = tmp / (tmp + hr + hc);*/
-
- r = ssp_rng_canonical(rng);
- if(r < radia_proba) { /* Switch in radiative random walk */
- T->func = XD(radiative_path);
- rwalk->mdm = fluid;
- rwalk->hit_side = rwalk->mdm == mdm_front ? SDIS_FRONT : SDIS_BACK;
- } else if(r < fluid_proba + radia_proba) { /* Switch to convective random walk */
- T->func = XD(convective_path);
- rwalk->mdm = fluid;
- rwalk->hit_side = rwalk->mdm == mdm_front ? SDIS_FRONT : SDIS_BACK;
- } else { /* Solid random walk */
- /* Handle the volumic power */
- const double power = solid_get_volumic_power(solid, &rwalk->vtx);
- if(power != SDIS_VOLUMIC_POWER_NONE) {
- const double delta_in_meter = reinject_dst * scn->fp_to_meter;
- tmp = delta_in_meter * delta_in_meter / (2.0 * DIM * lambda);
- T->value += power * tmp;
-
- if(ctx->green_path) {
- res = green_path_add_power_term(ctx->green_path, solid, &rwalk->vtx, tmp);
- if(res != RES_OK) goto error;
- }
- }
-
- /* Time rewind */
- res = XD(time_rewind)(solid, rng, reinject_dst * scn->fp_to_meter, ctx, rwalk, T);
- if(res != RES_OK) goto error;
- if(T->done) goto exit; /* Limit condition was reached */
-
- /* Perform solid reinjection */
- XD(move_pos)(rwalk->vtx.P, dir0, reinject_dst);
- if(hit.distance == reinject_dst) {
- T->func = XD(boundary_path);
- rwalk->mdm = NULL;
- rwalk->hit = hit;
- rwalk->hit_side = fX(dot)(hit.normal, dir0) < 0 ? SDIS_FRONT : SDIS_BACK;
- } else {
- T->func = XD(conductive_path);
- rwalk->mdm = solid;
- rwalk->hit = SXD_HIT_NULL;
- rwalk->hit_side = SDIS_SIDE_NULL__;
- }
-
- /* Register the new vertex against the heat path */
- res = register_heat_vertex
- (ctx->heat_path, &rwalk->vtx, T->value, SDIS_HEAT_VERTEX_CONDUCTION);
- if(res != RES_OK) goto error;
- }
-
-exit:
- return res;
-error:
- goto exit;
-}
-
-static res_T
-XD(solid_boundary_with_flux_path)
- (const struct sdis_scene* scn,
- const struct rwalk_context* ctx,
- const struct sdis_interface_fragment* frag,
- const double phi,
- struct XD(rwalk)* rwalk,
- struct ssp_rng* rng,
- struct XD(temperature)* T)
-{
- struct XD(rwalk) rwalk_saved;
- struct sdis_interface* interf = NULL;
- struct sdis_medium* mdm = NULL;
- double lambda;
- double delta;
- double delta_boundary;
- double delta_in_meter;
- double power;
- double tmp;
- struct sXd(hit) hit;
- float dir0[DIM];
- float dir1[DIM];
- float reinject_dst;
- /* 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;
- int iattempt = 0;
- int reinjection_is_valid = 0;
- res_T res = RES_OK;
- ASSERT(frag && phi != SDIS_FLUX_NONE);
- ASSERT(XD(check_rwalk_fragment_consistency)(rwalk, frag));
- (void)ctx;
-
- /* Fetch current interface */
- interf = scene_get_interface(scn, rwalk->hit.prim.prim_id);
- ASSERT(phi == interface_side_get_flux(interf, frag));
-
- /* Fetch incoming solid */
- mdm = interface_get_medium(interf, frag->side);
- ASSERT(mdm->type == SDIS_SOLID);
-
- /* Fetch medium properties */
- lambda = solid_get_thermal_conductivity(mdm, &rwalk->vtx);
- delta = solid_get_delta(mdm, &rwalk->vtx);
-
- /* Compute the reinjection distance. It MUST ensure that the orthogonal
- * distance from the boundary to the point to chalenge is equal to delta. */
- delta_boundary = delta * sqrt(DIM);
-
- rwalk_saved = *rwalk;
- reinjection_is_valid = 0;
- iattempt = 0;
- do {
- if(iattempt != 0) *rwalk = rwalk_saved;
- /* Sample a reinjection direction */
- XD(sample_reinjection_dir)(rwalk, rng, dir0);
-
- /* Reflect the sampled direction around the normal */
- XD(reflect)(dir1, dir0, rwalk->hit.normal);
-
- if(frag->side == SDIS_BACK) {
- fX(minus)(dir0, dir0);
- fX(minus)(dir1, dir1);
- }
-
- /* Select the reinjection direction and distance */
- res = XD(select_reinjection_dir_and_check_validity)(scn, mdm, rwalk, dir0,
- dir1, delta_boundary, dir0, &reinject_dst, 1, NULL,
- &reinjection_is_valid, &hit);
- if(res != RES_OK) goto error;
-
- } while(!reinjection_is_valid && ++iattempt < MAX_ATTEMPTS);
-
- /* Could not find a valid reinjecton */
- if(iattempt >= MAX_ATTEMPTS) {
- *rwalk = rwalk_saved;
- log_warn(scn->dev,
- "%s: could not find a valid solid/fluid with flux reinjection "
- "at {%g, %g, %g}.\n", FUNC_NAME, SPLIT3(rwalk->vtx.P));
- res = RES_BAD_OP_IRRECOVERABLE;
- goto error;
- }
-
- /* Define the orthogonal dst from the reinjection pos to the interface */
- delta = reinject_dst / sqrt(DIM);
-
- /* Handle the flux */
- delta_in_meter = delta * scn->fp_to_meter;
- tmp = delta_in_meter / lambda;
- T->value += phi * tmp;
- if(ctx->green_path) {
- res = green_path_add_flux_term(ctx->green_path, interf, frag, tmp);
- if(res != RES_OK) goto error;
- }
-
- /* Handle the volumic power */
- power = solid_get_volumic_power(mdm, &rwalk->vtx);
- if(power != SDIS_VOLUMIC_POWER_NONE) {
- delta_in_meter = reinject_dst * scn->fp_to_meter;
- tmp = delta_in_meter * delta_in_meter / (2.0 * DIM * lambda);
- T->value += power * tmp;
- if(ctx->green_path) {
- res = green_path_add_power_term(ctx->green_path, mdm, &rwalk->vtx, tmp);
- if(res != RES_OK) goto error;
- }
- }
-
- /* Time rewind */
- res = XD(time_rewind)(mdm, rng, reinject_dst * scn->fp_to_meter, ctx, rwalk, T);
- if(res != RES_OK) goto error;
- if(T->done) goto exit; /* Limit condition was reached */
-
- /* Reinject. If the reinjection move the point too close of a boundary,
- * assume that the zone is isotherm and move to the boundary. */
- XD(move_pos)(rwalk->vtx.P, dir0, reinject_dst);
- if(hit.distance == reinject_dst) {
- T->func = XD(boundary_path);
- rwalk->mdm = NULL;
- rwalk->hit = hit;
- rwalk->hit_side = fX(dot)(hit.normal, dir0) < 0 ? SDIS_FRONT : SDIS_BACK;
- } else {
- T->func = XD(conductive_path);
- rwalk->mdm = mdm;
- rwalk->hit = SXD_HIT_NULL;
- rwalk->hit_side = SDIS_SIDE_NULL__;
- }
-
- /* Register the new vertex against the heat path */
- res = register_heat_vertex
- (ctx->heat_path, &rwalk->vtx, T->value, SDIS_HEAT_VERTEX_CONDUCTION);
- if(res != RES_OK) goto error;
-
-exit:
- return res;
-error:
- goto exit;
-}
-
/*******************************************************************************
* Local functions
******************************************************************************/
res_T
XD(boundary_path)
(struct sdis_scene* scn,
- const struct rwalk_context* ctx,
+ struct rwalk_context* ctx,
struct XD(rwalk)* rwalk,
struct ssp_rng* rng,
struct XD(temperature)* T)
@@ -1030,8 +89,11 @@ XD(boundary_path)
if(mdm_front->type == mdm_back->type) {
res = XD(solid_solid_boundary_path)(scn, ctx, &frag, rwalk, rng, T);
+ } else if(ctx->nbranchings == ctx->max_branchings) {
+ res = XD(solid_fluid_boundary_picard1_path)(scn, ctx, &frag, rwalk, rng, T);
} else {
- res = XD(solid_fluid_boundary_path)(scn, ctx, &frag, rwalk, rng, T);
+ ASSERT(ctx->nbranchings < ctx->max_branchings);
+ res = XD(solid_fluid_boundary_picardN_path)(scn, ctx, &frag, rwalk, rng, T);
}
if(res != RES_OK) goto error;
diff --git a/src/sdis_heat_path_boundary_Xd_c.h b/src/sdis_heat_path_boundary_Xd_c.h
@@ -0,0 +1,875 @@
+/* Copyright (C) 2016-2022 |Meso|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_green.h"
+#include "sdis_heat_path_boundary_c.h"
+#include "sdis_interface_c.h"
+#include "sdis_log.h"
+#include "sdis_medium_c.h"
+#include "sdis_misc.h"
+#include "sdis_scene_c.h"
+
+#include <star/ssp.h>
+
+#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 */
+ float dir0[DIM]; /* Challenged ray direction */
+ float dir1[DIM]; /* Challenged ray direction */
+ double distance; /* Maximum reinjection distance */
+
+ /* 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 };
+
+struct XD(reinjection_ray) {
+ double org[DIM]; /* Origin of the reinjection */
+ float dir[DIM]; /* Direction of the reinjection */
+ float dst; /* Reinjection distance along dir */
+ struct sXd(hit) hit; /* Hit along the reinjection dir */
+
+ /* Define whether or not the random walk was moved to find this reinjection
+ * ray */
+ int position_was_moved;
+};
+static const struct XD(reinjection_ray)
+XD(REINJECTION_RAY_NULL) = { {0}, {0}, 0, SXD_HIT_NULL__, 0 };
+
+/*******************************************************************************
+ * Helper functions
+ ******************************************************************************/
+static INLINE int
+XD(check_find_reinjection_ray_args)
+ (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);
+}
+
+static INLINE int
+XD(check_sample_reinjection_step_args)
+ (const struct XD(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__;
+}
+
+static INLINE int
+XD(check_reinjection_step)(const struct XD(reinjection_step)* step)
+{
+ return step
+ && fX(is_normalized)(step->direction)
+ && step->distance > 0;
+}
+
+static INLINE int
+XD(check_solid_reinjection_args)(const struct XD(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 that the interface fragment is consistent with the current state of
+ * the random walk */
+static INLINE int
+XD(check_rwalk_fragment_consistency)
+ (const struct XD(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;
+ }
+#if (SDIS_XD_DIMENSION == 2)
+ uv[0] = rwalk->hit.u;
+#else
+ d2_set_f2(uv, rwalk->hit.uv);
+#endif
+ return d2_eq_eps(uv, frag->uv, 1.e-6);
+}
+
+static void
+XD(sample_reinjection_dir)
+ (const struct XD(rwalk)* rwalk,
+ struct ssp_rng* rng,
+ float dir[DIM])
+{
+#if DIM == 2
+ /* The sampled directions is defined by rotating the normal around the Z axis
+ * of an angle of PI/4 or -PI/4. Let the rotation matrix defined as
+ * | cos(a) -sin(a) |
+ * | sin(a) cos(a) |
+ * with a = PI/4, dir = sqrt(2)/2 * | 1 -1 | . N
+ * | 1 1 |
+ * with a =-PI/4, dir = sqrt(2)/2 * | 1 1 | . N
+ * |-1 1 |
+ * Note that since the sampled direction is finally normalized, we can
+ * 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);
+
+ if(r) {
+ dir[0] = rwalk->hit.normal[0] - rwalk->hit.normal[1];
+ dir[1] = rwalk->hit.normal[0] + rwalk->hit.normal[1];
+ } else {
+ dir[0] = rwalk->hit.normal[0] + rwalk->hit.normal[1];
+ dir[1] =-rwalk->hit.normal[0] + rwalk->hit.normal[1];
+ }
+ f2_normalize(dir, dir);
+#else
+ /* Sample a random direction around the normal whose cosine is 1/sqrt(3). To
+ * do so we sample a position onto a cone whose height is 1/sqrt(2) and the
+ * 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));
+
+ ssp_ran_circle_uniform_float(rng, dir, NULL);
+ dir[2] = (float)(1.0/sqrt(2));
+
+ f33_basis(frame, rwalk->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));
+#endif
+}
+
+
+#if DIM == 2
+static void
+XD(move_away_primitive_boundaries)
+ (const struct XD(rwalk)* rwalk,
+ const double delta,
+ double position[DIM]) /* Position to move */
+{
+ struct sXd(attrib) attr;
+ float pos[DIM];
+ float dir[DIM];
+ float len;
+ const float st = 0.5f;
+ ASSERT(rwalk && !SXD_HIT_NONE(&rwalk->hit) && delta > 0);
+
+ SXD(primitive_get_attrib(&rwalk->hit.prim, SXD_POSITION, st, &attr));
+
+ fX_set_dX(pos, position);
+ fX(sub)(dir, attr.value, pos);
+ len = fX(normalize)(dir, dir);
+ len = MMIN(len, (float)(delta*0.1));
+
+ XD(move_pos)(position, dir, len);
+}
+#else
+/* Move the submitted position away from the primitive boundaries to avoid
+ * numerical issues leading to inconsistent random walks. */
+static void
+XD(move_away_primitive_boundaries)
+ (const struct XD(rwalk)* rwalk,
+ const double delta,
+ double position[DIM])
+{
+ struct s3d_attrib v0, v1, v2; /* Triangle vertices */
+ float E[3][4]; /* 3D edge equations */
+ float dst[3]; /* Distance from current position to edge equation */
+ float N[3]; /* Triangle normal */
+ float P[3]; /* Random walk position */
+ float tmp[3];
+ float min_dst, max_dst;
+ float cos_a1, cos_a2;
+ float len;
+ int imax = 0;
+ int imin = 0;
+ int imid = 0;
+ int i;
+ ASSERT(rwalk && delta > 0 && !S3D_HIT_NONE(&rwalk->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));
+
+ /* Compute the edge vector */
+ f3_sub(E[0], v1.value, v0.value);
+ f3_sub(E[1], v2.value, v1.value);
+ f3_sub(E[2], v0.value, v2.value);
+
+ /* Compute the triangle normal */
+ f3_cross(N, E[1], E[0]);
+
+ /* Compute the 3D edge equation */
+ f3_normalize(E[0], f3_cross(E[0], E[0], N));
+ f3_normalize(E[1], f3_cross(E[1], E[1], N));
+ f3_normalize(E[2], f3_cross(E[2], E[2], N));
+ E[0][3] = -f3_dot(E[0], v0.value);
+ E[1][3] = -f3_dot(E[1], v1.value);
+ E[2][3] = -f3_dot(E[2], v2.value);
+
+ /* Compute the distance from current position to the edges */
+ dst[0] = f3_dot(E[0], P) + E[0][3];
+ dst[1] = f3_dot(E[1], P) + E[1][3];
+ dst[2] = f3_dot(E[2], P) + E[2][3];
+
+ /* Retrieve the min and max distance from random walk position to triangle
+ * edges */
+ min_dst = MMIN(MMIN(dst[0], dst[1]), dst[2]);
+ max_dst = MMAX(MMAX(dst[0], dst[1]), dst[2]);
+
+ /* Sort the edges with respect to their distance to the random walk position */
+ FOR_EACH(i, 0, 3) {
+ if(dst[i] == min_dst) {
+ imin = i;
+ } else if(dst[i] == max_dst) {
+ imax = i;
+ } else {
+ imid = i;
+ }
+ }
+ (void)imax;
+
+ /* TODO if the current position is near a vertex, one should move toward the
+ * farthest edge along its normal to avoid too small displacement */
+
+ /* Compute the distance `dst' from the current position to the edges to move
+ * to, along the normal of the edge from which the random walk is the nearest
+ *
+ * +. cos(a) = d / dst => dst = d / cos_a
+ * / `*.
+ * / | `*.
+ * / dst| a /`*.
+ * / | / `*.
+ * / | / d `*.
+ * / |/ `*.
+ * +---------o----------------+ */
+ cos_a1 = f3_dot(E[imin], f3_minus(tmp, E[imid]));
+ cos_a2 = f3_dot(E[imin], f3_minus(tmp, E[imax]));
+ dst[imid] = cos_a1 > 0 ? dst[imid] / cos_a1 : FLT_MAX;
+ dst[imax] = cos_a2 > 0 ? dst[imax] / cos_a2 : FLT_MAX;
+
+ /* Compute the maximum displacement distance into the triangle along the
+ * normal of the edge from which the random walk is the nearest */
+ len = MMIN(dst[imid], dst[imax]);
+ ASSERT(len != FLT_MAX);
+
+ /* Define the displacement distance as the minimum between 10 percent of
+ * delta and len / 2. */
+ len = MMIN(len*0.5f, (float)(delta*0.1));
+ XD(move_pos)(position, E[imin], len);
+}
+#endif
+
+static res_T
+XD(find_reinjection_ray)
+ (const struct sdis_scene* scn,
+ const struct XD(find_reinjection_ray_args)* args,
+ struct XD(reinjection_ray)* ray)
+{
+ /* Emperical scale factor applied to the challenged reinjection distance. If
+ * the distance to reinject is less than this adjusted value, the solver will
+ * try to discard the reinjection distance if possible in order to avoid
+ * numerical issues. */
+ const float REINJECT_DST_MIN_SCALE = 0.125f;
+
+ /* # attempts to find a ray direction */
+ int MAX_ATTEMPTS = 1;
+
+ /* Physical properties */
+ struct sdis_interface* interf;
+ struct sdis_medium* mdm0;
+ struct sdis_medium* mdm1;
+
+ struct hit_filter_data filter_data;
+ struct sXd(hit) hit;
+ struct sXd(hit) hit0;
+ struct sXd(hit) hit1;
+ double tmp[DIM];
+ double dst;
+ double dst0;
+ double dst1;
+ const float* dir;
+ float reinject_threshold;
+ double dst_adjusted;
+ float org[DIM];
+ const float range[2] = {0, FLT_MAX};
+ enum sdis_side side;
+ int iattempt = 0;
+ res_T res = RES_OK;
+
+ ASSERT(scn && args && ray);
+ ASSERT(XD(check_find_reinjection_ray_args)(args));
+
+ *ray = XD(REINJECTION_RAY_NULL);
+ MAX_ATTEMPTS = args->can_move ? 2 : 1;
+
+ dst_adjusted = args->distance * RAY_RANGE_MAX_SCALE;
+ reinject_threshold = (float)args->distance * REINJECT_DST_MIN_SCALE;
+
+ dX(set)(ray->org, args->rwalk->vtx.P);
+
+ do {
+ fX_set_dX(org, ray->org);
+ filter_data.XD(hit) = args->rwalk->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)) {
+ 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; }
+ 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)) {
+ 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; }
+ 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(hit0.distance <= dst_adjusted) {
+ dst0 = hit0.distance;
+ } else {
+ dst0 = args->distance;
+ hit0 = SXD_HIT_NULL;
+ }
+ }
+ if(mdm1 == args->solid) { /* Check reinjection consistency */
+ if(hit1.distance <= dst_adjusted) {
+ dst1 = hit1.distance;
+ } else {
+ dst1 = args->distance;
+ hit1 = SXD_HIT_NULL;
+ }
+ }
+
+ /* No valid reinjection. Maybe the random walk is near a sharp corner and
+ * thus the ray-tracing misses the enclosure geometry. Another possibility
+ * is that the random walk lies roughly on an edge. In this case, sampled
+ * reinjection dirs can intersect the primitive on the other side of the
+ * edge. Normally, this primitive should be filtered by the "hit_filter"
+ * function but this may be not the case due to a "threshold effect". In
+ * both situations, try to slightly move away from the primitive boundaries
+ * and retry to find a valid reinjection. */
+ if(dst0 == -1 && dst1 == -1) {
+ XD(move_away_primitive_boundaries)(args->rwalk, args->distance, ray->org);
+ ray->position_was_moved = 1;
+ }
+ } while(dst0 == -1 && dst1 == -1 && ++iattempt < MAX_ATTEMPTS);
+
+ if(dst0 == -1 && dst1 == -1) { /* No valid reinjection */
+#if DIM == 2
+ log_warn(scn->dev, "%s: no valid reinjection direction at {%g, %g}.\n",
+ FUNC_NAME, SPLIT2(ray->org));
+#else
+ log_warn(scn->dev, "%s: no valid reinjection direction at {%g, %g, %g}.\n",
+ FUNC_NAME, SPLIT3(ray->org));
+#endif
+ res = RES_BAD_OP_IRRECOVERABLE;
+ goto error;
+ }
+
+ if(dst0 == -1) {
+ /* Invalid dir0 -> move along dir1 */
+ dir = args->dir1;
+ dst = dst1;
+ hit = hit1;
+ } else if(dst1 == -1) {
+ /* Invalid dir1 -> move along dir0 */
+ dir = args->dir0;
+ dst = dst0;
+ hit = hit0;
+ } else if(dst0 < reinject_threshold && dst1 < reinject_threshold) {
+ /* The displacement along dir0 and dir1 are both below the reinjection
+ * threshold that defines a distance under which the temperature gradients
+ * are ignored. Move along the direction that allows the maximum
+ * displacement. */
+ if(dst0 > dst1) {
+ dir = args->dir0;
+ dst = dst0;
+ hit = hit0;
+ } else {
+ dir = args->dir1;
+ dst = dst1;
+ hit = hit1;
+ }
+ } else if(dst0 < reinject_threshold) {
+ /* Ingore dir0 that is bellow the reinject threshold */
+ dir = args->dir1;
+ dst = dst1;
+ hit = hit1;
+ } else if(dst1 < reinject_threshold) {
+ /* Ingore dir1 that is bellow the reinject threshold */
+ dir = args->dir0;
+ dst = dst0;
+ hit = hit0;
+ } else {
+ /* All reinjection directions are valid. Choose the first 1 that was
+ * randomly selected by the sample_reinjection_dir procedure and adjust
+ * the displacement distance. */
+ dir = args->dir0;
+
+ /* Define the reinjection distance along dir0 and its corresponding hit */
+ if(dst0 <= dst1) {
+ dst = dst0;
+ hit = hit0;
+ } else {
+ dst = dst1;
+ hit = SXD_HIT_NULL;
+ }
+
+ /* If the displacement distance is too close of a boundary, move to the
+ * boundary in order to avoid numerical uncertainty. */
+ if(!SXD_HIT_NONE(&hit0)
+ && dst0 != dst
+ && eq_eps(dst0, dst, dst0*0.1)) {
+ dst = dst0;
+ hit = hit0;
+ }
+ }
+
+ /* Setup the ray */
+ fX(set)(ray->dir, dir);
+ ray->dst = (float)dst;
+ ray->hit = hit;
+
+exit:
+ return res;
+error:
+ goto exit;
+}
+
+static res_T
+XD(find_reinjection_ray_and_check_validity)
+ (const struct sdis_scene* scn,
+ const struct XD(find_reinjection_ray_args)* args,
+ 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));
+
+ /* 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 */
+ XD(move_pos)(dX(set)(pos, ray->org), ray->dir, (float)ray->dst);
+ res = scene_get_medium_in_closed_boundaries(scn, pos, &reinject_mdm);
+ if(res != RES_OK) goto error;
+
+ if(reinject_mdm != args->solid) {
+ res = RES_BAD_OP;
+ goto error;
+ }
+ }
+
+exit:
+ return res;
+error:
+ goto exit;
+}
+
+static res_T
+XD(handle_volumic_power)
+ (struct sdis_medium* solid,
+ struct rwalk_context* rwalk_ctx,
+ struct XD(rwalk)* rwalk,
+ const double reinject_dst_m,
+ struct XD(temperature)* T)
+{
+ double power;
+ double lambda;
+ double power_term;
+ size_t picard_order;
+ res_T res = RES_OK;
+
+ /* Check pre-conditions */
+ ASSERT(solid && rwalk_ctx && rwalk && T && reinject_dst_m > 0);
+
+ /* Fetch the volumic power */
+ power = solid_get_volumic_power(solid, &rwalk->vtx);
+ if(power == SDIS_VOLUMIC_POWER_NONE) goto exit; /* Do nothing */
+
+ /* Currently, the power term can be correctly taken into account only when
+ * the radiative temperature is linearized, i.e. when the picard order is
+ * equal to 1 */
+ picard_order = get_picard_order(rwalk_ctx);
+ if(picard_order > 1) {
+ log_err(solid->dev,
+ "%s: invalid not null volumic power '%g' kg/m^3. Could not manage a "
+ "volumic power when the picard order is not equal to 1; Picard order is "
+ "currently set to %lu.\n",
+ FUNC_NAME, power, (unsigned long)picard_order);
+ res = RES_BAD_ARG;
+ goto error;
+ }
+
+ /* Fetch the conductivity */
+ lambda = solid_get_thermal_conductivity(solid, &rwalk->vtx);
+
+ /* Compute the power term and handle the volumic power */
+ power_term = (reinject_dst_m * reinject_dst_m)/ (2.0 * DIM * lambda);
+ T->value += power * power_term;
+
+ /* Update the green path with the power term */
+ if(rwalk_ctx->green_path) {
+ res = green_path_add_power_term
+ (rwalk_ctx->green_path, solid, &rwalk->vtx, power_term);
+ if(res != RES_OK) goto error;
+ }
+
+exit:
+ return res;
+error:
+ goto exit;
+}
+
+/*******************************************************************************
+ * Local functions
+ ******************************************************************************/
+res_T
+XD(sample_reinjection_step_solid_fluid)
+ (const struct sdis_scene* scn,
+ const struct XD(sample_reinjection_step_args)* args,
+ struct XD(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);
+
+ /* 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;
+
+ /* Miscellaneous variables */
+ float dir0[DIM]; /* Sampled direction */
+ float dir1[DIM]; /* Sampled direction reflected */
+ int iattempt = 0; /* #attempts to find a reinjection dir */
+ res_T res = RES_OK;
+
+ /* Pre-conditions */
+ ASSERT(scn && args && step);
+ ASSERT(XD(check_sample_reinjection_step_args)(args));
+
+ iattempt = 0;
+ do {
+ /* Sample a reinjection direction */
+ XD(sample_reinjection_dir)(args->rwalk, args->rng, dir0);
+
+ /* Reflect the sampled direction around the normal */
+ XD(reflect)(dir1, dir0, args->rwalk->hit.normal);
+
+ /* Flip the sampled directions if one wants to reinject to back side */
+ if(args->side == SDIS_BACK) {
+ fX(minus)(dir0, dir0);
+ fX(minus)(dir1, dir1);
+ }
+
+ /* Find the reinjection step */
+ find_reinject_ray_args.solid = args->solid;
+ find_reinject_ray_args.rwalk = args->rwalk;
+ find_reinject_ray_args.distance = args->distance;
+ find_reinject_ray_args.can_move = 1;
+ fX(set)(find_reinject_ray_args.dir0, dir0);
+ fX(set)(find_reinject_ray_args.dir1, dir1);
+ res = XD(find_reinjection_ray_and_check_validity)
+ (scn, &find_reinject_ray_args, &ray);
+ if(res == RES_BAD_OP) continue; /* Cannot find a valid reinjection ray. Retry */
+ if(res != RES_OK) goto error;
+
+ } while(res != RES_OK && ++iattempt < MAX_ATTEMPTS);
+
+ /* Could not find a valid reinjecton step */
+ if(iattempt >= MAX_ATTEMPTS) {
+ log_warn(scn->dev,
+ "%s: could not find a valid reinjection step at `%g %g %g'.\n",
+ FUNC_NAME, SPLIT3(args->rwalk->vtx.P));
+ res = RES_BAD_OP_IRRECOVERABLE;
+ goto error;
+ }
+
+ /* Setup the reinjection step */
+ step->hit = ray.hit;
+ step->distance = ray.dst;
+ fX(set)(step->direction, ray.dir);
+
+ /* Update the random walk position if necessary */
+ if(ray.position_was_moved) {
+ dX(set)(args->rwalk->vtx.P, ray.org);
+ }
+
+ /* Post-conditions */
+ ASSERT(dX(eq)(args->rwalk->vtx.P, ray.org));
+ ASSERT(XD(check_reinjection_step)(step));
+
+exit:
+ return res;
+error:
+ goto exit;
+}
+
+res_T
+XD(sample_reinjection_step_solid_solid)
+ (const 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)
+{
+ /* Input/output data of the function finding a valid reinjection ray */
+ struct XD(find_reinjection_ray_args) find_reinject_ray_frt_args =
+ XD(FIND_REINJECTION_RAY_ARGS_NULL);
+ struct XD(find_reinjection_ray_args) find_reinject_ray_bck_args =
+ XD(FIND_REINJECTION_RAY_ARGS_NULL);
+ struct XD(reinjection_ray) ray_frt = XD(REINJECTION_RAY_NULL);
+ struct XD(reinjection_ray) ray_bck = XD(REINJECTION_RAY_NULL);
+
+ /* Initial random walk position used as a backup */
+ double rwalk_pos_backup[DIM];
+
+ /* Variables shared by the two side */
+ struct XD(rwalk)* rwalk = NULL;
+ struct ssp_rng* rng = 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;
+
+ 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 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(args_frt->side == SDIS_FRONT);
+ ASSERT(args_bck->side == SDIS_BACK);
+
+ rng = args_frt->rng;
+ rwalk = args_frt->rwalk;
+ ASSERT(args_bck->rng == rng);
+ ASSERT(args_bck->rwalk == rwalk);
+
+ dX(set)(rwalk_pos_backup, rwalk->vtx.P);
+ iattempt = 0;
+ do {
+ /* Restore random walk pos */
+ if(iattempt != 0) dX(set)(rwalk->vtx.P, rwalk_pos_backup);
+
+ /* 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);
+ fX(minus)(dir_bck_samp, dir_frt_samp);
+ fX(minus)(dir_bck_refl, dir_frt_refl);
+
+ /* Find the reinjection ray for the front side */
+ find_reinject_ray_frt_args.solid = args_frt->solid;
+ 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;
+ fX(set)(find_reinject_ray_frt_args.dir0, dir_frt_samp);
+ fX(set)(find_reinject_ray_frt_args.dir1, dir_frt_refl);
+ res = XD(find_reinjection_ray_and_check_validity)
+ (scn, &find_reinject_ray_frt_args, &ray_frt);
+ if(res == RES_BAD_OP) continue;
+ if(res != RES_OK) goto error;
+
+ /* Update the random walk position if necessary */
+ if(ray_frt.position_was_moved) dX(set)(rwalk->vtx.P, ray_frt.org);
+
+ /* Select the reinjection direction and distance for the back side */
+ find_reinject_ray_bck_args.solid = args_bck->solid;
+ 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;
+ fX(set)(find_reinject_ray_bck_args.dir0, dir_bck_samp);
+ fX(set)(find_reinject_ray_bck_args.dir1, dir_bck_refl);
+ res = XD(find_reinjection_ray_and_check_validity)
+ (scn, &find_reinject_ray_bck_args, &ray_bck);
+ if(res == RES_BAD_OP) continue;
+ if(res != RES_OK) goto error;
+
+ /* Update the random walk position if necessary */
+ if(ray_bck.position_was_moved) dX(set)(rwalk->vtx.P, ray_bck.org);
+
+ /* If random walk was moved to find a valid rinjection ray on back side,
+ * one has to find a valid reinjection ob front side from the new pos */
+ 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);
+ if(res == RES_BAD_OP) continue;
+ if(res != RES_OK) goto error;
+
+ /* Update the random walk position if necessary */
+ if(ray_frt.position_was_moved) dX(set)(rwalk->vtx.P, ray_frt.org);
+ }
+ } while(res != RES_OK && ++iattempt < MAX_ATTEMPTS);
+
+ /* Could not find a valid reinjection */
+ if(iattempt >= MAX_ATTEMPTS) {
+ dX(set)(rwalk->vtx.P, rwalk_pos_backup); /* Restore random walk pos */
+ log_warn(scn->dev,
+ "%s: could not find a valid solid/solid reinjection at {%g, %g, %g}.\n",
+ FUNC_NAME, SPLIT3(rwalk->vtx.P));
+ res = RES_BAD_OP_IRRECOVERABLE;
+ goto error;
+ }
+
+ /* Setup the front and back reinjection steps */
+ step_frt->hit = ray_frt.hit;
+ step_bck->hit = ray_bck.hit;
+ step_frt->distance = ray_frt.dst;
+ step_bck->distance = ray_bck.dst;
+ fX(set)(step_frt->direction, ray_frt.dir);
+ fX(set)(step_bck->direction, ray_bck.dir);
+
+ /* Post-conditions */
+ ASSERT(XD(check_reinjection_step)(step_frt));
+ ASSERT(XD(check_reinjection_step)(step_bck));
+
+exit:
+ return res;
+error:
+ goto exit;
+}
+
+res_T
+XD(solid_reinjection)
+ (struct sdis_medium* solid,
+ struct XD(solid_reinjection_args)* args)
+{
+ struct solid_props props = SOLID_PROPS_NULL;
+ double reinject_dst_m; /* Reinjection distance in meters */
+ double mu;
+ res_T res = RES_OK;
+ ASSERT(solid && XD(check_solid_reinjection_args)(args));
+
+ reinject_dst_m = args->reinjection->distance * args->fp_to_meter;
+
+ res = solid_get_properties(solid, &args->rwalk->vtx, &props);
+ if(res != RES_OK) goto error;
+
+ /* Manage the volumic power */
+ res = XD(handle_volumic_power)
+ (solid, args->rwalk_ctx, args->rwalk, reinject_dst_m, args->T);
+ if(res != RES_OK) goto error;
+
+ /* Time rewind */
+ args->rwalk->mdm = solid; /* Medium 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);
+ if(res != RES_OK) goto error;
+
+ /* Test if a limit condition was reached */
+ if(args->T->done) goto exit;
+
+ /* Move the random walk to the reinjection position */
+ XD(move_pos)
+ (args->rwalk->vtx.P,
+ args->reinjection->direction,
+ args->reinjection->distance);
+
+ /* The random walk is in the solid */
+ if(args->reinjection->hit.distance != args->reinjection->distance) {
+ args->T->func = XD(conductive_path);
+ args->rwalk->mdm = solid;
+ args->rwalk->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->hit_side = SDIS_FRONT;
+ } else {
+ args->rwalk->hit_side = SDIS_BACK;
+ }
+ }
+
+ /* Register the new vertex against the heat path */
+ res = register_heat_vertex
+ (args->rwalk_ctx->heat_path,
+ &args->rwalk->vtx,
+ args->T->value,
+ SDIS_HEAT_VERTEX_CONDUCTION,
+ (int)args->rwalk_ctx->nbranchings);
+ if(res != RES_OK) goto error;
+
+exit:
+ return res;
+error:
+ goto exit;
+}
+
+#include "sdis_Xd_end.h"
diff --git a/src/sdis_heat_path_boundary_Xd_fixed_flux.h b/src/sdis_heat_path_boundary_Xd_fixed_flux.h
@@ -0,0 +1,135 @@
+/* Copyright (C) 2016-2022 |Meso|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_green.h"
+#include "sdis_heat_path_boundary_c.h"
+#include "sdis_interface_c.h"
+#include "sdis_log.h"
+#include "sdis_medium_c.h"
+#include "sdis_misc.h"
+#include "sdis_scene_c.h"
+
+#include <star/ssp.h>
+
+#include "sdis_Xd_begin.h"
+
+/*******************************************************************************
+ * Boundary path between a solid and a fluid with a fixed flux
+ ******************************************************************************/
+res_T
+XD(solid_boundary_with_flux_path)
+ (struct sdis_scene* scn,
+ struct rwalk_context* ctx,
+ const struct sdis_interface_fragment* frag,
+ const double phi,
+ struct XD(rwalk)* rwalk,
+ struct ssp_rng* rng,
+ struct XD(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);
+
+ /* Reinjection arguments */
+ struct XD(solid_reinjection_args) solid_reinject_args =
+ XD(SOLID_REINJECTION_ARGS_NULL);
+
+ /* Data attached to the boundary */
+ struct sdis_interface* interf = NULL;
+ struct sdis_medium* solid = NULL;
+
+ /* Miscellaneous variables */
+ double lambda; /* Solid conductivity */
+ double delta_boundary; /* Orthogonal reinjection dst at the boundary */
+ double delta; /* Orthogonal fitted reinjection dst at the boundary */
+ double delta_m; /* Delta in meters */
+ double flux_term;
+ size_t picard_order;
+ enum sdis_side solid_side = SDIS_SIDE_NULL__;
+ res_T res = RES_OK;
+
+ ASSERT(frag && phi != SDIS_FLUX_NONE);
+ ASSERT(XD(check_rwalk_fragment_consistency)(rwalk, frag));
+ (void)ctx;
+
+ /* Currently, the flux can be correctly taken into account only when the
+ * radiative temperature is linearized, i.e. when the picard order is equal
+ * to 1 */
+ picard_order = get_picard_order(ctx);
+ if(picard_order > 1 && phi != 0) {
+ log_err(scn->dev,
+ "%s: invalid flux '%g' W/m^2. Could not manage a flux != 0 when the "
+ "picard order is not equal to 1; Picard order is currently set to %lu.\n",
+ FUNC_NAME, phi, (unsigned long)picard_order);
+ res = RES_BAD_ARG;
+ goto error;
+ }
+
+ /* Retrieve the solid split by the interface */
+ interf = scene_get_interface(scn, rwalk->hit.prim.prim_id);
+ solid = interface_get_medium(interf, frag->side);
+ solid_side = frag->side;
+ ASSERT(phi == interface_side_get_flux(interf, frag));
+ ASSERT(solid->type == SDIS_SOLID);
+
+ /* Fetch the solid properties */
+ lambda = solid_get_thermal_conductivity(solid, &rwalk->vtx);
+ delta = solid_get_delta(solid, &rwalk->vtx);
+
+ /* Note that the reinjection distance is *FIXED*. It MUST ensure that the
+ * orthogonal distance from the boundary to the reinjection point is at most
+ * equal to delta. */
+ delta_boundary = delta * sqrt(DIM);
+
+ /* Sample a reinjection step */
+ samp_reinject_step_args.rng = rng;
+ samp_reinject_step_args.solid = solid;
+ samp_reinject_step_args.rwalk = rwalk;
+ samp_reinject_step_args.distance = delta_boundary;
+ samp_reinject_step_args.side = solid_side;
+ res = XD(sample_reinjection_step_solid_fluid)
+ (scn, &samp_reinject_step_args, &reinject_step);
+ if(res != RES_OK) goto error;
+
+ /* Define the orthogonal dst from the boundary to the reinjection position */
+ delta = reinject_step.distance / sqrt(DIM);
+ delta_m = delta * scn->fp_to_meter;
+
+ /* Handle the flux */
+ flux_term = delta_m / lambda;
+ T->value += phi * flux_term;
+ if(ctx->green_path) {
+ res = green_path_add_flux_term(ctx->green_path, interf, frag, flux_term);
+ if(res != RES_OK) goto error;
+ }
+
+ /* Perform the reinjection into the solid */
+ solid_reinject_args.reinjection = &reinject_step;
+ solid_reinject_args.rwalk_ctx = ctx;
+ solid_reinject_args.rwalk = rwalk;
+ 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);
+ if(res != RES_OK) goto error;
+
+exit:
+ return res;
+error:
+ goto exit;
+}
+
+#include "sdis_Xd_end.h"
diff --git a/src/sdis_heat_path_boundary_Xd_solid_fluid_picard1.h b/src/sdis_heat_path_boundary_Xd_solid_fluid_picard1.h
@@ -1,4 +1,4 @@
-/* Copyright (C) 2016-2021 |Meso|Star> (contact@meso-star.com)
+/* Copyright (C) 2016-2022 |Meso|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
@@ -25,176 +25,238 @@
#include "sdis_Xd_begin.h"
/*******************************************************************************
+ * Helper functions
+ ******************************************************************************/
+static INLINE res_T
+XD(check_Tref)
+ (const struct sdis_scene* scn,
+ const double pos[DIM],
+ const double Tref,
+ const char* func_name)
+{
+ ASSERT(scn && pos && func_name);
+
+#if DIM == 2
+ #define STR_VECX "%g %g"
+ #define SPLITX SPLIT2
+#else
+ #define STR_VECX "%g %g %g"
+ #define SPLITX SPLIT3
+#endif
+ if(Tref < 0) {
+ log_err(scn->dev,
+ "%s: invalid reference temperature `%gK' at the position `"STR_VECX"'.\n",
+ func_name, Tref, SPLITX(pos));
+ return RES_BAD_OP_IRRECOVERABLE;
+ }
+ if(Tref > scn->tmax) {
+ log_err(scn->dev,
+ "%s: invalid maximum temperature `%gK'. The reference temperature `%gK'"
+ "at the position `"STR_VECX"' is greater than this temperature.\n",
+ func_name, scn->tmax, Tref, SPLITX(pos));
+ return RES_BAD_OP_IRRECOVERABLE;
+ }
+#undef STR_VECX
+#undef SPLITX
+
+ return RES_OK;
+}
+
+static INLINE res_T
+XD(rwalk_get_Tref)
+ (const struct sdis_scene* scn,
+ const struct XD(rwalk)* rwalk,
+ const struct XD(temperature)* T,
+ double* out_Tref)
+{
+ double Tref = -1;
+ res_T res = RES_OK;
+ ASSERT(rwalk && T && out_Tref);
+
+ if(T->done) {
+ /* The path reaches a limit condition, i.e. it goes to the infinity and
+ * fetches the ambient radiative temperature. We do not use the limit
+ * conditions as the reference temperature to make the sampled paths
+ * independant of them. */
+ Tref = scn->trad.reference;
+ } else {
+ struct sdis_interface_fragment frag;
+ struct sdis_interface* interf = NULL;
+ ASSERT(!SXD_HIT_NONE(&rwalk->hit));
+
+ /* Fetch the interface where the random walk ends */
+ interf = scene_get_interface(scn, rwalk->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);
+
+ Tref = interface_side_get_reference_temperature(interf, &frag);
+ }
+
+ res = XD(check_Tref)(scn, rwalk->vtx.P, Tref, FUNC_NAME);
+ if(res != RES_OK) goto error;
+
+exit:
+ *out_Tref = Tref;
+ return res;
+error:
+ Tref = -1;
+ goto exit;
+}
+
+/*******************************************************************************
* Boundary path between a solid and a fluid
******************************************************************************/
res_T
XD(solid_fluid_boundary_picard1_path)
- (const struct sdis_scene* scn,
- const struct rwalk_context* ctx,
+ (struct sdis_scene* scn,
+ struct rwalk_context* ctx,
const struct sdis_interface_fragment* frag,
struct XD(rwalk)* rwalk,
struct ssp_rng* rng,
struct XD(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);
+
+ /* Temperature and random walk state of the sampled radiative path */
+ struct XD(temperature) T_s;
+ struct XD(rwalk) rwalk_s;
+
+ /* Fragment on the fluid side of the boundary */
+ struct sdis_interface_fragment frag_fluid;
+
+ /* Data attached to the boundary */
struct sdis_interface* interf = NULL;
- struct sdis_medium* mdm_front = NULL;
- struct sdis_medium* mdm_back = NULL;
struct sdis_medium* solid = NULL;
struct sdis_medium* fluid = NULL;
- struct XD(rwalk) rwalk_saved;
- struct sXd(hit) hit = SXD_HIT_NULL;
- struct sdis_interface_fragment frag_fluid;
- double hc;
- double hr;
+
+ double h_cond; /* Conductive coefficient */
+ double h_conv; /* Convective coefficient */
+ double h_radi_hat; /* Radiative coefficient with That */
+ double h_hat; /* Sum of h_<conv|cond|rad_hat> */
+ double p_conv; /* Convective proba */
+ double p_cond; /* Conductive proba */
+
double epsilon; /* Interface emissivity */
- double lambda;
- double fluid_proba;
- double radia_proba;
- double delta;
- double delta_boundary;
+ double Tref; /* Reference temperature */
+ double Tref_s; /* Reference temperature of the sampled radiative path */
+ double lambda; /* Solid conductivity */
+ double delta_boundary; /* Orthogonal reinjection dst at the boundary */
+ double delta; /* Orthogonal fitted reinjection dst at the boundary */
+
double r;
- double tmp;
- float dir0[DIM], dir1[DIM];
- float reinject_dst;
- /* 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;
- int iattempt;
- int reinjection_is_valid = 0;
+ struct sdis_heat_vertex hvtx = SDIS_HEAT_VERTEX_NULL;
+ enum sdis_side solid_side = SDIS_SIDE_NULL__;
+ enum sdis_side fluid_side = SDIS_SIDE_NULL__;
res_T res = RES_OK;
+
ASSERT(scn && rwalk && rng && T && ctx);
ASSERT(XD(check_rwalk_fragment_consistency)(rwalk, frag));
/* Retrieve the solid and the fluid split by the boundary */
interf = scene_get_interface(scn, rwalk->hit.prim.prim_id);
- mdm_front = interface_get_medium(interf, SDIS_FRONT);
- mdm_back = interface_get_medium(interf, SDIS_BACK);
- ASSERT(mdm_front->type != mdm_back->type);
-
- /* Setup the fluid side fragment */
- frag_fluid = *frag;
- if(mdm_front->type == SDIS_SOLID) {
- solid = mdm_front;
- fluid = mdm_back;
- frag_fluid.side = SDIS_BACK;
- } else {
- solid = mdm_back;
- fluid = mdm_front;
- frag_fluid.side = SDIS_FRONT;
+ solid = interface_get_medium(interf, SDIS_FRONT);
+ fluid = interface_get_medium(interf, SDIS_BACK);
+ solid_side = SDIS_FRONT;
+ fluid_side = SDIS_BACK;
+ if(solid->type != SDIS_SOLID) {
+ SWAP(struct sdis_medium*, solid, fluid);
+ SWAP(enum sdis_side, solid_side, fluid_side);
+ ASSERT(fluid->type == SDIS_FLUID);
}
- /* Fetch the boundary properties */
- epsilon = interface_side_get_emissivity(interf, &frag_fluid);
- Tref = interface_side_get_reference_temperature(interf, &frag_fluid);
+ /* Setup a fragment for the fluid side */
+ frag_fluid = *frag;
+ frag_fluid.side = fluid_side;
/* Fetch the solid properties */
lambda = solid_get_thermal_conductivity(solid, &rwalk->vtx);
delta = solid_get_delta(solid, &rwalk->vtx);
- /* Note that the reinjection distance is *FIXED*. It MUST ensure that the
- * orthogonal distance from the boundary to the point to chalenge is equal to
- * delta. */
- delta_boundary = sqrt(DIM) * delta;
-
- rwalk_saved = *rwalk;
- reinjection_is_valid = 0;
- iattempt = 0;
- do {
- if(iattempt != 0) *rwalk = rwalk_saved;
-
- /* Sample a reinjection direction */
- XD(sample_reinjection_dir)(rwalk, rng, dir0);
-
- /* Reflect the sampled direction around the normal */
- XD(reflect)(dir1, dir0, rwalk->hit.normal);
-
- if(solid == mdm_back) {
- fX(minus)(dir0, dir0);
- fX(minus)(dir1, dir1);
- }
+ /* Fetch the boundary emissivity */
+ epsilon = interface_side_get_emissivity(interf, &frag_fluid);
- /* Select the solid reinjection direction and distance */
- res = XD(select_reinjection_dir_and_check_validity)(scn, solid, rwalk,
- dir0, dir1, delta_boundary, dir0, &reinject_dst, 1, NULL,
- &reinjection_is_valid, &hit);
+ if(epsilon <= 0) {
+ Tref = 0;
+ } else {
+ /* Check the Tref */
+ Tref = interface_side_get_reference_temperature(interf, &frag_fluid);
+ res = XD(check_Tref)(scn, frag_fluid.P, Tref, FUNC_NAME);
if(res != RES_OK) goto error;
+ }
- } while(!reinjection_is_valid && ++iattempt < MAX_ATTEMPTS);
+ /* Note that the reinjection distance is *FIXED*. It MUST ensure that the
+ * orthogonal distance from the boundary to the reinjection point is at most
+ * equal to delta. */
+ delta_boundary = sqrt(DIM) * delta;
- /* Could not find a valid reinjecton */
- if(iattempt >= MAX_ATTEMPTS) {
- *rwalk = rwalk_saved;
- log_warn(scn->dev,
- "%s: could not find a valid solid/fluid reinjection at {%g, %g %g}.\n",
- FUNC_NAME, SPLIT3(rwalk->vtx.P));
- res = RES_BAD_OP_IRRECOVERABLE;
- goto error;
- }
+ /* Sample a reinjection step */
+ samp_reinject_step_args.rng = rng;
+ samp_reinject_step_args.solid = solid;
+ samp_reinject_step_args.rwalk = rwalk;
+ samp_reinject_step_args.distance = delta_boundary;
+ samp_reinject_step_args.side = solid_side;
+ res = XD(sample_reinjection_step_solid_fluid)
+ (scn, &samp_reinject_step_args, &reinject_step);
+ if(res != RES_OK) goto error;
/* Define the orthogonal dst from the reinjection pos to the interface */
- delta = reinject_dst / sqrt(DIM);
+ delta = reinject_step.distance / sqrt(DIM);
/* Compute the convective, conductive and the upper bound radiative coef */
h_conv = interface_get_convection_coef(interf, frag);
h_cond = lambda / (delta * scn->fp_to_meter);
- h_rad_hat = 4.0 * BOLTZMANN_CONSTANT * ctx->That3 * epsilon;
-
+ h_radi_hat = 4.0 * BOLTZMANN_CONSTANT * ctx->That3 * epsilon;
+
/* Compute a global upper bound coefficient */
- h_hat = h_conv + h_cond + h_rad_hat;
+ h_hat = h_conv + h_cond + h_radi_hat;
/* Compute the probas to switch in solid, fluid or radiative random walk */
p_conv = h_conv / h_hat;
p_cond = h_cond / h_hat;
+ /* Fetch the last registered heat path vertex */
+ if(ctx->heat_path) hvtx = *heat_path_get_last_vertex(ctx->heat_path);
+
/* Null collision */
for(;;) {
- r = ssp_rng_canonical(rng);
+ double h_radi; /* Radiative coefficient */
+ double p_radi; /* Radiative proba */
+
+ /* Indices of the registered vertex of the sampled radiative path */
+ size_t ihvtx_radi_begin = 0;
+ size_t ihvtx_radi_end = 0;
+
+ r = ssp_rng_canonical(rng);
/* Switch in convective path */
if(r < p_conv) {
T->func = XD(convective_path);
rwalk->mdm = fluid;
- rwalk->hit_side = rwalk->mdm == mdm_front ? SDIS_FRONT : SDIS_BACK;
+ rwalk->hit_side = fluid_side;
break;
}
/* Switch in conductive path */
if(r < p_conv + p_cond) {
- /* Handle the volumic power */
- const double power = solid_get_volumic_power(solid, &rwalk->vtx);
- if(power != SDIS_VOLUMIC_POWER_NONE) {
- const double delta_in_meter = reinject_dst * scn->fp_to_meter;
- tmp = delta_in_meter * delta_in_meter / (2.0 * DIM * lambda);
- T->value += power * tmp;
-
- if(ctx->green_path) {
- res = green_path_add_power_term(ctx->green_path, solid, &rwalk->vtx, tmp);
- if(res != RES_OK) goto error;
- }
- }
-
- /* Time rewind */
- res = XD(time_rewind)(solid, rng, reinject_dst * scn->fp_to_meter, ctx, rwalk, T);
- if(res != RES_OK) goto error;
- if(T->done) goto exit; /* Limit condition was reached */
-
- /* Perform solid reinjection */
- XD(move_pos)(rwalk->vtx.P, dir0, reinject_dst);
- if(hit.distance == reinject_dst) {
- T->func = XD(boundary_path);
- rwalk->mdm = NULL;
- rwalk->hit = hit;
- rwalk->hit_side = fX(dot)(hit.normal, dir0) < 0 ? SDIS_FRONT : SDIS_BACK;
- } else {
- T->func = XD(conductive_path);
- rwalk->mdm = solid;
- rwalk->hit = SXD_HIT_NULL;
- rwalk->hit_side = SDIS_SIDE_NULL__;
- }
-
- /* Register the new vertex against the heat path */
- res = register_heat_vertex
- (ctx->heat_path, &rwalk->vtx, T->value, SDIS_HEAT_VERTEX_CONDUCTION);
+ struct XD(solid_reinjection_args) solid_reinject_args =
+ XD(SOLID_REINJECTION_ARGS_NULL);
+
+ /* Perform the reinjection into the solid */
+ solid_reinject_args.reinjection = &reinject_step;
+ solid_reinject_args.rwalk_ctx = ctx;
+ solid_reinject_args.rwalk = rwalk;
+ 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);
if(res != RES_OK) goto error;
break;
}
@@ -202,47 +264,56 @@ XD(solid_fluid_boundary_picard1_path)
/* From there, we know the path is either a radiative path or a
* null-collision */
- /* Trace a candidate radiative path and get the Tref at its end.
- * TODO handle the registration of the path geometry */
- T_candidate = *T;
- rwalk_candidate = *rwalk;
- res = XD(radiative_path)(scn, ctx, &rwalk_candidate, rng, T_candidate);
+ if(ctx->heat_path) {
+ /* Fetch the index of the first vertex of the radiative path that is
+ * going to be traced i.e. the last registered vertex */
+ ihvtx_radi_begin = heat_path_get_vertices_count(ctx->heat_path) - 1;
+ }
+
+ /* Sample a radiative path and get the Tref at its end. */
+ T_s = *T;
+ rwalk_s = *rwalk;
+ rwalk_s.mdm = fluid;
+ rwalk_s.hit_side = fluid_side;
+ res = XD(radiative_path)(scn, ctx, &rwalk_s, rng, &T_s);
if(res != RES_OK) goto error;
/* Get the Tref at the end of the candidate radiative path */
- if(T_candidate->done) {
- Tref_candidate = T_candidate->value;
- } else {
- ASSERT(!SXD_HIT_NONE(rwalk_candidate->hit));
- XD(setup_interface_fragment)
- (&frag_candidate, &rwalk_candidate->vtx, &rwalk_candidate->hit,
- rwalk_candidate->hit_side);
- interf_candidate = scene_get_interface
- (scn, rwalk_candidate->hit.prim.prim_id);
-
- Tref_candidate = interface_side_get_reference_temperature(interf, f&rag);
- }
+ res = XD(rwalk_get_Tref)(scn, &rwalk_s, &T_s, &Tref_s);
+ if(res != RES_OK) goto error;
- if(Tref_candidate < 0) {
- log_err(scn->dev,
- "%s: invalid reference temperature `%gK' at the position `%g %g %g'.\n",
- FUNC_NAME, Tref_candidate, SPLIT3(rwalk_candidate->vtx.P));
- res = RES_BAD_OP_IRRECOVERABLE;
- goto error;
- }
+ h_radi = BOLTZMANN_CONSTANT * epsilon *
+ ( Tref*Tref*Tref
+ + Tref*Tref * Tref_s
+ + Tref * Tref_s*Tref_s
+ + Tref_s*Tref_s*Tref_s);
- h_rad = BOLTZMANN_CONSTANT
- * epsilon
- * ( Tref*Tref*Tref
- + Tref*Tref * Tref_candidate
- + Tref* Tref_candidate*Tref_candidate
- + Tref_candidate*Tref_candidate*Tref_candidate);
-
- p_rad = h_rad / h_hat;
- if(r < p_conv + p_cond + p_rad) { /* Radiative path */
- *rwalk = *rwalk_candidate;
- *T = *T_candidate;
+ p_radi = h_radi / h_hat;
+ if(r < p_conv + p_cond + p_radi) { /* Radiative path */
+ *rwalk = rwalk_s;
+ *T = T_s;
break;
+
+ /* Null collision: the sampled path is rejected. */
+ } else {
+
+ if(ctx->green_path) {
+ /* The limit condition of the green path could be set by the rejected
+ * sampled radiative path. Reset this limit condition. */
+ green_path_reset_limit(ctx->green_path);
+ }
+
+ if(ctx->heat_path) {
+ /* Set the sampled radiative path as a branch of the current path */
+ ihvtx_radi_end = heat_path_get_vertices_count(ctx->heat_path);
+ heat_path_increment_sub_path_branch_id
+ (ctx->heat_path, ihvtx_radi_begin, ihvtx_radi_end);
+
+ /* Add a break into the heat path geometry and restart it from the
+ * position of the input random walk. */
+ res = heat_path_restart(ctx->heat_path, &hvtx);
+ if(res != RES_OK) goto error;
+ }
}
/* Null-collision, looping at the beginning */
diff --git a/src/sdis_heat_path_boundary_Xd_solid_fluid_picardN.h b/src/sdis_heat_path_boundary_Xd_solid_fluid_picardN.h
@@ -0,0 +1,365 @@
+/* Copyright (C) 2016-2022 |Meso|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_green.h"
+#include "sdis_heat_path_boundary_c.h"
+#include "sdis_interface_c.h"
+#include "sdis_medium_c.h"
+#include "sdis_misc.h"
+#include "sdis_realisation.h"
+#include "sdis_scene_c.h"
+
+#include <star/ssp.h>
+
+#include "sdis_Xd_begin.h"
+
+/*******************************************************************************
+ * Generic helper functions
+ ******************************************************************************/
+static INLINE res_T
+XD(sample_path)
+ (struct sdis_scene* scn,
+ const struct XD(rwalk)* rwalk_from,
+ struct rwalk_context* ctx,
+ struct ssp_rng* rng,
+ struct XD(temperature)* T)
+{
+ struct XD(rwalk) rwalk = XD(RWALK_NULL);
+ res_T res = RES_OK;
+ ASSERT(rwalk_from && rng && T);
+
+ /* Clean-up the output variable */
+ *T = XD(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.hit_side = rwalk_from->hit_side;
+
+ /* Start the registration of a new heat path */
+ if(ctx->heat_path) {
+ struct sdis_heat_vertex heat_vtx = SDIS_HEAT_VERTEX_NULL;
+
+ heat_vtx.P[0] = rwalk.vtx.P[0];
+ heat_vtx.P[1] = rwalk.vtx.P[1];
+ heat_vtx.P[2] = rwalk.vtx.P[2];
+ heat_vtx.time = rwalk.vtx.time;
+ heat_vtx.weight = 0;
+ heat_vtx.type = SDIS_HEAT_VERTEX_RADIATIVE;
+ heat_vtx.branch_id = (int)ctx->nbranchings + 1;
+
+ res = heat_path_restart(ctx->heat_path, &heat_vtx);
+ if(res != RES_OK) goto error;
+ }
+
+ /* Sample the path */
+ res = XD(compute_temperature)(scn, ctx, &rwalk, rng, T);
+ if(res != RES_OK) goto error;
+
+ /* Check the returned temperature */
+ ASSERT(T->done);
+ if(T->value < scn->tmin || scn->tmax < T->value) {
+ log_err(scn->dev, "%s: invalid temperature range `[%g, %g]K` regarding the "
+ "retrieved temperature %gK.\n", FUNC_NAME, scn->tmin, scn->tmax, T->value);
+ res = RES_BAD_OP_IRRECOVERABLE;
+ goto error;
+ }
+
+exit:
+ return res;
+error:
+ goto exit;
+}
+
+/*******************************************************************************
+ * Boundary path between a solid and a fluid
+ ******************************************************************************/
+res_T
+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 ssp_rng* rng,
+ struct XD(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);
+
+ /* Fragment on the fluid side of the boundary */
+ struct sdis_interface_fragment frag_fluid;
+
+ /* Vertex of the heat path */
+ struct sdis_heat_vertex hvtx = SDIS_HEAT_VERTEX_NULL;
+ struct sdis_heat_vertex hvtx_s = SDIS_HEAT_VERTEX_NULL;
+
+ /* Data attached to the boundary */
+ struct sdis_interface* interf = NULL;
+ struct sdis_medium* solid = NULL;
+ struct sdis_medium* fluid = NULL;
+
+ double h_cond; /* Conductive coefficient */
+ double h_conv; /* Convective coefficient */
+ double h_radi_hat; /* Radiative coefficient with That */
+ double h_hat; /* Sum of h_<conv|cond|rad_hat> */
+ double p_conv; /* Convective proba */
+ double p_cond; /* Conductive proba */
+
+ /* Min/Max Temperatures */
+ double Tmin, Tmin2, Tmin3;
+ double That, That2, That3;
+
+ double epsilon; /* Interface emissivity */
+ double lambda; /* Solid conductivity */
+ double delta_boundary; /* Orthogonal reinjection dst at the boundary */
+ double delta; /* Orthogonal fitted reinjection dst at the boundary */
+
+ double r;
+ enum sdis_side solid_side = SDIS_SIDE_NULL__;
+ enum sdis_side fluid_side = SDIS_SIDE_NULL__;
+ res_T res = RES_OK;
+
+ ASSERT(scn && rwalk && rng && T && ctx);
+ ASSERT(XD(check_rwalk_fragment_consistency)(rwalk, frag));
+
+ /* Fetch the Min/max temperature */
+ Tmin = ctx->Tmin;
+ Tmin2 = ctx->Tmin2;
+ Tmin3 = ctx->Tmin3;
+ That = ctx->That;
+ That2 = ctx->That2;
+ That3 = ctx->That3;
+
+ /* Retrieve the solid and the fluid split by the boundary */
+ interf = scene_get_interface(scn, rwalk->hit.prim.prim_id);
+ solid = interface_get_medium(interf, SDIS_FRONT);
+ fluid = interface_get_medium(interf, SDIS_BACK);
+ solid_side = SDIS_FRONT;
+ fluid_side = SDIS_BACK;
+ if(solid->type != SDIS_SOLID) {
+ SWAP(struct sdis_medium*, solid, fluid);
+ SWAP(enum sdis_side, solid_side, fluid_side);
+ ASSERT(fluid->type == SDIS_FLUID);
+ }
+
+ /* Setup a fragment for the fluid side */
+ frag_fluid = *frag;
+ frag_fluid.side = fluid_side;
+
+ /* Fetch the solid properties */
+ lambda = solid_get_thermal_conductivity(solid, &rwalk->vtx);
+ delta = solid_get_delta(solid, &rwalk->vtx);
+
+ /* Fetch the boundary emissivity */
+ epsilon = interface_side_get_emissivity(interf, &frag_fluid);
+
+ /* Note that the reinjection distance is *FIXED*. It MUST ensure that the
+ * orthogonal distance from the boundary to the reinjection point is at most
+ * equal to delta. */
+ delta_boundary = sqrt(DIM) * delta;
+
+ /* Sample a reinjection step */
+ samp_reinject_step_args.rng = rng;
+ samp_reinject_step_args.solid = solid;
+ samp_reinject_step_args.rwalk = rwalk;
+ samp_reinject_step_args.distance = delta_boundary;
+ samp_reinject_step_args.side = solid_side;
+ res = XD(sample_reinjection_step_solid_fluid)
+ (scn, &samp_reinject_step_args, &reinject_step);
+ if(res != RES_OK) goto error;
+
+ /* Define the orthogonal dst from the reinjection pos to the interface */
+ delta = reinject_step.distance / sqrt(DIM);
+
+ /* Compute the convective, conductive and the upper bound radiative coef */
+ h_conv = interface_get_convection_coef(interf, frag);
+ h_cond = lambda / (delta * scn->fp_to_meter);
+ h_radi_hat = 4.0 * BOLTZMANN_CONSTANT * That3 * epsilon;
+
+ /* Compute a global upper bound coefficient */
+ h_hat = h_conv + h_cond + h_radi_hat;
+
+ /* Compute the probas to switch in convection or conduction */
+ p_conv = h_conv / h_hat;
+ p_cond = h_cond / h_hat;
+
+ /* Fetch the last registered heat path vertex */
+ if(ctx->heat_path) hvtx = *heat_path_get_last_vertex(ctx->heat_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;
+
+ double h_radi, h_radi_min, h_radi_max; /* Radiative coefficients */
+ double p_radi, p_radi_min, p_radi_max; /* Radiative probas */
+ double T0, T1, T2, T3, T4, T5; /* Computed temperatures */
+
+ /* Indices of the registered vertex of the sampled radiative path */
+ size_t ihvtx_radi_begin = 0;
+ size_t ihvtx_radi_end = 0;
+
+ r = ssp_rng_canonical(rng);
+
+ /* Switch in convective path */
+ if(r < p_conv) {
+ T->func = XD(convective_path);
+ rwalk->mdm = fluid;
+ 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);
+
+ /* Perform the reinjection into the solid */
+ solid_reinject_args.reinjection = &reinject_step;
+ solid_reinject_args.rwalk_ctx = ctx;
+ solid_reinject_args.rwalk = rwalk;
+ 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);
+ if(res != RES_OK) goto error;
+ break;
+ }
+
+ if(ctx->heat_path) {
+ /* Fetch the index of the first vertex of the radiative path that is
+ * going to be traced i.e. the last registered vertex */
+ ihvtx_radi_begin = heat_path_get_vertices_count(ctx->heat_path) - 1;
+ }
+
+ /* Sample a radiative path */
+ T_s = *T;
+ rwalk_s = *rwalk;
+ rwalk_s.mdm = fluid;
+ rwalk_s.hit_side = fluid_side;
+ res = XD(radiative_path)(scn, ctx, &rwalk_s, rng, &T_s);
+ if(res != RES_OK) goto error;
+
+ if(ctx->heat_path) {
+ /* Fetch the index after the last registered vertex of the sampled
+ * radiative path */
+ ihvtx_radi_end = heat_path_get_vertices_count(ctx->heat_path);
+ }
+
+ /* Fetch the last registered heat path vertex of the radiative path */
+ if(ctx->heat_path) hvtx_s = *heat_path_get_last_vertex(ctx->heat_path);
+
+ h_radi_min = 4.0 * BOLTZMANN_CONSTANT * Tmin3 * epsilon;
+ p_radi_min = h_radi_min / h_hat;
+
+ /* Switch in radiative path */
+ if(r < p_conv + p_cond + p_radi_min) { *rwalk = rwalk_s; *T = T_s; break; }
+
+ /* Define some helper macros */
+ #define SWITCH_IN_RADIATIVE { \
+ *rwalk = rwalk_s; *T = T_s; \
+ res = heat_path_restart(ctx->heat_path, &hvtx_s); \
+ if(res != RES_OK) goto error; \
+ } (void)0
+
+ #define NULL_COLLISION { \
+ res = heat_path_restart(ctx->heat_path, &hvtx); \
+ if(res != RES_OK) goto error; \
+ if(ctx->heat_path) { \
+ heat_path_increment_sub_path_branch_id \
+ (ctx->heat_path, ihvtx_radi_begin, ihvtx_radi_end); \
+ } \
+ } (void)0
+
+ #define COMPUTE_TEMPERATURE(Result, RWalk, Temp) { \
+ struct XD(temperature) T_p; \
+ if((Temp)->done) { /* Ambient radiative temperature */ \
+ ASSERT(SXD_HIT_NONE(&(RWalk)->hit)); \
+ T_p = *(Temp); \
+ } else { \
+ res = XD(sample_path)(scn, RWalk, ctx, rng, &T_p); \
+ if(res != RES_OK) goto error; \
+ } \
+ Result = T_p.value; \
+ } (void)0
+
+ #define CHECK_PMIN_PMAX { \
+ p_radi_min = h_radi_min*epsilon / h_hat; \
+ p_radi_max = h_radi_max*epsilon / h_hat; \
+ if(r < p_conv + p_cond + p_radi_min) { SWITCH_IN_RADIATIVE; break; } \
+ if(r > p_conv + p_cond + p_radi_max) { NULL_COLLISION; continue; } \
+ } (void)0
+
+ /* Sample a 1st heat path at the end of the radiative path */
+ COMPUTE_TEMPERATURE(T0, &rwalk_s, &T_s);
+ h_radi_min = BOLTZMANN_CONSTANT*(Tmin3 + 3*Tmin2*T0);
+ h_radi_max = BOLTZMANN_CONSTANT*(That3 + 3*That2*T0);
+ CHECK_PMIN_PMAX;
+
+ /* Sample a 2nd heat path at the end of the radiative path */
+ COMPUTE_TEMPERATURE(T1, &rwalk_s, &T_s);
+ h_radi_min = BOLTZMANN_CONSTANT*(Tmin3 + Tmin2*T0 + 2*Tmin*T0*T1);
+ h_radi_max = BOLTZMANN_CONSTANT*(That3 + That2*T0 + 2*That*T0*T1);
+ CHECK_PMIN_PMAX;
+
+ /* Sample a 3rd heat path at the end of the radiative path */
+ COMPUTE_TEMPERATURE(T2, &rwalk_s, &T_s);
+ h_radi_min = BOLTZMANN_CONSTANT*(Tmin3 + Tmin2*T0 + Tmin*T0*T1 + T0*T1*T2);
+ h_radi_max = BOLTZMANN_CONSTANT*(That3 + That2*T0 + That*T0*T1 + T0*T1*T2);
+ CHECK_PMIN_PMAX;
+
+ /* Sample a 1st heat path at the current position onto the interface */
+ COMPUTE_TEMPERATURE(T3, rwalk, T);
+ h_radi_min = BOLTZMANN_CONSTANT*(Tmin2*T3 + Tmin*T0*T3 + T0*T1*T3 + T0*T1*T2);
+ h_radi_max = BOLTZMANN_CONSTANT*(That2*T3 + That*T0*T3 + T0*T1*T3 + T0*T1*T2);
+ CHECK_PMIN_PMAX;
+
+ /* Sample a 2nd heat path at the current position onto the interface */
+ COMPUTE_TEMPERATURE(T4, rwalk, T);
+ h_radi_min = BOLTZMANN_CONSTANT*(Tmin*T3*T4 + T0*T3*T4 + T0*T1*T3 + T0*T1*T2);
+ h_radi_max = BOLTZMANN_CONSTANT*(That*T3*T4 + T0*T3*T4 + T0*T1*T3 + T0*T1*T2);
+ CHECK_PMIN_PMAX;
+
+ /* Sample a 3rd heat path at the current position onto the interface */
+ COMPUTE_TEMPERATURE(T5, rwalk, T);
+ h_radi = BOLTZMANN_CONSTANT*(T3*T4*T5 + T0*T3*T4 + T0*T1*T3 + T0*T1*T2);
+ p_radi = h_radi * epsilon / h_hat;
+
+ /* Switch in radiative path */
+ if(r < p_cond + p_conv + p_radi) { SWITCH_IN_RADIATIVE; break; }
+
+ /* Null-collision, looping at the beginning */
+ NULL_COLLISION;
+
+ #undef SWITCH_IN_RADIATIVE
+ #undef NULL_COLLISION
+ #undef COMPUTE_TEMPERATURE
+ #undef CHECK_PMIN_PMAX
+ }
+
+exit:
+ return res;
+error:
+ goto exit;
+}
+
+#include "sdis_Xd_end.h"
+
diff --git a/src/sdis_heat_path_boundary_Xd_solid_solid.h b/src/sdis_heat_path_boundary_Xd_solid_solid.h
@@ -0,0 +1,175 @@
+/* Copyright (C) 2016-2022 |Meso|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_green.h"
+#include "sdis_heat_path_boundary_c.h"
+#include "sdis_interface_c.h"
+#include "sdis_log.h"
+#include "sdis_medium_c.h"
+#include "sdis_misc.h"
+#include "sdis_scene_c.h"
+
+#include <star/ssp.h>
+
+#include "sdis_Xd_begin.h"
+
+/*******************************************************************************
+ * Boundary path between a solid and a fluid
+ ******************************************************************************/
+res_T
+XD(solid_solid_boundary_path)
+ (struct sdis_scene* scn,
+ struct rwalk_context* ctx,
+ const struct sdis_interface_fragment* frag,
+ struct XD(rwalk)* rwalk,
+ struct ssp_rng* rng,
+ struct XD(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;
+
+ /* Reinjection arguments */
+ struct XD(solid_reinjection_args) solid_reinject_args =
+ XD(SOLID_REINJECTION_ARGS_NULL);
+
+ /* Data attached to the boundary */
+ struct sdis_interface* interf = NULL;
+ struct sdis_medium* solid_frt = NULL;
+ struct sdis_medium* solid_bck = NULL;
+ struct sdis_medium* solid = NULL;
+
+ double lambda_frt;
+ double lambda_bck;
+ double delta_boundary_frt;
+ double delta_boundary_bck;
+
+ double proba;
+ double r;
+ double tcr;
+
+ res_T res = RES_OK;
+ ASSERT(scn && ctx && frag && rwalk && rng && T);
+ ASSERT(XD(check_rwalk_fragment_consistency)(rwalk, frag));
+ (void)frag, (void)ctx;
+
+ /* Retrieve the two solids split by the boundary */
+ interf = scene_get_interface(scn, rwalk->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);
+ ASSERT(solid_bck->type == SDIS_SOLID);
+
+ /* Retrieve the thermal contact resistance */
+ tcr = interface_get_thermal_contact_resistance(interf, frag);
+
+ /* Fetch the properties of the media */
+ lambda_frt = solid_get_thermal_conductivity(solid_frt, &rwalk->vtx);
+ lambda_bck = solid_get_thermal_conductivity(solid_bck, &rwalk->vtx);
+
+ /* Note that the reinjection distance is *FIXED*. It MUST ensure that the
+ * orthogonal distance from the boundary to the reinjection point is at most
+ * equal to delta. */
+ delta_boundary_frt = solid_get_delta(solid_frt, &rwalk->vtx) * sqrt(DIM);
+ delta_boundary_bck = solid_get_delta(solid_bck, &rwalk->vtx) * sqrt(DIM);
+
+ /* 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.rwalk = rwalk;
+ samp_reinject_step_bck_args.rwalk = rwalk;
+ samp_reinject_step_frt_args.distance = delta_boundary_frt;
+ samp_reinject_step_bck_args.distance = delta_boundary_bck;
+ samp_reinject_step_frt_args.side = SDIS_FRONT;
+ samp_reinject_step_bck_args.side = SDIS_BACK;
+ res = XD(sample_reinjection_step_solid_solid)
+ (scn,
+ &samp_reinject_step_frt_args,
+ &samp_reinject_step_bck_args,
+ &reinject_step_frt,
+ &reinject_step_bck);
+ if(res != RES_OK) goto error;
+
+ r = ssp_rng_canonical(rng);
+ if(tcr == 0) { /* No thermal contact resistance */
+ /* Define the reinjection side. Note that the proba should be : Lf/Df' /
+ * (Lf/Df' + Lb/Db')
+ *
+ * with L<f|b> the lambda of the <front|back> side and D<f|b>' the adjusted
+ * delta of the <front|back> side, i.e. : D<f|b>' =
+ * reinject_dst_<front|back> / sqrt(DIM)
+ *
+ * Anyway, one can avoid to compute the adjusted delta by directly using the
+ * adjusted reinjection distance since the resulting proba is strictly the
+ * same; sqrt(DIM) can be simplified. */
+ const double tmp_frt = lambda_frt / reinject_step_frt.distance;
+ const double tmp_bck = lambda_bck / reinject_step_bck.distance;
+ proba = tmp_frt / (tmp_frt + tmp_bck);
+ } else {
+ const double delta_frt = reinject_step_frt.distance/sqrt(DIM);
+ const double delta_bck = reinject_step_bck.distance/sqrt(DIM);
+ const double tmp_frt = lambda_frt/delta_frt;
+ const double tmp_bck = lambda_bck/delta_bck;
+ const double tmp_tcr = tcr*tmp_frt*tmp_bck;
+ switch(rwalk->hit_side) {
+ case SDIS_BACK:
+ /* When coming from the BACK side, the probability to be reinjected on
+ * the FRONT side depends on the thermal contact resistance: it
+ * decreases when the TCR increases (and tends to 0 when TCR -> +inf) */
+ proba = tmp_frt / (tmp_frt + tmp_bck + tmp_tcr);
+ break;
+ case SDIS_FRONT:
+ /* Same thing when coming from the FRONT side: the probability of
+ * reinjection on the FRONT side depends on the thermal contact
+ * resistance: it increases when the TCR increases (and tends to 1 when
+ * the TCR -> +inf) */
+ proba = (tmp_frt + tmp_tcr) / (tmp_frt + tmp_bck + tmp_tcr);
+ break;
+ default: FATAL("Unreachable code.\n"); break;
+ }
+ }
+
+ if(r < proba) { /* Reinject in front */
+ reinject_step = &reinject_step_frt;
+ solid = solid_frt;
+ } else { /* Reinject in back */
+ reinject_step = &reinject_step_bck;
+ solid = solid_bck;
+ }
+
+ /* Perform the reinjection into the solid */
+ solid_reinject_args.reinjection = reinject_step;
+ solid_reinject_args.rng = rng;
+ solid_reinject_args.rwalk = rwalk;
+ 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);
+ if(res != RES_OK) goto error;
+
+exit:
+ return res;
+error:
+ goto exit;
+}
+
+#include "sdis_Xd_end.h"
diff --git a/src/sdis_heat_path_boundary_c.h b/src/sdis_heat_path_boundary_c.h
@@ -0,0 +1,219 @@
+/* Copyright (C) 2016-2022 |Meso|Star> (contact@meso-star.com)
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+#ifndef SDIS_HEAT_PATH_BOUNDARY_C_H
+#define SDIS_HEAT_PATH_BOUNDARY_C_H
+
+#include <star/s2d.h>
+#include <star/s3d.h>
+#include <rsys/rsys.h>
+
+/* Forward declarations */
+struct rwalk_2d;
+struct rwalk_3d;
+struct sdis_scene;
+struct sdis_medium;
+
+/*******************************************************************************
+ * Sample a reinjection step
+ ******************************************************************************/
+struct sample_reinjection_step_args_2d {
+ 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 */
+ double distance; /* Maximum Reinjection distance */
+ 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 */
+};
+
+struct reinjection_step_3d {
+ struct s3d_hit hit; /* 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;
+
+extern LOCAL_SYM res_T
+sample_reinjection_step_solid_fluid_2d
+ (const struct sdis_scene* scn,
+ const struct sample_reinjection_step_args_2d* args,
+ struct reinjection_step_2d* step);
+
+extern LOCAL_SYM res_T
+sample_reinjection_step_solid_fluid_3d
+ (const struct sdis_scene* scn,
+ const struct sample_reinjection_step_args_3d* args,
+ struct reinjection_step_3d *step);
+
+extern LOCAL_SYM res_T
+sample_reinjection_step_solid_solid_2d
+ (const 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);
+
+extern LOCAL_SYM res_T
+sample_reinjection_step_solid_solid_3d
+ (const 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);
+
+/*******************************************************************************
+ * Reinject the random walk into a solid
+ ******************************************************************************/
+struct solid_reinjection_args_2d {
+ const struct reinjection_step_2d* reinjection; /* Reinjection to do */
+ struct rwalk_context* rwalk_ctx;
+ struct rwalk_2d* rwalk; /* Current state of the random walk */
+ struct ssp_rng* rng; /* Random number generator */
+ struct temperature_2d* 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;
+
+extern LOCAL_SYM res_T
+solid_reinjection_2d
+ (struct sdis_medium* solid,
+ struct solid_reinjection_args_2d* args);
+
+extern LOCAL_SYM res_T
+solid_reinjection_3d
+ (struct sdis_medium* solid,
+ struct solid_reinjection_args_3d* args);
+
+/*******************************************************************************
+ * Boundary sub-paths
+ ******************************************************************************/
+extern LOCAL_SYM res_T
+solid_boundary_with_flux_path_2d
+ (struct sdis_scene* scn,
+ struct rwalk_context* ctx,
+ const struct sdis_interface_fragment* frag,
+ const double phi,
+ struct rwalk_2d* rwalk,
+ struct ssp_rng* rng,
+ struct temperature_2d* T);
+
+extern LOCAL_SYM res_T
+solid_boundary_with_flux_path_3d
+ (struct sdis_scene* scn,
+ struct rwalk_context* ctx,
+ const struct sdis_interface_fragment* frag,
+ const double phi,
+ struct rwalk_3d* rwalk,
+ struct ssp_rng* rng,
+ struct temperature_3d* 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 ssp_rng* rng,
+ struct temperature_2d* 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 ssp_rng* rng,
+ struct temperature_3d* 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 ssp_rng* rng,
+ struct temperature_2d* 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 ssp_rng* rng,
+ struct temperature_3d* 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 ssp_rng* rng,
+ struct temperature_2d* 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 ssp_rng* rng,
+ struct temperature_3d* T);
+
+#endif /* SDIS_HEAT_PATH_BOUNDARY_C_H */
diff --git a/src/sdis_heat_path_conductive_Xd.h b/src/sdis_heat_path_conductive_Xd.h
@@ -1,4 +1,4 @@
-/* Copyright (C) 2016-2021 |Meso|Star> (contact@meso-star.com)
+/* Copyright (C) 2016-2022 |Meso|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
@@ -25,6 +25,63 @@
#include "sdis_Xd_begin.h"
/*******************************************************************************
+ * Non generic helper function
+ ******************************************************************************/
+#ifndef SDIS_HEAT_PATH_CONDUCTIVE_XD_H
+#define SDIS_HEAT_PATH_CONDUCTIVE_XD_H
+
+static res_T
+check_solid_constant_properties
+ (struct sdis_device* dev,
+ const int evaluate_green,
+ const struct solid_props* props_ref,
+ const struct solid_props* props)
+{
+ res_T res = RES_OK;
+ ASSERT(dev && props_ref && props);
+
+ if(props_ref->lambda != props->lambda) {
+ log_err(dev,
+ "%s: invalid thermal conductivity. One assumes a constant conductivity "
+ "for the whole solid.\n", FUNC_NAME);
+ res = RES_BAD_ARG;
+ goto error;
+ }
+
+ if(props_ref->rho != props->rho) {
+ log_err(dev,
+ "%s: invalid volumic mass. One assumes a constant volumic mass for "
+ "the whole solid.\n", FUNC_NAME);
+ res = RES_BAD_ARG;
+ goto error;
+ }
+
+ if(props_ref->cp != props->cp) {
+ log_err(dev,
+ "%s: invalid calorific capacity. One assumes a constant calorific "
+ "capacity for the whole solid.\n", FUNC_NAME);
+ res = RES_BAD_ARG;
+ goto error;
+ }
+
+ if(evaluate_green && props_ref->power != props->power) {
+ log_err(dev,
+ "%s: invalid volumic power. When estimating the green function, a "
+ "constant volumic power is assumed for the whole solid.\n",
+ FUNC_NAME);
+ res = RES_BAD_ARG;
+ goto error;
+ }
+
+exit:
+ return res;
+error:
+ goto exit;
+}
+
+#endif /* SDIS_HEAT_PATH_CONDUCTIVE_XD_H */
+
+/*******************************************************************************
* Helper functions
******************************************************************************/
/* Sample the next direction to walk toward and compute the distance to travel.
@@ -193,20 +250,155 @@ error:
goto exit;
}
+
+/*******************************************************************************
+ * Handle the volumic power at a given diffusive step
+ ******************************************************************************/
+struct XD(handle_volumic_power_args) {
+ /* Forward/backward direction of the sampled diffusive step */
+ const float* dir0;
+ const float* dir1;
+
+ /* Forward/backward intersections along the sampled diffusive step */
+ const struct sXd(hit)* hit0;
+ const struct sXd(hit)* hit1;
+
+ /* Physical properties */
+ double power; /* Volumic power */
+ double lambda; /* Conductivity */
+
+ float delta_solid; /* Challenged length of a diffusive step */
+ float delta; /* Current length of the current diffusive step */
+
+ size_t picard_order;
+};
+static const struct XD(handle_volumic_power_args)
+XD(HANDLE_VOLUMIC_POWER_ARGS_NULL) = {
+ NULL, NULL, NULL, NULL, -1, -1, -1, -1, 0
+};
+
+static INLINE int
+XD(check_handle_volumic_power_args)
+ (const struct XD(handle_volumic_power_args)* args)
+{
+ ASSERT(args);
+ return args
+ && args->dir0
+ && args->dir1
+ && args->hit0
+ && args->hit1
+ && args->lambda >= 0
+ && args->delta_solid > 0
+ && args->delta >= 0
+ && args->delta_solid >= 0
+ && args->picard_order > 0;
+}
+
+static res_T
+XD(handle_volumic_power)
+ (const struct sdis_scene* scn,
+ const struct XD(handle_volumic_power_args)* args,
+ double* out_power_term,
+ struct XD(temperature)* T)
+{
+ double power_term = 0;
+ res_T res = RES_OK;
+ ASSERT(scn && out_power_term && T && XD(check_handle_volumic_power_args)(args));
+
+ /* No volumic power. Do nothing */
+ if(args->power == SDIS_VOLUMIC_POWER_NONE) goto exit;
+
+ /* Check that picardN is not enabled when a volumic power is set since in
+ * this situation the upper bound of the Monte-Carlo weight required by
+ * picardN cannot be known */
+ if(args->picard_order > 1) {
+ log_err(scn->dev,
+ "%s: invalid not null volumic power '%g' kg/m^3. Could not manage a "
+ "volumic power when the picard order is not equal to 1; Picard order is "
+ "currently set to %lu.\n",
+ FUNC_NAME, args->power, (unsigned long)args->picard_order);
+ res = RES_BAD_ARG;
+ goto error;
+ }
+
+ /* No forward/backward intersection along the sampled direction */
+ if(SXD_HIT_NONE(args->hit0) && SXD_HIT_NONE(args->hit1)) {
+ const double delta_in_meter = args->delta * scn->fp_to_meter;
+ power_term = delta_in_meter * delta_in_meter / (2.0 * DIM * args->lambda);
+ T->value += args->power * power_term;
+
+ /* An intersection along this diffusive step is find. Use it to statically
+ * correct the power term currently registered */
+ } else {
+ const double delta_s_adjusted = args->delta_solid * RAY_RANGE_MAX_SCALE;
+ const double delta_s_in_meter = args->delta_solid * scn->fp_to_meter;
+ double h;
+ double h_in_meter;
+ double cos_U_N;
+ float N[DIM];
+
+ if(args->delta == args->hit0->distance) {
+ fX(normalize)(N, args->hit0->normal);
+ cos_U_N = fX(dot)(args->dir0, N);
+
+ } else {
+ ASSERT(args->delta == args->hit1->distance);
+ fX(normalize)(N, args->hit1->normal);
+ cos_U_N = fX(dot)(args->dir1, N);
+ }
+
+ h = args->delta * fabs(cos_U_N);
+ h_in_meter = h * scn->fp_to_meter;
+
+ /* The regular power term */
+ power_term = h_in_meter * h_in_meter / (2.0*args->lambda);
+
+ /* Add the power corrective term. Be careful to use the adjusted
+ * delta_solid to correctly handle the RAY_RANGE_MAX_SCALE factor in the
+ * computation of the limit angle. But keep going with the unmodified
+ * delta_solid in the corrective term since it was the one that was
+ * "wrongly" used in the previous step and that must be corrected. */
+ if(h == delta_s_adjusted) {
+ power_term +=
+ -(delta_s_in_meter * delta_s_in_meter) / (2.0*DIM*args->lambda);
+
+ } else if(h < delta_s_adjusted) {
+ const double sin_a = h / delta_s_adjusted;
+#if DIM==2
+ /* tmp = sin(2a) / (PI - 2*a) */
+ const double tmp = sin_a * sqrt(1 - sin_a*sin_a) / acos(sin_a);
+ power_term +=
+ -(delta_s_in_meter * delta_s_in_meter) / (4.0*args->lambda) * tmp;
+#else
+ const double tmp = (sin_a*sin_a*sin_a - sin_a) / (1-sin_a);
+ power_term +=
+ (delta_s_in_meter * delta_s_in_meter) / (6.0*args->lambda) * tmp;
+#endif
+ }
+ T->value += args->power * power_term;
+ }
+
+exit:
+ *out_power_term = power_term;
+ return res;
+error:
+ goto exit;
+}
+
/*******************************************************************************
* Local function
******************************************************************************/
res_T
XD(conductive_path)
(struct sdis_scene* scn,
- const struct rwalk_context* ctx,
+ struct rwalk_context* ctx,
struct XD(rwalk)* rwalk,
struct ssp_rng* rng,
struct XD(temperature)* T)
{
double position_start[DIM];
- double green_power_factor = 0;
- double power_ref = SDIS_VOLUMIC_POWER_NONE;
+ struct solid_props props_ref = SOLID_PROPS_NULL;
+ double green_power_term = 0;
struct sdis_medium* mdm;
size_t istep = 0; /* Help for debug */
res_T res = RES_OK;
@@ -217,7 +409,7 @@ XD(conductive_path)
/* Check the random walk consistency */
res = scene_get_medium_in_closed_boundaries(scn, rwalk->vtx.P, &mdm);
if(res != RES_OK || mdm != rwalk->mdm) {
- log_warn(scn->dev, "%s: invalid solid random walk. "
+ log_err(scn->dev, "%s: invalid solid random walk. "
"Unexpected medium at {%g, %g, %g}.\n", FUNC_NAME, SPLIT3(rwalk->vtx.P));
res = RES_BAD_OP_IRRECOVERABLE;
goto error;
@@ -225,27 +417,41 @@ XD(conductive_path)
/* Save the submitted position */
dX(set)(position_start, rwalk->vtx.P);
- if(ctx->green_path) {
- /* Retrieve the power of the medium. Use it to check that it is effectively
- * constant along the random walk */
- power_ref = solid_get_volumic_power(mdm, &rwalk->vtx);
- }
+ /* Retrieve the solid properties at the current position. Use them to verify
+ * that those that are supposed to be constant by the conductive random walk
+ * remain the same. Note that we take care of the same constraints on the
+ * solid reinjection since once reinjected, the position of the random walk
+ * is that at the beginning of the conductive random walkh. Thus, after a
+ * reinjection, the next line retrieves the properties of the reinjection
+ * position. By comparing them to the properties along the random walk, we
+ * thus verify that the properties are constant throughout the random walk
+ * with respect to the properties of the reinjected position. */
+ solid_get_properties(mdm, &rwalk->vtx, &props_ref);
do { /* Solid random walk */
+ struct XD(handle_volumic_power_args) handle_volpow_args =
+ XD(HANDLE_VOLUMIC_POWER_ARGS_NULL);
struct sXd(hit) hit0, hit1;
- double lambda; /* Thermal conductivity */
- double tmp;
- double power_factor = 0;
- double power;
- float delta, delta_solid; /* Random walk numerical parameter */
+ struct solid_props props = SOLID_PROPS_NULL;
+ double power_term = 0;
+ double mu;
+ float delta; /* Random walk numerical parameter */
+ double delta_m;
float dir0[DIM], dir1[DIM];
float org[DIM];
+ /* Fetch solid properties */
+ res = solid_get_properties(mdm, &rwalk->vtx, &props);
+ if(res != RES_OK) goto error;
+
+ res = check_solid_constant_properties
+ (scn->dev, ctx->green_path != NULL, &props_ref, &props);
+ if(res != RES_OK) goto error;
+
/* Check the limit condition
* REVIEW Rfo: This can be a bug if the random walk comes from a boundary */
- tmp = solid_get_temperature(mdm, &rwalk->vtx);
- if(tmp >= 0) {
- T->value += tmp;
+ if(props.temperature >= 0) {
+ T->value += props.temperature;
T->done = 1;
if(ctx->green_path) {
@@ -261,88 +467,36 @@ XD(conductive_path)
break;
}
- /* Fetch solid properties */
- delta_solid = (float)solid_get_delta(mdm, &rwalk->vtx);
- lambda = solid_get_thermal_conductivity(mdm, &rwalk->vtx);
- power = solid_get_volumic_power(mdm, &rwalk->vtx);
-
- if(ctx->green_path && power_ref != power) {
- log_err(scn->dev,
- "%s: invalid non constant volumic power term. Expecting a constant "
- "volumic power in time and space on green function estimation.\n",
- FUNC_NAME);
- res = RES_BAD_ARG;
- goto error;
- }
-
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, delta_solid,
- dir0, dir1, &hit0, &hit1, &delta);
+ res = XD(sample_next_step_robust)(scn, mdm, rng, rwalk->vtx.P,
+ (float)props.delta, dir0, dir1, &hit0, &hit1, &delta);
if(res != RES_OK) goto error;
/* Add the volumic power density to the measured temperature */
- if(power != SDIS_VOLUMIC_POWER_NONE) {
- if((S3D_HIT_NONE(&hit0) && S3D_HIT_NONE(&hit1))) { /* Hit nothing */
- const double delta_in_meter = delta * scn->fp_to_meter;
- power_factor = delta_in_meter * delta_in_meter / (2.0 * DIM * lambda);
- T->value += power * power_factor;
- } else {
- const double delta_s_adjusted = delta_solid * RAY_RANGE_MAX_SCALE;
- const double delta_s_in_meter = delta_solid * scn->fp_to_meter;
- double h;
- double h_in_meter;
- double cos_U_N;
- float N[DIM];
-
- if(delta == hit0.distance) {
- fX(normalize)(N, hit0.normal);
- cos_U_N = fX(dot)(dir0, N);
- } else {
- ASSERT(delta == hit1.distance);
- fX(normalize)(N, hit1.normal);
- cos_U_N = fX(dot)(dir1, N);
- }
-
- h = delta * fabs(cos_U_N);
- h_in_meter = h * scn->fp_to_meter;
-
- /* The regular power term at wall */
- tmp = h_in_meter * h_in_meter / (2.0 * lambda);
-
- /* Add the power corrective term. Be careful to use the adjusted
- * delta_solid to correctly handle the RAY_RANGE_MAX_SCALE factor in
- * the computation of the limit angle. But keep going with the
- * unmodified delta_solid in the corrective term since it was the one
- * that was "wrongly" used in the previous step and that must be
- * corrected. */
- if(h == delta_s_adjusted) {
- tmp += -(delta_s_in_meter * delta_s_in_meter)/(2.0*DIM*lambda);
- } else if(h < delta_s_adjusted) {
- const double sin_a = h / delta_s_adjusted;
-#if DIM==2
- /* tmp1 = sin(2a) / (PI - 2*a) */
- const double tmp1 = sin_a * sqrt(1 - sin_a*sin_a)/acos(sin_a);
- tmp += -(delta_s_in_meter * delta_s_in_meter)/(4.0*lambda) * tmp1;
-#else
- const double tmp1 = (sin_a*sin_a*sin_a - sin_a)/ (1-sin_a);
- tmp += (delta_s_in_meter * delta_s_in_meter)/(6.0*lambda) * tmp1;
-#endif
- }
- power_factor = tmp;
- T->value += power * power_factor;
- }
- }
+ handle_volpow_args.dir0 = dir0;
+ handle_volpow_args.dir1 = dir1;
+ handle_volpow_args.hit0 = &hit0;
+ handle_volpow_args.hit1 = &hit1;
+ handle_volpow_args.power = props.power;
+ handle_volpow_args.lambda = props.lambda;
+ handle_volpow_args.delta_solid = (float)props.delta;
+ handle_volpow_args.delta = delta;
+ handle_volpow_args.picard_order = get_picard_order(ctx);
+ res = XD(handle_volumic_power)(scn, &handle_volpow_args, &power_term, T);
+ if(res != RES_OK) goto error;
/* Register the power term for the green function. Delay its registration
* until the end of the conductive path, i.e. the path is valid */
- if(ctx->green_path && power != SDIS_VOLUMIC_POWER_NONE) {
- green_power_factor += power_factor;
+ if(ctx->green_path && props.power != SDIS_VOLUMIC_POWER_NONE) {
+ green_power_term += power_term;
}
/* Rewind the time */
- res = XD(time_rewind)(rwalk->mdm, rng, delta * scn->fp_to_meter, ctx, rwalk, T);
+ delta_m = delta * scn->fp_to_meter;
+ mu = (2*DIM*props.lambda)/(props.rho*props.cp*delta_m*delta_m);
+ res = XD(time_rewind)(mu, props.t0, rng, rwalk, ctx, T);
if(res != RES_OK) goto error;
if(T->done) break; /* Limit condition was reached */
@@ -359,8 +513,8 @@ XD(conductive_path)
XD(move_pos)(rwalk->vtx.P, dir0, delta);
/* Register the new vertex against the heat path */
- res = register_heat_vertex
- (ctx->heat_path, &rwalk->vtx, T->value, SDIS_HEAT_VERTEX_CONDUCTION);
+ res = register_heat_vertex(ctx->heat_path, &rwalk->vtx, T->value,
+ SDIS_HEAT_VERTEX_CONDUCTION, (int)ctx->nbranchings);
if(res != RES_OK) goto error;
++istep;
@@ -369,9 +523,9 @@ XD(conductive_path)
} while(SXD_HIT_NONE(&rwalk->hit));
/* Register the power term for the green function */
- if(ctx->green_path && power_ref != SDIS_VOLUMIC_POWER_NONE) {
+ 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_factor);
+ (ctx->green_path, rwalk->mdm, &rwalk->vtx, green_power_term);
if(res != RES_OK) goto error;
}
diff --git a/src/sdis_heat_path_convective_Xd.h b/src/sdis_heat_path_convective_Xd.h
@@ -1,4 +1,4 @@
-/* Copyright (C) 2016-2021 |Meso|Star> (contact@meso-star.com)
+/* Copyright (C) 2016-2022 |Meso|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
@@ -24,12 +24,51 @@
#include "sdis_Xd_begin.h"
/*******************************************************************************
+ * Non generic helper functions
+ ******************************************************************************/
+#ifndef SDIS_HEAT_PATH_CONVECTIVE_XD_H
+#define SDIS_HEAT_PATH_CONVECTIVE_XD_H
+
+static res_T
+check_fluid_constant_properties
+ (struct sdis_device* dev,
+ const struct fluid_props* props_ref,
+ const struct fluid_props* props)
+{
+ res_T res = RES_OK;
+ ASSERT(dev && props_ref && props);
+
+ if(props_ref->rho != props->rho) {
+ log_err(dev,
+ "%s: invalid volumic mass. One assumes a constant volumic mass for "
+ "the whole fluid.\n", FUNC_NAME);
+ res = RES_BAD_ARG;
+ goto error;
+ }
+
+ if(props_ref->cp != props->cp) {
+ log_err(dev,
+ "%s: invalid calorific capacity. One assumes a constant calorific "
+ "capacity for the whole fluid.\n", FUNC_NAME);
+ res = RES_BAD_ARG;
+ goto error;
+ }
+
+exit:
+ return res;
+error:
+ goto exit;
+}
+
+#endif /* SDIS_HEAT_PATH_CONVECTIVE_XD_H */
+
+/*******************************************************************************
* Helper functions
******************************************************************************/
static res_T
XD(register_heat_vertex_in_fluid)
(struct sdis_scene* scn,
- const struct rwalk_context* ctx,
+ struct rwalk_context* ctx,
struct XD(rwalk)* rwalk,
const double weight)
{
@@ -60,88 +99,105 @@ XD(register_heat_vertex_in_fluid)
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);
+ return register_heat_vertex(ctx->heat_path, &vtx, weight,
+ SDIS_HEAT_VERTEX_CONVECTION, (int)ctx->nbranchings);
}
-/*******************************************************************************
- * Local functions
- ******************************************************************************/
-res_T
-XD(convective_path)
+static res_T
+XD(handle_known_fluid_temperature)
(struct sdis_scene* scn,
- const struct rwalk_context* ctx,
+ struct rwalk_context* ctx,
struct XD(rwalk)* rwalk,
- struct ssp_rng* rng,
struct XD(temperature)* T)
{
- struct sXd(attrib) attr_P, attr_N;
- const struct sdis_interface* interf;
- const struct enclosure* enc;
- unsigned enc_ids[2];
- unsigned enc_id;
- double rho; /* Volumic mass */
- double hc; /* Convection coef */
- double cp; /* Calorific capacity */
- double tmp;
- double r;
- int path_started_in_fluid;
-#if SDIS_XD_DIMENSION == 2
- float st;
-#else
- float st[2];
-#endif
+ double temperature;
+ int known_temperature;
res_T res = RES_OK;
- (void)rng, (void)ctx;
- ASSERT(scn && ctx && rwalk && rng && T);
- ASSERT(rwalk->mdm->type == SDIS_FLUID);
+ ASSERT(scn && ctx && rwalk && T);
+ ASSERT(sdis_medium_get_type(rwalk->mdm) == SDIS_FLUID);
- tmp = fluid_get_temperature(rwalk->mdm, &rwalk->vtx);
- if(tmp >= 0) { /* T is known. */
- T->value += tmp;
- T->done = 1;
+ temperature = fluid_get_temperature(rwalk->mdm, &rwalk->vtx);
- 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;
- }
+ /* Check if the temperature is known */
+ known_temperature = temperature >= 0;
+ if(!known_temperature) goto exit;
- res = XD(register_heat_vertex_in_fluid)(scn, ctx, rwalk, T->value);
- if(res != RES_OK) goto error;
+ T->value += temperature;
+ T->done = 1;
- goto exit;
+ 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;
}
- path_started_in_fluid = SXD_HIT_NONE(&rwalk->hit);
- if(path_started_in_fluid) { /* The path begins in the fluid */
- const float range[2] = {FLT_MIN, FLT_MAX};
- float dir[DIM] = {0};
- float org[DIM];
+ res = XD(register_heat_vertex_in_fluid)(scn, ctx, rwalk, T->value);
+ if(res != RES_OK) goto error;
+
+exit:
+ return res;
+error:
+ goto exit;
+}
- dir[DIM-1] = 1;
- fX_set_dX(org, rwalk->vtx.P);
+static res_T
+XD(handle_convective_path_startup)
+ (struct sdis_scene* scn,
+ struct XD(rwalk)* rwalk,
+ int* path_starts_in_fluid)
+{
+ const float range[2] = {FLT_MIN, FLT_MAX};
+ float dir[DIM] = {0};
+ 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);
- /* 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));
+ *path_starts_in_fluid = SXD_HIT_NONE(&rwalk->hit);
+ if(*path_starts_in_fluid == 0) goto exit; /* Nothing to do */
- if(SXD_HIT_NONE(&rwalk->hit)) {
- log_err(scn->dev,
-"%s: the position %g %g %g lies in the surrounding fluid whose temperature must \n"
-"be known.\n", FUNC_NAME, SPLIT3(rwalk->vtx.P));
- res = RES_BAD_OP;
- goto error;
- }
+ dir[DIM-1] = 1;
+ fX_set_dX(org, rwalk->vtx.P);
- rwalk->hit_side = fX(dot)(rwalk->hit.normal, dir) < 0 ? SDIS_FRONT : SDIS_BACK;
+ /* 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)) {
+ 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));
+ res = RES_BAD_OP;
+ goto error;
}
+ rwalk->hit_side = fX(dot)(rwalk->hit.normal, dir) < 0 ? SDIS_FRONT : SDIS_BACK;
+
+exit:
+ return res;
+error:
+ goto exit;
+}
+
+static res_T
+XD(fetch_fluid_enclosure)
+ (struct sdis_scene* scn,
+ struct XD(rwalk)* rwalk,
+ const struct enclosure** out_enclosure)
+{
+ 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);
- /* Define the enclosure identifier of the current medium */
+ /* 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];
@@ -159,91 +215,101 @@ XD(convective_path)
* the external enclosure. In this situation unknown temperature is
* forbidden. */
log_err(scn->dev,
-"%s: invalid enclosure. The surrounding fluid has an unset temperature.\n",
+ "%s: invalid enclosure. The surrounding fluid has an unset temperature.\n",
FUNC_NAME);
res = RES_BAD_ARG;
goto error;
}
+exit:
+ *out_enclosure = enc;
+ return res;
+error:
+ enc = NULL;
+ goto exit;
+}
+
+/*******************************************************************************
+ * Local functions
+ ******************************************************************************/
+res_T
+XD(convective_path)
+ (struct sdis_scene* scn,
+ struct rwalk_context* ctx,
+ struct XD(rwalk)* rwalk,
+ struct ssp_rng* rng,
+ struct XD(temperature)* T)
+{
+ struct sXd(attrib) attr_P, attr_N;
+ struct fluid_props props_ref = FLUID_PROPS_NULL;
+ const struct sdis_interface* interf;
+ const struct enclosure* enc;
+ double r;
+#if SDIS_XD_DIMENSION == 2
+ float st;
+#else
+ float st[2];
+#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);
+
+ res = XD(handle_known_fluid_temperature)(scn, ctx, rwalk, T);
+ if(res != RES_OK) goto error;
+ if(T->done) goto exit; /* The fluid temperature is known */
+
+ /* Setup the missing random walk member variables when the convective path
+ * starts from the fluid */
+ 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);
+ if(res != RES_OK) goto error;
+
/* The hc upper bound can be 0 if h is uniformly 0. In that case the result
* is the initial condition. */
if(enc->hc_upper_bound == 0) {
- /* Cannot be in the fluid without starting there. */
- ASSERT(path_started_in_fluid);
-
- rwalk->vtx.time = fluid_get_t0(rwalk->mdm);
- tmp = fluid_get_temperature(rwalk->mdm, &rwalk->vtx);
- if(tmp >= 0) {
- T->value += tmp;
- T->done = 1;
- goto exit;
+ 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);
+ if(res != RES_OK) goto error;
+ if(T->done) {
+ goto exit; /* Stop the random walk */
+ } else {
+ log_err(scn->dev, "%s: undefined initial condition.", FUNC_NAME);
+ res = RES_BAD_OP;
+ goto error;
}
-
- /* At t=t0, the initial condition should have been reached. */
- log_err(scn->dev,
- "%s: undefined initial condition. "
- "Time is %g but the temperature remains unknown.\n",
- FUNC_NAME, rwalk->vtx.time);
- res = RES_BAD_OP;
- goto error;
}
/* Sample time until init condition is reached or a true convection occurs. */
for(;;) {
struct sdis_interface_fragment frag;
struct sXd(primitive) prim;
- double mu, tau, t0;
+ struct fluid_props props = FLUID_PROPS_NULL;
+ double hc;
+ double mu;
+
+ /* Fetch fluid properties */
+ res = fluid_get_properties(rwalk->mdm, &rwalk->vtx, &props);
+ if(res != RES_OK) goto error;
- /* Fetch other physical properties. */
- cp = fluid_get_calorific_capacity(rwalk->mdm, &rwalk->vtx);
- rho = fluid_get_volumic_mass(rwalk->mdm, &rwalk->vtx);
- t0 = fluid_get_t0(rwalk->mdm); /* Limit time */
+ res = check_fluid_constant_properties(scn->dev, &props_ref, &props);
+ if(res != RES_OK) goto error;
/* Sample the time using the upper bound. */
- mu = enc->hc_upper_bound / (rho * cp) * enc->S_over_V;
- 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(rwalk->vtx.time != INF) {
- rwalk->vtx.time = MMAX(rwalk->vtx.time - tau, t0); /* Time rewind */
-
- /* Register the new vertex against the heat path */
- res = XD(register_heat_vertex_in_fluid)(scn, ctx, rwalk, T->value);
- if(res != RES_OK) goto error;
-
- if(rwalk->vtx.time == t0) {
- /* Check the initial condition. */
- tmp = fluid_get_temperature(rwalk->mdm, &rwalk->vtx);
- if(tmp >= 0) {
- T->value += tmp;
- 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;
- }
- goto exit;
- }
- /* The initial condition should have been reached. */
- log_err(scn->dev,
- "%s: undefined initial condition. "
- "Time is %g but the temperature remains unknown.\n",
- FUNC_NAME, t0);
- res = RES_BAD_OP;
- goto error;
- }
- }
+ mu = enc->hc_upper_bound / (props.rho * props.cp) * enc->S_over_V;
+ res = XD(time_rewind)(mu, props.t0, rng, rwalk, ctx, T);
+ if(res != RES_OK) goto error;
+ if(T->done) break; /* Limit condition was reached */
/* Uniformly sample the enclosure. */
#if DIM == 2
@@ -283,8 +349,8 @@ XD(convective_path)
}
/* Register the new vertex against the heat path */
- res = register_heat_vertex
- (ctx->heat_path, &rwalk->vtx, T->value, SDIS_HEAT_VERTEX_CONVECTION);
+ 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. */
diff --git a/src/sdis_heat_path_radiative_Xd.h b/src/sdis_heat_path_radiative_Xd.h
@@ -1,4 +1,4 @@
-/* Copyright (C) 2016-2021 |Meso|Star> (contact@meso-star.com)
+/* Copyright (C) 2016-2022 |Meso|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
@@ -33,7 +33,7 @@ res_T
XD(trace_radiative_path)
(struct sdis_scene* scn,
const float ray_dir[3],
- const struct rwalk_context* ctx,
+ struct rwalk_context* ctx,
struct XD(rwalk)* rwalk,
struct ssp_rng* rng,
struct XD(temperature)* T)
@@ -42,12 +42,16 @@ XD(trace_radiative_path)
* are assumed to be extruded to the infinity along the Z dimension. */
float N[3] = {0, 0, 0};
float dir[3] = {0, 0, 0};
+ int branch_id;
res_T res = RES_OK;
ASSERT(scn && ray_dir && ctx && rwalk && rng && T);
f3_set(dir, ray_dir);
+ /* (int)ctx->nbranchings < 0 <=> Beginning of the realisation */
+ branch_id = MMAX((int)ctx->nbranchings, 0);
+
/* Launch the radiative random walk */
for(;;) {
const struct sdis_interface* interf = NULL;
@@ -74,8 +78,8 @@ XD(trace_radiative_path)
#endif
if(SXD_HIT_NONE(&rwalk->hit)) { /* Fetch the ambient radiative temperature */
rwalk->hit_side = SDIS_SIDE_NULL__;
- if(ctx->Tarad >= 0) {
- T->value += ctx->Tarad;
+ if(scn->trad.temperature >= 0) {
+ T->value += scn->trad.temperature;
T->done = 1;
if(ctx->green_path) {
@@ -86,12 +90,14 @@ XD(trace_radiative_path)
if(ctx->heat_path) {
const float empirical_dst = 0.1f;
struct sdis_rwalk_vertex vtx;
+
+
vtx = rwalk->vtx;
vtx.P[0] += dir[0] * empirical_dst;
vtx.P[1] += dir[1] * empirical_dst;
vtx.P[2] += dir[2] * empirical_dst;
- res = register_heat_vertex
- (ctx->heat_path, &vtx, T->value, SDIS_HEAT_VERTEX_RADIATIVE);
+ res = register_heat_vertex(ctx->heat_path, &vtx, T->value,
+ SDIS_HEAT_VERTEX_RADIATIVE, branch_id);
if(res != RES_OK) goto error;
}
break;
@@ -104,7 +110,7 @@ XD(trace_radiative_path)
"such temperature, one has to setup a valid ambient radiative "
"temperature, i.e. it must be greater or equal to 0.\n",
FUNC_NAME,
- ctx->Tarad,
+ scn->trad.temperature,
SPLIT3(rwalk->vtx.P));
res = RES_BAD_OP;
goto error;
@@ -119,8 +125,8 @@ XD(trace_radiative_path)
XD(move_pos)(rwalk->vtx.P, dir, rwalk->hit.distance);
/* Register the random walk vertex against the heat path */
- res = register_heat_vertex
- (ctx->heat_path, &rwalk->vtx, T->value, SDIS_HEAT_VERTEX_RADIATIVE);
+ res = register_heat_vertex(ctx->heat_path, &rwalk->vtx, T->value,
+ SDIS_HEAT_VERTEX_RADIATIVE, branch_id);
if(res != RES_OK) goto error;
/* Fetch the new interface and setup the hit fragment */
@@ -188,7 +194,7 @@ error:
res_T
XD(radiative_path)
(struct sdis_scene* scn,
- const struct rwalk_context* ctx,
+ struct rwalk_context* ctx,
struct XD(rwalk)* rwalk,
struct ssp_rng* rng,
struct XD(temperature)* T)
diff --git a/src/sdis_interface.c b/src/sdis_interface.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 2016-2021 |Meso|Star> (contact@meso-star.com)
+/* Copyright (C) 2016-2022 |Meso|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
@@ -53,7 +53,7 @@ check_interface_shader
&& shader->convection_coef) {
log_warn(dev,
"%s: a solid/solid interface can't have a convection coefficient. The "
- " shader's pointer function for this attribute should be NULL.\n",
+ "shader's pointer function for this attribute should be NULL.\n",
caller_name);
}
if(shader->convection_coef_upper_bound < 0) {
@@ -67,18 +67,20 @@ check_interface_shader
&& shader->thermal_contact_resistance) {
log_warn(dev,
"%s: only solid/solid interface can have a thermal contact resistance. The "
- " shader's pointer function for this attribute should be NULL.\n",
+ "shader's pointer function for this attribute should be NULL.\n",
caller_name);
}
FOR_EACH(i, 0, 2) {
switch(type[i]) {
case SDIS_SOLID:
- if(shaders[i]->emissivity || shaders[i]->specular_fraction) {
+ if(shaders[i]->emissivity
+ || shaders[i]->specular_fraction
+ || shaders[i]->reference_temperature) {
log_warn(dev,
- "%s: the interface side toward a solid can neither have the "
- "emissivity nor the specular_fraction properties. The shader's "
- " pointer functions for these attributes should be NULL.\n",
+ "%s: the interface side toward a solid cannot have an emissivity, "
+ "a specular_fraction or a reference temperature. The shader's "
+ "pointer functions for these attributes should be NULL.\n",
caller_name);
}
break;
diff --git a/src/sdis_interface_c.h b/src/sdis_interface_c.h
@@ -1,4 +1,4 @@
-/* Copyright (C) 2016-2021 |Meso|Star> (contact@meso-star.com)
+/* Copyright (C) 2016-2022 |Meso|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
@@ -167,5 +167,21 @@ interface_side_get_specular_fraction
? shader->specular_fraction(frag, interf->data) : 0;
}
+static INLINE double
+interface_side_get_reference_temperature
+ (const struct sdis_interface* interf,
+ const struct sdis_interface_fragment* frag)
+{
+ const struct sdis_interface_side_shader* shader;
+ ASSERT(interf && frag);
+ switch(frag->side) {
+ case SDIS_FRONT: shader = &interf->shader.front; break;
+ case SDIS_BACK: shader = &interf->shader.back; break;
+ default: FATAL("Unreachable code\n"); break;
+ }
+ return shader->reference_temperature
+ ? shader->reference_temperature(frag, interf->data) : -1;
+}
+
#endif /* SDIS_INTERFACE_C_H */
diff --git a/src/sdis_log.c b/src/sdis_log.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 2016-2021 |Meso|Star> (contact@meso-star.com)
+/* Copyright (C) 2016-2022 |Meso|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
@@ -90,9 +90,15 @@ log_info(const struct sdis_device* dev, const char* msg, ...)
va_list vargs_list;
ASSERT(dev && msg);
- va_start(vargs_list, msg);
- log_msg(dev, LOG_OUTPUT, msg, vargs_list);
- va_end(vargs_list);
+#ifdef SDIS_ENABLE_MPI
+ /* Log standard messages only on master process */
+ if(dev->mpi_rank == 0)
+#endif
+ {
+ va_start(vargs_list, msg);
+ log_msg(dev, LOG_OUTPUT, msg, vargs_list);
+ va_end(vargs_list);
+ }
}
void
@@ -101,9 +107,15 @@ log_err(const struct sdis_device* dev, const char* msg, ...)
va_list vargs_list;
ASSERT(dev && msg);
- va_start(vargs_list, msg);
- log_msg(dev, LOG_ERROR, msg, vargs_list);
- va_end(vargs_list);
+#ifdef SDIS_ENABLE_MPI
+ /* Log error messages only on master process */
+ if(dev->mpi_rank == 0)
+#endif
+ {
+ va_start(vargs_list, msg);
+ log_msg(dev, LOG_ERROR, msg, vargs_list);
+ va_end(vargs_list);
+ }
}
void
@@ -112,8 +124,14 @@ log_warn(const struct sdis_device* dev, const char* msg, ...)
va_list vargs_list;
ASSERT(dev && msg);
- va_start(vargs_list, msg);
- log_msg(dev, LOG_WARNING, msg, vargs_list);
- va_end(vargs_list);
+#ifdef SDIS_ENABLE_MPI
+ /* Log warnings only on master process */
+ if(dev->mpi_rank == 0)
+#endif
+ {
+ va_start(vargs_list, msg);
+ log_msg(dev, LOG_WARNING, msg, vargs_list);
+ va_end(vargs_list);
+ }
}
diff --git a/src/sdis_log.h b/src/sdis_log.h
@@ -1,4 +1,4 @@
-/* Copyright (C) 2016-2021 |Meso|Star> (contact@meso-star.com)
+/* Copyright (C) 2016-2022 |Meso|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
diff --git a/src/sdis_medium.c b/src/sdis_medium.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 2016-2021 |Meso|Star> (contact@meso-star.com)
+/* Copyright (C) 2016-2022 |Meso|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
@@ -40,7 +40,7 @@ check_solid_shader(const struct sdis_solid_shader* shader)
return shader->calorific_capacity
&& shader->thermal_conductivity
&& shader->volumic_mass
- && shader->delta_solid
+ && shader->delta
&& shader->temperature
&& 0 <= shader->t0 && shader->t0 < INF;
}
diff --git a/src/sdis_medium_c.h b/src/sdis_medium_c.h
@@ -1,4 +1,4 @@
-/* Copyright (C) 2016-2021 |Meso|Star> (contact@meso-star.com)
+/* Copyright (C) 2016-2022 |Meso|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
@@ -17,6 +17,7 @@
#define SDIS_MEDIUM_C_H
#include "sdis.h"
+#include "sdis_log.h"
#include <rsys/free_list.h>
#include <rsys/math.h>
@@ -36,40 +37,93 @@ struct sdis_medium {
struct sdis_device* dev;
};
-static FINLINE unsigned
-medium_get_id(const struct sdis_medium* mdm)
-{
- ASSERT(mdm);
- return mdm->id.index;
-}
+struct fluid_props {
+ double rho; /* Volumic mass */
+ double cp; /* Calorific capacity */
+ double temperature;
+ double t0; /* Initial time */
+};
+#define FLUID_PROPS_NULL__ {0,0,0,0}
+static const struct fluid_props FLUID_PROPS_NULL = FLUID_PROPS_NULL__;
+
+struct solid_props {
+ double lambda; /* Conductivity */
+ double rho; /* Volumic mass */
+ double cp; /* Calorific capacity */
+ double delta; /* Random walk step */
+ double power; /* Volumic power */
+ double temperature;
+ double t0; /* Initial time */
+};
+#define SOLID_PROPS_NULL__ {0,0,0,0,0,0,0}
+static const struct solid_props SOLID_PROPS_NULL = SOLID_PROPS_NULL__;
+
+#define MDM_TYPE(Mdm) CONCAT(MDM_TYPE_, Mdm)
+#define MDM_TYPE_solid SDIS_SOLID
+#define MDM_TYPE_fluid SDIS_FLUID
+
+#define PROP_STR(Prop) CONCAT(PROP_STR_, Prop)
+#define PROP_STR_calorific_capacity "calorific capacity"
+#define PROP_STR_conductivity "conductivity"
+#define PROP_STR_delta "delta"
+#define PROP_STR_temperature "temperature"
+#define PROP_STR_thermal_conductivity "thermal conductivity"
+#define PROP_STR_volumic_mass "volumic mass"
+#define PROP_STR_volumic_power "volumic power"
+
+#define DEFINE_MDM_GET_PROP_FUNC(Mdm, Prop) \
+ static INLINE double \
+ Mdm##_get_##Prop \
+ (const struct sdis_medium* mdm, const struct sdis_rwalk_vertex* vtx) \
+ { \
+ ASSERT(mdm && mdm->type == MDM_TYPE(Mdm)); \
+ return mdm->shader.Mdm.Prop(vtx, mdm->data); \
+ }
+
+#define DEFINE_MDM_CHK_PROP_FUNC(Mdm, Prop, Low, Upp, LowIsInc, UppIsInc) \
+ static INLINE res_T \
+ Mdm##_check_##Prop \
+ (struct sdis_device* dev, \
+ const double val, /* Value of the property */ \
+ const double pos[], /* Position at which the property was queried */ \
+ const double time) /* Time at which the property was queried */ \
+ { \
+ const int low_test = LowIsInc ? Low <= val : Low < val; \
+ const int upp_test = UppIsInc ? Upp >= val : Upp > val; \
+ const char low_char = LowIsInc ? '[' : ']'; \
+ const char upp_char = UppIsInc ? ']' : '['; \
+ ASSERT(dev && pos); \
+ \
+ if(!low_test || !upp_test) { \
+ log_err(dev, \
+ "invalid "STR(Mdm)" "PROP_STR(Prop)" '%g': it must be in %c%g, %g%c " \
+ "-- position=%g, %g, %g; time=%g\n", \
+ val, low_char, (double)Low, (double)Upp, upp_char, SPLIT3(pos), time); \
+ return RES_BAD_ARG; \
+ } \
+ return RES_OK; \
+ }
/*******************************************************************************
* Fluid local functions
******************************************************************************/
-static INLINE double
-fluid_get_calorific_capacity
- (const struct sdis_medium* mdm, const struct sdis_rwalk_vertex* vtx)
-{
- ASSERT(mdm && mdm->type == SDIS_FLUID);
- return mdm->shader.fluid.calorific_capacity(vtx, mdm->data);
-}
+DEFINE_MDM_CHK_PROP_FUNC(fluid, calorific_capacity, 0, INF, 0, 1)
+DEFINE_MDM_CHK_PROP_FUNC(fluid, volumic_mass, 0, INF, 0, 1)
+DEFINE_MDM_CHK_PROP_FUNC(fluid, temperature, 0, INF, 1, 1)
-static INLINE double
-fluid_get_volumic_mass
- (const struct sdis_medium* mdm, const struct sdis_rwalk_vertex* vtx)
+static INLINE res_T
+fluid_check_t0(struct sdis_device* dev, const double t0)
{
- ASSERT(mdm && mdm->type == SDIS_FLUID);
- return mdm->shader.fluid.volumic_mass(vtx, mdm->data);
+ if(t0 < 0) {
+ log_err(dev, "invalid negative initial time '%g'.\n", t0);
+ return RES_BAD_ARG;
+ }
+ return RES_OK;
}
-static INLINE double
-fluid_get_temperature
- (const struct sdis_medium* mdm, const struct sdis_rwalk_vertex* vtx)
-{
- ASSERT(mdm && mdm->type == SDIS_FLUID);
- /*ASSERT(vtx->time >= mdm->shader.fluid.t0);*/
- return mdm->shader.fluid.temperature(vtx, mdm->data);
-}
+DEFINE_MDM_GET_PROP_FUNC(fluid, calorific_capacity)
+DEFINE_MDM_GET_PROP_FUNC(fluid, volumic_mass)
+DEFINE_MDM_GET_PROP_FUNC(fluid, temperature)
static INLINE double
fluid_get_t0(const struct sdis_medium* mdm)
@@ -79,44 +133,76 @@ fluid_get_t0(const struct sdis_medium* mdm)
return mdm->shader.fluid.t0;
}
-/*******************************************************************************
- * Solid local functions
- ******************************************************************************/
-static INLINE double
-solid_get_calorific_capacity
- (const struct sdis_medium* mdm, const struct sdis_rwalk_vertex* vtx)
+static INLINE res_T
+fluid_check_properties
+ (struct sdis_device* dev,
+ const struct fluid_props* props,
+ const double pos[],
+ const double time)
{
- ASSERT(mdm && mdm->type == SDIS_SOLID);
- return mdm->shader.solid.calorific_capacity(vtx, mdm->data);
-}
+ res_T res = RES_OK;
+ ASSERT(dev && props);
-static INLINE double
-solid_get_thermal_conductivity
- (const struct sdis_medium* mdm, const struct sdis_rwalk_vertex* vtx)
-{
- ASSERT(mdm && mdm->type == SDIS_SOLID);
- return mdm->shader.solid.thermal_conductivity(vtx, mdm->data);
+ #define CHK_PROP(Prop, Val) { \
+ res = fluid_check_##Prop(dev, Val, pos, time); \
+ if(res != RES_OK) return res; \
+ } (void)0
+ CHK_PROP(volumic_mass, props->rho);
+ CHK_PROP(calorific_capacity, props->cp);
+ #undef CHK_PROP
+
+ /* Do not check the temperature. An invalid temperature means that the
+ * temperature is unknown */
+
+ res = fluid_check_t0(dev, props->t0);
+ if(res != RES_OK) return res;
+
+ return RES_OK;
}
-static INLINE double
-solid_get_volumic_mass
- (const struct sdis_medium* mdm, const struct sdis_rwalk_vertex* vtx)
+static INLINE res_T
+fluid_get_properties
+ (const struct sdis_medium* mdm,
+ const struct sdis_rwalk_vertex* vtx,
+ struct fluid_props* props)
{
- ASSERT(mdm && mdm->type == SDIS_SOLID);
- return mdm->shader.solid.volumic_mass(vtx, mdm->data);
+ ASSERT(mdm && mdm->type == SDIS_FLUID);
+ props->rho = fluid_get_volumic_mass(mdm, vtx);
+ props->cp = fluid_get_calorific_capacity(mdm, vtx);
+ props->temperature = fluid_get_temperature(mdm, vtx);
+ return fluid_check_properties(mdm->dev, props, vtx->P, vtx->time);
}
-static INLINE double
-solid_get_delta
- (const struct sdis_medium* mdm, const struct sdis_rwalk_vertex* vtx)
+/*******************************************************************************
+ * Solid local functions
+ ******************************************************************************/
+DEFINE_MDM_CHK_PROP_FUNC(solid, calorific_capacity,0, INF, 0, 1)
+DEFINE_MDM_CHK_PROP_FUNC(solid, thermal_conductivity, 0, INF, 0, 1)
+DEFINE_MDM_CHK_PROP_FUNC(solid, volumic_mass, 0, INF, 0, 1)
+DEFINE_MDM_CHK_PROP_FUNC(solid, delta, 0, INF, 0, 1)
+DEFINE_MDM_CHK_PROP_FUNC(solid, volumic_power, -INF, INF, 1, 1)
+DEFINE_MDM_CHK_PROP_FUNC(solid, temperature, 0, INF, 1, 1)
+
+static INLINE res_T
+solid_check_t0(struct sdis_device* dev, const double t0)
{
- ASSERT(mdm && mdm->type == SDIS_SOLID);
- return mdm->shader.solid.delta_solid(vtx, mdm->data);
+ if(t0 < 0) {
+ log_err(dev, "invalid negative initial time '%g'.\n", t0);
+ return RES_BAD_ARG;
+ }
+ return RES_OK;
}
+DEFINE_MDM_GET_PROP_FUNC(solid, calorific_capacity)
+DEFINE_MDM_GET_PROP_FUNC(solid, thermal_conductivity)
+DEFINE_MDM_GET_PROP_FUNC(solid, volumic_mass)
+DEFINE_MDM_GET_PROP_FUNC(solid, delta)
+DEFINE_MDM_GET_PROP_FUNC(solid, temperature)
+
static INLINE double
solid_get_volumic_power
- (const struct sdis_medium* mdm, const struct sdis_rwalk_vertex* vtx)
+ (const struct sdis_medium* mdm,
+ const struct sdis_rwalk_vertex* vtx)
{
ASSERT(mdm && mdm->type == SDIS_SOLID);
return mdm->shader.solid.volumic_power
@@ -125,26 +211,64 @@ solid_get_volumic_power
}
static INLINE double
-solid_get_temperature
- (const struct sdis_medium* mdm, const struct sdis_rwalk_vertex* vtx)
+solid_get_t0(const struct sdis_medium* mdm)
{
ASSERT(mdm && mdm->type == SDIS_SOLID);
- /*ASSERT(vtx->time >= mdm->shader.solid.t0);*/
- return mdm->shader.solid.temperature(vtx, mdm->data);
+ ASSERT(0 <= mdm->shader.solid.t0 && mdm->shader.solid.t0 < INF);
+ return mdm->shader.solid.t0;
}
-static INLINE double
-solid_get_t0(const struct sdis_medium* mdm)
+static INLINE res_T
+solid_check_properties
+ (struct sdis_device* dev,
+ const struct solid_props* props,
+ const double pos[],
+ const double time)
+{
+ res_T res = RES_OK;
+ ASSERT(dev && props);
+
+ #define CHK_PROP(Prop, Val) { \
+ res = solid_check_##Prop(dev, Val, pos, time); \
+ if(res != RES_OK) return res; \
+ } (void)0
+ CHK_PROP(calorific_capacity, props->cp);
+ CHK_PROP(thermal_conductivity, props->lambda);
+ CHK_PROP(volumic_mass, props->rho);
+ CHK_PROP(delta, props->delta);
+ CHK_PROP(volumic_power, props->power);
+ #undef CHK_PROP
+
+ /* Do not check the temperature. An invalid temperature means that the
+ * temperature is unknown */
+
+ res = solid_check_t0(dev, props->t0);
+ if(res != RES_OK) return res;
+
+ return RES_OK;
+}
+
+static INLINE res_T
+solid_get_properties
+ (const struct sdis_medium* mdm,
+ const struct sdis_rwalk_vertex* vtx,
+ struct solid_props* props)
{
ASSERT(mdm && mdm->type == SDIS_SOLID);
- ASSERT(0 <= mdm->shader.solid.t0 && mdm->shader.solid.t0 < INF);
- return mdm->shader.solid.t0;
+ props->lambda = solid_get_thermal_conductivity(mdm, vtx);
+ props->rho = solid_get_volumic_mass(mdm, vtx);
+ props->cp = solid_get_calorific_capacity(mdm, vtx);
+ props->delta = solid_get_delta(mdm, vtx);
+ props->power = solid_get_volumic_power(mdm, vtx);
+ props->temperature = solid_get_temperature(mdm, vtx);
+ props->t0 = solid_get_t0(mdm);
+ return solid_check_properties(mdm->dev, props, vtx->P, vtx->time);
}
/*******************************************************************************
* Generic functions
******************************************************************************/
-static FINLINE double
+static INLINE double
medium_get_temperature
(const struct sdis_medium* mdm, const struct sdis_rwalk_vertex* vtx)
{
@@ -158,7 +282,7 @@ medium_get_temperature
return temp;
}
-static FINLINE double
+static INLINE double
medium_get_t0(const struct sdis_medium* mdm)
{
double t0;
@@ -171,5 +295,38 @@ medium_get_t0(const struct sdis_medium* mdm)
return t0;
}
+static INLINE unsigned
+medium_get_id(const struct sdis_medium* mdm)
+{
+ ASSERT(mdm);
+ return mdm->id.index;
+}
+
+static INLINE const char*
+medium_type_to_string(const enum sdis_medium_type type)
+{
+ const char* str = "none";
+ switch(type) {
+ case SDIS_FLUID: str = "fluid"; break;
+ case SDIS_SOLID: str = "solid"; break;
+ default: FATAL("Unreachable code.\n"); break;
+ }
+ return str;
+}
+
+#undef MDM_TYPE
+#undef MDM_TYPE_solid
+#undef MDM_TYPE_fluid
+#undef PROP_STR
+#undef PROP_STR_calorific_capacity
+#undef PROP_STR_conductivity
+#undef PROP_STR_delta
+#undef PROP_STR_temperature
+#undef PROP_STR_thermal_conductivity
+#undef PROP_STR_volumic_mass
+#undef PROP_STR_volumic_power
+#undef DEFINE_MDM_CHK_PROP_FUNC
+#undef DEFINE_MDM_GET_PROP_FUNC
+
#endif /* SDIS_MEDIUM_C_H */
diff --git a/src/sdis_misc.c b/src/sdis_misc.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 2016-2021 |Meso|Star> (contact@meso-star.com)
+/* Copyright (C) 2016-2022 |Meso|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
@@ -21,3 +21,51 @@
#define SDIS_XD_DIMENSION 3
#include "sdis_misc_Xd.h"
+res_T
+check_primitive_uv_2d(struct sdis_device* dev, const double param_coord[])
+{
+ double u;
+ res_T res = RES_OK;
+ ASSERT(dev && param_coord);
+
+ u = param_coord[0];
+
+ if(u < 0 || 1 < u) {
+ log_err(dev,
+ "%s: invalid parametric coordinates u=%g; it must be in [0, 1].\n",
+ FUNC_NAME, u);
+ res = RES_BAD_ARG;
+ goto error;
+ }
+
+exit:
+ return res;
+error:
+ goto exit;
+}
+
+res_T
+check_primitive_uv_3d(struct sdis_device* dev, const double param_coords[])
+{
+ double u, v, w;
+ res_T res = RES_OK;
+ ASSERT(dev && param_coords);
+
+ u = param_coords[0];
+ v = param_coords[1];
+ w = CLAMP(1 - u - v, 0, 1);
+
+ if(u < 0 || 1 < u || v < 0 || 1 < v || !eq_eps(u + v + w, 1, 1.e-6)) {
+ log_err(dev,
+ "%s: invalid parametric coordinates u=%g; v=%g. "
+ "u + v + (1-u-v) must be equal to 1 with u and v in [0, 1].\n",
+ FUNC_NAME, u, v);
+ res = RES_BAD_ARG;
+ goto error;
+ }
+
+exit:
+ return res;
+error:
+ goto exit;
+}
diff --git a/src/sdis_misc.h b/src/sdis_misc.h
@@ -1,4 +1,4 @@
-/* Copyright (C) 2016-2021 |Meso|Star> (contact@meso-star.com)
+/* Copyright (C) 2016-2022 |Meso|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
@@ -16,6 +16,8 @@
#ifndef SDIS_MISC_H
#define SDIS_MISC_H
+#include "sdis_heat_path.h"
+
#include <rsys/float2.h>
#include <rsys/float3.h>
#include <star/ssp.h>
@@ -127,10 +129,11 @@ register_heat_vertex
(struct sdis_heat_path* path,
const struct sdis_rwalk_vertex* vtx,
const double weight,
- const enum sdis_heat_vertex_type type)
+ const enum sdis_heat_vertex_type type,
+ const int branch_id)
{
struct sdis_heat_vertex heat_vtx = SDIS_HEAT_VERTEX_NULL;
- ASSERT(vtx);
+ ASSERT(vtx && branch_id >= 0);
if(!path) return RES_OK;
@@ -140,25 +143,41 @@ register_heat_vertex
heat_vtx.time = vtx->time;
heat_vtx.weight = weight;
heat_vtx.type = type;
+ heat_vtx.branch_id = branch_id;
return heat_path_add_vertex(path, &heat_vtx);
}
extern LOCAL_SYM res_T
time_rewind_2d
- (struct sdis_medium* mdm, /* Medium into which the time is rewinded */
+ (const double mu,
+ const double t0, /* Initial time */
struct ssp_rng* rng,
- const double dist_in_meter,
- const struct rwalk_context* ctx,
struct rwalk_2d* rwalk,
+ const struct rwalk_context* ctx,
struct temperature_2d* T);
extern LOCAL_SYM res_T
time_rewind_3d
- (struct sdis_medium* mdm, /* Medium into which the time is rewinded */
+ (const double mu,
+ const double t0, /* Initial time */
struct ssp_rng* rng,
- const double dist_in_meter,
- const struct rwalk_context* ctx,
struct rwalk_3d* rwalk,
+ const struct rwalk_context* ctx,
struct temperature_3d* 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. */
+extern LOCAL_SYM res_T
+check_primitive_uv_2d
+ (struct sdis_device* dev,
+ const double u[]);
+
+/* Check the validity of the parametric coordinates onto a 3D primitive. If
+ * they are invalid, the function prints an error message and return
+ * RES_BAD_ARG. */
+extern LOCAL_SYM res_T
+check_primitive_uv_3d
+ (struct sdis_device* dev,
+ const double uv[]);
+
#endif /* SDIS_MISC_H */
diff --git a/src/sdis_misc_Xd.h b/src/sdis_misc_Xd.h
@@ -1,4 +1,4 @@
-/* Copyright (C) 2016-2021 |Meso|Star> (contact@meso-star.com)
+/* Copyright (C) 2016-2022 |Meso|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
@@ -25,29 +25,19 @@
res_T
XD(time_rewind)
- (struct sdis_medium* mdm,
+ (const double mu,
+ const double t0,
struct ssp_rng* rng,
- const double dist_in_meter,
- const struct rwalk_context* ctx,
struct XD(rwalk)* rwalk,
+ const struct rwalk_context* ctx,
struct XD(temperature)* T)
{
double temperature;
- double lambda, rho, cp;
- double tau, mu, t0;
+ double tau;
res_T res = RES_OK;
- ASSERT(mdm && rng && ctx && rwalk && dist_in_meter > 0);
- ASSERT(sdis_medium_get_type(mdm) == SDIS_SOLID);
- ASSERT(T->done == 0);
-
- /* Fetch physical properties */
- lambda = solid_get_thermal_conductivity(mdm, &rwalk->vtx);
- rho = solid_get_volumic_mass(mdm, &rwalk->vtx);
- cp = solid_get_calorific_capacity(mdm, &rwalk->vtx);
- t0 = solid_get_t0(mdm); /* Limit time */
+ ASSERT(rwalk && rng && T);
- /* Sample the time to reroll */
- mu = (2*DIM*lambda)/(rho*cp*dist_in_meter*dist_in_meter);
+ /* Sample the time using the upper bound. */
tau = ssp_ran_exp(rng, mu);
/* Increment the elapsed time */
@@ -57,16 +47,18 @@ XD(time_rewind)
if(IS_INF(rwalk->vtx.time)) goto exit; /* Steady computation */
/* Time rewind */
- rwalk->vtx.time = MMAX(rwalk->vtx.time - tau, t0);
+ 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 initial temperature */
- temperature = solid_get_temperature(mdm, &rwalk->vtx);
+ /* Fetch the initial temperature */
+ temperature = medium_get_temperature(rwalk->mdm, &rwalk->vtx);
if(temperature < 0) {
- log_err(mdm->dev, "%s: the path reaches the limit condition but the "
- "temperature remains unknown.\n", FUNC_NAME);
+ 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;
}
@@ -84,8 +76,8 @@ XD(time_rewind)
}
if(ctx->green_path) {
- res = green_path_set_limit_vertex(ctx->green_path, mdm, &rwalk->vtx,
- rwalk->elapsed_time);
+ res = green_path_set_limit_vertex(ctx->green_path, rwalk->mdm,
+ &rwalk->vtx, rwalk->elapsed_time);
if(res != RES_OK) goto error;
}
diff --git a/src/sdis_mpi.c b/src/sdis_mpi.c
@@ -0,0 +1,138 @@
+/* Copyright (C) 2016-2022 |Meso|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_c.h"
+#include "sdis_device_c.h"
+#include "sdis_mpi.h"
+
+#include <rsys/mutex.h>
+
+#include <time.h> /* nanosleep */
+#include <sys/time.h> /* struct timespec */
+
+/*******************************************************************************
+ * Local functions
+ ******************************************************************************/
+void
+mpi_send_progress(struct sdis_device* dev, const int32_t progress)
+{
+ ASSERT(dev && dev->use_mpi);
+ (void)dev;
+
+ mutex_lock(dev->mpi_mutex);
+ MPI(Send(&progress, 1/*#data*/, MPI_INT32_T, 0/*dst rank*/,
+ MPI_SDIS_MSG_PROGRESS, MPI_COMM_WORLD));
+ mutex_unlock(dev->mpi_mutex);
+}
+
+void
+mpi_fetch_progress(struct sdis_device* dev, int32_t progress[])
+{
+ int iproc;
+ ASSERT(dev && dev->use_mpi && dev->mpi_rank == 0);
+
+ FOR_EACH(iproc, 1, dev->mpi_nprocs) {
+ /* Flush all progress messages sent by the process `iproc' */
+ for(;;) {
+ MPI_Request req;
+ int flag;
+
+ /* Query for a progress message */
+ mutex_lock(dev->mpi_mutex);
+ MPI(Iprobe(iproc, MPI_SDIS_MSG_PROGRESS, MPI_COMM_WORLD, &flag,
+ MPI_STATUS_IGNORE));
+ mutex_unlock(dev->mpi_mutex);
+
+ if(flag == 0) break; /* No more progress status to receive */
+
+ /* Asynchronously receive the progress status */
+ mutex_lock(dev->mpi_mutex);
+ MPI(Irecv(&progress[iproc], 1/*count*/, MPI_INT32_T, iproc,
+ MPI_SDIS_MSG_PROGRESS, MPI_COMM_WORLD, &req));
+ mutex_unlock(dev->mpi_mutex);
+
+ /* Actively wait for the completion of the receive procedure */
+ mpi_waiting_for_request(dev, &req);
+ }
+ }
+}
+
+void
+mpi_waiting_for_request(struct sdis_device* dev, MPI_Request* req)
+{
+ struct timespec t;
+ ASSERT(dev && dev->use_mpi && req);
+
+ /* Setup the suspend time of the process while waiting for a request */
+ t.tv_sec = 0;
+ t.tv_nsec = 10000000; /* 10ms */
+
+ /* Wait for process synchronisation */
+ for(;;) {
+ int complete;
+
+ mutex_lock(dev->mpi_mutex);
+ MPI(Test(req, &complete, MPI_STATUS_IGNORE));
+ mutex_unlock(dev->mpi_mutex);
+
+ if(complete) break;
+ nanosleep(&t, NULL);
+ }
+}
+
+void
+mpi_waiting_for_message
+ (struct sdis_device* dev,
+ const int iproc,
+ const enum mpi_sdis_message msg,
+ MPI_Status* status)
+{
+ struct timespec t;
+ ASSERT(dev && dev->use_mpi && status);
+
+ /* Setup the suspend time of the process while waiting for a message */
+ t.tv_sec = 0;
+ t.tv_nsec = 10000000; /* 10ms */
+
+ /* Wait for process synchronisation */
+ for(;;) {
+ int flag;
+
+ /* Asynchronously probe for green function data */
+ mutex_lock(dev->mpi_mutex);
+ MPI(Iprobe(iproc, msg, MPI_COMM_WORLD, &flag, status));
+ mutex_unlock(dev->mpi_mutex);
+
+ if(flag) break;
+ nanosleep(&t, NULL);
+ }
+}
+
+void
+mpi_barrier(struct sdis_device* dev)
+{
+ MPI_Request req;
+ ASSERT(dev && dev->use_mpi);
+
+ /* Asynchronously wait for process completion. Use an asynchronous barrier to
+ * avoid a dead lock if another thread on the same process queries the
+ * mpi_mutex */
+
+ mutex_lock(dev->mpi_mutex);
+ MPI(Ibarrier(MPI_COMM_WORLD, &req));
+ mutex_unlock(dev->mpi_mutex);
+
+ mpi_waiting_for_request(dev, &req);
+}
diff --git a/src/sdis_mpi.h b/src/sdis_mpi.h
@@ -0,0 +1,64 @@
+/* Copyright (C) 2016-2022 |Meso|Star> (contact@meso-star.com)
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+#ifndef SDIS_MPI_H
+#define SDIS_MPI_H
+
+#ifndef SDIS_ENABLE_MPI
+ #error "Invalid inclusion. Stardis-Solver is compiled without MPI support"
+#endif
+
+#include "sdis_c.h"
+
+#include <rsys/rsys.h>
+#include <mpi.h>
+
+/* Forward declarations */
+struct sdis_device;
+
+/* Send the progress status `progress' to the master process */
+extern LOCAL_SYM void
+mpi_send_progress
+ (struct sdis_device* dev,
+ const int32_t progress);
+
+/* Fetch the progress status of non master processes into `progress'. The
+ * progress of the i-th process is stored in progress[i], meaning that the
+ * length of progress must be at least equal to the number of MPI processes */
+extern LOCAL_SYM void
+mpi_fetch_progress
+ (struct sdis_device* dev,
+ int32_t progress[]);
+
+/* Actively wait for the completion of the MPI request `req' */
+extern LOCAL_SYM void
+mpi_waiting_for_request
+ (struct sdis_device* dev,
+ MPI_Request* req);
+
+/* Actively wait for a message from the process iproc */
+extern LOCAL_SYM void
+mpi_waiting_for_message
+ (struct sdis_device* dev,
+ const int iproc,
+ const enum mpi_sdis_message msg,
+ MPI_Status* status);
+
+/* Waiting for all processes */
+extern LOCAL_SYM void
+mpi_barrier
+ (struct sdis_device* dev);
+
+#endif /* SDIS_MPI_H */
diff --git a/src/sdis_realisation.c b/src/sdis_realisation.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 2016-2021 |Meso|Star> (contact@meso-star.com)
+/* Copyright (C) 2016-2022 |Meso|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
@@ -13,8 +13,26 @@
* 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_medium_c.h"
#include "sdis_realisation.h"
+/*******************************************************************************
+ * Helper functions
+ ******************************************************************************/
+static INLINE int
+check_ray_realisatio_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;
+}
+
+/*******************************************************************************
+ * Local functions
+ ******************************************************************************/
/* Generate the generic realisations */
#define SDIS_XD_DIMENSION 2
#include "sdis_realisation_Xd.h"
@@ -24,12 +42,7 @@
res_T
ray_realisation_3d
(struct sdis_scene* scn,
- struct ssp_rng* rng,
- struct sdis_medium* medium,
- const double position[3],
- const double direction[3],
- const double time,
- struct sdis_heat_path* heat_path, /* May be NULL */
+ struct ray_realisation_args* args,
double* weight)
{
struct rwalk_context ctx = RWALK_CONTEXT_NULL;
@@ -37,31 +50,35 @@ ray_realisation_3d
struct temperature_3d T = TEMPERATURE_NULL_3d;
float dir[3];
res_T res = RES_OK;
- ASSERT(scn && position && direction && time>=0 && weight);
- ASSERT(medium && medium->type == SDIS_FLUID);
+ ASSERT(scn && weight && check_ray_realisatio_args(args));
- d3_set(rwalk.vtx.P, position);
- rwalk.vtx.time = time;
+ d3_set(rwalk.vtx.P, args->position);
+ rwalk.vtx.time = args->time;
rwalk.hit = S3D_HIT_NULL;
rwalk.hit_side = SDIS_SIDE_NULL__;
- rwalk.mdm = medium;
-
- ctx.Tarad = scn->ambient_radiative_temperature;
- ctx.Tref3 = scn->reference_temperature * scn->reference_temperature
- * scn->reference_temperature;
- ctx.heat_path = heat_path;
+ rwalk.mdm = args->medium;
- f3_set_d3(dir, direction);
+ ctx.heat_path = args->heat_path;
+ ctx.Tmin = scn->tmin;
+ ctx.Tmin2 = ctx.Tmin * ctx.Tmin;
+ ctx.Tmin3 = ctx.Tmin * ctx.Tmin2;
+ ctx.That = scn->tmax;
+ ctx.That2 = ctx.That * ctx.That;
+ ctx.That3 = ctx.That * ctx.That2;
+ ctx.max_branchings = args->picard_order - 1;
+
+ f3_set_d3(dir, args->direction);
/* Register the starting position against the heat path */
- res = register_heat_vertex(heat_path, &rwalk.vtx, 0, SDIS_HEAT_VERTEX_RADIATIVE);
+ res = register_heat_vertex
+ (args->heat_path, &rwalk.vtx, 0, SDIS_HEAT_VERTEX_RADIATIVE, 0);
if(res != RES_OK) goto error;
- res = trace_radiative_path_3d(scn, dir, &ctx, &rwalk, rng, &T);
+ res = trace_radiative_path_3d(scn, dir, &ctx, &rwalk, args->rng, &T);
if(res != RES_OK) goto error;
if(!T.done) {
- res = compute_temperature_3d(scn, &ctx, &rwalk, rng, &T);
+ res = compute_temperature_3d(scn, &ctx, &rwalk, args->rng, &T);
if(res != RES_OK) goto error;
}
diff --git a/src/sdis_realisation.h b/src/sdis_realisation.h
@@ -1,4 +1,4 @@
-/* Copyright (C) 2016-2021 |Meso|Star> (contact@meso-star.com)
+/* Copyright (C) 2016-2022 |Meso|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
@@ -35,93 +35,138 @@ enum flux_flag {
};
/*******************************************************************************
+ * Helper function used to compute a temperature
+ ******************************************************************************/
+extern LOCAL_SYM res_T
+compute_temperature_2d
+ (struct sdis_scene* scn,
+ struct rwalk_context* ctx,
+ struct rwalk_2d* rwalk,
+ struct ssp_rng* rng,
+ struct temperature_2d* T);
+
+extern LOCAL_SYM res_T
+compute_temperature_3d
+ (struct sdis_scene* scn,
+ struct rwalk_context* ctx,
+ struct rwalk_3d* rwalk,
+ struct ssp_rng* rng,
+ struct temperature_3d* 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 */
+ double position[3]; /* Probe position */
+ double time; /* Observation time */
+ size_t picard_order; /* Picard order to estimate radiative temperature */
+ struct green_path_handle* green_path; /* May be NULL */
+ struct sdis_heat_path* heat_path; /* May be NULL */
+ size_t irealisation; /* Id of the realisation (for debug) */
+};
+#define PROBE_REALISATION_ARGS_NULL__ { \
+ NULL, NULL, {0,0,0}, -1, 0, NULL, NULL, 0 \
+}
+static const struct probe_realisation_args PROBE_REALISATION_ARGS_NULL =
+ PROBE_REALISATION_ARGS_NULL__;
+
extern LOCAL_SYM res_T
probe_realisation_2d
- (const size_t irealisation, /* For debug */
- struct sdis_scene* scn,
- struct ssp_rng* rng,
- struct sdis_medium* medium,
- const double position[2],
- const double time,
- struct green_path_handle* green_path, /* May be NULL */
- struct sdis_heat_path* heat_path, /* May be NULL */
+ (struct sdis_scene* scn,
+ struct probe_realisation_args* args,
double* weight);
extern LOCAL_SYM res_T
probe_realisation_3d
- (const size_t irealisation, /* For debug */
- struct sdis_scene* scn,
- struct ssp_rng* rng,
- struct sdis_medium* medium,
- const double position[3],
- const double time,
- struct green_path_handle* green_path, /* May be NULL */
- struct sdis_heat_path* heat_path, /* May be NULL */
+ (struct sdis_scene* scn,
+ struct probe_realisation_args* args,
double* weight);
/*******************************************************************************
* Realisation at a given position and time ON a given side of a boundary
******************************************************************************/
+struct boundary_realisation_args {
+ struct ssp_rng* rng;
+ size_t iprim; /* Index of the geometruc primitive */
+ double uv[2]; /* Parametric coordinate into the geometric primitive */
+ double time; /* Observation time */
+ size_t picard_order; /* Picard order to estimate radiative temperature */
+ enum sdis_side side; /* Side of the geometric primitive */
+ struct green_path_handle* green_path; /* May be NULL */
+ struct sdis_heat_path* heat_path; /* May be NULL */
+};
+#define BOUNDARY_REALISATION_ARGS_NULL__ { \
+ NULL, SIZE_MAX, {0,0}, -1, 0, SDIS_SIDE_NULL__, NULL, NULL \
+}
+static const struct boundary_realisation_args BOUNDARY_REALISATION_ARGS_NULL =
+ BOUNDARY_REALISATION_ARGS_NULL__;
+
extern LOCAL_SYM res_T
boundary_realisation_2d
(struct sdis_scene* scn,
- struct ssp_rng* rng,
- const size_t iprim,
- const double u[1],
- const double time,
- const enum sdis_side side,
- struct green_path_handle* green_path, /* May be NULL */
- struct sdis_heat_path* heat_path, /* May be NULL */
+ struct boundary_realisation_args* args,
double* weight);
extern LOCAL_SYM res_T
boundary_realisation_3d
(struct sdis_scene* scn,
- struct ssp_rng* rng,
- const size_t iprim,
- const double uv[2],
- const double time,
- const enum sdis_side side,
- struct green_path_handle* green_path, /* May be NULL */
- struct sdis_heat_path* heat_path, /* May be NULL */
+ struct boundary_realisation_args* args,
double* weight);
+/*******************************************************************************
+ * Realisation at a given position and time ON a given side of a boundary
+ ******************************************************************************/
+struct boundary_flux_realisation_args {
+ struct ssp_rng* rng;
+ size_t iprim; /* Index of the geometruc primitive */
+ double uv[2]; /* Parametric coordinate into the geometric primitive */
+ double time; /* Observation time */
+ size_t picard_order; /* Picard order to estimate radiative temperature */
+ enum sdis_side solid_side; /* Side of the geometric primitive */
+ int flux_mask; /* Combination of enum flux_flag */
+};
+#define BOUNDARY_FLUX_REALISATION_ARGS_NULL__ { \
+ NULL, SIZE_MAX, {0,0}, -1, 0, SDIS_SIDE_NULL__, 0 \
+}
+static const struct boundary_flux_realisation_args
+BOUNDARY_FLUX_REALISATION_ARGS_NULL = BOUNDARY_FLUX_REALISATION_ARGS_NULL__;
+
extern LOCAL_SYM res_T
boundary_flux_realisation_2d
(struct sdis_scene* scn,
- struct ssp_rng* rng,
- const size_t iprim,
- const double uv[1],
- const double time,
- const enum sdis_side solid_side,
- const int flux_mask, /* Combination of enum flux_flag */
+ struct boundary_flux_realisation_args* args,
struct bound_flux_result* result);
extern LOCAL_SYM res_T
boundary_flux_realisation_3d
(struct sdis_scene* scn,
- struct ssp_rng* rng,
- const size_t iprim,
- const double uv[2],
- const double time,
- const enum sdis_side solid_side,
- const int flux_mask, /* Combination of enum flux_flag */
+ struct boundary_flux_realisation_args* args,
struct bound_flux_result* result);
/*******************************************************************************
* Realisation along a given ray at a given time. Available only in 3D.
******************************************************************************/
+struct ray_realisation_args {
+ struct ssp_rng* rng;
+ struct sdis_medium* medium; /* Medium into which the realisation starts */
+ double position[3]; /* Ray position */
+ double direction[3]; /* Ray direction */
+ double time; /* Observation time */
+ size_t picard_order; /* Picard order to estimate radiative temperature */
+ struct sdis_heat_path* heat_path; /* May be NULL */
+};
+#define RAY_REALISATION_ARGS_NULL__ { \
+ NULL, NULL, {0,0,0}, {0,0,0}, -1, 0, NULL \
+}
+static const struct ray_realisation_args RAY_REALISATION_ARGS_NULL =
+ RAY_REALISATION_ARGS_NULL__;
+
extern LOCAL_SYM res_T
ray_realisation_3d
(struct sdis_scene* scn,
- struct ssp_rng* rng,
- struct sdis_medium* medium,
- const double position[3],
- const double direction[3],
- const double time,
- struct sdis_heat_path* heat_path, /* May be NULL */
+ struct ray_realisation_args* args,
double* weight);
#endif /* SDIS_REALISATION_H */
diff --git a/src/sdis_realisation_Xd.h b/src/sdis_realisation_Xd.h
@@ -1,4 +1,4 @@
-/* Copyright (C) 2016-2021 |Meso|Star> (contact@meso-star.com)
+/* Copyright (C) 2016-2022 |Meso|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
@@ -27,12 +27,58 @@
#include "sdis_Xd_begin.h"
/*******************************************************************************
- * Helper functions
+ * Non generic helper functions
******************************************************************************/
-static res_T
+#ifndef SDIS_REALISATION_XD_H
+#define SDIS_REALISATION_XD_H
+
+static INLINE int
+check_probe_realisation_args(const struct probe_realisation_args* args)
+{
+ return args
+ && args->rng
+ && args->medium
+ && args->time >= 0
+ && args->picard_order > 0;
+}
+
+static INLINE int
+check_boundary_realisation_args(const struct boundary_realisation_args* args)
+{
+ return args
+ && args->rng
+ && args->uv[0] >= 0
+ && args->uv[0] <= 1
+ && args->uv[1] >= 0
+ && args->uv[1] <= 1
+ && args->time >= 0
+ && args->picard_order > 0
+ && (args->side == SDIS_FRONT || args->side == SDIS_BACK);
+}
+
+static INLINE int
+check_boundary_flux_realisation_args
+ (const struct boundary_flux_realisation_args* args)
+{
+ return args
+ && args->rng
+ && args->uv[0] >= 0
+ && args->uv[0] <= 1
+ && args->uv[1] >= 0
+ && args->uv[1] <= 1
+ && args->time >= 0
+ && args->picard_order > 0
+ && (args->solid_side == SDIS_FRONT || args->solid_side == SDIS_BACK);
+}
+#endif /* SDIS_REALISATION_XD_H */
+
+/*******************************************************************************
+ * Local functions
+ ******************************************************************************/
+res_T
XD(compute_temperature)
(struct sdis_scene* scn,
- const struct rwalk_context* ctx,
+ struct rwalk_context* ctx,
struct XD(rwalk)* rwalk,
struct ssp_rng* rng,
struct XD(temperature)* T)
@@ -51,11 +97,14 @@ XD(compute_temperature)
res_T res = RES_OK;
ASSERT(scn && ctx && rwalk && rng && T);
+ ctx->nbranchings += 1;
+ CHK(ctx->nbranchings <= ctx->max_branchings);
+
if(ctx->heat_path && T->func == XD(boundary_path)) {
heat_vtx = heat_path_get_last_vertex(ctx->heat_path);
}
- do {
+ while(!T->done) {
/* Save the current random walk state */
const struct XD(rwalk) rwalk_bkp = *rwalk;
const struct XD(temperature) T_bkp = *T;
@@ -94,32 +143,23 @@ XD(compute_temperature)
}
heat_vtx = NULL; /* Notify that the first vertex is finalized */
}
+ }
- } while(!T->done);
exit:
#ifndef NDEBUG
sa_release(stack);
#endif
+ ctx->nbranchings -= 1;
return res == RES_BAD_OP_IRRECOVERABLE ? RES_BAD_OP : res;
error:
goto exit;
}
-
-/*******************************************************************************
- * Local functions
- ******************************************************************************/
res_T
XD(probe_realisation)
- (const size_t irealisation, /* For debug */
- struct sdis_scene* scn,
- struct ssp_rng* rng,
- struct sdis_medium* medium,
- const double position[DIM],
- const double time,
- struct green_path_handle* green_path, /* May be NULL */
- struct sdis_heat_path* heat_path, /* May be NULL */
+ (struct sdis_scene* scn,
+ struct probe_realisation_args* args,
double* weight)
{
struct rwalk_context ctx = RWALK_CONTEXT_NULL;
@@ -131,38 +171,37 @@ XD(probe_realisation)
(const struct sdis_medium* mdm,
const struct sdis_rwalk_vertex* vtx);
res_T res = RES_OK;
- ASSERT(medium && position && weight && time >= 0);
- (void)irealisation;
+ ASSERT(scn && weight && check_probe_realisation_args(args));
- switch(medium->type) {
+ switch(args->medium->type) {
case SDIS_FLUID:
T.func = XD(convective_path);
get_initial_temperature = fluid_get_temperature;
- t0 = fluid_get_t0(medium);
+ t0 = fluid_get_t0(args->medium);
break;
case SDIS_SOLID:
T.func = XD(conductive_path);
get_initial_temperature = solid_get_temperature;
- t0 = solid_get_t0(medium);
+ t0 = solid_get_t0(args->medium);
break;
default: FATAL("Unreachable code\n"); break;
}
- dX(set)(rwalk.vtx.P, position);
- rwalk.vtx.time = time;
+ dX(set)(rwalk.vtx.P, args->position);
+ rwalk.vtx.time = args->time;
/* Register the starting position against the heat path */
- type = medium->type == SDIS_SOLID
+ type = args->medium->type == SDIS_SOLID
? SDIS_HEAT_VERTEX_CONDUCTION
: SDIS_HEAT_VERTEX_CONVECTION;
- res = register_heat_vertex(heat_path, &rwalk.vtx, 0, type);
+ res = register_heat_vertex(args->heat_path, &rwalk.vtx, 0, type, 0);
if(res != RES_OK) goto error;
if(t0 >= rwalk.vtx.time) {
double tmp;
/* Check the initial condition. */
rwalk.vtx.time = t0;
- tmp = get_initial_temperature(medium, &rwalk.vtx);
+ tmp = get_initial_temperature(args->medium, &rwalk.vtx);
if(tmp >= 0) {
*weight = tmp;
goto exit;
@@ -177,17 +216,19 @@ XD(probe_realisation)
}
rwalk.hit = SXD_HIT_NULL;
- rwalk.mdm = medium;
-
- ctx.green_path = green_path;
- ctx.heat_path = heat_path;
- ctx.Tarad = scn->ambient_radiative_temperature;
- ctx.Tref3 =
- scn->reference_temperature
- * scn->reference_temperature
- * scn->reference_temperature;
-
- res = XD(compute_temperature)(scn, &ctx, &rwalk, rng, &T);
+ rwalk.mdm = args->medium;
+
+ ctx.green_path = args->green_path;
+ ctx.heat_path = args->heat_path;
+ ctx.Tmin = scn->tmin;
+ ctx.Tmin2 = ctx.Tmin * ctx.Tmin;
+ ctx.Tmin3 = ctx.Tmin * ctx.Tmin2;
+ ctx.That = scn->tmax;
+ ctx.That2 = ctx.That * ctx.That;
+ ctx.That3 = ctx.That * ctx.That2;
+ ctx.max_branchings = args->picard_order - 1;
+
+ res = XD(compute_temperature)(scn, &ctx, &rwalk, args->rng, &T);
if(res != RES_OK) goto error;
ASSERT(T.value >= 0);
@@ -202,13 +243,7 @@ error:
res_T
XD(boundary_realisation)
(struct sdis_scene* scn,
- struct ssp_rng* rng,
- const size_t iprim,
- const double uv[DIM-1],
- const double time,
- const enum sdis_side side,
- struct green_path_handle* green_path, /* May be NULL */
- struct sdis_heat_path* heat_path, /* May be NULL */
+ struct boundary_realisation_args* args,
double* weight)
{
struct rwalk_context ctx = RWALK_CONTEXT_NULL;
@@ -221,23 +256,23 @@ XD(boundary_realisation)
float st[2];
#endif
res_T res = RES_OK;
- ASSERT(uv && weight && time >= 0);
+ ASSERT(scn && weight && check_boundary_realisation_args(args));
T.func = XD(boundary_path);
- rwalk.hit_side = side;
+ rwalk.hit_side = args->side;
rwalk.hit.distance = 0;
- rwalk.vtx.time = time;
+ rwalk.vtx.time = args->time;
rwalk.mdm = NULL; /* The random walk is at an interface between 2 media */
#if SDIS_XD_DIMENSION == 2
- st = (float)uv[0];
+ st = (float)args->uv[0];
#else
- f2_set_d2(st, uv);
+ f2_set_d2(st, args->uv);
#endif
/* Fetch the primitive */
SXD(scene_view_get_primitive
- (scn->sXd(view), (unsigned int)iprim, &rwalk.hit.prim));
+ (scn->sXd(view), (unsigned int)args->iprim, &rwalk.hit.prim));
/* Retrieve the world space position of the probe onto the primitive */
SXD(primitive_get_attrib(&rwalk.hit.prim, SXD_POSITION, st, &attr));
@@ -253,17 +288,21 @@ XD(boundary_realisation)
f2_set(rwalk.hit.uv, st);
#endif
- res = register_heat_vertex(heat_path, &rwalk.vtx, 0/*weight*/,
- SDIS_HEAT_VERTEX_CONDUCTION);
+ res = register_heat_vertex(args->heat_path, &rwalk.vtx, 0/*weight*/,
+ SDIS_HEAT_VERTEX_CONDUCTION, 0/*Branch id*/);
if(res != RES_OK) goto error;
- ctx.green_path = green_path;
- ctx.heat_path = heat_path;
- ctx.Tarad = scn->ambient_radiative_temperature;
- ctx.Tref3 = scn->reference_temperature * scn->reference_temperature
- * scn->reference_temperature;
-
- res = XD(compute_temperature)(scn, &ctx, &rwalk, rng, &T);
+ ctx.green_path = args->green_path;
+ ctx.heat_path = args->heat_path;
+ ctx.Tmin = scn->tmin;
+ ctx.Tmin2 = ctx.Tmin * ctx.Tmin;
+ ctx.Tmin3 = ctx.Tmin * ctx.Tmin2;
+ ctx.That = scn->tmax;
+ ctx.That2 = ctx.That * ctx.That;
+ ctx.That3 = ctx.That * ctx.That2;
+ ctx.max_branchings = args->picard_order - 1;
+
+ res = XD(compute_temperature)(scn, &ctx, &rwalk, args->rng, &T);
if(res != RES_OK) goto error;
*weight = T.value;
@@ -277,12 +316,7 @@ error:
res_T
XD(boundary_flux_realisation)
(struct sdis_scene* scn,
- struct ssp_rng* rng,
- const size_t iprim,
- const double uv[DIM-1],
- const double time,
- const enum sdis_side solid_side,
- const int flux_mask,
+ struct boundary_flux_realisation_args* args,
struct bound_flux_result* result)
{
struct rwalk_context ctx = RWALK_CONTEXT_NULL;
@@ -300,25 +334,36 @@ XD(boundary_flux_realisation)
#endif
double P[SDIS_XD_DIMENSION];
float N[SDIS_XD_DIMENSION];
- const double Tr3 = scn->reference_temperature * scn->reference_temperature
- * scn->reference_temperature;
- const enum sdis_side fluid_side =
- (solid_side == SDIS_FRONT) ? SDIS_BACK : SDIS_FRONT;
+ double Tmin, Tmin2, Tmin3;
+ double That, That2, That3;
+ enum sdis_side fluid_side;
res_T res = RES_OK;
- const char compute_radiative = (flux_mask & FLUX_FLAG_RADIATIVE) != 0;
- const char compute_convective = (flux_mask & FLUX_FLAG_CONVECTIVE) != 0;
- ASSERT(uv && result && time >= 0 );
+ char compute_radiative;
+ char compute_convective;
+ ASSERT(scn && result && check_boundary_flux_realisation_args(args));
#if SDIS_XD_DIMENSION == 2
#define SET_PARAM(Dest, Src) (Dest).u = (Src);
- st = (float)uv[0];
+ st = (float)args->uv[0];
#else
#define SET_PARAM(Dest, Src) f2_set((Dest).uv, (Src));
- f2_set_d2(st, uv);
+ f2_set_d2(st, args->uv);
#endif
+ Tmin = scn->tmin;
+ Tmin2 = Tmin * Tmin;
+ Tmin3 = Tmin * Tmin2;
+ That = scn->tmax;
+ That2 = That * That;
+ That3 = That * That2;
+
+ fluid_side = (args->solid_side/*solid*/==SDIS_FRONT) ? SDIS_BACK : SDIS_FRONT;
+
+ compute_radiative = (args->flux_mask & FLUX_FLAG_RADIATIVE) != 0;
+ compute_convective = (args->flux_mask & FLUX_FLAG_CONVECTIVE) != 0;
+
/* Fetch the primitive */
- SXD(scene_view_get_primitive(scn->sXd(view), (unsigned int)iprim, &prim));
+ SXD(scene_view_get_primitive(scn->sXd(view), (unsigned int)args->iprim, &prim));
/* Retrieve the world space position of the probe onto the primitive */
SXD(primitive_get_attrib(&prim, SXD_POSITION, st, &attr));
@@ -332,33 +377,37 @@ XD(boundary_flux_realisation)
rwalk = XD(RWALK_NULL); \
rwalk.hit_side = (Side); \
rwalk.hit.distance = 0; \
- rwalk.vtx.time = time; \
+ rwalk.vtx.time = args->time; \
rwalk.mdm = (Mdm); \
rwalk.hit.prim = prim; \
SET_PARAM(rwalk.hit, st); \
- ctx.Tarad = scn->ambient_radiative_temperature; \
- ctx.Tref3 = Tr3; \
+ ctx.Tmin = Tmin; \
+ ctx.Tmin3 = Tmin3; \
+ ctx.That = That; \
+ ctx.That2 = That2; \
+ ctx.That3 = That3; \
+ ctx.max_branchings = args->picard_order - 1; \
dX(set)(rwalk.vtx.P, P); \
fX(set)(rwalk.hit.normal, N); \
T = XD(TEMPERATURE_NULL); \
} (void)0
/* Compute boundary temperature */
- RESET_WALK(solid_side, NULL);
+ RESET_WALK(args->solid_side, NULL);
T.func = XD(boundary_path);
- res = XD(compute_temperature)(scn, &ctx, &rwalk, rng, &T);
+ res = XD(compute_temperature)(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)iprim);
+ interf = scene_get_interface(scn, (unsigned)args->iprim);
fluid_mdm = interface_get_medium(interf, fluid_side);
/* Compute radiative temperature */
if(compute_radiative) {
RESET_WALK(fluid_side, fluid_mdm);
T.func = XD(radiative_path);
- res = XD(compute_temperature)(scn, &ctx, &rwalk, rng, &T);
+ res = XD(compute_temperature)(scn, &ctx, &rwalk, args->rng, &T);
if(res != RES_OK) return res;
ASSERT(T.value >= 0);
result->Tradiative = T.value;
@@ -368,7 +417,7 @@ XD(boundary_flux_realisation)
if(compute_convective) {
RESET_WALK(fluid_side, fluid_mdm);
T.func = XD(convective_path);
- res = XD(compute_temperature)(scn, &ctx, &rwalk, rng, &T);
+ res = XD(compute_temperature)(scn, &ctx, &rwalk, args->rng, &T);
if(res != RES_OK) return res;
result->Tfluid = T.value;
}
diff --git a/src/sdis_scene.c b/src/sdis_scene.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 2016-2021 |Meso|Star> (contact@meso-star.com)
+/* Copyright (C) 2016-2022 |Meso|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
@@ -203,40 +203,42 @@ sdis_scene_set_fp_to_meter
res_T
sdis_scene_get_ambient_radiative_temperature
(const struct sdis_scene* scn,
- double* trad)
+ struct sdis_ambient_radiative_temperature* trad)
{
if(!scn || !trad) return RES_BAD_ARG;
- *trad = scn->ambient_radiative_temperature;
+ *trad = scn->trad;
return RES_OK;
}
res_T
-sdis_scene_set_reference_temperature
+sdis_scene_set_ambient_radiative_temperature
(struct sdis_scene* scn,
- const double tref)
+ const struct sdis_ambient_radiative_temperature* trad)
{
- if(!scn || tref < 0) return RES_BAD_ARG;
- scn->reference_temperature = tref;
+ if(!scn) return RES_BAD_ARG;
+ scn->trad = *trad;
return RES_OK;
}
res_T
-sdis_scene_get_reference_temperature
+sdis_scene_get_temperature_range
(const struct sdis_scene* scn,
- double* tref)
+ double t_range[2])
{
- if(!scn || !tref) return RES_BAD_ARG;
- *tref = scn->reference_temperature;
+ if(!scn || !t_range) return RES_BAD_ARG;
+ t_range[0] = scn->tmin;
+ t_range[1] = scn->tmax;
return RES_OK;
}
res_T
-sdis_scene_set_ambient_radiative_temperature
+sdis_scene_set_temperature_range
(struct sdis_scene* scn,
- const double trad)
+ const double t_range[2])
{
- if(!scn) return RES_BAD_ARG;
- scn->ambient_radiative_temperature = trad;
+ if(!scn || !t_range) return RES_BAD_ARG;
+ scn->tmin = t_range[0];
+ scn->tmax = t_range[1];
return RES_OK;
}
@@ -474,7 +476,8 @@ scene_compute_hash(const struct sdis_scene* scn, hash256_T hash)
} else {
S3D(scene_view_primitives_count(scn->s3d_view, &nprims));
}
- WRITE(&scn->reference_temperature, 1);
+ WRITE(&scn->trad.reference, 1);
+ WRITE(&scn->tmax, 1);
WRITE(&scn->fp_to_meter, 1);
FOR_EACH(iprim, 0, nprims) {
struct sdis_interface* interf = NULL;
@@ -539,3 +542,63 @@ exit:
error:
goto exit;
}
+
+res_T
+scene_check_primitive_index(const struct sdis_scene* scn, const size_t iprim)
+{
+ res_T res = RES_OK;
+ ASSERT(scn);
+
+ if(iprim >= scene_get_primitives_count(scn)) {
+ log_err(scn->dev,
+ "%s: invalid primitive identifier `%lu'. "
+ "It must be in the [0 %lu] range.\n",
+ FUNC_NAME,
+ (unsigned long)iprim,
+ (unsigned long)scene_get_primitives_count(scn)-1);
+ res = RES_BAD_ARG;
+ goto error;
+ }
+
+exit:
+ return res;
+error:
+ goto exit;
+}
+
+res_T
+scene_check_dimensionality_2d(const struct sdis_scene* scn)
+{
+ res_T res = RES_OK;
+ ASSERT(scn);
+ if(scene_is_2d(scn) == 0) {
+ log_err(scn->dev,
+ "%s: expects a 2D scene while the input scene is 3D.\n",
+ FUNC_NAME);
+ res = RES_BAD_ARG;
+ goto error;
+ }
+exit:
+ return res;
+error:
+ goto exit;
+}
+
+res_T
+scene_check_dimensionality_3d(const struct sdis_scene* scn)
+{
+ res_T res = RES_OK;
+ ASSERT(scn);
+ if(scene_is_2d(scn) != 0) {
+ log_err(scn->dev,
+ "%s: expects a 3D scene while the input scene is 2D.\n",
+ FUNC_NAME);
+ res = RES_BAD_ARG;
+ goto error;
+ }
+exit:
+ return res;
+error:
+ goto exit;
+}
+
diff --git a/src/sdis_scene_Xd.h b/src/sdis_scene_Xd.h
@@ -1,4 +1,4 @@
-/* Copyright (C) 2016-2021 |Meso|Star> (contact@meso-star.com)
+/* Copyright (C) 2016-2022 |Meso|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
@@ -912,8 +912,9 @@ XD(scene_create)
SDIS(device_ref_get(dev));
scn->dev = dev;
scn->fp_to_meter = args->fp_to_meter;
- scn->ambient_radiative_temperature = args->trad;
- scn->reference_temperature = args->tref;
+ scn->trad = args->trad;
+ scn->tmin = args->t_range[0];
+ scn->tmax = args->t_range[1];
scn->outer_enclosure_id = UINT_MAX;
darray_interf_init(dev->allocator, &scn->interfaces);
darray_medium_init(dev->allocator, &scn->media);
diff --git a/src/sdis_scene_c.h b/src/sdis_scene_c.h
@@ -1,4 +1,4 @@
-/* Copyright (C) 2016-2021 |Meso|Star> (contact@meso-star.com)
+/* Copyright (C) 2016-2022 |Meso|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
@@ -209,8 +209,9 @@ struct sdis_scene {
unsigned outer_enclosure_id;
double fp_to_meter;
- double ambient_radiative_temperature; /* In Kelvin */
- double reference_temperature;
+ struct sdis_ambient_radiative_temperature trad;
+ double tmin; /* Minimum temperature of the system (In Kelvin) */
+ double tmax; /* Maximum temperature of the system (In Kelvin) */
ref_T ref;
struct sdis_device* dev;
@@ -242,7 +243,7 @@ scene_get_medium
* time consuming.
*
* 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
+ * 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). */
extern LOCAL_SYM res_T
@@ -256,6 +257,25 @@ scene_compute_hash
(const struct sdis_scene* scn,
hash256_T hash);
+/* Check that the primitive identifier is valid wrt the scene. If not, the
+ * function prints an error message and returns RES_BAD_ARG. */
+extern LOCAL_SYM res_T
+scene_check_primitive_index
+ (const struct sdis_scene* scn,
+ const size_t iprim);
+
+/* Check that the scene is 2D. If not, the function prints an error message and
+ * returns RES_BAD_ARG */
+extern LOCAL_SYM res_T
+scene_check_dimensionality_2d
+ (const struct sdis_scene* scn);
+
+/* Check that the scene is 3D. If not, the function prints an error message and
+ * returns RES_BAD_ARG */
+extern LOCAL_SYM res_T
+scene_check_dimensionality_3d
+ (const struct sdis_scene* scn);
+
static INLINE void
scene_get_enclosure_ids
(const struct sdis_scene* scn,
@@ -289,7 +309,7 @@ scene_get_enclosure(struct sdis_scene* scn, const unsigned ienc)
return enc;
}
-static FINLINE int
+static INLINE int
scene_is_2d(const struct sdis_scene* scn)
{
ASSERT(scn && (scn->s2d_view || scn->s3d_view));
diff --git a/src/sdis_solve.c b/src/sdis_solve.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 2016-2021 |Meso|Star> (contact@meso-star.com)
+/* Copyright (C) 2016-2022 |Meso|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
@@ -14,14 +14,6 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>. */
#include "sdis.h"
-#include "sdis_camera.h"
-#include "sdis_device_c.h"
-#include "sdis_estimator_c.h"
-#include "sdis_estimator_buffer_c.h"
-#include "sdis_interface_c.h"
-
-#include <star/ssp.h>
-#include <omp.h>
/* Generate the probe solvers */
#define SDIS_XD_DIMENSION 2
@@ -48,170 +40,6 @@
#include "sdis_solve_medium_Xd.h"
/*******************************************************************************
- * Helper functions
- ******************************************************************************/
-static FINLINE uint16_t
-morton2D_decode(const uint32_t u32)
-{
- uint32_t x = u32 & 0x55555555;
- x = (x | (x >> 1)) & 0x33333333;
- x = (x | (x >> 2)) & 0x0F0F0F0F;
- x = (x | (x >> 4)) & 0x00FF00FF;
- x = (x | (x >> 8)) & 0x0000FFFF;
- return (uint16_t)x;
-}
-
-static res_T
-solve_pixel
- (struct sdis_scene* scn,
- struct ssp_rng* rng,
- struct sdis_medium* mdm,
- const struct sdis_camera* cam,
- const double time_range[2], /* Observation time */
- const size_t ipix[2], /* Pixel coordinate in the image plane */
- const size_t nrealisations,
- const int register_paths, /* Combination of enum sdis_heat_path_flag */
- const double pix_sz[2], /* Pixel size in the normalized image plane */
- struct sdis_estimator* estimator)
-{
- struct accum acc_temp = ACCUM_NULL;
- struct accum acc_time = ACCUM_NULL;
- struct sdis_heat_path* pheat_path = NULL;
- size_t irealisation;
- res_T res = RES_OK;
- ASSERT(scn && mdm && rng && cam && ipix && nrealisations);
- ASSERT(pix_sz && pix_sz[0] > 0 && pix_sz[1] > 0);
- ASSERT(estimator && time_range);
-
- FOR_EACH(irealisation, 0, nrealisations) {
- struct time t0, t1;
- double samp[2]; /* Pixel sample */
- double ray_pos[3];
- double ray_dir[3];
- double w = 0;
- struct sdis_heat_path heat_path;
- double time;
- res_T res_simul = RES_OK;
-
- /* Begin time registration */
- time_current(&t0);
-
- time = sample_time(rng, time_range);
- if(register_paths) {
- heat_path_init(scn->dev->allocator, &heat_path);
- pheat_path = &heat_path;
- }
-
- /* Generate a sample into the pixel to estimate */
- samp[0] = ((double)ipix[0] + ssp_rng_canonical(rng)) * pix_sz[0];
- samp[1] = ((double)ipix[1] + ssp_rng_canonical(rng)) * pix_sz[1];
-
- /* Generate a ray starting from the camera position and passing through
- * pixel sample */
- camera_ray(cam, samp, ray_pos, ray_dir);
-
- /* Launch the realisation */
- res_simul = ray_realisation_3d(scn, rng, mdm, ray_pos, ray_dir,
- time, pheat_path, &w);
-
- /* Handle fatal error */
- if(res_simul != RES_OK && res_simul != RES_BAD_OP) {
- res = res_simul;
- goto error;
- }
-
- if(pheat_path) {
- pheat_path->status = res_simul == RES_OK
- ? SDIS_HEAT_PATH_SUCCESS
- : SDIS_HEAT_PATH_FAILURE;
-
- /* Check if the path must be saved regarding the register_paths mask */
- if(!(register_paths & (int)pheat_path->status)) {
- heat_path_release(pheat_path);
- pheat_path = NULL;
- } else { /* Register the sampled path */
- res = estimator_add_and_release_heat_path(estimator, pheat_path);
- if(res != RES_OK) goto error;
- pheat_path = NULL;
- }
- }
-
- /* Stop time registration */
- time_sub(&t0, time_current(&t1), &t0);
-
- if(res_simul == RES_OK) {
- /* Update global accumulators */
- const double usec = (double)time_val(&t0, TIME_NSEC) * 0.001;
- acc_temp.sum += w; acc_temp.sum2 += w*w; ++acc_temp.count;
- acc_time.sum += usec; acc_time.sum2 += usec*usec; ++acc_time.count;
- }
- }
-
- /* Setup the pixel estimator */
- ASSERT(acc_temp.count == acc_time.count);
- estimator_setup_realisations_count(estimator, nrealisations, acc_temp.count);
- estimator_setup_temperature(estimator, acc_temp.sum, acc_temp.sum2);
- estimator_setup_realisation_time(estimator, acc_time.sum, acc_time.sum2);
-
-exit:
- if(pheat_path) heat_path_release(pheat_path);
- return res;
-error:
- goto exit;
-}
-
-static res_T
-solve_tile
- (struct sdis_scene* scn,
- struct ssp_rng* rng,
- struct sdis_medium* mdm,
- const struct sdis_camera* cam,
- const double time_range[2],
- const size_t origin[2], /* Tile origin in image plane */
- const size_t size[2], /* #pixels in X and Y */
- const size_t spp, /* #samples per pixel */
- const int register_paths, /* Combination of enum sdis_heat_path_flag */
- const double pix_sz[2], /* Pixel size in the normalized image plane */
- struct sdis_estimator_buffer* buf)
-{
- size_t mcode; /* Morton code of the tile pixel */
- size_t npixels;
- res_T res = RES_OK;
- ASSERT(scn && rng && mdm && cam && spp && origin);
- ASSERT(size &&size[0] && size[1] && buf);
- ASSERT(pix_sz && pix_sz[0] > 0 && pix_sz[1] > 0 && time_range);
-
- /* Adjust the #pixels to process them wrt a morton order */
- npixels = round_up_pow2(MMAX(size[0], size[1]));
- npixels *= npixels;
-
- FOR_EACH(mcode, 0, npixels) {
- size_t ipix[2];
- struct sdis_estimator* estimator;
-
- ipix[0] = morton2D_decode((uint32_t)(mcode>>0));
- if(ipix[0] >= size[0]) continue;
- ipix[1] = morton2D_decode((uint32_t)(mcode>>1));
- if(ipix[1] >= size[1]) continue;
-
- ipix[0] = ipix[0] + origin[0];
- ipix[1] = ipix[1] + origin[1];
-
- /* Fetch the pixel estimator */
- estimator = estimator_buffer_grab(buf, ipix[0], ipix[1]);
-
- res = solve_pixel(scn, rng, mdm, cam, time_range,
- ipix, spp, register_paths, pix_sz, estimator);
- if(res != RES_OK) goto error;
- }
-
-exit:
- return res;
-error:
- goto exit;
-}
-
-/*******************************************************************************
* Exported functions
******************************************************************************/
res_T
@@ -327,181 +155,6 @@ sdis_solve_boundary_flux
}
res_T
-sdis_solve_camera
- (struct sdis_scene* scn,
- const struct sdis_solve_camera_args* args,
- struct sdis_estimator_buffer** out_buf)
-{
- #define TILE_SIZE 32 /* definition in X & Y of a tile */
- STATIC_ASSERT(IS_POW2(TILE_SIZE), TILE_SIZE_must_be_a_power_of_2);
-
- struct sdis_estimator_buffer* buf = NULL;
- struct sdis_medium* medium = NULL;
- struct accum acc_temp = ACCUM_NULL;
- struct accum acc_time = ACCUM_NULL;
- struct ssp_rng_proxy* rng_proxy = NULL;
- struct ssp_rng** rngs = NULL;
- size_t ntiles_x, ntiles_y, ntiles;
- double pix_sz[2]; /* Size of a pixel in the normalized image plane */
- int64_t mcode; /* Morton code of a tile */
- size_t nrealisations;
- size_t nsuccesses;
- size_t ix, iy;
- size_t i;
- int progress = 0;
- ATOMIC nsolved_tiles = 0;
- ATOMIC res = RES_OK;
-
- if(!scn
- || !args
- || !out_buf
- || !args->cam
- || !args->image_resolution[0]
- || !args->image_resolution[1]
- || !args->spp
- || args->time_range[0] < 0
- || args->time_range[1] < args->time_range[0]
- || ( args->time_range[1] > DBL_MAX
- && args->time_range[0] != args->time_range[1])) {
- res = RES_BAD_ARG;
- goto error;
- }
-
- if(scene_is_2d(scn)) {
- log_err(scn->dev, "%s: 2D scene are not supported.\n", FUNC_NAME);
- goto error;
- }
-
- /* Retrieve the medium in which the submitted position lies */
- res = scene_get_medium(scn, args->cam->position, NULL, &medium);
- if(res != RES_OK) goto error;
-
- if(medium->type != SDIS_FLUID) {
- log_err(scn->dev, "%s: the camera position `%g %g %g' is not in a fluid.\n",
- FUNC_NAME, SPLIT3(args->cam->position));
- res = RES_BAD_ARG;
- goto error;
- }
-
- /* Create the proxy RNG */
- res = ssp_rng_proxy_create(scn->dev->allocator, SSP_RNG_MT19937_64,
- scn->dev->nthreads, &rng_proxy);
- if(res != RES_OK) goto error;
-
- /* Create the per thread RNG */
- rngs = MEM_CALLOC
- (scn->dev->allocator, scn->dev->nthreads, sizeof(struct ssp_rng*));
- if(!rngs) {
- res = RES_MEM_ERR;
- goto error;
- }
- FOR_EACH(i, 0, scn->dev->nthreads) {
- res = ssp_rng_proxy_create_rng(rng_proxy, i, rngs+i);
- if(res != RES_OK) goto error;
- }
-
- ntiles_x = (args->image_resolution[0] + (TILE_SIZE-1)/*ceil*/)/TILE_SIZE;
- ntiles_y = (args->image_resolution[1] + (TILE_SIZE-1)/*ceil*/)/TILE_SIZE;
- ntiles = round_up_pow2(MMAX(ntiles_x, ntiles_y));
- ntiles *= ntiles;
-
- pix_sz[0] = 1.0 / (double)args->image_resolution[0];
- pix_sz[1] = 1.0 / (double)args->image_resolution[1];
-
- /* Create the global estimator */
- res = estimator_buffer_create
- (scn->dev, args->image_resolution[0], args->image_resolution[1], &buf);
- if(res != RES_OK) goto error;
-
- omp_set_num_threads((int)scn->dev->nthreads);
- #pragma omp parallel for schedule(static, 1/*chunk size*/)
- for(mcode = 0; mcode < (int64_t)ntiles; ++mcode) {
- size_t tile_org[2] = {0, 0};
- size_t tile_sz[2] = {0, 0};
- const int ithread = omp_get_thread_num();
- struct ssp_rng* rng = rngs[ithread];
- size_t n;
- int pcent;
- res_T res_local = RES_OK;
-
- if(ATOMIC_GET(&res) != RES_OK) continue;
-
- tile_org[0] = morton2D_decode((uint32_t)(mcode>>0));
- if(tile_org[0] >= ntiles_x) continue; /* Discard tile */
- tile_org[1] = morton2D_decode((uint32_t)(mcode>>1));
- if(tile_org[1] >= ntiles_y) continue; /* Disaard tile */
-
- /* Setup the tile coordinates in the image plane */
- tile_org[0] *= TILE_SIZE;
- tile_org[1] *= TILE_SIZE;
- tile_sz[0] = MMIN(TILE_SIZE, args->image_resolution[0] - tile_org[0]);
- tile_sz[1] = MMIN(TILE_SIZE, args->image_resolution[1] - tile_org[1]);
-
- /* Draw the tile */
- res_local = solve_tile(scn, rng, medium, args->cam, args->time_range,
- tile_org, tile_sz, args->spp, args->register_paths, pix_sz, buf);
- if(res_local != RES_OK) {
- ATOMIC_SET(&res, res_local);
- continue;
- }
-
- /* Update progress */
- n = (size_t)ATOMIC_INCR(&nsolved_tiles);
- pcent = (int)((double)n*100.0 / (double)(ntiles_x*ntiles_y) + 0.5/*round*/);
- #pragma omp critical
- if(pcent > progress) {
- progress = pcent;
- log_info(scn->dev, "Infrared rendering: %3d%%\r", progress);
- }
- }
- if(res != RES_OK) goto error;
-
- /* Add a new line after the progress status */
- log_info(scn->dev, "Infrared rendering: %3d%%\n", progress);
-
- /* Setup the accumulators of the whole estimator buffer */
- acc_temp = ACCUM_NULL;
- acc_time = ACCUM_NULL;
- nsuccesses = 0;
- FOR_EACH(iy, 0, args->image_resolution[1]) {
- FOR_EACH(ix, 0, args->image_resolution[0]) {
- const struct sdis_estimator* estimator;
- SDIS(estimator_buffer_at(buf, ix, iy, &estimator));
- acc_temp.sum += estimator->temperature.sum;
- acc_temp.sum2 += estimator->temperature.sum2;
- acc_temp.count += estimator->temperature.count;
- acc_time.sum += estimator->realisation_time.sum;
- acc_time.sum2 += estimator->realisation_time.sum2;
- acc_time.count += estimator->realisation_time.count;
- nsuccesses += estimator->nrealisations;
- }
- }
-
- nrealisations = args->image_resolution[0]*args->image_resolution[1]*args->spp;
- ASSERT(acc_temp.count == acc_time.count);
- ASSERT(acc_temp.count == nsuccesses);
- estimator_buffer_setup_realisations_count(buf, nrealisations, nsuccesses);
- estimator_buffer_setup_temperature(buf, acc_temp.sum, acc_temp.sum2);
- estimator_buffer_setup_realisation_time(buf, acc_time.sum, acc_time.sum2);
- res = estimator_buffer_save_rng_state(buf, rng_proxy);
- if(res != RES_OK) goto error;
-
-exit:
- if(rngs) {
- FOR_EACH(i, 0, scn->dev->nthreads) {
- if(rngs[i]) SSP(rng_ref_put(rngs[i]));
- }
- MEM_RM(scn->dev->allocator, rngs);
- }
- if(rng_proxy) SSP(rng_proxy_ref_put(rng_proxy));
- if(out_buf) *out_buf = buf;
- return (res_T)res;
-error:
- if(buf) SDIS(estimator_buffer_ref_put(buf));
- goto exit;
-}
-
-res_T
sdis_solve_medium
(struct sdis_scene* scn,
const struct sdis_solve_medium_args* args,
diff --git a/src/sdis_solve_boundary_Xd.h b/src/sdis_solve_boundary_Xd.h
@@ -1,5 +1,5 @@
-/* Copyright (C) 2016-2021 |Meso|Star> (contact@meso-star.com)
- *
+/* Copyright (C) 2016-2022 |Meso|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
@@ -13,16 +13,18 @@
* 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_c.h"
#include "sdis_device_c.h"
#include "sdis_estimator_c.h"
#include "sdis_interface_c.h"
+#include "sdis_log.h"
+#include "sdis_green.h"
#include "sdis_medium_c.h"
#include "sdis_misc.h"
#include "sdis_realisation.h"
#include "sdis_scene_c.h"
#include <rsys/clock_time.h>
-#include <rsys/rsys.h>
#include <star/ssp.h>
#include <omp.h>
@@ -37,7 +39,89 @@ static const struct XD(boundary_context) XD(BOUNDARY_CONTEXT_NULL) = {
};
/*******************************************************************************
- * Help functions
+ * Non generic helper functions
+ ******************************************************************************/
+#ifndef SDIS_SOLVE_BOUNDARY_XD
+#define SDIS_SOLVE_BOUNDARY_XD
+
+static INLINE res_T
+check_solve_boundary_args(const struct sdis_solve_boundary_args* args)
+{
+ if(!args) return RES_BAD_ARG;
+
+ /* Check #realisations */
+ if(!args->nrealisations || args->nrealisations > INT64_MAX) {
+ return RES_BAD_ARG;
+ }
+
+ /* Check the list of primitives */
+ if(!args->primitives || !args->sides || !args->nprimitives) {
+ return RES_BAD_ARG;
+ }
+
+ /* Check time range */
+ if(args->time_range[0] < 0 || args->time_range[1] < args->time_range[0]) {
+ return RES_BAD_ARG;
+ }
+ if(args->time_range[1] > DBL_MAX
+ && args->time_range[0] != args->time_range[1]) {
+ return RES_BAD_ARG;
+ }
+
+ /* Check picard order */
+ if(args->picard_order < 1) {
+ return RES_BAD_ARG;
+ }
+
+ /* Check RNG type */
+ if(!args->rng_state && args->rng_type >= SSP_RNG_TYPES_COUNT__) {
+ return RES_BAD_ARG;
+ }
+
+ return RES_OK;
+}
+
+static INLINE res_T
+check_solve_boundary_flux_args(const struct sdis_solve_boundary_flux_args* args)
+{
+ if(!args) return RES_BAD_ARG;
+
+ /* Check #realisations */
+ if(!args->nrealisations || args->nrealisations > INT64_MAX) {
+ return RES_BAD_ARG;
+ }
+
+ /* Check the list of primitives */
+ if(!args->primitives || !args->nprimitives) {
+ return RES_BAD_ARG;
+ }
+
+ /* Check time range */
+ if(args->time_range[0] < 0 || args->time_range[1] < args->time_range[0]) {
+ return RES_BAD_ARG;
+ }
+ if(args->time_range[1] > DBL_MAX
+ && args->time_range[0] != args->time_range[1]) {
+ return RES_BAD_ARG;
+ }
+
+ /* Check picard order */
+ if(args->picard_order < 1) {
+ return RES_BAD_ARG;
+ }
+
+ /* Check RNG type */
+ if(!args->rng_state && args->rng_type >= SSP_RNG_TYPES_COUNT__) {
+ return RES_BAD_ARG;
+ }
+
+ return RES_OK;
+}
+
+#endif /* SDIS_SOLVE_BOUNDARY_XD */
+
+/*******************************************************************************
+ * Helper functions
******************************************************************************/
static INLINE void
XD(boundary_get_indices)(const unsigned iprim, unsigned ids[DIM], void* context)
@@ -80,63 +164,57 @@ XD(solve_boundary)
struct sdis_green_function** out_green,
struct sdis_estimator** out_estimator)
{
+ /* Time registration */
+ struct time time0, time1;
+ char buf[128]; /* Temporary buffer used to store formated time */
+
+ /* Device variables */
+ struct mem_allocator* allocator = NULL;
+ size_t nthreads = 0;
+
+ /* Stardis variables */
+ struct sdis_estimator* estimator = NULL;
+ struct sdis_green_function* green = NULL;
+ struct sdis_green_function** per_thread_green = NULL;
+
+ /* Random number generator */
+ struct ssp_rng_proxy* rng_proxy = NULL;
+ struct ssp_rng** per_thread_rng = NULL;
+
+ /* XD variables */
struct XD(boundary_context) ctx = XD(BOUNDARY_CONTEXT_NULL);
struct sXd(vertex_data) vdata = SXD_VERTEX_DATA_NULL;
struct sXd(scene)* scene = NULL;
struct sXd(shape)* shape = NULL;
struct sXd(scene_view)* view = NULL;
- struct sdis_estimator* estimator = NULL;
- struct sdis_green_function* green = NULL;
- struct sdis_green_function** greens = NULL;
- struct ssp_rng_proxy* rng_proxy = NULL;
- struct ssp_rng** rngs = NULL;
- struct accum* acc_temps = NULL;
- struct accum* acc_times = NULL;
+
+ /* Miscellaneous */
+ struct accum* per_thread_acc_temp = NULL;
+ struct accum* per_thread_acc_time = NULL;
size_t nrealisations = 0;
int64_t irealisation = 0;
size_t i;
- size_t view_nprims;
- int progress = 0;
+ int32_t* progress = NULL; /* Per process progress bar */
int register_paths = SDIS_HEAT_PATH_NONE;
+ int is_master_process = 1;
ATOMIC nsolved_realisations = 0;
ATOMIC res = RES_OK;
- if(!scn || !args || !args->nrealisations || args->nrealisations > INT64_MAX
- || !args->primitives || !args->sides || !args->nprimitives) {
- res = RES_BAD_ARG;
- goto error;
- }
- if(!out_estimator && !out_green) {
- res = RES_BAD_ARG;
- goto error;
- }
- if(args->time_range[0] < 0 || args->time_range[1] < args->time_range[0]) {
- res = RES_BAD_ARG;
- goto error;
- }
- if(args->time_range[1] > DBL_MAX
- && args->time_range[0] != args->time_range[1]) {
- res = RES_BAD_ARG;
- goto error;
- }
+ if(!scn) { res = RES_BAD_ARG; goto error; }
+ if(!out_estimator && !out_green) { res = RES_BAD_ARG; goto error; }
+ res = check_solve_boundary_args(args);
+ if(res != RES_OK) goto error;
+ res = XD(scene_check_dimensionality)(scn);
+ if(res != RES_OK) goto error;
-#if SDIS_XD_DIMENSION == 2
- if(scene_is_2d(scn) == 0) { res = RES_BAD_ARG; goto error; }
-#else
- if(scene_is_2d(scn) != 0) { res = RES_BAD_ARG; goto error; }
-#endif
+ /* Check the submitted primitive indices */
+ FOR_EACH(i, 0, args->nprimitives) {
+ res = scene_check_primitive_index(scn, args->primitives[i]);
+ if(res != RES_OK) goto error;
+ }
- SXD(scene_view_primitives_count(scn->sXd(view), &view_nprims));
+ /* Check the submitted primitive sides */
FOR_EACH(i, 0, args->nprimitives) {
- if(args->primitives[i] >= view_nprims) {
- log_err(scn->dev,
- "%s: invalid primitive identifier `%lu'. It must be in the [0 %lu] range.\n",
- FUNC_NAME,
- (unsigned long)args->primitives[i],
- (unsigned long)scene_get_primitives_count(scn)-1);
- res = RES_BAD_ARG;
- goto error;
- }
if((unsigned)args->sides[i] >= SDIS_SIDE_NULL__) {
log_err(scn->dev,
"%s: invalid side for the primitive `%lu'.\n",
@@ -146,6 +224,19 @@ XD(solve_boundary)
}
}
+ if(out_green && args->picard_order != 1) {
+ log_err(scn->dev, "%s: the evaluation of the green function does not make "
+ "sense when dealing with the non-linearities of the system; i.e. picard "
+ "order must be set to 1 while it is currently set to %lu.\n",
+ FUNC_NAME, (unsigned long)args->picard_order);
+ res = RES_BAD_ARG;
+ goto error;
+ }
+
+#ifdef SDIS_ENABLE_MPI
+ is_master_process = !scn->dev->use_mpi || scn->dev->mpi_rank == 0;
+#endif
+
/* Create the Star-XD shape of the boundary */
#if SDIS_XD_DIMENSION == 2
res = s2d_shape_create_line_segments(scn->dev->sXd(dev), &shape);
@@ -181,59 +272,59 @@ XD(solve_boundary)
res = sXd(scene_view_create)(scene, SXD_SAMPLE, &view);
if(res != RES_OK) goto error;
- /* Create the proxy RNG */
- if(args->rng_state) {
- res = ssp_rng_proxy_create_from_rng(scn->dev->allocator, args->rng_state,
- scn->dev->nthreads, &rng_proxy);
- if(res != RES_OK) goto error;
- } else {
- res = ssp_rng_proxy_create(scn->dev->allocator, SSP_RNG_MT19937_64,
- scn->dev->nthreads, &rng_proxy);
- if(res != RES_OK) goto error;
- }
+ nthreads = scn->dev->nthreads;
+ allocator = scn->dev->allocator;
- /* Create the per thread RNG */
- rngs = MEM_CALLOC(scn->dev->allocator, scn->dev->nthreads, sizeof(*rngs));
- if(!rngs) { res = RES_MEM_ERR; goto error; }
- FOR_EACH(i, 0, scn->dev->nthreads) {
- res = ssp_rng_proxy_create_rng(rng_proxy, i, rngs+i);
- if(res != RES_OK) 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);
+ if(res != RES_OK) goto error;
+
+ /* Allocate the per process progress status */
+ res = alloc_process_progress(scn->dev, &progress);
+ if(res != RES_OK) goto error;
/* Create the per thread accumulators */
- acc_temps = MEM_CALLOC
- (scn->dev->allocator, scn->dev->nthreads, sizeof(*acc_temps));
- if(!acc_temps) { res = RES_MEM_ERR; goto error; }
- acc_times = MEM_CALLOC
- (scn->dev->allocator, scn->dev->nthreads, sizeof(*acc_times));
- if(!acc_times) { res = RES_MEM_ERR; goto error; }
+ per_thread_acc_temp = MEM_CALLOC(allocator, nthreads, sizeof(struct accum));
+ per_thread_acc_time = MEM_CALLOC(allocator, nthreads, sizeof(struct accum));
+ if(!per_thread_acc_temp) { res = RES_MEM_ERR; goto error; }
+ if(!per_thread_acc_time) { res = RES_MEM_ERR; goto error; }
/* Create the per thread green function */
if(out_green) {
- greens = MEM_CALLOC(scn->dev->allocator, scn->dev->nthreads, sizeof(*greens));
- if(!greens) { res = RES_MEM_ERR; goto error; }
- FOR_EACH(i, 0, scn->dev->nthreads) {
- res = green_function_create(scn, &greens[i]);
- if(res != RES_OK) goto error;
- }
+ res = create_per_thread_green_function(scn, &per_thread_green);
+ if(res != RES_OK) goto error;
}
- /* Create the estimator */
- if(out_estimator) {
+ /* Create the estimator on the master process only. No estimator is needed
+ * for non master process */
+ if(out_estimator && is_master_process) {
res = estimator_create(scn->dev, SDIS_ESTIMATOR_TEMPERATURE, &estimator);
if(res != RES_OK) goto error;
}
- nrealisations = args->nrealisations;
- register_paths = out_estimator ? args->register_paths : SDIS_HEAT_PATH_NONE;
+ /* Synchronise the processes */
+ process_barrier(scn->dev);
+
+ #define PROGRESS_MSG "Solving surface temperature: "
+ print_progress(scn->dev, progress, PROGRESS_MSG);
+
+ /* Begin time registration of the computation */
+ time_current(&time0);
+
+ /* Here we go! Launch the Monte Carlo estimation */
+ nrealisations = compute_process_realisations_count(scn->dev, args->nrealisations);
+ register_paths = out_estimator && is_master_process
+ ? args->register_paths : SDIS_HEAT_PATH_NONE;
omp_set_num_threads((int)scn->dev->nthreads);
#pragma omp parallel for schedule(static)
for(irealisation=0; irealisation<(int64_t)nrealisations; ++irealisation) {
+ struct boundary_realisation_args realis_args = BOUNDARY_REALISATION_ARGS_NULL;
struct time t0, t1;
const int ithread = omp_get_thread_num();
- struct ssp_rng* rng = rngs[ithread];
- struct accum* acc_temp = &acc_temps[ithread];
- struct accum* acc_time = &acc_times[ithread];
+ struct ssp_rng* rng = per_thread_rng[ithread];
+ struct accum* acc_temp = &per_thread_acc_temp[ithread];
+ 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;
struct sdis_heat_path* pheat_path = NULL;
@@ -257,7 +348,8 @@ XD(solve_boundary)
time = sample_time(rng, args->time_range);
if(out_green) {
- res_local = green_function_create_path(greens[ithread], &green_path);
+ res_local = green_function_create_path
+ (per_thread_green[ithread], &green_path);
if(res_local != RES_OK) {
ATOMIC_SET(&res, res_local);
goto error_it;
@@ -298,8 +390,18 @@ XD(solve_boundary)
side = args->sides[prim.prim_id];
/* Invoke the boundary realisation */
- res_simul = XD(boundary_realisation)(scn, rng, iprim, uv, time, side,
- pgreen_path, pheat_path, &w);
+ realis_args.rng = rng;
+ realis_args.iprim = iprim;
+ realis_args.time = time;
+ realis_args.picard_order = args->picard_order;
+ realis_args.side = side;
+ realis_args.green_path = pgreen_path;
+ realis_args.heat_path = pheat_path;
+ realis_args.uv[0] = uv[0];
+#if SDIS_XD_DIMENSION == 3
+ realis_args.uv[1] = uv[1];
+#endif
+ res_simul = XD(boundary_realisation)(scn, &realis_args, &w);
/* Fatal error */
if(res_simul != RES_OK && res_simul != RES_BAD_OP) {
@@ -341,9 +443,9 @@ XD(solve_boundary)
n = (size_t)ATOMIC_INCR(&nsolved_realisations);
pcent = (int)((double)n * 100.0 / (double)nrealisations + 0.5/*round*/);
#pragma omp critical
- if(pcent > progress) {
- progress = pcent;
- log_info(scn->dev, "Solving boundary temperature: %3d%%\r", progress);
+ if(pcent > progress[0]) {
+ progress[0] = pcent;
+ print_progress_update(scn->dev, progress, PROGRESS_MSG);
}
exit_it:
if(pheat_path) heat_path_release(pheat_path);
@@ -351,58 +453,82 @@ XD(solve_boundary)
error_it:
goto exit_it;
}
+ /* Synchronise processes */
+ process_barrier(scn->dev);
+
+ res = gather_res_T(scn->dev, (res_T)res);
if(res != RES_OK) goto error;
- /* Add a new line after the progress status */
- log_info(scn->dev, "Solving boundary temperature: %3d%%\n", progress);
+ print_progress_update(scn->dev, progress, PROGRESS_MSG);
+ log_info(scn->dev, "\n");
+ #undef PROGRESS_MSG
+
+ /* Report computation time */
+ time_sub(&time0, time_current(&time1), &time0);
+ time_dump(&time0, TIME_ALL, NULL, buf, sizeof(buf));
+ log_info(scn->dev, "Surface probe temperature solved in %s.\n", buf);
+
+ /* Gather the RNG proxy sequence IDs and ensure that the RNG proxy state of
+ * the master process is greater than the RNG proxy state of all other
+ * processes */
+ res = gather_rng_proxy_sequence_id(scn->dev, rng_proxy);
+ if(res != RES_OK) goto error;
/* Setup the estimated temperature */
if(out_estimator) {
struct accum acc_temp;
struct accum acc_time;
- sum_accums(acc_temps, scn->dev->nthreads, &acc_temp);
- sum_accums(acc_times, scn->dev->nthreads, &acc_time);
- ASSERT(acc_temp.count == acc_time.count);
-
- estimator_setup_realisations_count(estimator, nrealisations, acc_temp.count);
- estimator_setup_temperature(estimator, acc_temp.sum, acc_temp.sum2);
- estimator_setup_realisation_time(estimator, acc_time.sum, acc_time.sum2);
- res = estimator_save_rng_state(estimator, rng_proxy);
- if(res != RES_OK) goto error;
+ time_current(&time0);
+
+ #define GATHER_ACCUMS(Msg, Acc) { \
+ res = gather_accumulators(scn->dev, Msg, per_thread_##Acc, &Acc); \
+ if(res != RES_OK) goto error; \
+ } (void)0
+ GATHER_ACCUMS(MPI_SDIS_MSG_ACCUM_TEMP, acc_temp);
+ GATHER_ACCUMS(MPI_SDIS_MSG_ACCUM_TIME, acc_time);
+ #undef GATHER_ACCUMS
+
+ time_sub(&time0, time_current(&time1), &time0);
+ time_dump(&time0, TIME_ALL, NULL, buf, sizeof(buf));
+ log_info(scn->dev, "Accumulators gathered in %s.\n", buf);
+
+ /* Return an estimator only on master process */
+ if(is_master_process) {
+ ASSERT(acc_temp.count == acc_time.count);
+ estimator_setup_realisations_count(estimator, args->nrealisations, acc_temp.count);
+ estimator_setup_temperature(estimator, acc_temp.sum, acc_temp.sum2);
+ estimator_setup_realisation_time(estimator, acc_time.sum, acc_time.sum2);
+ res = estimator_save_rng_state(estimator, rng_proxy);
+ if(res != RES_OK) goto error;
+ }
}
/* Setup the green function */
if(out_green) {
- struct accum acc_time;
+ time_current(&time0);
- /* Redux the per thread green function into the green of the 1st thread */
- green = greens[0]; /* Return the green of the 1st thread */
- greens[0] = NULL; /* Make invalid the 1st green for 'on exit' clean up*/
- res = green_function_redux_and_clear(green, greens+1, scn->dev->nthreads-1);
+ res = gather_green_functions
+ (scn, rng_proxy, per_thread_green, per_thread_acc_time, &green);
if(res != RES_OK) goto error;
- /* Finalize the estimated green */
- sum_accums(acc_times, scn->dev->nthreads, &acc_time);
- res = green_function_finalize(green, rng_proxy, &acc_time);
- if(res != RES_OK) goto error;
- }
+ time_sub(&time0, time_current(&time1), &time0);
+ time_dump(&time0, TIME_ALL, NULL, buf, sizeof(buf));
+ log_info(scn->dev, "Green functions gathered in %s.\n", buf);
-exit:
- if(rngs) {
- FOR_EACH(i, 0, scn->dev->nthreads) {
- if(rngs[i]) SSP(rng_ref_put(rngs[i]));
- }
- MEM_RM(scn->dev->allocator, rngs);
- }
- if(greens) {
- FOR_EACH(i, 0, scn->dev->nthreads) {
- if(greens[i]) SDIS(green_function_ref_put(greens[i]));
+ /* Return a green function only on master process */
+ if(!is_master_process) {
+ SDIS(green_function_ref_put(green));
+ green = NULL;
}
- MEM_RM(scn->dev->allocator, greens);
}
- if(acc_temps) MEM_RM(scn->dev->allocator, acc_temps);
- if(acc_times) MEM_RM(scn->dev->allocator, acc_times);
+
+exit:
+ if(per_thread_rng) release_per_thread_rng(scn->dev, per_thread_rng);
+ if(per_thread_green) release_per_thread_green_function(scn, per_thread_green);
+ if(progress) free_process_progress(scn->dev, progress);
+ if(per_thread_acc_temp) MEM_RM(scn->dev->allocator, per_thread_acc_temp);
+ if(per_thread_acc_time) MEM_RM(scn->dev->allocator, per_thread_acc_time);
if(scene) SXD(scene_ref_put(scene));
if(shape) SXD(shape_ref_put(shape));
if(view) SXD(scene_view_ref_put(view));
@@ -411,14 +537,8 @@ exit:
if(out_estimator) *out_estimator = estimator;
return (res_T)res;
error:
- if(estimator) {
- SDIS(estimator_ref_put(estimator));
- estimator = NULL;
- }
- if(green) {
- SDIS(green_function_ref_put(green));
- green = NULL;
- }
+ if(estimator) { SDIS(estimator_ref_put(estimator)); estimator = NULL; }
+ if(green) { SDIS(green_function_ref_put(green)); green = NULL; }
goto exit;
}
@@ -428,59 +548,59 @@ XD(solve_boundary_flux)
const struct sdis_solve_boundary_flux_args* args,
struct sdis_estimator** out_estimator)
{
+ /* Time registration */
+ struct time time0, time1;
+ char buf[128]; /* Temporary buffer used to store formated time */
+
+ /* Stardis variables */
+ struct sdis_estimator* estimator = NULL;
+
+ /* XD variables */
struct XD(boundary_context) ctx = XD(BOUNDARY_CONTEXT_NULL);
struct sXd(vertex_data) vdata = SXD_VERTEX_DATA_NULL;
struct sXd(scene)* scene = NULL;
struct sXd(shape)* shape = NULL;
struct sXd(scene_view)* view = NULL;
- struct sdis_estimator* estimator = NULL;
+
+ /* Random number generator */
struct ssp_rng_proxy* rng_proxy = NULL;
- struct ssp_rng** rngs = NULL;
- struct accum* acc_tp = NULL; /* Per thread temperature accumulator */
- struct accum* acc_ti = NULL; /* Per thread realisation time accumulator */
- struct accum* acc_fl = NULL; /* Per thread flux accumulator */
- struct accum* acc_fc = NULL; /* Per thread convective flux accumulator */
- struct accum* acc_fr = NULL; /* Per thread radiative flux accumulator */
- struct accum* acc_fi = NULL; /* Per thread imposed flux accumulator */
+ struct ssp_rng** per_thread_rng = NULL;
+
+ /* Per thread accumulators */
+ struct accum* per_thread_acc_tp = NULL; /* Temperature accumulator */
+ struct accum* per_thread_acc_ti = NULL; /* Realisation time accumulator */
+ struct accum* per_thread_acc_fl = NULL; /* Flux accumulator */
+ struct accum* per_thread_acc_fc = NULL; /* Convective flux accumulator */
+ struct accum* per_thread_acc_fr = NULL; /* Radiative flux accumulator */
+ struct accum* per_thread_acc_fi = NULL; /* Imposed flux accumulator */
+
+ /* Gathered accumulators */
+ struct accum acc_tp = ACCUM_NULL;
+ struct accum acc_ti = ACCUM_NULL;
+ struct accum acc_fl = ACCUM_NULL;
+ struct accum acc_fc = ACCUM_NULL;
+ struct accum acc_fr = ACCUM_NULL;
+ struct accum acc_fi = ACCUM_NULL;
+
+ /* Miscellaneous */
size_t nrealisations = 0;
int64_t irealisation;
size_t i;
- size_t view_nprims;
- int progress = 0;
+ int32_t* progress = NULL; /* Per process progress bar */
+ int is_master_process = 1;
ATOMIC nsolved_realisations = 0;
ATOMIC res = RES_OK;
- if(!scn
- || !args
- || !args->nrealisations
- || args->nrealisations > INT64_MAX
- || !args->primitives
- || args->time_range[0] < 0
- || args->time_range[1] < args->time_range[0]
- || (args->time_range[1] > DBL_MAX && args->time_range[0] != args->time_range[1])
- || !args->nprimitives
- || !out_estimator) {
- res = RES_BAD_ARG;
- goto error;
- }
+ if(!scn || !out_estimator) { res = RES_BAD_ARG; goto error; }
-#if SDIS_XD_DIMENSION == 2
- if(scene_is_2d(scn) == 0) { res = RES_BAD_ARG; goto error; }
-#else
- if(scene_is_2d(scn) != 0) { res = RES_BAD_ARG; goto error; }
-#endif
+ res = check_solve_boundary_flux_args(args);
+ if(res != RES_OK) goto error;
+ res = XD(scene_check_dimensionality)(scn);
+ if(res != RES_OK) goto error;
- SXD(scene_view_primitives_count(scn->sXd(view), &view_nprims));
FOR_EACH(i, 0, args->nprimitives) {
- if(args->primitives[i] >= view_nprims) {
- log_err(scn->dev,
- "%s: invalid primitive identifier `%lu'. It must be in the [0 %lu] range.\n",
- FUNC_NAME,
- (unsigned long)args->primitives[i],
- (unsigned long)scene_get_primitives_count(scn)-1);
- res = RES_BAD_ARG;
- goto error;
- }
+ res = scene_check_primitive_index(scn, args->primitives[i]);
+ if(res != RES_OK) goto error;
}
/* Create the Star-XD shape of the boundary */
@@ -518,63 +638,70 @@ XD(solve_boundary_flux)
res = sXd(scene_view_create)(scene, SXD_SAMPLE, &view);
if(res != RES_OK) goto error;
- /* Create the proxy RNG */
- if(args->rng_state) {
- res = ssp_rng_proxy_create_from_rng(scn->dev->allocator, args->rng_state,
- scn->dev->nthreads, &rng_proxy);
- if(res != RES_OK) goto error;
- } else {
- res = ssp_rng_proxy_create(scn->dev->allocator, SSP_RNG_MT19937_64,
- scn->dev->nthreads, &rng_proxy);
- if(res != RES_OK) goto error;
- }
+#ifdef SDIS_ENABLE_MPI
+ is_master_process = !scn->dev->use_mpi || scn->dev->mpi_rank == 0;
+#endif
- /* Create the per thread RNG */
- rngs = MEM_CALLOC(scn->dev->allocator, scn->dev->nthreads, sizeof(*rngs));
- if(!rngs) { res = RES_MEM_ERR; goto error; }
- FOR_EACH(i, 0, scn->dev->nthreads) {
- res = ssp_rng_proxy_create_rng(rng_proxy, i, rngs + i);
- if(res != RES_OK) 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);
+ if(res != RES_OK) goto error;
+
+ /* Allocate the per process progress status */
+ res = alloc_process_progress(scn->dev, &progress);
+ if(res != RES_OK) goto error;
/* Create the per thread accumulator */
#define ALLOC_ACCUMS(Dst) { \
Dst = MEM_CALLOC(scn->dev->allocator, scn->dev->nthreads, sizeof(*Dst)); \
if(!Dst) { res = RES_MEM_ERR; goto error; } \
} (void)0
- ALLOC_ACCUMS(acc_tp);
- ALLOC_ACCUMS(acc_ti);
- ALLOC_ACCUMS(acc_fc);
- ALLOC_ACCUMS(acc_fl);
- ALLOC_ACCUMS(acc_fr);
- ALLOC_ACCUMS(acc_fi);
+ ALLOC_ACCUMS(per_thread_acc_tp);
+ ALLOC_ACCUMS(per_thread_acc_ti);
+ ALLOC_ACCUMS(per_thread_acc_fc);
+ ALLOC_ACCUMS(per_thread_acc_fl);
+ ALLOC_ACCUMS(per_thread_acc_fr);
+ ALLOC_ACCUMS(per_thread_acc_fi);
#undef ALLOC_ACCUMS
- /* Create the estimator */
- res = estimator_create(scn->dev, SDIS_ESTIMATOR_FLUX, &estimator);
- if(res != RES_OK) goto error;
+ if(is_master_process) {
+ /* Create the estimator */
+ res = estimator_create(scn->dev, SDIS_ESTIMATOR_FLUX, &estimator);
+ if(res != RES_OK) goto error;
+ }
+
+ /* Synchronise the processes */
+ process_barrier(scn->dev);
+
+ #define PROGRESS_MSG "Solving surface flux: "
+ print_progress(scn->dev, progress, PROGRESS_MSG);
+
+ /* Begin time registration of the computation */
+ time_current(&time0);
- nrealisations = args->nrealisations;
+ /* Here we go! Launch the Monte Carlo estimation */
+ nrealisations = compute_process_realisations_count(scn->dev, args->nrealisations);
omp_set_num_threads((int)scn->dev->nthreads);
#pragma omp parallel for schedule(static)
for(irealisation = 0; irealisation < (int64_t)nrealisations; ++irealisation) {
+ struct boundary_flux_realisation_args realis_args =
+ BOUNDARY_FLUX_REALISATION_ARGS_NULL;
struct time t0, t1;
const int ithread = omp_get_thread_num();
- struct ssp_rng* rng = rngs[ithread];
- struct accum* acc_temp = &acc_tp[ithread];
- struct accum* acc_time = &acc_ti[ithread];
- struct accum* acc_flux = &acc_fl[ithread];
- struct accum* acc_fcon = &acc_fc[ithread];
- struct accum* acc_frad = &acc_fr[ithread];
- struct accum* acc_fimp = &acc_fi[ithread];
+ struct ssp_rng* rng = per_thread_rng[ithread];
+ struct accum* acc_temp = &per_thread_acc_tp[ithread];
+ struct accum* acc_time = &per_thread_acc_ti[ithread];
+ struct accum* acc_flux = &per_thread_acc_fl[ithread];
+ struct accum* acc_fcon = &per_thread_acc_fc[ithread];
+ struct accum* acc_frad = &per_thread_acc_fr[ithread];
+ struct accum* acc_fimp = &per_thread_acc_fi[ithread];
struct sXd(primitive) prim;
struct sdis_interface_fragment frag = SDIS_INTERFACE_FRAGMENT_NULL;
const struct sdis_interface* interf;
const struct sdis_medium *fmd, *bmd;
enum sdis_side solid_side, fluid_side;
struct bound_flux_result result = BOUND_FLUX_RESULT_NULL__;
- const double Tref = scn->reference_temperature;
- double epsilon, hc, hr, imposed_flux, imposed_temp;
+ double epsilon, hc, hr, imposed_flux, imposed_temp, Tref;
size_t iprim;
double uv[DIM - 1];
float st[DIM - 1];
@@ -638,6 +765,7 @@ XD(solve_boundary_flux)
/* Fetch interface parameters */
epsilon = interface_side_get_emissivity(interf, &frag);
+ Tref = interface_side_get_reference_temperature(interf, &frag);
hc = interface_get_convection_coef(interf, &frag);
hr = 4.0 * BOLTZMANN_CONSTANT * Tref * Tref * Tref * epsilon;
frag.side = solid_side;
@@ -655,8 +783,19 @@ XD(solve_boundary_flux)
flux_mask = 0;
if(hr > 0) flux_mask |= FLUX_FLAG_RADIATIVE;
if(hc > 0) flux_mask |= FLUX_FLAG_CONVECTIVE;
- res_simul = XD(boundary_flux_realisation)(scn, rng, iprim, uv, time,
- solid_side, flux_mask, &result);
+
+ /* Invoke the boundary flux realisation */
+ realis_args.rng = rng;
+ realis_args.iprim = iprim;
+ realis_args.time = time;
+ realis_args.picard_order = args->picard_order;
+ realis_args.solid_side = solid_side;
+ realis_args.flux_mask = flux_mask;
+ realis_args.uv[0] = uv[0];
+#if SDIS_XD_DIMENSION == 3
+ realis_args.uv[1] = uv[1];
+#endif
+ res_simul = XD(boundary_flux_realisation)(scn, &realis_args, &result);
/* Stop time registration */
time_sub(&t0, time_current(&t1), &t0);
@@ -701,52 +840,77 @@ XD(solve_boundary_flux)
n = (size_t)ATOMIC_INCR(&nsolved_realisations);
pcent = (int)((double)n * 100.0 / (double)nrealisations + 0.5/*round*/);
#pragma omp critical
- if(pcent > progress) {
- progress = pcent;
- log_info(scn->dev, "Solving boundary flux: %3d%%\r", progress);
+ if(pcent > progress[0]) {
+ progress[0] = pcent;
+ print_progress_update(scn->dev, progress, PROGRESS_MSG);
}
}
+ /* Synchronise processes */
+ process_barrier(scn->dev);
+
+ res = gather_res_T(scn->dev, (res_T)res);
if(res != RES_OK) goto error;
- /* Add a new line after the progress status */
- log_info(scn->dev, "Solving boundary flux: %3d%%\n", progress);
-
- /* Redux the per thread accumulators */
- sum_accums(acc_tp, scn->dev->nthreads, &acc_tp[0]);
- sum_accums(acc_ti, scn->dev->nthreads, &acc_ti[0]);
- sum_accums(acc_fc, scn->dev->nthreads, &acc_fc[0]);
- sum_accums(acc_fr, scn->dev->nthreads, &acc_fr[0]);
- sum_accums(acc_fl, scn->dev->nthreads, &acc_fl[0]);
- sum_accums(acc_fi, scn->dev->nthreads, &acc_fi[0]);
- ASSERT(acc_tp[0].count == acc_fl[0].count);
- ASSERT(acc_tp[0].count == acc_ti[0].count);
- ASSERT(acc_tp[0].count == acc_fr[0].count);
- ASSERT(acc_tp[0].count == acc_fc[0].count);
- ASSERT(acc_tp[0].count == acc_fi[0].count);
+ print_progress_update(scn->dev, progress, PROGRESS_MSG);
+ log_info(scn->dev, "\n");
+ #undef PROGRESS_MSG
- /* Setup the estimated values */
- estimator_setup_realisations_count(estimator, nrealisations, acc_tp[0].count);
- estimator_setup_temperature(estimator, acc_tp[0].sum, acc_tp[0].sum2);
- estimator_setup_realisation_time(estimator, acc_ti[0].sum, acc_ti[0].sum2);
- estimator_setup_flux(estimator, FLUX_CONVECTIVE, acc_fc[0].sum, acc_fc[0].sum2);
- estimator_setup_flux(estimator, FLUX_RADIATIVE, acc_fr[0].sum, acc_fr[0].sum2);
- estimator_setup_flux(estimator, FLUX_IMPOSED, acc_fi[0].sum, acc_fi[0].sum2);
- estimator_setup_flux(estimator, FLUX_TOTAL, acc_fl[0].sum, acc_fl[0].sum2);
-
- res = estimator_save_rng_state(estimator, rng_proxy);
+ /* Report computation time */
+ time_sub(&time0, time_current(&time1), &time0);
+ time_dump(&time0, TIME_ALL, NULL, buf, sizeof(buf));
+ log_info(scn->dev, "Surface flux solved in %s.\n", buf);
+
+ /* Gather the RNG proxy sequence IDs and ensure that the RNG proxy state of
+ * the master process is greater than the RNG proxy state of all other
+ * processes */
+ res = gather_rng_proxy_sequence_id(scn->dev, rng_proxy);
if(res != RES_OK) goto error;
-exit:
- if(rngs) {
- FOR_EACH(i, 0, scn->dev->nthreads) { if(rngs[i]) SSP(rng_ref_put(rngs[i])); }
- MEM_RM(scn->dev->allocator, rngs);
+ time_current(&time0);
+ #define GATHER_ACCUMS(Msg, Acc) { \
+ res = gather_accumulators(scn->dev, Msg, per_thread_##Acc, &Acc); \
+ if(res != RES_OK) goto error; \
+ } (void)0
+ GATHER_ACCUMS(MPI_SDIS_MSG_ACCUM_TEMP, acc_tp);
+ GATHER_ACCUMS(MPI_SDIS_MSG_ACCUM_TIME, acc_ti);
+ GATHER_ACCUMS(MPI_SDIS_MSG_ACCUM_FLUX_CONVECTIVE, acc_fc);
+ GATHER_ACCUMS(MPI_SDIS_MSG_ACCUM_FLUX_IMPOSED, acc_fi);
+ GATHER_ACCUMS(MPI_SDIS_MSG_ACCUM_FLUX_RADIATIVE, acc_fr);
+ GATHER_ACCUMS(MPI_SDIS_MSG_ACCUM_FLUX_TOTAL, acc_fl);
+ #undef GATHER_ACCUMS
+
+ time_sub(&time0, time_current(&time1), &time0);
+ time_dump(&time0, TIME_ALL, NULL, buf, sizeof(buf));
+ log_info(scn->dev, "Accumulators gathered in %s.\n", buf);
+
+ /* Setup the estimated values */
+ if(is_master_process) {
+ ASSERT(acc_tp.count == acc_fl.count);
+ ASSERT(acc_tp.count == acc_ti.count);
+ ASSERT(acc_tp.count == acc_fr.count);
+ ASSERT(acc_tp.count == acc_fc.count);
+ ASSERT(acc_tp.count == acc_fi.count);
+ estimator_setup_realisations_count(estimator, args->nrealisations, acc_tp.count);
+ estimator_setup_temperature(estimator, acc_tp.sum, acc_tp.sum2);
+ estimator_setup_realisation_time(estimator, acc_ti.sum, acc_ti.sum2);
+ estimator_setup_flux(estimator, FLUX_CONVECTIVE, acc_fc.sum, acc_fc.sum2);
+ estimator_setup_flux(estimator, FLUX_RADIATIVE, acc_fr.sum, acc_fr.sum2);
+ estimator_setup_flux(estimator, FLUX_IMPOSED, acc_fi.sum, acc_fi.sum2);
+ estimator_setup_flux(estimator, FLUX_TOTAL, acc_fl.sum, acc_fl.sum2);
+
+ res = estimator_save_rng_state(estimator, rng_proxy);
+ if(res != RES_OK) goto error;
}
- if(acc_tp) MEM_RM(scn->dev->allocator, acc_tp);
- if(acc_ti) MEM_RM(scn->dev->allocator, acc_ti);
- if(acc_fc) MEM_RM(scn->dev->allocator, acc_fc);
- if(acc_fr) MEM_RM(scn->dev->allocator, acc_fr);
- if(acc_fl) MEM_RM(scn->dev->allocator, acc_fl);
- if(acc_fi) MEM_RM(scn->dev->allocator, acc_fi);
+
+exit:
+ if(per_thread_rng) release_per_thread_rng(scn->dev, per_thread_rng);
+ if(per_thread_acc_tp) MEM_RM(scn->dev->allocator, per_thread_acc_tp);
+ if(per_thread_acc_ti) MEM_RM(scn->dev->allocator, per_thread_acc_ti);
+ if(per_thread_acc_fc) MEM_RM(scn->dev->allocator, per_thread_acc_fc);
+ if(per_thread_acc_fr) MEM_RM(scn->dev->allocator, per_thread_acc_fr);
+ if(per_thread_acc_fl) MEM_RM(scn->dev->allocator, per_thread_acc_fl);
+ if(per_thread_acc_fi) MEM_RM(scn->dev->allocator, per_thread_acc_fi);
+ if(progress) free_process_progress(scn->dev, progress);
if(scene) SXD(scene_ref_put(scene));
if(shape) SXD(shape_ref_put(shape));
if(view) SXD(scene_view_ref_put(view));
@@ -754,10 +918,7 @@ exit:
if(out_estimator) *out_estimator = estimator;
return (res_T)res;
error:
- if(estimator) {
- SDIS(estimator_ref_put(estimator));
- estimator = NULL;
- }
+ if(estimator) { SDIS(estimator_ref_put(estimator)); estimator = NULL; }
goto exit;
}
diff --git a/src/sdis_solve_camera.c b/src/sdis_solve_camera.c
@@ -0,0 +1,704 @@
+/* Copyright (C) 2016-2022 |Meso|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_c.h"
+#include "sdis_camera.h"
+#include "sdis_device_c.h"
+#include "sdis_estimator_buffer_c.h"
+#include "sdis_log.h"
+#include "sdis_medium_c.h"
+#include "sdis_realisation.h"
+#include "sdis_scene_c.h"
+#include "sdis_tile.h"
+#ifdef SDIS_ENABLE_MPI
+ #include "sdis_mpi.h"
+#endif
+
+#include <rsys/clock_time.h>
+#include <rsys/cstr.h>
+#include <rsys/list.h>
+#include <rsys/morton.h>
+
+#include <omp.h>
+
+/*******************************************************************************
+ * Helper function
+ ******************************************************************************/
+static res_T
+check_solve_camera_args(const struct sdis_solve_camera_args* args)
+{
+ if(!args) return RES_BAD_ARG;
+ if(!args->cam) return RES_BAD_ARG;
+
+ /* Check the image resolution */
+ if(!args->image_definition[0] || !args->image_definition[1]) {
+ return RES_BAD_ARG;
+ }
+
+ /* Check the number of samples per pixel */
+ if(!args->spp) {
+ return RES_BAD_ARG;
+ }
+
+ /* Check the time range */
+ if(args->time_range[0] < 0 || args->time_range[1] < args->time_range[0]) {
+ return RES_BAD_ARG;
+ }
+ if(args->time_range[1] > DBL_MAX
+ && args->time_range[0] != args->time_range[1]) {
+ return RES_BAD_ARG;
+ }
+
+ /* Check the picard order */
+ if(args->picard_order < 1) {
+ return RES_BAD_ARG;
+ }
+
+ /* Check RNG type */
+ if(!args->rng_state && args->rng_type >= SSP_RNG_TYPES_COUNT__) {
+ return RES_BAD_ARG;
+ }
+
+ return RES_OK;
+}
+
+static res_T
+solve_pixel
+ (struct sdis_scene* scn,
+ struct ssp_rng* rng,
+ struct sdis_medium* mdm,
+ const struct sdis_camera* cam,
+ const double time_range[2], /* Observation time */
+ const size_t ipix[2], /* Pixel coordinate in the image space */
+ const size_t nrealisations,
+ const int register_paths, /* Combination of enum sdis_heat_path_flag */
+ const double pix_sz[2], /* Pixel size in the normalized image plane */
+ const size_t picard_order,
+ struct sdis_estimator* estimator,
+ struct pixel* pixel)
+{
+ struct sdis_heat_path* pheat_path = NULL;
+ size_t irealisation;
+ res_T res = RES_OK;
+ ASSERT(scn && mdm && rng && cam && ipix && nrealisations);
+ ASSERT(pix_sz && pix_sz[0] > 0 && pix_sz[1] > 0);
+ ASSERT(pixel && time_range);
+
+ pixel->acc_temp = ACCUM_NULL;
+ pixel->acc_time = ACCUM_NULL;
+
+ FOR_EACH(irealisation, 0, nrealisations) {
+ struct ray_realisation_args realis_args = RAY_REALISATION_ARGS_NULL;
+ struct time t0, t1;
+ double samp[2]; /* Pixel sample */
+ double ray_pos[3];
+ double ray_dir[3];
+ double w = 0;
+ struct sdis_heat_path heat_path;
+ double time;
+ res_T res_simul = RES_OK;
+
+ /* Begin time registration */
+ time_current(&t0);
+
+ time = sample_time(rng, time_range);
+ if(register_paths) {
+ heat_path_init(scn->dev->allocator, &heat_path);
+ pheat_path = &heat_path;
+ }
+
+ /* Generate a sample into the pixel to estimate */
+ samp[0] = ((double)ipix[0] + ssp_rng_canonical(rng)) * pix_sz[0];
+ samp[1] = ((double)ipix[1] + ssp_rng_canonical(rng)) * pix_sz[1];
+
+ /* Generate a ray starting from the camera position and passing through
+ * pixel sample */
+ camera_ray(cam, samp, ray_pos, ray_dir);
+
+ /* Launch the realisation */
+ realis_args.rng = rng;
+ realis_args.medium = mdm;
+ realis_args.time = time;
+ realis_args.picard_order = picard_order;
+ realis_args.heat_path = pheat_path;
+ d3_set(realis_args.position, ray_pos);
+ d3_set(realis_args.direction, ray_dir);
+ res_simul = ray_realisation_3d(scn, &realis_args, &w);
+
+ /* Handle fatal error */
+ if(res_simul != RES_OK && res_simul != RES_BAD_OP) {
+ res = res_simul;
+ goto error;
+ }
+
+ if(pheat_path) {
+ pheat_path->status = res_simul == RES_OK
+ ? SDIS_HEAT_PATH_SUCCESS
+ : SDIS_HEAT_PATH_FAILURE;
+
+ /* Check if the path must be saved regarding the register_paths mask */
+ if(!(register_paths & (int)pheat_path->status)) {
+ heat_path_release(pheat_path);
+ pheat_path = NULL;
+ } else { /* Register the sampled path */
+ ASSERT(estimator);
+ res = estimator_add_and_release_heat_path(estimator, pheat_path);
+ if(res != RES_OK) goto error;
+ pheat_path = NULL;
+ }
+ }
+
+ /* Stop time registration */
+ time_sub(&t0, time_current(&t1), &t0);
+
+ if(res_simul == RES_OK) {
+ /* Update pixel accumulators */
+ const double usec = (double)time_val(&t0, TIME_NSEC) * 0.001;
+ pixel->acc_temp.sum += w;
+ pixel->acc_temp.sum2 += w*w;
+ pixel->acc_temp.count += 1;
+ pixel->acc_time.sum += usec;
+ pixel->acc_time.sum2 += usec*usec;
+ pixel->acc_time.count += 1;
+ }
+ }
+
+exit:
+ if(pheat_path) heat_path_release(pheat_path);
+ return res;
+error:
+ goto exit;
+}
+
+static res_T
+solve_tile
+ (struct sdis_scene* scn,
+ struct ssp_rng* rng,
+ struct sdis_medium* mdm,
+ const struct sdis_camera* cam,
+ const double time_range[2],
+ const size_t tile_org[2], /* Origin of the tile in pixel space */
+ const size_t tile_size[2], /* #pixels in the tile in X and Y */
+ const size_t spp, /* #samples per pixel */
+ const int register_paths, /* Combination of enum sdis_heat_path_flag */
+ const double pix_sz[2], /* Pixel size in the normalized image plane */
+ const size_t picard_order,
+ struct sdis_estimator_buffer* buf,
+ struct tile* 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(tile_size && tile_size[0] && tile_size[1]);
+ ASSERT(pix_sz && pix_sz[0] > 0 && pix_sz[1] > 0 && time_range);
+
+ /* Adjust the #pixels to process them wrt a morton order */
+ npixels = round_up_pow2(MMAX(tile_size[0], tile_size[1]));
+ npixels *= npixels;
+
+ FOR_EACH(mcode, 0, npixels) {
+ struct pixel* pixel = NULL;
+ struct sdis_estimator* estimator = NULL;
+ uint16_t ipix_tile[2];
+ size_t ipix_image[2];
+
+ ipix_tile[0] = morton2D_decode_u16((uint32_t)(mcode>>0));
+ if(ipix_tile[0] >= tile_size[0]) continue;
+ ipix_tile[1] = morton2D_decode_u16((uint32_t)(mcode>>1));
+ if(ipix_tile[1] >= tile_size[1]) continue;
+
+ pixel = tile_at(tile, ipix_tile[0], ipix_tile[1]);
+
+ /* Compute the pixel coordinates in image space */
+ ipix_image[0] = ipix_tile[0] + tile_org[0];
+ ipix_image[1] = ipix_tile[1] + tile_org[1];
+
+ if(register_paths != SDIS_HEAT_PATH_NONE) {
+ ASSERT(buf);
+ 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, estimator, pixel);
+ if(res != RES_OK) goto error;
+ }
+
+exit:
+ return res;
+error:
+ goto exit;
+}
+
+static INLINE res_T
+setup_estimator_from_pixel
+ (struct sdis_estimator* estimator,
+ const size_t spp, /* #samples per pixel */
+ struct pixel* pixel)
+{
+ ASSERT(estimator && spp && pixel);
+ ASSERT(pixel->acc_temp.count == pixel->acc_time.count);
+ estimator_setup_realisations_count
+ (estimator, spp, pixel->acc_temp.count);
+ estimator_setup_temperature
+ (estimator, pixel->acc_temp.sum, pixel->acc_temp.sum2);
+ estimator_setup_realisation_time
+ (estimator, pixel->acc_time.sum, pixel->acc_time.sum2);
+ return RES_OK;
+}
+
+static res_T
+write_tile
+ (struct sdis_estimator_buffer* buf,
+ const size_t spp, /* #samples per pixel */
+ struct tile* tile)
+{
+ res_T res = RES_OK;
+ size_t tile_org[2];
+ uint16_t x, y;
+ ASSERT(buf && spp && tile);
+
+ tile_org[0] = tile->data.x * TILE_SIZE;
+ tile_org[1] = tile->data.y * TILE_SIZE;
+
+ FOR_EACH(y, 0, TILE_SIZE) {
+ const size_t pix_y = tile_org[1] + y;
+ FOR_EACH(x, 0, TILE_SIZE) {
+ const size_t pix_x = tile_org[0] + x;
+ struct sdis_estimator* estimator = NULL;
+ struct pixel* pixel = NULL;
+
+ estimator = estimator_buffer_grab(buf, pix_x, pix_y);
+ pixel = tile_at(tile, x, y);
+
+ res = setup_estimator_from_pixel(estimator, spp, pixel);
+ if(res != RES_OK) goto error;
+ }
+ }
+
+exit:
+ return res;
+error:
+ goto exit;
+}
+
+static res_T
+write_list_of_tiles
+ (struct sdis_estimator_buffer* buf,
+ const size_t spp, /* #samples per pixel */
+ struct list_node* tiles) /* Tiles to write */
+{
+ struct list_node* node = NULL;
+ res_T res = RES_OK;
+ ASSERT(buf && spp && tiles);
+
+ LIST_FOR_EACH(node, tiles) {
+ struct tile* tile = CONTAINER_OF(node, struct tile, node);
+ res = write_tile(buf, spp, tile);
+ if(res != RES_OK) goto error;
+ }
+
+exit:
+ return res;
+error:
+ goto exit;
+}
+
+#ifndef SDIS_ENABLE_MPI
+static INLINE res_T
+gather_tiles
+ (struct sdis_device* dev,
+ struct sdis_estimator_buffer* buf, /* NULL on non master processes */
+ const size_t spp, /* #realisations per pixel */
+ const size_t ntiles, /* Overall #tiles that must be written into `buf' */
+ struct list_node* tiles) /* List of tiles of the current process */
+{
+ (void)dev, (void)ntiles;
+ return write_list_of_tiles(buf, spp, tiles);
+}
+#else
+/* Gather the tiles and write them into the estimator buffer. The master process
+ * write its own tiles into the estimator buffer. Then, it gathers the tiles
+ * send by non master processes and write them too into the estimator buffer */
+static res_T
+gather_tiles
+ (struct sdis_device* dev,
+ struct sdis_estimator_buffer* buf, /* NULL on non master processes */
+ const size_t spp, /* #realisations per pixel */
+ const size_t ntiles, /* Overall #tiles that must be written into `buf' */
+ struct list_node* tiles) /* List of tiles of the current process */
+{
+ struct tile* tile_temp = NULL;
+ struct list_node* node = NULL;
+ res_T res = RES_OK;
+ ASSERT(dev && spp && tiles);
+
+ if(!dev->use_mpi) {
+ res = write_list_of_tiles(buf, spp, tiles);
+ if(res != RES_OK) goto error;
+ goto exit; /* No more to do */
+ }
+
+ /* Non master process */
+ if(dev->mpi_rank != 0) {
+
+ /* Send to the master process the list of tiles solved by the current
+ * process */
+ LIST_FOR_EACH(node, tiles) {
+ struct tile* tile = CONTAINER_OF(node, struct tile, node);
+ mutex_lock(dev->mpi_mutex);
+ MPI(Send(&tile->data, sizeof(tile->data), MPI_CHAR, 0, MPI_SDIS_MSG_TILE,
+ MPI_COMM_WORLD));
+ mutex_unlock(dev->mpi_mutex);
+ }
+
+ /* Master process */
+ } else {
+ size_t itile;
+ size_t ntiles_master;
+
+ /* Write into the buffer the tiles solved by the master process itself */
+ res = write_list_of_tiles(buf, spp, tiles);
+ if(res != RES_OK) goto error;
+
+ /* Create a temporary tile to store the tile sent by the non master
+ * processes */
+ res = tile_create(dev->allocator, &tile_temp);
+ if(res != RES_OK) {
+ log_err(dev,
+ "Could not allocate the tile to temporary store the tiles sent by "
+ "the non master processes -- %s", res_to_cstr(res));
+ goto error;
+ }
+
+ /* Count the number of tiles rendered onto the master process */
+ ntiles_master = 0;
+ LIST_FOR_EACH(node, tiles) ++ntiles_master;
+ ASSERT(ntiles_master <= ntiles);
+
+ /* Receive the remaining tiles sent by the non master processes */
+ FOR_EACH(itile, ntiles_master, ntiles) {
+ MPI_Request req;
+
+ /* Asynchronously receive a tile */
+ mutex_lock(dev->mpi_mutex);
+ MPI(Irecv(&tile_temp->data, sizeof(tile_temp->data), MPI_CHAR,
+ MPI_ANY_SOURCE, MPI_SDIS_MSG_TILE, MPI_COMM_WORLD, &req));
+ mutex_unlock(dev->mpi_mutex);
+ mpi_waiting_for_request(dev, &req);
+
+ /* Write the tile into the estimator buffer */
+ res = write_tile(buf, spp, tile_temp);
+ if(res != RES_OK) goto error;
+ }
+ }
+
+exit:
+ if(tile_temp) tile_ref_put(tile_temp);
+ return res;
+error:
+ goto exit;
+}
+#endif
+
+/* Setup the accumulators of the whole estimator buffer */
+static res_T
+finalize_estimator_buffer
+ (struct sdis_estimator_buffer* buf,
+ struct ssp_rng_proxy* rng_proxy,
+ const size_t spp) /* #samples per pixel */
+{
+ struct accum acc_temp = ACCUM_NULL;
+ struct accum acc_time = ACCUM_NULL;
+ size_t definition[2];
+ size_t x, y;
+ size_t nrealisations = 0;
+ size_t nsuccesses = 0;
+ res_T res = RES_OK;
+ ASSERT(buf && rng_proxy && spp);
+
+ SDIS(estimator_buffer_get_definition(buf, definition));
+
+ FOR_EACH(y, 0, definition[1]) {
+ FOR_EACH(x, 0, definition[0]) {
+ const struct sdis_estimator* estimator;
+ SDIS(estimator_buffer_at(buf, x, y, &estimator));
+ acc_temp.sum += estimator->temperature.sum;
+ acc_temp.sum2 += estimator->temperature.sum2;
+ acc_temp.count += estimator->temperature.count;
+ acc_time.sum += estimator->realisation_time.sum;
+ acc_time.sum2 += estimator->realisation_time.sum2;
+ acc_time.count += estimator->realisation_time.count;
+ nsuccesses += estimator->nrealisations;
+ }
+ }
+
+ nrealisations = definition[0]*definition[1]*spp;
+ ASSERT(acc_temp.count == acc_time.count);
+ ASSERT(acc_temp.count == nsuccesses);
+ estimator_buffer_setup_realisations_count(buf, nrealisations, nsuccesses);
+ estimator_buffer_setup_temperature(buf, acc_temp.sum, acc_temp.sum2);
+ estimator_buffer_setup_realisation_time(buf, acc_time.sum, acc_time.sum2);
+ res = estimator_buffer_save_rng_state(buf, rng_proxy);
+ if(res != RES_OK) goto error;
+
+exit:
+ return res;
+error:
+ goto exit;
+}
+
+static void
+free_rendered_tiles(struct list_node* tiles)
+{
+ struct list_node* node;
+ struct list_node* tmp;
+ ASSERT(tiles);
+ LIST_FOR_EACH_SAFE(node, tmp, tiles) {
+ struct tile* tile = CONTAINER_OF(node, struct tile, node);
+ list_del(node);
+ tile_ref_put(tile);
+ }
+}
+
+/*******************************************************************************
+ * Exported function
+ ******************************************************************************/
+res_T
+sdis_solve_camera
+ (struct sdis_scene* scn,
+ const struct sdis_solve_camera_args* args,
+ struct sdis_estimator_buffer** out_buf)
+{
+ /* Time registration */
+ struct time time0, time1;
+ char buffer[128]; /* Temporary buffer used to store formated time */
+
+ /* 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;
+
+ /* Miscellaneous */
+ size_t ntiles_x, ntiles_y, ntiles, ntiles_adjusted;
+ size_t ntiles_proc; /* #tiles for the current proc */
+ struct list_node tiles; /* List of tiles rendered by the process */
+ double pix_sz[2]; /* Size of a pixel in the normalized image plane */
+ int64_t mcode; /* Morton code of a tile */
+ int64_t mcode_1st; /* morton code of the 1st tile computed by the process */
+ int64_t mcode_incr; /* Increment toward the next morton code */
+ int32_t* progress = NULL; /* Per process progress bar */
+ int register_paths = SDIS_HEAT_PATH_NONE;
+ int is_master_process = 1;
+ ATOMIC nsolved_tiles = 0;
+ ATOMIC res = RES_OK;
+
+ list_init(&tiles);
+
+ if(!scn || !out_buf) { res = RES_BAD_ARG; goto error; }
+ res = check_solve_camera_args(args);
+ if(res != RES_OK) goto error;
+
+ if(scene_is_2d(scn)) {
+ log_err(scn->dev, "%s: 2D scenes are not supported.\n", FUNC_NAME);
+ goto error;
+ }
+
+ /* Retrieve the medium in which the submitted position lies */
+ res = scene_get_medium(scn, args->cam->position, NULL, &medium);
+ 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);
+ if(res != RES_OK) goto error;
+
+ /* Allocate the per process progress status */
+ res = alloc_process_progress(scn->dev, &progress);
+ if(res != RES_OK) goto error;
+
+ /* Compute the overall number of tiles */
+ ntiles_x = (args->image_definition[0] + (TILE_SIZE-1)/*ceil*/)/TILE_SIZE;
+ ntiles_y = (args->image_definition[1] + (TILE_SIZE-1)/*ceil*/)/TILE_SIZE;
+ ntiles = ntiles_x * ntiles_y;
+ ntiles_adjusted = round_up_pow2(MMAX(ntiles_x, ntiles_y));
+ ntiles_adjusted *= ntiles_adjusted;
+
+#ifdef SDIS_ENABLE_MPI
+ is_master_process = !scn->dev->use_mpi || scn->dev->mpi_rank == 0;
+ if(scn->dev->use_mpi) {
+ mcode_1st = scn->dev->mpi_rank;
+ mcode_incr = scn->dev->mpi_nprocs;
+
+ /* Compute the #tiles of the current proc */
+ ntiles_proc = ntiles / (size_t)scn->dev->mpi_nprocs;
+ if(ntiles % (size_t)scn->dev->mpi_nprocs > (size_t)scn->dev->mpi_rank) {
+ ++ntiles_proc;
+ }
+ } else
+#endif
+ {
+ is_master_process = 1;
+ mcode_1st = 0;
+ mcode_incr = 1;
+ ntiles_proc = ntiles;
+ }
+
+ /* Compute the normalized pixel size */
+ pix_sz[0] = 1.0 / (double)args->image_definition[0];
+ pix_sz[1] = 1.0 / (double)args->image_definition[1];
+
+ /* Create the global estimator on the master process only */
+ if(is_master_process) {
+ res = estimator_buffer_create
+ (scn->dev, args->image_definition[0], args->image_definition[1], &buf);
+ if(res != RES_OK) goto error;
+ }
+
+ /* Synchronise the processes */
+ process_barrier(scn->dev);
+
+ #define PROGRESS_MSG "Rendering: "
+ print_progress(scn->dev, progress, PROGRESS_MSG);
+
+ /* Begin time registration of the computation */
+ time_current(&time0);
+
+ /* Here we go! Launch the Monte Carlo estimation */
+ omp_set_num_threads((int)scn->dev->nthreads);
+ register_paths = is_master_process
+ ? args->register_paths : SDIS_HEAT_PATH_NONE;
+ #pragma omp parallel for schedule(static, 1/*chunk size*/)
+ for(mcode = mcode_1st; mcode < (int64_t)ntiles_adjusted; mcode+=mcode_incr) {
+ size_t tile_org[2] = {0, 0};
+ size_t tile_sz[2] = {0, 0};
+ struct tile* tile = NULL;
+ const int ithread = omp_get_thread_num();
+ struct ssp_rng* rng = per_thread_rng[ithread];
+ size_t n;
+ int pcent;
+ res_T res_local = RES_OK;
+
+ if(ATOMIC_GET(&res) != RES_OK) continue;
+
+ tile_org[0] = morton2D_decode_u16((uint32_t)(mcode>>0));
+ if(tile_org[0] >= ntiles_x) continue; /* Discard tile */
+ tile_org[1] = morton2D_decode_u16((uint32_t)(mcode>>1));
+ if(tile_org[1] >= ntiles_y) continue; /* Disaard tile */
+
+ res_local = tile_create(scn->dev->allocator, &tile);
+ if(tile == NULL) {
+ log_err(scn->dev, "%s: error allocating the tile (%lu, %lu) -- %s\n",
+ FUNC_NAME,
+ (unsigned long)tile_org[0],
+ (unsigned long)tile_org[1],
+ res_to_cstr(res_local));
+ ATOMIC_SET(&res, res_local);
+ continue;
+ }
+
+ /* Register the tile */
+ #pragma omp critical
+ list_add_tail(&tiles, &tile->node);
+
+ /* Setup the tile coordinates */
+ tile->data.x = (uint16_t)tile_org[0];
+ tile->data.y = (uint16_t)tile_org[1];
+
+ /* Setup the tile coordinates in the image plane */
+ tile_org[0] *= TILE_SIZE;
+ tile_org[1] *= TILE_SIZE;
+ tile_sz[0] = MMIN(TILE_SIZE, args->image_definition[0] - tile_org[0]);
+ tile_sz[1] = MMIN(TILE_SIZE, args->image_definition[1] - tile_org[1]);
+
+ /* Draw the tile */
+ res_local = solve_tile
+ (scn, rng, medium, args->cam, args->time_range, tile_org, tile_sz,
+ args->spp, register_paths, pix_sz, args->picard_order, buf, tile);
+ if(res_local != RES_OK) {
+ ATOMIC_SET(&res, res_local);
+ continue;
+ }
+
+ /* Update progress */
+ n = (size_t)ATOMIC_INCR(&nsolved_tiles);
+ pcent = (int)((double)n*100.0 / (double)ntiles_proc + 0.5/*round*/);
+ #pragma omp critical
+ if(pcent > progress[0]) {
+ progress[0] = pcent;
+ print_progress_update(scn->dev, progress, PROGRESS_MSG);
+ }
+ }
+
+ /* Synchronise the processes */
+ process_barrier(scn->dev);
+
+ res = gather_res_T(scn->dev, (res_T)res);
+ if(res != RES_OK) goto error;
+
+ print_progress_update(scn->dev, progress, PROGRESS_MSG);
+ log_info(scn->dev, "\n");
+ #undef PROGRESS_MSG
+
+ /* Report computation time */
+ time_sub(&time0, time_current(&time1), &time0);
+ time_dump(&time0, TIME_ALL, NULL, buffer, sizeof(buffer));
+ log_info(scn->dev, "Image rendered in %s.\n", buffer);
+
+ /* Gather the RNG proxy sequence IDs and ensure that the RNG proxy state of
+ * the master process is greater than the RNG proxy state of all other
+ * processes */
+ res = gather_rng_proxy_sequence_id(scn->dev, rng_proxy);
+ if(res != RES_OK) goto error;
+
+ time_current(&time0);
+
+ res = gather_tiles(scn->dev, buf, args->spp, ntiles, &tiles);
+ if(res != RES_OK) goto error;
+
+ time_sub(&time0, time_current(&time1), &time0);
+ time_dump(&time0, TIME_ALL, NULL, buffer, sizeof(buffer));
+ log_info(scn->dev, "Image tiles gathered in %s.\n", buffer);
+
+ if(is_master_process) {
+ res = finalize_estimator_buffer(buf, rng_proxy, args->spp);
+ if(res != RES_OK) goto error;
+ }
+
+exit:
+ free_rendered_tiles(&tiles);
+ if(per_thread_rng)release_per_thread_rng(scn->dev, per_thread_rng);
+ if(progress) free_process_progress(scn->dev, progress);
+ if(rng_proxy) SSP(rng_proxy_ref_put(rng_proxy));
+ if(out_buf) *out_buf = buf;
+ return (res_T)res;
+error:
+ if(buf) { SDIS(estimator_buffer_ref_put(buf)); buf = NULL; }
+ goto exit;
+}
+
+
diff --git a/src/sdis_solve_medium_Xd.h b/src/sdis_solve_medium_Xd.h
@@ -1,4 +1,4 @@
-/* Copyright (C) 2016-2021 |Meso|Star> (contact@meso-star.com)
+/* Copyright (C) 2016-2022 |Meso|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
@@ -13,8 +13,11 @@
* 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_c.h"
#include "sdis_device_c.h"
#include "sdis_estimator_c.h"
+#include "sdis_interface_c.h"
+#include "sdis_log.h"
#include "sdis_green.h"
#include "sdis_realisation.h"
#include "sdis_scene_c.h"
@@ -23,6 +26,8 @@
#include <rsys/clock_time.h>
#include <rsys/dynamic_array.h>
+#include <omp.h>
+
#include "sdis_Xd_begin.h"
#ifndef SDIS_SOLVE_MEDIUM_XD_H
@@ -135,6 +140,71 @@ sample_medium_enclosure
return enc_cumul_found->enc;
}
+static INLINE res_T
+check_solve_medium_args(const struct sdis_solve_medium_args* args)
+{
+ if(!args) return RES_BAD_ARG;
+
+ /* Check the medium */
+ if(!args->medium) return RES_BAD_ARG;
+
+ /* Check #realisations */
+ if(!args->nrealisations || args->nrealisations > INT64_MAX) {
+ return RES_BAD_ARG;
+ }
+
+ /* Check time range */
+ if(args->time_range[0] < 0 || args->time_range[1] < args->time_range[0]) {
+ return RES_BAD_ARG;
+ }
+ if(args->time_range[1] > DBL_MAX
+ && args->time_range[0] != args->time_range[1]) {
+ return RES_BAD_ARG;
+ }
+
+ /* Check picard order */
+ if(args->picard_order < 1) {
+ return RES_BAD_ARG;
+ }
+
+ /* Check the RNG type */
+ if(!args->rng_state && args->rng_type >= SSP_RNG_TYPES_COUNT__) {
+ return RES_BAD_ARG;
+ }
+
+ return RES_OK;
+}
+
+static INLINE res_T
+check_compute_power_args(const struct sdis_compute_power_args* args)
+{
+ if(!args) return RES_BAD_ARG;
+
+ /* Check the medium */
+ if(!args->medium) return RES_BAD_ARG;
+
+ /* Check #realisations */
+ if(!args->nrealisations || args->nrealisations > INT64_MAX) {
+ return RES_BAD_ARG;
+ }
+
+ /* Check time range */
+ if(args->time_range[0] < 0 || args->time_range[1] < args->time_range[0]) {
+ return RES_BAD_ARG;
+ }
+ if(args->time_range[1] > DBL_MAX
+ && args->time_range[0] != args->time_range[1]) {
+ return RES_BAD_ARG;
+ }
+
+ /* Check the RNG type */
+ if(!args->rng_state && args->rng_type >= SSP_RNG_TYPES_COUNT__) {
+ return RES_BAD_ARG;
+ }
+
+ return RES_OK;
+}
+
#endif /* !SDIS_SOLVE_MEDIUM_XD_H */
/*******************************************************************************
@@ -204,74 +274,73 @@ XD(solve_medium)
struct sdis_green_function** out_green, /* May be NULL <=> No green func */
struct sdis_estimator** out_estimator) /* May be NULL <=> No estimator */
{
- struct darray_enclosure_cumul cumul;
+ /* Time registration */
+ struct time time0, time1;
+ char buf[128]; /* Temporary buffer used to store formated time */
+
+ /* Device variables */
+ struct mem_allocator* allocator = NULL;
+ size_t nthreads = 0;
+
+ /* Stardis variables */
+ struct sdis_estimator* estimator = NULL;
struct sdis_green_function* green = NULL;
- struct sdis_green_function** greens = NULL;
+ struct sdis_green_function** per_thread_green = NULL;
+
+ /* Random number generator */
struct ssp_rng_proxy* rng_proxy = NULL;
- struct ssp_rng** rngs = NULL;
- struct sdis_estimator* estimator = NULL;
- struct accum* acc_temps = NULL;
- struct accum* acc_times = NULL;
+ struct ssp_rng** per_thread_rng = NULL;
+
+ /* Miscellaneous */
+ struct darray_enclosure_cumul cumul;
+ struct accum* per_thread_acc_temp = NULL;
+ struct accum* per_thread_acc_time = NULL;
size_t nrealisations = 0;
int64_t irealisation;
+ int32_t* progress = NULL; /* Per process progress bar */
+ int is_master_process = 1;
int cumul_is_init = 0;
- size_t i;
- int progress = 0;
int register_paths = SDIS_HEAT_PATH_NONE;
ATOMIC nsolved_realisations = 0;
ATOMIC res = RES_OK;
- if(!scn || !args || !args->medium || !args->nrealisations
- || args->nrealisations > INT64_MAX) {
- res = RES_BAD_ARG;
- goto error;
- }
- if(!out_estimator && !out_green) {
+ if(!scn) { res = RES_BAD_ARG; goto error; }
+ if(!out_estimator && !out_green) { res = RES_BAD_ARG; goto error; }
+ res = check_solve_medium_args(args);
+ if(res != RES_OK) goto error;
+ res = XD(scene_check_dimensionality)(scn);
+ if(res != RES_OK) goto error;
+
+ if(out_green && args->picard_order != 1) {
+ log_err(scn->dev, "%s: the evaluation of the green function does not make "
+ "sense when dealing with the non-linearities of the system; i.e. picard "
+ "order must be set to 1 while it is currently set to %lu.\n",
+ FUNC_NAME, (unsigned long)args->picard_order);
res = RES_BAD_ARG;
goto error;
}
- if(out_estimator) {
- if(args->time_range[0] < 0
- || args->time_range[0] > args->time_range[1]
- || ( args->time_range[1] > DBL_MAX
- && args->time_range[0] != args->time_range[1])) {
- res = RES_BAD_ARG;
- goto error;
- }
- }
-#if SDIS_XD_DIMENSION == 2
- if(scene_is_2d(scn) == 0) { res = RES_BAD_ARG; goto error; }
-#else
- if(scene_is_2d(scn) != 0) { res = RES_BAD_ARG; goto error; }
+#ifdef SDIS_ENABLE_MPI
+ is_master_process = !scn->dev->use_mpi || scn->dev->mpi_rank == 0;
#endif
- /* Create the proxy RNG */
- if(args->rng_state) {
- res = ssp_rng_proxy_create_from_rng(scn->dev->allocator, args->rng_state,
- scn->dev->nthreads, &rng_proxy);
- if(res != RES_OK) goto error;
- } else {
- res = ssp_rng_proxy_create(scn->dev->allocator, SSP_RNG_MT19937_64,
- scn->dev->nthreads, &rng_proxy);
- if(res != RES_OK) goto error;
- }
+ nthreads = scn->dev->nthreads;
+ allocator = scn->dev->allocator;
- /* Create the per thread RNG */
- rngs = MEM_CALLOC(scn->dev->allocator, scn->dev->nthreads, sizeof(*rngs));
- if(!rngs) { res = RES_MEM_ERR; goto error; }
- FOR_EACH(i, 0, scn->dev->nthreads) {
- res = ssp_rng_proxy_create_rng(rng_proxy, i, rngs+i);
- if(res != RES_OK) 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);
+ if(res != RES_OK) goto error;
+
+ /* Allocate the per process progress status */
+ res = alloc_process_progress(scn->dev, &progress);
+ if(res != RES_OK) goto error;
/* Create the per thread accumulators */
- acc_temps = MEM_CALLOC
- (scn->dev->allocator, scn->dev->nthreads, sizeof(*acc_temps));
- if(!acc_temps) { res = RES_MEM_ERR; goto error; }
- acc_times = MEM_CALLOC
- (scn->dev->allocator, scn->dev->nthreads, sizeof(*acc_times));
- if(!acc_times) { res = RES_MEM_ERR; goto error; }
+ per_thread_acc_temp = MEM_CALLOC(allocator, nthreads, sizeof(struct accum));
+ per_thread_acc_time = MEM_CALLOC(allocator, nthreads, sizeof(struct accum));
+ if(!per_thread_acc_temp) { res = RES_MEM_ERR; goto error; }
+ if(!per_thread_acc_time) { res = RES_MEM_ERR; goto error; }
/* Compute the enclosure cumulative */
darray_enclosure_cumul_init(scn->dev->allocator, &cumul);
@@ -280,31 +349,39 @@ XD(solve_medium)
if(res != RES_OK) goto error;
if(out_green) {
- /* Create the per thread green function */
- greens = MEM_CALLOC(scn->dev->allocator, scn->dev->nthreads, sizeof(*greens));
- if(!greens) { res = RES_MEM_ERR; goto error; }
- FOR_EACH(i, 0, scn->dev->nthreads) {
- res = green_function_create(scn, &greens[i]);
- if(res != RES_OK) goto error;
- }
+ res = create_per_thread_green_function(scn, &per_thread_green);
+ if(res != RES_OK) goto error;
}
- /* Create the estimator */
- if(out_estimator) {
+ /* Create the estimator on the master process only. No estimator is needed
+ * for non master process */
+ if(out_estimator && is_master_process) {
res = estimator_create(scn->dev, SDIS_ESTIMATOR_TEMPERATURE, &estimator);
if(res != RES_OK) goto error;
}
- nrealisations = args->nrealisations;
- register_paths = out_estimator ? args->register_paths : SDIS_HEAT_PATH_NONE;
+ /* Synchronise the processes */
+ process_barrier(scn->dev);
+
+ #define PROGRESS_MSG "Solving medium temperature: "
+ print_progress(scn->dev, progress, PROGRESS_MSG);
+
+ /* Begin time registration of the computation */
+ time_current(&time0);
+
+ /* Here we go! Launch the Monte Carlo estimation */
+ nrealisations = compute_process_realisations_count(scn->dev, args->nrealisations);
+ register_paths = out_estimator && is_master_process
+ ? args->register_paths : SDIS_HEAT_PATH_NONE;
omp_set_num_threads((int)scn->dev->nthreads);
#pragma omp parallel for schedule(static)
for(irealisation = 0; irealisation < (int64_t)nrealisations; ++irealisation) {
+ struct probe_realisation_args realis_args = PROBE_REALISATION_ARGS_NULL;
struct time t0, t1;
const int ithread = omp_get_thread_num();
- struct ssp_rng* rng = rngs[ithread];
- struct accum* acc_temp = &acc_temps[ithread];
- struct accum* acc_time = &acc_times[ithread];
+ struct ssp_rng* rng = per_thread_rng[ithread];
+ struct accum* acc_temp = &per_thread_acc_temp[ithread];
+ 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;
@@ -321,14 +398,11 @@ XD(solve_medium)
if(ATOMIC_GET(&res) != RES_OK) continue; /* An error occurred */
time_current(&t0);
-
+
time = sample_time(rng, args->time_range);
if(out_green) {
- res_local = green_function_create_path(greens[ithread], &green_path);
- if(res_local != RES_OK) {
- ATOMIC_SET(&res, res_local);
- goto error_it;
- }
+ res_local = green_function_create_path(per_thread_green[ithread], &green_path);
+ if(res_local != RES_OK) { ATOMIC_SET(&res, res_local); goto error_it; }
pgreen_path = &green_path;
}
@@ -348,9 +422,15 @@ XD(solve_medium)
}
/* Run a probe realisation */
- res_simul = XD(probe_realisation)((size_t)irealisation, scn, rng,
- args->medium, pos, time, pgreen_path, pheat_path, &weight);
-
+ realis_args.rng = rng;
+ realis_args.medium = args->medium;
+ realis_args.time = time;
+ realis_args.picard_order = args->picard_order;
+ realis_args.green_path = pgreen_path;
+ realis_args.heat_path = pheat_path;
+ realis_args.irealisation = (size_t)irealisation;
+ dX(set)(realis_args.position, pos);
+ res_simul = XD(probe_realisation)(scn, &realis_args, &weight);
if(res_simul != RES_OK && res_simul != RES_BAD_OP) {
ATOMIC_SET(&res, res_simul);
goto error_it;
@@ -390,9 +470,9 @@ XD(solve_medium)
n = (size_t)ATOMIC_INCR(&nsolved_realisations);
pcent = (int)((double)n * 100.0 / (double)nrealisations + 0.5/*round*/);
#pragma omp critical
- if(pcent > progress) {
- progress = pcent;
- log_info(scn->dev, "Solving medium temperature: %3d%%\r", progress);
+ if(pcent > progress[0]) {
+ progress[0] = pcent;
+ print_progress_update(scn->dev, progress, PROGRESS_MSG);
}
exit_it:
if(pheat_path) heat_path_release(pheat_path);
@@ -400,71 +480,89 @@ XD(solve_medium)
error_it:
goto exit_it;
}
+ /* Synchronise processes */
+ process_barrier(scn->dev);
+
+ res = gather_res_T(scn->dev, (res_T)res);
if(res != RES_OK) goto error;
- /* Add a new line after the progress status */
- log_info(scn->dev, "Solving medium temperature: %3d%%\n", progress);
+ print_progress_update(scn->dev, progress, PROGRESS_MSG);
+ log_info(scn->dev, "\n");
+ #undef PROGRESS_MSG
+
+ /* Report computation time */
+ time_sub(&time0, time_current(&time1), &time0);
+ time_dump(&time0, TIME_ALL, NULL, buf, sizeof(buf));
+ log_info(scn->dev, "Medium temperature solved in %s.\n", buf);
+
+ /* Gather the RNG proxy sequence IDs and ensure that the RNG proxy state of
+ * the master process is greater than the RNG proxy state of all other
+ * processes */
+ res = gather_rng_proxy_sequence_id(scn->dev, rng_proxy);
+ if(res != RES_OK) goto error;
/* Setup the estimated temperature */
if(out_estimator) {
struct accum acc_temp;
struct accum acc_time;
- sum_accums(acc_temps, scn->dev->nthreads, &acc_temp);
- sum_accums(acc_times, scn->dev->nthreads, &acc_time);
- ASSERT(acc_temp.count == acc_time.count);
-
- estimator_setup_realisations_count(estimator, nrealisations, acc_temp.count);
- estimator_setup_temperature(estimator, acc_temp.sum, acc_temp.sum2);
- estimator_setup_realisation_time(estimator, acc_time.sum, acc_time.sum2);
- res = estimator_save_rng_state(estimator, rng_proxy);
- if(res != RES_OK) goto error;
+ time_current(&time0);
+
+ #define GATHER_ACCUMS(Msg, Acc) { \
+ res = gather_accumulators(scn->dev, Msg, per_thread_##Acc, &Acc); \
+ if(res != RES_OK) goto error; \
+ } (void)0
+ GATHER_ACCUMS(MPI_SDIS_MSG_ACCUM_TEMP, acc_temp);
+ GATHER_ACCUMS(MPI_SDIS_MSG_ACCUM_TIME, acc_time);
+ #undef GATHER_ACCUMS
+
+ time_sub(&time0, time_current(&time1), &time0);
+ time_dump(&time0, TIME_ALL, NULL, buf, sizeof(buf));
+ log_info(scn->dev, "Accumulators gathered in %s.\n", buf);
+
+ /* Return an estimator only on master process */
+ if(is_master_process) {
+ ASSERT(acc_temp.count == acc_time.count);
+ estimator_setup_realisations_count(estimator, args->nrealisations, acc_temp.count);
+ estimator_setup_temperature(estimator, acc_temp.sum, acc_temp.sum2);
+ estimator_setup_realisation_time(estimator, acc_time.sum, acc_time.sum2);
+ res = estimator_save_rng_state(estimator, rng_proxy);
+ if(res != RES_OK) goto error;
+ }
}
if(out_green) {
- struct accum acc_time;
+ time_current(&time0);
- /* Redux the per thread green function into the green of the 1st thread */
- green = greens[0]; /* Return the green of the 1st thread */
- greens[0] = NULL; /* Make invalid the 1st green for 'on exit' clean up*/
- res = green_function_redux_and_clear(green, greens+1, scn->dev->nthreads-1);
+ res = gather_green_functions
+ (scn, rng_proxy, per_thread_green, per_thread_acc_time, &green);
if(res != RES_OK) goto error;
- /* Finalize the estimated green */
- sum_accums(acc_times, scn->dev->nthreads, &acc_time);
- res = green_function_finalize(green, rng_proxy, &acc_time);
- if(res != RES_OK) goto error;
- }
+ time_sub(&time0, time_current(&time1), &time0);
+ time_dump(&time0, TIME_ALL, NULL, buf, sizeof(buf));
+ log_info(scn->dev, "Green functions gathered in %s.\n", buf);
-exit:
- if(rngs) {
- FOR_EACH(i, 0, scn->dev->nthreads) {
- if(rngs[i]) SSP(rng_ref_put(rngs[i]));
- }
- MEM_RM(scn->dev->allocator, rngs);
- }
- if(greens) {
- FOR_EACH(i, 0, scn->dev->nthreads) {
- if(greens[i]) SDIS(green_function_ref_put(greens[i]));
+ /* Return a green function only on master process */
+ if(!is_master_process) {
+ SDIS(green_function_ref_put(green));
+ green = NULL;
}
- MEM_RM(scn->dev->allocator, greens);
}
- if(acc_temps) MEM_RM(scn->dev->allocator, acc_temps);
- if(acc_times) MEM_RM(scn->dev->allocator, acc_times);
+
+exit:
+ if(per_thread_rng) release_per_thread_rng(scn->dev, per_thread_rng);
+ if(per_thread_green) release_per_thread_green_function(scn, per_thread_green);
+ if(progress) free_process_progress(scn->dev, progress);
+ if(per_thread_acc_temp) MEM_RM(scn->dev->allocator, per_thread_acc_temp);
+ if(per_thread_acc_time) MEM_RM(scn->dev->allocator, per_thread_acc_time);
if(cumul_is_init) darray_enclosure_cumul_release(&cumul);
if(rng_proxy) SSP(rng_proxy_ref_put(rng_proxy));
if(out_estimator) *out_estimator = estimator;
if(out_green) *out_green = green;
return (res_T)res;
error:
- if(green) {
- SDIS(green_function_ref_put(green));
- green = NULL;
- }
- if(estimator) {
- SDIS(estimator_ref_put(estimator));
- estimator = NULL;
- }
+ if(green) { SDIS(green_function_ref_put(green)); green = NULL; }
+ if(estimator) { SDIS(estimator_ref_put(estimator)); estimator = NULL; }
goto exit;
}
@@ -474,39 +572,40 @@ XD(compute_power)
const struct sdis_compute_power_args* args,
struct sdis_estimator** out_estimator)
{
- struct darray_enclosure_cumul cumul;
+ /* Time registration */
+ struct time time0, time1;
+ char buf[128]; /* Temporary buffer used to store formated time */
+
+ /* Device variables */
+ struct mem_allocator* allocator = NULL;
+ size_t nthreads = 0;
+
+ /* Stardis variables */
struct sdis_estimator* estimator = NULL;
+
+ /* Random number generator */
struct ssp_rng_proxy* rng_proxy = NULL;
- struct ssp_rng** rngs = NULL;
- struct accum* acc_mpows = NULL;
- struct accum* acc_times = NULL;
+ struct ssp_rng** per_thread_rng = NULL;
+
+ /* Miscellaneous */
+ struct darray_enclosure_cumul cumul;
+ struct accum* per_thread_acc_mpow = NULL;
+ struct accum* per_thread_acc_time = NULL;
double spread = 0;
- size_t i = 0;
size_t nrealisations = 0;
int64_t irealisation = 0;
+ int32_t* progress = NULL; /* Per process progress bar */
int cumul_is_init = 0;
- int progress = 0;
+ int is_master_process = 1;
ATOMIC nsolved_realisations = 0;
ATOMIC res = RES_OK;
- if(!scn
- || !args
- || !out_estimator
- || !args->medium
- || !args->nrealisations
- || args->nrealisations > INT64_MAX
- || args->time_range[0] < 0
- || args->time_range[0] > args->time_range[1]
- || ( args->time_range[1] > DBL_MAX
- && args->time_range[0] != args->time_range[1])) {
- res = RES_BAD_ARG;
- goto error;
- }
-
- if(scene_is_2d(scn) != (SDIS_XD_DIMENSION==2)) {
- res = RES_BAD_ARG;
- goto error;
- }
+ if(!scn) { res = RES_BAD_ARG; goto error; }
+ if(!out_estimator) { res = RES_BAD_ARG; goto error; }
+ res = check_compute_power_args(args);
+ if(res != RES_OK) goto error;
+ res = XD(scene_check_dimensionality)(scn);
+ if(res != RES_OK) goto error;
if(sdis_medium_get_type(args->medium) != SDIS_SOLID) {
log_err(scn->dev, "Could not compute mean power on a non solid medium.\n");
@@ -514,32 +613,27 @@ XD(compute_power)
goto error;
}
- /* Create the RNG proxy */
- if(args->rng_state) {
- res = ssp_rng_proxy_create_from_rng(scn->dev->allocator, args->rng_state,
- scn->dev->nthreads, &rng_proxy);
- if(res != RES_OK) goto error;
- } else {
- res = ssp_rng_proxy_create(scn->dev->allocator, SSP_RNG_MT19937_64,
- scn->dev->nthreads, &rng_proxy);
- if(res != RES_OK) goto error;
- }
+#ifdef SDIS_ENABLE_MPI
+ is_master_process = !scn->dev->use_mpi || scn->dev->mpi_rank == 0;
+#endif
- /* Create the per thread RNG */
- rngs = MEM_CALLOC(scn->dev->allocator, scn->dev->nthreads, sizeof(*rngs));
- if(!rngs) { res = RES_MEM_ERR; goto error; }
- FOR_EACH(i, 0, scn->dev->nthreads) {
- res = ssp_rng_proxy_create_rng(rng_proxy, i, rngs+i);
- if(res != RES_OK) goto error;
- }
+ nthreads = scn->dev->nthreads;
+ allocator = scn->dev->allocator;
+
+ /* Create the per thread RNGs */
+ res = create_per_thread_rng
+ (scn->dev, args->rng_state, args->rng_type, &rng_proxy, &per_thread_rng);
+ if(res != RES_OK) goto error;
+
+ /* Allocate the per process progress status */
+ res = alloc_process_progress(scn->dev, &progress);
+ if(res != RES_OK) goto error;
/* Create the per thread accumulators */
- acc_mpows = MEM_CALLOC
- (scn->dev->allocator, scn->dev->nthreads, sizeof(*acc_mpows));
- if(!acc_mpows) { res = RES_MEM_ERR; goto error; }
- acc_times = MEM_CALLOC
- (scn->dev->allocator, scn->dev->nthreads, sizeof(*acc_times));
- if(!acc_times) { res = RES_MEM_ERR; goto error; }
+ per_thread_acc_mpow = MEM_CALLOC(allocator, nthreads, sizeof(struct accum));
+ per_thread_acc_time = MEM_CALLOC(allocator, nthreads, sizeof(struct accum));
+ if(!per_thread_acc_mpow) { res = RES_MEM_ERR; goto error; }
+ if(!per_thread_acc_time) { res = RES_MEM_ERR; goto error; }
/* Compute the cumulative of the spreads of the enclosures surrounding the
* submitted medium */
@@ -552,20 +646,33 @@ XD(compute_power)
spread = darray_enclosure_cumul_cdata_get(&cumul)
[darray_enclosure_cumul_size_get(&cumul)-1].cumul;
- /* Create the estimator */
- res = estimator_create(scn->dev, SDIS_ESTIMATOR_POWER, &estimator);
- if(res != RES_OK) goto error;
+ /* Create the estimator on the master process only. No estimator is needed
+ * for non master process */
+ if(is_master_process) {
+ res = estimator_create(scn->dev, SDIS_ESTIMATOR_POWER, &estimator);
+ if(res != RES_OK) goto error;
+ }
+
+ /* Synchronise the processes */
+ process_barrier(scn->dev);
+
+ #define PROGRESS_MSG "Computing mean power: "
+ print_progress(scn->dev, progress, PROGRESS_MSG);
- nrealisations = args->nrealisations;
+ /* Begin time registration of the computation */
+ time_current(&time0);
+
+ /* Here we go! Launch the Monte Carlo estimation */
+ nrealisations = compute_process_realisations_count(scn->dev, args->nrealisations);
omp_set_num_threads((int)scn->dev->nthreads);
#pragma omp parallel for schedule(static)
for(irealisation = 0; irealisation < (int64_t)nrealisations; ++irealisation) {
struct time t0, t1;
struct sdis_rwalk_vertex vtx = SDIS_RWALK_VERTEX_NULL;
const int ithread = omp_get_thread_num();
- struct ssp_rng* rng = rngs[ithread];
- struct accum* acc_mpow = &acc_mpows[ithread];
- struct accum* acc_time = &acc_times[ithread];
+ 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;
@@ -606,52 +713,78 @@ XD(compute_power)
n = (size_t)ATOMIC_INCR(&nsolved_realisations);
pcent = (int)((double)n * 100.0 / (double)nrealisations + 0.5/*round*/);
#pragma omp critical
- if(pcent > progress) {
- progress = pcent;
- log_info(scn->dev, "Computing mean power: %3d%%\r", progress);
+ if(pcent > progress[0]) {
+ progress[0] = pcent;
+ print_progress_update(scn->dev, progress, PROGRESS_MSG);
}
exit_it:
continue;
error_it:
goto exit_it;
}
+ /* Synchronise the processes */
+ process_barrier(scn->dev);
+
+ res = gather_res_T(scn->dev, (res_T)res);
if(res != RES_OK) goto error;
- /* Add a new line after the progress status */
- log_info(scn->dev, "Computing mean power: %3d%%\n", progress);
+ print_progress_update(scn->dev, progress, PROGRESS_MSG);
+ log_info(scn->dev, "\n");
+ #undef PROGRESS_MSG
+
+ /* Report computation time */
+ time_sub(&time0, time_current(&time1), &time0);
+ time_dump(&time0, TIME_ALL, NULL, buf, sizeof(buf));
+ log_info(scn->dev, "Mean power computed in in %s.\n", buf);
+
+ /* Gather the RNG proxy sequence IDs and ensure that the RNG proxy state of
+ * the master process is greater than the RNG proxy state of all other
+ * processes */
+ res = gather_rng_proxy_sequence_id(scn->dev, rng_proxy);
+ if(res != RES_OK) goto error;
/* Setup the estimated mean power */
{
struct accum acc_mpow;
struct accum acc_time;
- sum_accums(acc_mpows, scn->dev->nthreads, &acc_mpow);
- sum_accums(acc_times, scn->dev->nthreads, &acc_time);
- ASSERT(acc_mpow.count == acc_time.count);
-
- estimator_setup_realisations_count(estimator, nrealisations, acc_mpow.count);
- estimator_setup_realisation_time(estimator, acc_time.sum, acc_time.sum2);
- estimator_setup_power
- (estimator, acc_mpow.sum, acc_mpow.sum2, spread, args->time_range);
- res = estimator_save_rng_state(estimator, rng_proxy);
- if(res != RES_OK) goto error;
+
+ time_current(&time0);
+
+ #define GATHER_ACCUMS(Msg, Acc) { \
+ res = gather_accumulators(scn->dev, Msg, per_thread_##Acc, &Acc); \
+ if(res != RES_OK) goto error; \
+ } (void)0
+ GATHER_ACCUMS(MPI_SDIS_MSG_ACCUM_MEAN_POWER, acc_mpow);
+ GATHER_ACCUMS(MPI_SDIS_MSG_ACCUM_TIME, acc_time);
+ #undef GATHER_ACCUMS
+
+ time_sub(&time0, time_current(&time1), &time0);
+ time_dump(&time0, TIME_ALL, NULL, buf, sizeof(buf));
+ log_info(scn->dev, "Accumulators gathered in %s.\n", buf);
+
+ /* Return an estimator only on master process */
+ if(is_master_process) {
+ ASSERT(acc_mpow.count == acc_time.count);
+ estimator_setup_realisations_count(estimator, args->nrealisations, acc_mpow.count);
+ estimator_setup_realisation_time(estimator, acc_time.sum, acc_time.sum2);
+ estimator_setup_power
+ (estimator, acc_mpow.sum, acc_mpow.sum2, spread, args->time_range);
+ res = estimator_save_rng_state(estimator, rng_proxy);
+ if(res != RES_OK) goto error;
+ }
}
exit:
- if(rngs) {
- FOR_EACH(i, 0, scn->dev->nthreads) {if(rngs[i]) SSP(rng_ref_put(rngs[i]));}
- MEM_RM(scn->dev->allocator, rngs);
- }
- if(acc_mpows) MEM_RM(scn->dev->allocator, acc_mpows);
- if(acc_times) MEM_RM(scn->dev->allocator, acc_times);
+ if(per_thread_rng) release_per_thread_rng(scn->dev, per_thread_rng);
+ if(progress) free_process_progress(scn->dev, progress);
+ if(per_thread_acc_mpow) MEM_RM(scn->dev->allocator, per_thread_acc_mpow);
+ if(per_thread_acc_time) MEM_RM(scn->dev->allocator, per_thread_acc_time);
if(cumul_is_init) darray_enclosure_cumul_release(&cumul);
if(rng_proxy) SSP(rng_proxy_ref_put(rng_proxy));
if(out_estimator) *out_estimator = estimator;
return (res_T)res;
error:
- if(estimator) {
- SDIS(estimator_ref_put(estimator));
- estimator = NULL;
- }
+ if(estimator) { SDIS(estimator_ref_put(estimator)); estimator = NULL; }
goto exit;
}
diff --git a/src/sdis_solve_probe_Xd.h b/src/sdis_solve_probe_Xd.h
@@ -1,4 +1,4 @@
-/* Copyright (C) 2016-2021 |Meso|Star> (contact@meso-star.com)
+/* Copyright (C) 2016-2022 |Meso|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
@@ -13,6 +13,7 @@
* 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_c.h"
#include "sdis_device_c.h"
#include "sdis_estimator_c.h"
#include "sdis_log.h"
@@ -28,6 +29,46 @@
#include "sdis_Xd_begin.h"
/*******************************************************************************
+ * Helper function
+ ******************************************************************************/
+#ifndef SDIS_SOLVE_PROBE_XD_H
+#define SDIS_SOLVE_PROBE_XD_H
+
+static INLINE res_T
+check_solve_probe_args(const struct sdis_solve_probe_args* args)
+{
+ if(!args) return RES_BAD_ARG;
+
+ /* Check #realisations */
+ if(!args->nrealisations || args->nrealisations > INT64_MAX) {
+ return RES_BAD_ARG;
+ }
+
+ /* Check time range */
+ if(args->time_range[0] < 0 || args->time_range[1] < args->time_range[0]) {
+ return RES_BAD_ARG;
+ }
+ if(args->time_range[1] > DBL_MAX
+ && args->time_range[0] != args->time_range[1]) {
+ return RES_BAD_ARG;
+ }
+
+ /* Check picard order */
+ if(args->picard_order < 1) {
+ return RES_BAD_ARG;
+ }
+
+ /* Check the RNG type */
+ if(!args->rng_state && args->rng_type >= SSP_RNG_TYPES_COUNT__) {
+ return RES_BAD_ARG;
+ }
+
+ return RES_OK;
+}
+
+#endif /* SDIS_SOLVE_PROBE_XD_H */
+
+/*******************************************************************************
* Generic solve function
******************************************************************************/
static res_T
@@ -37,72 +78,72 @@ XD(solve_probe)
struct sdis_green_function** out_green, /* May be NULL <=> No green func */
struct sdis_estimator** out_estimator) /* May be NULL <=> No estimator */
{
+ /* Time registration */
+ struct time time0, time1;
+ char buf[128]; /* Temporary buffer used to store formated time */
+
+ /* Device variables */
+ struct mem_allocator* allocator = NULL;
+ 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** greens = NULL;
+ struct sdis_green_function** per_thread_green = NULL;
+
+ /* Random Number generator */
struct ssp_rng_proxy* rng_proxy = NULL;
- struct ssp_rng** rngs = NULL;
- struct accum* acc_temps = NULL;
- struct accum* acc_times = NULL;
+ struct ssp_rng** per_thread_rng = NULL;
+
+ /* Miscellaneous */
+ struct accum* per_thread_acc_temp = NULL;
+ struct accum* per_thread_acc_time = NULL;
size_t nrealisations = 0;
int64_t irealisation = 0;
- size_t i;
- int progress = 0;
+ int32_t* progress = NULL; /* Per process progress bar */
int register_paths = SDIS_HEAT_PATH_NONE;
+ int is_master_process = 1;
ATOMIC nsolved_realisations = 0;
ATOMIC res = RES_OK;
- if(!scn || !args || !args->nrealisations || args->nrealisations > INT64_MAX) {
- res = RES_BAD_ARG;
- goto error;
- }
- if(!out_estimator && !out_green) {
- res = RES_BAD_ARG;
- goto error;
- }
- if(args->time_range[0] < 0 || args->time_range[1] < args->time_range[0]) {
- res = RES_BAD_ARG;
- goto error;
- }
- if(args->time_range[1] > DBL_MAX
- && args->time_range[0] != args->time_range[1]) {
+ if(!scn) { res = RES_BAD_ARG; goto error; }
+ if(!out_estimator && !out_green) { res = RES_BAD_ARG; goto error; }
+ res = check_solve_probe_args(args);
+ if(res != RES_OK) goto error;
+ res = XD(scene_check_dimensionality)(scn);
+ if(res != RES_OK) goto error;
+
+ if(out_green && args->picard_order != 1) {
+ log_err(scn->dev, "%s: the evaluation of the green function does not make "
+ "sense when dealing with the non-linearities of the system; i.e. picard "
+ "order must be set to 1 while it is currently set to %lu.\n",
+ FUNC_NAME, (unsigned long)args->picard_order);
res = RES_BAD_ARG;
goto error;
}
-#if SDIS_XD_DIMENSION == 2
- if(scene_is_2d(scn) == 0) { res = RES_BAD_ARG; goto error; }
-#else
- if(scene_is_2d(scn) != 0) { res = RES_BAD_ARG; goto error; }
+#ifdef SDIS_ENABLE_MPI
+ is_master_process = !scn->dev->use_mpi || scn->dev->mpi_rank == 0;
#endif
- /* Create the proxy RNG */
- if(args->rng_state) {
- res = ssp_rng_proxy_create_from_rng(scn->dev->allocator, args->rng_state,
- scn->dev->nthreads, &rng_proxy);
- if(res != RES_OK) goto error;
- } else {
- res = ssp_rng_proxy_create(scn->dev->allocator, SSP_RNG_MT19937_64,
- scn->dev->nthreads, &rng_proxy);
- if(res != RES_OK) goto error;
- }
+ nthreads = scn->dev->nthreads;
+ allocator = scn->dev->allocator;
- /* Create the per thread RNG */
- rngs = MEM_CALLOC(scn->dev->allocator, scn->dev->nthreads, sizeof(*rngs));
- if(!rngs) { res = RES_MEM_ERR; goto error; }
- FOR_EACH(i, 0, scn->dev->nthreads) {
- res = ssp_rng_proxy_create_rng(rng_proxy, i, rngs+i);
- if(res != RES_OK) 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);
+ if(res != RES_OK) goto error;
+
+ /* Allocate the per process progress status */
+ res = alloc_process_progress(scn->dev, &progress);
+ if(res != RES_OK) goto error;
/* Create the per thread accumulators */
- acc_temps = MEM_CALLOC
- (scn->dev->allocator, scn->dev->nthreads, sizeof(*acc_temps));
- if(!acc_temps) { res = RES_MEM_ERR; goto error; }
- acc_times = MEM_CALLOC
- (scn->dev->allocator, scn->dev->nthreads, sizeof(*acc_times));
- if(!acc_times) { res = RES_MEM_ERR; goto error; }
+ per_thread_acc_temp = MEM_CALLOC(allocator, nthreads, sizeof(struct accum));
+ per_thread_acc_time = MEM_CALLOC(allocator, nthreads, sizeof(struct accum));
+ 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);
@@ -110,31 +151,39 @@ XD(solve_probe)
/* Create the per thread green function */
if(out_green) {
- greens = MEM_CALLOC(scn->dev->allocator, scn->dev->nthreads, sizeof(*greens));
- if(!greens) { res = RES_MEM_ERR; goto error; }
- FOR_EACH(i, 0, scn->dev->nthreads) {
- res = green_function_create(scn, &greens[i]);
- if(res != RES_OK) goto error;
- }
+ res = create_per_thread_green_function(scn, &per_thread_green);
+ if(res != RES_OK) goto error;
}
- /* Create the estimator */
- if(out_estimator) {
+ /* Create the estimator on the master process only. No estimator is needed
+ * for non master process */
+ if(out_estimator && is_master_process) {
res = estimator_create(scn->dev, SDIS_ESTIMATOR_TEMPERATURE, &estimator);
if(res != RES_OK) goto error;
}
+ /* Synchronise the processes */
+ process_barrier(scn->dev);
+
+ #define PROGRESS_MSG "Solving probe temperature: "
+ print_progress(scn->dev, progress, PROGRESS_MSG);
+
+ /* Begin time registration of the computation */
+ time_current(&time0);
+
/* Here we go! Launch the Monte Carlo estimation */
- nrealisations = args->nrealisations;
- register_paths = out_estimator ? args->register_paths : SDIS_HEAT_PATH_NONE;
+ nrealisations = compute_process_realisations_count(scn->dev, args->nrealisations);
+ register_paths = out_estimator && is_master_process
+ ? args->register_paths : SDIS_HEAT_PATH_NONE;
omp_set_num_threads((int)scn->dev->nthreads);
#pragma omp parallel for schedule(static)
for(irealisation = 0; irealisation < (int64_t)nrealisations; ++irealisation) {
+ struct probe_realisation_args realis_args = PROBE_REALISATION_ARGS_NULL;
struct time t0, t1;
const int ithread = omp_get_thread_num();
- struct ssp_rng* rng = rngs[ithread];
- struct accum* acc_temp = &acc_temps[ithread];
- struct accum* acc_time = &acc_times[ithread];
+ struct ssp_rng* rng = per_thread_rng[ithread];
+ struct accum* acc_temp = &per_thread_acc_temp[ithread];
+ 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;
struct sdis_heat_path* pheat_path = NULL;
@@ -148,26 +197,33 @@ XD(solve_probe)
if(ATOMIC_GET(&res) != RES_OK) continue; /* An error occurred */
- /* Begin time registration */
+ /* Begin time registration of the realisation */
time_current(&t0);
time = sample_time(rng, args->time_range);
if(out_green) {
- res_local = green_function_create_path(greens[ithread], &green_path);
- if(res_local != RES_OK) {
- ATOMIC_SET(&res, res_local);
- goto error_it;
- }
+ res_local = green_function_create_path
+ (per_thread_green[ithread], &green_path);
+ if(res_local != RES_OK) { ATOMIC_SET(&res, res_local); goto error_it; }
pgreen_path = &green_path;
}
+
if(register_paths) {
heat_path_init(scn->dev->allocator, &heat_path);
pheat_path = &heat_path;
}
- res_simul = XD(probe_realisation)((size_t)irealisation, scn, rng, medium,
- args->position, time, pgreen_path, pheat_path, &w);
+ /* Invoke the probe realisation */
+ realis_args.rng = rng;
+ realis_args.medium = medium;
+ realis_args.time = time;
+ realis_args.picard_order = args->picard_order;
+ realis_args.green_path = pgreen_path;
+ realis_args.heat_path = pheat_path;
+ realis_args.irealisation = (size_t)irealisation;
+ dX(set)(realis_args.position, args->position);
+ res_simul = XD(probe_realisation)(scn, &realis_args, &w);
/* Handle fatal error */
if(res_simul != RES_OK && res_simul != RES_BAD_OP) {
@@ -204,84 +260,106 @@ XD(solve_probe)
acc_time->sum += usec; acc_time->sum2 += usec*usec; ++acc_time->count;
}
- /* Update progress */
+ /* Update the progress status */
n = (size_t)ATOMIC_INCR(&nsolved_realisations);
pcent = (int)((double)n * 100.0 / (double)nrealisations + 0.5/*round*/);
+
#pragma omp critical
- if(pcent > progress) {
- progress = pcent;
- log_info(scn->dev, "Solving probe temperature: %3d%%\r", progress);
+ if(pcent > progress[0]) {
+ progress[0] = pcent;
+ print_progress_update(scn->dev, progress, PROGRESS_MSG);
}
+
exit_it:
if(pheat_path) heat_path_release(pheat_path);
continue;
error_it:
goto exit_it;
}
+
+ /* Synchronise processes */
+ process_barrier(scn->dev);
+
+ res = gather_res_T(scn->dev, (res_T)res);
if(res != RES_OK) goto error;
- /* Add a new line after the progress status */
- log_info(scn->dev, "Solving probe temperature: %3d%%\n", progress);
+ print_progress_update(scn->dev, progress, PROGRESS_MSG);
+ log_info(scn->dev, "\n");
+ #undef PROGRESS_MSG
+
+ /* Report computation time */
+ time_sub(&time0, time_current(&time1), &time0);
+ time_dump(&time0, TIME_ALL, NULL, buf, sizeof(buf));
+ log_info(scn->dev, "Probe temperature solved in %s.\n", buf);
+
+ /* Gather the RNG proxy sequence IDs and ensure that the RNG proxy state of
+ * the master process is greater than the RNG proxy state of all other
+ * processes */
+ res = gather_rng_proxy_sequence_id(scn->dev, rng_proxy);
+ if(res != RES_OK) goto error;
- /* Setup the estimated temperature and per realisation time */
+ /* Setup the estimated values */
if(out_estimator) {
struct accum acc_temp;
struct accum acc_time;
- sum_accums(acc_temps, scn->dev->nthreads, &acc_temp);
- sum_accums(acc_times, scn->dev->nthreads, &acc_time);
- ASSERT(acc_temp.count == acc_time.count);
-
- estimator_setup_realisations_count(estimator, nrealisations, acc_temp.count);
- estimator_setup_temperature(estimator, acc_temp.sum, acc_temp.sum2);
- estimator_setup_realisation_time(estimator, acc_time.sum, acc_time.sum2);
- res = estimator_save_rng_state(estimator, rng_proxy);
- if(res != RES_OK) goto error;
+ time_current(&time0);
+
+ #define GATHER_ACCUMS(Msg, Acc) { \
+ res = gather_accumulators(scn->dev, Msg, per_thread_##Acc, &Acc); \
+ if(res != RES_OK) goto error; \
+ } (void)0
+ GATHER_ACCUMS(MPI_SDIS_MSG_ACCUM_TEMP, acc_temp);
+ GATHER_ACCUMS(MPI_SDIS_MSG_ACCUM_TEMP, acc_time);
+ #undef GATHER_ACCUMS
+
+ time_sub(&time0, time_current(&time1), &time0);
+ time_dump(&time0, TIME_ALL, NULL, buf, sizeof(buf));
+ log_info(scn->dev, "Accumulators gathered in %s.\n", buf);
+
+ /* Return an estimator only on master process */
+ if(is_master_process) {
+ ASSERT(acc_temp.count == acc_time.count);
+ estimator_setup_realisations_count(estimator, args->nrealisations, acc_temp.count);
+ estimator_setup_temperature(estimator, acc_temp.sum, acc_temp.sum2);
+ estimator_setup_realisation_time(estimator, acc_time.sum, acc_time.sum2);
+ res = estimator_save_rng_state(estimator, rng_proxy);
+ if(res != RES_OK) goto error;
+ }
}
+ /* Setup the green function */
if(out_green) {
- struct accum acc_time;
+ time_current(&time0);
- /* Redux the per thread green function into the green of the 1st thread */
- green = greens[0]; /* Return the green of the 1st thread */
- greens[0] = NULL; /* Make invalid the 1st green for 'on exit' clean up*/
- res = green_function_redux_and_clear(green, greens+1, scn->dev->nthreads-1);
+ res = gather_green_functions
+ (scn, rng_proxy, per_thread_green, per_thread_acc_time, &green);
if(res != RES_OK) goto error;
- /* Finalize the estimated green */
- sum_accums(acc_times, scn->dev->nthreads, &acc_time);
- res = green_function_finalize(green, rng_proxy, &acc_time);
- if(res != RES_OK) goto error;
- }
+ time_sub(&time0, time_current(&time1), &time0);
+ time_dump(&time0, TIME_ALL, NULL, buf, sizeof(buf));
+ log_info(scn->dev, "Green functions gathered in %s.\n", buf);
-exit:
- if(rngs) {
- FOR_EACH(i, 0, scn->dev->nthreads) {
- if(rngs[i]) SSP(rng_ref_put(rngs[i]));
- }
- MEM_RM(scn->dev->allocator, rngs);
- }
- if(greens) {
- FOR_EACH(i, 0, scn->dev->nthreads) {
- if(greens[i]) SDIS(green_function_ref_put(greens[i]));
+ /* Return a green function only on master process */
+ if(!is_master_process) {
+ SDIS(green_function_ref_put(green));
+ green = NULL;
}
- MEM_RM(scn->dev->allocator, greens);
}
- if(acc_temps) MEM_RM(scn->dev->allocator, acc_temps);
- if(acc_times) MEM_RM(scn->dev->allocator, acc_times);
+
+exit:
+ if(per_thread_rng) release_per_thread_rng(scn->dev, per_thread_rng);
+ if(per_thread_green) release_per_thread_green_function(scn, per_thread_green);
+ if(progress) free_process_progress(scn->dev, progress);
+ if(per_thread_acc_temp) MEM_RM(scn->dev->allocator, per_thread_acc_temp);
+ if(per_thread_acc_time) MEM_RM(scn->dev->allocator, per_thread_acc_time);
if(rng_proxy) SSP(rng_proxy_ref_put(rng_proxy));
if(out_green) *out_green = green;
if(out_estimator) *out_estimator = estimator;
return (res_T)res;
error:
- if(green) {
- SDIS(green_function_ref_put(green));
- green = NULL;
- }
- if(estimator) {
- SDIS(estimator_ref_put(estimator));
- estimator = NULL;
- }
+ if(estimator) { SDIS(estimator_ref_put(estimator)); estimator = NULL; }
+ if(green) { SDIS(green_function_ref_put(green)); green = NULL; }
goto exit;
}
diff --git a/src/sdis_solve_probe_boundary_Xd.h b/src/sdis_solve_probe_boundary_Xd.h
@@ -1,4 +1,4 @@
-/* Copyright (C) 2016-2021 |Meso|Star> (contact@meso-star.com)
+/* Copyright (C) 2016-2022 |Meso|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
@@ -13,9 +13,12 @@
* 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_c.h"
#include "sdis_device_c.h"
#include "sdis_estimator_c.h"
+#include "sdis_interface_c.h"
#include "sdis_log.h"
+#include "sdis_green.h"
#include "sdis_medium_c.h"
#include "sdis_misc.h"
#include "sdis_realisation.h"
@@ -28,6 +31,85 @@
#include "sdis_Xd_begin.h"
/*******************************************************************************
+ * Helper function
+ ******************************************************************************/
+#ifndef SDIS_SOLVE_PROBE_BOUNDARY_XD_H
+#define SDIS_SOLVE_PROBE_BOUNDARY_XD_H
+
+static INLINE res_T
+check_solve_probe_boundary_args
+ (const struct sdis_solve_probe_boundary_args* args)
+{
+ if(!args) return RES_BAD_ARG;
+
+ /* Check #realisations */
+ if(!args->nrealisations || args->nrealisations > INT64_MAX) {
+ return RES_BAD_ARG;
+ }
+
+ /* Check side */
+ if((unsigned)args->side >= SDIS_SIDE_NULL__) {
+ return RES_BAD_ARG;
+ }
+
+ /* Check time range */
+ if(args->time_range[0] < 0 || args->time_range[1] < args->time_range[0]) {
+ return RES_BAD_ARG;
+ }
+ if(args->time_range[1] > DBL_MAX
+ && args->time_range[0] != args->time_range[1]) {
+ return RES_BAD_ARG;
+ }
+
+ /* Check picard order */
+ if(args->picard_order < 1) {
+ return RES_BAD_ARG;
+ }
+
+ /* Check the RNG type */
+ if(!args->rng_state && args->rng_type >= SSP_RNG_TYPES_COUNT__) {
+ return RES_BAD_ARG;
+ }
+
+ return RES_OK;
+}
+
+static INLINE res_T
+check_solve_probe_boundary_flux_args
+ (const struct sdis_solve_probe_boundary_flux_args* args)
+{
+ if(!args) return RES_BAD_ARG;
+
+ /* Check #realisations */
+ if(!args->nrealisations || args->nrealisations > INT64_MAX) {
+ return RES_BAD_ARG;
+ }
+
+ /* Check time range */
+ if(args->time_range[0] < 0 || args->time_range[1] < args->time_range[0]) {
+ return RES_BAD_ARG;
+ }
+ if(args->time_range[1] > DBL_MAX
+ && args->time_range[0] != args->time_range[1]) {
+ return RES_BAD_ARG;
+ }
+
+ /* Check picard order */
+ if(args->picard_order < 1) {
+ return RES_BAD_ARG;
+ }
+
+ /* Check the RNG type */
+ if(!args->rng_state && args->rng_type >= SSP_RNG_TYPES_COUNT__) {
+ return RES_BAD_ARG;
+ }
+
+ return RES_OK;
+}
+
+#endif /* SDIS_SOLVE_PROBE_BOUNDARY_XD_H */
+
+/*******************************************************************************
* Local functions
******************************************************************************/
static res_T
@@ -37,141 +119,111 @@ XD(solve_probe_boundary)
struct sdis_green_function** out_green,
struct sdis_estimator** out_estimator)
{
+ /* Time registration */
+ struct time time0, time1;
+ char buf[128]; /* Temporary buffer used to store formated time */
+
+ /* Device variables */
+ struct mem_allocator* allocator = NULL;
+ size_t nthreads = 0;
+
+ /* Stardis variables */
struct sdis_estimator* estimator = NULL;
struct sdis_green_function* green = NULL;
- struct sdis_green_function** greens = NULL;
+ struct sdis_green_function** per_thread_green = NULL;
+
+ /* Random number generator */
struct ssp_rng_proxy* rng_proxy = NULL;
- struct ssp_rng** rngs = NULL;
- struct accum* acc_temps = NULL;
- struct accum* acc_times = NULL;
+ struct ssp_rng** per_thread_rng = NULL;
+
+ /* Miscellaneous */
+ struct accum* per_thread_acc_temp = NULL;
+ struct accum* per_thread_acc_time = NULL;
size_t nrealisations = 0;
int64_t irealisation = 0;
- size_t i;
- int progress = 0;
+ int32_t* progress = NULL; /* Per process progress bar */
int register_paths = SDIS_HEAT_PATH_NONE;
+ int is_master_process = 1;
ATOMIC nsolved_realisations = 0;
ATOMIC res = RES_OK;
- if(!scn || !args || !args->nrealisations || args->nrealisations > INT64_MAX
- || ((unsigned)args->side >= SDIS_SIDE_NULL__)) {
- res = RES_BAD_ARG;
- goto error;
- }
- if(!out_estimator && !out_green) {
- res = RES_BAD_ARG;
- goto error;
- }
- if(args->time_range[0] < 0 || args->time_range[1] < args->time_range[0]) {
- res = RES_BAD_ARG;
- goto error;
- }
- if(args->time_range[1] > DBL_MAX
- && args->time_range[0] != args->time_range[1]) {
- res = RES_BAD_ARG;
- goto error;
- }
-
-#if SDIS_XD_DIMENSION == 2
- if(scene_is_2d(scn) == 0) { res = RES_BAD_ARG; goto error; }
-#else
- if(scene_is_2d(scn) != 0) { res = RES_BAD_ARG; goto error; }
-#endif
+ if(!scn) { res = RES_BAD_ARG; goto error; }
+ if(!out_estimator && !out_green) { res = RES_BAD_ARG; goto error; }
+ res = check_solve_probe_boundary_args(args);
+ if(res != RES_OK) goto error;
+ res = XD(check_primitive_uv)(scn->dev, args->uv);
+ if(res != RES_OK) goto error;
+ res = XD(scene_check_dimensionality)(scn);
+ if(res != RES_OK) goto error;
+ res = scene_check_primitive_index(scn, args->iprim);
+ if(res != RES_OK) goto error;
- /* Check the primitive identifier */
- if(args->iprim >= scene_get_primitives_count(scn)) {
- log_err(scn->dev,
- "%s: invalid primitive identifier `%lu'. "
- "It must be in the [0 %lu] range.\n",
- FUNC_NAME,
- (unsigned long)args->iprim,
- (unsigned long)scene_get_primitives_count(scn)-1);
+ if(out_green && args->picard_order != 1) {
+ log_err(scn->dev, "%s: the evaluation of the green function does not make "
+ "sense when dealing with the non-linearities of the system; i.e. picard "
+ "order must be set to 1 while it is currently set to %lu.\n",
+ FUNC_NAME, (unsigned long)args->picard_order);
res = RES_BAD_ARG;
goto error;
}
- /* Check parametric coordinates */
-#if SDIS_XD_DIMENSION == 2
- {
- const double v = CLAMP(1.0 - args->uv[0], 0, 1);
- if(args->uv[0] < 0 || args->uv[0] > 1 || !eq_eps(args->uv[0]+v, 1, 1.e-6)) {
- log_err(scn->dev,
- "%s: invalid parametric coordinates %g."
- "u + (1-u) must be equal to 1 with u [0, 1].\n",
- FUNC_NAME, args->uv[0]);
- res = RES_BAD_ARG;
- goto error;
- }
- }
-#else /* SDIS_XD_DIMENSION == 3 */
- {
- const double w = CLAMP(1 - args->uv[0] - args->uv[1], 0, 1);
- if(args->uv[0] < 0 || args->uv[1] < 0 || args->uv[0] > 1 || args->uv[1] > 1
- || !eq_eps(w + args->uv[0] + args->uv[1], 1, 1.e-6)) {
- log_err(scn->dev,
- "%s: invalid parametric coordinates [%g, %g]. "
- "u + v + (1-u-v) must be equal to 1 with u and v in [0, 1].\n",
- FUNC_NAME, args->uv[0], args->uv[1]);
- res = RES_BAD_ARG;
- goto error;
- }
- }
+#ifdef SDIS_ENABLE_MPI
+ is_master_process = !scn->dev->use_mpi || scn->dev->mpi_rank == 0;
#endif
- /* Create the proxy RNG */
- if(args->rng_state) {
- res = ssp_rng_proxy_create_from_rng(scn->dev->allocator, args->rng_state,
- scn->dev->nthreads, &rng_proxy);
- if(res != RES_OK) goto error;
- } else {
- res = ssp_rng_proxy_create(scn->dev->allocator, SSP_RNG_MT19937_64,
- scn->dev->nthreads, &rng_proxy);
- if(res != RES_OK) goto error;
- }
+ nthreads = scn->dev->nthreads;
+ allocator = scn->dev->allocator;
- /* Create the per thread RNG */
- rngs = MEM_CALLOC
- (scn->dev->allocator, scn->dev->nthreads, sizeof(struct ssp_rng*));
- if(!rngs) { res = RES_MEM_ERR; goto error; }
- FOR_EACH(i, 0, scn->dev->nthreads) {
- res = ssp_rng_proxy_create_rng(rng_proxy, i, rngs+i);
- if(res != RES_OK) 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);
+ if(res != RES_OK) goto error;
- /* Create the per thread accumulator */
- acc_temps = MEM_CALLOC
- (scn->dev->allocator, scn->dev->nthreads, sizeof(*acc_temps));
- if(!acc_temps) { res = RES_MEM_ERR; goto error; }
- acc_times = MEM_CALLOC
- (scn->dev->allocator, scn->dev->nthreads, sizeof(*acc_times));
- if(!acc_times) { res = RES_MEM_ERR; goto error; }
+ /* Allocate the per process progress status */
+ res = alloc_process_progress(scn->dev, &progress);
+ if(res != RES_OK) goto error;
+
+ /* Create the per thread accumulators */
+ per_thread_acc_temp = MEM_CALLOC(allocator, nthreads, sizeof(struct accum));
+ per_thread_acc_time = MEM_CALLOC(allocator, nthreads, sizeof(struct accum));
+ if(!per_thread_acc_temp) { res = RES_MEM_ERR; goto error; }
+ if(!per_thread_acc_time) { res = RES_MEM_ERR; goto error; }
/* Create the per thread green function */
if(out_green) {
- greens = MEM_CALLOC(scn->dev->allocator, scn->dev->nthreads, sizeof(*greens));
- if(!greens) { res = RES_MEM_ERR; goto error; }
- FOR_EACH(i, 0, scn->dev->nthreads) {
- res = green_function_create(scn, &greens[i]);
- if(res != RES_OK) goto error;
- }
+ res = create_per_thread_green_function(scn, &per_thread_green);
+ if(res != RES_OK) goto error;
}
- /* Create the estimator */
- if(out_estimator) {
+ /* Create the estimator on the master process only. No estimator is needed
+ * for non master process */
+ if(out_estimator && is_master_process) {
res = estimator_create(scn->dev, SDIS_ESTIMATOR_TEMPERATURE, &estimator);
if(res != RES_OK) goto error;
}
+ /* Synchronise the processes */
+ process_barrier(scn->dev);
+
+ #define PROGRESS_MSG "Solving surface probe temperature: "
+ print_progress(scn->dev, progress, PROGRESS_MSG);
+
+ /* Begin time registration of the computation */
+ time_current(&time0);
+
/* Here we go! Launch the Monte Carlo estimation */
- nrealisations = args->nrealisations;
- register_paths = out_estimator ? args->register_paths : SDIS_HEAT_PATH_NONE;
+ nrealisations = compute_process_realisations_count(scn->dev, args->nrealisations);
+ register_paths = out_estimator && is_master_process
+ ? args->register_paths : SDIS_HEAT_PATH_NONE;
omp_set_num_threads((int)scn->dev->nthreads);
#pragma omp parallel for schedule(static)
for(irealisation = 0; irealisation < (int64_t)nrealisations; ++irealisation) {
+ struct boundary_realisation_args realis_args = BOUNDARY_REALISATION_ARGS_NULL;
struct time t0, t1;
const int ithread = omp_get_thread_num();
- struct ssp_rng* rng = rngs[ithread];
- struct accum* acc_temp = &acc_temps[ithread];
- struct accum* acc_time = &acc_times[ithread];
+ struct ssp_rng* rng = per_thread_rng[ithread];
+ struct accum* acc_temp = &per_thread_acc_temp[ithread];
+ 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;
struct sdis_heat_path* pheat_path = NULL;
@@ -190,11 +242,9 @@ XD(solve_probe_boundary)
time = sample_time(rng, args->time_range);
if(out_green) {
- res_local = green_function_create_path(greens[ithread], &green_path);
- if(res_local != RES_OK) {
- ATOMIC_SET(&res, res_local);
- goto error_it;
- }
+ res_local = green_function_create_path
+ (per_thread_green[ithread], &green_path);
+ if(res_local != RES_OK) { ATOMIC_SET(&res, res_local); goto error_it; }
pgreen_path = &green_path;
}
@@ -203,8 +253,19 @@ XD(solve_probe_boundary)
pheat_path = &heat_path;
}
- res_simul = XD(boundary_realisation)(scn, rng, args->iprim, args->uv, time,
- args->side, pgreen_path, pheat_path, &w);
+ /* Invoke the boundary realisation */
+ realis_args.rng = rng;
+ realis_args.iprim = args->iprim;
+ realis_args.time = time;
+ realis_args.picard_order = args->picard_order;
+ realis_args.side = args->side;
+ realis_args.green_path = pgreen_path;
+ realis_args.heat_path = pheat_path;
+ realis_args.uv[0] = args->uv[0];
+#if SDIS_XD_DIMENSION == 3
+ realis_args.uv[1] = args->uv[1];
+#endif
+ res_simul = XD(boundary_realisation)(scn, &realis_args, &w);
/* Handle fatal error */
if(res_simul != RES_OK && res_simul != RES_BAD_OP) {
@@ -246,9 +307,9 @@ XD(solve_probe_boundary)
n = (size_t)ATOMIC_INCR(&nsolved_realisations);
pcent = (int)((double)n * 100.0 / (double)nrealisations + 0.5/*round*/);
#pragma omp critical
- if(pcent > progress) {
- progress = pcent;
- log_info(scn->dev, "Solving probe boundary temperature: %3d%%\r", progress);
+ if(pcent > progress[0]) {
+ progress[0] = pcent;
+ print_progress_update(scn->dev, progress, PROGRESS_MSG);
}
exit_it:
@@ -257,70 +318,88 @@ XD(solve_probe_boundary)
error_it:
goto exit_it;
}
+ /* Synchronise processes */
+ process_barrier(scn->dev);
+
+ res = gather_res_T(scn->dev, (res_T)res);
if(res != RES_OK) goto error;
- /* Add a new line after the progress status */
- log_info(scn->dev, "Solving probe boundary temperature: %3d%%\n", progress);
+ print_progress_update(scn->dev, progress, PROGRESS_MSG);
+ log_info(scn->dev, "\n");
+ #undef PROGRESS_MSG
+
+ /* Report computation time */
+ time_sub(&time0, time_current(&time1), &time0);
+ time_dump(&time0, TIME_ALL, NULL, buf, sizeof(buf));
+ log_info(scn->dev, "Surface probe temperature solved in %s.\n", buf);
+
+ /* Gather the RNG proxy sequence IDs and ensure that the RNG proxy state of
+ * the master process is greater than the RNG proxy state of all other
+ * processes */
+ res = gather_rng_proxy_sequence_id(scn->dev, rng_proxy);
+ if(res != RES_OK) goto error;
/* Setup the estimated temperature and per realisation time */
if(out_estimator) {
struct accum acc_temp;
struct accum acc_time;
- sum_accums(acc_temps, scn->dev->nthreads, &acc_temp);
- sum_accums(acc_times, scn->dev->nthreads, &acc_time);
- ASSERT(acc_temp.count == acc_time.count);
-
- estimator_setup_realisations_count(estimator, nrealisations, acc_temp.count);
- estimator_setup_temperature(estimator, acc_temp.sum, acc_temp.sum2);
- estimator_setup_realisation_time(estimator, acc_time.sum, acc_time.sum2);
- res = estimator_save_rng_state(estimator, rng_proxy);
- if(res != RES_OK) goto error;
+ time_current(&time0);
+
+ #define GATHER_ACCUMS(Msg, Acc) { \
+ res = gather_accumulators(scn->dev, Msg, per_thread_##Acc, &Acc); \
+ if(res != RES_OK) goto error; \
+ } (void)0
+ GATHER_ACCUMS(MPI_SDIS_MSG_ACCUM_TEMP, acc_temp);
+ GATHER_ACCUMS(MPI_SDIS_MSG_ACCUM_TIME, acc_time);
+ #undef GATHER_ACCUMS
+
+ time_sub(&time0, time_current(&time1), &time0);
+ time_dump(&time0, TIME_ALL, NULL, buf, sizeof(buf));
+ log_info(scn->dev, "Accumulators gathered in %s.\n", buf);
+
+ /* Return an estimator only on master process */
+ if(is_master_process) {
+ ASSERT(acc_temp.count == acc_time.count);
+ estimator_setup_realisations_count(estimator, args->nrealisations, acc_temp.count);
+ estimator_setup_temperature(estimator, acc_temp.sum, acc_temp.sum2);
+ estimator_setup_realisation_time(estimator, acc_time.sum, acc_time.sum2);
+ res = estimator_save_rng_state(estimator, rng_proxy);
+ if(res != RES_OK) goto error;
+ }
}
if(out_green) {
- struct accum acc_time;
+ time_current(&time0);
- /* Redux the per thread green function into the green of the 1st thread */
- green = greens[0]; /* Return the green of the 1st thread */
- greens[0] = NULL; /* Make invalid the 1st green for 'on exit' clean up*/
- res = green_function_redux_and_clear(green, greens+1, scn->dev->nthreads-1);
+ res = gather_green_functions
+ (scn, rng_proxy, per_thread_green, per_thread_acc_time, &green);
if(res != RES_OK) goto error;
- /* Finalize the estimated green */
- sum_accums(acc_times, scn->dev->nthreads, &acc_time);
- res = green_function_finalize(green, rng_proxy, &acc_time);
- if(res != RES_OK) goto error;
- }
+ time_sub(&time0, time_current(&time1), &time0);
+ time_dump(&time0, TIME_ALL, NULL, buf, sizeof(buf));
+ log_info(scn->dev, "Green functions gathered in %s.\n", buf);
-exit:
- if(rngs) {
- FOR_EACH(i, 0, scn->dev->nthreads) {
- if(rngs[i]) SSP(rng_ref_put(rngs[i]));
- }
- MEM_RM(scn->dev->allocator, rngs);
- }
- if(greens) {
- FOR_EACH(i, 0, scn->dev->nthreads) {
- if(greens[i]) SDIS(green_function_ref_put(greens[i]));
+ /* Return a green function only on master process */
+ if(!is_master_process) {
+ SDIS(green_function_ref_put(green));
+ green = NULL;
}
- MEM_RM(scn->dev->allocator, greens);
}
- if(acc_temps) MEM_RM(scn->dev->allocator, acc_temps);
- if(acc_times) MEM_RM(scn->dev->allocator, acc_times);
+
+exit:
+ if(per_thread_rng) release_per_thread_rng(scn->dev, per_thread_rng);
+ if(per_thread_green) release_per_thread_green_function(scn, per_thread_green);
+ if(progress) free_process_progress(scn->dev, progress);
+ if(per_thread_acc_temp) MEM_RM(scn->dev->allocator, per_thread_acc_temp);
+ if(per_thread_acc_time) MEM_RM(scn->dev->allocator, per_thread_acc_time);
if(rng_proxy) SSP(rng_proxy_ref_put(rng_proxy));
if(out_green) *out_green = green;
if(out_estimator) *out_estimator = estimator;
return (res_T)res;
error:
- if(green) {
- SDIS(green_function_ref_put(green));
- green = NULL;
- }
- if(estimator) {
- SDIS(estimator_ref_put(estimator));
- estimator = NULL;
- }
+ if(estimator) { SDIS(estimator_ref_put(estimator)); estimator = NULL; }
+ if(green) { SDIS(green_function_ref_put(green)); green = NULL; }
goto exit;
}
@@ -330,86 +409,63 @@ XD(solve_probe_boundary_flux)
const struct sdis_solve_probe_boundary_flux_args* args,
struct sdis_estimator** out_estimator)
{
+ /* Time registration */
+ struct time time0, time1;
+ char buf[128]; /* Temporary buffer used to store formated time */
+
+ /* Stardis variables */
+ const struct sdis_interface* interf = NULL;
+ const struct sdis_medium* fmd = NULL;
+ const struct sdis_medium* bmd = NULL;
struct sdis_estimator* estimator = NULL;
+ struct sdis_interface_fragment frag = SDIS_INTERFACE_FRAGMENT_NULL;
+ enum sdis_side solid_side = SDIS_SIDE_NULL__;
+ enum sdis_side fluid_side = SDIS_SIDE_NULL__;
+
+ /* Random number generator */
struct ssp_rng_proxy* rng_proxy = NULL;
- struct ssp_rng** rngs = NULL;
- const struct sdis_interface* interf;
- const struct sdis_medium *fmd, *bmd;
- enum sdis_side solid_side, fluid_side;
- struct sdis_interface_fragment frag;
- struct accum* acc_tp = NULL; /* Per thread temperature accumulator */
- struct accum* acc_ti = NULL; /* Per thread realisation time */
- struct accum* acc_fl = NULL; /* Per thread flux accumulator */
- struct accum* acc_fc = NULL; /* Per thread convective flux accumulator */
- struct accum* acc_fr = NULL; /* Per thread radiative flux accumulator */
- struct accum* acc_fi = NULL; /* Per thread imposed flux accumulator */
+ struct ssp_rng** per_thread_rng = NULL;
+
+ /* Per thread accumulators */
+ struct accum* per_thread_acc_tp = NULL; /* Temperature accumulator */
+ struct accum* per_thread_acc_ti = NULL; /* Realisation time */
+ struct accum* per_thread_acc_fl = NULL; /* Flux accumulator */
+ struct accum* per_thread_acc_fc = NULL; /* Convective flux accumulator */
+ struct accum* per_thread_acc_fr = NULL; /* Radiative flux accumulator */
+ struct accum* per_thread_acc_fi = NULL; /* Imposed flux accumulator */
+
+ /* Gathered accumulator */
+ struct accum acc_tp = ACCUM_NULL;
+ struct accum acc_ti = ACCUM_NULL;
+ struct accum acc_fl = ACCUM_NULL;
+ struct accum acc_fc = ACCUM_NULL;
+ struct accum acc_fr = ACCUM_NULL;
+ struct accum acc_fi = ACCUM_NULL;
+
+ /* Miscellaneous */
size_t nrealisations = 0;
int64_t irealisation = 0;
- size_t i;
- int progress = 0;
+ int32_t* progress = NULL; /* Per process progress bar */
+ int is_master_process = 1;
ATOMIC nsolved_realisations = 0;
ATOMIC res = RES_OK;
- if(!scn || !args || !args->nrealisations || args->nrealisations > INT64_MAX
- || args->time_range[0] < 0 || args->time_range[1] < args->time_range[0]
- || (args->time_range[1]>DBL_MAX && args->time_range[0] != args->time_range[1])
- || !out_estimator) {
- res = RES_BAD_ARG;
- goto error;
- }
-
-#if SDIS_XD_DIMENSION == 2
- if(scene_is_2d(scn) == 0) { res = RES_BAD_ARG; goto error; }
-#else
- if(scene_is_2d(scn) != 0) { res = RES_BAD_ARG; goto error; }
-#endif
-
- /* Check the primitive identifier */
- if(args->iprim >= scene_get_primitives_count(scn)) {
- log_err(scn->dev,
- "%s: invalid primitive identifier `%lu'. "
- "It must be in the [0 %lu] range.\n",
- FUNC_NAME,
- (unsigned long)args->iprim,
- (unsigned long)scene_get_primitives_count(scn)-1);
- res = RES_BAD_ARG;
- goto error;
- }
+ if(!scn) { res = RES_BAD_ARG; goto error; }
+ if(!out_estimator) { res = RES_BAD_ARG; goto error; }
+ res = check_solve_probe_boundary_flux_args(args);
+ if(res != RES_OK) goto error;
+ res = XD(check_primitive_uv)(scn->dev, args->uv);
+ if(res != RES_OK) goto error;
+ res = XD(scene_check_dimensionality)(scn);
+ if(res != RES_OK) goto error;
+ res = scene_check_primitive_index(scn, args->iprim);
+ if(res != RES_OK) goto error;
- /* Check parametric coordinates */
- if(scene_is_2d(scn)) {
- const double v = CLAMP(1.0 - args->uv[0], 0, 1);
- if(args->uv[0] < 0 || args->uv[0] > 1
- || !eq_eps(args->uv[0] + v, 1, 1.e-6)) {
- log_err(scn->dev,
- "%s: invalid parametric coordinates %g. "
- "u + (1-u) must be equal to 1 with u [0, 1].\n",
- FUNC_NAME, args->uv[0]);
- res = RES_BAD_ARG;
- goto error;
- }
- } else {
- const double w = CLAMP(1 - args->uv[0] - args->uv[1], 0, 1);
- if(args->uv[0] < 0
- || args->uv[1] < 0
- || args->uv[0] > 1
- || args->uv[1] > 1
- || !eq_eps(w + args->uv[0] + args->uv[1], 1, 1.e-6)) {
- log_err(scn->dev,
- "%s: invalid parametric coordinates [%g, %g]. "
- "u + v + (1-u-v) must be equal to 1 with u and v in [0, 1].\n",
- FUNC_NAME, args->uv[0], args->uv[1]);
- res = RES_BAD_ARG;
- goto error;
- }
- }
/* Check medium is fluid on one side and solid on the other */
interf = scene_get_interface(scn, (unsigned)args->iprim);
fmd = interface_get_medium(interf, SDIS_FRONT);
bmd = interface_get_medium(interf, SDIS_BACK);
- if(!fmd || !bmd
- || ( !(fmd->type == SDIS_FLUID && bmd->type == SDIS_SOLID)
- && !(fmd->type == SDIS_SOLID && bmd->type == SDIS_FLUID))) {
+ if(!fmd || !bmd || fmd->type == bmd->type) {
log_err(scn->dev,
"%s: Attempt to compute a flux at a %s-%s interface.\n",
FUNC_NAME,
@@ -421,37 +477,30 @@ XD(solve_probe_boundary_flux)
solid_side = (fmd->type == SDIS_SOLID) ? SDIS_FRONT : SDIS_BACK;
fluid_side = (fmd->type == SDIS_FLUID) ? SDIS_FRONT : SDIS_BACK;
- /* Create the proxy RNG */
- if(args->rng_state) {
- res = ssp_rng_proxy_create_from_rng(scn->dev->allocator, args->rng_state,
- scn->dev->nthreads, &rng_proxy);
- if(res != RES_OK) goto error;
- } else {
- res = ssp_rng_proxy_create(scn->dev->allocator, SSP_RNG_MT19937_64,
- scn->dev->nthreads, &rng_proxy);
- if(res != RES_OK) goto error;
- }
+#ifdef SDIS_ENABLE_MPI
+ is_master_process = !scn->dev->use_mpi || scn->dev->mpi_rank == 0;
+#endif
- /* Create the per thread RNG */
- rngs = MEM_CALLOC
- (scn->dev->allocator, scn->dev->nthreads, sizeof(struct ssp_rng*));
- if(!rngs) { res = RES_MEM_ERR; goto error; }
- FOR_EACH(i, 0, scn->dev->nthreads) {
- res = ssp_rng_proxy_create_rng(rng_proxy, i, rngs + i);
- if(res != RES_OK) 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);
+ if(res != RES_OK) goto error;
- /* Create the per thread accumulator */
+ /* Allocate the per process progress status */
+ res = alloc_process_progress(scn->dev, &progress);
+ if(res != RES_OK) goto error;
+
+ /* Create the per thread accumulators */
#define ALLOC_ACCUMS(Dst) { \
Dst = MEM_CALLOC(scn->dev->allocator, scn->dev->nthreads, sizeof(*Dst)); \
if(!Dst) { res = RES_MEM_ERR; goto error; } \
} (void)0
- ALLOC_ACCUMS(acc_tp);
- ALLOC_ACCUMS(acc_ti);
- ALLOC_ACCUMS(acc_fc);
- ALLOC_ACCUMS(acc_fl);
- ALLOC_ACCUMS(acc_fr);
- ALLOC_ACCUMS(acc_fi);
+ ALLOC_ACCUMS(per_thread_acc_tp);
+ ALLOC_ACCUMS(per_thread_acc_ti);
+ ALLOC_ACCUMS(per_thread_acc_fc);
+ ALLOC_ACCUMS(per_thread_acc_fl);
+ ALLOC_ACCUMS(per_thread_acc_fr);
+ ALLOC_ACCUMS(per_thread_acc_fi);
#undef ALLOC_ACCUMS
/* Prebuild the interface fragment */
@@ -459,28 +508,41 @@ XD(solve_probe_boundary_flux)
(&frag, scn, (unsigned)args->iprim, args->uv, fluid_side);
if(res != RES_OK) goto error;
- /* Create the estimator */
- res = estimator_create(scn->dev, SDIS_ESTIMATOR_FLUX, &estimator);
- if(res != RES_OK) goto error;
+ if(is_master_process) {
+ /* Create the estimator */
+ res = estimator_create(scn->dev, SDIS_ESTIMATOR_FLUX, &estimator);
+ if(res != RES_OK) goto error;
+ }
+
+ /* Synchronise the processes */
+ process_barrier(scn->dev);
+
+ #define PROGRESS_MSG "Solving surface probe flux: "
+ print_progress(scn->dev, progress, PROGRESS_MSG);
+
+ /* Begin time registration of the computation */
+ time_current(&time0);
/* Here we go! Launch the Monte Carlo estimation */
- nrealisations = args->nrealisations;
+ nrealisations = compute_process_realisations_count(scn->dev, args->nrealisations);
omp_set_num_threads((int)scn->dev->nthreads);
#pragma omp parallel for schedule(static)
for(irealisation = 0; irealisation < (int64_t)nrealisations; ++irealisation) {
+ struct boundary_flux_realisation_args realis_args =
+ BOUNDARY_FLUX_REALISATION_ARGS_NULL;
struct time t0, t1;
const int ithread = omp_get_thread_num();
- struct ssp_rng* rng = rngs[ithread];
- struct accum* acc_temp = &acc_tp[ithread];
- struct accum* acc_time = &acc_ti[ithread];
- struct accum* acc_flux = &acc_fl[ithread];
- struct accum* acc_fcon = &acc_fc[ithread];
- struct accum* acc_frad = &acc_fr[ithread];
- struct accum* acc_fimp = &acc_fi[ithread];
+ struct ssp_rng* rng = per_thread_rng[ithread];
+ struct accum* acc_temp = &per_thread_acc_tp[ithread];
+ struct accum* acc_time = &per_thread_acc_ti[ithread];
+ struct accum* acc_flux = &per_thread_acc_fl[ithread];
+ struct accum* acc_fcon = &per_thread_acc_fc[ithread];
+ struct accum* acc_frad = &per_thread_acc_fr[ithread];
+ struct accum* acc_fimp = &per_thread_acc_fi[ithread];
double time, epsilon, hc, hr, imposed_flux, imposed_temp;
int flux_mask = 0;
struct bound_flux_result result = BOUND_FLUX_RESULT_NULL__;
- const double Tref = scn->reference_temperature;
+ double Tref = -1;
size_t n;
int pcent;
res_T res_simul = RES_OK;
@@ -496,6 +558,7 @@ XD(solve_probe_boundary_flux)
frag.time = time;
frag.side = fluid_side;
epsilon = interface_side_get_emissivity(interf, &frag);
+ Tref = interface_side_get_reference_temperature(interf, &frag);
hc = interface_get_convection_coef(interf, &frag);
hr = 4.0 * BOLTZMANN_CONSTANT * Tref * Tref * Tref * epsilon;
frag.side = solid_side;
@@ -503,7 +566,8 @@ XD(solve_probe_boundary_flux)
imposed_temp = interface_side_get_temperature(interf, &frag);
if(imposed_temp >= 0) {
/* Flux computation on T boundaries is not supported yet */
- log_err(scn->dev,"%s: Attempt to compute a flux at a Dirichlet boundary "
+ log_err(scn->dev,
+ "%s: Attempt to compute a flux at a Dirichlet boundary "
"(not available yet).\n", FUNC_NAME);
ATOMIC_SET(&res, RES_BAD_ARG);
continue;
@@ -513,8 +577,19 @@ XD(solve_probe_boundary_flux)
flux_mask = 0;
if(hr > 0) flux_mask |= FLUX_FLAG_RADIATIVE;
if(hc > 0) flux_mask |= FLUX_FLAG_CONVECTIVE;
- res_simul = XD(boundary_flux_realisation)(scn, rng, args->iprim, args->uv,
- time, solid_side, flux_mask, &result);
+
+ /* Invoke the boundary flux realisation */
+ realis_args.rng = rng;
+ realis_args.iprim = args->iprim;
+ realis_args.time = time;
+ realis_args.picard_order = args->picard_order;
+ realis_args.solid_side = solid_side;
+ realis_args.flux_mask = flux_mask;
+ realis_args.uv[0] = args->uv[0];
+#if SDIS_XD_DIMENSION == 3
+ realis_args.uv[1] = args->uv[1];
+#endif
+ res_simul = XD(boundary_flux_realisation)(scn, &realis_args, &result);
/* Stop time registration */
time_sub(&t0, time_current(&t1), &t0);
@@ -559,60 +634,83 @@ XD(solve_probe_boundary_flux)
n = (size_t)ATOMIC_INCR(&nsolved_realisations);
pcent = (int)((double)n * 100.0 / (double)nrealisations + 0.5/*round*/);
#pragma omp critical
- if(pcent > progress) {
- progress = pcent;
- log_info(scn->dev, "Solving probe boundary flux: %3d%%\r", progress);
+ if(pcent > progress[0]) {
+ progress[0] = pcent;
+ print_progress_update(scn->dev, progress, PROGRESS_MSG);
}
}
+ /* Synchronise processes */
+ process_barrier(scn->dev);
+
+ res = gather_res_T(scn->dev, (res_T)res);
if(res != RES_OK) goto error;
- /* Add a new line after the progress status */
- log_info(scn->dev, "Solving probe boundary flux: %3d%%\n", progress);
-
- /* Redux the per thread accumulators */
- sum_accums(acc_tp, scn->dev->nthreads, &acc_tp[0]);
- sum_accums(acc_ti, scn->dev->nthreads, &acc_ti[0]);
- sum_accums(acc_fc, scn->dev->nthreads, &acc_fc[0]);
- sum_accums(acc_fr, scn->dev->nthreads, &acc_fr[0]);
- sum_accums(acc_fl, scn->dev->nthreads, &acc_fl[0]);
- sum_accums(acc_fi, scn->dev->nthreads, &acc_fi[0]);
- ASSERT(acc_tp[0].count == acc_fl[0].count);
- ASSERT(acc_tp[0].count == acc_ti[0].count);
- ASSERT(acc_tp[0].count == acc_fr[0].count);
- ASSERT(acc_tp[0].count == acc_fc[0].count);
- ASSERT(acc_tp[0].count == acc_fi[0].count);
+ print_progress_update(scn->dev, progress, PROGRESS_MSG);
+ log_info(scn->dev, "\n");
+ #undef PROGRESS_MSG
- /* Setup the estimated values */
- estimator_setup_realisations_count(estimator, nrealisations, acc_tp[0].count);
- estimator_setup_temperature(estimator, acc_tp[0].sum, acc_tp[0].sum2);
- estimator_setup_realisation_time(estimator, acc_ti[0].sum, acc_ti[0].sum2);
- estimator_setup_flux(estimator, FLUX_CONVECTIVE, acc_fc[0].sum, acc_fc[0].sum2);
- estimator_setup_flux(estimator, FLUX_RADIATIVE, acc_fr[0].sum, acc_fr[0].sum2);
- estimator_setup_flux(estimator, FLUX_IMPOSED, acc_fi[0].sum, acc_fi[0].sum2);
- estimator_setup_flux(estimator, FLUX_TOTAL, acc_fl[0].sum, acc_fl[0].sum2);
-
- res = estimator_save_rng_state(estimator, rng_proxy);
+ /* Report computation time */
+ time_sub(&time0, time_current(&time1), &time0);
+ time_dump(&time0, TIME_ALL, NULL, buf, sizeof(buf));
+ log_info(scn->dev, "Surface probe flux solved in %s.\n", buf);
+
+ /* Gather the RNG proxy sequence IDs and ensure that the RNG proxy state of
+ * the master process is greater than the RNG proxy state of all other
+ * processes */
+ res = gather_rng_proxy_sequence_id(scn->dev, rng_proxy);
if(res != RES_OK) goto error;
-exit:
- if(rngs) {
- FOR_EACH(i, 0, scn->dev->nthreads) {if(rngs[i]) SSP(rng_ref_put(rngs[i]));}
- MEM_RM(scn->dev->allocator, rngs);
+ time_current(&time0);
+
+ #define GATHER_ACCUMS(Msg, Acc) { \
+ res = gather_accumulators(scn->dev, Msg, per_thread_##Acc, &Acc); \
+ if(res != RES_OK) goto error; \
+ } (void)0
+ GATHER_ACCUMS(MPI_SDIS_MSG_ACCUM_TEMP, acc_tp);
+ GATHER_ACCUMS(MPI_SDIS_MSG_ACCUM_TIME, acc_ti);
+ GATHER_ACCUMS(MPI_SDIS_MSG_ACCUM_FLUX_CONVECTIVE, acc_fc);
+ GATHER_ACCUMS(MPI_SDIS_MSG_ACCUM_FLUX_IMPOSED, acc_fi);
+ GATHER_ACCUMS(MPI_SDIS_MSG_ACCUM_FLUX_RADIATIVE, acc_fr);
+ GATHER_ACCUMS(MPI_SDIS_MSG_ACCUM_FLUX_TOTAL, acc_fl);
+ #undef GATHER_ACCUMS
+
+ time_sub(&time0, time_current(&time1), &time0);
+ time_dump(&time0, TIME_ALL, NULL, buf, sizeof(buf));
+ log_info(scn->dev, "Accumulators gathered in %s.\n", buf);
+
+ /* Setup the estimated values */
+ if(is_master_process) {
+ ASSERT(acc_tp.count == acc_fl.count);
+ ASSERT(acc_tp.count == acc_ti.count);
+ ASSERT(acc_tp.count == acc_fr.count);
+ ASSERT(acc_tp.count == acc_fc.count);
+ ASSERT(acc_tp.count == acc_fi.count);
+ estimator_setup_realisations_count(estimator, args->nrealisations, acc_tp.count);
+ estimator_setup_temperature(estimator, acc_tp.sum, acc_tp.sum2);
+ estimator_setup_realisation_time(estimator, acc_ti.sum, acc_ti.sum2);
+ estimator_setup_flux(estimator, FLUX_CONVECTIVE, acc_fc.sum, acc_fc.sum2);
+ estimator_setup_flux(estimator, FLUX_RADIATIVE, acc_fr.sum, acc_fr.sum2);
+ estimator_setup_flux(estimator, FLUX_IMPOSED, acc_fi.sum, acc_fi.sum2);
+ estimator_setup_flux(estimator, FLUX_TOTAL, acc_fl.sum, acc_fl.sum2);
+
+ res = estimator_save_rng_state(estimator, rng_proxy);
+ if(res != RES_OK) goto error;
}
- if(acc_tp) MEM_RM(scn->dev->allocator, acc_tp);
- if(acc_ti) MEM_RM(scn->dev->allocator, acc_ti);
- if(acc_fc) MEM_RM(scn->dev->allocator, acc_fc);
- if(acc_fr) MEM_RM(scn->dev->allocator, acc_fr);
- if(acc_fl) MEM_RM(scn->dev->allocator, acc_fl);
- if(acc_fi) MEM_RM(scn->dev->allocator, acc_fi);
+
+exit:
+ if(per_thread_rng) release_per_thread_rng(scn->dev, per_thread_rng);
+ if(per_thread_acc_tp) MEM_RM(scn->dev->allocator, per_thread_acc_tp);
+ if(per_thread_acc_ti) MEM_RM(scn->dev->allocator, per_thread_acc_ti);
+ if(per_thread_acc_fc) MEM_RM(scn->dev->allocator, per_thread_acc_fc);
+ if(per_thread_acc_fr) MEM_RM(scn->dev->allocator, per_thread_acc_fr);
+ if(per_thread_acc_fl) MEM_RM(scn->dev->allocator, per_thread_acc_fl);
+ if(per_thread_acc_fi) MEM_RM(scn->dev->allocator, per_thread_acc_fi);
+ if(progress) free_process_progress(scn->dev, progress);
if(rng_proxy) SSP(rng_proxy_ref_put(rng_proxy));
if(out_estimator) *out_estimator = estimator;
return (res_T)res;
error:
- if(estimator) {
- SDIS(estimator_ref_put(estimator));
- estimator = NULL;
- }
+ if(estimator) { SDIS(estimator_ref_put(estimator)); estimator = NULL; }
goto exit;
}
diff --git a/src/sdis_tile.c b/src/sdis_tile.c
@@ -0,0 +1,67 @@
+/* Copyright (C) 2016-2022 |Meso|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_tile.h"
+
+/*******************************************************************************
+ * Helper functions
+ ******************************************************************************/
+static INLINE void
+release_tile(ref_T* ref)
+{
+ struct tile* tile = CONTAINER_OF(ref, struct tile, ref);
+ ASSERT(ref);
+ MEM_RM(tile->allocator, tile);
+}
+
+/*******************************************************************************
+ * Helper functions
+ ******************************************************************************/
+res_T
+tile_create(struct mem_allocator* allocator, struct tile** out_tile)
+{
+ struct tile* tile = NULL;
+ res_T res = RES_OK;
+ ASSERT(allocator && out_tile);
+
+ tile = MEM_ALLOC_ALIGNED(allocator, sizeof(*tile), 16);
+ if(!tile) { res = RES_MEM_ERR; goto error; }
+
+ ref_init(&tile->ref);
+ list_init(&tile->node);
+ tile->allocator = allocator;
+ memset(&tile->data, 0, sizeof(tile->data));
+exit:
+ *out_tile = tile;
+ return res;
+error:
+ if(tile) { tile_ref_put(tile); tile = NULL; }
+ goto exit;
+}
+
+void
+tile_ref_get(struct tile* tile)
+{
+ ASSERT(tile);
+ ref_get(&tile->ref);
+}
+
+void
+tile_ref_put(struct tile* tile)
+{
+ ASSERT(tile);
+ ref_put(&tile->ref, release_tile);
+}
+
diff --git a/src/sdis_tile.h b/src/sdis_tile.h
@@ -0,0 +1,67 @@
+/* Copyright (C) 2016-2022 |Meso|Star> (contact@meso-star.com)
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+#ifndef SDIS_TILE_H
+#define SDIS_TILE_H
+
+#include "sdis_misc.h"
+
+#include <rsys/list.h>
+#include <rsys/ref_count.h>
+
+/* Forward declarations */
+struct mem_allocator;
+
+#define TILE_SIZE 4 /* definition in X & Y of a tile */
+STATIC_ASSERT(IS_POW2(TILE_SIZE), TILE_SIZE_must_be_a_power_of_2);
+
+struct pixel {
+ struct accum acc_temp; /* Temperature accumulator */
+ struct accum acc_time; /* Time accumulator */
+};
+
+/* Tile of row ordered pixels */
+struct tile {
+ struct list_node node;
+ struct mem_allocator* allocator;
+ ref_T ref;
+
+ struct tile_data {
+ uint16_t x, y; /* 2D coordinates of the tile in tile space */
+ struct pixel ALIGN(16) pixels[TILE_SIZE*TILE_SIZE];
+ } data;
+};
+
+extern LOCAL_SYM res_T
+tile_create
+ (struct mem_allocator* allocator,
+ struct tile** tile);
+
+extern LOCAL_SYM void
+tile_ref_get
+ (struct tile* tile);
+
+extern LOCAL_SYM void
+tile_ref_put
+ (struct tile* tile);
+
+static INLINE struct pixel*
+tile_at(struct tile* tile, const uint16_t x, const uint16_t y)
+{
+ ASSERT(tile && x < TILE_SIZE && y < TILE_SIZE);
+ return tile->data.pixels + y*TILE_SIZE + x;
+}
+
+#endif /* SDIS_TILE_H */
diff --git a/src/test_sdis.c b/src/test_sdis.c
@@ -0,0 +1,34 @@
+/* Copyright (C) 2016-2022 |Meso|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"
+
+int
+main(int argc, char** argv)
+{
+ struct sdis_info info = SDIS_INFO_NULL;
+ (void)argc, (void)argv;
+
+ BA(sdis_get_info(NULL));
+ OK(sdis_get_info(&info));
+#ifdef SDIS_ENABLE_MPI
+ CHK(info.mpi_enabled);
+#else
+ CHK(!info.mpi_enabled);
+#endif
+ return 0;
+}
+
diff --git a/src/test_sdis_accum_buffer.c b/src/test_sdis_accum_buffer.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 2016-2021 |Meso|Star> (contact@meso-star.com)
+/* Copyright (C) 2016-2022 |Meso|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
diff --git a/src/test_sdis_camera.c b/src/test_sdis_camera.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 2016-2021 |Meso|Star> (contact@meso-star.com)
+/* Copyright (C) 2016-2022 |Meso|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
@@ -23,15 +23,12 @@ main(int argc, char** argv)
{
struct sdis_device* dev;
struct sdis_camera* cam;
- struct mem_allocator allocator;
double pos[3] = {0};
double tgt[3] = {0};
double up[3] = {0};
(void)argc, (void)argv;
- OK(mem_init_proxy_allocator(&allocator, &mem_default_allocator));
-
- OK(sdis_device_create(NULL, &allocator, SDIS_NTHREADS_DEFAULT, 0, &dev));
+ OK(sdis_device_create(&SDIS_DEVICE_CREATE_ARGS_DEFAULT, &dev));
BA(sdis_camera_create(NULL, NULL));
BA(sdis_camera_create(dev, NULL));
@@ -85,8 +82,6 @@ main(int argc, char** argv)
OK(sdis_device_ref_put(dev));
OK(sdis_camera_ref_put(cam));
- check_memory_allocator(&allocator);
- mem_shutdown_proxy_allocator(&allocator);
CHK(mem_allocated_size() == 0);
return 0;
}
diff --git a/src/test_sdis_compute_power.c b/src/test_sdis_compute_power.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 2016-2021 |Meso|Star> (contact@meso-star.com)
+/* Copyright (C) 2016-2022 |Meso|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
@@ -164,7 +164,6 @@ solid_get_volumic_power
int
main(int argc, char** argv)
{
- struct mem_allocator allocator;
struct context ctx;
struct s3dut_mesh* sphere = NULL;
struct s3dut_mesh* cylinder = NULL;
@@ -187,10 +186,10 @@ main(int argc, char** argv)
size_t nverts = 0;
size_t ntris = 0;
double ref = 0;
+ int is_master_process;
(void)argc, (void) argv;
- OK(mem_init_proxy_allocator(&allocator, &mem_default_allocator));
- OK(sdis_device_create(NULL, &allocator, SDIS_NTHREADS_DEFAULT, 1, &dev));
+ create_default_device(&argc, &argv, &is_master_process, &dev);
/* Setup the interface shader */
interf_shader.convection_coef = interface_get_convection_coef;
@@ -202,7 +201,7 @@ main(int argc, char** argv)
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 = solid_get_delta;
+ solid_shader.delta = solid_get_delta;
solid_shader.volumic_power = solid_get_volumic_power;
/* Create the fluid */
@@ -219,8 +218,8 @@ main(int argc, char** argv)
ctx.interf1 = interf1;
/* Create the geometry */
- OK(s3dut_create_sphere(&allocator, 1, 512, 256, &sphere));
- OK(s3dut_create_cylinder(&allocator, 1, 10, 512, 8, &cylinder));
+ OK(s3dut_create_sphere(NULL, 1, 512, 256, &sphere));
+ OK(s3dut_create_cylinder(NULL, 1, 10, 512, 8, &cylinder));
OK(s3dut_mesh_get_data(sphere, &ctx.msh0));
OK(s3dut_mesh_get_data(cylinder, &ctx.msh1));
@@ -258,38 +257,48 @@ main(int argc, char** argv)
args.time_range[0] = args.time_range[1] = INF;
OK(sdis_compute_power(scn, &args, &estimator));
- BA(sdis_estimator_get_power(NULL, &mpow));
- BA(sdis_estimator_get_power(estimator, NULL));
- OK(sdis_estimator_get_power(estimator, &mpow));
- OK(sdis_estimator_get_realisation_time(estimator, &time));
-
- /* Check results for solid 0 */
- ref = 4.0/3.0 * PI * POWER0;
- printf("Mean power of the solid0 = %g ~ %g +/- %g\n",
- ref, mpow.E, mpow.SE);
- check_intersection(ref, 1.e-3*ref, mpow.E, 3*mpow.SE);
- OK(sdis_estimator_ref_put(estimator));
+ if(!is_master_process) {
+ CHK(estimator == NULL);
+ } else {
+ BA(sdis_estimator_get_power(NULL, &mpow));
+ BA(sdis_estimator_get_power(estimator, NULL));
+ OK(sdis_estimator_get_power(estimator, &mpow));
+ OK(sdis_estimator_get_realisation_time(estimator, &time));
+
+ /* Check results for solid 0 */
+ ref = 4.0/3.0 * PI * POWER0;
+ printf("Mean power of the solid0 = %g ~ %g +/- %g\n",
+ ref, mpow.E, mpow.SE);
+ check_intersection(ref, 1.e-3*ref, mpow.E, 3*mpow.SE);
+ OK(sdis_estimator_ref_put(estimator));
+ }
- /* Check results for solid 1 */
args.medium = solid1;
OK(sdis_compute_power(scn, &args, &estimator));
- OK(sdis_estimator_get_power(estimator, &mpow));
- ref = PI * 10 * POWER1;
- printf("Mean power of the solid1 = %g ~ %g +/- %g\n",
- ref, mpow.E, mpow.SE);
- check_intersection(ref, 1.e-3*ref, mpow.E, 3*mpow.SE);
- OK(sdis_estimator_ref_put(estimator));
-
- /* Check for a not null time range */
+
+ if(is_master_process) {
+ /* Check results for solid 1 */
+ OK(sdis_estimator_get_power(estimator, &mpow));
+ ref = PI * 10 * POWER1;
+ printf("Mean power of the solid1 = %g ~ %g +/- %g\n",
+ ref, mpow.E, mpow.SE);
+ check_intersection(ref, 1.e-3*ref, mpow.E, 3*mpow.SE);
+ OK(sdis_estimator_ref_put(estimator));
+ }
+
args.time_range[0] = 0;
args.time_range[1] = 10;
OK(sdis_compute_power(scn, &args, &estimator));
- OK(sdis_estimator_get_power(estimator, &mpow));
- ref = PI * 10 * POWER1 / 10;
- printf("Mean power of the solid1 in [0, 10] s = %g ~ %g +/- %g\n",
- ref, mpow.E, mpow.SE);
- check_intersection(ref, 1.e-3*ref, mpow.E, 3*mpow.SE);
- OK(sdis_estimator_ref_put(estimator));
+
+ if(is_master_process) {
+ /* Check for a not null time range */
+ OK(sdis_estimator_get_power(estimator, &mpow));
+ ref = PI * 10 * POWER1 / 10;
+ printf("Mean power of the solid1 in [0, 10] s = %g ~ %g +/- %g\n",
+ ref, mpow.E, mpow.SE);
+ check_intersection(ref, 1.e-3*ref, mpow.E, 3*mpow.SE);
+ OK(sdis_estimator_ref_put(estimator));
+ }
/* Reset the scene with only one solid medium */
OK(sdis_scene_ref_put(scn));
@@ -305,12 +314,14 @@ main(int argc, char** argv)
/* Check non constant volumic power */
args.medium = solid0;
OK(sdis_compute_power(scn, &args, &estimator));
- OK(sdis_estimator_get_power(estimator, &mpow));
- ref = 4.0/3.0*PI*POWER0 + PI*10*POWER1;
- printf("Mean power of the sphere+cylinder = %g ~ %g +/- %g\n",
- ref, mpow.E, mpow.SE);
- check_intersection(ref, 1e-3*ref, mpow.E, 3*mpow.SE);
- OK(sdis_estimator_ref_put(estimator));
+ if(is_master_process) {
+ OK(sdis_estimator_get_power(estimator, &mpow));
+ ref = 4.0/3.0*PI*POWER0 + PI*10*POWER1;
+ printf("Mean power of the sphere+cylinder = %g ~ %g +/- %g\n",
+ ref, mpow.E, mpow.SE);
+ check_intersection(ref, 1e-2*ref, mpow.E, 3*mpow.SE);
+ OK(sdis_estimator_ref_put(estimator));
+ }
#if 0
{
@@ -328,7 +339,6 @@ main(int argc, char** argv)
#endif
/* Clean up memory */
- OK(sdis_device_ref_put(dev));
OK(sdis_medium_ref_put(fluid));
OK(sdis_medium_ref_put(solid0));
OK(sdis_medium_ref_put(solid1));
@@ -338,8 +348,8 @@ main(int argc, char** argv)
OK(s3dut_mesh_ref_put(sphere));
OK(s3dut_mesh_ref_put(cylinder));
- check_memory_allocator(&allocator);
- mem_shutdown_proxy_allocator(&allocator);
+ free_default_device(dev);
+
CHK(mem_allocated_size() == 0);
return 0;
}
diff --git a/src/test_sdis_conducto_radiative.c b/src/test_sdis_conducto_radiative.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 2016-2021 |Meso|Star> (contact@meso-star.com)
+/* Copyright (C) 2016-2022 |Meso|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
@@ -69,7 +69,7 @@ static const double vertices[16/*#vertices*/*3/*#coords per vertex*/] = {
-1.5, 1.0, 1.0,
1.5, 1.0, 1.0,
};
-static const size_t nvertices = sizeof(vertices) / (3*sizeof(double));
+static const size_t nvertices = sizeof(vertices) / (sizeof(double)*3);
static const size_t indices[32/*#triangles*/*3/*#indices per triangle*/] = {
0, 2, 1, 1, 2, 3, /* Solid back face */
@@ -91,7 +91,7 @@ static const size_t indices[32/*#triangles*/*3/*#indices per triangle*/] = {
3, 7, 11, 11, 7, 15, /* Right fluid top face */
1, 9, 5, 5, 9, 13 /* Right fluid bottom face */
};
-static const size_t ntriangles = sizeof(indices) / (3*sizeof(size_t));
+static const size_t ntriangles = sizeof(indices) / (sizeof(size_t)*3);
static void
get_indices(const size_t itri, size_t ids[3], void* ctx)
@@ -193,6 +193,7 @@ struct interfac {
double convection_coef;
double emissivity;
double specular_fraction;
+ double Tref;
};
static double
@@ -227,6 +228,14 @@ interface_get_specular_fraction
return ((const struct interfac*)sdis_data_cget(data))->specular_fraction;
}
+static double
+interface_get_Tref
+ (const struct sdis_interface_fragment* frag, struct sdis_data* data)
+{
+ CHK(data != NULL && frag != NULL);
+ return ((const struct interfac*)sdis_data_cget(data))->Tref;
+}
+
/*******************************************************************************
* Helper functions
******************************************************************************/
@@ -251,10 +260,12 @@ create_interface
if(sdis_medium_get_type(front) == SDIS_FLUID) {
shader.front.emissivity = interface_get_emissivity;
shader.front.specular_fraction = interface_get_specular_fraction;
+ shader.front.reference_temperature = interface_get_Tref;
}
if(sdis_medium_get_type(back) == SDIS_FLUID) {
shader.back.emissivity = interface_get_emissivity;
shader.back.specular_fraction = interface_get_specular_fraction;
+ shader.back.reference_temperature = interface_get_Tref;
}
shader.convection_coef_upper_bound = MMAX(0, interf->convection_coef);
@@ -267,6 +278,54 @@ create_interface
}
/*******************************************************************************
+ * Test that the evaluation of the green function failed with a picard order
+ * greater than 1, i.e. when one want to handle the non-linearties of the
+ * system.
+ ******************************************************************************/
+static void
+test_invalidity_picardN_green
+ (struct sdis_scene* scn,
+ struct sdis_medium* solid)
+{
+ struct sdis_solve_probe_args probe = SDIS_SOLVE_PROBE_ARGS_DEFAULT;
+ struct sdis_solve_boundary_args bound = SDIS_SOLVE_BOUNDARY_ARGS_DEFAULT;
+ struct sdis_solve_medium_args mdm = SDIS_SOLVE_MEDIUM_ARGS_DEFAULT;
+ struct sdis_solve_probe_boundary_args probe_bound =
+ SDIS_SOLVE_PROBE_BOUNDARY_ARGS_DEFAULT;
+
+ struct sdis_green_function* green = NULL;
+ CHK(scn);
+
+ CHK(probe.picard_order == 1);
+ CHK(probe_bound.picard_order == 1);
+ CHK(bound.picard_order == 1);
+ CHK(mdm.picard_order == 1);
+
+ probe.position[0] = 0;
+ probe.position[1] = 0;
+ probe.position[2] = 0;
+ probe.picard_order = 2;
+ BA(sdis_solve_probe_green_function(scn, &probe, &green));
+
+ probe_bound.iprim = 2; /* Solid left */
+ probe_bound.uv[0] = 0.3;
+ probe_bound.uv[1] = 0.3;
+ probe_bound.side = SDIS_FRONT;
+ probe_bound.picard_order = 2;
+ BA(sdis_solve_probe_boundary_green_function(scn, &probe_bound, &green));
+
+ bound.primitives = &probe_bound.iprim;
+ bound.sides = &probe_bound.side;
+ bound.nprimitives = 1;
+ bound.picard_order = 2;
+ BA(sdis_solve_boundary_green_function(scn, &bound, &green));
+
+ mdm.medium = solid;
+ mdm.picard_order = 2;
+ BA(sdis_solve_medium_green_function(scn, &mdm, &green));
+}
+
+/*******************************************************************************
* Test
******************************************************************************/
int
@@ -283,6 +342,7 @@ main(int argc, char** argv)
struct sdis_interface* interfaces[5] = {NULL};
struct sdis_interface* prim_interfaces[32/*#triangles*/];
struct sdis_scene_create_args scn_args = SDIS_SCENE_CREATE_ARGS_DEFAULT;
+ struct sdis_device_create_args dev_args = SDIS_DEVICE_CREATE_ARGS_DEFAULT;
struct sdis_fluid_shader fluid_shader = DUMMY_FLUID_SHADER;
struct sdis_solid_shader solid_shader = DUMMY_SOLID_SHADER;
struct sdis_scene* scn = NULL;
@@ -295,12 +355,14 @@ main(int argc, char** argv)
const double T0 = 300; /* Fixed temperature on the left side of the system */
const double T1 = 310; /* Fixed temperature on the right side of the system */
const double thickness = 2.0; /* Thickness of the solid along X */
+ double t_range[2];
double Ts0, Ts1, hr, tmp;
struct interfac* p_intface;
(void)argc, (void)argv;
OK(mem_init_proxy_allocator(&allocator, &mem_default_allocator));
- OK(sdis_device_create(NULL, &allocator, SDIS_NTHREADS_DEFAULT, 1, &dev));
+ dev_args.allocator = &allocator;
+ OK(sdis_device_create(&dev_args, &dev));
/* Create the fluid medium */
fluid_shader.temperature = temperature_unknown;
@@ -315,7 +377,7 @@ main(int argc, char** argv)
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 = solid_get_delta;
+ solid_shader.delta = solid_get_delta;
solid_shader.temperature = solid_get_temperature;
OK(sdis_solid_create(dev, &solid_shader, data, &solid));
OK(sdis_data_ref_put(data));
@@ -327,7 +389,7 @@ main(int argc, char** argv)
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 = solid_get_delta;
+ solid_shader.delta = solid_get_delta;
solid_shader.temperature = temperature_unknown;
OK(sdis_solid_create(dev, &solid_shader, data, &solid2));
OK(sdis_data_ref_put(data));
@@ -337,6 +399,7 @@ main(int argc, char** argv)
interf.convection_coef = -1;
interf.emissivity = -1;
interf.specular_fraction = -1;
+ interf.Tref = Tref;
create_interface(dev, solid, solid2, &interf, interfaces+0);
/* Create the interface that emits radiative heat from the solid */
@@ -344,6 +407,7 @@ main(int argc, char** argv)
interf.convection_coef = 0;
interf.emissivity = emissivity;
interf.specular_fraction = 1;
+ interf.Tref = Tref;
create_interface(dev, solid, fluid, &interf, interfaces+1);
/* Create the interface that forces the radiative heat to bounce */
@@ -351,6 +415,7 @@ main(int argc, char** argv)
interf.convection_coef = 0;
interf.emissivity = 0;
interf.specular_fraction = 1;
+ interf.Tref = Tref;
create_interface(dev, fluid, solid2, &interf, interfaces+2);
/* Create the interface with a limit condition of T0 Kelvin */
@@ -358,6 +423,7 @@ main(int argc, char** argv)
interf.convection_coef = 0;
interf.emissivity = 1;
interf.specular_fraction = 1;
+ interf.Tref = T0;
create_interface(dev, fluid, solid2, &interf, interfaces+3);
/* Create the interface with a limit condition of T1 Kelvin */
@@ -365,6 +431,7 @@ main(int argc, char** argv)
interf.convection_coef = 0;
interf.emissivity = 1;
interf.specular_fraction = 1;
+ interf.Tref = T1;
create_interface(dev, fluid, solid2, &interf, interfaces+4);
/* Setup the per primitive interface of the solid medium */
@@ -398,7 +465,8 @@ main(int argc, char** argv)
scn_args.get_position = get_position;
scn_args.nprimitives = ntriangles;
scn_args.nvertices = nvertices;
- scn_args.tref = Tref;
+ scn_args.t_range[0] = MMIN(T0, T1);
+ scn_args.t_range[1] = MMAX(T0, T1);
scn_args.context = &geom;
OK(sdis_scene_create(dev, &scn_args, &scn));
@@ -476,6 +544,9 @@ main(int argc, char** argv)
/* Check same green used at a different temperature */
p_intface->temperature = T1b = T1 + ((double)isimul + 1) * 10;
+ t_range[0] = MMIN(T0, T1b);
+ t_range[1] = MMAX(T0, T1b);
+ OK(sdis_scene_set_temperature_range(scn, t_range));
OK(sdis_solve_probe(scn, &solve_args, &estimator));
OK(sdis_estimator_get_realisation_count(estimator, &nreals));
@@ -522,6 +593,8 @@ main(int argc, char** argv)
printf("\n\n");
}
+ test_invalidity_picardN_green(scn, solid);
+
/* Release memory */
OK(sdis_scene_ref_put(scn));
OK(sdis_interface_ref_put(interfaces[0]));
diff --git a/src/test_sdis_conducto_radiative_2d.c b/src/test_sdis_conducto_radiative_2d.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 2016-2021 |Meso|Star> (contact@meso-star.com)
+/* Copyright (C) 2016-2022 |Meso|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
@@ -58,7 +58,7 @@ static const double vertices[8/*#vertices*/*2/*#coords par vertex*/] = {
-1.5, 1.0,
1.5, 1.0
};
-static const size_t nvertices = sizeof(vertices) / (2*sizeof(double));
+static const size_t nvertices = sizeof(vertices) / (sizeof(double)*2);
static const size_t indices[10/*#segments*/*2/*#indices per segment*/] = {
0, 1, /* Solid bottom segment */
@@ -74,7 +74,7 @@ static const size_t indices[10/*#segments*/*2/*#indices per segment*/] = {
3, 7, /* Right fluid top segment */
7, 4 /* Right fluid right segment */
};
-static const size_t nsegments = sizeof(indices) / (2*sizeof(size_t));
+static const size_t nsegments = sizeof(indices) / (sizeof(size_t)*2);
static void
get_indices(const size_t iseg, size_t ids[2], void* ctx)
@@ -158,11 +158,12 @@ struct interfac {
double temperature;
double emissivity;
double specular_fraction;
+ double reference_temperature;
} front, back;
};
static const struct interfac INTERFACE_NULL = {
- 0, {-1, -1, -1}, {-1, -1, -1}
+ 0, {-1, -1, -1, -1}, {-1, -1, -1, -1}
};
static double
@@ -223,6 +224,22 @@ interface_get_specular_fraction
return f;
}
+static double
+interface_get_reference_temperature
+ (const struct sdis_interface_fragment* frag, struct sdis_data* data)
+{
+ const struct interfac* interf;
+ double T = -1;
+ CHK(data != NULL && frag != NULL);
+ interf = sdis_data_cget(data);
+ switch(frag->side) {
+ case SDIS_FRONT: T = interf->front.reference_temperature; break;
+ case SDIS_BACK: T = interf->back.reference_temperature; break;
+ default: FATAL("Unreachable code.\n"); break;
+ }
+ return T;
+}
+
/*******************************************************************************
* Helper functions
******************************************************************************/
@@ -250,10 +267,12 @@ create_interface
if(type_f == SDIS_FLUID) {
shader.front.emissivity = interface_get_emissivity;
shader.front.specular_fraction = interface_get_specular_fraction;
+ shader.front.reference_temperature = interface_get_reference_temperature;
}
if(type_b == SDIS_FLUID) {
shader.back.emissivity = interface_get_emissivity;
shader.back.specular_fraction = interface_get_specular_fraction;
+ shader.back.reference_temperature = interface_get_reference_temperature;
}
shader.convection_coef_upper_bound = MMAX(0, interf->convection_coef);
@@ -266,6 +285,52 @@ create_interface
}
/*******************************************************************************
+ * Test that the evaluation of the green function failed with a picard order
+ * greater than 1, i.e. when one want to handle the non-linearties of the
+ * system.
+ ******************************************************************************/
+static void
+test_invalidity_picardN_green
+ (struct sdis_scene* scn,
+ struct sdis_medium* solid)
+{
+ struct sdis_solve_probe_args probe = SDIS_SOLVE_PROBE_ARGS_DEFAULT;
+ struct sdis_solve_boundary_args bound = SDIS_SOLVE_BOUNDARY_ARGS_DEFAULT;
+ struct sdis_solve_medium_args mdm = SDIS_SOLVE_MEDIUM_ARGS_DEFAULT;
+ struct sdis_solve_probe_boundary_args probe_bound =
+ SDIS_SOLVE_PROBE_BOUNDARY_ARGS_DEFAULT;
+
+ struct sdis_green_function* green = NULL;
+ CHK(scn);
+
+ CHK(probe.picard_order == 1);
+ CHK(probe_bound.picard_order == 1);
+ CHK(bound.picard_order == 1);
+ CHK(mdm.picard_order == 1);
+
+ probe.position[0] = 0;
+ probe.position[1] = 0;
+ probe.picard_order = 2;
+ BA(sdis_solve_probe_green_function(scn, &probe, &green));
+
+ probe_bound.iprim = 1; /* Solid left */
+ probe_bound.uv[0] = 0.5;
+ probe_bound.side = SDIS_FRONT;
+ probe_bound.picard_order = 2;
+ BA(sdis_solve_probe_boundary_green_function(scn, &probe_bound, &green));
+
+ bound.primitives = &probe_bound.iprim;
+ bound.sides = &probe_bound.side;
+ bound.nprimitives = 1;
+ bound.picard_order = 2;
+ BA(sdis_solve_boundary_green_function(scn, &bound, &green));
+
+ mdm.medium = solid;
+ mdm.picard_order = 2;
+ BA(sdis_solve_medium_green_function(scn, &mdm, &green));
+}
+
+/*******************************************************************************
* Test
******************************************************************************/
int
@@ -298,7 +363,7 @@ main(int argc, char** argv)
(void)argc, (void)argv;
OK(mem_init_proxy_allocator(&allocator, &mem_default_allocator));
- OK(sdis_device_create(NULL, &allocator, SDIS_NTHREADS_DEFAULT, 1, &dev));
+ OK(sdis_device_create(&SDIS_DEVICE_CREATE_ARGS_DEFAULT, &dev));
/* Create the fluid medium */
fluid_shader.temperature = temperature_unknown;
@@ -311,7 +376,7 @@ main(int argc, char** argv)
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 = solid_get_delta;
+ solid_shader.delta = solid_get_delta;
solid_shader.temperature = temperature_unknown;
OK(sdis_solid_create(dev, &solid_shader, data, &solid));
OK(sdis_data_ref_put(data));
@@ -323,7 +388,7 @@ main(int argc, char** argv)
solid_shader.calorific_capacity = solid_get_thermal_conductivity;
solid_shader.thermal_conductivity = solid_get_thermal_conductivity;
solid_shader.volumic_mass = solid_get_volumic_mass;
- solid_shader.delta_solid = solid_get_delta;
+ solid_shader.delta = solid_get_delta;
OK(sdis_solid_create(dev, &solid_shader, data, &solid2));
OK(sdis_data_ref_put(data));
@@ -336,6 +401,7 @@ main(int argc, char** argv)
interf.back.temperature = UNKNOWN_TEMPERATURE;
interf.back.emissivity = emissivity;
interf.back.specular_fraction = -1; /* Should not be fetched */
+ interf.back.reference_temperature = Tref;
create_interface(dev, solid, fluid, &interf, interfaces+1);
/* Create the interface that forces the radiative heat to bounce */
@@ -343,6 +409,7 @@ main(int argc, char** argv)
interf.front.temperature = UNKNOWN_TEMPERATURE;
interf.front.emissivity = 0;
interf.front.specular_fraction = 1;
+ interf.front.reference_temperature = Tref;
create_interface(dev, fluid, solid2, &interf, interfaces+2);
/* Create the interface with a limit condition of T0 Kelvin */
@@ -350,6 +417,7 @@ main(int argc, char** argv)
interf.front.temperature = T0;
interf.front.emissivity = 1;
interf.front.specular_fraction = 1;
+ interf.front.reference_temperature = T0;
create_interface(dev, fluid, solid2, &interf, interfaces+3);
/* Create the interface with a limit condition of T1 Kelvin */
@@ -357,6 +425,7 @@ main(int argc, char** argv)
interf.front.temperature = T1;
interf.front.emissivity = 1;
interf.front.specular_fraction = 1;
+ interf.front.reference_temperature = T1;
create_interface(dev, fluid, solid2, &interf, interfaces+4);
/* Setup the per primitive interface of the solid medium */
@@ -384,8 +453,9 @@ main(int argc, char** argv)
scn_args.get_position = get_position;
scn_args.nprimitives = nsegments;
scn_args.nvertices = nvertices;
- scn_args.tref = Tref;
scn_args.context = &geom;
+ scn_args.t_range[0] = MMIN(T0, T1);
+ scn_args.t_range[1] = MMAX(T0, T1);
OK(sdis_scene_2d_create(dev, &scn_args, &scn));
hr = 4*BOLTZMANN_CONSTANT * Tref*Tref*Tref * emissivity;
@@ -450,6 +520,8 @@ main(int argc, char** argv)
printf("\n\n");
}
+ test_invalidity_picardN_green(scn, solid);
+
/* Release memory */
OK(sdis_scene_ref_put(scn));
OK(sdis_interface_ref_put(interfaces[0]));
diff --git a/src/test_sdis_contact_resistance.c b/src/test_sdis_contact_resistance.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 2016-2021 |Meso|Star> (contact@meso-star.com)
+/* Copyright (C) 2016-2022 |Meso|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
@@ -251,7 +251,6 @@ solve
int
main(int argc, char** argv)
{
- struct mem_allocator allocator;
struct sdis_data* data = NULL;
struct sdis_device* dev = NULL;
struct sdis_medium* fluid = NULL;
@@ -275,8 +274,7 @@ main(int argc, char** argv)
struct ssp_rng* rng = NULL;
(void)argc, (void)argv;
- OK(mem_init_proxy_allocator(&allocator, &mem_default_allocator));
- OK(sdis_device_create(NULL, &allocator, SDIS_NTHREADS_DEFAULT, 1, &dev));
+ OK(sdis_device_create(&SDIS_DEVICE_CREATE_ARGS_DEFAULT, &dev));
fluid_shader.temperature = fluid_get_temperature;
OK(sdis_fluid_create(dev, &fluid_shader, NULL, &fluid));
@@ -285,7 +283,7 @@ main(int argc, char** argv)
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 = solid_get_delta;
+ solid_shader.delta = solid_get_delta;
solid_shader.temperature = solid_get_temperature;
/* Create the solid medium #1 */
@@ -425,7 +423,7 @@ main(int argc, char** argv)
OK(sdis_interface_ref_put(interf_R));
/* Solve */
- OK(ssp_rng_create(&allocator, SSP_RNG_KISS, &rng));
+ OK(ssp_rng_create(NULL, SSP_RNG_KISS, &rng));
printf(">> Box scene\n");
solve(box_scn, interf_props, rng);
printf("\n>> Square scene\n");
@@ -436,8 +434,6 @@ main(int argc, char** argv)
OK(sdis_device_ref_put(dev));
OK(ssp_rng_ref_put(rng));
- check_memory_allocator(&allocator);
- mem_shutdown_proxy_allocator(&allocator);
CHK(mem_allocated_size() == 0);
return 0;
}
diff --git a/src/test_sdis_contact_resistance.h b/src/test_sdis_contact_resistance.h
@@ -1,4 +1,4 @@
-/* Copyright (C) 2016-2021 |Meso|Star> (contact@meso-star.com)
+/* Copyright (C) 2016-2022 |Meso|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
@@ -37,8 +37,7 @@
/*******************************************************************************
* Box geometry
******************************************************************************/
-static const double model3d_vertices[12/*#vertices*/ * 3/*#coords per vertex*/]
-= {
+static const double model3d_vertices[12/*#vertices*/*3/*#coords per vertex*/] = {
0, 0, 0,
X0, 0, 0,
L, 0, 0,
@@ -52,7 +51,7 @@ static const double model3d_vertices[12/*#vertices*/ * 3/*#coords per vertex*/]
X0, L, L,
L, L, L
};
-static const size_t model3d_nvertices = sizeof(model3d_vertices) / (3*sizeof(double));
+static const size_t model3d_nvertices = sizeof(model3d_vertices)/(sizeof(double)*3);
/* The following array lists the indices toward the 3D vertices of each
* triangle.
@@ -64,8 +63,7 @@ static const size_t model3d_nvertices = sizeof(model3d_vertices) / (3*sizeof(dou
* 6----7----8' 6----7'---8' 7 /
* Front, right Back, left and Internal Z
* and Top faces bottom faces face */
-static const size_t model3d_indices[22/*#triangles*/ * 3/*#indices per triangle*/]
-= {
+static const size_t model3d_indices[22/*#triangles*/*3/*#indices per triangle*/] = {
0, 3, 1, 1, 3, 4, 1, 4, 2, 2, 4, 5, /* -Z */
0, 6, 3, 3, 6, 9, /* -X */
6, 7, 9, 9, 7, 10, 7, 8, 10, 10, 8, 11, /* +Z */
@@ -74,7 +72,7 @@ static const size_t model3d_indices[22/*#triangles*/ * 3/*#indices per triangle*
0, 1, 7, 7, 6, 0, 1, 2, 8, 8, 7, 1, /* -Y */
4, 10, 7, 7, 1, 4 /* Inside */
};
-static const size_t model3d_ntriangles = sizeof(model3d_indices) / (3*sizeof(size_t));
+static const size_t model3d_ntriangles = sizeof(model3d_indices)/(sizeof(size_t)*3);
static INLINE void
model3d_get_indices(const size_t itri, size_t ids[3], void* context)
@@ -110,7 +108,7 @@ model3d_get_interface(const size_t itri, struct sdis_interface** bound, void* co
/*******************************************************************************
* Square geometry
******************************************************************************/
-static const double model2d_vertices[6/*#vertices*/ * 2/*#coords per vertex*/] = {
+static const double model2d_vertices[6/*#vertices*/*2/*#coords per vertex*/] = {
L, 0,
X0, 0,
0, 0,
@@ -118,7 +116,7 @@ static const double model2d_vertices[6/*#vertices*/ * 2/*#coords per vertex*/] =
X0, L,
L, L
};
-static const size_t model2d_nvertices = sizeof(model2d_vertices) / (2*sizeof(double));
+static const size_t model2d_nvertices = sizeof(model2d_vertices)/(sizeof(double)*2);
static const size_t model2d_indices[7/*#segments*/ * 2/*#indices per segment*/] = {
0, 1, 1, 2, /* Bottom */
@@ -127,8 +125,7 @@ static const size_t model2d_indices[7/*#segments*/ * 2/*#indices per segment*/]
5, 0, /* Right */
4, 1 /* Inside */
};
-static const size_t model2d_nsegments = sizeof(model2d_indices) / (2*sizeof(size_t));
-
+static const size_t model2d_nsegments = sizeof(model2d_indices) / (sizeof(size_t)*2);
static INLINE void
model2d_get_indices(const size_t iseg, size_t ids[2], void* context)
diff --git a/src/test_sdis_contact_resistance_2.c b/src/test_sdis_contact_resistance_2.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 2016-2021 |Meso|Star> (contact@meso-star.com)
+/* Copyright (C) 2016-2022 |Meso|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
@@ -54,8 +54,8 @@
#define TL 100.0
#define LAMBDA2 0.2
-#define DELTA1 X0/25.0
-#define DELTA2 (L-X0)/25.0
+#define DELTA1 X0/30.0
+#define DELTA2 (L-X0)/30.0
/*******************************************************************************
* Media
@@ -345,7 +345,6 @@ solve
int
main(int argc, char** argv)
{
- struct mem_allocator allocator;
struct sdis_data* data = NULL;
struct sdis_device* dev = NULL;
struct sdis_medium* fluid = NULL;
@@ -369,8 +368,7 @@ main(int argc, char** argv)
struct ssp_rng* rng = NULL;
(void)argc, (void)argv;
- OK(mem_init_proxy_allocator(&allocator, &mem_default_allocator));
- OK(sdis_device_create(NULL, &allocator, SDIS_NTHREADS_DEFAULT, 1, &dev));
+ OK(sdis_device_create(&SDIS_DEVICE_CREATE_ARGS_DEFAULT, &dev));
fluid_shader.temperature = fluid_get_temperature;
OK(sdis_fluid_create(dev, &fluid_shader, NULL, &fluid));
@@ -379,7 +377,7 @@ main(int argc, char** argv)
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 = solid_get_delta;
+ solid_shader.delta = solid_get_delta;
solid_shader.temperature = solid_get_temperature;
/* Create the solid medium #1 */
@@ -519,7 +517,7 @@ main(int argc, char** argv)
OK(sdis_interface_ref_put(interf_R));
/* Solve */
- OK(ssp_rng_create(&allocator, SSP_RNG_KISS, &rng));
+ OK(ssp_rng_create(NULL, SSP_RNG_KISS, &rng));
printf(">> Box scene\n");
solve_probe(box_scn, interf_props, rng);
solve(box_scn, interf_props, rng);
@@ -532,8 +530,6 @@ main(int argc, char** argv)
OK(sdis_device_ref_put(dev));
OK(ssp_rng_ref_put(rng));
- check_memory_allocator(&allocator);
- mem_shutdown_proxy_allocator(&allocator);
CHK(mem_allocated_size() == 0);
return 0;
}
diff --git a/src/test_sdis_convection.c b/src/test_sdis_convection.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 2016-2021 |Meso|Star> (contact@meso-star.com)
+/* Copyright (C) 2016-2022 |Meso|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
@@ -165,7 +165,6 @@ create_interface
int
main(int argc, char** argv)
{
- struct mem_allocator allocator;
struct sdis_mc T = SDIS_MC_NULL;
struct sdis_mc mc_time = SDIS_MC_NULL;
struct sdis_device* dev = NULL;
@@ -198,8 +197,7 @@ main(int argc, char** argv)
int i;
(void)argc, (void)argv;
- OK(mem_init_proxy_allocator(&allocator, &mem_default_allocator));
- OK(sdis_device_create(NULL, &allocator, SDIS_NTHREADS_DEFAULT, 0, &dev));
+ OK(sdis_device_create(&SDIS_DEVICE_CREATE_ARGS_DEFAULT, &dev));
/* Create the fluid medium */
OK(sdis_data_create(dev, sizeof(int), ALIGNOF(int), NULL, &is_stationary));
@@ -361,8 +359,6 @@ main(int argc, char** argv)
OK(sdis_device_ref_put(dev));
OK(sdis_data_ref_put(is_stationary));
- check_memory_allocator(&allocator);
- mem_shutdown_proxy_allocator(&allocator);
CHK(mem_allocated_size() == 0);
return 0;
}
diff --git a/src/test_sdis_convection_non_uniform.c b/src/test_sdis_convection_non_uniform.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 2016-2021 |Meso|Star> (contact@meso-star.com)
+/* Copyright (C) 2016-2022 |Meso|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
@@ -175,7 +175,6 @@ create_interface
int
main(int argc, char** argv)
{
- struct mem_allocator allocator;
struct sdis_mc T = SDIS_MC_NULL;
struct sdis_mc mc_time = SDIS_MC_NULL;
struct sdis_device* dev = NULL;
@@ -208,8 +207,7 @@ main(int argc, char** argv)
int i;
(void)argc, (void)argv;
- OK(mem_init_proxy_allocator(&allocator, &mem_default_allocator));
- OK(sdis_device_create(NULL, &allocator, SDIS_NTHREADS_DEFAULT, 0, &dev));
+ OK(sdis_device_create(&SDIS_DEVICE_CREATE_ARGS_DEFAULT, &dev));
OK(sdis_data_create(dev, sizeof(int), ALIGNOF(int), NULL, &is_stationary));
*((int*)sdis_data_get(is_stationary)) = 0;
@@ -376,8 +374,6 @@ main(int argc, char** argv)
OK(sdis_device_ref_put(dev));
OK(sdis_data_ref_put(is_stationary));
- check_memory_allocator(&allocator);
- mem_shutdown_proxy_allocator(&allocator);
CHK(mem_allocated_size() == 0);
return 0;
}
diff --git a/src/test_sdis_data.c b/src/test_sdis_data.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 2016-2021 |Meso|Star> (contact@meso-star.com)
+/* Copyright (C) 2016-2022 |Meso|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
@@ -36,14 +36,12 @@ int
main(int argc, char** argv)
{
const char* str = "Hello world!";
- struct mem_allocator allocator;
struct sdis_device* dev = NULL;
struct sdis_data* data = NULL;
struct param* param = NULL;
(void)argc, (void)argv;
- OK(mem_init_proxy_allocator(&allocator, &mem_default_allocator));
- OK(sdis_device_create(NULL, &allocator, SDIS_NTHREADS_DEFAULT, 0, &dev));
+ OK(sdis_device_create(&SDIS_DEVICE_CREATE_ARGS_DEFAULT, &dev));
BA(sdis_data_create(NULL, 0, 0, NULL, NULL));
BA(sdis_data_create(dev, 0, 0, NULL, NULL));
BA(sdis_data_create(NULL, 8, 0, NULL, NULL));
@@ -87,7 +85,6 @@ main(int argc, char** argv)
OK(sdis_data_ref_put(data));
OK(sdis_device_ref_put(dev));
- mem_shutdown_proxy_allocator(&allocator);
CHK(mem_allocated_size() == 0);
return 0;
}
diff --git a/src/test_sdis_device.c b/src/test_sdis_device.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 2016-2021 |Meso|Star> (contact@meso-star.com)
+/* Copyright (C) 2016-2022 |Meso|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
@@ -18,6 +18,10 @@
#include <rsys/logger.h>
+#ifdef SDIS_ENABLE_MPI
+#include <mpi.h>
+#endif
+
static INLINE void
log_stream(const char* msg, void* ctx)
{
@@ -29,14 +33,22 @@ log_stream(const char* msg, void* ctx)
int
main(int argc, char** argv)
{
+ struct sdis_device_create_args args = SDIS_DEVICE_CREATE_ARGS_DEFAULT;
struct logger logger;
struct mem_allocator allocator;
struct sdis_device* dev;
+#ifdef SDIS_ENABLE_MPI
+ int provided;
+#endif
(void)argc, (void)argv;
- BA(sdis_device_create(NULL, NULL, 0, 0, NULL));
- BA(sdis_device_create(NULL, NULL, 0, 0, &dev));
- OK(sdis_device_create(NULL, NULL, 1, 0, &dev));
+ args.nthreads_hint = 0;
+ args.verbosity = 0;
+
+ BA(sdis_device_create(&args, NULL));
+ BA(sdis_device_create(&args, &dev));
+ args.nthreads_hint = 1;
+ OK(sdis_device_create(&args, &dev));
BA(sdis_device_ref_get(NULL));
OK(sdis_device_ref_get(dev));
BA(sdis_device_ref_put(NULL));
@@ -46,8 +58,11 @@ main(int argc, char** argv)
OK(mem_init_proxy_allocator(&allocator, &mem_default_allocator));
CHK(MEM_ALLOCATED_SIZE(&allocator) == 0);
- BA(sdis_device_create(NULL, &allocator, 1, 0, NULL));
- OK(sdis_device_create(NULL, &allocator, 1, 0, &dev));
+
+ args.allocator = &allocator;
+ args.verbosity = 0;
+ BA(sdis_device_create(&args, NULL));
+ OK(sdis_device_create(&args, &dev));
OK(sdis_device_ref_put(dev));
CHK(MEM_ALLOCATED_SIZE(&allocator) == 0);
@@ -56,16 +71,33 @@ main(int argc, char** argv)
logger_set_stream(&logger, LOG_ERROR, log_stream, NULL);
logger_set_stream(&logger, LOG_WARNING, log_stream, NULL);
- BA(sdis_device_create(&logger, NULL, 1, 0, NULL));
- OK(sdis_device_create(&logger, NULL, 1, 0, &dev));
+ args.logger = &logger;
+ args.allocator = NULL;
+ BA(sdis_device_create(&args, NULL));
+ OK(sdis_device_create(&args, &dev));
OK(sdis_device_ref_put(dev));
- BA(sdis_device_create(&logger, &allocator, 1, 0, NULL));
- OK(sdis_device_create(&logger, &allocator, 1, 0, &dev));
+ args.allocator = &allocator;
+ BA(sdis_device_create(&args, NULL));
+ OK(sdis_device_create(&args, &dev));
OK(sdis_device_ref_put(dev));
- OK(sdis_device_create(&logger, &allocator, SDIS_NTHREADS_DEFAULT, 0, &dev));
+ args.nthreads_hint = SDIS_NTHREADS_DEFAULT;
+ OK(sdis_device_create(&args, &dev));
+ OK(sdis_device_ref_put(dev));
+
+ args.use_mpi = 1;
+ args.verbosity = 1;
+
+#ifndef SDIS_ENABLE_MPI
+ OK(sdis_device_create(&args, &dev));
+ OK(sdis_device_ref_put(dev));
+#else
+ CHK(MPI_Init_thread(&argc, &argv, MPI_THREAD_SERIALIZED, &provided) == MPI_SUCCESS);
+ OK(sdis_device_create(&args, &dev));
+ CHK(MPI_Finalize() == MPI_SUCCESS);
OK(sdis_device_ref_put(dev));
+#endif
logger_release(&logger);
check_memory_allocator(&allocator);
diff --git a/src/test_sdis_flux.c b/src/test_sdis_flux.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 2016-2021 |Meso|Star> (contact@meso-star.com)
+/* Copyright (C) 2016-2022 |Meso|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
@@ -153,6 +153,7 @@ solve
ASSERT(scn && rng && interf);
OK(sdis_scene_get_dimension(scn, &dim));
+
FOR_EACH(isimul, 0, nsimuls) {
int steady = (isimul % 2) == 0;
@@ -335,6 +336,15 @@ solve
printf("\n\n");
}
+
+ /* Picard N is not supported with a flux != 0 */
+ solve_args.position[0] = 0.1;
+ solve_args.position[1] = 0.1;
+ solve_args.position[2] = dim == SDIS_SCENE_2D ? 0 : 0.1;
+ solve_args.time_range[0] = INF;
+ solve_args.time_range[1] = INF;
+ solve_args.picard_order = 2;
+ BA(sdis_solve_probe(scn, &solve_args, &estimator));
}
/*******************************************************************************
@@ -343,7 +353,6 @@ solve
int
main(int argc, char** argv)
{
- struct mem_allocator allocator;
struct sdis_data* data = NULL;
struct sdis_device* dev = NULL;
struct sdis_medium* fluid = NULL;
@@ -363,8 +372,7 @@ main(int argc, char** argv)
struct ssp_rng* rng = NULL;
(void)argc, (void)argv;
- OK(mem_init_proxy_allocator(&allocator, &mem_default_allocator));
- OK(sdis_device_create(NULL, &allocator, SDIS_NTHREADS_DEFAULT, 1, &dev));
+ OK(sdis_device_create(&SDIS_DEVICE_CREATE_ARGS_DEFAULT, &dev));
/* Create the dummy fluid medium */
OK(sdis_fluid_create(dev, &fluid_shader, NULL, &fluid));
@@ -373,7 +381,7 @@ main(int argc, char** argv)
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 = solid_get_delta;
+ solid_shader.delta = solid_get_delta;
solid_shader.temperature = solid_get_temperature;
OK(sdis_solid_create(dev, &solid_shader, NULL, &solid));
@@ -449,7 +457,7 @@ main(int argc, char** argv)
OK(sdis_interface_ref_put(interf_phi));
/* Solve */
- OK(ssp_rng_create(&allocator, SSP_RNG_KISS, &rng));
+ OK(ssp_rng_create(NULL, SSP_RNG_KISS, &rng));
printf(">> Box scene\n");
solve(box_scn, rng, interf_props);
printf(">> Square Scene\n");
@@ -460,8 +468,6 @@ main(int argc, char** argv)
OK(sdis_device_ref_put(dev));
OK(ssp_rng_ref_put(rng));
- check_memory_allocator(&allocator);
- mem_shutdown_proxy_allocator(&allocator);
CHK(mem_allocated_size() == 0);
return 0;
}
diff --git a/src/test_sdis_interface.c b/src/test_sdis_interface.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 2016-2021 |Meso|Star> (contact@meso-star.com)
+/* Copyright (C) 2016-2022 |Meso|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
@@ -19,7 +19,6 @@
int
main(int argc, char** argv)
{
- struct mem_allocator allocator;
struct sdis_data* data = NULL;
struct sdis_device* dev = NULL;
struct sdis_medium* fluid = NULL;
@@ -32,8 +31,7 @@ main(int argc, char** argv)
struct sdis_interface_shader shader2 = SDIS_INTERFACE_SHADER_NULL;
(void)argc, (void)argv;
- OK(mem_init_proxy_allocator(&allocator, &mem_default_allocator));
- OK(sdis_device_create(NULL, &allocator, SDIS_NTHREADS_DEFAULT, 1, &dev));
+ OK(sdis_device_create(&SDIS_DEVICE_CREATE_ARGS_DEFAULT, &dev));
OK(sdis_fluid_create(dev, &fluid_shader, NULL, &fluid));
OK(sdis_solid_create(dev, &solid_shader, NULL, &solid));
@@ -144,8 +142,6 @@ main(int argc, char** argv)
OK(sdis_medium_ref_put(fluid));
OK(sdis_medium_ref_put(solid));
- check_memory_allocator(&allocator);
- mem_shutdown_proxy_allocator(&allocator);
CHK(mem_allocated_size() == 0);
return 0;
}
diff --git a/src/test_sdis_medium.c b/src/test_sdis_medium.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 2016-2021 |Meso|Star> (contact@meso-star.com)
+/* Copyright (C) 2016-2022 |Meso|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
@@ -21,7 +21,6 @@
int
main(int argc, char** argv)
{
- struct mem_allocator allocator;
struct sdis_data* data = NULL;
struct sdis_device* dev = NULL;
struct sdis_medium* fluid = NULL;
@@ -32,8 +31,7 @@ main(int argc, char** argv)
struct sdis_solid_shader solid_shader2 = SDIS_SOLID_SHADER_NULL;
(void)argc, (void)argv;
- OK(mem_init_proxy_allocator(&allocator, &mem_default_allocator));
- OK(sdis_device_create(NULL, &allocator, SDIS_NTHREADS_DEFAULT, 0, &dev));
+ OK(sdis_device_create(&SDIS_DEVICE_CREATE_ARGS_DEFAULT, &dev));
BA(sdis_fluid_create(NULL, NULL, NULL, NULL));
BA(sdis_fluid_create(dev, NULL, NULL, NULL));
@@ -85,7 +83,7 @@ main(int argc, char** argv)
CHK(sdis_medium_get_type(solid) == SDIS_SOLID);
CHK(sdis_medium_get_data(solid) == data);
- OK(sdis_medium_ref_put(solid));
+ OK(sdis_medium_ref_put(solid));
OK(sdis_data_ref_put(data));
solid_shader.calorific_capacity = NULL;
@@ -100,9 +98,9 @@ main(int argc, char** argv)
BA(sdis_solid_create(dev, &solid_shader, NULL, &solid));
solid_shader.volumic_mass = DUMMY_SOLID_SHADER.volumic_mass;
- solid_shader.delta_solid = NULL;
+ solid_shader.delta = NULL;
BA(sdis_solid_create(dev, &solid_shader, NULL, &solid));
- solid_shader.delta_solid = DUMMY_SOLID_SHADER.delta_solid;
+ solid_shader.delta = DUMMY_SOLID_SHADER.delta;
solid_shader.temperature = NULL;
BA(sdis_solid_create(dev, &solid_shader, NULL, &solid));
@@ -137,7 +135,7 @@ main(int argc, char** argv)
CHK(solid_shader.calorific_capacity == solid_shader2.calorific_capacity);
CHK(solid_shader.thermal_conductivity == solid_shader2.thermal_conductivity);
CHK(solid_shader.volumic_mass == solid_shader2.volumic_mass);
- CHK(solid_shader.delta_solid == solid_shader2.delta_solid);
+ CHK(solid_shader.delta == solid_shader2.delta);
CHK(solid_shader.volumic_power == solid_shader2.volumic_power);
CHK(solid_shader.temperature == solid_shader2.temperature);
CHK(solid_shader.t0 == solid_shader2.t0);
@@ -146,8 +144,6 @@ main(int argc, char** argv)
OK(sdis_medium_ref_put(fluid));
OK(sdis_device_ref_put(dev));
- check_memory_allocator(&allocator);
- mem_shutdown_proxy_allocator(&allocator);
CHK(mem_allocated_size() == 0);
return 0;
diff --git a/src/test_sdis_picard.c b/src/test_sdis_picard.c
@@ -0,0 +1,776 @@
+/* Copyright (C) 2016-2022 |Meso|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 <string.h>
+
+#define UNKNOWN_TEMPERATURE -1
+#define N 10000
+
+/* This test consists in solving the stationary temperature profile in a solid
+ * slab surrounded by two different radiative temperatures (left / right). The
+ * conductivity of the solid material is known, as well as its thickness and
+ * the source term (volumic power density).
+ *
+ * The purpose is to test the Picard radiative transfer algorithm, that can be
+ * compared with analytic results. This algorithm can use a possibly
+ * non-uniform reference temperature field. When the reference temperature
+ * field is uniform and the picard order set to 1, results should be identical
+ * to the classical Monte-Carlo algorithm (using a linearized radiative
+ * transfer scheme).
+ *
+ * Y
+ * | (0.1,1)
+ * o--- X +----------+------+ (1.1,1)
+ * |##########| |
+ * |##########| |
+ * 280K E=1|##########| E=1 | 350K
+ * |##########| |
+ * |##########| |
+ * (-1,-1) +----------+------+
+ * (0,-1)
+ *
+ *
+ *
+ * Y (0.1, 1, 1)
+ * | +----------+------+ (1.1,1,1)
+ * o--- X /##########/' /|
+ * / +----------+------+ |
+ * Z |##########|*' | | 350K
+ * |##########|*' | |
+ * 280K E=1|##########|*'E=1 | |
+ * |##########|*+....|.+
+ * |##########|/ |/
+ * (-1,-1,-1) +----------+------+
+ * (0,-1,-1)
+ *
+ * lambda = 1.15 W/(m.K)
+ * rho = 1000 kg.m^-3
+ * cp = 800 J/(kg.K)
+ * emissivity = 1
+ *
+ * Basic Tref = 300 K
+ * probe = 0.05 0 0 m
+ * (power = 1000 W.m^-3) */
+
+enum interface_type {
+ ADIABATIC,
+ SOLID_FLUID_mX,
+ SOLID_FLUID_pX,
+ BOUNDARY_pX,
+ INTERFACES_COUNT__
+};
+
+/*******************************************************************************
+ * Geometry
+ ******************************************************************************/
+struct geometry {
+ const double* positions;
+ const size_t* indices;
+ struct sdis_interface** interfaces;
+};
+
+static const double vertices_2d[6/*#vertices*/*2/*#coords par vertex*/] = {
+ 0.1, -1.0,
+ 0.0, -1.0,
+ 0.0, 1.0,
+ 0.1, 1.0,
+ 1.1, -1.0,
+ 1.1, 1.0
+};
+static const size_t nvertices_2d = sizeof(vertices_2d) / (sizeof(double)*2);
+
+static const size_t indices_2d[7/*#segments*/*2/*#indices per segment*/] = {
+ 0, 1, /* Solid -Y */
+ 1, 2, /* Solid -X */
+ 2, 3, /* Solid +Y */
+ 3, 0, /* Solid +X */
+
+ 4, 0, /* Right fluid -Y */
+ 3, 5, /* Right fluid +Y */
+ 5, 4 /* Right fluid +X */
+};
+static const size_t nprimitives_2d = sizeof(indices_2d) / (sizeof(size_t)*2);
+
+static const double vertices_3d[12/*#vertices*/*3/*#coords per vertex*/] = {
+ 0.0,-1.0,-1.0,
+ 0.1,-1.0,-1.0,
+ 0.0, 1.0,-1.0,
+ 0.1, 1.0,-1.0,
+ 0.0,-1.0, 1.0,
+ 0.1,-1.0, 1.0,
+ 0.0, 1.0, 1.0,
+ 0.1, 1.0, 1.0,
+ 1.1,-1.0,-1.0,
+ 1.1, 1.0,-1.0,
+ 1.1,-1.0, 1.0,
+ 1.1, 1.0, 1.0
+};
+static const size_t nvertices_3d = sizeof(vertices_3d) / (sizeof(double)*3);
+
+static const size_t indices_3d[22/*#triangles*/*3/*#indices per triangle*/] = {
+ 0, 2, 1, 1, 2, 3, /* Solid -Z */
+ 0, 4, 2, 2, 4, 6, /* Solid -X */
+ 4, 5, 6, 6, 5, 7, /* Solid +Z */
+ 3, 7, 1, 1, 7, 5, /* Solid +X */
+ 2, 6, 3, 3, 6, 7, /* Solid +Y */
+ 0, 1, 4, 4, 1, 5, /* Solid -Y */
+
+ 1, 3, 8, 8, 3, 9, /* Right fluid -Z */
+ 5, 10, 7, 7, 10, 11, /* Right fluid +Z */
+ 9, 11, 8, 8, 11, 10, /* Right fluid +X */
+ 3, 7, 9, 9, 7, 11, /* Right fluid +Y */
+ 1, 8, 5, 5, 8, 10 /* Right fluid -Y */
+};
+static const size_t nprimitives_3d = sizeof(indices_3d) / (sizeof(size_t)*3);
+
+static void
+get_indices_2d(const size_t iseg, size_t ids[2], void* ctx)
+{
+ struct geometry* geom = ctx;
+ CHK(ctx != NULL);
+ ids[0] = geom->indices[iseg*2+0];
+ ids[1] = geom->indices[iseg*2+1];
+}
+
+static void
+get_indices_3d(const size_t itri, size_t ids[3], void* ctx)
+{
+ struct geometry* geom = ctx;
+ CHK(ctx != NULL);
+ ids[0] = geom->indices[itri*3+0];
+ ids[1] = geom->indices[itri*3+1];
+ ids[2] = geom->indices[itri*3+2];
+}
+
+static void
+get_position_2d(const size_t ivert, double pos[2], void* ctx)
+{
+ struct geometry* geom = ctx;
+ CHK(ctx != NULL);
+ pos[0] = geom->positions[ivert*2+0];
+ pos[1] = geom->positions[ivert*2+1];
+}
+
+static void
+get_position_3d(const size_t ivert, double pos[3], void* ctx)
+{
+ struct geometry* geom = ctx;
+ CHK(ctx != NULL);
+ pos[0] = geom->positions[ivert*3+0];
+ pos[1] = geom->positions[ivert*3+1];
+ pos[2] = geom->positions[ivert*3+2];
+}
+
+static void
+get_interface(const size_t iprim, struct sdis_interface** bound, void* ctx)
+{
+ struct geometry* geom = ctx;
+ CHK(ctx != NULL);
+ *bound = geom->interfaces[iprim];
+}
+
+/*******************************************************************************
+ * media
+ ******************************************************************************/
+struct solid {
+ double lambda;
+ double rho;
+ double cp;
+ double volumic_power;
+};
+
+static double
+solid_get_calorific_capacity
+ (const struct sdis_rwalk_vertex* vtx, struct sdis_data* data)
+{
+ const struct solid* solid = sdis_data_cget(data);
+ CHK(vtx && solid);
+ return solid->cp;
+}
+
+static double
+solid_get_thermal_conductivity
+ (const struct sdis_rwalk_vertex* vtx, struct sdis_data* data)
+{
+ const struct solid* solid = sdis_data_cget(data);
+ CHK(vtx && solid);
+ return solid->lambda;
+}
+
+static double
+solid_get_volumic_mass
+ (const struct sdis_rwalk_vertex* vtx, struct sdis_data* data)
+{
+ const struct solid* solid = sdis_data_cget(data);
+ CHK(vtx && solid);
+ return solid->rho;
+}
+
+static double
+solid_get_delta
+ (const struct sdis_rwalk_vertex* vtx, struct sdis_data* data)
+{
+ CHK(vtx && data);
+ return 0.005;
+}
+
+static double
+solid_get_temperature
+ (const struct sdis_rwalk_vertex* vtx, struct sdis_data* data)
+{
+ CHK(vtx && data);
+ return UNKNOWN_TEMPERATURE;
+}
+
+static double
+solid_get_volumic_power
+ (const struct sdis_rwalk_vertex* vtx, struct sdis_data* data)
+{
+ const struct solid* solid = sdis_data_cget(data);
+ CHK(vtx && solid);
+ return solid->volumic_power;
+}
+
+static void
+create_solid
+ (struct sdis_device* dev,
+ const struct solid* solid_props,
+ struct sdis_medium** solid)
+{
+ struct sdis_data* data = NULL;
+ struct sdis_solid_shader shader = SDIS_SOLID_SHADER_NULL;
+ CHK(dev && solid_props && solid);
+
+ OK(sdis_data_create
+ (dev, sizeof(struct solid), ALIGNOF(struct solid), NULL, &data));
+ memcpy(sdis_data_get(data), solid_props, sizeof(struct solid));
+ 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.volumic_power = solid_get_volumic_power;
+ OK(sdis_solid_create(dev, &shader, data, solid));
+ OK(sdis_data_ref_put(data));
+}
+
+static void
+create_fluid(struct sdis_device* dev, struct sdis_medium** fluid)
+{
+ struct sdis_fluid_shader shader = DUMMY_FLUID_SHADER;
+ OK(sdis_fluid_create(dev, &shader, NULL, fluid));
+}
+
+/*******************************************************************************
+ * Interface
+ ******************************************************************************/
+struct interf {
+ double temperature;
+ double h;
+ double emissivity;
+ double specular_fraction;
+ double Tref;
+};
+
+static double
+interface_get_temperature
+ (const struct sdis_interface_fragment* frag, struct sdis_data* data)
+{
+ const struct interf* interf = sdis_data_cget(data);
+ CHK(frag && interf);
+ return interf->temperature;
+}
+
+static double
+interface_get_convection_coef
+ (const struct sdis_interface_fragment* frag, struct sdis_data* data)
+{
+ const struct interf* interf = sdis_data_cget(data);
+ CHK(frag && interf);
+ return interf->h;
+}
+
+static double
+interface_get_emissivity
+ (const struct sdis_interface_fragment* frag, struct sdis_data* data)
+{
+ const struct interf* interf = sdis_data_cget(data);
+ CHK(frag && interf);
+ return interf->emissivity;
+}
+
+static double
+interface_get_specular_fraction
+ (const struct sdis_interface_fragment* frag, struct sdis_data* data)
+{
+ const struct interf* interf = sdis_data_cget(data);
+ CHK(frag && interf);
+ return interf->specular_fraction;
+}
+
+static double
+interface_get_Tref
+ (const struct sdis_interface_fragment* frag, struct sdis_data* data)
+{
+ const struct interf* interf = sdis_data_cget(data);
+ CHK(frag && interf);
+ return interf->Tref;
+}
+
+static void
+create_interface
+ (struct sdis_device* dev,
+ struct sdis_medium* front,
+ struct sdis_medium* back,
+ const struct interf* interf,
+ struct sdis_interface** out_interf)
+{
+ struct sdis_interface_shader shader = SDIS_INTERFACE_SHADER_NULL;
+ struct sdis_data* data = NULL;
+
+ CHK(interf != NULL);
+
+ shader.front.temperature = interface_get_temperature;
+ shader.back.temperature = interface_get_temperature;
+ if(sdis_medium_get_type(front) != sdis_medium_get_type(back)) {
+ shader.convection_coef = interface_get_convection_coef;
+ }
+ if(sdis_medium_get_type(front) == SDIS_FLUID) {
+ shader.front.emissivity = interface_get_emissivity;
+ shader.front.specular_fraction = interface_get_specular_fraction;
+ shader.front.reference_temperature = interface_get_Tref;
+ }
+ if(sdis_medium_get_type(back) == SDIS_FLUID) {
+ shader.back.emissivity = interface_get_emissivity;
+ shader.back.specular_fraction = interface_get_specular_fraction;
+ shader.back.reference_temperature = interface_get_Tref;
+ }
+ shader.convection_coef_upper_bound = MMAX(0, interf->h);
+
+ OK(sdis_data_create
+ (dev, sizeof(struct interf), ALIGNOF(struct interf), NULL, &data));
+ memcpy(sdis_data_get(data), interf, sizeof(*interf));
+
+ OK(sdis_interface_create(dev, front, back, &shader, data, out_interf));
+ OK(sdis_data_ref_put(data));
+}
+
+/*******************************************************************************
+ * Helper functions
+ ******************************************************************************/
+struct reference_result {
+ double T; /* Temperature at the center of the solid [K] */
+ double T1; /* Temperature on the left boundary of the solid [K] */
+ double T2; /* Temperature on the right boundary of the solid [K] */
+};
+static const struct reference_result REFERENCE_RESULT_NULL = {0,0,0};
+
+static void
+test_picard
+ (struct sdis_scene* scn,
+ const size_t picard_order,
+ const struct reference_result* ref)
+{
+ struct sdis_solve_probe_args probe_args = SDIS_SOLVE_PROBE_ARGS_DEFAULT;
+ struct sdis_solve_boundary_args bound_args = SDIS_SOLVE_BOUNDARY_ARGS_DEFAULT;
+ struct sdis_mc mc = SDIS_MC_NULL;
+ struct sdis_estimator* estimator = NULL;
+ enum sdis_scene_dimension dim;
+ size_t prims[2];
+ enum sdis_side sides[2];
+ CHK(scn && ref && picard_order >= 1);
+
+ OK(sdis_scene_get_dimension(scn, &dim));
+ switch(dim) {
+ case SDIS_SCENE_2D: printf(">>> 2D\n"); break;
+ case SDIS_SCENE_3D: printf(">>> 3D\n"); break;
+ default: FATAL("Unreachable code.\n"); break;
+ }
+
+ probe_args.nrealisations = N;
+ probe_args.position[0] = 0.05;
+ probe_args.position[1] = 0;
+ probe_args.position[2] = 0;
+ probe_args.picard_order = picard_order;
+ OK(sdis_solve_probe(scn, &probe_args, &estimator));
+ OK(sdis_estimator_get_temperature(estimator, &mc));
+ printf("Temperature at `%g %g %g' = %g ~ %g +/- %g\n",
+ SPLIT3(probe_args.position), ref->T, mc.E, mc.SE);
+ CHK(eq_eps(ref->T, mc.E, mc.SE*3));
+ OK(sdis_estimator_ref_put(estimator));
+
+ switch(dim) {
+ case SDIS_SCENE_2D:
+ prims[0] = 1; sides[0] = SDIS_BACK;
+ bound_args.nprimitives = 1;
+ break;
+ case SDIS_SCENE_3D:
+ prims[0] = 2; sides[0] = SDIS_BACK;
+ prims[1] = 3; sides[1] = SDIS_BACK;
+ bound_args.nprimitives = 2;
+ break;
+ default: FATAL("Unreachable code.\n"); break;
+ }
+ bound_args.nrealisations = N;
+ bound_args.primitives = prims;
+ bound_args.sides = sides;
+ bound_args.picard_order = picard_order;
+ OK(sdis_solve_boundary(scn, &bound_args, &estimator));
+ OK(sdis_estimator_get_temperature(estimator, &mc));
+ printf("T1 = %g ~ %g +/- %g\n", ref->T1, mc.E, mc.SE);
+ CHK(eq_eps(ref->T1, mc.E, mc.SE*3));
+ OK(sdis_estimator_ref_put(estimator));
+
+ switch(dim) {
+ case SDIS_SCENE_2D:
+ prims[0] = 3; sides[0] = SDIS_BACK;
+ bound_args.nprimitives = 1;
+ break;
+ case SDIS_SCENE_3D:
+ prims[0] = 6; sides[0] = SDIS_BACK;
+ prims[1] = 7; sides[1] = SDIS_BACK;
+ bound_args.nprimitives = 2;
+ break;
+ default: FATAL("Unreachable code.\n"); break;
+ }
+ bound_args.nrealisations = N;
+ bound_args.primitives = prims;
+ bound_args.sides = sides;
+ bound_args.picard_order = picard_order;
+ OK(sdis_solve_boundary(scn, &bound_args, &estimator));
+ OK(sdis_estimator_get_temperature(estimator, &mc));
+ printf("T2 = %g ~ %g +/- %g\n", ref->T2, mc.E, mc.SE);
+ CHK(eq_eps(ref->T2, mc.E, mc.SE*3));
+ OK(sdis_estimator_ref_put(estimator));
+}
+
+static void
+register_heat_paths(struct sdis_scene* scn, const size_t picard_order, FILE* stream)
+{
+ struct sdis_solve_probe_args probe_args = SDIS_SOLVE_PROBE_ARGS_DEFAULT;
+ struct sdis_estimator* estimator = NULL;
+ CHK(scn && picard_order >= 1 && stream);
+
+
+ probe_args.nrealisations = 10;
+ probe_args.position[0] = 0.05;
+ probe_args.position[1] = 0;
+ probe_args.position[2] = 0;
+ probe_args.picard_order = picard_order;
+ probe_args.register_paths = SDIS_HEAT_PATH_ALL;
+ printf("Register %lu heat paths.\n", probe_args.nrealisations);
+ OK(sdis_solve_probe(scn, &probe_args, &estimator));
+ dump_heat_paths(stream, estimator);
+ OK(sdis_estimator_ref_put(estimator));
+}
+
+static void
+create_scene_3d
+ (struct sdis_device* dev,
+ struct sdis_interface* interfaces[INTERFACES_COUNT__],
+ struct sdis_scene** scn)
+{
+ struct geometry geom;
+ struct sdis_interface* prim_interfaces[32];
+ struct sdis_scene_create_args scn_args = SDIS_SCENE_CREATE_ARGS_DEFAULT;
+
+ CHK(dev && interfaces && scn);
+
+ /* Setup the per primitive interface of the solid medium */
+ prim_interfaces[0] = prim_interfaces[1] = interfaces[ADIABATIC];
+ prim_interfaces[2] = prim_interfaces[3] = interfaces[SOLID_FLUID_mX];
+ prim_interfaces[4] = prim_interfaces[5] = interfaces[ADIABATIC];
+ prim_interfaces[6] = prim_interfaces[7] = interfaces[SOLID_FLUID_pX];
+ prim_interfaces[8] = prim_interfaces[9] = interfaces[ADIABATIC];
+ prim_interfaces[10] = prim_interfaces[11] = interfaces[ADIABATIC];
+
+ /* Setup the per primitive interface for the right fluid */
+ prim_interfaces[12] = prim_interfaces[13] = interfaces[BOUNDARY_pX];
+ prim_interfaces[14] = prim_interfaces[15] = interfaces[BOUNDARY_pX];
+ prim_interfaces[16] = prim_interfaces[17] = interfaces[BOUNDARY_pX];
+ prim_interfaces[18] = prim_interfaces[19] = interfaces[BOUNDARY_pX];
+ prim_interfaces[20] = prim_interfaces[21] = interfaces[BOUNDARY_pX];
+
+ /* Create the scene */
+ geom.positions = vertices_3d;
+ geom.indices = indices_3d;
+ geom.interfaces = prim_interfaces;
+ scn_args.get_indices = get_indices_3d;
+ scn_args.get_interface = get_interface;
+ scn_args.get_position = get_position_3d;
+ scn_args.nprimitives = nprimitives_3d;
+ scn_args.nvertices = nvertices_3d;
+ scn_args.t_range[0] = 280;
+ scn_args.t_range[1] = 350;
+ scn_args.context = &geom;
+ OK(sdis_scene_create(dev, &scn_args, scn));
+}
+
+static void
+create_scene_2d
+ (struct sdis_device* dev,
+ struct sdis_interface* interfaces[INTERFACES_COUNT__],
+ struct sdis_scene** scn)
+{
+ struct geometry geom;
+ struct sdis_interface* prim_interfaces[10/*#segment*/];
+ struct sdis_scene_create_args scn_args = SDIS_SCENE_CREATE_ARGS_DEFAULT;
+
+ CHK(dev && interfaces && scn);
+
+ /* Setup the per primitive interface of the solid medium */
+ prim_interfaces[0] = interfaces[ADIABATIC];
+ prim_interfaces[1] = interfaces[SOLID_FLUID_mX];
+ prim_interfaces[2] = interfaces[ADIABATIC];
+ prim_interfaces[3] = interfaces[SOLID_FLUID_pX];
+
+ /* Setup the per primitive interface of the fluid on the right of the medium */
+ prim_interfaces[4] = interfaces[BOUNDARY_pX];
+ prim_interfaces[5] = interfaces[BOUNDARY_pX];
+ prim_interfaces[6] = interfaces[BOUNDARY_pX];
+
+ /* Create the scene */
+ geom.positions = vertices_2d;
+ geom.indices = indices_2d;
+ geom.interfaces = prim_interfaces;
+ scn_args.get_indices = get_indices_2d;
+ scn_args.get_interface = get_interface;
+ scn_args.get_position = get_position_2d;
+ scn_args.nprimitives = nprimitives_2d;
+ scn_args.nvertices = nvertices_2d;
+ scn_args.t_range[0] = 280;
+ scn_args.t_range[1] = 350;
+ scn_args.context = &geom;
+ OK(sdis_scene_2d_create(dev, &scn_args, scn));
+}
+
+/*******************************************************************************
+ * Test
+ ******************************************************************************/
+int
+main(int argc, char** argv)
+{
+ FILE* stream = NULL;
+
+ struct sdis_device* dev = NULL;
+ struct sdis_scene* scn_2d = NULL;
+ struct sdis_scene* scn_3d = NULL;
+ struct sdis_medium* solid = NULL;
+ struct sdis_medium* fluid = NULL;
+ struct sdis_medium* dummy = NULL;
+ struct sdis_interface* interfaces[INTERFACES_COUNT__];
+ struct sdis_ambient_radiative_temperature amb_rad_temp;
+
+ struct solid solid_props;
+ struct solid* psolid_props;
+ struct reference_result ref = REFERENCE_RESULT_NULL;
+ struct interf interf_props;
+ struct interf* pinterf_props[INTERFACES_COUNT__];
+
+ double t_range[2];
+
+ size_t i;
+ (void)argc, (void)argv;
+
+ OK(sdis_device_create(&SDIS_DEVICE_CREATE_ARGS_DEFAULT, &dev));
+
+ /* Solid medium */
+ solid_props.lambda = 1.15;
+ solid_props.rho = 1000;
+ solid_props.cp = 800;
+ solid_props.volumic_power = SDIS_VOLUMIC_POWER_NONE;
+ create_solid(dev, &solid_props, &solid);
+
+ /* Dummy solid medium */
+ solid_props.lambda = 0;
+ solid_props.rho = 1000;
+ solid_props.cp = 800;
+ solid_props.volumic_power = SDIS_VOLUMIC_POWER_NONE;
+ create_solid(dev, &solid_props, &dummy);
+
+ /* Fluid medium */
+ create_fluid(dev, &fluid);
+
+ /* Create the adiabatic interface for the solid */
+ interf_props.temperature = UNKNOWN_TEMPERATURE;
+ interf_props.h = -1;
+ interf_props.emissivity = -1;
+ interf_props.specular_fraction = -1;
+ interf_props.Tref = UNKNOWN_TEMPERATURE;
+ create_interface(dev, solid, dummy, &interf_props, interfaces+ADIABATIC);
+
+ /* Create the interface between the solid and the fluid */
+ interf_props.temperature = UNKNOWN_TEMPERATURE;
+ interf_props.h = 0;
+ interf_props.emissivity = 1;
+ interf_props.specular_fraction = 0;
+ interf_props.Tref = 280;
+ create_interface(dev, solid, fluid, &interf_props, interfaces+SOLID_FLUID_mX);
+ interf_props.Tref = 350;
+ create_interface(dev, solid, fluid, &interf_props, interfaces+SOLID_FLUID_pX);
+
+ /* Create the interface for the fluid on the right */
+ interf_props.temperature = 350;
+ interf_props.h = -1;
+ interf_props.emissivity = 1;
+ interf_props.specular_fraction = -1;
+ interf_props.Tref = 350;
+ create_interface(dev, fluid, dummy, &interf_props, interfaces+BOUNDARY_pX);
+
+ /* Fetch pointers toward the solid and the interfaces */
+ psolid_props = sdis_data_get(sdis_medium_get_data(solid));
+ FOR_EACH(i, 0, INTERFACES_COUNT__) {
+ pinterf_props[i] = sdis_data_get(sdis_interface_get_data(interfaces[i]));
+ }
+
+ create_scene_2d(dev, interfaces, &scn_2d);
+ create_scene_3d(dev, interfaces, &scn_3d);
+
+ CHK((stream = tmpfile()) != NULL);
+
+ /* Test picard1 with a constant Tref <=> regular linearisation */
+ printf("Test Picard1 with a constant Tref of 300 K\n");
+ ref.T = 314.99999999999989;
+ ref.T1 = 307.64122364709766;
+ ref.T2 = 322.35877635290217;
+ pinterf_props[SOLID_FLUID_mX]->Tref = 300;
+ pinterf_props[SOLID_FLUID_pX]->Tref = 300;
+ pinterf_props[BOUNDARY_pX]->Tref = 300;
+ amb_rad_temp.temperature = 280;
+ amb_rad_temp.reference = 300;
+ OK(sdis_scene_set_ambient_radiative_temperature(scn_2d, &amb_rad_temp));
+ OK(sdis_scene_set_ambient_radiative_temperature(scn_3d, &amb_rad_temp));
+ test_picard(scn_2d, 1/*Picard order*/, &ref);
+ test_picard(scn_3d, 1/*Picard order*/, &ref);
+ printf("\n");
+
+ /* Test picard1 using T4 as a reference */
+ printf("Test Picard1 using T4 as a reference\n");
+ ref.T = 320.37126474482994;
+ ref.T1 = 312.12650299072266;
+ ref.T2 = 328.61602649893723;
+ pinterf_props[SOLID_FLUID_mX]->Tref = ref.T1;
+ pinterf_props[SOLID_FLUID_pX]->Tref = ref.T2;
+ pinterf_props[BOUNDARY_pX]->Tref = 350;
+ amb_rad_temp.temperature = 280;
+ amb_rad_temp.reference = 280;
+ OK(sdis_scene_set_ambient_radiative_temperature(scn_2d, &amb_rad_temp));
+ OK(sdis_scene_set_ambient_radiative_temperature(scn_3d, &amb_rad_temp));
+ test_picard(scn_2d, 1/*Picard order*/, &ref);
+ test_picard(scn_3d, 1/*Picard order*/, &ref);
+ printf("\n");
+
+ /* Test picard2 */
+ printf("Test Picard2 with a constant Tref of 300K\n");
+ ref.T = 320.37126474482994;
+ ref.T1 = 312.12650299072266;
+ ref.T2 = 328.61602649893723;
+ pinterf_props[SOLID_FLUID_mX]->Tref = 300;
+ pinterf_props[SOLID_FLUID_pX]->Tref = 300;
+ pinterf_props[BOUNDARY_pX]->Tref = 300;
+ amb_rad_temp.temperature = 280;
+ amb_rad_temp.reference = 300;
+ OK(sdis_scene_set_ambient_radiative_temperature(scn_2d, &amb_rad_temp));
+ OK(sdis_scene_set_ambient_radiative_temperature(scn_3d, &amb_rad_temp));
+ test_picard(scn_2d, 2/*Picard order*/, &ref);
+ test_picard(scn_3d, 2/*Picard order*/, &ref);
+ printf("\n");
+
+ t_range[0] = 200;
+ t_range[1] = 500;
+
+ OK(sdis_scene_set_temperature_range(scn_2d, t_range));
+ OK(sdis_scene_set_temperature_range(scn_3d, t_range));
+
+ /* Test picard3 */
+ printf("Test Picard3 with a delta T of 300K\n");
+ ref.T = 416.4023;
+ ref.T1 = 372.7557;
+ ref.T2 = 460.0489;
+ pinterf_props[BOUNDARY_pX]->temperature = t_range[1];
+ pinterf_props[SOLID_FLUID_mX]->Tref = 350;
+ pinterf_props[SOLID_FLUID_pX]->Tref = 450;
+ pinterf_props[BOUNDARY_pX]->Tref = pinterf_props[BOUNDARY_pX]->temperature;
+ amb_rad_temp.temperature = t_range[0];
+ amb_rad_temp.reference = t_range[0];
+ OK(sdis_scene_set_ambient_radiative_temperature(scn_2d, &amb_rad_temp));
+ OK(sdis_scene_set_ambient_radiative_temperature(scn_3d, &amb_rad_temp));
+ test_picard(scn_2d, 3/*Picard order*/, &ref);
+ test_picard(scn_3d, 3/*Picard order*/, &ref);
+ register_heat_paths(scn_2d, 3/*Picard order*/, stream);
+ register_heat_paths(scn_3d, 3/*Picard order*/, stream);
+ printf("\n");
+
+ t_range[0] = 280;
+ t_range[1] = 350;
+ OK(sdis_scene_set_temperature_range(scn_2d, t_range));
+ OK(sdis_scene_set_temperature_range(scn_3d, t_range));
+ pinterf_props[BOUNDARY_pX]->temperature = t_range[1];
+
+ /* Add volumic power */
+ psolid_props->volumic_power = 1000;
+
+ /* Test picard1 with a volumic power and constant Tref */
+ printf("Test Picard1 with a volumic power of 1000 W/m^3 and a constant Tref "
+ "of 300 K\n");
+ ref.T = 324.25266420769509;
+ ref.T1 = 315.80693133305368;
+ ref.T2 = 330.52448403885825;
+ pinterf_props[SOLID_FLUID_mX]->Tref = 300;
+ pinterf_props[SOLID_FLUID_pX]->Tref = 300;
+ pinterf_props[BOUNDARY_pX]->Tref = 300;
+ amb_rad_temp.temperature = t_range[0];
+ amb_rad_temp.reference = 300;
+ OK(sdis_scene_set_ambient_radiative_temperature(scn_2d, &amb_rad_temp));
+ OK(sdis_scene_set_ambient_radiative_temperature(scn_3d, &amb_rad_temp));
+ test_picard(scn_2d, 1/*Picard order*/, &ref);
+ test_picard(scn_3d, 1/*Picard order*/, &ref);
+ printf("\n");
+
+ /* Test picard1 with a volumic power and T4 a the reference */
+ printf("Test Picard1 with a volumic power of 1000 W/m^3 and T4 as a reference\n");
+ ref.T = 327.95981050850446;
+ ref.T1 = 318.75148773193359;
+ ref.T2 = 334.99422024159708;
+ pinterf_props[SOLID_FLUID_mX]->Tref = ref.T1;
+ pinterf_props[SOLID_FLUID_pX]->Tref = ref.T2;
+ pinterf_props[BOUNDARY_pX]->Tref = 350;
+ amb_rad_temp.temperature = 280;
+ amb_rad_temp.reference = 280;
+ OK(sdis_scene_set_ambient_radiative_temperature(scn_2d, &amb_rad_temp));
+ OK(sdis_scene_set_ambient_radiative_temperature(scn_3d, &amb_rad_temp));
+ test_picard(scn_2d, 1/*Picard order*/, &ref);
+ test_picard(scn_3d, 1/*Picard order*/, &ref);
+ printf("\n");
+
+ /* Release memory */
+ OK(sdis_scene_ref_put(scn_2d));
+ OK(sdis_scene_ref_put(scn_3d));
+ OK(sdis_interface_ref_put(interfaces[ADIABATIC]));
+ OK(sdis_interface_ref_put(interfaces[SOLID_FLUID_mX]));
+ OK(sdis_interface_ref_put(interfaces[SOLID_FLUID_pX]));
+ OK(sdis_interface_ref_put(interfaces[BOUNDARY_pX]));
+ OK(sdis_medium_ref_put(fluid));
+ OK(sdis_medium_ref_put(solid));
+ OK(sdis_medium_ref_put(dummy));
+ OK(sdis_device_ref_put(dev));
+ CHK(fclose(stream) == 0);
+
+ CHK(mem_allocated_size() == 0);
+ return 0;
+}
diff --git a/src/test_sdis_scene.c b/src/test_sdis_scene.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 2016-2021 |Meso|Star> (contact@meso-star.com)
+/* Copyright (C) 2016-2022 |Meso|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
@@ -258,9 +258,12 @@ test_scene_2d(struct sdis_device* dev, struct sdis_interface* interf)
double duplicated_vertices[] = { 0, 0, 0, 0 };
struct sdis_scene* scn = NULL;
struct sdis_scene_create_args scn_args = SDIS_SCENE_CREATE_ARGS_DEFAULT;
+ struct sdis_ambient_radiative_temperature trad =
+ SDIS_AMBIENT_RADIATIVE_TEMPERATURE_NULL;
double lower[2], upper[2];
+ double t_range[2];
double u0, u1, u2, pos[2], pos1[2];
- double dst, fp, t;
+ double dst, fp;
struct context ctx;
struct senc2d_scene* scn2d;
struct senc3d_scene* scn3d;
@@ -353,29 +356,38 @@ test_scene_2d(struct sdis_device* dev, struct sdis_interface* interf)
BA(sdis_scene_get_ambient_radiative_temperature(NULL, NULL));
BA(sdis_scene_get_ambient_radiative_temperature(scn, NULL));
- BA(sdis_scene_get_ambient_radiative_temperature(NULL, &t));
- OK(sdis_scene_get_ambient_radiative_temperature(scn, &t));
- CHK(t == SDIS_SCENE_CREATE_ARGS_DEFAULT.trad);
-
- t = 100;
- BA(sdis_scene_set_ambient_radiative_temperature(NULL, t));
- OK(sdis_scene_set_ambient_radiative_temperature(scn, t));
- OK(sdis_scene_get_ambient_radiative_temperature(scn, &t));
- CHK(t == 100);
-
- BA(sdis_scene_get_reference_temperature(NULL, NULL));
- BA(sdis_scene_get_reference_temperature(scn, NULL));
- BA(sdis_scene_get_reference_temperature(NULL, &t));
- OK(sdis_scene_get_reference_temperature(scn, &t));
- CHK(t == SDIS_SCENE_CREATE_ARGS_DEFAULT.tref);
-
- t = -1;
- BA(sdis_scene_set_reference_temperature(NULL, t));
- BA(sdis_scene_set_reference_temperature(scn, t));
- t = 100;
- OK(sdis_scene_set_reference_temperature(scn, t));
- OK(sdis_scene_get_reference_temperature(scn, &t));
- CHK(t == 100);
+ BA(sdis_scene_get_ambient_radiative_temperature(NULL, &trad));
+ OK(sdis_scene_get_ambient_radiative_temperature(scn, &trad));
+ CHK(trad.temperature == SDIS_SCENE_CREATE_ARGS_DEFAULT.trad.temperature);
+ CHK(trad.reference == SDIS_SCENE_CREATE_ARGS_DEFAULT.trad.reference);
+
+ trad.temperature = 100;
+ trad.reference = 110;
+ BA(sdis_scene_set_ambient_radiative_temperature(NULL, &trad));
+ OK(sdis_scene_set_ambient_radiative_temperature(scn, &trad));
+ trad = SDIS_AMBIENT_RADIATIVE_TEMPERATURE_NULL;
+ OK(sdis_scene_get_ambient_radiative_temperature(scn, &trad));
+ CHK(trad.temperature == 100);
+ CHK(trad.reference == 110);
+
+ BA(sdis_scene_get_temperature_range(NULL, NULL));
+ BA(sdis_scene_get_temperature_range(scn, NULL));
+ BA(sdis_scene_get_temperature_range(NULL, t_range));
+ OK(sdis_scene_get_temperature_range(scn, t_range));
+ CHK(t_range[0] == SDIS_SCENE_CREATE_ARGS_DEFAULT.t_range[0]);
+ CHK(t_range[1] == SDIS_SCENE_CREATE_ARGS_DEFAULT.t_range[1]);
+
+ t_range[0] = 1;
+ t_range[1] = 100;
+
+ BA(sdis_scene_set_temperature_range(NULL, t_range));
+ BA(sdis_scene_set_temperature_range(scn, NULL));
+ OK(sdis_scene_set_temperature_range(scn, t_range));
+ t_range[0] = -1;
+ t_range[1] = -1;
+ OK(sdis_scene_get_temperature_range(scn, t_range));
+ CHK(t_range[0] == 1);
+ CHK(t_range[1] == 100);
BA(sdis_scene_get_boundary_position(NULL, 1, &u0, pos));
BA(sdis_scene_get_boundary_position(scn, 4, &u0, pos));
@@ -456,7 +468,6 @@ test_scene_2d(struct sdis_device* dev, struct sdis_interface* interf)
int
main(int argc, char** argv)
{
- struct mem_allocator allocator;
struct sdis_device* dev = NULL;
struct sdis_medium* solid = NULL;
struct sdis_medium* fluid = NULL;
@@ -468,8 +479,7 @@ main(int argc, char** argv)
interface_shader.convection_coef = DUMMY_INTERFACE_SHADER.convection_coef;
- OK(mem_init_proxy_allocator(&allocator, &mem_default_allocator));
- OK(sdis_device_create(NULL, &allocator, SDIS_NTHREADS_DEFAULT, 1, &dev));
+ OK(sdis_device_create(&SDIS_DEVICE_CREATE_ARGS_DEFAULT, &dev));
OK(sdis_fluid_create(dev, &fluid_shader, NULL, &fluid));
OK(sdis_solid_create(dev, &solid_shader, NULL, &solid));
@@ -485,8 +495,6 @@ main(int argc, char** argv)
OK(sdis_device_ref_put(dev));
OK(sdis_interface_ref_put(interf));
- check_memory_allocator(&allocator);
- mem_shutdown_proxy_allocator(&allocator);
CHK(mem_allocated_size() == 0);
return 0;
}
diff --git a/src/test_sdis_solid_random_walk_robustness.c b/src/test_sdis_solid_random_walk_robustness.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 2016-2021 |Meso|Star> (contact@meso-star.com)
+/* Copyright (C) 2016-2022 |Meso|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
@@ -259,7 +259,6 @@ solid_get_volumetric_power
int
main(int argc, char** argv)
{
- struct mem_allocator allocator;
struct s3dut_super_formula f0 = S3DUT_SUPER_FORMULA_NULL;
struct s3dut_super_formula f1 = S3DUT_SUPER_FORMULA_NULL;
struct s3dut_mesh* msh = NULL;
@@ -284,8 +283,7 @@ main(int argc, char** argv)
double spread;
(void)argc, (void)argv;
- OK(mem_init_proxy_allocator(&allocator, &mem_default_allocator));
- OK(sdis_device_create(NULL, &allocator, SDIS_NTHREADS_DEFAULT, 1, &dev));
+ OK(sdis_device_create(&SDIS_DEVICE_CREATE_ARGS_DEFAULT, &dev));
/* Create the fluid medium */
fluid_shader.temperature = fluid_get_temperature;
@@ -295,7 +293,7 @@ main(int argc, char** argv)
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 = solid_get_delta;
+ solid_shader.delta = solid_get_delta;
solid_shader.temperature = solid_get_temperature;
solid_shader.volumic_power = solid_get_volumetric_power;
@@ -325,7 +323,7 @@ main(int argc, char** argv)
/* Create the solid super shape */
f0.A = 1; f0.B = 1; f0.M = 20; f0.N0 = 1; f0.N1 = 1; f0.N2 = 5;
f1.A = 1; f1.B = 1; f1.M = 7; f1.N0 = 1; f1.N1 = 2; f1.N2 = 5;
- OK(s3dut_create_super_shape(&allocator, &f0, &f1, 1, 128, 64, &msh));
+ OK(s3dut_create_super_shape(NULL, &f0, &f1, 1, 128, 64, &msh));
OK(s3dut_mesh_get_data(msh, &ctx.msh));
compute_aabb(ctx.msh.positions, ctx.msh.nvertices, lower, upper);
@@ -395,8 +393,6 @@ main(int argc, char** argv)
OK(sdis_interface_ref_put(interf));
OK(sdis_scene_ref_put(scn));
- check_memory_allocator(&allocator);
- mem_shutdown_proxy_allocator(&allocator);
CHK(mem_allocated_size() == 0);
return 0;
}
diff --git a/src/test_sdis_solve_boundary.c b/src/test_sdis_solve_boundary.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 2016-2021 |Meso|Star> (contact@meso-star.com)
+/* Copyright (C) 2016-2022 |Meso|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
@@ -173,7 +173,6 @@ int
main(int argc, char** argv)
{
FILE* fp = NULL;
- struct mem_allocator allocator;
struct sdis_data* data = NULL;
struct sdis_device* dev = NULL;
struct sdis_medium* fluid = NULL;
@@ -195,16 +194,17 @@ main(int argc, char** argv)
struct sdis_solve_probe_boundary_args probe_args =
SDIS_SOLVE_PROBE_BOUNDARY_ARGS_DEFAULT;
struct sdis_solve_boundary_args bound_args = SDIS_SOLVE_BOUNDARY_ARGS_DEFAULT;
+ struct ssp_rng* rng = NULL;
struct interf* interf_props = NULL;
struct fluid* fluid_param;
double pos[3];
double ref;
size_t prims[4];
enum sdis_side sides[4];
+ int is_master_process = 0;
(void)argc, (void)argv;
- OK(mem_init_proxy_allocator(&allocator, &mem_default_allocator));
- OK(sdis_device_create(NULL, &allocator, SDIS_NTHREADS_DEFAULT, 1, &dev));
+ create_default_device(&argc, &argv, &is_master_process, &dev);
/* Temporary file used to dump heat paths */
CHK((fp = tmpfile()) != NULL);
@@ -222,7 +222,7 @@ main(int argc, char** argv)
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 = solid_get_delta;
+ solid_shader.delta = solid_get_delta;
solid_shader.temperature = solid_get_temperature;
OK(sdis_solid_create(dev, &solid_shader, NULL, &solid));
@@ -333,12 +333,53 @@ main(int argc, char** argv)
probe_args.time_range[1] = 0;
BA(SOLVE(box_scn, &probe_args, &estimator));
probe_args.time_range[0] = probe_args.time_range[1] = INF;
+ probe_args.picard_order = 0;
+ BA(SOLVE(box_scn, &probe_args, &estimator));
+ probe_args.picard_order = 1;
OK(SOLVE(box_scn, &probe_args, &estimator));
OK(sdis_scene_get_boundary_position
(box_scn, probe_args.iprim, probe_args.uv, pos));
- printf("Boundary temperature of the box at (%g %g %g) = ", SPLIT3(pos));
- check_estimator(estimator, N, ref);
+ if(is_master_process) {
+ printf("Boundary temperature of the box at (%g %g %g) = ", SPLIT3(pos));
+ check_estimator(estimator, N, ref);
+ }
+
+ /* Check RNG type */
+ probe_args.rng_state = NULL;
+ probe_args.rng_type = SSP_RNG_TYPE_NULL;
+ BA(SOLVE(box_scn, &probe_args, &estimator2));
+ probe_args.rng_type =
+ SDIS_SOLVE_PROBE_BOUNDARY_ARGS_DEFAULT.rng_type == SSP_RNG_THREEFRY
+ ? SSP_RNG_MT19937_64 : SSP_RNG_THREEFRY;
+ OK(SOLVE(box_scn, &probe_args, &estimator2));
+ if(is_master_process) {
+ struct sdis_mc T, T2;
+ check_estimator(estimator2, N, ref);
+ OK(sdis_estimator_get_temperature(estimator, &T));
+ OK(sdis_estimator_get_temperature(estimator2, &T2));
+ CHK(T2.E != T.E);
+ OK(sdis_estimator_ref_put(estimator2));
+ }
+
+ /* Check RNG state */
+ OK(ssp_rng_create(NULL, SSP_RNG_THREEFRY, &rng));
+ OK(ssp_rng_discard(rng, 31415926535)); /* Move the RNG state */
+ probe_args.rng_state = rng;
+ probe_args.rng_type = SSP_RNG_TYPE_NULL;
+ OK(SOLVE(box_scn, &probe_args, &estimator2));
+ OK(ssp_rng_ref_put(rng));
+ if(is_master_process) {
+ struct sdis_mc T, T2;
+ check_estimator(estimator2, N, ref);
+ OK(sdis_estimator_get_temperature(estimator, &T));
+ OK(sdis_estimator_get_temperature(estimator2, &T2));
+ CHK(T2.E != T.E);
+ OK(sdis_estimator_ref_put(estimator2));
+ }
+
+ probe_args.rng_state = SDIS_SOLVE_PROBE_BOUNDARY_ARGS_DEFAULT.rng_state;
+ probe_args.rng_type = SDIS_SOLVE_PROBE_BOUNDARY_ARGS_DEFAULT.rng_type;
BA(GREEN(NULL, &probe_args, &green));
BA(GREEN(box_scn, NULL, &green));
@@ -354,21 +395,28 @@ main(int argc, char** argv)
probe_args.side = SDIS_FRONT;
OK(GREEN(box_scn, &probe_args, &green));
- check_green_function(green);
- OK(sdis_green_function_solve(green, &estimator2));
- check_estimator(estimator2, N, ref);
- check_green_serialization(green, box_scn);
+ if(!is_master_process) {
+ CHK(estimator == NULL);
+ CHK(green == NULL);
+ } else {
+ check_green_function(green);
+ OK(sdis_green_function_solve(green, &estimator2));
+ check_estimator(estimator2, N, ref);
+ check_green_serialization(green, box_scn);
- OK(sdis_green_function_ref_put(green));
- OK(sdis_estimator_ref_put(estimator));
- OK(sdis_estimator_ref_put(estimator2));
+ OK(sdis_green_function_ref_put(green));
+ OK(sdis_estimator_ref_put(estimator));
+ OK(sdis_estimator_ref_put(estimator2));
+ }
/* Dump paths */
probe_args.nrealisations = N_dump;
probe_args.register_paths = SDIS_HEAT_PATH_ALL;
OK(SOLVE(box_scn, &probe_args, &estimator));
- dump_heat_paths(fp, estimator);
- OK(sdis_estimator_ref_put(estimator));
+ if(is_master_process) {
+ dump_heat_paths(fp, estimator);
+ OK(sdis_estimator_ref_put(estimator));
+ }
/* The external fluid cannot have an unknown temperature */
fluid_param->temperature = UNKNOWN_TEMPERATURE;
@@ -385,35 +433,39 @@ main(int argc, char** argv)
OK(SOLVE(square_scn, &probe_args, &estimator));
OK(GREEN(square_scn, &probe_args, &green));
- check_green_function(green);
- OK(sdis_green_function_solve(green, &estimator2));
- check_estimator(estimator2, N, ref);
- check_green_serialization(green, square_scn);
+ if(is_master_process) {
+ check_green_function(green);
+ OK(sdis_green_function_solve(green, &estimator2));
+ check_estimator(estimator2, N, ref);
+ check_green_serialization(green, square_scn);
- OK(sdis_estimator_ref_put(estimator));
- OK(sdis_estimator_ref_put(estimator2));
- OK(sdis_green_function_ref_put(green));
+ OK(sdis_estimator_ref_put(estimator));
+ OK(sdis_estimator_ref_put(estimator2));
+ OK(sdis_green_function_ref_put(green));
+ }
/* The external fluid cannot have an unknown temperature */
fluid_param->temperature = UNKNOWN_TEMPERATURE;
BA(SOLVE(square_scn, &probe_args, &estimator));
fluid_param->temperature = Tf;
-
+
/* Right-side temperature at initial time */
probe_args.time_range[0] = 0;
probe_args.time_range[1] = 0;
probe_args.iprim = 6;
OK(SOLVE(box_scn, &probe_args, &estimator));
- check_estimator(estimator, N, Tf);
-
- OK(sdis_estimator_ref_put(estimator));
+ if(is_master_process) {
+ check_estimator(estimator, N, Tf);
+ OK(sdis_estimator_ref_put(estimator));
+ }
probe_args.iprim = 3;
OK(SOLVE(square_scn, &probe_args, &estimator));
- check_estimator(estimator, N, Tf);
-
- OK(sdis_estimator_ref_put(estimator));
+ if(is_master_process) {
+ check_estimator(estimator, N, Tf);
+ OK(sdis_estimator_ref_put(estimator));
+ }
#undef F
#undef SOLVE
@@ -464,11 +516,53 @@ main(int argc, char** argv)
bound_args.time_range[1] = 0;
BA(SOLVE(box_scn, &bound_args, &estimator));
bound_args.time_range[0] = bound_args.time_range[1] = INF;
+ bound_args.picard_order = 0;
+ BA(SOLVE(box_scn, &bound_args, &estimator));
+ bound_args.picard_order = 1;
/* Average temperature on the right side of the box */
OK(SOLVE(box_scn, &bound_args, &estimator));
- printf("Average temperature of the right side of the box = ");
- check_estimator(estimator, N, ref);
+ if(is_master_process) {
+ printf("Average temperature of the right side of the box = ");
+ check_estimator(estimator, N, ref);
+ }
+
+ /* Check RNG type */
+ bound_args.rng_state = NULL;
+ bound_args.rng_type = SSP_RNG_TYPE_NULL;
+ BA(SOLVE(box_scn, &bound_args, &estimator2));
+ bound_args.rng_type =
+ SDIS_SOLVE_BOUNDARY_ARGS_DEFAULT.rng_type == SSP_RNG_THREEFRY
+ ? SSP_RNG_MT19937_64 : SSP_RNG_THREEFRY;
+ OK(SOLVE(box_scn, &bound_args, &estimator2));
+ if(is_master_process) {
+ struct sdis_mc T, T2;
+ check_estimator(estimator2, N, ref);
+ OK(sdis_estimator_get_temperature(estimator, &T));
+ OK(sdis_estimator_get_temperature(estimator2, &T2));
+ CHK(T2.E != T.E);
+ OK(sdis_estimator_ref_put(estimator2));
+ }
+
+ /* Check RNG state */
+ OK(ssp_rng_create(NULL, SSP_RNG_THREEFRY, &rng));
+ OK(ssp_rng_discard(rng, 31415926535)); /* Move the RNG state */
+ bound_args.rng_state = rng;
+ bound_args.rng_type = SSP_RNG_TYPE_NULL;
+ OK(SOLVE(box_scn, &bound_args, &estimator2));
+ OK(ssp_rng_ref_put(rng));
+ if(is_master_process) {
+ struct sdis_mc T, T2;
+ check_estimator(estimator2, N, ref);
+ OK(sdis_estimator_get_temperature(estimator, &T));
+ OK(sdis_estimator_get_temperature(estimator2, &T2));
+ CHK(T2.E != T.E);
+ OK(sdis_estimator_ref_put(estimator2));
+ }
+
+ /* Restore args */
+ bound_args.rng_state = SDIS_SOLVE_BOUNDARY_ARGS_DEFAULT.rng_state;
+ bound_args.rng_type = SDIS_SOLVE_BOUNDARY_ARGS_DEFAULT.rng_type;
BA(GREEN(NULL, &bound_args, &green));
BA(GREEN(box_scn, NULL, &green));
@@ -493,14 +587,19 @@ main(int argc, char** argv)
sides[0] = SDIS_FRONT;
OK(GREEN(box_scn, &bound_args, &green));
- check_green_function(green);
- OK(sdis_green_function_solve(green, &estimator2));
- check_estimator(estimator2, N, ref);
- check_green_serialization(green, box_scn);
-
- OK(sdis_green_function_ref_put(green));
- OK(sdis_estimator_ref_put(estimator));
- OK(sdis_estimator_ref_put(estimator2));
+ if(!is_master_process) {
+ CHK(estimator == NULL);
+ CHK(green == NULL);
+ } else {
+ check_green_function(green);
+ OK(sdis_green_function_solve(green, &estimator2));
+ check_estimator(estimator2, N, ref);
+ check_green_serialization(green, box_scn);
+
+ OK(sdis_green_function_ref_put(green));
+ OK(sdis_estimator_ref_put(estimator));
+ OK(sdis_estimator_ref_put(estimator2));
+ }
/* Dump path */
bound_args.nrealisations = N_dump;
@@ -513,8 +612,10 @@ main(int argc, char** argv)
/* Dump path */
fluid_param->temperature = Tf;
OK(SOLVE(box_scn, &bound_args, &estimator));
- dump_heat_paths(fp, estimator);
- OK(sdis_estimator_ref_put(estimator));
+ if(is_master_process) {
+ dump_heat_paths(fp, estimator);
+ OK(sdis_estimator_ref_put(estimator));
+ }
/* Switch in 2D */
bound_args.nrealisations = N;
@@ -526,25 +627,31 @@ main(int argc, char** argv)
/* Average temperature on the right side of the square */
prims[0] = 3;
OK(SOLVE(square_scn, &bound_args, &estimator));
- printf("Average temperature of the right side of the square = ");
- check_estimator(estimator, N, ref);
+ if(is_master_process) {
+ printf("Average temperature of the right side of the square = ");
+ check_estimator(estimator, N, ref);
+ }
OK(GREEN(square_scn, &bound_args, &green));
- check_green_function(green);
- OK(sdis_green_function_solve(green, &estimator2));
- check_estimator(estimator2, N, ref);
- check_green_serialization(green, square_scn);
+ if(is_master_process) {
+ check_green_function(green);
+ OK(sdis_green_function_solve(green, &estimator2));
+ check_estimator(estimator2, N, ref);
+ check_green_serialization(green, square_scn);
- OK(sdis_green_function_ref_put(green));
- OK(sdis_estimator_ref_put(estimator));
- OK(sdis_estimator_ref_put(estimator2));
+ OK(sdis_green_function_ref_put(green));
+ OK(sdis_estimator_ref_put(estimator));
+ OK(sdis_estimator_ref_put(estimator2));
+ }
/* Dump path */
bound_args.nrealisations = N_dump;
bound_args.register_paths = SDIS_HEAT_PATH_ALL;
OK(SOLVE(square_scn, &bound_args, &estimator));
- dump_heat_paths(fp, estimator);
- OK(sdis_estimator_ref_put(estimator));
+ if(is_master_process) {
+ dump_heat_paths(fp, estimator);
+ OK(sdis_estimator_ref_put(estimator));
+ }
bound_args.register_paths = SDIS_HEAT_PATH_NONE;
bound_args.nrealisations = N;
@@ -559,36 +666,44 @@ main(int argc, char** argv)
bound_args.nprimitives = 4;
OK(SOLVE(box_scn, &bound_args, &estimator));
- printf("Average temperature of the left+right sides of the box = ");
- check_estimator(estimator, N, ref);
+ if(is_master_process) {
+ printf("Average temperature of the left+right sides of the box = ");
+ check_estimator(estimator, N, ref);
+ }
OK(GREEN(box_scn, &bound_args, &green));
- check_green_function(green);
- OK(sdis_green_function_solve(green, &estimator2));
- check_estimator(estimator2, N, ref);
- check_green_serialization(green, box_scn);
+ if(is_master_process) {
+ check_green_function(green);
+ OK(sdis_green_function_solve(green, &estimator2));
+ check_estimator(estimator2, N, ref);
+ check_green_serialization(green, box_scn);
- OK(sdis_green_function_ref_put(green));
- OK(sdis_estimator_ref_put(estimator));
- OK(sdis_estimator_ref_put(estimator2));
+ OK(sdis_green_function_ref_put(green));
+ OK(sdis_estimator_ref_put(estimator));
+ OK(sdis_estimator_ref_put(estimator2));
+ }
/* Average temperature on the left+right sides of the square */
prims[0] = 1;
prims[1] = 3;
bound_args.nprimitives = 2;
OK(SOLVE(square_scn, &bound_args, &estimator));
- printf("Average temperature of the left+right sides of the square = ");
- check_estimator(estimator, N, ref);
+ if(is_master_process) {
+ printf("Average temperature of the left+right sides of the square = ");
+ check_estimator(estimator, N, ref);
+ }
OK(GREEN(square_scn, &bound_args, &green));
- check_green_function(green);
- OK(sdis_green_function_solve(green, &estimator2));
- check_estimator(estimator2, N, ref);
- check_green_serialization(green, square_scn);
+ if(is_master_process) {
+ check_green_function(green);
+ OK(sdis_green_function_solve(green, &estimator2));
+ check_estimator(estimator2, N, ref);
+ check_green_serialization(green, square_scn);
- OK(sdis_green_function_ref_put(green));
- OK(sdis_estimator_ref_put(estimator));
- OK(sdis_estimator_ref_put(estimator2));
+ OK(sdis_green_function_ref_put(green));
+ OK(sdis_estimator_ref_put(estimator));
+ OK(sdis_estimator_ref_put(estimator2));
+ }
/* Right-side temperature at initial time */
bound_args.time_range[0] = 0;
@@ -598,28 +713,28 @@ main(int argc, char** argv)
prims[1] = 7;
bound_args.nprimitives = 2;
OK(SOLVE(box_scn, &bound_args, &estimator));
- check_estimator(estimator, N, Tf);
-
- OK(sdis_estimator_ref_put(estimator));
+ if(is_master_process) {
+ check_estimator(estimator, N, Tf);
+ OK(sdis_estimator_ref_put(estimator));
+ }
prims[0] = 3;
bound_args.nprimitives = 1;
OK(SOLVE(square_scn, &bound_args, &estimator));
- check_estimator(estimator, N, Tf);
-
- OK(sdis_estimator_ref_put(estimator));
+ if(is_master_process) {
+ check_estimator(estimator, N, Tf);
+ OK(sdis_estimator_ref_put(estimator));
+ }
#undef SOLVE
#undef GREEN
OK(sdis_scene_ref_put(box_scn));
OK(sdis_scene_ref_put(square_scn));
- OK(sdis_device_ref_put(dev));
+ free_default_device(dev);
CHK(fclose(fp) == 0);
- check_memory_allocator(&allocator);
- mem_shutdown_proxy_allocator(&allocator);
CHK(mem_allocated_size() == 0);
return 0;
}
diff --git a/src/test_sdis_solve_boundary_flux.c b/src/test_sdis_solve_boundary_flux.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 2016-2021 |Meso|Star> (contact@meso-star.com)
+/* Copyright (C) 2016-2022 |Meso|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
@@ -16,6 +16,7 @@
#include "sdis.h"
#include "test_sdis_utils.h"
+#include <star/ssp.h>
#include <rsys/math.h>
/*
@@ -142,6 +143,7 @@ struct interf {
double temperature;
double emissivity;
double hc;
+ double reference_temperature;
};
static double
@@ -171,6 +173,15 @@ interface_get_convection_coef
return interf->hc;
}
+static double
+interface_get_reference_temperature
+ (const struct sdis_interface_fragment* frag, struct sdis_data* data)
+{
+ const struct interf* interf = sdis_data_cget(data);
+ CHK(frag && data);
+ return interf->reference_temperature;
+}
+
/*******************************************************************************
* Helper function
******************************************************************************/
@@ -218,7 +229,6 @@ check_estimator
int
main(int argc, char** argv)
{
- struct mem_allocator allocator;
struct sdis_data* data = NULL;
struct sdis_device* dev = NULL;
struct sdis_medium* fluid = NULL;
@@ -229,6 +239,7 @@ main(int argc, char** argv)
struct sdis_scene* box_scn = NULL;
struct sdis_scene* square_scn = NULL;
struct sdis_estimator* estimator = NULL;
+ struct sdis_estimator* estimator2 = NULL;
struct sdis_scene_create_args scn_args = SDIS_SCENE_CREATE_ARGS_DEFAULT;
struct sdis_fluid_shader fluid_shader = DUMMY_FLUID_SHADER;
struct sdis_solid_shader solid_shader = DUMMY_SOLID_SHADER;
@@ -241,14 +252,15 @@ main(int argc, char** argv)
SDIS_SOLVE_BOUNDARY_FLUX_ARGS_DEFAULT;
struct interf* interf_props = NULL;
struct fluid* fluid_param;
+ struct ssp_rng* rng = NULL;
enum sdis_estimator_type type;
double pos[3];
double analyticT, analyticCF, analyticRF, analyticTF;
size_t prims[2];
+ int is_master_process;
(void)argc, (void)argv;
- OK(mem_init_proxy_allocator(&allocator, &mem_default_allocator));
- OK(sdis_device_create(NULL, &allocator, SDIS_NTHREADS_DEFAULT, 1, &dev));
+ create_default_device(&argc, &argv, &is_master_process, &dev);
/* Create the fluid medium */
OK(sdis_data_create
@@ -263,7 +275,7 @@ main(int argc, char** argv)
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 = solid_get_delta;
+ solid_shader.delta = solid_get_delta;
solid_shader.temperature = solid_get_temperature;
OK(sdis_solid_create(dev, &solid_shader, NULL, &solid));
@@ -289,7 +301,9 @@ main(int argc, char** argv)
interf_props->hc = H;
interf_props->temperature = Tb;
interf_props->emissivity = EPSILON;
+ interf_props->reference_temperature = Tb;
interf_shader.back.emissivity = interface_get_emissivity;
+ interf_shader.back.reference_temperature = interface_get_reference_temperature;
OK(sdis_interface_create
(dev, solid, fluid, &interf_shader, data, &interf_Tb));
interf_shader.back.emissivity = NULL;
@@ -301,7 +315,9 @@ main(int argc, char** argv)
interf_props->hc = H;
interf_props->temperature = UNKNOWN_TEMPERATURE;
interf_props->emissivity = EPSILON;
+ interf_props->reference_temperature = Tref;
interf_shader.back.emissivity = interface_get_emissivity;
+ interf_shader.back.reference_temperature = interface_get_reference_temperature;
OK(sdis_interface_create
(dev, solid, fluid, &interf_shader, data, &interf_H));
interf_shader.back.emissivity = NULL;
@@ -331,8 +347,10 @@ main(int argc, char** argv)
scn_args.get_position = box_get_position;
scn_args.nprimitives = box_ntriangles;
scn_args.nvertices = box_nvertices;
- scn_args.trad = Trad;
- scn_args.tref = Tref;
+ scn_args.trad.temperature = Trad;
+ scn_args.trad.reference = Trad;
+ scn_args.t_range[0] = MMIN(MMIN(Tf, Trad), Tb);
+ scn_args.t_range[1] = MMAX(MMAX(Tf, Trad), Tb);
scn_args.context = box_interfaces;
OK(sdis_scene_create(dev, &scn_args, &box_scn));
@@ -342,8 +360,10 @@ main(int argc, char** argv)
scn_args.get_position = square_get_position;
scn_args.nprimitives = square_nsegments;
scn_args.nvertices = square_nvertices;
- scn_args.trad = Trad;
- scn_args.tref = Tref;
+ scn_args.trad.temperature = Trad;
+ scn_args.trad.reference = Trad;
+ scn_args.t_range[0] = MMIN(MMIN(Tf, Trad), Tb);
+ scn_args.t_range[1] = MMAX(MMAX(Tf, Trad), Tb);
scn_args.context = square_interfaces;
OK(sdis_scene_2d_create(dev, &scn_args, &square_scn));
@@ -387,25 +407,69 @@ main(int argc, char** argv)
probe_args.time_range[0] = INF;
OK(SOLVE(box_scn, &probe_args, &estimator));
- OK(sdis_estimator_get_type(estimator, &type));
- CHK(type == SDIS_ESTIMATOR_FLUX);
+ if(!is_master_process) {
+ CHK(estimator == NULL);
+ } else {
+ OK(sdis_estimator_get_type(estimator, &type));
+ CHK(type == SDIS_ESTIMATOR_FLUX);
+
+ OK(sdis_scene_get_boundary_position
+ (box_scn, probe_args.iprim, probe_args.uv, pos));
+ printf("Boundary values of the box at (%g %g %g) = ", SPLIT3(pos));
+ check_estimator(estimator, N, analyticT, analyticCF, analyticRF, analyticTF);
+ }
+
+ /* Check the RNG type */
+ probe_args.rng_state = NULL;
+ probe_args.rng_type = SSP_RNG_TYPE_NULL;
+ BA(SOLVE(box_scn, &probe_args, &estimator2));
+ probe_args.rng_type =
+ SDIS_SOLVE_PROBE_BOUNDARY_FLUX_ARGS_DEFAULT.rng_type == SSP_RNG_THREEFRY
+ ? SSP_RNG_MT19937_64 : SSP_RNG_THREEFRY;
+ OK(SOLVE(box_scn, &probe_args, &estimator2));
+ if(is_master_process) {
+ struct sdis_mc T, T2;
+ check_estimator(estimator2, N, analyticT, analyticCF, analyticRF, analyticTF);
+ OK(sdis_estimator_get_temperature(estimator, &T));
+ OK(sdis_estimator_get_temperature(estimator2, &T2));
+ CHK(T2.E != T.E);
+ OK(sdis_estimator_ref_put(estimator2));
+ }
- OK(sdis_scene_get_boundary_position
- (box_scn, probe_args.iprim, probe_args.uv, pos));
- printf("Boundary values of the box at (%g %g %g) = ", SPLIT3(pos));
- check_estimator(estimator, N, analyticT, analyticCF, analyticRF, analyticTF);
- OK(sdis_estimator_ref_put(estimator));
+ /* Check RNG state */
+ OK(ssp_rng_create(NULL, SSP_RNG_THREEFRY, &rng));
+ OK(ssp_rng_discard(rng, 31415926535)); /* Move the RNG state */
+ probe_args.rng_state = rng;
+ probe_args.rng_type = SSP_RNG_TYPE_NULL;
+ OK(SOLVE(box_scn, &probe_args, &estimator2));
+ OK(ssp_rng_ref_put(rng));
+ if(is_master_process) {
+ struct sdis_mc T, T2;
+ check_estimator(estimator2, N, analyticT, analyticCF, analyticRF, analyticTF);
+ OK(sdis_estimator_get_temperature(estimator, &T));
+ OK(sdis_estimator_get_temperature(estimator2, &T2));
+ CHK(T2.E != T.E);
+ OK(sdis_estimator_ref_put(estimator2));
+ }
+
+ if(estimator) OK(sdis_estimator_ref_put(estimator));
+
+ /* Restore arguments */
+ probe_args.rng_state = SDIS_SOLVE_PROBE_BOUNDARY_FLUX_ARGS_DEFAULT.rng_state;
+ probe_args.rng_type = SDIS_SOLVE_PROBE_BOUNDARY_FLUX_ARGS_DEFAULT.rng_type;
probe_args.uv[0] = 0.5;
probe_args.iprim = 4;
BA(SOLVE(square_scn, &probe_args, &estimator));
probe_args.iprim = 3;
OK(SOLVE(square_scn, &probe_args, &estimator));
- OK(sdis_scene_get_boundary_position
- (square_scn, probe_args.iprim, probe_args.uv, pos));
- printf("Boundary values of the square at (%g %g) = ", SPLIT2(pos));
- check_estimator(estimator, N, analyticT, analyticCF, analyticRF, analyticTF);
- OK(sdis_estimator_ref_put(estimator));
+ if(is_master_process) {
+ OK(sdis_scene_get_boundary_position
+ (square_scn, probe_args.iprim, probe_args.uv, pos));
+ printf("Boundary values of the square at (%g %g) = ", SPLIT2(pos));
+ check_estimator(estimator, N, analyticT, analyticCF, analyticRF, analyticTF);
+ OK(sdis_estimator_ref_put(estimator));
+ }
#undef F
#undef SOLVE
@@ -442,10 +506,52 @@ main(int argc, char** argv)
prims[0] = 6;
OK(SOLVE(box_scn, &bound_args, &estimator));
- /* Average temperature on the right side of the box */
- printf("Average values of the right side of the box = ");
- check_estimator(estimator, N, analyticT, analyticCF, analyticRF, analyticTF);
- OK(sdis_estimator_ref_put(estimator));
+ if(!is_master_process) {
+ CHK(estimator == NULL);
+ } else {
+ /* Average temperature on the right side of the box */
+ printf("Average values of the right side of the box = ");
+ check_estimator(estimator, N, analyticT, analyticCF, analyticRF, analyticTF);
+ }
+
+ /* Check the RNG type */
+ bound_args.rng_state = NULL;
+ bound_args.rng_type = SSP_RNG_TYPE_NULL;
+ BA(SOLVE(box_scn, &bound_args, &estimator2));
+ bound_args.rng_type =
+ SDIS_SOLVE_PROBE_BOUNDARY_FLUX_ARGS_DEFAULT.rng_type == SSP_RNG_THREEFRY
+ ? SSP_RNG_MT19937_64 : SSP_RNG_THREEFRY;
+ OK(SOLVE(box_scn, &bound_args, &estimator2));
+ if(is_master_process) {
+ struct sdis_mc T, T2;
+ check_estimator(estimator2, N, analyticT, analyticCF, analyticRF, analyticTF);
+ OK(sdis_estimator_get_temperature(estimator, &T));
+ OK(sdis_estimator_get_temperature(estimator2, &T2));
+ CHK(T2.E != T.E);
+ OK(sdis_estimator_ref_put(estimator2));
+ }
+
+ /* Check RNG state */
+ OK(ssp_rng_create(NULL, SSP_RNG_THREEFRY, &rng));
+ OK(ssp_rng_discard(rng, 31415926535)); /* Move the RNG state */
+ bound_args.rng_state = rng;
+ bound_args.rng_type = SSP_RNG_TYPE_NULL;
+ OK(SOLVE(box_scn, &bound_args, &estimator2));
+ OK(ssp_rng_ref_put(rng));
+ if(is_master_process) {
+ struct sdis_mc T, T2;
+ check_estimator(estimator2, N, analyticT, analyticCF, analyticRF, analyticTF);
+ OK(sdis_estimator_get_temperature(estimator, &T));
+ OK(sdis_estimator_get_temperature(estimator2, &T2));
+ CHK(T2.E != T.E);
+ OK(sdis_estimator_ref_put(estimator2));
+ }
+
+ if(estimator) OK(sdis_estimator_ref_put(estimator));
+
+ /* Restore arguments */
+ bound_args.rng_state = SDIS_SOLVE_BOUNDARY_FLUX_ARGS_DEFAULT.rng_state;
+ bound_args.rng_type = SDIS_SOLVE_BOUNDARY_FLUX_ARGS_DEFAULT.rng_type;
/* Average temperature on the right side of the square */
prims[0] = 4;
@@ -453,9 +559,11 @@ main(int argc, char** argv)
BA(SOLVE(square_scn, &bound_args, &estimator));
prims[0] = 3;
OK(SOLVE(square_scn, &bound_args, &estimator));
- printf("Average values of the right side of the square = ");
- check_estimator(estimator, N, analyticT, analyticCF, analyticRF, analyticTF);
- OK(sdis_estimator_ref_put(estimator));
+ if(is_master_process) {
+ printf("Average values of the right side of the square = ");
+ check_estimator(estimator, N, analyticT, analyticCF, analyticRF, analyticTF);
+ OK(sdis_estimator_ref_put(estimator));
+ }
/* Flux computation on Dirichlet boundaries is not available yet.
* Once available, the expected total flux is the same we expect on the right
@@ -471,10 +579,8 @@ main(int argc, char** argv)
OK(sdis_scene_ref_put(box_scn));
OK(sdis_scene_ref_put(square_scn));
- OK(sdis_device_ref_put(dev));
+ free_default_device(dev);
- check_memory_allocator(&allocator);
- mem_shutdown_proxy_allocator(&allocator);
CHK(mem_allocated_size() == 0);
return 0;
}
diff --git a/src/test_sdis_solve_camera.c b/src/test_sdis_solve_camera.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 2016-2021 |Meso|Star> (contact@meso-star.com)
+/* Copyright (C) 2016-2022 |Meso|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
@@ -16,6 +16,7 @@
#include "sdis.h"
#include "test_sdis_utils.h"
+#include <star/ssp.h>
#include <star/s3dut.h>
#include <rsys/algorithm.h>
@@ -237,8 +238,11 @@ struct interf {
double epsilon;
double specular_fraction;
double temperature;
+ double reference_temperature;
+};
+static const struct interf INTERF_NULL = {
+ 0, 0, 0, UNKOWN_TEMPERATURE, UNKOWN_TEMPERATURE
};
-static const struct interf INTERF_NULL = {0, 0, 0, UNKOWN_TEMPERATURE};
static double
interface_get_convection_coef
@@ -272,6 +276,14 @@ interface_get_temperature
return ((const struct interf*)sdis_data_cget(data))->temperature;
}
+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;
+}
+
/*******************************************************************************
* Helper functions
******************************************************************************/
@@ -299,7 +311,7 @@ create_solid
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 = solid_get_delta;
+ solid_shader.delta = solid_get_delta;
solid_shader.temperature = solid_get_temperature;
/* Create the solid medium */
@@ -372,10 +384,14 @@ create_interface
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;
}
/* Create the interface */
OK(sdis_interface_create
@@ -525,15 +541,16 @@ dump_image(const struct sdis_estimator_buffer* buf)
int
main(int argc, char** argv)
{
- struct mem_allocator allocator;
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;
@@ -542,6 +559,9 @@ main(int argc, char** argv)
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 sdis_ambient_radiative_temperature trad =
+ SDIS_AMBIENT_RADIATIVE_TEMPERATURE_NULL;
+ struct ssp_rng* rng = NULL;
struct ssp_rng* rng_state = NULL;
struct fluid fluid_param = FLUID_NULL;
struct solid solid_param = SOLID_NULL;
@@ -553,10 +573,10 @@ main(int argc, char** argv)
double pos[3];
double tgt[3];
double up[3];
+ int is_master_process;
(void)argc, (void)argv;
- OK(mem_init_proxy_allocator(&allocator, &mem_default_allocator));
- OK(sdis_device_create(NULL, &allocator, SDIS_NTHREADS_DEFAULT, 1, &dev));
+ create_default_device(&argc, &argv, &is_master_process, &dev);
/* Create the fluid0 */
fluid_param.temperature = 350;
@@ -590,17 +610,18 @@ main(int argc, char** argv)
interface_param.epsilon = 1;
interface_param.specular_fraction = 1;
interface_param.temperature = UNKOWN_TEMPERATURE;
+ interface_param.reference_temperature = 300;
create_interface(dev, fluid1, solid, &interface_param, &interf1);
/* Setup the cube geometry */
- OK(s3dut_create_cuboid(&allocator, 2, 2, 2, &msh));
+ 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));
/* Setup the sphere geometry */
- OK(s3dut_create_sphere(&allocator, 0.5, 32, 16, &msh));
+ 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);
@@ -614,8 +635,10 @@ main(int argc, char** argv)
scn_args.get_position = geometry_get_position;
scn_args.nprimitives = ntris;
scn_args.nvertices = npos;
- scn_args.trad = 300;
- scn_args.tref = 300;
+ scn_args.trad.temperature = 300;
+ scn_args.trad.reference = 300;
+ scn_args.t_range[0] = 300;
+ scn_args.t_range[1] = 350;
scn_args.context = &geom;
OK(sdis_scene_create(dev, &scn_args, &scn));
@@ -640,8 +663,8 @@ main(int argc, char** argv)
solve_args.cam = cam;
solve_args.time_range[0] = INF;
solve_args.time_range[0] = INF;
- solve_args.image_resolution[0] = IMG_WIDTH;
- solve_args.image_resolution[1] = IMG_HEIGHT;
+ 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));
@@ -650,9 +673,12 @@ main(int argc, char** argv)
solve_args.cam = NULL;
BA(sdis_solve_camera(scn, &solve_args, &buf));
solve_args.cam = cam;
- OK(sdis_scene_set_ambient_radiative_temperature(scn, -1));
+ OK(sdis_scene_get_ambient_radiative_temperature(scn, &trad));
+ trad.temperature = -1;
+ OK(sdis_scene_set_ambient_radiative_temperature(scn, &trad));
BA(sdis_solve_camera(scn, &solve_args, &buf));
- OK(sdis_scene_set_ambient_radiative_temperature(scn, 300));
+ trad.temperature = 300;
+ OK(sdis_scene_set_ambient_radiative_temperature(scn, &trad));
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;
@@ -664,42 +690,81 @@ main(int argc, char** argv)
/* Launch the simulation */
OK(sdis_solve_camera(scn, &solve_args, &buf));
- 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);
+ 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));
+ }
- 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));
+ /* 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);
+ 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));
+ }
- 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);
+ /* Check the RNG state */
+ OK(ssp_rng_create(NULL, SSP_RNG_THREEFRY, &rng));
+ OK(ssp_rng_discard(rng, 31415926535)); /* 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);
+ 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));
+ }
- /* Write the image */
- dump_image(buf);
- OK(sdis_estimator_buffer_ref_put(buf));
+ /* 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_param = sdis_data_get(sdis_medium_get_data(fluid1));
pfluid_param->temperature = UNKOWN_TEMPERATURE;
@@ -717,11 +782,9 @@ main(int argc, char** argv)
OK(sdis_camera_ref_put(cam));
OK(sdis_interface_ref_put(interf0));
OK(sdis_interface_ref_put(interf1));
- OK(sdis_device_ref_put(dev));
+ free_default_device(dev);
geometry_release(&geom);
- check_memory_allocator(&allocator);
- mem_shutdown_proxy_allocator(&allocator);
CHK(mem_allocated_size() == 0);
return 0;
}
diff --git a/src/test_sdis_solve_medium.c b/src/test_sdis_solve_medium.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 2016-2021 |Meso|Star> (contact@meso-star.com)
+/* Copyright (C) 2016-2022 |Meso|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
@@ -18,6 +18,7 @@
#include <rsys/math.h>
#include <rsys/stretchy_array.h>
+#include <star/ssp.h>
#include <star/s3dut.h>
#include <string.h>
@@ -197,12 +198,12 @@ interface_get_specular_fraction
int
main(int argc, char** argv)
{
- struct mem_allocator allocator;
struct s3dut_super_formula f0 = S3DUT_SUPER_FORMULA_NULL;
struct s3dut_super_formula f1 = S3DUT_SUPER_FORMULA_NULL;
struct s3dut_mesh* msh0 = NULL;
struct s3dut_mesh* msh1 = NULL;
struct sdis_mc T = SDIS_MC_NULL;
+ struct sdis_mc T2 = SDIS_MC_NULL;
struct sdis_mc time = SDIS_MC_NULL;
struct sdis_device* dev = NULL;
struct sdis_medium* solid0 = NULL;
@@ -225,6 +226,7 @@ main(int argc, char** argv)
struct sdis_solid_shader solid_shader = DUMMY_SOLID_SHADER;
struct sdis_interface_shader interface_shader = SDIS_INTERFACE_SHADER_NULL;
struct sdis_solve_medium_args solve_args = SDIS_SOLVE_MEDIUM_ARGS_DEFAULT;
+ struct ssp_rng* rng = NULL;
struct context ctx;
double ref;
double v, v0, v1;
@@ -232,10 +234,10 @@ main(int argc, char** argv)
size_t nfails;
size_t ntris;
size_t nverts;
+ int is_master_process;
(void)argc, (void)argv;
- OK(mem_init_proxy_allocator(&allocator, &mem_default_allocator));
- OK(sdis_device_create(NULL, &allocator, SDIS_NTHREADS_DEFAULT, 1, &dev));
+ create_default_device(&argc, &argv, &is_master_process, &dev);
fluid_shader.temperature = fluid_get_temperature;
@@ -259,7 +261,7 @@ main(int argc, char** argv)
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 = solid_get_delta;
+ solid_shader.delta = solid_get_delta;
solid_shader.temperature = solid_get_temperature;
/* Create the solid0 medium */
@@ -309,13 +311,13 @@ main(int argc, char** argv)
/* Create the mesh0 */
f0.A = 1; f0.B = 1; f0.M = 3; f0.N0 = 1; f0.N1 = 1; f0.N2 = 2;
f1.A = 1; f1.B = 1; f1.M = 10; f1.N0 = 1; f1.N1 = 1; f1.N2 = 3;
- OK(s3dut_create_super_shape(&allocator, &f0, &f1, 1, 64, 32, &msh0));
+ OK(s3dut_create_super_shape(NULL, &f0, &f1, 1, 64, 32, &msh0));
OK(s3dut_mesh_get_data(msh0, &ctx.msh0));
/* Create the mesh1 */
f0.A = 1; f0.B = 1; f0.M = 10; f0.N0 = 1; f0.N1 = 1; f0.N2 = 5;
f1.A = 1; f1.B = 1; f1.M = 1; f1.N0 = 1; f1.N1 = 1; f1.N2 = 1;
- OK(s3dut_create_super_shape(&allocator, &f0, &f1, 1, 64, 32, &msh1));
+ OK(s3dut_create_super_shape(NULL, &f0, &f1, 1, 64, 32, &msh1));
OK(s3dut_mesh_get_data(msh1, &ctx.msh1));
/* Create the scene */
@@ -381,16 +383,20 @@ main(int argc, char** argv)
solve_args.time_range[0] = solve_args.time_range[1] = INF;
OK(sdis_solve_medium(scn, &solve_args, &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));
- printf("Shape0 temperature = "STR(Tf0)" ~ %g +/- %g\n", T.E, T.SE);
- printf("Time per realisation (in usec) = %g +/- %g\n", time.E, time.SE);
- printf("#failures = %lu/%lu\n\n", (unsigned long)nfails, N);
- CHK(eq_eps(T.E, Tf0, T.SE));
- CHK(nreals + nfails == N);
- OK(sdis_estimator_ref_put(estimator));
+ if(!is_master_process) {
+ CHK(estimator == NULL);
+ } else {
+ 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));
+ printf("Shape0 temperature = "STR(Tf0)" ~ %g +/- %g\n", T.E, T.SE);
+ printf("Time per realisation (in usec) = %g +/- %g\n", time.E, time.SE);
+ printf("#failures = %lu/%lu\n\n", (unsigned long)nfails, N);
+ CHK(eq_eps(T.E, Tf0, T.SE));
+ CHK(nreals + nfails == N);
+ OK(sdis_estimator_ref_put(estimator));
+ }
solve_args.medium = solid1;
@@ -401,21 +407,25 @@ main(int argc, char** argv)
BA(sdis_solve_medium(scn, &solve_args, &estimator));
fluid_param->temperature = Tf1;
OK(sdis_solve_medium(scn, &solve_args, &estimator));
- OK(sdis_estimator_ref_put(estimator));
+ if(is_master_process) {
+ OK(sdis_estimator_ref_put(estimator));
+ }
solve_args.nrealisations = N;
solve_args.register_paths = SDIS_HEAT_PATH_NONE;
OK(sdis_solve_medium(scn, &solve_args, &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));
- printf("Shape1 temperature = "STR(Tf1)" ~ %g +/- %g\n", T.E, T.SE);
- printf("Time per realisation (in usec) = %g +/- %g\n", time.E, time.SE);
- printf("#failures = %lu/%lu\n\n", (unsigned long)nfails, N);
- CHK(eq_eps(T.E, Tf1, T.SE));
- CHK(nreals + nfails == N);
- OK(sdis_estimator_ref_put(estimator));
+ if(is_master_process) {
+ 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));
+ printf("Shape1 temperature = "STR(Tf1)" ~ %g +/- %g\n", T.E, T.SE);
+ printf("Time per realisation (in usec) = %g +/- %g\n", time.E, time.SE);
+ printf("#failures = %lu/%lu\n\n", (unsigned long)nfails, N);
+ CHK(eq_eps(T.E, Tf1, T.SE));
+ CHK(nreals + nfails == N);
+ OK(sdis_estimator_ref_put(estimator));
+ }
/* Create a new scene with the same medium in the 2 super shapes */
OK(sdis_scene_ref_put(scn));
@@ -431,15 +441,52 @@ main(int argc, char** argv)
solve_args.medium = solid0;
solve_args.nrealisations = Np;
OK(sdis_solve_medium(scn, &solve_args, &estimator));
- OK(sdis_estimator_get_temperature(estimator, &T));
- OK(sdis_estimator_get_realisation_time(estimator, &time));
- OK(sdis_estimator_get_realisation_count(estimator, &nreals));
- OK(sdis_estimator_get_failure_count(estimator, &nfails));
- ref = Tf0 * v0/v + Tf1 * v1/v;
- printf("Shape0 + Shape1 temperature = %g ~ %g +/- %g\n", ref, T.E, T.SE);
- printf("Time per realisation (in usec) = %g +/- %g\n", time.E, time.SE);
- printf("#failures = %lu/%lu\n", (unsigned long)nfails, Np);
- CHK(eq_eps(T.E, ref, T.SE*3));
+ if(is_master_process) {
+ OK(sdis_estimator_get_temperature(estimator, &T));
+ OK(sdis_estimator_get_realisation_time(estimator, &time));
+ OK(sdis_estimator_get_realisation_count(estimator, &nreals));
+ OK(sdis_estimator_get_failure_count(estimator, &nfails));
+ ref = Tf0 * v0/v + Tf1 * v1/v;
+ printf("Shape0 + Shape1 temperature = %g ~ %g +/- %g\n", ref, T.E, T.SE);
+ printf("Time per realisation (in usec) = %g +/- %g\n", time.E, time.SE);
+ printf("#failures = %lu/%lu\n", (unsigned long)nfails, Np);
+ CHK(eq_eps(T.E, ref, T.SE*3));
+ }
+
+ /* Check RNG type */
+ solve_args.rng_state = NULL;
+ solve_args.rng_type = SSP_RNG_TYPE_NULL;
+ BA(sdis_solve_medium(scn, &solve_args, &estimator2));
+ solve_args.rng_type =
+ SDIS_SOLVE_MEDIUM_ARGS_DEFAULT.rng_type == SSP_RNG_THREEFRY
+ ? SSP_RNG_MT19937_64 : SSP_RNG_THREEFRY;
+ OK(sdis_solve_medium(scn, &solve_args, &estimator2));
+ if(is_master_process) {
+ OK(sdis_estimator_get_temperature(estimator2, &T2));
+ CHK(eq_eps(T2.E, ref, 3*T2.SE));
+ CHK(T2.E != T.E);
+ OK(sdis_estimator_ref_put(estimator2));
+ }
+
+ /* Check RNG state */
+ OK(ssp_rng_create(NULL, SSP_RNG_THREEFRY, &rng));
+ OK(ssp_rng_discard(rng, 31415926535)); /* Move the RNG state */
+ solve_args.rng_state = rng;
+ solve_args.rng_type = SSP_RNG_TYPE_NULL;
+ OK(sdis_solve_medium(scn, &solve_args, &estimator2));
+ OK(ssp_rng_ref_put(rng));
+ if(is_master_process) {
+ OK(sdis_estimator_get_temperature(estimator2, &T2));
+ CHK(eq_eps(T2.E, ref, 3*T2.SE));
+ CHK(T2.E != T.E);
+ OK(sdis_estimator_ref_put(estimator2));
+ }
+
+ /* Restore args */
+ solve_args.rng_state = SDIS_SOLVE_PROBE_ARGS_DEFAULT.rng_state;
+ solve_args.rng_type = SDIS_SOLVE_PROBE_ARGS_DEFAULT.rng_type;
+
+
/* Solve green */
BA(sdis_solve_medium_green_function(NULL, &solve_args, &green));
@@ -453,22 +500,28 @@ main(int argc, char** argv)
solve_args.medium = solid1;
BA(sdis_solve_medium_green_function(scn, &solve_args, &green));
solve_args.medium = solid0;
+ solve_args.picard_order = 0;
+ BA(sdis_solve_medium_green_function(scn, &solve_args, &green));
+ solve_args.picard_order = 1;
OK(sdis_solve_medium_green_function(scn, &solve_args, &green));
- OK(sdis_green_function_solve(green, &estimator2));
- check_green_function(green);
- check_estimator_eq(estimator, estimator2);
- check_green_serialization(green, scn);
+ if(!is_master_process) {
+ CHK(green == NULL);
+ } else {
+ OK(sdis_green_function_solve(green, &estimator2));
+ check_green_function(green);
+ check_estimator_eq(estimator, estimator2);
+ check_green_serialization(green, scn);
- OK(sdis_green_function_ref_put(green));
+ OK(sdis_green_function_ref_put(green));
- OK(sdis_estimator_ref_put(estimator));
- OK(sdis_estimator_ref_put(estimator2));
+ OK(sdis_estimator_ref_put(estimator));
+ OK(sdis_estimator_ref_put(estimator2));
+ }
/* Release */
OK(s3dut_mesh_ref_put(msh0));
OK(s3dut_mesh_ref_put(msh1));
- OK(sdis_device_ref_put(dev));
OK(sdis_medium_ref_put(fluid0));
OK(sdis_medium_ref_put(fluid1));
OK(sdis_medium_ref_put(solid0));
@@ -477,9 +530,8 @@ main(int argc, char** argv)
OK(sdis_interface_ref_put(solid0_fluid1));
OK(sdis_interface_ref_put(solid1_fluid1));
OK(sdis_scene_ref_put(scn));
+ free_default_device(dev);
- check_memory_allocator(&allocator);
- mem_shutdown_proxy_allocator(&allocator);
CHK(mem_allocated_size() == 0);
return 0;
}
diff --git a/src/test_sdis_solve_medium_2d.c b/src/test_sdis_solve_medium_2d.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 2016-2021 |Meso|Star> (contact@meso-star.com)
+/* Copyright (C) 2016-2022 |Meso|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
@@ -186,7 +186,6 @@ interface_get_specular_fraction
int
main(int argc, char** argv)
{
- struct mem_allocator allocator;
struct sdis_mc T = SDIS_MC_NULL;
struct sdis_mc time = SDIS_MC_NULL;
struct sdis_device* dev = NULL;
@@ -219,10 +218,10 @@ main(int argc, char** argv)
size_t nreals;
size_t nfails;
size_t i;
+ int is_master_process;
(void)argc, (void)argv;
- OK(mem_init_proxy_allocator(&allocator, &mem_default_allocator));
- OK(sdis_device_create(NULL, &allocator, SDIS_NTHREADS_DEFAULT, 1, &dev));
+ create_default_device(&argc, &argv, &is_master_process, &dev);
fluid_shader.temperature = fluid_get_temperature;
@@ -246,7 +245,7 @@ main(int argc, char** argv)
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 = solid_get_delta;
+ solid_shader.delta = solid_get_delta;
solid_shader.temperature = solid_get_temperature;
/* Create the solid0 medium */
@@ -347,30 +346,36 @@ main(int argc, char** argv)
/* Estimate the temperature of the square */
solve_args.medium = solid0;
OK(sdis_solve_medium(scn, &solve_args, &estimator));
- OK(sdis_estimator_get_temperature(estimator, &T));
- OK(sdis_estimator_get_realisation_time(estimator, &time));
- OK(sdis_estimator_get_realisation_count(estimator, &nreals));
- OK(sdis_estimator_get_failure_count(estimator, &nfails));
- printf("Square temperature = "STR(Tf0)" ~ %g +/- %g\n", T.E, T.SE);
- printf("Time per realisation (in usec) = %g +/- %g\n", time.E, time.SE);
- printf("#failures = %lu / %lu\n\n", (unsigned long)nfails, N);
- CHK(eq_eps(T.E, Tf0, T.SE));
- CHK(nreals + nfails == N);
- OK(sdis_estimator_ref_put(estimator));
+ if(!is_master_process) {
+ CHK(estimator == NULL);
+ } else {
+ OK(sdis_estimator_get_temperature(estimator, &T));
+ OK(sdis_estimator_get_realisation_time(estimator, &time));
+ OK(sdis_estimator_get_realisation_count(estimator, &nreals));
+ OK(sdis_estimator_get_failure_count(estimator, &nfails));
+ printf("Square temperature = "STR(Tf0)" ~ %g +/- %g\n", T.E, T.SE);
+ printf("Time per realisation (in usec) = %g +/- %g\n", time.E, time.SE);
+ printf("#failures = %lu / %lu\n\n", (unsigned long)nfails, N);
+ CHK(eq_eps(T.E, Tf0, T.SE));
+ CHK(nreals + nfails == N);
+ OK(sdis_estimator_ref_put(estimator));
+ }
/* Estimate the temperature of the disk */
solve_args.medium = solid1;
OK(sdis_solve_medium(scn, &solve_args, &estimator));
- OK(sdis_estimator_get_temperature(estimator, &T));
- OK(sdis_estimator_get_realisation_time(estimator, &time));
- OK(sdis_estimator_get_realisation_count(estimator, &nreals));
- OK(sdis_estimator_get_failure_count(estimator, &nfails));
- printf("Disk temperature = "STR(Tf1)" ~ %g +/- %g\n", T.E, T.SE);
- printf("Time per realisation (in usec) = %g +/- %g\n", time.E, time.SE);
- printf("#failures = %lu / %lu\n\n", (unsigned long)nfails, N);
- CHK(eq_eps(T.E, Tf1, T.SE));
- CHK(nreals + nfails == N);
- OK(sdis_estimator_ref_put(estimator));
+ if(is_master_process) {
+ OK(sdis_estimator_get_temperature(estimator, &T));
+ OK(sdis_estimator_get_realisation_time(estimator, &time));
+ OK(sdis_estimator_get_realisation_count(estimator, &nreals));
+ OK(sdis_estimator_get_failure_count(estimator, &nfails));
+ printf("Disk temperature = "STR(Tf1)" ~ %g +/- %g\n", T.E, T.SE);
+ printf("Time per realisation (in usec) = %g +/- %g\n", time.E, time.SE);
+ printf("#failures = %lu / %lu\n\n", (unsigned long)nfails, N);
+ CHK(eq_eps(T.E, Tf1, T.SE));
+ CHK(nreals + nfails == N);
+ OK(sdis_estimator_ref_put(estimator));
+ }
/* Create a new scene with the same medium for the disk and the square */
OK(sdis_scene_ref_put(scn));
@@ -387,16 +392,18 @@ main(int argc, char** argv)
BA(sdis_solve_medium(scn, &solve_args, &estimator));
solve_args.medium = solid0;
OK(sdis_solve_medium(scn, &solve_args, &estimator));
- OK(sdis_estimator_get_temperature(estimator, &T));
- OK(sdis_estimator_get_realisation_time(estimator, &time));
- OK(sdis_estimator_get_realisation_count(estimator, &nreals));
- OK(sdis_estimator_get_failure_count(estimator, &nfails));
- ref = Tf0 * a0/a + Tf1 * a1/a;
- printf("Square + Disk temperature = %g ~ %g +/- %g\n", ref, T.E, T.SE);
- printf("Time per realisation (in usec) = %g +/- %g\n", time.E, time.SE);
- printf("#failures = %lu / %lu\n", (unsigned long)nfails, Np);
- CHK(eq_eps(T.E, ref, 3*T.SE));
- CHK(nreals + nfails == Np);
+ if(is_master_process) {
+ OK(sdis_estimator_get_temperature(estimator, &T));
+ OK(sdis_estimator_get_realisation_time(estimator, &time));
+ OK(sdis_estimator_get_realisation_count(estimator, &nreals));
+ OK(sdis_estimator_get_failure_count(estimator, &nfails));
+ ref = Tf0 * a0/a + Tf1 * a1/a;
+ printf("Square + Disk temperature = %g ~ %g +/- %g\n", ref, T.E, T.SE);
+ printf("Time per realisation (in usec) = %g +/- %g\n", time.E, time.SE);
+ printf("#failures = %lu / %lu\n", (unsigned long)nfails, Np);
+ CHK(eq_eps(T.E, ref, 3*T.SE));
+ CHK(nreals + nfails == Np);
+ }
/* Solve green */
BA(sdis_solve_medium_green_function(NULL, &solve_args, &green));
@@ -404,18 +411,21 @@ main(int argc, char** argv)
BA(sdis_solve_medium_green_function(scn, &solve_args, NULL));
OK(sdis_solve_medium_green_function(scn, &solve_args, &green));
- OK(sdis_green_function_solve(green, &estimator2));
- check_green_function(green);
- check_estimator_eq(estimator, estimator2);
- check_green_serialization(green, scn);
+ if(!is_master_process) {
+ CHK(green == NULL);
+ } else {
+ OK(sdis_green_function_solve(green, &estimator2));
+ check_green_function(green);
+ check_estimator_eq(estimator, estimator2);
+ check_green_serialization(green, scn);
- OK(sdis_green_function_ref_put(green));
+ OK(sdis_green_function_ref_put(green));
- OK(sdis_estimator_ref_put(estimator));
- OK(sdis_estimator_ref_put(estimator2));
+ OK(sdis_estimator_ref_put(estimator));
+ OK(sdis_estimator_ref_put(estimator2));
+ }
/* Release */
- OK(sdis_device_ref_put(dev));
OK(sdis_medium_ref_put(solid0));
OK(sdis_medium_ref_put(solid1));
OK(sdis_medium_ref_put(fluid0));
@@ -425,11 +435,11 @@ main(int argc, char** argv)
OK(sdis_interface_ref_put(solid1_fluid1));
OK(sdis_scene_ref_put(scn));
+ free_default_device(dev);
+
sa_release(positions);
sa_release(indices);
- check_memory_allocator(&allocator);
- mem_shutdown_proxy_allocator(&allocator);
CHK(mem_allocated_size() == 0);
return 0;
}
diff --git a/src/test_sdis_solve_probe.c b/src/test_sdis_solve_probe.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 2016-2021 |Meso|Star> (contact@meso-star.com)
+/* Copyright (C) 2016-2022 |Meso|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
@@ -141,6 +141,7 @@ struct interf {
double hc;
double epsilon;
double specular_fraction;
+ double reference_temperature;
};
static double
@@ -167,6 +168,14 @@ interface_get_specular_fraction
return ((const struct interf*)sdis_data_cget(data))->specular_fraction;
}
+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;
+}
+
/*******************************************************************************
* Helper functions
******************************************************************************/
@@ -199,10 +208,10 @@ process_heat_path(const struct sdis_heat_path* path, void* context)
CHK(path && context);
- BA(sdis_heat_path_get_vertices_count(NULL, &n));
- BA(sdis_heat_path_get_vertices_count(path, NULL));
- OK(sdis_heat_path_get_vertices_count(path, &n));
- CHK(n != 0);
+ BA(sdis_heat_path_get_line_strips_count(NULL, &n));
+ BA(sdis_heat_path_get_line_strips_count(path, NULL));
+ OK(sdis_heat_path_get_line_strips_count(path, &n));
+ CHK(n == 1);
BA(sdis_heat_path_get_status(NULL, &status));
BA(sdis_heat_path_get_status(path, NULL));
@@ -215,20 +224,28 @@ process_heat_path(const struct sdis_heat_path* path, void* context)
default: FATAL("Unreachable code.\n"); break;
}
- BA(sdis_heat_path_get_vertex(NULL, 0, &vert));
- BA(sdis_heat_path_get_vertex(path, n, &vert));
- BA(sdis_heat_path_get_vertex(path, 0, NULL));
+ BA(sdis_heat_path_line_strip_get_vertices_count(NULL, 0, &n));
+ BA(sdis_heat_path_line_strip_get_vertices_count(path, 1, &n));
+ BA(sdis_heat_path_line_strip_get_vertices_count(path, 0, NULL));
+ OK(sdis_heat_path_line_strip_get_vertices_count(path, 0, &n));
+ CHK(n != 0);
+
+ BA(sdis_heat_path_line_strip_get_vertex(NULL, 0, 0, &vert));
+ BA(sdis_heat_path_line_strip_get_vertex(path, 1, 1, &vert));
+ BA(sdis_heat_path_line_strip_get_vertex(path, 0, n, &vert));
+ BA(sdis_heat_path_line_strip_get_vertex(path, 0, 0, NULL));
FOR_EACH(i, 0, n) {
- OK(sdis_heat_path_get_vertex(path, i, &vert));
+ OK(sdis_heat_path_line_strip_get_vertex(path, 0, i, &vert));
CHK(vert.type == SDIS_HEAT_VERTEX_CONVECTION
|| vert.type == SDIS_HEAT_VERTEX_CONDUCTION
|| vert.type == SDIS_HEAT_VERTEX_RADIATIVE);
}
- BA(sdis_heat_path_for_each_vertex(NULL, dump_vertex_pos, context));
- BA(sdis_heat_path_for_each_vertex(path, NULL, context));
- OK(sdis_heat_path_for_each_vertex(path, dump_vertex_pos, context));
+ BA(sdis_heat_path_line_strip_for_each_vertex(NULL, 0, dump_vertex_pos, context));
+ BA(sdis_heat_path_line_strip_for_each_vertex(path, 1, dump_vertex_pos, context));
+ BA(sdis_heat_path_line_strip_for_each_vertex(path, 0, NULL, context));
+ OK(sdis_heat_path_line_strip_for_each_vertex(path, 0, dump_vertex_pos, context));
FOR_EACH(i, 0, n-1) {
fprintf(ctx->stream, "l %lu %lu\n",
@@ -262,11 +279,14 @@ main(int argc, char** argv)
struct sdis_estimator* estimator3 = NULL;
struct sdis_green_function* green = NULL;
const struct sdis_heat_path* path = NULL;
+ struct sdis_device_create_args dev_args = SDIS_DEVICE_CREATE_ARGS_DEFAULT;
struct sdis_scene_create_args scn_args = SDIS_SCENE_CREATE_ARGS_DEFAULT;
struct sdis_fluid_shader fluid_shader = DUMMY_FLUID_SHADER;
struct sdis_solid_shader solid_shader = DUMMY_SOLID_SHADER;
struct sdis_interface_shader interface_shader = SDIS_INTERFACE_SHADER_NULL;
struct sdis_solve_probe_args solve_args = SDIS_SOLVE_PROBE_ARGS_DEFAULT;
+ struct sdis_ambient_radiative_temperature trad =
+ SDIS_AMBIENT_RADIATIVE_TEMPERATURE_NULL;
struct dump_path_context dump_ctx = DUMP_PATH_CONTEXT_NULL;
struct context ctx;
struct fluid* fluid_param;
@@ -275,6 +295,7 @@ main(int argc, char** argv)
struct ssp_rng* rng_state = NULL;
enum sdis_estimator_type type;
FILE* stream = NULL;
+ double t_range[2];
double ref;
const size_t N = 1000;
const size_t N_dump = 10;
@@ -284,7 +305,8 @@ main(int argc, char** argv)
(void)argc, (void)argv;
OK(mem_init_proxy_allocator(&allocator, &mem_default_allocator));
- OK(sdis_device_create(NULL, &allocator, SDIS_NTHREADS_DEFAULT, 0, &dev));
+ dev_args.allocator = &allocator;
+ OK(sdis_device_create(&dev_args, &dev));
/* Create the fluid medium */
OK(sdis_data_create
@@ -307,7 +329,7 @@ main(int argc, char** argv)
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 = solid_get_delta;
+ solid_shader.delta = solid_get_delta;
solid_shader.temperature = solid_get_temperature;
OK(sdis_solid_create(dev, &solid_shader, data, &solid));
OK(sdis_data_ref_put(data));
@@ -324,6 +346,7 @@ main(int argc, char** argv)
interface_shader.back.temperature = NULL;
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;
OK(sdis_interface_create
(dev, solid, fluid, &interface_shader, data, &interf));
OK(sdis_data_ref_put(data));
@@ -367,6 +390,9 @@ main(int argc, char** argv)
solve_args.time_range[1] = 0;
BA(sdis_solve_probe(scn, &solve_args, &estimator));
solve_args.time_range[0] = solve_args.time_range[1] = INF;
+ solve_args.picard_order = 0;
+ BA(sdis_solve_probe(scn, &solve_args, &estimator));
+ solve_args.picard_order = 1;
OK(sdis_solve_probe(scn, &solve_args, &estimator));
BA(sdis_estimator_get_type(estimator, NULL));
@@ -538,10 +564,14 @@ main(int argc, char** argv)
/* Green and ambient radiative temperature */
solve_args.nrealisations = N;
- OK(sdis_scene_set_ambient_radiative_temperature(scn, 300));
- OK(sdis_scene_set_reference_temperature(scn, 300));
+ trad.temperature = trad.reference = 300;
+ t_range[0] = 300;
+ t_range[1] = 300;
+ OK(sdis_scene_set_ambient_radiative_temperature(scn, &trad));
+ OK(sdis_scene_set_temperature_range(scn, t_range));
interface_param->epsilon = 1;
+ interface_param->reference_temperature = 300;
OK(sdis_solve_probe(scn, &solve_args, &estimator));
OK(sdis_solve_probe_green_function(scn, &solve_args, &green));
@@ -554,7 +584,11 @@ main(int argc, char** argv)
OK(sdis_estimator_ref_put(estimator2));
/* Check same green used at different ambient radiative temperature */
- OK(sdis_scene_set_ambient_radiative_temperature(scn, 600));
+ trad.temperature = 600;
+ t_range[0] = 300;
+ t_range[1] = 600;
+ OK(sdis_scene_set_ambient_radiative_temperature(scn, &trad));
+ OK(sdis_scene_set_temperature_range(scn, t_range));
OK(sdis_solve_probe(scn, &solve_args, &estimator));
OK(sdis_green_function_solve(green, &estimator2));
diff --git a/src/test_sdis_solve_probe2.c b/src/test_sdis_solve_probe2.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 2016-2021 |Meso|Star> (contact@meso-star.com)
+/* Copyright (C) 2016-2022 |Meso|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
@@ -16,8 +16,11 @@
#include "sdis.h"
#include "test_sdis_utils.h"
+#include <star/ssp.h>
#include <rsys/math.h>
+#include <string.h>
+
/*
* The scene is composed of a solid cube whose temperature is unknown. The
* convection coefficient with the surrounding fluid is null. The temperature
@@ -145,8 +148,8 @@ interface_get_temperature
int
main(int argc, char** argv)
{
- struct mem_allocator allocator;
struct sdis_mc T = SDIS_MC_NULL;
+ struct sdis_mc T2 = SDIS_MC_NULL;
struct sdis_mc time = SDIS_MC_NULL;
struct sdis_device* dev = NULL;
struct sdis_data* data = NULL;
@@ -165,16 +168,17 @@ main(int argc, char** argv)
struct sdis_interface_shader interface_shader = DUMMY_INTERFACE_SHADER;
struct sdis_interface* interfaces[12];
struct sdis_solve_probe_args solve_args = SDIS_SOLVE_PROBE_ARGS_DEFAULT;
+ struct ssp_rng* rng = NULL;
struct context ctx;
struct interf* interface_param = NULL;
double ref;
const size_t N = 10000;
size_t nreals;
size_t nfails;
+ int is_master_process;
(void)argc, (void)argv;
- OK(mem_init_proxy_allocator(&allocator, &mem_default_allocator));
- OK(sdis_device_create(NULL, &allocator, SDIS_NTHREADS_DEFAULT, 1, &dev));
+ create_default_device(&argc, &argv, &is_master_process, &dev);
/* Create the fluid medium */
fluid_shader.temperature = temperature_unknown;
@@ -184,7 +188,7 @@ main(int argc, char** argv)
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 = solid_get_delta;
+ solid_shader.delta = solid_get_delta;
solid_shader.temperature = temperature_unknown;
OK(sdis_solid_create(dev, &solid_shader, NULL, &solid));
@@ -253,39 +257,80 @@ main(int argc, char** argv)
solve_args.time_range[1] = INF;
OK(sdis_solve_probe(scn, &solve_args, &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));
- /* Print the estimation results */
ref = 350 * solve_args.position[2] + (1-solve_args.position[2]) * 300;
- printf("Temperature at (%g, %g, %g) = %g ~ %g +/- %g\n",
- SPLIT3(solve_args.position), ref, T.E, T.SE);
- printf("Time per realisation (in usec) = %g +/- %g\n", time.E, time.SE);
- printf("#failures = %lu/%lu\n", (unsigned long)nfails, (unsigned long)N);
-
- /* Check the results */
- CHK(nfails + nreals == N);
- CHK(nfails < N/1000);
- CHK(eq_eps(T.E, ref, 3*T.SE));
+ if(!is_master_process) {
+ CHK(estimator == NULL);
+ } else {
+ 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));
+
+ /* Print the estimation results */
+ printf("Temperature at (%g, %g, %g) = %g ~ %g +/- %g\n",
+ SPLIT3(solve_args.position), ref, T.E, T.SE);
+ printf("Time per realisation (in usec) = %g +/- %g\n", time.E, time.SE);
+ printf("#failures = %lu/%lu\n", (unsigned long)nfails, (unsigned long)N);
+
+ /* Check the results */
+ CHK(nfails + nreals == N);
+ CHK(nfails < N/1000);
+ CHK(eq_eps(T.E, ref, 3*T.SE));
+ }
+
+ /* Check RNG type */
+ solve_args.rng_state = NULL;
+ solve_args.rng_type = SSP_RNG_TYPE_NULL;
+ BA(sdis_solve_probe(scn, &solve_args, &estimator2));
+ solve_args.rng_type =
+ SDIS_SOLVE_PROBE_ARGS_DEFAULT.rng_type == SSP_RNG_THREEFRY
+ ? SSP_RNG_MT19937_64 : SSP_RNG_THREEFRY;
+ OK(sdis_solve_probe(scn, &solve_args, &estimator2));
+ if(is_master_process) {
+ OK(sdis_estimator_get_temperature(estimator2, &T2));
+ CHK(eq_eps(T2.E, ref, 3*T2.SE));
+ CHK(T2.E != T.E);
+ OK(sdis_estimator_ref_put(estimator2));
+ }
+
+ /* Check the RNG state */
+ OK(ssp_rng_create(NULL, SSP_RNG_THREEFRY, &rng));
+ OK(ssp_rng_discard(rng, 31415926535)); /* Move the RNG state */
+ solve_args.rng_state = rng;
+ solve_args.rng_type = SSP_RNG_TYPE_NULL;
+ OK(sdis_solve_probe(scn, &solve_args, &estimator2));
+ OK(ssp_rng_ref_put(rng));
+ if(is_master_process) {
+ OK(sdis_estimator_get_temperature(estimator2, &T2));
+ CHK(eq_eps(T2.E, ref, 3*T2.SE));
+ CHK(T2.E != T.E);
+ OK(sdis_estimator_ref_put(estimator2));
+ }
+
+ /* Restore args */
+ solve_args.rng_state = SDIS_SOLVE_PROBE_ARGS_DEFAULT.rng_state;
+ solve_args.rng_type = SDIS_SOLVE_PROBE_ARGS_DEFAULT.rng_type;
/* Check green */
OK(sdis_solve_probe_green_function(scn, &solve_args, &green));
- OK(sdis_green_function_solve(green, &estimator2));
- check_green_function(green);
- check_estimator_eq(estimator, estimator2);
- check_green_serialization(green, scn);
+ if(!is_master_process) {
+ CHK(green == NULL);
+ } else {
+ OK(sdis_green_function_solve(green, &estimator2));
+ check_green_function(green);
+ check_estimator_eq(estimator, estimator2);
+ check_green_serialization(green, scn);
+ }
/* Release data */
- OK(sdis_estimator_ref_put(estimator));
- OK(sdis_estimator_ref_put(estimator2));
- OK(sdis_green_function_ref_put(green));
+ if(estimator) OK(sdis_estimator_ref_put(estimator));
+ if(estimator2) OK(sdis_estimator_ref_put(estimator2));
+ if(green) OK(sdis_green_function_ref_put(green));
OK(sdis_scene_ref_put(scn));
- OK(sdis_device_ref_put(dev));
+ free_default_device(dev);
- check_memory_allocator(&allocator);
- mem_shutdown_proxy_allocator(&allocator);
CHK(mem_allocated_size() == 0);
+
return 0;
}
diff --git a/src/test_sdis_solve_probe2_2d.c b/src/test_sdis_solve_probe2_2d.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 2016-2021 |Meso|Star> (contact@meso-star.com)
+/* Copyright (C) 2016-2022 |Meso|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
@@ -141,7 +141,6 @@ interface_get_temperature
int
main(int argc, char** argv)
{
- struct mem_allocator allocator;
struct sdis_mc T = SDIS_MC_NULL;
struct sdis_mc time = SDIS_MC_NULL;
struct sdis_device* dev = NULL;
@@ -169,8 +168,7 @@ main(int argc, char** argv)
size_t nfails;
(void)argc, (void)argv;
- OK(mem_init_proxy_allocator(&allocator, &mem_default_allocator));
- OK(sdis_device_create(NULL, &allocator, SDIS_NTHREADS_DEFAULT, 1, &dev));
+ OK(sdis_device_create(&SDIS_DEVICE_CREATE_ARGS_DEFAULT, &dev));
/* Create the fluid medium */
fluid_shader.temperature = temperature_unknown;
@@ -180,7 +178,7 @@ main(int argc, char** argv)
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 = solid_get_delta;
+ solid_shader.delta = solid_get_delta;
solid_shader.temperature = temperature_unknown;
OK(sdis_solid_create(dev, &solid_shader, NULL, &solid));
@@ -282,8 +280,6 @@ main(int argc, char** argv)
OK(sdis_green_function_ref_put(green));
OK(sdis_device_ref_put(dev));
- check_memory_allocator(&allocator);
- mem_shutdown_proxy_allocator(&allocator);
CHK(mem_allocated_size() == 0);
return 0;
}
diff --git a/src/test_sdis_solve_probe3.c b/src/test_sdis_solve_probe3.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 2016-2021 |Meso|Star> (contact@meso-star.com)
+/* Copyright (C) 2016-2022 |Meso|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
@@ -166,7 +166,6 @@ interface_get_temperature
int
main(int argc, char** argv)
{
- struct mem_allocator allocator;
struct sdis_mc T = SDIS_MC_NULL;
struct sdis_mc time = SDIS_MC_NULL;
struct sdis_device* dev = NULL;
@@ -199,8 +198,7 @@ main(int argc, char** argv)
size_t i;
(void)argc, (void)argv;
- OK(mem_init_proxy_allocator(&allocator, &mem_default_allocator));
- OK(sdis_device_create(NULL, &allocator, SDIS_NTHREADS_DEFAULT, 1, &dev));
+ OK(sdis_device_create(&SDIS_DEVICE_CREATE_ARGS_DEFAULT, &dev));
/* Create the fluid medium */
fluid_shader.temperature = temperature_unknown;
@@ -210,7 +208,7 @@ main(int argc, char** argv)
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 = solid_get_delta;
+ solid_shader.delta = solid_get_delta;
solid_shader.temperature = temperature_unknown;
OK(sdis_solid_create(dev, &solid_shader, NULL, &solid));
@@ -262,7 +260,7 @@ main(int argc, char** argv)
}
/* Setup a sphere at the center of the box */
- OK(s3dut_create_sphere(&allocator, 0.25, 64, 32, &msh));
+ OK(s3dut_create_sphere(NULL, 0.25, 64, 32, &msh));
OK(s3dut_mesh_get_data(msh, &msh_data));
FOR_EACH(i, 0, msh_data.nvertices) {
sa_push(ctx.positions, msh_data.positions[i*3+0] + 0.5);
@@ -339,8 +337,6 @@ main(int argc, char** argv)
OK(sdis_scene_ref_put(scn));
OK(sdis_device_ref_put(dev));
- check_memory_allocator(&allocator);
- mem_shutdown_proxy_allocator(&allocator);
CHK(mem_allocated_size() == 0);
return 0;
diff --git a/src/test_sdis_solve_probe3_2d.c b/src/test_sdis_solve_probe3_2d.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 2016-2021 |Meso|Star> (contact@meso-star.com)
+/* Copyright (C) 2016-2022 |Meso|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
@@ -163,7 +163,6 @@ interface_get_temperature
int
main(int argc, char** argv)
{
- struct mem_allocator allocator;
struct sdis_mc T = SDIS_MC_NULL;
struct sdis_mc time = SDIS_MC_NULL;
struct sdis_device* dev = NULL;
@@ -194,8 +193,7 @@ main(int argc, char** argv)
size_t i;
(void)argc, (void)argv;
- OK(mem_init_proxy_allocator(&allocator, &mem_default_allocator));
- OK(sdis_device_create(NULL, &allocator, SDIS_NTHREADS_DEFAULT, 1, &dev));
+ OK(sdis_device_create(&SDIS_DEVICE_CREATE_ARGS_DEFAULT, &dev));
/* Create the fluid medium */
fluid_shader.temperature = temperature_unknown;
@@ -205,7 +203,7 @@ main(int argc, char** argv)
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 = solid_get_delta;
+ solid_shader.delta = solid_get_delta;
solid_shader.temperature = temperature_unknown;
OK(sdis_solid_create(dev, &solid_shader, NULL, &solid));
@@ -331,8 +329,6 @@ main(int argc, char** argv)
OK(sdis_scene_ref_put(scn));
OK(sdis_device_ref_put(dev));
- check_memory_allocator(&allocator);
- mem_shutdown_proxy_allocator(&allocator);
CHK(mem_allocated_size() == 0);
return 0;
}
diff --git a/src/test_sdis_solve_probe_2d.c b/src/test_sdis_solve_probe_2d.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 2016-2021 |Meso|Star> (contact@meso-star.com)
+/* Copyright (C) 2016-2022 |Meso|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
@@ -133,7 +133,6 @@ interface_get_convection_coef
int
main(int argc, char** argv)
{
- struct mem_allocator allocator;
struct sdis_mc T = SDIS_MC_NULL;
struct sdis_mc time = SDIS_MC_NULL;
struct sdis_device* dev = NULL;
@@ -158,8 +157,7 @@ main(int argc, char** argv)
size_t nfails;
(void)argc, (void)argv;
- OK(mem_init_proxy_allocator(&allocator, &mem_default_allocator));
- OK(sdis_device_create(NULL, &allocator, SDIS_NTHREADS_DEFAULT, 1, &dev));
+ OK(sdis_device_create(&SDIS_DEVICE_CREATE_ARGS_DEFAULT, &dev));
/* Create the fluid medium */
OK(sdis_data_create
@@ -174,7 +172,7 @@ main(int argc, char** argv)
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 = solid_get_delta;
+ solid_shader.delta = solid_get_delta;
solid_shader.temperature = solid_get_temperature;
OK(sdis_solid_create(dev, &solid_shader, NULL, &solid));
@@ -243,8 +241,6 @@ main(int argc, char** argv)
OK(sdis_scene_ref_put(scn));
OK(sdis_device_ref_put(dev));
- check_memory_allocator(&allocator);
- mem_shutdown_proxy_allocator(&allocator);
CHK(mem_allocated_size() == 0);
return 0;
}
diff --git a/src/test_sdis_transcient.c b/src/test_sdis_transcient.c
@@ -47,7 +47,7 @@ static const double vertices[12/*#vertices*/*3/*#coords per vertex*/] = {
1.0, 0.0, 1.0,
1.0, 1.0, 1.0
};
-static const size_t nvertices = sizeof(vertices) / (3*sizeof(double));
+static const size_t nvertices = sizeof(vertices) / (sizeof(double)*3);
/* The following array lists the indices toward the 3D vertices of each
* triangle.
@@ -67,7 +67,7 @@ static const size_t indices[22/*#triangles*/*3/*#indices per triangle*/] = {
0, 2, 1, 1, 2, 3, 1, 3, 8, 8, 3, 9, /* Z min */
4, 5, 6, 6, 5, 7, 5,10, 7, 7,10,11 /* Z max */
};
-static const size_t ntriangles = sizeof(indices) / (3*sizeof(size_t));
+static const size_t ntriangles = sizeof(indices) / (sizeof(size_t)*3);
/*******************************************************************************
* Box geometry functions
@@ -463,7 +463,6 @@ temperature_analytical
int
main(int argc, char** argv)
{
- struct mem_allocator allocator;
struct sdis_device* dev = NULL;
struct sdis_scene* box_scn = NULL;
struct sdis_scene* box2_scn = NULL;
@@ -509,8 +508,7 @@ main(int argc, char** argv)
boxsz[1] = 0.1;
boxsz[2] = 0.2;
- OK(mem_init_proxy_allocator(&allocator, &mem_default_allocator));
- OK(sdis_device_create(NULL, &allocator, SDIS_NTHREADS_DEFAULT, 1, &dev));
+ OK(sdis_device_create(&SDIS_DEVICE_CREATE_ARGS_DEFAULT, &dev));
/* Create the fluid medium */
fluid_shader = DUMMY_FLUID_SHADER;
@@ -520,7 +518,7 @@ main(int argc, char** argv)
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 = solid_get_delta;
+ solid_shader.delta = solid_get_delta;
solid_shader.temperature = solid_get_temperature;
/* Create the solid medium */
@@ -530,7 +528,7 @@ main(int argc, char** argv)
solid_param->rho = rho;
solid_param->cp = cp;
solid_param->lambda = lambda;
- solid_param->delta = 1.0/20.0 * MMIN(MMIN(boxsz[0], boxsz[1]), boxsz[2]);
+ solid_param->delta = 1.0/30.0 * MMIN(MMIN(boxsz[0], boxsz[1]), boxsz[2]);
solid_param->init_temperature = Tinit;
OK(sdis_solid_create(dev, &solid_shader, data, &solid));
@@ -618,7 +616,7 @@ main(int argc, char** argv)
(Tbounds, Tinit, boxsz, probe, time[0], rho, cp, lambda);
/* Run simulation on regular scene */
- solid_param->delta = 1.0/20.0 * MMIN(MMIN(boxsz[0], boxsz[1]), boxsz[2]);
+ solid_param->delta = 1.0/30.0 * MMIN(MMIN(boxsz[0], boxsz[1]), boxsz[2]);
solve_args.nrealisations = nrealisations;
solve_args.position[0] = probe[0];
solve_args.position[1] = probe[1];
@@ -638,7 +636,7 @@ main(int argc, char** argv)
OK(sdis_estimator_ref_put(estimator));
/* Run simulation on split scene */
- solid_param->delta = 1.0/20.0 * MMIN(MMIN(boxsz[0]/2.0, boxsz[1]), boxsz[2]);
+ solid_param->delta = 1.0/30.0 * MMIN(MMIN(boxsz[0]/2.0, boxsz[1]), boxsz[2]);
OK(sdis_solve_probe(box2_scn, &solve_args, &estimator));
OK(sdis_estimator_get_failure_count(estimator, &nfails));
OK(sdis_estimator_get_temperature(estimator, &temperature));
@@ -653,7 +651,7 @@ main(int argc, char** argv)
/* Run simulation on matriochkas */
solid_param->delta = MMIN(MMIN(boxsz[0], boxsz[1]), boxsz[2]);
solid_param->delta /= (double)nmatriochkas;
- solid_param->delta *= 1.0/20.0;
+ solid_param->delta *= 1.0/30.0;
OK(sdis_solve_probe(box_matriochka_scn, &solve_args, &estimator));
OK(sdis_estimator_get_failure_count(estimator, &nfails));
OK(sdis_estimator_get_temperature(estimator, &temperature));
@@ -680,8 +678,6 @@ main(int argc, char** argv)
OK(sdis_scene_ref_put(box2_scn));
OK(sdis_scene_ref_put(box_matriochka_scn));
- check_memory_allocator(&allocator);
- mem_shutdown_proxy_allocator(&allocator);
CHK(mem_allocated_size() == 0);
return 0;
}
diff --git a/src/test_sdis_unstationary_atm.c b/src/test_sdis_unstationary_atm.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 2016-2021 |Meso|Star> (contact@meso-star.com)
+/* Copyright (C) 2016-2022 |Meso|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
@@ -23,6 +23,20 @@
#include <star/ssp.h>
/*
+ * The physical configuration is the following: a slab of fluid with known
+ * thermophysical properties but unknown temperature is located between a
+ * "ground" and a slab of solid, with also a unknown temperature profile. On
+ * the other side of the solid slab, is a "atmosphere" with known temperature,
+ * and known radiative temperature.
+ *
+ * Solving the system means: finding the temperature of the ground, of the
+ * fluid, of the boundaries, and also the temperature inside the solid, at
+ * various locations (the 1D slab is discretized in order to obtain the
+ * reference)
+ *
+ * The reference for this system comes from a numerical method and is not
+ * analytic. Thus the compliance test MC VS reference is not the usual |MC -
+ * ref| <= 3*sigma but is |MC -ref| <= (Tmax -Tmin) * 0.01.
*
* 3D 2D
*
@@ -59,6 +73,10 @@
#define HA 400
#define TR 260
+#define TMAX (MMAX(MMAX(MMAX(T0_FLUID, T0_SOLID), MMAX(TG, TA)), TR))
+#define TMIN (MMIN(MMIN(MMIN(T0_FLUID, T0_SOLID), MMIN(TG, TA)), TR))
+#define EPS ((TMAX-TMIN)*0.01)
+
/* hr = 4.0 * BOLTZMANN_CONSTANT * Tref * Tref * Tref * epsilon
* Tref = (hr / (4 * 5.6696e-8 * epsilon)) ^ 1/3, hr = 6 */
#define TREF 297.974852286
@@ -71,13 +89,12 @@
#define X_PROBE (XH + 0.2 * XE)
-#define DELTA (XE/30.0)
+#define DELTA (XE/40.0)
- /*******************************************************************************
- * Box geometry
- ******************************************************************************/
-static const double model3d_vertices[12/*#vertices*/ * 3/*#coords per vertex*/]
-= {
+/*******************************************************************************
+ * Box geometry
+ ******************************************************************************/
+static const double model3d_vertices[12/*#vertices*/*3/*#coords per vertex*/] = {
0, 0, 0,
XH, 0, 0,
XHpE, 0, 0,
@@ -91,20 +108,19 @@ static const double model3d_vertices[12/*#vertices*/ * 3/*#coords per vertex*/]
XH, XHpE, XHpE,
XHpE, XHpE, XHpE
};
-static const size_t model3d_nvertices = sizeof(model3d_vertices) / (3*sizeof(double));
+static const size_t model3d_nvertices = sizeof(model3d_vertices)/(sizeof(double)*3);
/* The following array lists the indices toward the 3D vertices of each
* triangle.
* ,3---,4---,5 ,3----4----5 ,4
* ,' | ,' | ,'/| ,'/| \ | \ | ,'/|
- * 9----10---11 / | 9' / | \ | \ | 10 / | Y
- * |', |', | / ,2 | / ,0---,1---,2 | / ,1 |
+ * 9----10---11 / | 9' / | \ | \ | 10 / | Y
+ * |', |', | / ,2 | / ,0---,1---,2 | / ,1 |
* | ',| ',|/,' |/,' | ,' | ,' |/,' o--X
- * 6----7----8' 6----7'---8' 7 /
- * Front, right Back, left and Internal Z
+ * 6----7----8' 6----7'---8' 7 /
+ * Front, right Back, left and Internal Z
* and Top faces bottom faces face */
-static const size_t model3d_indices[22/*#triangles*/ * 3/*#indices per triangle*/]
-= {
+static const size_t model3d_indices[22/*#triangles*/*3/*#indices per triangle*/] = {
0, 3, 1, 1, 3, 4, 1, 4, 2, 2, 4, 5, /* -Z */
0, 6, 3, 3, 6, 9, /* -X */
6, 7, 9, 9, 7, 10, 7, 8, 10, 10, 8, 11, /* +Z */
@@ -113,7 +129,7 @@ static const size_t model3d_indices[22/*#triangles*/ * 3/*#indices per triangle*
0, 1, 7, 7, 6, 0, 1, 2, 8, 8, 7, 1, /* -Y */
4, 10, 7, 7, 1, 4 /* Inside */
};
-static const size_t model3d_ntriangles = sizeof(model3d_indices) / (3*sizeof(size_t));
+static const size_t model3d_ntriangles = sizeof(model3d_indices)/(sizeof(size_t)*3);
static INLINE void
model3d_get_indices(const size_t itri, size_t ids[3], void* context)
@@ -157,7 +173,7 @@ static const double model2d_vertices[6/*#vertices*/ * 2/*#coords per vertex*/] =
XH, XHpE,
XHpE, XHpE
};
-static const size_t model2d_nvertices = sizeof(model2d_vertices) / (2*sizeof(double));
+static const size_t model2d_nvertices = sizeof(model2d_vertices)/(sizeof(double)*2);
static const size_t model2d_indices[7/*#segments*/ * 2/*#indices per segment*/] = {
0, 1, 1, 2, /* Bottom */
@@ -166,8 +182,7 @@ static const size_t model2d_indices[7/*#segments*/ * 2/*#indices per segment*/]
5, 0, /* Right */
4, 1 /* Inside */
};
-static const size_t model2d_nsegments = sizeof(model2d_indices) / (2*sizeof(size_t));
-
+static const size_t model2d_nsegments = sizeof(model2d_indices)/(sizeof(size_t)*2);
static INLINE void
model2d_get_indices(const size_t iseg, size_t ids[2], void* context)
@@ -309,6 +324,7 @@ struct interf {
double temperature;
double emissivity;
double h;
+ double Tref;
};
static double
@@ -341,10 +357,56 @@ interface_get_emissivity
return interf->emissivity;
}
+static double
+interface_get_Tref
+ (const struct sdis_interface_fragment* frag, struct sdis_data* data)
+{
+ const struct interf* interf;
+ CHK(frag && data);
+ interf = sdis_data_cget(data);
+ return interf->Tref;
+}
+
/*******************************************************************************
* Helper functions
******************************************************************************/
static void
+create_interface
+ (struct sdis_device* dev,
+ struct sdis_medium* front,
+ struct sdis_medium* back,
+ const struct interf* interf,
+ struct sdis_interface** out_interf)
+{
+ struct sdis_interface_shader shader = SDIS_INTERFACE_SHADER_NULL;
+ struct sdis_data* data = NULL;
+
+ CHK(interf != NULL);
+
+ shader.front.temperature = interface_get_temperature;
+ shader.back.temperature = interface_get_temperature;
+ if(sdis_medium_get_type(front) != sdis_medium_get_type(back)) {
+ shader.convection_coef = interface_get_convection_coef;
+ shader.convection_coef_upper_bound = interf->h;
+ }
+ if(sdis_medium_get_type(front) == SDIS_FLUID) {
+ shader.front.emissivity = interface_get_emissivity;
+ shader.front.reference_temperature = interface_get_Tref;
+ }
+ if(sdis_medium_get_type(back) == SDIS_FLUID) {
+ shader.back.emissivity = interface_get_emissivity;
+ shader.back.reference_temperature = interface_get_Tref;
+ }
+
+ OK(sdis_data_create(dev, sizeof(struct interf), ALIGNOF(struct interf),
+ NULL, &data));
+ *((struct interf*)sdis_data_get(data)) = *interf;
+
+ OK(sdis_interface_create(dev, front, back, &shader, data, out_interf));
+ OK(sdis_data_ref_put(data));
+}
+
+static void
solve_tbound1
(struct sdis_scene* scn,
struct ssp_rng* rng)
@@ -359,10 +421,11 @@ solve_tbound1
size_t nreals;
size_t nfails;
enum sdis_scene_dimension dim;
- double t[] = { 1000, 2000, 3000, 4000, 5000, 6000, 7000, 8000, 9000, 10000 };
- double ref[sizeof(t) / sizeof(*t)]
- = { 290.046375, 289.903935, 289.840490, 289.802690, 289.777215,
- 289.759034, 289.745710, 289.735826, 289.728448, 289.722921 };
+ const double t[] = { 1000, 2000, 3000, 4000, 5000, 6000, 7000, 8000, 9000, 10000 };
+ const double ref[sizeof(t) / sizeof(*t)] = {
+ 290.046375, 289.903935, 289.840490, 289.802690, 289.777215, 289.759034,
+ 289.745710, 289.735826, 289.728448, 289.722921
+ };
const int nsimuls = sizeof(t) / sizeof(*t);
int isimul;
ASSERT(scn && rng);
@@ -413,9 +476,8 @@ solve_tbound1
printf("Elapsed time = %s\n", dump);
printf("Time per realisation (in usec) = %g +/- %g\n\n", time.E, time.SE);
- CHK(nfails + nreals == N);
- CHK(nfails <= N/1000);
- CHK(t[isimul] == 0 || eq_eps(T.E, ref[isimul], T.SE * 4));
+ CHK(eq_eps(T.E, ref[isimul], EPS));
+ /*CHK(eq_eps(T.E, ref[isimul], T.SE*3));*/
OK(sdis_estimator_ref_put(estimator));
}
@@ -436,10 +498,11 @@ solve_tbound2
size_t nreals;
size_t nfails;
enum sdis_scene_dimension dim;
- double t[] = { 1000, 2000, 3000, 4000, 5000, 6000, 7000, 8000, 9000, 10000 };
- double ref[sizeof(t) / sizeof(*t)]
- = { 309.08032, 309.34626, 309.46525, 309.53625, 309.58408,
- 309.618121, 309.642928, 309.661167, 309.674614, 309.684524 };
+ const double t[] = { 1000, 2000, 3000, 4000, 5000, 6000, 7000, 8000, 9000, 10000 };
+ const double ref[sizeof(t) / sizeof(*t)] = {
+ 309.08032, 309.34626, 309.46525, 309.53625, 309.58408, 309.618121,
+ 309.642928, 309.661167, 309.674614, 309.684524
+ };
const int nsimuls = sizeof(t) / sizeof(*t);
int isimul;
ASSERT(scn && rng);
@@ -492,7 +555,8 @@ solve_tbound2
CHK(nfails + nreals == N);
CHK(nfails <= N/1000);
- CHK(eq_eps(T.E, ref[isimul], T.SE * 4));
+ CHK(eq_eps(T.E, ref[isimul], EPS));
+ /*CHK(eq_eps(T.E, ref[isimul], T.SE*3));*/
OK(sdis_estimator_ref_put(estimator));
}
@@ -512,10 +576,11 @@ solve_tsolid
size_t nreals;
size_t nfails;
enum sdis_scene_dimension dim;
- double t[] = { 0, 1000, 2000, 3000, 4000, 5000, 6000, 7000, 8000, 9000, 10000 };
- double ref[sizeof(t) / sizeof(*t)]
- = { 300, 300.87408, 302.25832, 303.22164, 303.89954, 304.39030,
- 304.75041, 305.01595, 305.21193, 305.35641, 305.46271 };
+ const double t[] = { 0, 1000, 2000, 3000, 4000, 5000, 6000, 7000, 8000, 9000, 10000 };
+ const double ref[sizeof(t) / sizeof(*t)] = {
+ 300, 300.87408, 302.25832, 303.22164, 303.89954, 304.39030, 304.75041,
+ 305.01595, 305.21193, 305.35641, 305.46271
+ };
const int nsimuls = sizeof(t) / sizeof(*t);
int isimul;
ASSERT(scn && rng);
@@ -558,7 +623,8 @@ solve_tsolid
CHK(nfails + nreals == N);
CHK(nfails <= N / 1000);
- CHK(eq_eps(T.E, ref[isimul], T.SE * 4));
+ CHK(eq_eps(T.E, ref[isimul], EPS));
+ /*CHK(eq_eps(T.E, ref[isimul], T.SE*3));*/
OK(sdis_estimator_ref_put(estimator));
}
@@ -577,10 +643,12 @@ solve_tfluid
size_t nreals;
size_t nfails;
enum sdis_scene_dimension dim;
- double t[] = { 0, 1000, 2000, 3000, 4000, 5000, 6000, 7000, 8000, 9000, 10000 };
- double ref[sizeof(t) / sizeof(*t)]
- = { 300, 309.53905, 309.67273, 309.73241, 309.76798, 309.79194, 309.80899,
- 309.82141, 309.83055, 309.83728, 309.84224 };
+ double eps;
+ const double t[] = { 0, 1000, 2000, 3000, 4000, 5000, 6000, 7000, 8000, 9000, 10000 };
+ const double ref[sizeof(t) / sizeof(*t)] = {
+ 300, 309.53905, 309.67273, 309.73241, 309.76798, 309.79194, 309.80899,
+ 309.82141, 309.83055, 309.83728, 309.84224
+ };
const int nsimuls = sizeof(t) / sizeof(*t);
int isimul;
ASSERT(scn);
@@ -621,7 +689,9 @@ solve_tfluid
CHK(nfails + nreals == N);
CHK(nfails <= N / 1000);
- CHK(eq_eps(T.E, ref[isimul], T.SE * 4));
+
+ eps = EPS;
+ CHK(eq_eps(T.E, ref[isimul], eps));
OK(sdis_estimator_ref_put(estimator));
}
@@ -633,7 +703,6 @@ solve_tfluid
int
main(int argc, char** argv)
{
- struct mem_allocator allocator;
struct sdis_data* data = NULL;
struct sdis_device* dev = NULL;
struct sdis_medium* fluid = NULL;
@@ -650,23 +719,21 @@ main(int argc, char** argv)
struct sdis_scene_create_args scn_args = SDIS_SCENE_CREATE_ARGS_DEFAULT;
struct sdis_fluid_shader fluid_shader = DUMMY_FLUID_SHADER;
struct sdis_solid_shader solid_shader = DUMMY_SOLID_SHADER;
- struct sdis_interface_shader interf_shader = SDIS_INTERFACE_SHADER_NULL;
struct sdis_interface* model3d_interfaces[22 /*#triangles*/];
struct sdis_interface* model2d_interfaces[7/*#segments*/];
- struct interf* interf_props = NULL;
+ struct interf interf_props;
struct solid* solid_props = NULL;
struct fluid* fluid_props = NULL;
struct ssp_rng* rng = NULL;
(void)argc, (void)argv;
- OK(mem_init_proxy_allocator(&allocator, &mem_default_allocator));
- OK(sdis_device_create(NULL, &allocator, SDIS_NTHREADS_DEFAULT, 1, &dev));
+ OK(sdis_device_create(&SDIS_DEVICE_CREATE_ARGS_DEFAULT, &dev));
/* Setup the solid shader */
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 = solid_get_delta;
+ solid_shader.delta = solid_get_delta;
solid_shader.temperature = solid_get_temperature;
/* Create the solid media */
@@ -718,66 +785,34 @@ main(int argc, char** argv)
OK(sdis_fluid_create(dev, &fluid_shader, data, &fluid_A));
OK(sdis_data_ref_put(data));
- /* Setup the interface shader */
- interf_shader.front.temperature = interface_get_temperature;
- interf_shader.back.temperature = interface_get_temperature;
- interf_shader.convection_coef = interface_get_convection_coef;
- interf_shader.convection_coef_upper_bound = 0;
-
/* Create the adiabatic interfaces */
- OK(sdis_data_create(dev, sizeof(struct interf), 16, NULL, &data));
- interf_props = sdis_data_get(data);
- interf_props->temperature = UNKNOWN_TEMPERATURE;
- interf_props->h = 0;
- OK(sdis_interface_create
- (dev, fluid, dummy_solid, &interf_shader, data, &interf_adiabatic_1));
- OK(sdis_data_ref_put(data));
-
- interf_shader.convection_coef = NULL;
- OK(sdis_data_create(dev, sizeof(struct interf), 16, NULL, &data));
- interf_props = sdis_data_get(data);
- interf_props->temperature = UNKNOWN_TEMPERATURE;
- interf_props->h = 0;
- OK(sdis_interface_create
- (dev, solid, dummy_solid, &interf_shader, data, &interf_adiabatic_2));
- OK(sdis_data_ref_put(data));
+ interf_props.temperature = UNKNOWN_TEMPERATURE;
+ interf_props.h = 0;
+ interf_props.emissivity = 0;
+ interf_props.Tref = TREF;
+ create_interface(dev, fluid, dummy_solid, &interf_props, &interf_adiabatic_1);
+ create_interface(dev, solid, dummy_solid, &interf_props, &interf_adiabatic_2);
/* Create the P interface */
- interf_shader.convection_coef_upper_bound = HC;
- interf_shader.convection_coef = interface_get_convection_coef;
- interf_shader.front.emissivity = interface_get_emissivity;
- OK(sdis_data_create(dev, sizeof(struct interf), 16, NULL, &data));
- interf_props = sdis_data_get(data);
- interf_props->temperature = UNKNOWN_TEMPERATURE;
- interf_props->h = HC;
- interf_props->emissivity = 1;
- OK(sdis_interface_create
- (dev, fluid, solid, &interf_shader, data, &interf_P));
- OK(sdis_data_ref_put(data));
+ interf_props.temperature = UNKNOWN_TEMPERATURE;
+ interf_props.h = HC;
+ interf_props.emissivity = 1;
+ interf_props.Tref = TREF;
+ create_interface(dev, fluid, solid, &interf_props, &interf_P);
/* Create the TG interface */
- interf_shader.convection_coef_upper_bound = HG;
- OK(sdis_data_create(dev, sizeof(struct interf), 16, NULL, &data));
- interf_props = sdis_data_get(data);
- interf_props->temperature = TG;
- interf_props->h = HG;
- interf_props->emissivity = 1;
- OK(sdis_interface_create
- (dev, fluid, dummy_solid, &interf_shader, data, &interf_TG));
- OK(sdis_data_ref_put(data));
+ interf_props.temperature = TG;
+ interf_props.h = HG;
+ interf_props.emissivity = 1;
+ interf_props.Tref = TG;
+ create_interface(dev, fluid, dummy_solid, &interf_props, &interf_TG);
/* Create the TA interface */
- interf_shader.convection_coef_upper_bound = HA;
- interf_shader.front.emissivity = NULL;
- interf_shader.back.emissivity = interface_get_emissivity;
- OK(sdis_data_create(dev, sizeof(struct interf), 16, NULL, &data));
- interf_props = sdis_data_get(data);
- interf_props->temperature = UNKNOWN_TEMPERATURE;
- interf_props->h = HA;
- interf_props->emissivity = 1;
- OK(sdis_interface_create
- (dev, solid, fluid_A, &interf_shader, data, &interf_TA));
- OK(sdis_data_ref_put(data));
+ interf_props.temperature = UNKNOWN_TEMPERATURE;
+ interf_props.h = HA;
+ interf_props.emissivity = 1;
+ interf_props.Tref = TREF;
+ create_interface(dev, solid, fluid_A, &interf_props, &interf_TA);
/* Release the media */
OK(sdis_medium_ref_put(solid));
@@ -802,7 +837,7 @@ main(int argc, char** argv)
model3d_interfaces[10] = interf_TA;
model3d_interfaces[11] = interf_TA;
/* Top */
- model3d_interfaces[12] = interf_adiabatic_1;
+ model3d_interfaces[12] = interf_adiabatic_1;
model3d_interfaces[13] = interf_adiabatic_1;
model3d_interfaces[14] = interf_adiabatic_2;
model3d_interfaces[15] = interf_adiabatic_2;
@@ -835,8 +870,10 @@ main(int argc, char** argv)
scn_args.nprimitives = model3d_ntriangles;
scn_args.nvertices = model3d_nvertices;
scn_args.context = model3d_interfaces;
- scn_args.trad = TR;
- scn_args.tref = TREF;
+ scn_args.trad.temperature = TR;
+ scn_args.trad.reference = TR;
+ scn_args.t_range[0] = MMIN(MMIN(MMIN(MMIN(T0_FLUID, T0_SOLID), TA), TG), TR);
+ scn_args.t_range[1] = MMAX(MMAX(MMAX(MMAX(T0_FLUID, T0_SOLID), TA), TG), TR);
OK(sdis_scene_create(dev, &scn_args, &box_scn));
/* Create the square scene */
@@ -846,8 +883,10 @@ main(int argc, char** argv)
scn_args.nprimitives = model2d_nsegments;
scn_args.nvertices = model2d_nvertices;
scn_args.context = model2d_interfaces;
- scn_args.trad = TR;
- scn_args.tref = TREF;
+ scn_args.trad.temperature = TR;
+ scn_args.trad.reference = TR;
+ scn_args.t_range[0] = MMIN(MMIN(MMIN(MMIN(T0_FLUID, T0_SOLID), TA), TG), TR);
+ scn_args.t_range[1] = MMAX(MMAX(MMAX(MMAX(T0_FLUID, T0_SOLID), TA), TG), TR);
OK(sdis_scene_2d_create(dev, &scn_args, &square_scn));
/* Release the interfaces */
@@ -858,7 +897,7 @@ main(int argc, char** argv)
OK(sdis_interface_ref_put(interf_TA));
/* Solve */
- OK(ssp_rng_create(&allocator, SSP_RNG_KISS, &rng));
+ OK(ssp_rng_create(NULL, SSP_RNG_KISS, &rng));
printf(">> Box scene\n");
solve_tfluid(box_scn);
solve_tbound1(box_scn, rng);
@@ -875,8 +914,6 @@ main(int argc, char** argv)
OK(sdis_device_ref_put(dev));
OK(ssp_rng_ref_put(rng));
- check_memory_allocator(&allocator);
- mem_shutdown_proxy_allocator(&allocator);
CHK(mem_allocated_size() == 0);
return 0;
}
diff --git a/src/test_sdis_utils.c b/src/test_sdis_utils.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 2016-2021 |Meso|Star> (contact@meso-star.com)
+/* Copyright (C) 2016-2022 |Meso|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
@@ -17,6 +17,7 @@
#include <rsys/math.h>
enum heat_vertex_attrib {
+ HEAT_VERTEX_BRANCH_ID,
HEAT_VERTEX_WEIGHT,
HEAT_VERTEX_TIME,
HEAT_VERTEX_TYPE
@@ -125,6 +126,7 @@ solve_green_path(struct sdis_green_path* path, void* ctx)
BA(sdis_green_path_get_limit_point(NULL, &pt));
BA(sdis_green_path_get_limit_point(path, NULL));
if(end_type == SDIS_GREEN_PATH_END_RADIATIVE) {
+ struct sdis_ambient_radiative_temperature trad;
struct sdis_green_function* green;
struct sdis_scene* scn;
BO(sdis_green_path_get_limit_point(path, &pt));
@@ -140,8 +142,9 @@ solve_green_path(struct sdis_green_path* path, void* ctx)
BA(sdis_scene_get_ambient_radiative_temperature(NULL, NULL));
BA(sdis_scene_get_ambient_radiative_temperature(scn, NULL));
- BA(sdis_scene_get_ambient_radiative_temperature(NULL, &temp));
- OK(sdis_scene_get_ambient_radiative_temperature(scn, &temp));
+ BA(sdis_scene_get_ambient_radiative_temperature(NULL, &trad));
+ OK(sdis_scene_get_ambient_radiative_temperature(scn, &trad));
+ temp = trad.temperature;
} else {
OK(sdis_green_path_get_limit_point(path, &pt));
switch(pt.type) {
@@ -176,31 +179,54 @@ solve_green_path(struct sdis_green_path* path, void* ctx)
return RES_OK;
}
+static size_t
+heat_path_get_vertices_count(const struct sdis_heat_path* path)
+{
+ size_t istrip = 0;
+ size_t nstrips = 0;
+ size_t nvertices = 0;
+ CHK(path);
+
+ OK(sdis_heat_path_get_line_strips_count(path, &nstrips));
+ FOR_EACH(istrip, 0, nstrips) {
+ size_t n;
+ OK(sdis_heat_path_line_strip_get_vertices_count(path, istrip, &n));
+ nvertices += n;
+ }
+ return nvertices;
+}
+
static void
-dump_heat_path_position(FILE* stream, const struct sdis_heat_path* path)
+dump_heat_path_positions(FILE* stream, const struct sdis_heat_path* path)
{
- size_t nverts;
- size_t ivert;
+ size_t istrip, nstrips;
+ size_t ivert, nverts;
CHK(stream && path);
- OK(sdis_heat_path_get_vertices_count(path, &nverts));
- FOR_EACH(ivert, 0, nverts) {
- struct sdis_heat_vertex vtx;
- OK(sdis_heat_path_get_vertex(path, ivert, &vtx));
- fprintf(stream, "%g %g %g\n", SPLIT3(vtx.P));
+ OK(sdis_heat_path_get_line_strips_count(path, &nstrips));
+ FOR_EACH(istrip, 0, nstrips) {
+ OK(sdis_heat_path_line_strip_get_vertices_count(path, istrip, &nverts));
+ FOR_EACH(ivert, 0, nverts) {
+ struct sdis_heat_vertex vtx;
+ OK(sdis_heat_path_line_strip_get_vertex(path, istrip, ivert, &vtx));
+ fprintf(stream, "%g %g %g\n", SPLIT3(vtx.P));
+ }
}
}
static void
-dump_heat_path_segments
- (FILE* stream, const struct sdis_heat_path* path, const size_t offset)
+dump_heat_path_line_strip
+ (FILE* stream,
+ const struct sdis_heat_path* path,
+ const size_t istrip,
+ const size_t offset)
{
- size_t nverts, ivert;
+ size_t ivert, nverts;
CHK(stream);
- OK(sdis_heat_path_get_vertices_count(path, &nverts));
+ OK(sdis_heat_path_line_strip_get_vertices_count(path, istrip, &nverts));
fprintf(stream, "%lu", (unsigned long)nverts);
FOR_EACH(ivert, 0, nverts) {
fprintf(stream, " %lu", (unsigned long)(ivert + offset));
@@ -214,29 +240,37 @@ dump_heat_path_vertex_attribs
const struct sdis_heat_path* path,
const enum heat_vertex_attrib attr)
{
- size_t nverts, ivert;
+ size_t ivert, nverts;
+ size_t istrip, nstrips;
CHK(stream && path);
- OK(sdis_heat_path_get_vertices_count(path, &nverts));
- FOR_EACH(ivert, 0, nverts) {
- struct sdis_heat_vertex vtx;
- OK(sdis_heat_path_get_vertex(path, ivert, &vtx));
- switch(attr) {
- case HEAT_VERTEX_WEIGHT:
- fprintf(stream, "%g\n", vtx.weight);
- break;
- case HEAT_VERTEX_TIME:
- fprintf(stream, "%g\n", IS_INF(vtx.time) ? FLT_MAX : vtx.time);
- break;
- case HEAT_VERTEX_TYPE:
- switch(vtx.type) {
- case SDIS_HEAT_VERTEX_CONDUCTION: fprintf(stream, "0.0\n"); break;
- case SDIS_HEAT_VERTEX_CONVECTION: fprintf(stream, "0.5\n"); break;
- case SDIS_HEAT_VERTEX_RADIATIVE: fprintf(stream, "1.0\n"); break;
- default: FATAL("Unreachable code.\n"); break;
- }
- break;
- default: FATAL("Unreachable code.\n"); break;
+ OK(sdis_heat_path_get_line_strips_count(path, &nstrips));
+ FOR_EACH(istrip, 0, nstrips) {
+ OK(sdis_heat_path_line_strip_get_vertices_count(path, istrip, &nverts));
+ FOR_EACH(ivert, 0, nverts) {
+ struct sdis_heat_vertex vtx;
+ OK(sdis_heat_path_line_strip_get_vertex(path, istrip, ivert, &vtx));
+ switch(attr) {
+ case HEAT_VERTEX_BRANCH_ID:
+ fprintf(stream, "%i\n", vtx.branch_id);
+ break;
+ case HEAT_VERTEX_WEIGHT:
+ fprintf(stream, "%g\n", vtx.weight);
+ break;
+ case HEAT_VERTEX_TIME:
+ fprintf(stream, "%g\n",
+ IS_INF(vtx.time) || vtx.time > FLT_MAX ? -1 : vtx.time);
+ break;
+ case HEAT_VERTEX_TYPE:
+ switch(vtx.type) {
+ case SDIS_HEAT_VERTEX_CONDUCTION: fprintf(stream, "0.0\n"); break;
+ case SDIS_HEAT_VERTEX_CONVECTION: fprintf(stream, "0.5\n"); break;
+ case SDIS_HEAT_VERTEX_RADIATIVE: fprintf(stream, "1.0\n"); break;
+ default: FATAL("Unreachable code.\n"); break;
+ }
+ break;
+ default: FATAL("Unreachable code.\n"); break;
+ }
}
}
}
@@ -304,9 +338,9 @@ dump_heat_paths(FILE* stream, const struct sdis_estimator* estimator)
const struct sdis_heat_path* path;
size_t ipath;
size_t npaths;
+ size_t nstrips_overall;
size_t nvertices;
size_t offset;
- size_t n;
CHK(stream && estimator);
OK(sdis_estimator_get_paths_count(estimator, &npaths));
@@ -318,30 +352,40 @@ dump_heat_paths(FILE* stream, const struct sdis_estimator* estimator)
fprintf(stream, "ASCII\n");
fprintf(stream, "DATASET POLYDATA\n");
- /* Compute the overall number of vertices */
+ /* Compute the overall number of vertices and the overall number of strips */
nvertices = 0;
+ nstrips_overall = 0;
FOR_EACH(ipath, 0, npaths) {
+ size_t n;
OK(sdis_estimator_get_path(estimator, ipath, &path));
- OK(sdis_heat_path_get_vertices_count(path, &n));
- nvertices += n;
+ nvertices += heat_path_get_vertices_count(path);
+ OK(sdis_heat_path_get_line_strips_count(path, &n));
+ nstrips_overall += n;
}
/* Write path positions */
fprintf(stream, "POINTS %lu double\n", (unsigned long)nvertices);
FOR_EACH(ipath, 0, npaths) {
OK(sdis_estimator_get_path(estimator, ipath, &path));
- dump_heat_path_position(stream, path);
+ dump_heat_path_positions(stream, path);
}
/* Write the segment of the paths */
fprintf(stream, "LINES %lu %lu\n",
- (unsigned long)npaths, (unsigned long)(npaths + nvertices));
+ (unsigned long)(nstrips_overall),
+ (unsigned long)(nstrips_overall + nvertices));
offset = 0;
FOR_EACH(ipath, 0, npaths) {
+ size_t path_istrip;
+ size_t path_nstrips;
OK(sdis_estimator_get_path(estimator, ipath, &path));
- dump_heat_path_segments(stream, path, offset);
- OK(sdis_heat_path_get_vertices_count(path, &n));
- offset += n;
+ OK(sdis_heat_path_get_line_strips_count(path, &path_nstrips));
+ FOR_EACH(path_istrip, 0, path_nstrips) {
+ size_t n;
+ dump_heat_path_line_strip(stream, path, path_istrip, offset);
+ OK(sdis_heat_path_line_strip_get_vertices_count(path, path_istrip, &n));
+ offset += n;
+ }
}
fprintf(stream, "POINT_DATA %lu\n", (unsigned long)nvertices);
@@ -374,18 +418,31 @@ dump_heat_paths(FILE* stream, const struct sdis_estimator* estimator)
dump_heat_path_vertex_attribs(stream, path, HEAT_VERTEX_TIME);
}
+ /* Write the branch id of the random walk vertices */
+ fprintf(stream, "SCALARS BranchID int 1\n");
+ fprintf(stream, "LOOKUP_TABLE default\n");
+ FOR_EACH(ipath, 0, npaths) {
+ OK(sdis_estimator_get_path(estimator, ipath, &path));
+ dump_heat_path_vertex_attribs(stream, path, HEAT_VERTEX_BRANCH_ID);
+ }
+
/* Write path type */
- fprintf(stream, "CELL_DATA %lu\n", (unsigned long)npaths);
+ fprintf(stream, "CELL_DATA %lu\n", (unsigned long)nstrips_overall);
fprintf(stream, "SCALARS Path_Type float 1\n");
fprintf(stream, "LOOKUP_TABLE path_type\n");
FOR_EACH(ipath, 0, npaths) {
+ size_t path_istrip;
+ size_t path_nstrips;
enum sdis_heat_path_flag status = SDIS_HEAT_PATH_NONE;
OK(sdis_estimator_get_path(estimator, ipath, &path));
OK(sdis_heat_path_get_status(path, &status));
- switch(status) {
- case SDIS_HEAT_PATH_SUCCESS: fprintf(stream, "0.0\n"); break;
- case SDIS_HEAT_PATH_FAILURE: fprintf(stream, "1.0\n"); break;
- default: FATAL("Unreachable code.\n"); break;
+ OK(sdis_heat_path_get_line_strips_count(path, &path_nstrips));
+ FOR_EACH(path_istrip, 0, path_nstrips) {
+ switch(status) {
+ case SDIS_HEAT_PATH_SUCCESS: fprintf(stream, "0.0\n"); break;
+ case SDIS_HEAT_PATH_FAILURE: fprintf(stream, "1.0\n"); break;
+ default: FATAL("Unreachable code.\n"); break;
+ }
}
}
fprintf(stream, "LOOKUP_TABLE path_type 2\n");
@@ -423,4 +480,3 @@ check_green_serialization
OK(sdis_green_function_ref_put(green2));
}
-
diff --git a/src/test_sdis_utils.h b/src/test_sdis_utils.h
@@ -1,4 +1,4 @@
-/* Copyright (C) 2016-2021 |Meso|Star> (contact@meso-star.com)
+/* Copyright (C) 2016-2022 |Meso|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
@@ -21,6 +21,11 @@
#include <rsys/double33.h>
#include <rsys/mem_allocator.h>
#include <stdio.h>
+#include <string.h>
+
+#ifdef SDIS_ENABLE_MPI
+ #include <mpi.h>
+#endif
#define BOLTZMANN_CONSTANT 5.6696e-8 /* W/m^2/K^4 */
@@ -41,7 +46,7 @@ static const double box_vertices[8/*#vertices*/*3/*#coords per vertex*/] = {
0.0, 1.0, 1.0,
1.0, 1.0, 1.0
};
-static const size_t box_nvertices = sizeof(box_vertices) / (3*sizeof(double));
+static const size_t box_nvertices = sizeof(box_vertices) / (sizeof(double)*3);
/* The following array lists the indices toward the 3D vertices of each
* triangle.
@@ -61,7 +66,7 @@ static const size_t box_indices[12/*#triangles*/*3/*#indices per triangle*/] = {
2, 6, 7, 7, 3, 2, /* +Y */
0, 1, 5, 5, 4, 0 /* -Y */
};
-static const size_t box_ntriangles = sizeof(box_indices) / (3*sizeof(size_t));
+static const size_t box_ntriangles = sizeof(box_indices) / (sizeof(size_t)*3);
static INLINE void
box_get_indices(const size_t itri, size_t ids[3], void* context)
@@ -103,7 +108,7 @@ static const double square_vertices[4/*#vertices*/*2/*#coords per vertex*/] = {
0.0, 1.0,
1.0, 1.0
};
-static const size_t square_nvertices = sizeof(square_vertices)/(2*sizeof(double));
+static const size_t square_nvertices = sizeof(square_vertices)/(sizeof(double)*2);
static const size_t square_indices[4/*#segments*/*2/*#indices per segment*/]= {
0, 1, /* Bottom */
@@ -111,7 +116,7 @@ static const size_t square_indices[4/*#segments*/*2/*#indices per segment*/]= {
2, 3, /* Top */
3, 0 /* Right */
};
-static const size_t square_nsegments = sizeof(square_indices)/(2*sizeof(size_t));
+static const size_t square_nsegments = sizeof(square_indices)/(sizeof(size_t)*2);
static INLINE void
square_get_indices(const size_t iseg, size_t ids[2], void* context)
@@ -165,38 +170,99 @@ dummy_interface_getter
}
static const struct sdis_solid_shader DUMMY_SOLID_SHADER = {
- dummy_medium_getter,
- dummy_medium_getter,
- dummy_medium_getter,
- dummy_medium_getter,
- dummy_medium_getter,
- dummy_medium_getter,
- 0
+ dummy_medium_getter, /* Calorific capacity */
+ dummy_medium_getter, /* Thermal conductivity */
+ dummy_medium_getter, /* Volumic mass */
+ dummy_medium_getter, /* Delta */
+ dummy_medium_getter, /* Volumic power */
+ dummy_medium_getter, /* Temperature */
+ 0 /* Initial time */
};
static const struct sdis_fluid_shader DUMMY_FLUID_SHADER = {
- dummy_medium_getter,
- dummy_medium_getter,
- dummy_medium_getter,
- 0
+ dummy_medium_getter, /* Calorific capacity */
+ dummy_medium_getter, /* Volumic mass */
+ dummy_medium_getter, /* Temperature */
+ 0 /* Initial time */
};
#define DUMMY_INTERFACE_SIDE_SHADER__ { \
- dummy_interface_getter, \
- dummy_interface_getter, \
- dummy_interface_getter, \
- dummy_interface_getter \
+ dummy_interface_getter, /* Temperature */ \
+ dummy_interface_getter, /* Flux */ \
+ dummy_interface_getter, /* Emissivity */ \
+ dummy_interface_getter, /* Specular fraction */ \
+ dummy_interface_getter /* Reference temperature */ \
}
static const struct sdis_interface_shader DUMMY_INTERFACE_SHADER = {
- dummy_interface_getter,
- 0,
- dummy_interface_getter,
- DUMMY_INTERFACE_SIDE_SHADER__,
- DUMMY_INTERFACE_SIDE_SHADER__
+ dummy_interface_getter, /* Convection coef */
+ 0, /* Upper bound of the convection coef */
+ dummy_interface_getter, /* Thermal contact resistance */
+ DUMMY_INTERFACE_SIDE_SHADER__, /* Front side */
+ DUMMY_INTERFACE_SIDE_SHADER__ /* Back side */
};
/*******************************************************************************
+ * Device creation
+ ******************************************************************************/
+#ifndef SDIS_ENABLE_MPI
+
+static INLINE void
+create_default_device
+ (int* argc,
+ char*** argv,
+ int* is_master_process,
+ struct sdis_device** dev)
+{
+ (void)argc, (void)argv;
+ CHK(dev && is_master_process);
+ OK(sdis_device_create(&SDIS_DEVICE_CREATE_ARGS_DEFAULT, dev));
+ *is_master_process = 1;
+}
+
+#else
+
+static INLINE void
+create_default_device
+ (int* pargc,
+ char*** pargv,
+ int* is_master_process,
+ struct sdis_device** out_dev)
+{
+ struct sdis_device_create_args dev_args = SDIS_DEVICE_CREATE_ARGS_DEFAULT;
+ struct sdis_device* dev = NULL;
+ int mpi_thread_support;
+ int mpi_rank;
+ CHK(pargc && pargv && is_master_process && out_dev);
+
+ CHK(MPI_Init_thread
+ (pargc, pargv, MPI_THREAD_SERIALIZED, &mpi_thread_support) == MPI_SUCCESS);
+ CHK(mpi_thread_support >= MPI_THREAD_SERIALIZED);
+
+ dev_args.use_mpi = *pargc >= 2 && !strcmp((*pargv)[1], "mpi");
+ OK(sdis_device_create(&dev_args, &dev));
+
+ if(dev_args.use_mpi) {
+ OK(sdis_device_get_mpi_rank(dev, &mpi_rank));
+ *is_master_process = mpi_rank == 0;
+ } else {
+ CHK(sdis_device_get_mpi_rank(dev, &mpi_rank) == RES_BAD_OP);
+ *is_master_process = 1;
+ }
+ *out_dev = dev;
+}
+#endif
+
+static INLINE void
+free_default_device(struct sdis_device* dev)
+{
+ OK(sdis_device_ref_put(dev));
+#ifdef SDIS_ENABLE_MPI
+ CHK(MPI_Finalize() == MPI_SUCCESS);
+#endif
+}
+
+/*******************************************************************************
* Miscellaneous
******************************************************************************/
static INLINE void
diff --git a/src/test_sdis_volumic_power.c b/src/test_sdis_volumic_power.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 2016-2021 |Meso|Star> (contact@meso-star.com)
+/* Copyright (C) 2016-2022 |Meso|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
@@ -51,7 +51,7 @@
#define T0 320
#define LAMBDA 0.1
#define P0 10
-#define DELTA 1.0/40.0
+#define DELTA 1.0/50.0
/*******************************************************************************
* Media
@@ -379,7 +379,6 @@ solve
int
main(int argc, char** argv)
{
- struct mem_allocator allocator;
struct sdis_data* data = NULL;
struct sdis_device* dev = NULL;
struct sdis_medium* fluid = NULL;
@@ -399,8 +398,7 @@ main(int argc, char** argv)
struct ssp_rng* rng = NULL;
(void)argc, (void)argv;
- OK(mem_init_proxy_allocator(&allocator, &mem_default_allocator));
- OK(sdis_device_create(NULL, &allocator, SDIS_NTHREADS_DEFAULT, 1, &dev));
+ OK(sdis_device_create(&SDIS_DEVICE_CREATE_ARGS_DEFAULT, &dev));
fluid_shader.temperature = fluid_get_temperature;
OK(sdis_fluid_create(dev, &fluid_shader, NULL, &fluid));
@@ -409,7 +407,7 @@ main(int argc, char** argv)
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 = solid_get_delta;
+ solid_shader.delta = solid_get_delta;
solid_shader.temperature = solid_get_temperature;
solid_shader.volumic_power = solid_get_volumic_power;
@@ -487,7 +485,7 @@ main(int argc, char** argv)
OK(sdis_interface_ref_put(interf_T0));
/* Solve */
- OK(ssp_rng_create(&allocator, SSP_RNG_KISS, &rng));
+ OK(ssp_rng_create(NULL, SSP_RNG_KISS, &rng));
printf(">> Box scene\n");
solve(box_scn, rng, solid_props);
printf(">> Square scene\n");
@@ -498,8 +496,6 @@ main(int argc, char** argv)
OK(sdis_device_ref_put(dev));
OK(ssp_rng_ref_put(rng));
- check_memory_allocator(&allocator);
- mem_shutdown_proxy_allocator(&allocator);
CHK(mem_allocated_size() == 0);
return 0;
}
diff --git a/src/test_sdis_volumic_power2.c b/src/test_sdis_volumic_power2.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 2016-2021 |Meso|Star> (contact@meso-star.com)
+/* Copyright (C) 2016-2022 |Meso|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
@@ -66,7 +66,7 @@ static const double vertices[16/*#vertices*/*3/*#coords per vertex*/] = {
0.1, 0.6, 0.5,
0.1, 0.4, 0.5
};
-static const size_t nvertices = sizeof(vertices)/(3*sizeof(double));
+static const size_t nvertices = sizeof(vertices)/(sizeof(double)*3);
static const size_t indices[36/*#triangles*/*3/*#indices per triangle*/]= {
0, 4, 5, 5, 1, 0, /* Cuboid left */
@@ -90,7 +90,7 @@ static const size_t indices[36/*#triangles*/*3/*#indices per triangle*/]= {
8, 9, 10, 10, 11, 8, /* Cube back */
12, 15, 14, 14, 13, 12 /* Cube front */
};
-static const size_t ntriangles = sizeof(indices)/(3*sizeof(size_t));
+static const size_t ntriangles = sizeof(indices)/(sizeof(size_t)*3);
/*******************************************************************************
* Geometry
@@ -262,7 +262,6 @@ check(struct sdis_scene* scn, const struct reference refs[], const size_t nrefs)
int
main(int argc, char** argv)
{
- struct mem_allocator allocator;
struct solid* solid_param = NULL;
struct fluid* fluid_param = NULL;
struct interf* interf_param = NULL;
@@ -302,8 +301,7 @@ main(int argc, char** argv)
};
(void)argc, (void)argv;
- OK(mem_init_proxy_allocator(&allocator, &mem_default_allocator));
- OK(sdis_device_create(NULL, &allocator, SDIS_NTHREADS_DEFAULT, 1, &dev));
+ OK(sdis_device_create(&SDIS_DEVICE_CREATE_ARGS_DEFAULT, &dev));
/* Setup the fluid shader */
fluid_shader.temperature = fluid_get_temperature;
@@ -330,7 +328,7 @@ main(int argc, char** argv)
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 = solid_get_delta;
+ solid_shader.delta = solid_get_delta;
solid_shader.temperature = solid_get_temperature;
solid_shader.volumic_power = solid_get_volumic_power;
@@ -467,8 +465,6 @@ main(int argc, char** argv)
OK(sdis_scene_ref_put(scn));
OK(sdis_device_ref_put(dev));
- check_memory_allocator(&allocator);
- mem_shutdown_proxy_allocator(&allocator);
CHK(mem_allocated_size() == 0);
return 0;
}
diff --git a/src/test_sdis_volumic_power2_2d.c b/src/test_sdis_volumic_power2_2d.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 2016-2021 |Meso|Star> (contact@meso-star.com)
+/* Copyright (C) 2016-2022 |Meso|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
@@ -99,7 +99,7 @@ static const double vertices[8/*#vertices*/*2/*#coords per vertex*/] = {
0.1, 0.6,
0.1, 0.4
};
-static const size_t nvertices = sizeof(vertices)/(2*sizeof(double));
+static const size_t nvertices = sizeof(vertices)/(sizeof(double)*2);
static const size_t indices[8/*#segments*/*2/*#indices per segment*/]= {
0, 1, /* Rectangle left */
@@ -111,7 +111,7 @@ static const size_t indices[8/*#segments*/*2/*#indices per segment*/]= {
6, 7, /* Square right */
7, 4 /* Square bottom */
};
-static const size_t nsegments = sizeof(indices)/(2*sizeof(size_t));
+static const size_t nsegments = sizeof(indices)/(sizeof(size_t)*2);
/*******************************************************************************
* Geometry
@@ -284,7 +284,6 @@ check(struct sdis_scene* scn, const struct reference refs[], const size_t nrefs)
int
main(int argc, char** argv)
{
- struct mem_allocator allocator;
struct solid* solid_param = NULL;
struct fluid* fluid_param = NULL;
struct interf* interf_param = NULL;
@@ -334,8 +333,7 @@ main(int argc, char** argv)
};
(void)argc, (void)argv;
- OK(mem_init_proxy_allocator(&allocator, &mem_default_allocator));
- OK(sdis_device_create(NULL, &allocator, SDIS_NTHREADS_DEFAULT, 1, &dev));
+ OK(sdis_device_create(&SDIS_DEVICE_CREATE_ARGS_DEFAULT, &dev));
/* Setup the fluid shader */
fluid_shader.temperature = fluid_get_temperature;
@@ -362,7 +360,7 @@ main(int argc, char** argv)
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 = solid_get_delta;
+ solid_shader.delta = solid_get_delta;
solid_shader.temperature = solid_get_temperature;
solid_shader.volumic_power = solid_get_volumic_power;
@@ -501,8 +499,6 @@ main(int argc, char** argv)
OK(sdis_scene_ref_put(scn));
OK(sdis_device_ref_put(dev));
- check_memory_allocator(&allocator);
- mem_shutdown_proxy_allocator(&allocator);
CHK(mem_allocated_size() == 0);
return 0;
}
diff --git a/src/test_sdis_volumic_power3_2d.c b/src/test_sdis_volumic_power3_2d.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 2016-2021 |Meso|Star> (contact@meso-star.com)
+/* Copyright (C) 2016-2022 |Meso|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
@@ -84,7 +84,7 @@ static const double vertices[8/*#vertices*/*2/*#coords per vertex*/] = {
100000.5, 1.4, /* 6 */
100000.5, 0.0 /* 7 */
};
-static const size_t nvertices = sizeof(vertices)/(2*sizeof(double));
+static const size_t nvertices = sizeof(vertices)/(sizeof(double)*2);
static const size_t indices[10/*#segments*/*2/*#indices per segment*/]= {
0, 1,
@@ -98,7 +98,7 @@ static const size_t indices[10/*#segments*/*2/*#indices per segment*/]= {
6, 1,
2, 5
};
-static const size_t nsegments = sizeof(indices)/(2*sizeof(size_t));
+static const size_t nsegments = sizeof(indices)/(sizeof(size_t)*2);
/*******************************************************************************
* Geometry
@@ -238,7 +238,6 @@ interface_get_temperature
int
main(int argc, char** argv)
{
- struct mem_allocator allocator;
struct solid* solid_param = NULL;
struct fluid* fluid_param = NULL;
struct interf* interf_param = NULL;
@@ -271,8 +270,7 @@ main(int argc, char** argv)
size_t nreals;
(void)argc, (void)argv;
- OK(mem_init_proxy_allocator(&allocator, &mem_default_allocator));
- OK(sdis_device_create(NULL, &allocator, SDIS_NTHREADS_DEFAULT, 1, &dev));
+ OK(sdis_device_create(&SDIS_DEVICE_CREATE_ARGS_DEFAULT, &dev));
/* Create the fluid medium */
fluid_shader.temperature = fluid_get_temperature;
@@ -290,7 +288,7 @@ main(int argc, char** argv)
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 = solid_get_delta;
+ solid_shader.delta = solid_get_delta;
solid_shader.temperature = solid_get_temperature;
solid_shader.volumic_power = solid_get_volumic_power;
@@ -469,8 +467,6 @@ main(int argc, char** argv)
OK(sdis_scene_ref_put(scn));
OK(sdis_device_ref_put(dev));
- check_memory_allocator(&allocator);
- mem_shutdown_proxy_allocator(&allocator);
CHK(mem_allocated_size() == 0);
return 0;
}
diff --git a/src/test_sdis_volumic_power4.c b/src/test_sdis_volumic_power4.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 2016-2021 |Meso|Star> (contact@meso-star.com)
+/* Copyright (C) 2016-2022 |Meso|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
@@ -205,7 +205,6 @@ main(int argc, char** argv)
{
char dump[128];
struct time t0, t1;
- struct mem_allocator allocator;
struct solid* solid_param = NULL;
struct fluid* fluid_param = NULL;
struct interf* interf_param = NULL;
@@ -233,8 +232,7 @@ main(int argc, char** argv)
double x;
(void)argc, (void)argv;
- OK(mem_init_proxy_allocator(&allocator, &mem_default_allocator));
- OK(sdis_device_create(NULL, &allocator, SDIS_NTHREADS_DEFAULT, 1, &dev));
+ OK(sdis_device_create(&SDIS_DEVICE_CREATE_ARGS_DEFAULT, &dev));
/* Create the fluid medium */
fluid_shader.temperature = fluid_get_temperature;
@@ -259,7 +257,7 @@ main(int argc, char** argv)
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 = solid_get_delta;
+ solid_shader.delta = solid_get_delta;
solid_shader.temperature = solid_get_temperature;
solid_shader.volumic_power = solid_get_volumic_power;
@@ -413,8 +411,6 @@ main(int argc, char** argv)
OK(sdis_scene_ref_put(scn_3d));
OK(sdis_device_ref_put(dev));
- check_memory_allocator(&allocator);
- mem_shutdown_proxy_allocator(&allocator);
CHK(mem_allocated_size() == 0);
return 0;
}