commit cdc5ce0ec54aae65d91f333af868b5120e6643dc
parent 4f7a34d95ab77a42ec48189d3197ebc7b8e5d371
Author: Vincent Forest <vincent.forest@meso-star.com>
Date: Wed, 5 Jan 2022 14:26:21 +0100
Merge branch 'feature_mpi' into develop
Diffstat:
95 files changed, 4344 insertions(+), 1785 deletions(-)
diff --git a/README.md b/README.md
@@ -374,7 +374,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 |Meso|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)
@@ -61,6 +70,7 @@ set(VERSION_PATCH 3)
set(VERSION ${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_PATCH})
set(SDIS_FILES_SRC
+ sdis.c
sdis_camera.c
sdis_data.c
sdis_device.c
@@ -75,12 +85,15 @@ set(SDIS_FILES_SRC
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
@@ -107,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'
@@ -152,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)
###############################################################################
@@ -180,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)
@@ -195,22 +217,25 @@ if(NOT NO_TEST)
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)
@@ -228,7 +253,35 @@ 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)
-
+
+ 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()
@@ -242,4 +295,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,869 @@
+/* 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,
+ 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 = SSP_RNG_MT19937_64;
+ 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
@@ -130,6 +130,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
******************************************************************************/
@@ -570,7 +595,7 @@ struct sdis_solve_camera_args {
* higher orders allow the estimation of the T4 radiative transfer. */
size_t picard_order;
- size_t image_resolution[2]; /* Image resolution */
+ size_t image_definition[2]; /* Image definition */
size_t spp; /* #samples per pixel */
int register_paths; /* Combination of enum sdis_heat_path_flag */
};
@@ -608,10 +633,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
@@ -622,6 +644,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
@@ -1317,6 +1344,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
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,156 @@
+/* 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 <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,
+ 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
+
+ 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;
- 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 = 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;
- }
-
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
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
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
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
diff --git a/src/sdis_heat_path_boundary.c b/src/sdis_heat_path_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
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
diff --git a/src/sdis_heat_path_boundary_Xd_c.h b/src/sdis_heat_path_boundary_Xd_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_heat_path_boundary_Xd_fixed_flux.h b/src/sdis_heat_path_boundary_Xd_fixed_flux.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_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
@@ -231,8 +231,8 @@ XD(solid_fluid_boundary_picard1_path)
double p_radi; /* Radiative proba */
/* Indices of the registered vertex of the sampled radiative path */
- size_t ihvtx_radi_begin;
- size_t ihvtx_radi_end;
+ size_t ihvtx_radi_begin = 0;
+ size_t ihvtx_radi_end = 0;
r = ssp_rng_canonical(rng);
diff --git a/src/sdis_heat_path_boundary_Xd_solid_fluid_picardN.h b/src/sdis_heat_path_boundary_Xd_solid_fluid_picardN.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
@@ -214,8 +214,8 @@ XD(solid_fluid_boundary_picardN_path)
double T0, T1, T2, T3, T4, T5; /* Computed temperatures */
/* Indices of the registered vertex of the sampled radiative path */
- size_t ihvtx_radi_begin;
- size_t ihvtx_radi_end;
+ size_t ihvtx_radi_begin = 0;
+ size_t ihvtx_radi_end = 0;
r = ssp_rng_canonical(rng);
diff --git a/src/sdis_heat_path_boundary_Xd_solid_solid.h b/src/sdis_heat_path_boundary_Xd_solid_solid.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_heat_path_boundary_c.h b/src/sdis_heat_path_boundary_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_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
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
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
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,7 +67,7 @@ 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);
}
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
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
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
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>
@@ -163,4 +165,19 @@ time_rewind_3d
struct rwalk_3d* rwalk,
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
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
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
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
@@ -49,7 +49,7 @@ check_boundary_realisation_args(const struct boundary_realisation_args* args)
&& args->rng
&& args->uv[0] >= 0
&& args->uv[0] <= 1
- && args->uv[1] >= 0
+ && args->uv[1] >= 0
&& args->uv[1] <= 1
&& args->time >= 0
&& args->picard_order > 0
@@ -64,7 +64,7 @@ check_boundary_flux_realisation_args
&& args->rng
&& args->uv[0] >= 0
&& args->uv[0] <= 1
- && args->uv[1] >= 0
+ && args->uv[1] >= 0
&& args->uv[1] <= 1
&& args->time >= 0
&& args->picard_order > 0
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
@@ -542,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
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
@@ -243,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
@@ -257,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,
@@ -290,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,179 +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 */
- const size_t picard_order,
- 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 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 */
- 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 */
- const size_t picard_order,
- 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, picard_order, estimator);
- if(res != RES_OK) goto error;
- }
-
-exit:
- return res;
-error:
- goto exit;
-}
-
-/*******************************************************************************
* Exported functions
******************************************************************************/
res_T
@@ -336,182 +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,
- args->picard_order, 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,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,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,7 @@ 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
@@ -74,8 +76,43 @@ check_solve_boundary_args(const struct sdis_solve_boundary_args* args)
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;
+ }
+
+ 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)
{
@@ -117,66 +154,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) {
- 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(!out_estimator && !out_green) {
- res = RES_BAD_ARG;
- 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;
+ /* 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;
}
-#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
-
- 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",
@@ -186,6 +214,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);
@@ -221,60 +262,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, &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;
@@ -298,7 +338,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;
@@ -392,9 +433,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);
@@ -402,58 +443,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]));
+ /* 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, rngs);
}
- if(greens) {
- FOR_EACH(i, 0, scn->dev->nthreads) {
- if(greens[i]) SDIS(green_function_ref_put(greens[i]));
- }
- 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));
@@ -462,14 +527,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;
}
@@ -479,59 +538,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 */
@@ -569,43 +628,49 @@ 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, &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);
- nrealisations = args->nrealisations;
+ #define PROGRESS_MSG "Solving surface 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 = 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) {
@@ -613,13 +678,13 @@ XD(solve_boundary_flux)
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;
@@ -765,52 +830,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));
@@ -818,10 +908,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,699 @@
+/* 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;
+ }
+
+ 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, NULL, &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
@@ -165,6 +170,31 @@ check_solve_medium_args(const struct sdis_solve_medium_args* args)
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;
+ }
+
+ return RES_OK;
+}
+
#endif /* !SDIS_SOLVE_MEDIUM_XD_H */
/*******************************************************************************
@@ -234,35 +264,42 @@ 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) {
- 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_medium_args(args);
if(res != RES_OK) goto error;
-
- if(!out_estimator && !out_green) {
- res = RES_BAD_ARG;
- 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 "
@@ -273,38 +310,27 @@ XD(solve_medium)
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, &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);
@@ -313,32 +339,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;
@@ -358,11 +391,8 @@ XD(solve_medium)
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;
}
@@ -430,9 +460,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);
@@ -440,71 +470,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]));
+ /* 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, rngs);
}
- if(greens) {
- FOR_EACH(i, 0, scn->dev->nthreads) {
- if(greens[i]) SDIS(green_function_ref_put(greens[i]));
- }
- 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;
}
@@ -514,39 +562,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");
@@ -554,32 +603,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, &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 */
@@ -592,20 +636,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;
@@ -646,52 +703,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"
@@ -72,34 +73,41 @@ 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) {
- 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_probe_args(args);
if(res != RES_OK) goto error;
-
- if(!out_estimator && !out_green) {
- res = RES_BAD_ARG;
- 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 "
@@ -110,38 +118,27 @@ XD(solve_probe)
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, &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);
@@ -149,32 +146,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;
@@ -188,19 +192,18 @@ 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;
@@ -252,84 +255,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]));
+ /* 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, rngs);
}
- if(greens) {
- FOR_EACH(i, 0, scn->dev->nthreads) {
- if(greens[i]) SDIS(green_function_ref_put(greens[i]));
- }
- 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"
@@ -66,6 +69,34 @@ check_solve_probe_boundary_args
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;
+ }
+
+ return RES_OK;
+}
+
#endif /* SDIS_SOLVE_PROBE_BOUNDARY_XD_H */
/*******************************************************************************
@@ -78,33 +109,44 @@ 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) {
- 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_probe_boundary_args(args);
if(res != RES_OK) goto error;
-
- if(!out_estimator && !out_green) {
- res = RES_BAD_ARG;
- 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;
if(out_green && args->picard_order != 1) {
log_err(scn->dev, "%s: the evaluation of the green function does not make "
@@ -115,108 +157,63 @@ XD(solve_probe_boundary)
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
- /* 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;
- }
+ nthreads = scn->dev->nthreads;
+ allocator = scn->dev->allocator;
- /* 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;
- }
- }
-#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;
- }
+ /* Create the per thread RNGs */
+ res = create_per_thread_rng
+ (scn->dev, args->rng_state, &rng_proxy, &per_thread_rng);
+ 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;
- }
+ /* Allocate the per process progress status */
+ res = alloc_process_progress(scn->dev, &progress);
+ 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; }
+ /* 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;
@@ -235,11 +232,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;
}
@@ -302,9 +297,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:
@@ -313,70 +308,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;
}
@@ -386,86 +399,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,
@@ -477,37 +467,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, &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 */
+ /* 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 */
@@ -515,12 +498,23 @@ 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) {
@@ -528,13 +522,13 @@ XD(solve_probe_boundary_flux)
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__;
@@ -562,7 +556,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;
@@ -629,60 +624,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;
@@ -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
@@ -342,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;
@@ -360,7 +361,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, 1, &dev));
+ dev_args.allocator = &allocator;
+ OK(sdis_device_create(&dev_args, &dev));
/* Create the fluid medium */
fluid_shader.temperature = temperature_unknown;
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
@@ -363,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;
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));
@@ -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
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
@@ -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));
@@ -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
@@ -353,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;
@@ -373,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));
@@ -459,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");
@@ -470,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));
@@ -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
@@ -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
@@ -566,7 +566,6 @@ int
main(int argc, char** argv)
{
FILE* stream = NULL;
- struct mem_allocator allocator;
struct sdis_device* dev = NULL;
struct sdis_scene* scn_2d = NULL;
@@ -588,8 +587,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));
/* Solid medium */
solid_props.lambda = 1.15;
@@ -773,8 +771,6 @@ main(int argc, char** argv)
OK(sdis_device_ref_put(dev));
CHK(fclose(stream) == 0);
- check_memory_allocator(&allocator);
- mem_shutdown_proxy_allocator(&allocator);
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
@@ -468,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;
@@ -480,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));
@@ -497,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;
@@ -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;
@@ -201,10 +200,10 @@ main(int argc, char** argv)
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);
@@ -340,8 +339,10 @@ main(int argc, char** argv)
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);
+ }
BA(GREEN(NULL, &probe_args, &green));
BA(GREEN(box_scn, NULL, &green));
@@ -357,21 +358,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;
@@ -388,14 +396,16 @@ 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;
@@ -408,15 +418,17 @@ main(int argc, char** argv)
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
@@ -473,8 +485,10 @@ main(int argc, char** argv)
/* 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);
+ }
BA(GREEN(NULL, &bound_args, &green));
BA(GREEN(box_scn, NULL, &green));
@@ -499,14 +513,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;
@@ -519,8 +538,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;
@@ -532,25 +553,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;
@@ -565,36 +592,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;
@@ -604,28 +639,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
@@ -228,7 +228,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;
@@ -255,10 +254,10 @@ main(int argc, char** argv)
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
@@ -405,25 +404,31 @@ 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);
-
- 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));
+ 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);
+ OK(sdis_estimator_ref_put(estimator));
+ }
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
@@ -460,10 +465,14 @@ 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);
+ OK(sdis_estimator_ref_put(estimator));
+ }
/* Average temperature on the right side of the square */
prims[0] = 4;
@@ -471,9 +480,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
@@ -489,10 +500,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
@@ -540,7 +540,6 @@ 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;
@@ -570,10 +569,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;
@@ -611,14 +610,14 @@ main(int argc, char** argv)
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);
@@ -660,8 +659,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));
@@ -687,42 +686,46 @@ 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);
-
- 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));
+ 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));
+ }
pfluid_param = sdis_data_get(sdis_medium_get_data(fluid1));
pfluid_param->temperature = UNKOWN_TEMPERATURE;
@@ -740,11 +743,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
@@ -197,7 +197,6 @@ 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;
@@ -232,10 +231,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;
@@ -309,13 +308,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 +380,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 +404,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 +438,17 @@ 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));
+ }
/* Solve green */
BA(sdis_solve_medium_green_function(NULL, &solve_args, &green));
@@ -458,20 +467,23 @@ main(int argc, char** argv)
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));
@@ -480,9 +492,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;
@@ -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
@@ -279,6 +279,7 @@ 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;
@@ -304,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, 1, &dev));
+ dev_args.allocator = &allocator;
+ OK(sdis_device_create(&dev_args, &dev));
/* Create the fluid medium */
OK(sdis_data_create
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
@@ -18,6 +18,8 @@
#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,7 +147,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;
@@ -171,10 +172,10 @@ main(int argc, char** argv)
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;
@@ -253,39 +254,46 @@ 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 */
+ 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));
+ }
/* 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;
@@ -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;
@@ -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;
@@ -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
@@ -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
@@ -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;
@@ -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
@@ -703,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;
@@ -728,8 +727,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));
/* Setup the solid shader */
solid_shader.calorific_capacity = solid_get_calorific_capacity;
@@ -899,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);
@@ -916,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
@@ -480,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 */
@@ -198,6 +203,66 @@ static const struct sdis_interface_shader DUMMY_INTERFACE_SHADER = {
};
/*******************************************************************************
+ * 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
@@ -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));
@@ -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
@@ -302,8 +302,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;
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
@@ -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;
@@ -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
@@ -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;
@@ -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;
@@ -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;
}