stardis-solver

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

commit ef013176835b8e33141e87b7cb4c437454629824
parent db52f0b369426b18d4335b8a5c80c34ab7fb0704
Author: Vincent Forest <vincent.forest@meso-star.com>
Date:   Sat, 31 Mar 2018 12:05:53 +0200

Merge branch 'release_0.1'

Diffstat:
M.gitignore | 1+
MREADME.md | 14+++++++++++++-
Mcmake/CMakeLists.txt | 22++++++++++++++++++----
Msrc/sdis.h | 135++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-----
Asrc/sdis_accum_buffer.c | 160+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/sdis_camera.c | 138+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/sdis_camera.h | 60++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Msrc/sdis_device.c | 11++++++++++-
Msrc/sdis_device_c.h | 14++++++++++++++
Msrc/sdis_interface.c | 15++++++---------
Msrc/sdis_interface_c.h | 18++++++++++++++++++
Msrc/sdis_scene.c | 1+
Msrc/sdis_scene_c.h | 2++
Asrc/sdis_solve.c | 405+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/sdis_solve_Xd.h | 841+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Dsrc/sdis_solve_probe.c | 138-------------------------------------------------------------------------------
Dsrc/sdis_solve_probe_Xd.h | 565-------------------------------------------------------------------------------
Asrc/test_sdis_accum_buffer.c | 77+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/test_sdis_camera.c | 94+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/test_sdis_conducto_radiative.c | 430+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/test_sdis_conducto_radiative_2d.c | 405+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Msrc/test_sdis_interface.c | 9++++++++-
Asrc/test_sdis_solve_camera.c | 623+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Msrc/test_sdis_solve_probe.c | 35+++++++++++++++++++++++++++++------
Msrc/test_sdis_solve_probe2.c | 16+++++++++++-----
Msrc/test_sdis_solve_probe2_2d.c | 16+++++++++++-----
Msrc/test_sdis_solve_probe3.c | 20++++++++++++++------
Msrc/test_sdis_solve_probe3_2d.c | 19+++++++++++++------
Msrc/test_sdis_solve_probe_2d.c | 12+++++++++++-
Msrc/test_sdis_utils.h | 10++++++++--
30 files changed, 3548 insertions(+), 758 deletions(-)

diff --git a/.gitignore b/.gitignore @@ -1,3 +1,4 @@ +compile_commands.json .gitignore CMakeCache.txt CMakeFiles diff --git a/README.md b/README.md @@ -1,7 +1,7 @@ # Stardis The purpose of this library is to solve coupled convecto - conducto - radiative -thermal problems. +thermal problems in 2D and 3D environments. ## How to build @@ -23,6 +23,18 @@ variable the install directories of its dependencies. ## Release notes +### Version 0.1 + +- Add the support of radiative temperature. +- Add the `sdis_camera` API : it defines a pinhole camera into the scene. +- Add the `sdis_accum_buffer` API : it is a pool of MC accumulators, i.e. a sum + of MC weights and square weights. +- Add the `sdis_solve_camera` function : it relies on a `sdis_camera` and a + `sdis_accum_buffer` to compute the radiative temperature that reaches each + pixel of an image whose definition is defined by the caller. Note that + actually this function uses the same underlying MC algorithm behind the + `sdis_solve_probe` function. + ### Version 0.0 First version and implementation of the Stardis solver API. diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt @@ -40,28 +40,32 @@ rcmake_append_runtime_dirs(_runtime_dirs RSys Star3D StarSP) # Configure and define targets ################################################################################ set(VERSION_MAJOR 0) -set(VERSION_MINOR 0) +set(VERSION_MINOR 1) set(VERSION_PATCH 0) set(VERSION ${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_PATCH}) set(SDIS_FILES_SRC + sdis_accum_buffer.c + sdis_camera.c sdis_data.c sdis_device.c sdis_estimator.c sdis_interface.c sdis_medium.c sdis_scene.c - sdis_solve_probe.c) + sdis_solve.c) set(SDIS_FILES_INC_API sdis.h) set(SDIS_FILES_INC + sdis_camera.h sdis_device_c.h sdis_estimator_c.h sdis_interface_c.h sdis_medium_c.h - sdis_scene_c.h) + sdis_scene_c.h + sdis_solve_Xd.h) set(SDIS_FILES_DOC COPYING README.md) @@ -75,7 +79,10 @@ add_library(sdis SHARED ${SDIS_FILES_SRC} ${SDIS_FILES_INC} ${SDIS_FILES_INC_API}) -target_link_libraries(sdis RSys Star2D Star3D StarSP) +target_link_libraries(sdis RSys Star2D Star3D StarSP m) +if(CMAKE_COMPILER_IS_GNUCC) + target_link_libraries(sdis m) +endif() set_target_properties(sdis PROPERTIES DEFINE_SYMBOL SDIS_SHARED_BUILD @@ -111,11 +118,16 @@ if(NOT NO_TEST) register_test(${_name} ${_name}) endfunction() + new_test(test_sdis_accum_buffer) + new_test(test_sdis_camera) + new_test(test_sdis_conducto_radiative) + new_test(test_sdis_conducto_radiative_2d) new_test(test_sdis_data) new_test(test_sdis_device) new_test(test_sdis_interface) new_test(test_sdis_medium) new_test(test_sdis_scene) + new_test(test_sdis_solve_camera) new_test(test_sdis_solve_probe) new_test(test_sdis_solve_probe2) new_test(test_sdis_solve_probe3) @@ -124,6 +136,8 @@ if(NOT NO_TEST) new_test(test_sdis_solve_probe3_2d) target_link_libraries(test_sdis_solve_probe3 Star3DUT) + target_link_libraries(test_sdis_solve_camera Star3DUT) + if(CMAKE_COMPILER_IS_GNUCC) target_link_libraries(test_sdis_solve_probe3_2d m) endif() diff --git a/src/sdis.h b/src/sdis.h @@ -51,6 +51,8 @@ struct mem_allocator; * a reference on the data, i.e. they increment or decrement the reference * counter, respectively. When this counter reaches 0, the object is silently * destroyed and cannot be used anymore. */ +struct sdis_accum_buffer; +struct sdis_camera; struct sdis_data; struct sdis_device; struct sdis_estimator; @@ -91,6 +93,13 @@ struct sdis_interface_fragment { static const struct sdis_interface_fragment SDIS_INTERFACE_FRAGMENT_NULL = SDIS_INTERFACE_FRAGMENT_NULL__; +/* Monte-Carlo accumulator */ +struct sdis_accum { + double sum_weights; /* Sum of Monte-Carlo weight */ + double sum_weights_sqr; /* Sum of Monte-Carlo square weights */ + size_t nweights; /* #accumulated weights */ +}; + /* Monte-Carlo estimation */ struct sdis_mc { double E; /* Expected value */ @@ -124,7 +133,7 @@ struct sdis_solid_shader { * unknown for the submitted random walk vertex. */ sdis_medium_getter_T temperature; }; -#define SDIS_SOLID_SHADER_NULL__ {NULL} +#define SDIS_SOLID_SHADER_NULL__ {NULL, NULL, NULL, NULL, NULL, NULL} static const struct sdis_solid_shader SDIS_SOLID_SHADER_NULL = SDIS_SOLID_SHADER_NULL__; @@ -137,18 +146,38 @@ struct sdis_fluid_shader { * unknown for the submitted position and time. */ sdis_medium_getter_T temperature; }; -#define SDIS_FLUID_SHADER_NULL__ {NULL} +#define SDIS_FLUID_SHADER_NULL__ {NULL, NULL, NULL} static const struct sdis_fluid_shader SDIS_FLUID_SHADER_NULL = SDIS_FLUID_SHADER_NULL__; struct sdis_interface_shader { sdis_interface_getter_T temperature; /* Limit condition. NULL <=> Unknown */ - sdis_interface_getter_T convection_coef; /* NULL <=> Solid/Solid interface */ + sdis_interface_getter_T convection_coef; /* May be NULL for solid/solid */ + + /* Interface emssivity. May be NULL for solid/solid interface */ + sdis_interface_getter_T emissivity; /* Overall emissivity */ + sdis_interface_getter_T specular_fraction; /* Specular fraction in [0, 1] */ }; -#define SDIS_INTERFACE_SHADER_NULL__ {NULL} +#define SDIS_INTERFACE_SHADER_NULL__ {NULL, NULL, NULL, NULL} static const struct sdis_interface_shader SDIS_INTERFACE_SHADER_NULL = SDIS_INTERFACE_SHADER_NULL__; +struct sdis_accum_buffer_layout { + size_t width; + size_t height; +}; +#define SDIS_ACCUM_BUFFER_LAYOUT_NULL__ {0, 0} +static const struct sdis_accum_buffer_layout SDIS_ACCUM_BUFFER_LAYOUT_NULL = + SDIS_ACCUM_BUFFER_LAYOUT_NULL__; + +/* Functor use to write accumulations performed by sdis_solve_camera */ +typedef res_T +(*sdis_write_accums_T) + (void* context, /* User data */ + const size_t origin[2], /* Coordinates of the 1st accumulation in image plane */ + const size_t naccums[2], /* #accumulations in X and Y */ + const struct sdis_accum* accums); /* List of row ordered accumulations */ + BEGIN_DECLS /******************************************************************************* @@ -200,6 +229,80 @@ sdis_data_cget (const struct sdis_data* data); /******************************************************************************* + * A camera describes a point of view + ******************************************************************************/ +SDIS_API res_T +sdis_camera_create + (struct sdis_device* dev, + struct sdis_camera** cam); + +SDIS_API res_T +sdis_camera_ref_get + (struct sdis_camera* cam); + +SDIS_API res_T +sdis_camera_ref_put + (struct sdis_camera* cam); + +/* Width/height projection ratio */ +SDIS_API res_T +sdis_camera_set_proj_ratio + (struct sdis_camera* cam, + const double proj_ratio); + +SDIS_API res_T +sdis_camera_set_fov /* Horizontal field of view */ + (struct sdis_camera* cam, + const double fov); /* In radian */ + +SDIS_API res_T +sdis_camera_look_at + (struct sdis_camera* cam, + const double position[3], + const double target[3], + const double up[3]); + +/******************************************************************************* + * A buffer of accumulations + ******************************************************************************/ +SDIS_API res_T +sdis_accum_buffer_create + (struct sdis_device* dev, + const size_t width, + const size_t height, + struct sdis_accum_buffer** buf); + +SDIS_API res_T +sdis_accum_buffer_ref_get + (struct sdis_accum_buffer* buf); + +SDIS_API res_T +sdis_accum_buffer_ref_put + (struct sdis_accum_buffer* buf); + +SDIS_API res_T +sdis_accum_buffer_get_layout + (const struct sdis_accum_buffer* buf, + struct sdis_accum_buffer_layout* layout); + +SDIS_API res_T +sdis_accum_buffer_map + (const struct sdis_accum_buffer* buf, + const struct sdis_accum** accums); + +SDIS_API res_T +sdis_accum_buffer_unmap + (const struct sdis_accum_buffer* buf); + +/* Helper function that matches the `sdis_write_accums_T' functor type */ +SDIS_API res_T +sdis_accum_buffer_write + (void* buf, /* User data */ + const size_t origin[2], /* Coordinates of the 1st accum in image plane */ + const size_t naccum[2], /* #accum in X and Y */ + const struct sdis_accum* accums); /* List of row ordered accum */ + +/******************************************************************************* * A medium encapsulates the properties of either a fluid or a solid. ******************************************************************************/ SDIS_API res_T @@ -327,12 +430,28 @@ sdis_estimator_get_temperature SDIS_API res_T sdis_solve_probe (struct sdis_scene* scn, - const size_t nrealisations, - const double position[3], - const double time, - const double fp_to_meter,/* Scale from floating point units to meters */ + const size_t nrealisations, /* #realisations */ + const double position[3], /* Probe position */ + const double time, /* Observation time */ + const double fp_to_meter, /* Scale from floating point units to meters */ + const double ambient_radiative_temperature, /* In Kelvin */ + const double reference_temperature, /* In Kelvin */ struct sdis_estimator** estimator); +SDIS_API res_T +sdis_solve_camera + (struct sdis_scene* scn, + const struct sdis_camera* cam, /* Point of view */ + const double time, /* Observation time */ + const double fp_to_meter, /* Scale from floating point units to meters */ + const double ambient_radiative_temperature, /* In Kelvin */ + const double reference_temperature, /* In Kelvin */ + const size_t width, /* Image definition in in X */ + const size_t height, /* Image definition in Y */ + const size_t spp, /* #samples per pixel */ + sdis_write_accums_T writer, + void* writer_data); + END_DECLS #endif /* SDIS_H */ diff --git a/src/sdis_accum_buffer.c b/src/sdis_accum_buffer.c @@ -0,0 +1,160 @@ +/* Copyright (C) |Meso|Star> 2016-2018 (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_device_c.h" + +struct sdis_accum_buffer { + struct sdis_accum* accums; + size_t width; + size_t height; + + ref_T ref; + struct sdis_device* dev; +}; + +/******************************************************************************* + * Helper functions + ******************************************************************************/ +static void +accum_buffer_release(ref_T* ref) +{ + struct sdis_accum_buffer* buf; + struct sdis_device* dev; + ASSERT(ref); + buf = CONTAINER_OF(ref, struct sdis_accum_buffer, ref); + dev = buf->dev; + if(buf->accums) MEM_RM(dev->allocator, buf->accums); + MEM_RM(dev->allocator, buf); + SDIS(device_ref_put(dev)); +} + +/******************************************************************************* + * Export functions + ******************************************************************************/ +res_T +sdis_accum_buffer_create + (struct sdis_device* dev, + const size_t width, + const size_t height, + struct sdis_accum_buffer** out_buf) +{ + struct sdis_accum_buffer* buf = NULL; + size_t sz; + res_T res = RES_OK; + + if(!dev || !width || !height || !out_buf) { + res = RES_BAD_ARG; + goto error; + } + + buf = MEM_CALLOC(dev->allocator, 1, sizeof(struct sdis_accum_buffer)); + if(!buf) { + res = RES_MEM_ERR; + goto error; + } + ref_init(&buf->ref); + SDIS(device_ref_get(dev)); + buf->dev = dev; + buf->width = width; + buf->height = height; + + sz = buf->width * buf->height * sizeof(struct sdis_accum); + buf->accums = MEM_ALLOC_ALIGNED(dev->allocator, sz, 16); + if(!buf->accums) { + log_err(dev, "%s: could not allocate a buffer accumulations of %lux%lu.\n", + FUNC_NAME, (unsigned long)width, (unsigned long)height); + res = RES_MEM_ERR; + goto error; + } + +exit: + if(out_buf) *out_buf = buf; + return res; +error: + if(buf) { + SDIS(accum_buffer_ref_put(buf)); + buf = NULL; + } + goto exit; +} + +res_T +sdis_accum_buffer_ref_get(struct sdis_accum_buffer* buf) +{ + if(!buf) return RES_BAD_ARG; + ref_get(&buf->ref); + return RES_OK; +} + +res_T +sdis_accum_buffer_ref_put(struct sdis_accum_buffer* buf) +{ + if(!buf) return RES_BAD_ARG; + ref_put(&buf->ref, accum_buffer_release); + return RES_OK; +} + +res_T +sdis_accum_buffer_get_layout + (const struct sdis_accum_buffer* buf, + struct sdis_accum_buffer_layout* layout) +{ + if(!buf || !layout) return RES_BAD_ARG; + layout->width = buf->width; + layout->height = buf->height; + return RES_OK; +} + +res_T +sdis_accum_buffer_map + (const struct sdis_accum_buffer* buf, const struct sdis_accum** accums) +{ + if(!buf || !accums) return RES_BAD_ARG; + *accums = buf->accums; + return RES_OK; +} + +res_T +sdis_accum_buffer_unmap(const struct sdis_accum_buffer* buf) +{ + if(!buf) return RES_BAD_ARG; + /* Do nothing */ + return RES_OK; +} + +res_T +sdis_accum_buffer_write + (void* buffer, + const size_t origin[2], + const size_t size[2], + const struct sdis_accum* accums) +{ + struct sdis_accum_buffer* buf = buffer; + const struct sdis_accum* src_row = accums; + size_t dst_iy; + + if(UNLIKELY(!buffer || !origin || !size || !accums)) return RES_BAD_ARG; + if(UNLIKELY((origin[0] + size[0]) > buf->width)) return RES_BAD_ARG; + if(UNLIKELY((origin[1] + size[1]) > buf->height)) return RES_BAD_ARG; + + FOR_EACH(dst_iy, origin[1], origin[1] + size[1]) { + const size_t dst_irow = dst_iy*buf->width + origin[0]; + memcpy(buf->accums + dst_irow, src_row, size[0] * sizeof(struct sdis_accum)); + src_row += size[0]; + } + return RES_OK; +} + diff --git a/src/sdis_camera.c b/src/sdis_camera.c @@ -0,0 +1,138 @@ +/* Copyright (C) |Meso|Star> 2016-2018 (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_camera.h" +#include "sdis_device_c.h" + +#include <rsys/mem_allocator.h> + +/******************************************************************************* + * Helper functions + ******************************************************************************/ +static void +camera_release(ref_T* ref) +{ + struct sdis_camera* cam = CONTAINER_OF(ref, struct sdis_camera, ref); + struct sdis_device* dev; + ASSERT(ref); + dev = cam->dev; + MEM_RM(dev->allocator, cam); + SDIS(device_ref_put(dev)); +} + +/******************************************************************************* + * Exported functions + ******************************************************************************/ +res_T +sdis_camera_create(struct sdis_device* dev, struct sdis_camera** out_cam) +{ + const double pos[3] = {0, 0, 0}; + const double tgt[3] = {0, 0,-1}; + const double up[3] = {0, 1, 0}; + struct sdis_camera* cam = NULL; + res_T res = RES_OK; + + if(!dev || !out_cam) { + res = RES_BAD_ARG; + goto error; + } + + cam = MEM_CALLOC(dev->allocator, 1, sizeof(struct sdis_camera)); + if(!cam) { + res = RES_MEM_ERR; + goto error; + } + SDIS(device_ref_get(dev)); + cam->dev = dev; + ref_init(&cam->ref); + cam->rcp_proj_ratio = 1.0; + cam->fov_x = PI/2.0; + SDIS(camera_look_at(cam, pos, tgt, up)); + +exit: + if(out_cam) *out_cam = cam; + return res; +error: + if(cam) { + SDIS(camera_ref_put(cam)); + cam = NULL; + } + goto exit; +} + +res_T +sdis_camera_ref_get(struct sdis_camera* cam) +{ + if(!cam) return RES_BAD_ARG; + ref_get(&cam->ref); + return RES_OK; +} + +res_T +sdis_camera_ref_put(struct sdis_camera* cam) +{ + if(!cam) return RES_BAD_ARG; + ref_put(&cam->ref, camera_release); + return RES_OK; +} + +res_T +sdis_camera_set_proj_ratio(struct sdis_camera* cam, const double ratio) +{ + double y[3] = {0}; + if(!cam || ratio <= 0) return RES_BAD_ARG; + if(d3_normalize(y, cam->axis_y) <= 0) return RES_BAD_ARG; + cam->rcp_proj_ratio = 1.0 / ratio; + d3_muld(cam->axis_y, y, cam->rcp_proj_ratio); + return RES_OK; +} + +res_T +sdis_camera_set_fov(struct sdis_camera* cam, const double fov_x) +{ + double z[3] = {0}; + double img_plane_depth; + if(!cam || (float)fov_x <= 0) return RES_BAD_ARG; + if(d3_normalize(z, cam->axis_z) <= 0) return RES_BAD_ARG; + img_plane_depth = 1.0/tan(fov_x*0.5); + d3_muld(cam->axis_z, z, img_plane_depth); + cam->fov_x = fov_x; + return RES_OK; +} + +res_T +sdis_camera_look_at + (struct sdis_camera* cam, + const double pos[3], + const double tgt[3], + const double up[3]) +{ + double x[3], y[3], z[3]; + double img_plane_depth; + if(!cam || !pos || !tgt || !up) return RES_BAD_ARG; + + if(d3_normalize(z, d3_sub(z, tgt, pos)) <= 0) return RES_BAD_ARG; + if(d3_normalize(x, d3_cross(x, z, up)) <= 0) return RES_BAD_ARG; + if(d3_normalize(y, d3_cross(y, z, x)) <= 0) return RES_BAD_ARG; + img_plane_depth = 1.0/tan(cam->fov_x*0.5); + + d3_set(cam->axis_x, x); + d3_muld(cam->axis_y, y, cam->rcp_proj_ratio); + d3_muld(cam->axis_z, z, img_plane_depth); + d3_set(cam->position, pos); + return RES_OK; +} + diff --git a/src/sdis_camera.h b/src/sdis_camera.h @@ -0,0 +1,60 @@ +/* Copyright (C) |Meso|Star> 2016-2018 (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_CAMERA_H +#define SDIS_CAMERA_H + +#include <rsys/double3.h> +#include <rsys/ref_count.h> + +struct sdis_device; + +struct sdis_camera { + /* Orthogonal camera frame */ + double axis_x[3]; + double axis_y[3]; + double axis_z[3]; + + double position[3]; + double fov_x; /* Field of view in radians */ + double rcp_proj_ratio; /* height / width */ + + ref_T ref; + struct sdis_device* dev; +}; + +static FINLINE void +camera_ray + (const struct sdis_camera* cam, + const double sample[2], /* In [0, 1[ */ + double org[3], + double dir[3]) +{ + double x[3], y[3], len; + (void)len; /* Avoid warning in debug */ + ASSERT(cam && sample && org && dir); + ASSERT(sample[0] >= 0.0 || sample[0] < 1.0); + ASSERT(sample[1] >= 0.0 || sample[1] < 1.0); + + d3_muld(x, cam->axis_x, sample[0]*2.0 - 1.0); + d3_muld(y, cam->axis_y, sample[1]*2.0 - 1.0); + d3_add(dir, d3_add(dir, x, y), cam->axis_z); + len = d3_normalize(dir, dir); + ASSERT(len >= 1.e-6); + d3_set(org, cam->position); +} + +#endif /* SDIS_CAMERA_H */ + diff --git a/src/sdis_device.c b/src/sdis_device.c @@ -52,6 +52,7 @@ device_release(ref_T* ref) if(dev->s3d) S3D(device_ref_put(dev->s3d)); ASSERT(flist_name_is_empty(&dev->names)); flist_name_release(&dev->names); + darray_tile_release(&dev->tiles); MEM_RM(dev->allocator, dev); } @@ -94,11 +95,19 @@ sdis_device_create dev->nthreads = MMIN(nthreads_hint, (unsigned)omp_get_num_procs()); ref_init(&dev->ref); flist_name_init(allocator, &dev->names); + darray_tile_init(allocator, &dev->tiles); + + res = darray_tile_resize(&dev->tiles, dev->nthreads); + if(res != RES_OK) { + log_err(dev, + "%s: could not allocate the per thread buffer of estimations.\n", FUNC_NAME); + goto error; + } res = s2d_device_create(log, allocator, 0, &dev->s2d); if(res != RES_OK) { log_err(dev, - "%s, could not create the Star-2D device on Stardis.\n", FUNC_NAME); + "%s: could not create the Star-2D device on Stardis.\n", FUNC_NAME); } res = s3d_device_create(log, allocator, 0, &dev->s3d); diff --git a/src/sdis_device_c.h b/src/sdis_device_c.h @@ -16,6 +16,7 @@ #ifndef SDIS_DEVICE_C_H #define SDIS_DEVICE_C_H +#include <rsys/dynamic_array.h> #include <rsys/free_list.h> #include <rsys/ref_count.h> @@ -23,6 +24,18 @@ struct name { FITEM; }; #define FITEM_TYPE name #include <rsys/free_list.h> +#define DARRAY_NAME accum +#define DARRAY_DATA struct sdis_accum +#include <rsys/dynamic_array.h> + +#define DARRAY_NAME tile +#define DARRAY_DATA struct darray_accum +#define DARRAY_FUNCTOR_INIT darray_accum_init +#define DARRAY_FUNCTOR_RELEASE darray_accum_release +#define DARRAY_FUNCTOR_COPY darray_accum_copy +#define DARRAY_FUNCTOR_COPY_AND_RELEASE darray_accum_copy_and_release +#include <rsys/dynamic_array.h> + struct sdis_device { struct logger* logger; struct mem_allocator* allocator; @@ -30,6 +43,7 @@ struct sdis_device { int verbose; struct flist_name names; + struct darray_tile tiles; struct s2d_device* s2d; struct s3d_device* s3d; diff --git a/src/sdis_interface.c b/src/sdis_interface.c @@ -41,15 +41,12 @@ check_interface_shader type1 = sdis_medium_get_type(back); /* Fluid<->solid interface */ - if(type0 != type1 && shader->convection_coef == NULL) { - return 0; - } - - /* Solid<->solid interface */ - if(type0 == SDIS_MEDIUM_SOLID - && type1 == SDIS_MEDIUM_SOLID - && shader->convection_coef) { - return 0; + if(type0 != type1) { + if(shader->convection_coef == NULL + || shader->emissivity == NULL + || shader->specular_fraction == NULL) { + return 0; + } } return 1; diff --git a/src/sdis_interface_c.h b/src/sdis_interface_c.h @@ -76,5 +76,23 @@ interface_get_convection_coef return interf->shader.convection_coef(frag, interf->data); } +static INLINE double +interface_get_emissivity + (const struct sdis_interface* interf, + const struct sdis_interface_fragment* frag) +{ + ASSERT(interf && frag); + return interf->shader.emissivity(frag, interf->data); +} + +static INLINE double +interface_get_specular_fraction + (const struct sdis_interface* interf, + const struct sdis_interface_fragment* frag) +{ + ASSERT(interf && frag); + return interf->shader.specular_fraction(frag, interf->data); +} + #endif /* SDIS_INTERFACE_C_H */ diff --git a/src/sdis_scene.c b/src/sdis_scene.c @@ -361,6 +361,7 @@ scene_create ref_init(&scn->ref); SDIS(device_ref_get(dev)); scn->dev = dev; + scn->ambient_radiative_temperature = -1; darray_interf_init(dev->allocator, &scn->interfaces); darray_interf_init(dev->allocator, &scn->prim_interfaces); diff --git a/src/sdis_scene_c.h b/src/sdis_scene_c.h @@ -40,6 +40,8 @@ struct sdis_scene { struct s2d_scene_view* s2d_view; struct s3d_scene_view* s3d_view; + double ambient_radiative_temperature; /* In Kelvin */ + ref_T ref; struct sdis_device* dev; }; diff --git a/src/sdis_solve.c b/src/sdis_solve.c @@ -0,0 +1,405 @@ +/* Copyright (C) |Meso|Star> 2016-2018 (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_camera.h" +#include "sdis_device_c.h" +#include "sdis_estimator_c.h" +#include "sdis_solve_Xd.h" + +/* Generate the 2D solver */ +#define SDIS_SOLVE_DIMENSION 2 +#include "sdis_solve_Xd.h" + +/* Generate the 3D solver */ +#define SDIS_SOLVE_DIMENSION 3 +#include "sdis_solve_Xd.h" + +#include <star/ssp.h> +#include <omp.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, + const struct sdis_medium* mdm, + const struct sdis_camera* cam, + const double time, /* Observation time */ + const double fp_to_meter, /* Scale from floating point units to meters */ + const double Tarad, /* In Kelvin */ + const double Tref, /* In Kelvin */ + const size_t ipix[2], /* Pixel coordinate in the image plane */ + const size_t nrealisations, + const double pix_sz[2], /* Pixel size in the normalized image plane */ + struct sdis_accum* accum) +{ + double sum_weights = 0; + double sum_weights_sqr = 0; + size_t N = 0; /* #realisations that do not fail */ + 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); + + FOR_EACH(irealisation, 0, nrealisations) { + double samp[2]; /* Pixel sample */ + double ray_pos[3]; + double ray_dir[3]; + double w = 0; + + /* Generate a sample into the pixel to estimate */ + samp[0] = ((double)ipix[0] + ssp_rng_canonical(rng)) * pix_sz[0]; + samp[1] = ((double)ipix[1] + ssp_rng_canonical(rng)) * pix_sz[1]; + + /* Generate a ray starting from the camera position and passing through + * pixel sample */ + camera_ray(cam, samp, ray_pos, ray_dir); + + /* Launch the realisation */ + res = ray_realisation_3d(scn, rng, mdm, ray_pos, ray_dir, + time, fp_to_meter, Tarad, Tref, &w); + if(res == RES_OK) { + sum_weights += w; + sum_weights_sqr += w*w; + ++N; + } else if(res != RES_BAD_OP) { + goto error; + } + } + + accum->sum_weights = sum_weights; + accum->sum_weights_sqr = sum_weights_sqr; + accum->nweights = N; + +exit: + return res; +error: + goto exit; +} + +static res_T +solve_tile + (struct sdis_scene* scn, + struct ssp_rng* rng, + const struct sdis_medium* mdm, + const struct sdis_camera* cam, + const double time, + const double fp_to_meter, + const double Tarad, + const double Tref, + 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 double pix_sz[2], /* Pixel size in the normalized image plane */ + struct sdis_accum* accums) +{ + size_t mcode; /* Morton code of the tile pixel */ + size_t npixels; + res_T res = RES_OK; + ASSERT(scn && rng && mdm && cam && spp && origin && accums); + ASSERT(size &&size[0] && size[1]); + ASSERT(pix_sz && pix_sz[0] > 0 && pix_sz[1] > 0); + + /* 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_accum* accum; + + 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; + + accum = accums + ipix[1]*size[0] + ipix[0]; + ipix[0] = ipix[0] + origin[0]; + ipix[1] = ipix[1] + origin[1]; + + res = solve_pixel(scn, rng, mdm, cam, time, fp_to_meter, Tarad, Tref, ipix, + spp, pix_sz, accum); + if(res != RES_OK) goto error; + } + +exit: + return res; +error: + goto exit; +} + +/******************************************************************************* + * Exported functions + ******************************************************************************/ +res_T +sdis_solve_probe + (struct sdis_scene* scn, + const size_t nrealisations, + const double position[3], + const double time, + const double fp_to_meter,/* Scale factor from floating point unit to meter */ + const double Tarad, /* Ambient radiative temperature */ + const double Tref, /* Reference temperature */ + struct sdis_estimator** out_estimator) +{ + const struct sdis_medium* medium = NULL; + struct sdis_estimator* estimator = NULL; + struct ssp_rng_proxy* rng_proxy = NULL; + struct ssp_rng** rngs = NULL; + double weight = 0; + double sqr_weight = 0; + size_t irealisation = 0; + size_t N = 0; /* #realisations that do not fail */ + size_t i; + ATOMIC res = RES_OK; + + if(!scn || !nrealisations || !position || time < 0 || fp_to_meter <= 0 + || Tref < 0 || !out_estimator) { + 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; + } + + /* Create the estimator */ + res = estimator_create(scn->dev, &estimator); + if(res != RES_OK) goto error; + + /* Retrieve the medium in which the submitted position lies */ + res = scene_get_medium(scn, position, &medium); + if(res != RES_OK) goto error; + + /* Here we go! Launch the Monte Carlo estimation */ + #pragma omp parallel for schedule(static) reduction(+:weight,sqr_weight,N) + for(irealisation = 0; irealisation < nrealisations; ++irealisation) { + res_T res_local; + double w; + const int ithread = omp_get_thread_num(); + struct ssp_rng* rng = rngs[ithread]; + + if(ATOMIC_GET(&res) != RES_OK) continue; /* An error occured */ + + if(scene_is_2d(scn)) { + res_local = probe_realisation_2d + (scn, rng, medium, position, time, fp_to_meter, Tarad, Tref, &w); + } else { + res_local = probe_realisation_3d + (scn, rng, medium, position, time, fp_to_meter, Tarad, Tref, &w); + } + if(res_local != RES_OK) { + if(res_local != RES_BAD_OP) { + ATOMIC_SET(&res, res_local); + continue; + } + } else { + weight += w; + sqr_weight += w*w; + ++N; + } + } + + estimator->nrealisations = N; + estimator->nfailures = nrealisations - N; + estimator->temperature.E = weight / (double)N; + estimator->temperature.V = + sqr_weight / (double)N + - estimator->temperature.E * estimator->temperature.E; + estimator->temperature.SE = sqrt(estimator->temperature.V / (double)N); + +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_estimator) *out_estimator = estimator; + return (res_T)res; +error: + if(estimator) { + SDIS(estimator_ref_put(estimator)); + estimator = NULL; + } + goto exit; +} + +res_T +sdis_solve_camera + (struct sdis_scene* scn, + const struct sdis_camera* cam, + const double time, + const double fp_to_meter, /* Scale from floating point units to meters */ + const double Tarad, /* In Kelvin */ + const double Tref, /* In Kelvin */ + const size_t width, /* #pixels in X */ + const size_t height, /* #pixels in Y */ + const size_t spp, /* #samples per pixel */ + sdis_write_accums_T writer, + void* writer_data) +{ + #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); + + const struct sdis_medium* medium = NULL; + struct darray_accum* tiles = 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 i; + ATOMIC res = RES_OK; + + if(!scn || !cam || time < 0 || fp_to_meter <= 0 || Tref < 0 || !width + || !height || !spp || !writer) { + 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, cam->position, &medium); + if(res != RES_OK) goto error; + + if(medium->type != SDIS_MEDIUM_FLUID) { + log_err(scn->dev, "%s: the camera position `%g %g %g' is not in a fluid.\n", + FUNC_NAME, SPLIT3(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; + } + + /* Allocate per thread buffer of accumulations */ + tiles = darray_tile_data_get(&scn->dev->tiles); + ASSERT(darray_tile_size_get(&scn->dev->tiles) == scn->dev->nthreads); + FOR_EACH(i, 0, scn->dev->nthreads) { + const size_t naccums = TILE_SIZE * TILE_SIZE; + res = darray_accum_resize(tiles+i, naccums); + if(res != RES_OK) goto error; + } + + ntiles_x = (width + (TILE_SIZE-1)/*ceil*/)/TILE_SIZE; + ntiles_y = (height + (TILE_SIZE-1)/*ceil*/)/TILE_SIZE; + ntiles = round_up_pow2(MMAX(ntiles_x, ntiles_y)); + ntiles *= ntiles; + + pix_sz[0] = 1.0 / (double)width; + pix_sz[1] = 1.0 / (double)height; + + omp_set_num_threads((int)scn->dev->nthreads); + #pragma omp parallel for schedule(static, 1/*chunki 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 sdis_accum* accums = NULL; + struct ssp_rng* rng = rngs[ithread]; + 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, width - tile_org[0]); + tile_sz[1] = MMIN(TILE_SIZE, width - tile_org[1]); + + /* Fetch the accumulations buffer */ + accums = darray_accum_data_get(tiles+ithread); + + /* Draw the tile */ + res_local = solve_tile(scn, rng, medium, cam, time, fp_to_meter, Tarad, + Tref, tile_org, tile_sz, spp, pix_sz, accums); + if(res_local != RES_OK) { + ATOMIC_SET(&res, res_local); + continue; + } + + /* Write the accumulations */ + res_local = writer(writer_data, tile_org, tile_sz, accums); + if(res_local != RES_OK) { + ATOMIC_SET(&res, res_local); + continue; + } + } + +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)); + return (res_T)res; +error: + goto exit; +} + diff --git a/src/sdis_solve_Xd.h b/src/sdis_solve_Xd.h @@ -0,0 +1,841 @@ +/* Copyright (C) |Meso|Star> 2016-2018 (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_SOLVE_DIMENSION +#ifndef SDIS_SOLVE_XD_H +#define SDIS_SOLVE_XD_H + +#include "sdis_device_c.h" +#include "sdis_interface_c.h" +#include "sdis_medium_c.h" +#include "sdis_scene_c.h" + +#include <rsys/stretchy_array.h> + +#include <star/ssp.h> + +/* Emperical scale factor to apply to the upper bound of the ray range in order + * to handle numerical imprecisions */ +#define RAY_RANGE_MAX_SCALE 1.0001f + +#define BOLTZMANN_CONSTANT 5.6696e-8 /* W/m^2/K^4 */ + +struct rwalk_context { + double Tarad; /* Ambient radiative temperature */ + double Tref3; /* Reference temperature ^ 3 */ +}; + +/* Reflect the vector V wrt the normal N. By convention V points outward the + * surface. */ +static INLINE float* +reflect(float res[3], const float V[3], const float N[3]) +{ + float tmp[3]; + float cos_V_N; + ASSERT(res && V && N); + ASSERT(f3_is_normalized(V) && f3_is_normalized(N)); + cos_V_N = f3_dot(V, N); + f3_mulf(tmp, N, 2*cos_V_N); + f3_sub(res, tmp, V); + return res; +} + +#endif /* SDIS_SOLVE_XD_H */ +#else + +#if (SDIS_SOLVE_DIMENSION == 2) + #include <rsys/double2.h> + #include <rsys/float2.h> + #include <star/s2d.h> +#elif (SDIS_SOLVE_DIMENSION == 3) + #include <rsys/double2.h> + #include <rsys/double3.h> + #include <rsys/float3.h> + #include <star/s3d.h> +#else + #error "Invalid SDIS_SOLVE_DIMENSION value." +#endif + +/* Syntactic sugar */ +#define DIM SDIS_SOLVE_DIMENSION + +/* Star-XD macros generic to SDIS_SOLVE_DIMENSION */ +#define sXd(Name) CONCAT(CONCAT(CONCAT(s, DIM), d_), Name) +#define SXD_HIT_NONE CONCAT(CONCAT(S,DIM), D_HIT_NONE) +#define SXD_HIT_NULL CONCAT(CONCAT(S,DIM), D_HIT_NULL) +#define SXD_HIT_NULL__ CONCAT(CONCAT(S, DIM), D_HIT_NULL__) +#define SXD CONCAT(CONCAT(S, DIM), D) + +/* Vector macros generic to SDIS_SOLVE_DIMENSION */ +#define dX(Func) CONCAT(CONCAT(CONCAT(d, DIM), _), Func) +#define fX(Func) CONCAT(CONCAT(CONCAT(f, DIM), _), Func) +#define fX_set_dX CONCAT(CONCAT(CONCAT(f, DIM), _set_d), DIM) +#define dX_set_fX CONCAT(CONCAT(CONCAT(d, DIM), _set_f), DIM) + +/* Macro making generic its subimitted name to SDIS_SOLVE_DIMENSION */ +#define XD(Name) CONCAT(CONCAT(CONCAT(Name, _), DIM), d) + +/* Current state of the random walk */ +struct XD(rwalk) { + struct sdis_rwalk_vertex vtx; /* Position and time of the Random walk */ + const struct sdis_medium* mdm; /* Medium in which the random walk lies */ + struct sXd(hit) hit; /* Hit of the random walk */ +}; +static const struct XD(rwalk) XD(RWALK_NULL) = { + SDIS_RWALK_VERTEX_NULL__, NULL, SXD_HIT_NULL__ +}; + +struct XD(temperature) { + res_T (*func)/* Next function to invoke in order to compute the temperature */ + (const struct sdis_scene* scn, + const double fp_to_meter, + const struct rwalk_context* ctx, + struct XD(rwalk)* rwalk, + struct ssp_rng* rng, + struct XD(temperature)* temp); + double value; /* Current value of the temperature */ + int done; +}; +static const struct XD(temperature) XD(TEMPERATURE_NULL) = { NULL, 0, 0 }; + +static res_T +XD(boundary_temperature) + (const struct sdis_scene* scn, + const double fp_to_meter, + const struct rwalk_context* ctx, + struct XD(rwalk)* rwalk, + struct ssp_rng* rng, + struct XD(temperature)* T); + +static res_T +XD(solid_temperature) + (const struct sdis_scene* scn, + const double fp_to_meter, + const struct rwalk_context* ctx, + struct XD(rwalk)* rwalk, + struct ssp_rng* rng, + struct XD(temperature)* T); + +static res_T +XD(fluid_temperature) + (const struct sdis_scene* scn, + const double fp_to_meter, + const struct rwalk_context* ctx, + struct XD(rwalk)* rwalk, + struct ssp_rng* rng, + struct XD(temperature)* T); + +static res_T +XD(radiative_temperature) + (const struct sdis_scene* scn, + const double fp_to_meter, + const struct rwalk_context* ctx, + struct XD(rwalk)* rwalk, + struct ssp_rng* rng, + struct XD(temperature)* T); + +/******************************************************************************* + * Helper functions + ******************************************************************************/ + +static FINLINE void +XD(move_pos)(double pos[DIM], const float dir[DIM], const float delta) +{ + ASSERT(pos && dir); + pos[0] += dir[0] * delta; + pos[1] += dir[1] * delta; +#if(SDIS_SOLVE_DIMENSION == 3) + pos[2] += dir[2] * delta; +#endif +} + +/* Check that the interface fragment is consistent with the current state of + * the random walk */ +static INLINE int +XD(check_rwalk_fragment_consistency) + (const struct XD(rwalk)* rwalk, + const struct sdis_interface_fragment* frag) +{ + double N[DIM]; + double uv[2] = {0, 0}; + ASSERT(rwalk && frag); + dX(normalize)(N, dX_set_fX(N, rwalk->hit.normal)); + if( SXD_HIT_NONE(&rwalk->hit) + || !dX(eq_eps)(rwalk->vtx.P, frag->P, 1.e-6) + || !dX(eq_eps)(N, frag->Ng, 1.e-6) + || !( (IS_INF(rwalk->vtx.time) && IS_INF(frag->time)) + || eq_eps(rwalk->vtx.time, frag->time, 1.e-6))) { + return 0; + } +#if (SDIS_SOLVE_DIMENSION == 2) + uv[0] = rwalk->hit.u; +#else + d2_set_f2(uv, rwalk->hit.uv); +#endif + return d2_eq_eps(uv, frag->uv, 1.e-6); +} + +static res_T +XD(trace_radiative_path) + (const struct sdis_scene* scn, + const float ray_dir[3], + const double fp_to_meter, + const struct rwalk_context* ctx, + struct XD(rwalk)* rwalk, + struct ssp_rng* rng, + struct XD(temperature)* T) +{ + /* The radiative random walk is always perform in 3D. In 2D, the geometry are + * assumed to be extruded to the infinty along the Z dimension. */ + float N[3] = {0, 0, 0}; + float dir[3] = {0, 0, 0}; + res_T res = RES_OK; + + ASSERT(scn && ray_dir && fp_to_meter > 0 && ctx && rwalk && rng && T); + (void)fp_to_meter; + + f3_set(dir, ray_dir); + + /* Launch the radiative random walk */ + for(;;) { + const struct sdis_interface* interf = NULL; + struct sdis_interface_fragment frag = SDIS_INTERFACE_FRAGMENT_NULL; + const struct sdis_medium* chk_mdm = NULL; + double alpha; + double epsilon; + double r; + float pos[DIM]; + const float range[2] = { 0, FLT_MAX }; + + fX_set_dX(pos, rwalk->vtx.P); + + /* Trace the radiative ray */ +#if (SDIS_SOLVE_DIMENSION == 2) + SXD(scene_view_trace_ray_3d + (scn->sXd(view), pos, dir, range, &rwalk->hit, &rwalk->hit)); +#else + SXD(scene_view_trace_ray + (scn->sXd(view), pos, dir, range, &rwalk->hit, &rwalk->hit)); +#endif + if(SXD_HIT_NONE(&rwalk->hit)) { /* Fetch the ambient radiative temperature */ + if(ctx->Tarad >= 0) { + T->value += ctx->Tarad; + T->done = 1; + break; + } else { + log_err(scn->dev, +"%s: the random walk reaches an invalid ambient radiative temperature of `%gK'\n" +"at position `%g %g %g'. This may be due to numerical inaccuracies or to\n" +"inconsistency in the simulated system (eg: unclosed geometry). For systems\n" +"where the random walks can reach such temperature, one has to setup a valid\n" +"ambient radiative temperature, i.e. it must be greater or equal to 0.\n", + FUNC_NAME, + ctx->Tarad, + SPLIT3(rwalk->vtx.P)); + res = RES_BAD_ARG; + goto error; + } + } + + /* Move the random walk to the hit position */ + XD(move_pos)(rwalk->vtx.P, dir, rwalk->hit.distance); + + /* Fetch the new interface and setup the hit fragment */ + interf = scene_get_interface(scn, rwalk->hit.prim.prim_id); + XD(setup_interface_fragment)(&frag, &rwalk->vtx, &rwalk->hit); + + /* Fetch the interface emissivity */ + epsilon = interface_get_emissivity(interf, &frag); + if(epsilon > 1 && epsilon >= 0) { + log_err(scn->dev, + "%s: invalid overall emissivity `%g' at position `%g %g %g'.\n", + FUNC_NAME, epsilon, SPLIT3(rwalk->vtx.P)); + res = RES_BAD_ARG; + goto error; + } + + /* Switch in boundary temperature ? */ + r = ssp_rng_canonical(rng); + if(r < epsilon) { + T->func = XD(boundary_temperature); + break; + } + + /* Normalize the normal of the interface and ensure that it points toward the + * current medium */ + fX(normalize)(N, rwalk->hit.normal); + if(f3_dot(N, dir) > 0) { + chk_mdm = interf->medium_back; + fX(minus)(N, N); + } else { + chk_mdm = interf->medium_front; + } + + if(chk_mdm != rwalk->mdm) { + log_err(scn->dev, "%s: inconsistent medium definition at `%g %g %g'.\n", + FUNC_NAME, SPLIT3(rwalk->vtx.P)); + res = RES_BAD_ARG; + goto error; + } + alpha = interface_get_specular_fraction(interf, &frag); + r = ssp_rng_canonical(rng); + if(r < alpha) { /* Sample specular part */ + reflect(dir, f3_minus(dir, dir), N); + } else { /* Sample diffuse part */ + ssp_ran_hemisphere_cos_float(rng, N, dir, NULL); + } + } + +exit: + return res; +error: + goto exit; +} + +res_T +XD(radiative_temperature) + (const struct sdis_scene* scn, + const double fp_to_meter, + const struct rwalk_context* ctx, + struct XD(rwalk)* rwalk, + struct ssp_rng* rng, + struct XD(temperature)* T) +{ + const struct sdis_interface* interf; + + /* The radiative random walk is always perform in 3D. In 2D, the geometry are + * assumed to be extruded to the infinty along the Z dimension. */ + float N[3] = {0, 0, 0}; + float dir[3] = {0, 0, 0}; + res_T res = RES_OK; + + ASSERT(scn && fp_to_meter > 0 && ctx && rwalk && rng && T); + ASSERT(!SXD_HIT_NONE(&rwalk->hit)); + (void)fp_to_meter; + + /* Fetch the current interface */ + interf = scene_get_interface(scn, rwalk->hit.prim.prim_id); + + /* Normalize the normal of the interface and ensure that it points toward the + * current medium */ + fX(normalize(N, rwalk->hit.normal)); + if(interf->medium_back == rwalk->mdm) { + fX(minus(N, N)); + } + + /* Cosine weighted sampling of a direction around the surface normal */ + ssp_ran_hemisphere_cos_float(rng, N, dir, NULL); + + /* Launch the radiative random walk */ + res = XD(trace_radiative_path)(scn, dir, fp_to_meter, ctx, rwalk, rng, T); + if(res != RES_OK) goto error; + +exit: + return res; +error: + goto exit; +} + +res_T +XD(fluid_temperature) + (const struct sdis_scene* scn, + const double fp_to_meter, + const struct rwalk_context* ctx, + struct XD(rwalk)* rwalk, + struct ssp_rng* rng, + struct XD(temperature)* T) +{ + double tmp; + (void)rng, (void)fp_to_meter, (void)ctx; + ASSERT(scn && fp_to_meter > 0 && ctx && rwalk && rng && T); + ASSERT(rwalk->mdm->type == SDIS_MEDIUM_FLUID); + + tmp = fluid_get_temperature(rwalk->mdm, &rwalk->vtx); + if(tmp < 0) { + log_err(scn->dev, "%s: unknown fluid temperature is not supported.\n", + FUNC_NAME); + return RES_BAD_OP; + } + T->value += tmp; + T->done = 1; + return RES_OK; +} + +static void +XD(solid_solid_boundary_temperature) + (const struct sdis_scene* scn, + const double fp_to_meter, + const struct rwalk_context* ctx, + const struct sdis_interface_fragment* frag, + struct XD(rwalk)* rwalk, + struct ssp_rng* rng, + struct XD(temperature)* T) +{ + const struct sdis_interface* interf = NULL; + const struct sdis_medium* solid_front = NULL; + const struct sdis_medium* solid_back = NULL; + double lambda_front, lambda_back; + double delta_front_boundary, delta_back_boundary; + double delta_front_boundary_meter, delta_back_boundary_meter; + double delta_boundary; + double proba; + double tmp; + double r; + float pos[DIM], dir[DIM], range[2]; + ASSERT(scn && fp_to_meter > 0 && ctx && frag && rwalk && rng && T); + ASSERT(XD(check_rwalk_fragment_consistency)(rwalk, frag)); + (void)frag, (void)ctx; + + /* Retrieve the current boundary media */ + interf = scene_get_interface(scn, rwalk->hit.prim.prim_id); + solid_front = interface_get_medium(interf, SDIS_FRONT); + solid_back = interface_get_medium(interf, SDIS_BACK); + ASSERT(solid_front->type == SDIS_MEDIUM_SOLID); + ASSERT(solid_back->type == SDIS_MEDIUM_SOLID); + + /* Fetch the properties of the media */ + lambda_front = solid_get_thermal_conductivity(solid_front, &rwalk->vtx); + lambda_back = solid_get_thermal_conductivity(solid_back, &rwalk->vtx); + delta_front_boundary = solid_get_delta_boundary(solid_front, &rwalk->vtx); + delta_back_boundary = solid_get_delta_boundary(solid_back, &rwalk->vtx); + + /* Convert the delta boundary from floating point units to meters */ + delta_front_boundary_meter = fp_to_meter * delta_front_boundary; + delta_back_boundary_meter = fp_to_meter * delta_back_boundary; + + /* Compute the proba to switch in solid0 or in solid1 */ + tmp = lambda_front / delta_front_boundary_meter; + proba = tmp / (tmp + lambda_back / delta_back_boundary_meter); + + r = ssp_rng_canonical(rng); + fX(normalize)(dir, rwalk->hit.normal); + if(r < proba) { /* Reinject in front */ + delta_boundary = delta_front_boundary; + rwalk->mdm = solid_front; + } else { /* Reinject in back */ + delta_boundary = delta_back_boundary; + fX(minus)(dir, dir); + rwalk->mdm = solid_back; + } + + /* "Reinject" the path into the solid along the surface normal. */ + fX_set_dX(pos, rwalk->vtx.P); + range[0] = 0, range[1] = (float)delta_boundary*RAY_RANGE_MAX_SCALE; + SXD(scene_view_trace_ray + (scn->sXd(view), pos, dir, range, &rwalk->hit, &rwalk->hit)); + if(!SXD_HIT_NONE(&rwalk->hit)) delta_boundary = rwalk->hit.distance * 0.5; + XD(move_pos)(rwalk->vtx.P, dir, (float)delta_boundary); + + /* Switch in solid random walk */ + T->func = XD(solid_temperature); +} + +static void +XD(solid_fluid_boundary_temperature) + (const struct sdis_scene* scn, + const double fp_to_meter, + const struct rwalk_context* ctx, + const struct sdis_interface_fragment* frag, + struct XD(rwalk)* rwalk, + struct ssp_rng* rng, + struct XD(temperature)* T) +{ + const struct sdis_interface* interf = NULL; + const struct sdis_medium* mdm_front = NULL; + const struct sdis_medium* mdm_back = NULL; + const struct sdis_medium* solid = NULL; + const struct sdis_medium* fluid = NULL; + double hc; + double hr; + double epsilon; /* Interface emissivity */ + double lambda; + double fluid_proba; + double radia_proba; + double delta_boundary; + double r; + double tmp; + float dir[DIM], pos[DIM], range[2]; + + ASSERT(scn && fp_to_meter > 0 && rwalk && rng && T && ctx); + ASSERT(XD(check_rwalk_fragment_consistency)(rwalk, frag)); + + /* Retrieve the solid and the fluid split by the boundary */ + interf = scene_get_interface(scn, rwalk->hit.prim.prim_id); + mdm_front = interface_get_medium(interf, SDIS_FRONT); + mdm_back = interface_get_medium(interf, SDIS_BACK); + ASSERT(mdm_front->type != mdm_back->type); + if(mdm_front->type == SDIS_MEDIUM_SOLID) { + solid = mdm_front; + fluid = mdm_back; + } else { + solid = mdm_back; + fluid = mdm_front; + } + + /* Fetch the solid properties */ + lambda = solid_get_thermal_conductivity(solid, &rwalk->vtx); + delta_boundary = solid_get_delta_boundary(solid, &rwalk->vtx); + + /* Fetch the boundary properties */ + epsilon = interface_get_emissivity(interf, frag); + hc = interface_get_convection_coef(interf, frag); + + /* Compute the radiative coefficient */ + hr = 4.0 * BOLTZMANN_CONSTANT * ctx->Tref3 * epsilon; + + /* Compute the probas to switch in solid or fluid random walk */ + tmp = lambda / (delta_boundary*fp_to_meter); + fluid_proba = hc / (tmp + hr + hc); + radia_proba = hr / (tmp + hr + hc); + /*solid_proba = tmp / (tmp + hr + hc);*/ + + r = ssp_rng_canonical(rng); + if(r < radia_proba) { /* Switch in radiative random walk */ + rwalk->mdm = fluid; + T->func = XD(radiative_temperature); + } else if(r < fluid_proba + radia_proba) { /* Switch to fluid random walk */ + rwalk->mdm = fluid; + T->func = XD(fluid_temperature); + } else { /* Solid random walk */ + rwalk->mdm = solid; + fX(normalize)(dir, rwalk->hit.normal); + if(solid == mdm_back) fX(minus)(dir, dir); + + /* "Reinject" the random walk into the solid */ + fX_set_dX(pos, rwalk->vtx.P); + range[0] = 0, range[1] = (float)delta_boundary*RAY_RANGE_MAX_SCALE; + SXD(scene_view_trace_ray + (scn->sXd(view), pos, dir, range, &rwalk->hit, &rwalk->hit)); + if(!SXD_HIT_NONE(&rwalk->hit)) delta_boundary = rwalk->hit.distance * 0.5; + XD(move_pos)(rwalk->vtx.P, dir, (float)delta_boundary); + + /* Switch in solid random walk */ + T->func = XD(solid_temperature); + } +} + +res_T +XD(boundary_temperature) + (const struct sdis_scene* scn, + const double fp_to_meter, + const struct rwalk_context* ctx, + struct XD(rwalk)* rwalk, + struct ssp_rng* rng, + struct XD(temperature)* T) +{ + struct sdis_interface_fragment frag = SDIS_INTERFACE_FRAGMENT_NULL; + const struct sdis_interface* interf = NULL; + const struct sdis_medium* mdm_front = NULL; + const struct sdis_medium* mdm_back = NULL; + double tmp; + ASSERT(scn && fp_to_meter > 0 && ctx && rwalk && rng && T); + ASSERT(!SXD_HIT_NONE(&rwalk->hit)); + + XD(setup_interface_fragment)(&frag, &rwalk->vtx, &rwalk->hit); + + /* Retrieve the current interface */ + interf = scene_get_interface(scn, rwalk->hit.prim.prim_id); + + /* Check if the boundary condition is known */ + tmp = interface_get_temperature(interf, &frag); + if(tmp >= 0) { + T->value += tmp; + T->done = 1; + return RES_OK; + } + + mdm_front = interface_get_medium(interf, SDIS_FRONT); + mdm_back = interface_get_medium(interf, SDIS_BACK); + + if(mdm_front->type == mdm_back->type) { + XD(solid_solid_boundary_temperature) + (scn, fp_to_meter, ctx, &frag, rwalk, rng, T); + } else { + XD(solid_fluid_boundary_temperature) + (scn, fp_to_meter, ctx, &frag, rwalk, rng, T); + } + return RES_OK; +} + +res_T +XD(solid_temperature) + (const struct sdis_scene* scn, + const double fp_to_meter, + const struct rwalk_context* ctx, + struct XD(rwalk)* rwalk, + struct ssp_rng* rng, + struct XD(temperature)* T) +{ + double position_start[DIM]; + const struct sdis_medium* mdm; + ASSERT(scn && fp_to_meter > 0 && rwalk && rng && T); + ASSERT(rwalk->mdm->type == SDIS_MEDIUM_SOLID); + (void)ctx; + + /* Check the random walk consistency */ + CHK(scene_get_medium(scn, rwalk->vtx.P, &mdm) == RES_OK); + if(mdm != rwalk->mdm) { + log_err(scn->dev, "%s: invalid solid random walk. " + "Unexpected medium at {%g, %g, %g}.\n", + FUNC_NAME, SPLIT3(rwalk->vtx.P)); + return RES_BAD_OP; + } + /* Save the submitted position */ + dX(set)(position_start, rwalk->vtx.P); + + do { /* Solid random walk */ + struct sXd(hit) hit0, hit1; + double lambda; /* Thermal conductivity */ + double rho; /* Volumic mass */ + double cp; /* Calorific capacity */ + double tau, mu; + double tmp; + float delta, delta_solid; /* Random walk numerical parameter */ + float range[2]; + float dir0[DIM], dir1[DIM]; + float org[DIM]; + + /* Check the limit condition */ + tmp = solid_get_temperature(mdm, &rwalk->vtx); + if(tmp >= 0) { + T->value += tmp; + T->done = 1; + return RES_OK; + } + + /* Fetch solid properties */ + delta_solid = (float)solid_get_delta(mdm, &rwalk->vtx); + lambda = solid_get_thermal_conductivity(mdm, &rwalk->vtx); + rho = solid_get_volumic_mass(mdm, &rwalk->vtx); + cp = solid_get_calorific_capacity(mdm, &rwalk->vtx); + +#if (SDIS_SOLVE_DIMENSION == 2) + /* Sample a direction around 2PI */ + ssp_ran_circle_uniform_float(rng, dir0, NULL); +#else + /* Sample a direction around 4PI */ + ssp_ran_sphere_uniform_float(rng, dir0, NULL); +#endif + + /* Trace a ray along the sampled direction and its opposite to check if a + * surface is hit in [0, delta_solid]. */ + fX_set_dX(org, rwalk->vtx.P); + fX(minus)(dir1, dir0); + hit0 = hit1 = SXD_HIT_NULL; + range[0] = 0.f, range[1] = delta_solid*RAY_RANGE_MAX_SCALE; + SXD(scene_view_trace_ray(scn->sXd(view), org, dir0, range, NULL, &hit0)); + SXD(scene_view_trace_ray(scn->sXd(view), org, dir1, range, NULL, &hit1)); + + if(SXD_HIT_NONE(&hit0) && SXD_HIT_NONE(&hit1)) { + /* Hit nothing: move along dir0 of the original delta */ + delta = delta_solid; + } else { + /* Hit something: move along dir0 of the minimum hit distance */ + delta = MMIN(hit0.distance, hit1.distance); + } + + /* Sample the time */ + mu = (2*DIM*lambda) / (rho*cp*delta*fp_to_meter*delta*fp_to_meter); + tau = ssp_ran_exp(rng, mu); + rwalk->vtx.time -= tau; + + /* Check the initial condition */ + tmp = solid_get_temperature(mdm, &rwalk->vtx); + if(tmp >= 0) { + T->value += tmp; + T->done = 1; + return RES_OK; + } + + /* Define if the random walk hits something along dir0 */ + rwalk->hit = hit0.distance > delta ? SXD_HIT_NULL : hit0; + + /* Update the random walk position */ + XD(move_pos)(rwalk->vtx.P, dir0, delta); + + /* Fetch the current medium */ + if(SXD_HIT_NONE(&rwalk->hit)) { + CHK(scene_get_medium(scn, rwalk->vtx.P, &mdm) == RES_OK); + } else { + const struct sdis_interface* interf; + interf = scene_get_interface(scn, rwalk->hit.prim.prim_id); + mdm = interface_get_medium + (interf, + fX(dot(rwalk->hit.normal, dir0)) < 0 ? SDIS_FRONT : SDIS_BACK); + } + + /* Check random walk consistency */ + if(mdm != rwalk->mdm) { + log_err(scn->dev, + "%s: inconsistent medium during the solid random walk.\n", FUNC_NAME); + if(DIM == 2) { + log_err(scn->dev, + " start position: %g %g; current position: %g %g\n", + SPLIT2(position_start), SPLIT2(rwalk->vtx.P)); + } else { + log_err(scn->dev, + " start position: %g %g %g; current position: %g %g %g\n", + SPLIT3(position_start), SPLIT3(rwalk->vtx.P)); + } + return RES_BAD_OP; + } + + /* Keep going while the solid random walk does not hit an interface */ + } while(SXD_HIT_NONE(&rwalk->hit)); + + T->func = XD(boundary_temperature); + return RES_OK; +} + +static res_T +XD(compute_temperature) + (struct sdis_scene* scn, + const double fp_to_meter, + const struct rwalk_context* ctx, + struct XD(rwalk)* rwalk, + struct ssp_rng* rng, + struct XD(temperature)* T) +{ +#ifndef NDEBUG + struct XD(temperature)* stack = NULL; + size_t istack = 0; +#endif + res_T res = RES_OK; + ASSERT(scn && fp_to_meter > 0 && ctx && rwalk && rng && T); + + do { + res = T->func(scn, fp_to_meter, ctx, rwalk, rng, T); + if(res != RES_OK) goto error; + +#ifndef NDEBUG + sa_push(stack, *T); + ++istack; +#endif + } while(!T->done); + +exit: +#ifndef NDEBUG + sa_release(stack); +#endif + return res; +error: + goto exit; +} + +static res_T +XD(probe_realisation) + (struct sdis_scene* scn, + struct ssp_rng* rng, + const struct sdis_medium* medium, + const double position[], + const double time, + const double fp_to_meter,/* Scale factor from floating point unit to meter */ + const double ambient_radiative_temperature, + const double reference_temperature, + double* weight) +{ + struct rwalk_context ctx; + struct XD(rwalk) rwalk = XD(RWALK_NULL); + struct XD(temperature) T = XD(TEMPERATURE_NULL); + res_T res = RES_OK; + ASSERT(medium && position && fp_to_meter > 0 && weight && time >= 0); + + switch(medium->type) { + case SDIS_MEDIUM_FLUID: T.func = XD(fluid_temperature); break; + case SDIS_MEDIUM_SOLID: T.func = XD(solid_temperature); break; + default: FATAL("Unreachable code\n"); break; + } + + dX(set)(rwalk.vtx.P, position); + rwalk.vtx.time = time; + rwalk.hit = SXD_HIT_NULL; + rwalk.mdm = medium; + + ctx.Tarad = ambient_radiative_temperature; + ctx.Tref3 = + reference_temperature + * reference_temperature + * reference_temperature; + + res = XD(compute_temperature)(scn, fp_to_meter, &ctx, &rwalk, rng, &T); + if(res != RES_OK) return res; + + *weight = T.value; + return RES_OK; +} + +#if SDIS_SOLVE_DIMENSION == 3 +static res_T +XD(ray_realisation) + (struct sdis_scene* scn, + struct ssp_rng* rng, + const struct sdis_medium* medium, + const double position[], + const double direction[], + const double time, + const double fp_to_meter, + const double Tarad, + const double Tref, + double* weight) +{ + struct rwalk_context ctx; + struct XD(rwalk) rwalk = XD(RWALK_NULL); + struct XD(temperature) T = XD(TEMPERATURE_NULL); + float dir[3]; + res_T res = RES_OK; + ASSERT(scn && position && direction && time>=0 && fp_to_meter>0 && weight); + ASSERT(medium && medium->type == SDIS_MEDIUM_FLUID); + + dX(set)(rwalk.vtx.P, position); + rwalk.vtx.time = time; + rwalk.hit = SXD_HIT_NULL; + rwalk.mdm = medium; + + ctx.Tarad = Tarad; + ctx.Tref3 = Tref*Tref*Tref; + + f3_set_d3(dir, direction); + + res = XD(trace_radiative_path)(scn, dir, fp_to_meter, &ctx, &rwalk, rng, &T); + if(res != RES_OK) goto error; + + if(!T.done) { + res = XD(compute_temperature)(scn, fp_to_meter, &ctx, &rwalk, rng, &T); + if(res != RES_OK) goto error; + } + + *weight = T.value; + +exit: + return res; +error: + goto exit; +} +#endif /* SDIS_SOLVE_DIMENSION == 3 */ + +#undef SDIS_SOLVE_DIMENSION +#undef DIM +#undef sXd +#undef SXD_HIT_NONE +#undef SXD_HIT_NULL +#undef SXD_HIT_NULL__ +#undef SXD +#undef dX +#undef fX +#undef fX_set_dX +#undef XD + +#endif /* !SDIS_SOLVE_DIMENSION */ + diff --git a/src/sdis_solve_probe.c b/src/sdis_solve_probe.c @@ -1,138 +0,0 @@ -/* Copyright (C) |Meso|Star> 2016-2018 (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_device_c.h" -#include "sdis_estimator_c.h" -#include "sdis_solve_probe_Xd.h" - -/* Generate the 2D solver */ -#define SDIS_SOLVE_PROBE_DIMENSION 2 -#include "sdis_solve_probe_Xd.h" - -/* Generate the 3D solver */ -#define SDIS_SOLVE_PROBE_DIMENSION 3 -#include "sdis_solve_probe_Xd.h" - -#include <star/ssp.h> -#include <omp.h> - -res_T -sdis_solve_probe - (struct sdis_scene* scn, - const size_t nrealisations, - const double position[3], - const double time, - const double fp_to_meter,/* Scale factor from floating point unit to meter */ - struct sdis_estimator** out_estimator) -{ - const struct sdis_medium* medium = NULL; - struct sdis_estimator* estimator = NULL; - struct ssp_rng_proxy* rng_proxy = NULL; - struct ssp_rng** rngs = NULL; - double weight = 0; - double sqr_weight = 0; - size_t irealisation = 0; - size_t N = 0; /* #realisations that do not fail */ - size_t i; - ATOMIC res = RES_OK; - - if(!scn || !nrealisations || !position || time < 0 || fp_to_meter <= 0 - || !out_estimator) { - 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; - } - - /* Create the estimator */ - res = estimator_create(scn->dev, &estimator); - if(res != RES_OK) goto error; - - /* Retrieve the medium in which the submitted position lies */ - res = scene_get_medium(scn, position, &medium); - if(res != RES_OK) goto error; - - /* Here we go! Launch the Monte Carlo estimation */ - #pragma omp parallel for schedule(static) reduction(+:weight,sqr_weight,N) - for(irealisation = 0; irealisation < nrealisations; ++irealisation) { - res_T res_local; - double w; - const int ithread = omp_get_thread_num(); - struct ssp_rng* rng = rngs[ithread]; - - if(ATOMIC_GET(&res) != RES_OK) continue; /* An error occured */ - - if(scene_is_2d(scn)) { - res_local = probe_realisation_2d - (scn, rng, medium, position, time, fp_to_meter, &w); - } else { - res_local = probe_realisation_3d - (scn, rng, medium, position, time, fp_to_meter, &w); - } - if(res_local != RES_OK) { - if(res_local == RES_BAD_OP) { - ++estimator->nfailures; - } else { - ATOMIC_SET(&res, res_local); - continue; - } - } else { - weight += w; - sqr_weight += w*w; - ++N; - } - } - - estimator->nrealisations = N; - estimator->temperature.E = weight / (double)N; - estimator->temperature.V = - sqr_weight / (double)N - - estimator->temperature.E * estimator->temperature.E; - estimator->temperature.SE = sqrt(estimator->temperature.V / (double)N); - -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_estimator) *out_estimator = estimator; - return (res_T)res; -error: - 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,565 +0,0 @@ -/* Copyright (C) |Meso|Star> 2016-2018 (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_SOLVE_PROBE_DIMENSION -#ifndef SDIS_SOLVE_PROBE_XD_H -#define SDIS_SOLVE_PROBE_XD_H - -#include "sdis_device_c.h" -#include "sdis_interface_c.h" -#include "sdis_medium_c.h" -#include "sdis_scene_c.h" - -#include <rsys/stretchy_array.h> - -#include <star/ssp.h> - -/* Emperical scale factor to apply to the upper bound of the ray range in order - * to handle numerical imprecisions */ -#define RAY_RANGE_MAX_SCALE 1.0001f - -#endif /* SDIS_SOLVE_PROBE_XD_H */ -#else - -#if (SDIS_SOLVE_PROBE_DIMENSION == 2) - #include <rsys/double2.h> - #include <rsys/float2.h> - #include <star/s2d.h> -#elif (SDIS_SOLVE_PROBE_DIMENSION == 3) - #include <rsys/double2.h> - #include <rsys/double3.h> - #include <rsys/float3.h> - #include <star/s3d.h> -#else - #error "Invalid SDIS_SOLVE_PROBE_DIMENSION value." -#endif - -/* Syntactic sugar */ -#define DIM SDIS_SOLVE_PROBE_DIMENSION - -/* Star-XD macros generic to SDIS_SOLVE_PROBE_DIMENSION */ -#define sXd(Name) CONCAT(CONCAT(CONCAT(s, DIM), d_), Name) -#define SXD_HIT_NONE CONCAT(CONCAT(S,DIM), D_HIT_NONE) -#define SXD_HIT_NULL CONCAT(CONCAT(S,DIM), D_HIT_NULL) -#define SXD_HIT_NULL__ CONCAT(CONCAT(S, DIM), D_HIT_NULL__) -#define SXD CONCAT(CONCAT(S, DIM), D) - -/* Vector macros generic to SDIS_SOLVE_PROBE_DIMENSION */ -#define dX(Func) CONCAT(CONCAT(CONCAT(d, DIM), _), Func) -#define fX(Func) CONCAT(CONCAT(CONCAT(f, DIM), _), Func) -#define fX_set_dX CONCAT(CONCAT(CONCAT(f, DIM), _set_d), DIM) -#define dX_set_fX CONCAT(CONCAT(CONCAT(d, DIM), _set_f), DIM) - -/* Macro making generic its subimitted name to SDIS_SOLVE_PROBE_DIMENSION */ -#define XD(Name) CONCAT(CONCAT(CONCAT(Name, _), DIM), d) - -/* Current state of the random walk */ -struct XD(rwalk) { - struct sdis_rwalk_vertex vtx; /* Position and time of the Random walk */ - const struct sdis_medium* mdm; /* Medium in which the random walk lies */ - struct sXd(hit) hit; /* Hit of the random walk */ -}; -static const struct XD(rwalk) XD(RWALK_NULL) = { - SDIS_RWALK_VERTEX_NULL__, NULL, SXD_HIT_NULL__ -}; - -struct XD(temperature) { - res_T (*func)/* Next function to invoke in order to compute the temperature */ - (const struct sdis_scene* scn, - const double fp_to_meter, - struct XD(rwalk)* rwalk, - struct ssp_rng* rng, - struct XD(temperature)* temp); - double value; /* Current value of the temperature */ - int done; -}; -static const struct XD(temperature) XD(TEMPERATURE_NULL) = { NULL, 0, 0 }; - -static res_T -XD(boundary_temperature) - (const struct sdis_scene* scn, - const double fp_to_meter, - struct XD(rwalk)* rwalk, - struct ssp_rng* rng, - struct XD(temperature)* T); - -static res_T -XD(solid_temperature) - (const struct sdis_scene* scn, - const double fp_to_meter, - struct XD(rwalk)* rwalk, - struct ssp_rng* rng, - struct XD(temperature)* T); - -static res_T -XD(fluid_temperature) - (const struct sdis_scene* scn, - const double fp_to_meter, - struct XD(rwalk)* rwalk, - struct ssp_rng* rng, - struct XD(temperature)* T); - -/******************************************************************************* - * Helper functions - ******************************************************************************/ -static FINLINE void -XD(move_pos)(double pos[DIM], const float dir[DIM], const float delta) -{ - ASSERT(pos && dir); - pos[0] += dir[0] * delta; - pos[1] += dir[1] * delta; -#if (SDIS_SOLVE_PROBE_DIMENSION == 3) - pos[2] += dir[2] * delta; -#endif - -} - -/* Check that the interface fragment is consistent with the current state of - * the random walk */ -static INLINE int -XD(check_rwalk_fragment_consistency) - (const struct XD(rwalk)* rwalk, - const struct sdis_interface_fragment* frag) -{ - double N[DIM]; - double uv[2] = {0, 0}; - ASSERT(rwalk && frag); - dX(normalize)(N, dX_set_fX(N, rwalk->hit.normal)); - if( SXD_HIT_NONE(&rwalk->hit) - || !dX(eq_eps)(rwalk->vtx.P, frag->P, 1.e-6) - || !dX(eq_eps)(N, frag->Ng, 1.e-6) - || !( (IS_INF(rwalk->vtx.time) && IS_INF(frag->time)) - || eq_eps(rwalk->vtx.time, frag->time, 1.e-6))) { - return 0; - } -#if (SDIS_SOLVE_PROBE_DIMENSION == 2) - uv[0] = rwalk->hit.u; -#else - d2_set_f2(uv, rwalk->hit.uv); -#endif - return d2_eq_eps(uv, frag->uv, 1.e-6); -} - -res_T -XD(fluid_temperature) - (const struct sdis_scene* scn, - const double fp_to_meter, - struct XD(rwalk)* rwalk, - struct ssp_rng* rng, - struct XD(temperature)* T) -{ - double tmp; - (void)rng, (void)fp_to_meter; - ASSERT(scn && fp_to_meter > 0 && rwalk && rng && T); - ASSERT(rwalk->mdm->type == SDIS_MEDIUM_FLUID); - - tmp = fluid_get_temperature(rwalk->mdm, &rwalk->vtx); - if(tmp < 0) { - log_err(scn->dev, "%s: unknown fluid temperature is not supported.\n", - FUNC_NAME); - return RES_BAD_OP; - } - T->value += tmp; - T->done = 1; - return RES_OK; -} - -static void -XD(solid_solid_boundary_temperature) - (const struct sdis_scene* scn, - const double fp_to_meter, - const struct sdis_interface_fragment* frag, - struct XD(rwalk)* rwalk, - struct ssp_rng* rng, - struct XD(temperature)* T) -{ - const struct sdis_interface* interf = NULL; - const struct sdis_medium* solid_front = NULL; - const struct sdis_medium* solid_back = NULL; - double lambda_front, lambda_back; - double delta_front_boundary, delta_back_boundary; - double delta_front_boundary_meter, delta_back_boundary_meter; - double delta_boundary; - double proba; - double tmp; - double r; - float pos[DIM], dir[DIM], range[2]; - ASSERT(scn && fp_to_meter > 0 && frag && rwalk && rng && T); - ASSERT(XD(check_rwalk_fragment_consistency)(rwalk, frag)); - (void)frag; - - /* Retrieve the current boundary media */ - interf = scene_get_interface(scn, rwalk->hit.prim.prim_id); - solid_front = interface_get_medium(interf, SDIS_FRONT); - solid_back = interface_get_medium(interf, SDIS_BACK); - ASSERT(solid_front->type == SDIS_MEDIUM_SOLID); - ASSERT(solid_back->type == SDIS_MEDIUM_SOLID); - - /* Fetch the properties of the media */ - lambda_front = solid_get_thermal_conductivity(solid_front, &rwalk->vtx); - lambda_back = solid_get_thermal_conductivity(solid_back, &rwalk->vtx); - delta_front_boundary = solid_get_delta_boundary(solid_front, &rwalk->vtx); - delta_back_boundary = solid_get_delta_boundary(solid_back, &rwalk->vtx); - - /* Convert the delta boundary from floating point units to meters */ - delta_front_boundary_meter = fp_to_meter * delta_front_boundary; - delta_back_boundary_meter = fp_to_meter * delta_back_boundary; - - /* Compute the proba to switch in solid0 or in solid1 */ - tmp = lambda_front / delta_front_boundary_meter; - proba = tmp / (tmp + lambda_back / delta_back_boundary_meter); - - r = ssp_rng_canonical(rng); - fX(normalize)(dir, rwalk->hit.normal); - if(r < proba) { /* Reinject in front */ - delta_boundary = delta_front_boundary; - rwalk->mdm = solid_front; - } else { /* Reinject in back */ - delta_boundary = delta_back_boundary; - fX(minus)(dir, dir); - rwalk->mdm = solid_back; - } - - /* "Reinject" the path into the solid along the surface normal. */ - fX_set_dX(pos, rwalk->vtx.P); - range[0] = 0, range[1] = (float)delta_boundary*RAY_RANGE_MAX_SCALE; - SXD(scene_view_trace_ray - (scn->sXd(view), pos, dir, range, &rwalk->hit, &rwalk->hit)); - if(!SXD_HIT_NONE(&rwalk->hit)) delta_boundary = rwalk->hit.distance * 0.5; - XD(move_pos)(rwalk->vtx.P, dir, (float)delta_boundary); - - /* Switch in solid random walk */ - T->func = XD(solid_temperature); -} - -static void -XD(solid_fluid_boundary_temperature) - (const struct sdis_scene* scn, - const double fp_to_meter, - const struct sdis_interface_fragment* frag, - struct XD(rwalk)* rwalk, - struct ssp_rng* rng, - struct XD(temperature)* T) -{ - const struct sdis_interface* interf = NULL; - const struct sdis_medium* mdm_front = NULL; - const struct sdis_medium* mdm_back = NULL; - const struct sdis_medium* solid = NULL; - const struct sdis_medium* fluid = NULL; - double hc; - double lambda; - double fluid_proba; - double delta_boundary; - double r; - double tmp; - float dir[DIM], pos[DIM], range[2]; - - ASSERT(scn && fp_to_meter > 0 && rwalk && rng && T); - ASSERT(XD(check_rwalk_fragment_consistency)(rwalk, frag)); - - /* Retrieve the solid and the fluid split by the boundary */ - interf = scene_get_interface(scn, rwalk->hit.prim.prim_id); - mdm_front = interface_get_medium(interf, SDIS_FRONT); - mdm_back = interface_get_medium(interf, SDIS_BACK); - ASSERT(mdm_front->type != mdm_back->type); - if(mdm_front->type == SDIS_MEDIUM_SOLID) { - solid = mdm_front; - fluid = mdm_back; - } else { - solid = mdm_back; - fluid = mdm_front; - } - - /* Fetch the solid properties */ - lambda = solid_get_thermal_conductivity(solid, &rwalk->vtx); - delta_boundary = solid_get_delta_boundary(solid, &rwalk->vtx); - hc = interface_get_convection_coef(interf, frag); - - /* Compute the probas to switch in solid or fluid random walk */ - tmp = lambda / (delta_boundary*fp_to_meter); - fluid_proba = hc / (tmp + hc); - - r = ssp_rng_canonical(rng); - if(r < fluid_proba) { /* Switch to fluid random walk */ - rwalk->mdm = fluid; - T->func = XD(fluid_temperature); - } else { /* Solid random walk */ - rwalk->mdm = solid; - fX(normalize)(dir, rwalk->hit.normal); - if(solid == mdm_back) fX(minus)(dir, dir); - - /* "Reinject" the random walk into the solid */ - fX_set_dX(pos, rwalk->vtx.P); - range[0] = 0, range[1] = (float)delta_boundary*RAY_RANGE_MAX_SCALE; - SXD(scene_view_trace_ray - (scn->sXd(view), pos, dir, range, &rwalk->hit, &rwalk->hit)); - if(!SXD_HIT_NONE(&rwalk->hit)) delta_boundary = rwalk->hit.distance * 0.5; - XD(move_pos)(rwalk->vtx.P, dir, (float)delta_boundary); - - /* Switch in solid random walk */ - T->func = XD(solid_temperature); - } -} - -res_T -XD(boundary_temperature) - (const struct sdis_scene* scn, - const double fp_to_meter, - struct XD(rwalk)* rwalk, - struct ssp_rng* rng, - struct XD(temperature)* T) -{ - struct sdis_interface_fragment frag = SDIS_INTERFACE_FRAGMENT_NULL; - const struct sdis_interface* interf = NULL; - const struct sdis_medium* mdm_front = NULL; - const struct sdis_medium* mdm_back = NULL; - double tmp; - ASSERT(scn && fp_to_meter > 0 && rwalk && rng && T); - ASSERT(!SXD_HIT_NONE(&rwalk->hit)); - - XD(setup_interface_fragment)(&frag, &rwalk->vtx, &rwalk->hit); - - /* Retrieve the current interface */ - interf = scene_get_interface(scn, rwalk->hit.prim.prim_id); - - /* Check if the boundary condition is known */ - tmp = interface_get_temperature(interf, &frag); - if(tmp >= 0) { - T->value += tmp; - T->done = 1; - return RES_OK; - } - - mdm_front = interface_get_medium(interf, SDIS_FRONT); - mdm_back = interface_get_medium(interf, SDIS_BACK); - - if(mdm_front->type == mdm_back->type) { - XD(solid_solid_boundary_temperature)(scn, fp_to_meter, &frag, rwalk, rng, T); - } else { - XD(solid_fluid_boundary_temperature)(scn, fp_to_meter, &frag, rwalk, rng, T); - } - return RES_OK; -} - -res_T -XD(solid_temperature) - (const struct sdis_scene* scn, - const double fp_to_meter, - struct XD(rwalk)* rwalk, - struct ssp_rng* rng, - struct XD(temperature)* T) -{ - double position_start[DIM]; - const struct sdis_medium* mdm; - ASSERT(scn && fp_to_meter > 0 && rwalk && rng && T); - ASSERT(rwalk->mdm->type == SDIS_MEDIUM_SOLID); - - /* Check the random walk consistency */ - CHK(scene_get_medium(scn, rwalk->vtx.P, &mdm) == RES_OK); - if(mdm != rwalk->mdm) { - log_err(scn->dev, "%s: invalid solid random walk. " - "Unexpected medium at {%g, %g, %g}.\n", - FUNC_NAME, SPLIT3(rwalk->vtx.P)); - return RES_BAD_ARG; - } - /* Save the submitted position */ - dX(set)(position_start, rwalk->vtx.P); - - do { /* Solid random walk */ - struct sXd(hit) hit0, hit1; - double lambda; /* Thermal conductivity */ - double rho; /* Volumic mass */ - double cp; /* Calorific capacity */ - double tau, mu; - double tmp; - float delta, delta_solid; /* Random walk numerical parameter */ - float range[2]; - float dir0[DIM], dir1[DIM]; - float org[DIM]; - - /* Check the limit condition */ - tmp = solid_get_temperature(mdm, &rwalk->vtx); - if(tmp >= 0) { - T->value += tmp; - T->done = 1; - return RES_OK; - } - - /* Fetch solid properties */ - delta_solid = (float)solid_get_delta(mdm, &rwalk->vtx); - lambda = solid_get_thermal_conductivity(mdm, &rwalk->vtx); - rho = solid_get_volumic_mass(mdm, &rwalk->vtx); - cp = solid_get_calorific_capacity(mdm, &rwalk->vtx); - -#if (SDIS_SOLVE_PROBE_DIMENSION == 2) - /* Sample a direction around 2PI */ - ssp_ran_circle_uniform_float(rng, dir0, NULL); -#else - /* Sample a direction around 4PI */ - ssp_ran_sphere_uniform_float(rng, dir0, NULL); -#endif - - /* Trace a ray along the sampled direction and its opposite to check if a - * surface is hit in [0, delta_solid]. */ - fX_set_dX(org, rwalk->vtx.P); - fX(minus)(dir1, dir0); - hit0 = hit1 = SXD_HIT_NULL; - range[0] = 0.f, range[1] = delta_solid*RAY_RANGE_MAX_SCALE; - SXD(scene_view_trace_ray(scn->sXd(view), org, dir0, range, NULL, &hit0)); - SXD(scene_view_trace_ray(scn->sXd(view), org, dir1, range, NULL, &hit1)); - - if(SXD_HIT_NONE(&hit0) && SXD_HIT_NONE(&hit1)) { - /* Hit nothing: move along dir0 of the original delta */ - delta = delta_solid; - } else { - /* Hit something: move along dir0 of the minimum hit distance */ - delta = MMIN(hit0.distance, hit1.distance); - } - - /* Sample the time */ - mu = (2*DIM*lambda) / (rho*cp*delta*fp_to_meter*delta*fp_to_meter); - tau = ssp_ran_exp(rng, mu); - rwalk->vtx.time -= tau; - - /* Check the initial condition */ - tmp = solid_get_temperature(mdm, &rwalk->vtx); - if(tmp >= 0) { - T->value += tmp; - T->done = 1; - return RES_OK; - } - - /* Define if the random walk hits something along dir0 */ - rwalk->hit = hit0.distance > delta ? SXD_HIT_NULL : hit0; - - /* Update the random walk position */ - XD(move_pos)(rwalk->vtx.P, dir0, delta); - - /* Fetch the current medium */ - if(SXD_HIT_NONE(&rwalk->hit)) { - CHK(scene_get_medium(scn, rwalk->vtx.P, &mdm) == RES_OK); - } else { - const struct sdis_interface* interf; - interf = scene_get_interface(scn, rwalk->hit.prim.prim_id); - mdm = interface_get_medium - (interf, - fX(dot(rwalk->hit.normal, dir0)) < 0 ? SDIS_FRONT : SDIS_BACK); - } - - /* Check random walk consistency */ - if(mdm != rwalk->mdm) { - log_err(scn->dev, - "%s: inconsistent medium during the solid random walk.\n", FUNC_NAME); - if(DIM == 2) { - log_err(scn->dev, - " start position: %g %g; current position: %g %g\n", - SPLIT2(position_start), SPLIT2(rwalk->vtx.P)); - } else { - log_err(scn->dev, - " start position: %g %g %g; current position: %g %g %g\n", - SPLIT3(position_start), SPLIT3(rwalk->vtx.P)); - } - return RES_BAD_OP; - } - - /* Keep going while the solid random walk does not hit an interface */ - } while(SXD_HIT_NONE(&rwalk->hit)); - - T->func = XD(boundary_temperature); - return RES_OK; -} - -static res_T -XD(compute_temperature) - (struct sdis_scene* scn, - const double fp_to_meter, - struct XD(rwalk)* rwalk, - struct ssp_rng* rng, - struct XD(temperature)* T) -{ -#ifndef NDEBUG - struct XD(temperature)* stack = NULL; - size_t istack = 0; -#endif - res_T res = RES_OK; - ASSERT(scn && fp_to_meter && rwalk && rng && T); - - do { - res = T->func(scn, fp_to_meter, rwalk, rng, T); - if(res != RES_OK) goto error; - -#ifndef NDEBUG - sa_push(stack, *T); - ++istack; -#endif - } while(!T->done); - -exit: -#ifndef NDEBUG - sa_release(stack); -#endif - return res; -error: - goto exit; -} - -static res_T -XD(probe_realisation) - (struct sdis_scene* scn, - struct ssp_rng* rng, - const struct sdis_medium* medium, - const double position[], - const double time, - const double fp_to_meter,/* Scale factor from floating point unit to meter */ - double* weight) -{ - struct XD(rwalk) rwalk = XD(RWALK_NULL); - struct XD(temperature) T = XD(TEMPERATURE_NULL); - res_T res = RES_OK; - ASSERT(medium && position && fp_to_meter > 0 && weight && time >= 0); - - switch(medium->type) { - case SDIS_MEDIUM_FLUID: T.func = XD(fluid_temperature); break; - case SDIS_MEDIUM_SOLID: T.func = XD(solid_temperature); break; - default: FATAL("Unreachable code\n"); break; - } - - dX(set)(rwalk.vtx.P, position); - rwalk.vtx.time = time; - rwalk.hit = SXD_HIT_NULL; - rwalk.mdm = medium; - - res = XD(compute_temperature)(scn, fp_to_meter, &rwalk, rng, &T); - if(res != RES_OK) return res; - - *weight = T.value; - return RES_OK; -} - - -#undef SDIS_SOLVE_PROBE_DIMENSION -#undef DIM -#undef sXd -#undef SXD_HIT_NONE -#undef SXD_HIT_NULL -#undef SXD_HIT_NULL__ -#undef SXD -#undef dX -#undef fX -#undef fX_set_dX -#undef XD - -#endif /* !SDIS_SOLVE_PROBE_DIMENSION */ - diff --git a/src/test_sdis_accum_buffer.c b/src/test_sdis_accum_buffer.c @@ -0,0 +1,77 @@ +/* Copyright (C) |Meso|Star> 2016-2018 (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 "test_sdis_utils.h" +#include <string.h> + +int +main(int argc, char** argv) +{ + struct mem_allocator allocator; + struct sdis_accum_buffer* buf = NULL; + struct sdis_device* dev = NULL; + struct sdis_accum_buffer_layout layout; + const struct sdis_accum* accums = NULL; + struct sdis_accum* accums_tmp = NULL; + (void)argc, (void)argv; + + CHK(mem_init_proxy_allocator(&allocator, &mem_default_allocator) == RES_OK); + CHK(sdis_device_create + (NULL, &allocator, SDIS_NTHREADS_DEFAULT, 0, &dev) == RES_OK); + + CHK(sdis_accum_buffer_create(NULL, 4 ,4, &buf) == RES_BAD_ARG); + CHK(sdis_accum_buffer_create(dev, 0 ,4, &buf) == RES_BAD_ARG); + CHK(sdis_accum_buffer_create(dev, 4 ,0, &buf) == RES_BAD_ARG); + CHK(sdis_accum_buffer_create(dev, 4 ,0, NULL) == RES_BAD_ARG); + CHK(sdis_accum_buffer_create(dev, 4 ,4, &buf) == RES_OK); + + CHK(sdis_accum_buffer_ref_get(NULL) == RES_BAD_ARG); + CHK(sdis_accum_buffer_ref_get(buf) == RES_OK); + CHK(sdis_accum_buffer_ref_put(NULL) == RES_BAD_ARG); + CHK(sdis_accum_buffer_ref_put(buf) == RES_OK); + CHK(sdis_accum_buffer_ref_put(buf) == RES_OK); + + CHK(sdis_accum_buffer_create(dev, 16, 8, &buf) == RES_OK); + + CHK(sdis_accum_buffer_get_layout(NULL, &layout) == RES_BAD_ARG); + CHK(sdis_accum_buffer_get_layout(buf, NULL) == RES_BAD_ARG); + CHK(sdis_accum_buffer_get_layout(buf, &layout) == RES_OK); + + CHK(layout.width == 16); + CHK(layout.height == 8); + + CHK(sdis_accum_buffer_map(NULL, &accums) == RES_BAD_ARG); + CHK(sdis_accum_buffer_map(buf, NULL) == RES_BAD_ARG); + CHK(sdis_accum_buffer_map(buf, &accums) == RES_OK); + + /* Check the accessibility to the mapped data */ + accums_tmp = MEM_CALLOC + (&allocator, layout.width*layout.height, sizeof(struct sdis_accum)); + CHK(accums_tmp != NULL); + memcpy(accums_tmp, accums_tmp, + layout.width*layout.height*sizeof(struct sdis_accum)); + MEM_RM(&allocator, accums_tmp); + + CHK(sdis_accum_buffer_unmap(NULL) == RES_BAD_ARG); + CHK(sdis_accum_buffer_unmap(buf) == RES_OK); + + CHK(sdis_accum_buffer_ref_put(buf) == RES_OK); + CHK(sdis_device_ref_put(dev) == RES_OK); + + check_memory_allocator(&allocator); + mem_shutdown_proxy_allocator(&allocator); + CHK(mem_allocated_size() == 0); + return 0; +} diff --git a/src/test_sdis_camera.c b/src/test_sdis_camera.c @@ -0,0 +1,94 @@ +/* Copyright (C) |Meso|Star> 2016-2018 (contact@meso-star.com) + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. */ + +#include "sdis.h" +#include "test_sdis_utils.h" + +#include <rsys/math.h> + +int +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; + + CHK(mem_init_proxy_allocator(&allocator, &mem_default_allocator) == RES_OK); + + CHK(sdis_device_create + (NULL, &allocator, SDIS_NTHREADS_DEFAULT, 0, &dev) == RES_OK); + + CHK(sdis_camera_create(NULL, NULL) == RES_BAD_ARG); + CHK(sdis_camera_create(dev, NULL) == RES_BAD_ARG); + CHK(sdis_camera_create(NULL, &cam) == RES_BAD_ARG); + CHK(sdis_camera_create(dev, &cam) == RES_OK); + + CHK(sdis_camera_ref_get(NULL) == RES_BAD_ARG); + CHK(sdis_camera_ref_get(cam) == RES_OK); + CHK(sdis_camera_ref_put(NULL) == RES_BAD_ARG); + CHK(sdis_camera_ref_put(cam) == RES_OK); + CHK(sdis_camera_ref_put(cam) == RES_OK); + + CHK(sdis_camera_create(dev, &cam) == RES_OK); + CHK(sdis_camera_set_proj_ratio(NULL, 0) == RES_BAD_ARG); + CHK(sdis_camera_set_proj_ratio(cam, 0) == RES_BAD_ARG); + CHK(sdis_camera_set_proj_ratio(NULL, 4.0/3.0) == RES_BAD_ARG); + CHK(sdis_camera_set_proj_ratio(cam, 4.0/3.0) == RES_OK); + CHK(sdis_camera_set_proj_ratio(cam, -4.0/3.0) == RES_BAD_ARG); + + CHK(sdis_camera_set_fov(NULL, 0) == RES_BAD_ARG); + CHK(sdis_camera_set_fov(cam, 0) == RES_BAD_ARG); + CHK(sdis_camera_set_fov(NULL, PI/4.0) == RES_BAD_ARG); + CHK(sdis_camera_set_fov(cam, PI/4.0) == RES_OK); + CHK(sdis_camera_set_fov(cam, -PI/4.0) == RES_BAD_ARG); + + pos[0] = 0, pos[1] = 0, pos[2] = 0; + tgt[0] = 0, tgt[1] = 0, tgt[2] = -1; + up[0] = 0, up[1] = 1, up[2] = 0; + CHK(sdis_camera_look_at(NULL, NULL, NULL, NULL) == RES_BAD_ARG); + CHK(sdis_camera_look_at(cam, NULL, NULL, NULL) == RES_BAD_ARG); + CHK(sdis_camera_look_at(NULL, pos, NULL, NULL) == RES_BAD_ARG); + CHK(sdis_camera_look_at(cam, pos, NULL, NULL) == RES_BAD_ARG); + CHK(sdis_camera_look_at(NULL, NULL, tgt, NULL) == RES_BAD_ARG); + CHK(sdis_camera_look_at(cam, NULL, tgt, NULL) == RES_BAD_ARG); + CHK(sdis_camera_look_at(NULL, pos, tgt, NULL) == RES_BAD_ARG); + CHK(sdis_camera_look_at(cam, pos, tgt, NULL) == RES_BAD_ARG); + CHK(sdis_camera_look_at(NULL, NULL, NULL, up) == RES_BAD_ARG); + CHK(sdis_camera_look_at(cam, NULL, NULL, up) == RES_BAD_ARG); + CHK(sdis_camera_look_at(NULL, pos, NULL, up) == RES_BAD_ARG); + CHK(sdis_camera_look_at(cam, pos, NULL, up) == RES_BAD_ARG); + CHK(sdis_camera_look_at(NULL, NULL, tgt, up) == RES_BAD_ARG); + CHK(sdis_camera_look_at(cam, NULL, tgt, up) == RES_BAD_ARG); + CHK(sdis_camera_look_at(NULL, pos, tgt, up) == RES_BAD_ARG); + CHK(sdis_camera_look_at(cam, pos, tgt, up) == RES_OK); + tgt[0] = 0, tgt[1] = 0, tgt[2] = 0; + CHK(sdis_camera_look_at(cam, pos, tgt, up) == RES_BAD_ARG); + tgt[0] = 0, tgt[1] = 0, tgt[2] = -1; + up[0] = 0, up[1] = 0, up[2] = 0; + CHK(sdis_camera_look_at(cam, pos, tgt, up) == RES_BAD_ARG); + + CHK(sdis_device_ref_put(dev) == RES_OK); + CHK(sdis_camera_ref_put(cam) == RES_OK); + + check_memory_allocator(&allocator); + mem_shutdown_proxy_allocator(&allocator); + CHK(mem_allocated_size() == 0); + return 0; +} + diff --git a/src/test_sdis_conducto_radiative.c b/src/test_sdis_conducto_radiative.c @@ -0,0 +1,430 @@ +/* Copyright (C) |Meso|Star> 2016-2018 (contact@meso-star.com) + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. */ + +#include "sdis.h" +#include "test_sdis_utils.h" + +#include <rsys/math.h> +#include <star/ssp.h> + +#define UNKNOWN_TEMPERATURE -1 + +/* The scene is composed of a solid cube whose temperature is unknown. The cube + * faces on +/-X are in contact with a fluid and their convection coefficient + * is null while their emissivity is 1. The left and right fluids are enclosed + * by surfaces whose emissivity are null excepted for the faces orthogonal to + * the X axis that are fully emissive and whose temperature is known. The + * medium that surrounds the solid cube and the 2 fluids is a solid with a null + * conductivity. + * + * Y (1, 1, 1) + * | +------+----------+------+ (1.5,1,1) + * o--- X /' /##########/' /| + * / +------+----------+------+ | + * Z | ' |##########|*' | | 310K + * | ' |##########|*' | | + * 300K | ' E=1|##########|*'E=1 | | + * | +....|##########|*+....|.+ + * |/ |##########|/ |/ + * (-1.5,-1,-1) +------+----------+------+ + * (-1,-1,-1) + */ + +/******************************************************************************* + * Geometry + ******************************************************************************/ +struct geometry { + const double* positions; + const size_t* indices; + struct sdis_interface** interfaces; +}; + +static const double vertices[16/*#vertices*/*3/*#coords per vertex*/] = { + -1.0,-1.0,-1.0, + 1.0,-1.0,-1.0, + -1.0, 1.0,-1.0, + 1.0, 1.0,-1.0, + -1.0,-1.0, 1.0, + 1.0,-1.0, 1.0, + -1.0, 1.0, 1.0, + 1.0, 1.0, 1.0, + -1.5,-1.0,-1.0, + 1.5,-1.0,-1.0, + -1.5, 1.0,-1.0, + 1.5, 1.0,-1.0, + -1.5,-1.0, 1.0, + 1.5,-1.0, 1.0, + -1.5, 1.0, 1.0, + 1.5, 1.0, 1.0, +}; +static const size_t nvertices = sizeof(vertices) / sizeof(double[3]); + +static const size_t indices[32/*#triangles*/*3/*#indices per triangle*/] = { + 0, 2, 1, 1, 2, 3, /* Solid back face */ + 0, 4, 2, 2, 4, 6, /* Solid left face*/ + 4, 5, 6, 6, 5, 7, /* Solid front face */ + 3, 7, 1, 1, 7, 5, /* Solid right face */ + 2, 6, 3, 3, 6, 7, /* Solid top face */ + 0, 1, 4, 4, 1, 5, /* Solid bottom face */ + + 8, 10, 0, 0, 10, 2, /* Left fluid back face */ + 8, 12, 10, 10, 12, 14, /* Left fluid left face */ + 12, 4, 14, 14, 4, 6, /* Left fluid front face */ + 10, 14, 2, 2, 14, 6, /* Left fluid top face */ + 8, 0, 12, 12, 0, 4, /* Left fluid bottom face */ + + 1, 3, 9, 9, 3, 11, /* Right fluid back face */ + 5, 13, 7, 7, 13, 15, /* Right fluid front face */ + 11, 15, 9, 9, 15, 13, /* Right fluid right face */ + 3, 7, 11, 11, 7, 15, /* Right fluid top face */ + 1, 9, 5, 5, 9, 13 /* Right fluid bottom face */ +}; +static const size_t ntriangles = sizeof(indices) / sizeof(size_t[3]); + +static void +get_indices(const size_t itri, size_t ids[3], void* ctx) +{ + struct geometry* geom = ctx; + CHK(ctx != NULL); + ids[0] = geom->indices[itri*3+0]; + ids[1] = geom->indices[itri*3+1]; + ids[2] = geom->indices[itri*3+2]; +} + +static void +get_position(const size_t ivert, double pos[3], void* ctx) +{ + struct geometry* geom = ctx; + CHK(ctx != NULL); + pos[0] = geom->positions[ivert*3+0]; + pos[1] = geom->positions[ivert*3+1]; + pos[2] = geom->positions[ivert*3+2]; +} + +static void +get_interface(const size_t itri, struct sdis_interface** bound, void* ctx) +{ + struct geometry* geom = ctx; + CHK(ctx != NULL); + *bound = geom->interfaces[itri]; +} + +/******************************************************************************* + * Media + ******************************************************************************/ +struct solid { + double lambda; +}; + +static double +temperature_unknown(const struct sdis_rwalk_vertex* vtx, struct sdis_data* data) +{ + CHK(vtx != NULL); (void)data; + return -1; +} + +static double +solid_get_calorific_capacity + (const struct sdis_rwalk_vertex* vtx, struct sdis_data* data) +{ + CHK(vtx != NULL); (void)data; + return 1; +} + +static double +solid_get_thermal_conductivity + (const struct sdis_rwalk_vertex* vtx, struct sdis_data* data) +{ + CHK(vtx != NULL); + CHK(data != NULL); + return ((const struct solid*)sdis_data_cget(data))->lambda; +} + +static double +solid_get_volumic_mass + (const struct sdis_rwalk_vertex* vtx, struct sdis_data* data) +{ + CHK(vtx != NULL); (void)data; + return 1; +} + +static double +solid_get_delta + (const struct sdis_rwalk_vertex* vtx, struct sdis_data* data) +{ + CHK(vtx != NULL); (void)data; + return 1.0/10.0; +} + +static double +solid_get_delta_boundary + (const struct sdis_rwalk_vertex* vtx, struct sdis_data* data) +{ + CHK(vtx != NULL); (void)data; + return 2.1/10.0; +} + +/******************************************************************************* + * Interface + ******************************************************************************/ +struct interface { + double temperature; + double convection_coef; + double emissivity; + double specular_fraction; +}; + +static double +interface_get_temperature + (const struct sdis_interface_fragment* frag, struct sdis_data* data) +{ + CHK(data != NULL && frag != NULL); + return ((const struct interface*)sdis_data_cget(data))->temperature; +} + +static double +interface_get_convection_coef + (const struct sdis_interface_fragment* frag, struct sdis_data* data) +{ + CHK(data != NULL && frag != NULL); + return ((const struct interface*)sdis_data_cget(data))->convection_coef; +} + +static double +interface_get_emissivity + (const struct sdis_interface_fragment* frag, struct sdis_data* data) +{ + CHK(data != NULL && frag != NULL); + return ((const struct interface*)sdis_data_cget(data))->emissivity; +} + +static double +interface_get_specular_fraction + (const struct sdis_interface_fragment* frag, struct sdis_data* data) +{ + CHK(data != NULL && frag != NULL); + return ((const struct interface*)sdis_data_cget(data))->specular_fraction; +} + +/******************************************************************************* + * Helper functions + ******************************************************************************/ +static void +create_interface + (struct sdis_device* dev, + struct sdis_medium* front, + struct sdis_medium* back, + const struct interface* interf, + struct sdis_interface** out_interf) +{ + struct sdis_interface_shader shader = DUMMY_INTERFACE_SHADER; + struct sdis_data* data = NULL; + + CHK(interf != NULL); + + shader.temperature = interface_get_temperature; + shader.convection_coef = interface_get_convection_coef; + shader.emissivity = interface_get_emissivity; + shader.specular_fraction = interface_get_specular_fraction; + + CHK(sdis_data_create(dev, sizeof(struct interface), ALIGNOF(struct interface), + NULL, &data) == RES_OK); + *((struct interface*)sdis_data_get(data)) = *interf; + + CHK(sdis_interface_create(dev, front, back, &shader, data, out_interf) == RES_OK); + CHK(sdis_data_ref_put(data) == RES_OK); +} + +/******************************************************************************* + * Test + ******************************************************************************/ +int +main(int argc, char** argv) +{ + struct mem_allocator allocator; + struct interface interf; + struct geometry geom; + struct sdis_data* data = NULL; + struct sdis_device* dev = NULL; + struct sdis_medium* fluid = NULL; + struct sdis_medium* solid = NULL; + struct sdis_medium* solid2 = NULL; + struct sdis_interface* interfaces[5] = {NULL}; + struct sdis_interface* prim_interfaces[32/*#triangles*/]; + struct sdis_fluid_shader fluid_shader = DUMMY_FLUID_SHADER; + struct sdis_solid_shader solid_shader = DUMMY_SOLID_SHADER; + struct sdis_scene* scn = NULL; + struct ssp_rng* rng = NULL; + const size_t nsimuls = 4; + size_t isimul; + const double emissivity = 1;/* Emissivity of the side +/-X of the solid */ + const double lambda = 0.1; /* Conductivity of the solid */ + const double Tref = 300; /* Reference temperature */ + const double T0 = 300; /* Fixed temperature on the left side of the system */ + const double T1 = 310; /* Fixed temperature on the right side of the system */ + const double thickness = 2.0; /* Thickness of the solid along X */ + double Ts0, Ts1, hr, tmp; + (void)argc, (void)argv; + + CHK(mem_init_proxy_allocator(&allocator, &mem_default_allocator) == RES_OK); + CHK(sdis_device_create + (NULL, &allocator, SDIS_NTHREADS_DEFAULT, 1, &dev) == RES_OK); + + /* Create the fluid medium */ + fluid_shader.temperature = temperature_unknown; + CHK(sdis_fluid_create(dev, &fluid_shader, NULL, &fluid) == RES_OK); + + /* Create the solid medium */ + CHK(sdis_data_create(dev, sizeof(struct solid), ALIGNOF(struct solid), + NULL, &data) == RES_OK); + ((struct solid*)sdis_data_get(data))->lambda = lambda; + solid_shader.calorific_capacity = solid_get_calorific_capacity; + solid_shader.thermal_conductivity = solid_get_thermal_conductivity; + solid_shader.volumic_mass = solid_get_volumic_mass; + solid_shader.delta_solid = solid_get_delta; + solid_shader.delta_boundary = solid_get_delta_boundary; + solid_shader.temperature = temperature_unknown; + CHK(sdis_solid_create(dev, &solid_shader, data, &solid) == RES_OK); + CHK(sdis_data_ref_put(data) == RES_OK); + + /* Create the surrounding solid medium */ + CHK(sdis_data_create(dev, sizeof(struct solid), ALIGNOF(struct solid), + NULL, &data) == RES_OK); + ((struct solid*)sdis_data_get(data))->lambda = 0; + solid_shader.calorific_capacity = solid_get_calorific_capacity; + solid_shader.thermal_conductivity = solid_get_thermal_conductivity; + solid_shader.volumic_mass = solid_get_volumic_mass; + solid_shader.delta_solid = solid_get_delta; + solid_shader.delta_boundary = solid_get_delta_boundary; + solid_shader.temperature = temperature_unknown; + CHK(sdis_solid_create(dev, &solid_shader, data, &solid2) == RES_OK); + CHK(sdis_data_ref_put(data) == RES_OK); + + /* Create the interface that forces to keep in conduction */ + interf.temperature = UNKNOWN_TEMPERATURE; + interf.convection_coef = -1; + interf.emissivity = -1; + interf.specular_fraction = -1; + create_interface(dev, solid, solid2, &interf, interfaces+0); + + /* Create the interface that emits radiative heat from the solid */ + interf.temperature = UNKNOWN_TEMPERATURE; + interf.convection_coef = 0; + interf.emissivity = emissivity; + interf.specular_fraction = 1; + create_interface(dev, solid, fluid, &interf, interfaces+1); + + /* Create the interface that forces the radiative heat to bounce */ + interf.temperature = UNKNOWN_TEMPERATURE; + interf.convection_coef = 0; + interf.emissivity = 0; + interf.specular_fraction = 1; + create_interface(dev, fluid, solid2, &interf, interfaces+2); + + /* Create the interface with a limit condition of T0 Kelvin */ + interf.temperature = T0; + interf.convection_coef = 0; + interf.emissivity = 1; + interf.specular_fraction = 1; + create_interface(dev, fluid, solid2, &interf, interfaces+3); + + /* Create the interface with a limit condition of T1 Kelvin */ + interf.temperature = T1; + interf.convection_coef = 0; + interf.emissivity = 1; + interf.specular_fraction = 1; + create_interface(dev, fluid, solid2, &interf, interfaces+4); + + /* Setup the per primitive interface of the solid medium */ + prim_interfaces[0] = prim_interfaces[1] = interfaces[0]; + prim_interfaces[2] = prim_interfaces[3] = interfaces[1]; + prim_interfaces[4] = prim_interfaces[5] = interfaces[0]; + prim_interfaces[6] = prim_interfaces[7] = interfaces[1]; + prim_interfaces[8] = prim_interfaces[9] = interfaces[0]; + prim_interfaces[10] = prim_interfaces[11] = interfaces[0]; + + /* Setup the per primitive interface of the fluid on the left of the medium */ + prim_interfaces[12] = prim_interfaces[13] = interfaces[2]; + prim_interfaces[14] = prim_interfaces[15] = interfaces[3]; + prim_interfaces[16] = prim_interfaces[17] = interfaces[2]; + prim_interfaces[18] = prim_interfaces[19] = interfaces[2]; + prim_interfaces[20] = prim_interfaces[21] = interfaces[2]; + + /* Setup the per primitive interface of the fluid on the right of the medium */ + prim_interfaces[22] = prim_interfaces[23] = interfaces[2]; + prim_interfaces[24] = prim_interfaces[25] = interfaces[2]; + prim_interfaces[26] = prim_interfaces[27] = interfaces[4]; + prim_interfaces[28] = prim_interfaces[29] = interfaces[2]; + prim_interfaces[30] = prim_interfaces[31] = interfaces[2]; + + /* Create the scene */ + geom.positions = vertices; + geom.indices = indices; + geom.interfaces = prim_interfaces; + CHK(sdis_scene_create(dev, ntriangles, get_indices, get_interface, nvertices, + get_position, &geom, &scn) == RES_OK); + + hr = 4.0 * BOLTZMANN_CONSTANT * Tref*Tref*Tref * emissivity; + tmp = lambda/(2*lambda + thickness*hr) * (T1 - T0); + Ts0 = T0 + tmp; + Ts1 = T1 - tmp; + + /* Run the simulations */ + CHK(ssp_rng_create(&allocator, &ssp_rng_kiss, &rng) == RES_OK); + FOR_EACH(isimul, 0, nsimuls) { + struct sdis_mc T = SDIS_MC_NULL; + struct sdis_estimator* estimator; + double pos[3]; + double ref, u; + size_t nreals = 0; + size_t nfails = 0; + + pos[0] = ssp_rng_uniform_double(rng, -0.9, 0.9); + pos[1] = ssp_rng_uniform_double(rng, -0.9, 0.9); + pos[2] = ssp_rng_uniform_double(rng, -0.9, 0.9); + + CHK(sdis_solve_probe(scn, 10000, pos, INF, 1, -1, Tref, &estimator) == RES_OK); + CHK(sdis_estimator_get_realisation_count(estimator, &nreals) == RES_OK); + CHK(sdis_estimator_get_failure_count(estimator, &nfails) == RES_OK); + CHK(sdis_estimator_get_temperature(estimator, &T) == RES_OK); + + u = (pos[0] + 1) / thickness; + ref = u * Ts1 + (1-u) * Ts0; + printf("Temperature at (%g, %g, %g) = %g ~ %g +/- %g\n", + SPLIT3(pos), ref, T.E, T.SE); + + CHK(eq_eps(T.E, ref, 2*T.SE) == 1); + + CHK(sdis_estimator_ref_put(estimator) == RES_OK); + } + + /* Release memory */ + CHK(sdis_scene_ref_put(scn) == RES_OK); + CHK(sdis_interface_ref_put(interfaces[0]) == RES_OK); + CHK(sdis_interface_ref_put(interfaces[1]) == RES_OK); + CHK(sdis_interface_ref_put(interfaces[2]) == RES_OK); + CHK(sdis_interface_ref_put(interfaces[3]) == RES_OK); + CHK(sdis_interface_ref_put(interfaces[4]) == RES_OK); + CHK(sdis_medium_ref_put(fluid) == RES_OK); + CHK(sdis_medium_ref_put(solid) == RES_OK); + CHK(sdis_medium_ref_put(solid2) == RES_OK); + CHK(sdis_device_ref_put(dev) == RES_OK); + CHK(ssp_rng_ref_put(rng) == RES_OK); + + check_memory_allocator(&allocator); + mem_shutdown_proxy_allocator(&allocator); + CHK(mem_allocated_size() == 0); + return 0; +} diff --git a/src/test_sdis_conducto_radiative_2d.c b/src/test_sdis_conducto_radiative_2d.c @@ -0,0 +1,405 @@ +/* Copyright (C) |Meso|Star> 2016-2018 (contact@meso-star.com) + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. */ + +#include "sdis.h" +#include "test_sdis_utils.h" + +#include <star/ssp.h> + +#define UNKNOWN_TEMPERATURE -1 + +/* The scene is composed of a solid square whose temperature is unknown. The + * square segments on +/-X are in contact with a fluid and their convection + * coefficient is null while their emissivity is 1. The left and right fluids + * are enclosed by segments whose emissivity are null excepted for the segments + * orthogonal to the X axis that are fully emissive and whose temperature is + * known. The medium that surrounds the solid square and the 2 fluids is a + * solid with a null conductivity. + * + * (1, 1) + * +-----+----------+-----+ (1.5,1,1) + * | |##########| | + * | |##########| | + * 300K | E=1 |##########| E=1 | 310K + * | |##########| | + * | |##########| | + * (-1.5,-1) +-----+----------+-----+ + * (-1,-1) + */ + +/******************************************************************************* + * Geometry + ******************************************************************************/ +struct geometry { + const double* positions; + const size_t* indices; + struct sdis_interface** interfaces; +}; + +static const double vertices[8/*#vertices*/*2/*#coords par vertex*/] = { + 1.0, -1.0, + -1.0, -1.0, + -1.0, 1.0, + 1.0, 1.0, + 1.5, -1.0, + -1.5, -1.0, + -1.5, 1.0, + 1.5, 1.0 +}; +static const size_t nvertices = sizeof(vertices) / sizeof(double[2]); + +static const size_t indices[10/*#segments*/*2/*#indices per segment*/] = { + 0, 1, /* Solid bottom segment */ + 1, 2, /* Solid left segment */ + 2, 3, /* Solid top segment */ + 3, 0, /* Solid right segment */ + + 1, 5, /* Left fluid bottom segment */ + 5, 6, /* Left fluid left segment */ + 6, 2, /* Left fluid top segment */ + + 4, 0, /* Right fluid bottom segment */ + 3, 7, /* Right fluid top segment */ + 7, 4 /* Right fluid right segment */ +}; +static const size_t nsegments = sizeof(indices) / sizeof(size_t[2]); + +static void +get_indices(const size_t iseg, size_t ids[2], void* ctx) +{ + struct geometry* geom = ctx; + CHK(ctx != NULL); + ids[0] = geom->indices[iseg*2+0]; + ids[1] = geom->indices[iseg*2+1]; +} + +static void +get_position(const size_t ivert, double pos[2], void* ctx) +{ + struct geometry* geom = ctx; + CHK(ctx != NULL); + pos[0] = geom->positions[ivert*2+0]; + pos[1] = geom->positions[ivert*2+1]; +} + +static void +get_interface(const size_t iseg, struct sdis_interface** bound, void* ctx) +{ + struct geometry* geom = ctx; + CHK(ctx != NULL); + *bound = geom->interfaces[iseg]; +} + +/******************************************************************************* + * Media + ******************************************************************************/ +struct solid { + double lambda; +}; + +static double +temperature_unknown(const struct sdis_rwalk_vertex* vtx, struct sdis_data* data) +{ + CHK(vtx != NULL); (void)data; + return -1; +} + +static double +solid_get_calorific_capacity + (const struct sdis_rwalk_vertex* vtx, struct sdis_data* data) +{ + CHK(vtx != NULL); (void)data; + return 1; +} + +static double +solid_get_thermal_conductivity + (const struct sdis_rwalk_vertex* vtx, struct sdis_data* data) +{ + CHK(vtx != NULL); + CHK(data != NULL); + return ((const struct solid*)sdis_data_cget(data))->lambda; +} + +static double +solid_get_volumic_mass + (const struct sdis_rwalk_vertex* vtx, struct sdis_data* data) +{ + CHK(vtx != NULL); (void)data; + return 1; +} + +static double +solid_get_delta + (const struct sdis_rwalk_vertex* vtx, struct sdis_data* data) +{ + CHK(vtx != NULL); (void)data; + return 1.0/10.0; +} + +static double +solid_get_delta_boundary + (const struct sdis_rwalk_vertex* vtx, struct sdis_data* data) +{ + CHK(vtx != NULL); (void)data; + return 2.1/10.0; +} + +/******************************************************************************* + * Interface + ******************************************************************************/ +struct interface { + double temperature; + double convection_coef; + double emissivity; + double specular_fraction; +}; + +static double +interface_get_temperature + (const struct sdis_interface_fragment* frag, struct sdis_data* data) +{ + CHK(data != NULL && frag != NULL); + return ((const struct interface*)sdis_data_cget(data))->temperature; +} + +static double +interface_get_convection_coef + (const struct sdis_interface_fragment* frag, struct sdis_data* data) +{ + CHK(data != NULL && frag != NULL); + return ((const struct interface*)sdis_data_cget(data))->convection_coef; +} + +static double +interface_get_emissivity + (const struct sdis_interface_fragment* frag, struct sdis_data* data) +{ + CHK(data != NULL && frag != NULL); + return ((const struct interface*)sdis_data_cget(data))->emissivity; +} + +static double +interface_get_specular_fraction + (const struct sdis_interface_fragment* frag, struct sdis_data* data) +{ + CHK(data != NULL && frag != NULL); + return ((const struct interface*)sdis_data_cget(data))->specular_fraction; +} + +/******************************************************************************* + * Helper functions + ******************************************************************************/ +static void +create_interface + (struct sdis_device* dev, + struct sdis_medium* front, + struct sdis_medium* back, + const struct interface* interf, + struct sdis_interface** out_interf) +{ + struct sdis_interface_shader shader = DUMMY_INTERFACE_SHADER; + struct sdis_data* data = NULL; + + CHK(interf != NULL); + + shader.temperature = interface_get_temperature; + shader.convection_coef = interface_get_convection_coef; + shader.emissivity = interface_get_emissivity; + shader.specular_fraction = interface_get_specular_fraction; + + CHK(sdis_data_create(dev, sizeof(struct interface), ALIGNOF(struct interface), + NULL, &data) == RES_OK); + *((struct interface*)sdis_data_get(data)) = *interf; + + CHK(sdis_interface_create(dev, front, back, &shader, data, out_interf) == RES_OK); + CHK(sdis_data_ref_put(data) == RES_OK); +} + + +/******************************************************************************* + * Test + ******************************************************************************/ +int +main(int argc, char** argv) +{ + struct mem_allocator allocator; + struct interface interf; + struct geometry geom; + struct ssp_rng* rng = NULL; + struct sdis_scene* scn = NULL; + struct sdis_data* data = NULL; + struct sdis_device* dev = NULL; + struct sdis_medium* fluid = NULL; + struct sdis_medium* solid = NULL; + struct sdis_medium* solid2 = NULL; + struct sdis_interface* interfaces[5] = {NULL}; + struct sdis_interface* prim_interfaces[10/*#segment*/]; + struct sdis_fluid_shader fluid_shader = DUMMY_FLUID_SHADER; + struct sdis_solid_shader solid_shader = DUMMY_SOLID_SHADER; + const size_t nsimuls = 4; + size_t isimul; + const double emissivity = 1;/* Emissivity of the side +/-X of the solid */ + const double lambda = 0.1; /* Conductivity of the solid */ + const double Tref = 300; /* Reference temperature */ + const double T0 = 300; /* Fixed temperature on the left side of the system */ + const double T1 = 310; /* Fixed temperature on the right side of the system */ + const double thickness = 2.0; /* Thickness of the solid along X */ + double Ts0, Ts1, hr, tmp; + (void)argc, (void)argv; + + CHK(mem_init_proxy_allocator(&allocator, &mem_default_allocator) == RES_OK); + CHK(sdis_device_create(NULL, &allocator, SDIS_NTHREADS_DEFAULT, 1, &dev) == RES_OK); + + /* Create the fluid medium */ + fluid_shader.temperature = temperature_unknown; + CHK(sdis_fluid_create(dev, &fluid_shader, NULL, &fluid) == RES_OK); + + /* Create the solid medium */ + CHK(sdis_data_create + (dev, sizeof(struct solid), ALIGNOF(struct solid), NULL, &data) == RES_OK); + ((struct solid*)sdis_data_get(data))->lambda = lambda; + solid_shader.calorific_capacity = solid_get_calorific_capacity; + solid_shader.thermal_conductivity = solid_get_thermal_conductivity; + solid_shader.volumic_mass = solid_get_volumic_mass; + solid_shader.delta_solid = solid_get_delta; + solid_shader.delta_boundary = solid_get_delta_boundary; + solid_shader.temperature = temperature_unknown; + CHK(sdis_solid_create(dev, &solid_shader, data, &solid) == RES_OK); + CHK(sdis_data_ref_put(data) == RES_OK); + + /* Create the surrounding solid medium */ + CHK(sdis_data_create(dev, sizeof(struct solid), ALIGNOF(struct solid), + NULL, &data) == RES_OK); + ((struct solid*)sdis_data_get(data))->lambda = 0; + solid_shader.calorific_capacity = solid_get_thermal_conductivity; + solid_shader.thermal_conductivity = solid_get_thermal_conductivity; + solid_shader.volumic_mass = solid_get_volumic_mass; + solid_shader.delta_solid = solid_get_delta; + solid_shader.delta_boundary = solid_get_delta_boundary; + CHK(sdis_solid_create(dev, &solid_shader, data, &solid2) == RES_OK); + CHK(sdis_data_ref_put(data) == RES_OK); + + /* Create the interface that forces to keep in conduction */ + interf.temperature = UNKNOWN_TEMPERATURE; + interf.convection_coef = -1; + interf.emissivity = -1; + interf.specular_fraction = -1; + create_interface(dev, solid, solid2, &interf, interfaces+0); + + /* Create the interface that emits radiative heat from the solid */ + interf.temperature = UNKNOWN_TEMPERATURE; + interf.convection_coef = 0; + interf.emissivity = emissivity; + interf.specular_fraction = -1; + create_interface(dev, solid, fluid, &interf, interfaces+1); + + /* Create the interface that forces the radiative heat to bounce */ + interf.temperature = UNKNOWN_TEMPERATURE; + interf.convection_coef = 0; + interf.emissivity = 0; + interf.specular_fraction = 1; + create_interface(dev, fluid, solid2, &interf, interfaces+2); + + /* Create the interface with a limit condition of T0 Kelvin */ + interf.temperature = T0; + interf.convection_coef = 0; + interf.emissivity = 1; + interf.specular_fraction = 1; + create_interface(dev, fluid, solid2, &interf, interfaces+3); + + /* Create the interface with a limit condition of T1 Kelvin */ + interf.temperature = T1; + interf.convection_coef = 0; + interf.emissivity = 1; + interf.specular_fraction = 1; + create_interface(dev, fluid, solid2, &interf, interfaces+4); + + /* Setup the per primitive interface of the solid medium */ + prim_interfaces[0] = interfaces[0]; + prim_interfaces[1] = interfaces[1]; + prim_interfaces[2] = interfaces[0]; + prim_interfaces[3] = interfaces[1]; + + /* Setup the per primitive interface of the fluid on the left of the medium */ + prim_interfaces[4] = interfaces[2]; + prim_interfaces[5] = interfaces[3]; + prim_interfaces[6] = interfaces[2]; + + /* Setup the per primitive interface of the fluid on the right of the medium */ + prim_interfaces[7] = interfaces[2]; + prim_interfaces[8] = interfaces[2]; + prim_interfaces[9] = interfaces[4]; + + /* Create the scene */ + geom.positions = vertices; + geom.indices = indices; + geom.interfaces = prim_interfaces; + CHK(sdis_scene_2d_create(dev, nsegments, get_indices, get_interface, nvertices, + get_position, &geom, &scn) == RES_OK); + + hr = 4*BOLTZMANN_CONSTANT * Tref*Tref*Tref * emissivity; + tmp = lambda/(2*lambda + thickness*hr) * (T1 - T0); + Ts0 = T0 + tmp; + Ts1 = T1 - tmp; + + /* Run the simulations */ + CHK(ssp_rng_create(&allocator, &ssp_rng_kiss, &rng) == RES_OK); + FOR_EACH(isimul, 0, nsimuls) { + struct sdis_mc T = SDIS_MC_NULL; + struct sdis_estimator* estimator; + double pos[2]; + double ref, u; + size_t nreals = 0; + size_t nfails = 0; + + pos[0] = ssp_rng_uniform_double(rng, -0.9, 0.9); + pos[1] = ssp_rng_uniform_double(rng, -0.9, 0.9); + + CHK(sdis_solve_probe(scn, 10000, pos, INF, 1, -1, Tref, &estimator) == RES_OK); + CHK(sdis_estimator_get_realisation_count(estimator, &nreals) == RES_OK); + CHK(sdis_estimator_get_failure_count(estimator, &nfails) == RES_OK); + CHK(sdis_estimator_get_temperature(estimator, &T) == RES_OK); + + u = (pos[0] + 1) / thickness; + ref = u * Ts1 + (1-u) * Ts0; + printf("Temperature at (%g, %g) = %g ~ %g +/- %g\n", + SPLIT2(pos), ref, T.E, T.SE); + + CHK(eq_eps(T.E, ref, 2*T.SE) == 1); + + CHK(sdis_estimator_ref_put(estimator) == RES_OK); + } + + /* Release memory */ + CHK(sdis_scene_ref_put(scn) == RES_OK); + CHK(sdis_interface_ref_put(interfaces[0]) == RES_OK); + CHK(sdis_interface_ref_put(interfaces[1]) == RES_OK); + CHK(sdis_interface_ref_put(interfaces[2]) == RES_OK); + CHK(sdis_interface_ref_put(interfaces[3]) == RES_OK); + CHK(sdis_interface_ref_put(interfaces[4]) == RES_OK); + CHK(sdis_medium_ref_put(fluid) == RES_OK); + CHK(sdis_medium_ref_put(solid) == RES_OK); + CHK(sdis_medium_ref_put(solid2) == RES_OK); + CHK(ssp_rng_ref_put(rng) == RES_OK); + CHK(sdis_device_ref_put(dev) == RES_OK); + + 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 @@ -76,8 +76,11 @@ main(int argc, char** argv) CHK(sdis_interface_ref_put(interf) == RES_OK); CHK(sdis_interface_ref_put(interf) == RES_OK); - CHK(CREATE(dev, solid, solid, &shader, NULL, &interf) == RES_BAD_ARG); + CHK(CREATE(dev, solid, solid, &shader, NULL, &interf) == RES_OK); + CHK(sdis_interface_ref_put(interf) == RES_OK); shader.convection_coef = NULL; + shader.specular_fraction = NULL; + shader.emissivity = NULL; CHK(CREATE(dev, solid, solid, &shader, NULL, &interf) == RES_OK); CHK(sdis_interface_ref_put(interf) == RES_OK); @@ -87,6 +90,10 @@ main(int argc, char** argv) CHK(CREATE(dev, solid, fluid, &shader, NULL, &interf) == RES_BAD_ARG); shader.convection_coef = DUMMY_INTERFACE_SHADER.convection_coef; + CHK(CREATE(dev, solid, fluid, &shader, NULL, &interf) == RES_BAD_ARG); + shader.emissivity = DUMMY_INTERFACE_SHADER.emissivity; + CHK(CREATE(dev, solid, fluid, &shader, NULL, &interf) == RES_BAD_ARG); + shader.specular_fraction = DUMMY_INTERFACE_SHADER.specular_fraction; CHK(CREATE(dev, solid, fluid, &shader, NULL, &interf) == RES_OK); CHK(sdis_interface_ref_put(interf) == RES_OK); #undef CREATE diff --git a/src/test_sdis_solve_camera.c b/src/test_sdis_solve_camera.c @@ -0,0 +1,623 @@ +/* Copyright (C) |Meso|Star> 2016-2018 (contact@meso-star.com) + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. */ + +#include "sdis.h" +#include "test_sdis_utils.h" + +#include <star/s3dut.h> + +#include <rsys/algorithm.h> +#include <rsys/image.h> +#include <rsys/double3.h> +#include <rsys/double33.h> +#include <rsys/math.h> +#include <rsys/stretchy_array.h> + +#include <string.h> + +#define UNKOWN_TEMPERATURE -1 +#define IMG_WIDTH 640 +#define IMG_HEIGHT 480 +#define SPP 4 /* #Samples per pixel, i.e. #realisations per pixel */ + +/* + * The scene is composed of a solid cube whose temperature is unknown. The + * emissivity of the cube is 1 and its convection coefficient with the + * surrounding fluid is null. At the center of the cube there is a spherical + * fluid cavity whose temperature is 350K. The convection coefficient between + * the solid and the cavity is 1 and the emissivity of this interface is null. + * The ambient radiative temperature of the system is 300K. + * + * In this test, we compute the radiative temperature that reaches a camera + * that looks the cube and we `dump' a normalized image of the result. + * + * (1,1,1) + * +----------------+ + * /' # # /| + * +----*--------*--+ | + * | ' # # | | + * | ' # 350K # | | + * | ' # # | | + * | +.....#..#.....|.+ + * |/ |/ + * +----------------+ + * (-1,-1,-1) + */ + +/******************************************************************************* + * Geometry + ******************************************************************************/ +struct map_interf { + size_t key; + struct sdis_interface* interf; +}; + +static int +cmp_map_inter(const void* key, const void* elmt) +{ + const size_t* iprim = key; + const struct map_interf* interf = elmt; + if(*iprim < interf->key) return -1; + else if(*iprim > interf->key) return 1; + else return 0; +} + +struct geometry { + double* positions; + size_t* indices; + struct map_interf* interfaces; +}; +static const struct geometry GEOMETRY_NULL = {NULL, NULL, NULL}; + +static void +geometry_release(struct geometry* geom) +{ + CHK(geom != NULL); + sa_release(geom->positions); + sa_release(geom->indices); + sa_release(geom->interfaces); + *geom = GEOMETRY_NULL; +} + +static void +geometry_get_indices(const size_t itri, size_t ids[3], void* ctx) +{ + struct geometry* geom = ctx; + + CHK(ids != NULL); + CHK(geom != NULL); + CHK(itri < sa_size(geom->indices)/3/*#indices per triangle*/); + + /* Fetch the indices */ + ids[0] = geom->indices[itri*3+0]; + ids[1] = geom->indices[itri*3+1]; + ids[2] = geom->indices[itri*3+2]; +} + +static void +geometry_get_position(const size_t ivert, double pos[3], void* ctx) +{ + struct geometry* geom = ctx; + + CHK(pos != NULL); + CHK(geom != NULL); + CHK(ivert < sa_size(geom->positions)/3/*#coords per triangle*/); + + /* Fetch the vertices */ + pos[0] = geom->positions[ivert*3+0]; + pos[1] = geom->positions[ivert*3+1]; + pos[2] = geom->positions[ivert*3+2]; +} + +static void +geometry_get_interface + (const size_t itri, + struct sdis_interface** bound, + void* ctx) +{ + struct geometry* geom = ctx; + struct map_interf* interf = NULL; + + CHK(bound != NULL); + CHK(geom != NULL); + CHK(itri < sa_size(geom->indices)/3/*#indices per triangle*/); + + /* Find the interface of the triangle */ + interf = search_lower_bound(&itri, geom->interfaces, + sa_size(geom->interfaces), sizeof(struct map_interf), cmp_map_inter); + + CHK(interf != NULL); + CHK(interf->key >= itri); + *bound = interf->interf; +} + +/******************************************************************************* + * Fluid medium + ******************************************************************************/ +struct fluid { + double cp; + double rho; + double temperature; +}; +static const struct fluid FLUID_NULL = {0, 0, UNKOWN_TEMPERATURE}; + +static double +fluid_get_calorific_capacity + (const struct sdis_rwalk_vertex* vtx, struct sdis_data* data) +{ + CHK(data != NULL && vtx != NULL); + return ((const struct fluid*)sdis_data_cget(data))->cp; +} + +static double +fluid_get_volumic_mass + (const struct sdis_rwalk_vertex* vtx, struct sdis_data* data) +{ + CHK(data != NULL && vtx != NULL); + return ((const struct fluid*)sdis_data_cget(data))->rho; +} + +static double +fluid_get_temperature + (const struct sdis_rwalk_vertex* vtx, struct sdis_data* data) +{ + CHK(data != NULL && vtx != NULL); + return ((const struct fluid*)sdis_data_cget(data))->temperature; +} + +/******************************************************************************* + * Solid medium + ******************************************************************************/ +struct solid { + double cp; + double lambda; + double rho; + double delta; + double temperature; +}; +static const struct solid SOLID_NULL = {0, 0, 0, 0, UNKOWN_TEMPERATURE}; + +static double +solid_get_calorific_capacity + (const struct sdis_rwalk_vertex* vtx, struct sdis_data* data) +{ + CHK(data != NULL && vtx != NULL); + return ((const struct solid*)sdis_data_cget(data))->cp; +} + +static double +solid_get_thermal_conductivity + (const struct sdis_rwalk_vertex* vtx, struct sdis_data* data) +{ + CHK(data != NULL && vtx != NULL); + return ((const struct solid*)sdis_data_cget(data))->lambda; +} + +static double +solid_get_volumic_mass + (const struct sdis_rwalk_vertex* vtx, struct sdis_data* data) +{ + CHK(data != NULL && vtx != NULL); + return ((const struct solid*)sdis_data_cget(data))->rho; +} + +static double +solid_get_delta + (const struct sdis_rwalk_vertex* vtx, struct sdis_data* data) +{ + CHK(data != NULL && vtx != NULL); + return ((const struct solid*)sdis_data_cget(data))->delta; +} + +static double +solid_get_delta_boundary + (const struct sdis_rwalk_vertex* vtx, struct sdis_data* data) +{ + CHK(data != NULL && vtx != NULL); + return ((const struct solid*)sdis_data_cget(data))->delta * 2.1; +} + +static double +solid_get_temperature + (const struct sdis_rwalk_vertex* vtx, struct sdis_data* data) +{ + CHK(data != NULL && vtx != NULL); + return ((const struct solid*)sdis_data_cget(data))->temperature; +} + +/******************************************************************************* + * Interface + ******************************************************************************/ +struct interf { + double hc; + double epsilon; + double specular_fraction; + double temperature; +}; +static const struct interf INTERF_NULL = {0, 0, 0, UNKOWN_TEMPERATURE}; + +static double +interface_get_convection_coef + (const struct sdis_interface_fragment* frag, struct sdis_data* data) +{ + CHK(data != NULL && frag != NULL); + return ((const struct interf*)sdis_data_cget(data))->hc; +} + +static double +interface_get_emissivity + (const struct sdis_interface_fragment* frag, struct sdis_data* data) +{ + CHK(data != NULL && frag != NULL); + return ((const struct interf*)sdis_data_cget(data))->epsilon; +} + +static double +interface_get_specular_fraction + (const struct sdis_interface_fragment* frag, struct sdis_data* data) +{ + CHK(data != NULL && frag != NULL); + return ((const struct interf*)sdis_data_cget(data))->specular_fraction; +} + +static double +interface_get_temperature + (const struct sdis_interface_fragment* frag, struct sdis_data* data) +{ + CHK(data != NULL && frag != NULL); + return ((const struct interf*)sdis_data_cget(data))->temperature; +} + +/******************************************************************************* + * Helper functions + ******************************************************************************/ +static void +create_solid + (struct sdis_device* dev, + const struct solid* param, + struct sdis_medium** solid) +{ + struct sdis_data* data = NULL; + struct solid* solid_param = NULL; + struct sdis_solid_shader solid_shader = DUMMY_SOLID_SHADER; + + CHK(param != NULL); + CHK(solid != NULL); + + /* Copy the solid parameters into the Stardis memory space */ + CHK(sdis_data_create + (dev, sizeof(struct solid), ALIGNOF(struct solid), NULL, &data) == RES_OK); + solid_param = sdis_data_get(data); + memcpy(solid_param, param, sizeof(struct solid)); + + /* Setup the solid shader */ + solid_shader.calorific_capacity = solid_get_calorific_capacity; + solid_shader.calorific_capacity = solid_get_calorific_capacity; + solid_shader.thermal_conductivity = solid_get_thermal_conductivity; + solid_shader.volumic_mass = solid_get_volumic_mass; + solid_shader.delta_solid = solid_get_delta; + solid_shader.delta_boundary = solid_get_delta_boundary; + solid_shader.temperature = solid_get_temperature; + + /* Create the solid medium */ + CHK(sdis_solid_create(dev, &solid_shader, data, solid) == RES_OK); + + /* Release the ownership onto the Stardis memory space storing the solid + * parameters */ + CHK(sdis_data_ref_put(data) == RES_OK); +} + +static void +create_fluid + (struct sdis_device* dev, + const struct fluid* param, + struct sdis_medium** fluid) +{ + struct sdis_data* data = NULL; + struct fluid* fluid_param = NULL; + struct sdis_fluid_shader fluid_shader = DUMMY_FLUID_SHADER; + + CHK(param != NULL); + CHK(fluid != NULL); + + /* Copy the fluid parameters into the Stardis memory space */ + CHK(sdis_data_create + (dev, sizeof(struct fluid), ALIGNOF(struct fluid), NULL, &data) == RES_OK); + fluid_param = sdis_data_get(data); + memcpy(fluid_param, param, sizeof(struct fluid)); + + /* Setup the fluid shader */ + fluid_shader.calorific_capacity = fluid_get_calorific_capacity; + fluid_shader.volumic_mass = fluid_get_volumic_mass; + fluid_shader.temperature = fluid_get_temperature; + + /* Create the fluid medium */ + CHK(sdis_fluid_create(dev, &fluid_shader, data, fluid) == RES_OK); + + /* Release the ownership onto the Stardis memory space storing the fluid + * parameters */ + CHK(sdis_data_ref_put(data) == RES_OK); +} + +static void +create_interface + (struct sdis_device* dev, + struct sdis_medium* mdm_front, + struct sdis_medium* mdm_back, + const struct interf* param, + struct sdis_interface** interf) +{ + struct sdis_data* data = NULL; + struct interf* interface_param = NULL; + struct sdis_interface_shader interface_shader = DUMMY_INTERFACE_SHADER; + + CHK(mdm_front != NULL); + CHK(mdm_back != NULL); + CHK(param != NULL); + CHK(interf != NULL); + + /* Copy the interface parameters into the Stardis memory space */ + CHK(sdis_data_create + (dev, sizeof(struct interf), ALIGNOF(struct interf), NULL, &data) == RES_OK); + interface_param = sdis_data_get(data); + memcpy(interface_param, param, sizeof(struct interf)); + + /* Setup the interface shader */ + interface_shader.convection_coef = interface_get_convection_coef; + interface_shader.temperature = interface_get_temperature; + interface_shader.emissivity = interface_get_emissivity; + interface_shader.specular_fraction = interface_get_specular_fraction; + + /* Create the interface */ + CHK(sdis_interface_create + (dev, mdm_front, mdm_back, &interface_shader, data, interf) == RES_OK); + + /* Release the ownership onto the Stardis memory space storing the interface + * parameters */ + CHK(sdis_data_ref_put(data) == RES_OK); +} + +static void +geometry_add_shape + (struct geometry* geom, + const double* positions, + const size_t nverts, + const size_t* indices, + const size_t nprims, + const double transform[12], /* May be NULL <=> no transformation */ + struct sdis_interface* interf) +{ + struct map_interf* geom_interf = NULL; + size_t nverts_prev = 0; + size_t i; + + CHK(geom != NULL); + CHK(positions != NULL); + CHK(indices != NULL); + CHK(nverts != 0); + CHK(nprims != 0); + CHK(interf != NULL); + + /* Save the previous number of vertices/primitives of the geometry */ + nverts_prev = sa_size(geom->positions) / 3; + + /* Add the vertices */ + FOR_EACH(i, 0, nverts) { + double* pos = sa_add(geom->positions, 3); + d3_set(pos, positions + i*3); + if(transform) { + d33_muld3(pos, transform, pos); + d3_add(pos, transform+9, pos); + } + } + + /* Add the indices */ + FOR_EACH(i, 0, nprims) { + sa_push(geom->indices, indices[i*3+0] + nverts_prev); + sa_push(geom->indices, indices[i*3+1] + nverts_prev); + sa_push(geom->indices, indices[i*3+2] + nverts_prev); + } + + geom_interf = sa_add(geom->interfaces, 1); + geom_interf->key = sa_size(geom->indices) / 3 - 1; + geom_interf->interf = interf; +} + +static void +dump_image(const struct sdis_accum_buffer* buf) +{ + struct sdis_accum_buffer_layout layout = SDIS_ACCUM_BUFFER_LAYOUT_NULL; + struct image img; + double* temps = NULL; + const struct sdis_accum* accums = NULL; + double Tmax = -DBL_MAX; + double Tmin = DBL_MAX; + double norm; + size_t ix, iy; + + CHK(buf != NULL); + CHK(sdis_accum_buffer_get_layout(buf, &layout) == RES_OK); + + temps = mem_alloc(layout.width*layout.height*sizeof(double)); + CHK(temps != NULL); + + /* Compute the per pixel temperature */ + CHK(sdis_accum_buffer_map(buf, &accums) == RES_OK); + FOR_EACH(iy, 0, layout.height) { + const struct sdis_accum* row_accums = accums + iy * layout.width; + double* row = temps + iy * layout.width; + FOR_EACH(ix, 0, layout.width) { + row[ix] = row_accums[ix].sum_weights / (double)row_accums[ix].nweights; + Tmax = MMAX(row[ix], Tmax); + Tmin = MMIN(row[ix], Tmin); + } + } + if(Tmax != Tmin) { + norm = Tmax - Tmin; + } else { + Tmin = 0; + norm = 1; + } + + /* Allocate the image memory space */ + CHK(image_init(NULL, &img) == RES_OK); + CHK(image_setup(&img, IMG_WIDTH, IMG_HEIGHT, IMG_WIDTH*3, IMAGE_RGB8, NULL) + == RES_OK); + + FOR_EACH(iy, 0, layout.height) { + const double* src_row = temps + iy*layout.width; + char* dst_row = img.pixels + iy*img.pitch; + FOR_EACH(ix, 0, layout.width) { + unsigned char* pixels = (unsigned char*) + (dst_row + ix * sizeof_image_format(img.format)); + const unsigned char T = (unsigned char) + ((src_row[ix] - Tmin)/ norm * 255.0); + pixels[0] = T; + pixels[1] = T; + pixels[2] = T; + } + } + CHK(image_write_ppm_stream(&img, 0/*binary?*/, stdout) == RES_OK); + image_release(&img); + mem_rm(temps); +} + +/******************************************************************************* + * Test + ******************************************************************************/ +int +main(int argc, char** argv) +{ + struct mem_allocator allocator; + struct geometry geom = GEOMETRY_NULL; + struct s3dut_mesh* msh = NULL; + struct s3dut_mesh_data msh_data; + struct sdis_accum_buffer* buf = NULL; + struct sdis_camera* cam = NULL; + struct sdis_device* dev = NULL; + struct sdis_medium* solid = NULL; + struct sdis_medium* fluid0 = NULL; + struct sdis_medium* fluid1 = NULL; + struct sdis_interface* interf0 = NULL; + struct sdis_interface* interf1 = NULL; + struct sdis_scene* scn = NULL; + struct fluid fluid_param = FLUID_NULL; + struct solid solid_param = SOLID_NULL; + struct interf interface_param = INTERF_NULL; + size_t ntris, npos; + double pos[3]; + double tgt[3]; + double up[3]; + (void)argc, (void)argv; + + CHK(mem_init_proxy_allocator(&allocator, &mem_default_allocator) == RES_OK); + CHK(sdis_device_create + (NULL, &allocator, SDIS_NTHREADS_DEFAULT, 1, &dev) == RES_OK); + + /* Create the fluid0 */ + fluid_param.temperature = 350; + fluid_param.rho = 0; + fluid_param.cp = 0; + create_fluid(dev, &fluid_param, &fluid0); + + /* Create the fluid1 */ + fluid_param.temperature = UNKOWN_TEMPERATURE; + fluid_param.rho = 0; + fluid_param.cp = 0; + create_fluid(dev, &fluid_param, &fluid1); + + /* Create the solid medium */ + solid_param.cp = 1.0; + solid_param.lambda = 0.1; + solid_param.rho = 1.0; + solid_param.delta = 1.0/20.0; + solid_param.temperature = UNKOWN_TEMPERATURE; + create_solid(dev, &solid_param, &solid); + + /* Create the fluid0/solid interface */ + interface_param.hc = 1; + interface_param.epsilon = 0; + interface_param.specular_fraction = 0; + interface_param.temperature = UNKOWN_TEMPERATURE; + create_interface(dev, solid, fluid0, &interface_param, &interf0); + + /* Create the fluid1/solid interface */ + interface_param.hc = 0; + interface_param.epsilon = 1; + interface_param.specular_fraction = 1; + interface_param.temperature = UNKOWN_TEMPERATURE; + create_interface(dev, fluid1, solid, &interface_param, &interf1); + + /* Release the ownership onto the media */ + CHK(sdis_medium_ref_put(solid) == RES_OK); + CHK(sdis_medium_ref_put(fluid0) == RES_OK); + CHK(sdis_medium_ref_put(fluid1) == RES_OK); + + /* Setup the cube geometry */ + CHK(s3dut_create_cuboid(&allocator, 2, 2, 2, &msh) == RES_OK); + CHK(s3dut_mesh_get_data(msh, &msh_data) == RES_OK); + geometry_add_shape(&geom, msh_data.positions, msh_data.nvertices, + msh_data.indices, msh_data.nprimitives, NULL, interf1); + CHK(s3dut_mesh_ref_put(msh) == RES_OK); + + /* Setup the sphere geometry */ + CHK(s3dut_create_sphere(&allocator, 0.5, 32, 16, &msh) == RES_OK); + CHK(s3dut_mesh_get_data(msh, &msh_data) == RES_OK); + geometry_add_shape(&geom, msh_data.positions, msh_data.nvertices, + msh_data.indices, msh_data.nprimitives, NULL, interf0); + CHK(s3dut_mesh_ref_put(msh) == RES_OK); + + /* Setup the scene */ + ntris = sa_size(geom.indices) / 3; /* #primitives */ + npos = sa_size(geom.positions) / 3; /* #positions */ + CHK(sdis_scene_create(dev, ntris, geometry_get_indices, + geometry_get_interface, npos, geometry_get_position, + &geom, &scn) == RES_OK); + + /* Setup the camera */ + d3(pos, 3, 3, 3); + d3(tgt, 0, 0, 0); + d3(up, 0, 0, 1); + CHK(sdis_camera_create(dev, &cam) == RES_OK); + CHK(sdis_camera_set_proj_ratio + (cam, (double)IMG_WIDTH/(double)IMG_HEIGHT) == RES_OK); + CHK(sdis_camera_set_fov(cam, MDEG2RAD(70)) == RES_OK); + CHK(sdis_camera_look_at(cam, pos, tgt, up) == RES_OK); + + /* Create the accum buffer */ + CHK(sdis_accum_buffer_create(dev, IMG_WIDTH, IMG_HEIGHT, &buf) == RES_OK); + + /* Launch the simulation */ + CHK(sdis_solve_camera(scn, cam, INF, 1, 300, 300, IMG_WIDTH, IMG_HEIGHT, SPP, + sdis_accum_buffer_write, buf) == RES_OK); + + /* Write the image */ + dump_image(buf); + + /* Release memory */ + CHK(sdis_scene_ref_put(scn) == RES_OK); + CHK(sdis_camera_ref_put(cam) == RES_OK); + CHK(sdis_interface_ref_put(interf0) == RES_OK); + CHK(sdis_interface_ref_put(interf1) == RES_OK); + CHK(sdis_device_ref_put(dev) == RES_OK); + CHK(sdis_accum_buffer_ref_put(buf) == RES_OK); + 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_probe.c b/src/test_sdis_solve_probe.c @@ -146,6 +146,8 @@ solid_get_temperature ******************************************************************************/ struct interf { double hc; + double epsilon; + double specular_fraction; }; static double @@ -156,6 +158,22 @@ interface_get_convection_coef return ((const struct interf*)sdis_data_cget(data))->hc; } +static double +interface_get_emissivity + (const struct sdis_interface_fragment* frag, struct sdis_data* data) +{ + CHK(data != NULL && frag != NULL); + return ((const struct interf*)sdis_data_cget(data))->epsilon; +} + +static double +interface_get_specular_fraction + (const struct sdis_interface_fragment* frag, struct sdis_data* data) +{ + CHK(data != NULL && frag != NULL); + return ((const struct interf*)sdis_data_cget(data))->specular_fraction; +} + /******************************************************************************* * Test ******************************************************************************/ @@ -222,8 +240,12 @@ main(int argc, char** argv) ALIGNOF(struct interf), NULL, &data) == RES_OK); interface_param = sdis_data_get(data); interface_param->hc = 0.5; + interface_param->epsilon = 0; + interface_param->specular_fraction = 0; interface_shader.convection_coef = interface_get_convection_coef; interface_shader.temperature = NULL; + interface_shader.emissivity = interface_get_emissivity; + interface_shader.specular_fraction = interface_get_specular_fraction; CHK(sdis_interface_create (dev, solid, fluid, &interface_shader, data, &interf) == RES_OK); CHK(sdis_data_ref_put(data) == RES_OK); @@ -246,12 +268,13 @@ main(int argc, char** argv) pos[1] = 0.5; pos[2] = 0.5; time = INF; - CHK(sdis_solve_probe(NULL, N, pos, time, 1.0, &estimator) == RES_BAD_ARG); - CHK(sdis_solve_probe(scn, 0, pos, time, 1.0, &estimator) == RES_BAD_ARG); - CHK(sdis_solve_probe(scn, N, NULL, time, 1.0, &estimator) == RES_BAD_ARG); - CHK(sdis_solve_probe(scn, N, pos, time, 0, &estimator) == RES_BAD_ARG); - CHK(sdis_solve_probe(scn, N, pos, time, 1.0, NULL) == RES_BAD_ARG); - CHK(sdis_solve_probe(scn, N, pos, time, 1.0, &estimator) == RES_OK); + CHK(sdis_solve_probe(NULL, N, pos, time, 1.0, 0, 0, &estimator) == RES_BAD_ARG); + CHK(sdis_solve_probe(scn, 0, pos, time, 1.0, 0, 0, &estimator) == RES_BAD_ARG); + CHK(sdis_solve_probe(scn, N, NULL, time, 1.0, 0, 0, &estimator) == RES_BAD_ARG); + CHK(sdis_solve_probe(scn, N, pos, time, 0, 0, 0, &estimator) == RES_BAD_ARG); + CHK(sdis_solve_probe(scn, N, pos, time, 0, 0, -1, &estimator) == RES_BAD_ARG); + CHK(sdis_solve_probe(scn, N, pos, time, 1.0, 0, 0, NULL) == RES_BAD_ARG); + CHK(sdis_solve_probe(scn, N, pos, time, 1.0, 0, 0, &estimator) == RES_OK); CHK(sdis_estimator_get_realisation_count(estimator, NULL) == RES_BAD_ARG); CHK(sdis_estimator_get_realisation_count(NULL, &nreals) == RES_BAD_ARG); diff --git a/src/test_sdis_solve_probe2.c b/src/test_sdis_solve_probe2.c @@ -131,7 +131,7 @@ struct interf { }; static double -null_convection_coef +null_interface_value (const struct sdis_interface_fragment* frag, struct sdis_data* data) { CHK(frag != NULL); @@ -196,8 +196,10 @@ main(int argc, char** argv) CHK(sdis_solid_create(dev, &solid_shader, NULL, &solid) == RES_OK); /* Create the fluid/solid interface with no limit conidition */ - interface_shader.convection_coef = null_convection_coef; + interface_shader.convection_coef = null_interface_value; interface_shader.temperature = NULL; + interface_shader.emissivity = null_interface_value; + interface_shader.specular_fraction = null_interface_value; CHK(sdis_interface_create (dev, solid, fluid, &interface_shader, NULL, &Tnone) == RES_OK); @@ -206,8 +208,10 @@ main(int argc, char** argv) ALIGNOF(struct interf), NULL, &data) == RES_OK); interface_param = sdis_data_get(data); interface_param->temperature = 300; - interface_shader.convection_coef = null_convection_coef; + interface_shader.convection_coef = null_interface_value; interface_shader.temperature = interface_get_temperature; + interface_shader.emissivity = null_interface_value; + interface_shader.specular_fraction = null_interface_value; CHK(sdis_interface_create (dev, solid, fluid, &interface_shader, data, &T300) == RES_OK); CHK(sdis_data_ref_put(data) == RES_OK); @@ -217,8 +221,10 @@ main(int argc, char** argv) ALIGNOF(struct interf), NULL, &data) == RES_OK); interface_param = sdis_data_get(data); interface_param->temperature = 350; - interface_shader.convection_coef = null_convection_coef; + interface_shader.convection_coef = null_interface_value; interface_shader.temperature = interface_get_temperature; + interface_shader.emissivity = null_interface_value; + interface_shader.specular_fraction = null_interface_value; CHK(sdis_interface_create (dev, solid, fluid, &interface_shader, data, &T350) == RES_OK); CHK(sdis_data_ref_put(data) == RES_OK); @@ -253,7 +259,7 @@ main(int argc, char** argv) pos[1] = 0.5; pos[2] = 0.5; time = INF; - CHK(sdis_solve_probe( scn, N, pos, time, 1.0, &estimator) == RES_OK); + CHK(sdis_solve_probe( scn, N, pos, time, 1.0, -1, 0, &estimator) == RES_OK); CHK(sdis_estimator_get_realisation_count(estimator, &nreals) == RES_OK); CHK(sdis_estimator_get_failure_count(estimator, &nfails) == RES_OK); CHK(sdis_estimator_get_temperature(estimator, &T) == RES_OK); diff --git a/src/test_sdis_solve_probe2_2d.c b/src/test_sdis_solve_probe2_2d.c @@ -128,7 +128,7 @@ struct interf { }; static double -null_convection_coef +null_interface_value (const struct sdis_interface_fragment* frag, struct sdis_data* data) { CHK(frag != NULL); @@ -193,8 +193,10 @@ main(int argc, char** argv) CHK(sdis_solid_create(dev, &solid_shader, NULL, &solid) == RES_OK); /* Create the fluid/solid interface with no limit conidition */ - interface_shader.convection_coef = null_convection_coef; + interface_shader.convection_coef = null_interface_value; interface_shader.temperature = NULL; + interface_shader.emissivity = null_interface_value; + interface_shader.specular_fraction = null_interface_value; CHK(sdis_interface_create (dev, solid, fluid, &interface_shader, NULL, &Tnone) == RES_OK); @@ -203,8 +205,10 @@ main(int argc, char** argv) ALIGNOF(struct interf), NULL, &data) == RES_OK); interface_param = sdis_data_get(data); interface_param->temperature = 300; - interface_shader.convection_coef = null_convection_coef; + interface_shader.convection_coef = null_interface_value; interface_shader.temperature = interface_get_temperature; + interface_shader.emissivity = null_interface_value; + interface_shader.specular_fraction = null_interface_value; CHK(sdis_interface_create (dev, solid, fluid, &interface_shader, data, &T300) == RES_OK); CHK(sdis_data_ref_put(data) == RES_OK); @@ -214,8 +218,10 @@ main(int argc, char** argv) ALIGNOF(struct interf), NULL, &data) == RES_OK); interface_param = sdis_data_get(data); interface_param->temperature = 350; - interface_shader.convection_coef = null_convection_coef; + interface_shader.convection_coef = null_interface_value; interface_shader.temperature = interface_get_temperature; + interface_shader.emissivity = null_interface_value; + interface_shader.specular_fraction = null_interface_value; CHK(sdis_interface_create (dev, solid, fluid, &interface_shader, data, &T350) == RES_OK); CHK(sdis_data_ref_put(data) == RES_OK); @@ -247,7 +253,7 @@ main(int argc, char** argv) pos[0] = 0.5; pos[1] = 0.5; time = INF; - CHK(sdis_solve_probe( scn, N, pos, time, 1.0, &estimator) == RES_OK); + CHK(sdis_solve_probe( scn, N, pos, time, 1.0, -1, 0, &estimator) == RES_OK); CHK(sdis_estimator_get_realisation_count(estimator, &nreals) == RES_OK); CHK(sdis_estimator_get_failure_count(estimator, &nfails) == RES_OK); CHK(sdis_estimator_get_temperature(estimator, &T) == RES_OK); diff --git a/src/test_sdis_solve_probe3.c b/src/test_sdis_solve_probe3.c @@ -52,7 +52,7 @@ struct context { struct sdis_interface* solid_fluid_T350; struct sdis_interface* solid_solid; }; -static const struct context CONTEXT_NULL = { NULL }; +static const struct context CONTEXT_NULL = {NULL, NULL, NULL, NULL, NULL, NULL}; static void get_indices(const size_t itri, size_t ids[3], void* context) @@ -153,7 +153,7 @@ struct interf { }; static double -null_convection_coef +null_interface_value (const struct sdis_interface_fragment* frag, struct sdis_data* data) { CHK(frag != NULL); @@ -223,8 +223,10 @@ main(int argc, char** argv) CHK(sdis_solid_create(dev, &solid_shader, NULL, &solid) == RES_OK); /* Create the fluid/solid interface with no limit conidition */ - interface_shader.convection_coef = null_convection_coef; + interface_shader.convection_coef = null_interface_value; interface_shader.temperature = NULL; + interface_shader.emissivity = null_interface_value; + interface_shader.specular_fraction = null_interface_value; CHK(sdis_interface_create (dev, solid, fluid, &interface_shader, NULL, &Tnone) == RES_OK); @@ -233,8 +235,10 @@ main(int argc, char** argv) ALIGNOF(struct interf), NULL, &data) == RES_OK); interface_param = sdis_data_get(data); interface_param->temperature = 300; - interface_shader.convection_coef = null_convection_coef; + interface_shader.convection_coef = null_interface_value; interface_shader.temperature = interface_get_temperature; + interface_shader.emissivity = null_interface_value; + interface_shader.specular_fraction = null_interface_value; CHK(sdis_interface_create (dev, solid, fluid, &interface_shader, data, &T300) == RES_OK); CHK(sdis_data_ref_put(data) == RES_OK); @@ -244,8 +248,10 @@ main(int argc, char** argv) ALIGNOF(struct interf), NULL, &data) == RES_OK); interface_param = sdis_data_get(data); interface_param->temperature = 350; - interface_shader.convection_coef = null_convection_coef; + interface_shader.convection_coef = null_interface_value; interface_shader.temperature = interface_get_temperature; + interface_shader.emissivity = null_interface_value; + interface_shader.specular_fraction = null_interface_value; CHK(sdis_interface_create (dev, solid, fluid, &interface_shader, data, &T350) == RES_OK); CHK(sdis_data_ref_put(data) == RES_OK); @@ -253,6 +259,8 @@ main(int argc, char** argv) /* Create the solid/solid interface */ interface_shader.convection_coef = NULL; interface_shader.temperature = NULL; + interface_shader.specular_fraction = NULL; + interface_shader.emissivity = NULL; CHK(sdis_interface_create (dev, solid, solid, &interface_shader, NULL, &solid_solid) == RES_OK); @@ -310,7 +318,7 @@ main(int argc, char** argv) pos[1] = 0.5; pos[2] = 0.5; time = INF; - CHK(sdis_solve_probe( scn, N, pos, time, 1.0, &estimator) == RES_OK); + CHK(sdis_solve_probe( scn, N, pos, time, 1.0, -1, 0, &estimator) == RES_OK); CHK(sdis_estimator_get_realisation_count(estimator, &nreals) == RES_OK); CHK(sdis_estimator_get_failure_count(estimator, &nfails) == RES_OK); CHK(sdis_estimator_get_temperature(estimator, &T) == RES_OK); diff --git a/src/test_sdis_solve_probe3_2d.c b/src/test_sdis_solve_probe3_2d.c @@ -150,7 +150,7 @@ struct interf { }; static double -null_convection_coef +null_interface_value (const struct sdis_interface_fragment* frag, struct sdis_data* data) { CHK(frag != NULL); @@ -218,8 +218,10 @@ main(int argc, char** argv) CHK(sdis_solid_create(dev, &solid_shader, NULL, &solid) == RES_OK); /* Create the fluid/solid interface with no limit conidition */ - interface_shader.convection_coef = null_convection_coef; + interface_shader.convection_coef = null_interface_value; interface_shader.temperature = NULL; + interface_shader.emissivity = null_interface_value; + interface_shader.specular_fraction = null_interface_value; CHK(sdis_interface_create (dev, solid, fluid, &interface_shader, NULL, &Tnone) == RES_OK); @@ -228,8 +230,10 @@ main(int argc, char** argv) ALIGNOF(struct interf), NULL, &data) == RES_OK); interface_param = sdis_data_get(data); interface_param->temperature = 300; - interface_shader.convection_coef = null_convection_coef; + interface_shader.convection_coef = null_interface_value; interface_shader.temperature = interface_get_temperature; + interface_shader.emissivity = null_interface_value; + interface_shader.specular_fraction = null_interface_value; CHK(sdis_interface_create (dev, solid, fluid, &interface_shader, data, &T300) == RES_OK); CHK(sdis_data_ref_put(data) == RES_OK); @@ -239,8 +243,10 @@ main(int argc, char** argv) ALIGNOF(struct interf), NULL, &data) == RES_OK); interface_param = sdis_data_get(data); interface_param->temperature = 350; - interface_shader.convection_coef = null_convection_coef; + interface_shader.convection_coef = null_interface_value; interface_shader.temperature = interface_get_temperature; + interface_shader.emissivity = null_interface_value; + interface_shader.specular_fraction = null_interface_value; CHK(sdis_interface_create (dev, solid, fluid, &interface_shader, data, &T350) == RES_OK); CHK(sdis_data_ref_put(data) == RES_OK); @@ -248,6 +254,8 @@ main(int argc, char** argv) /* Create the solid/solid interface */ interface_shader.convection_coef = NULL; interface_shader.temperature = NULL; + interface_shader.specular_fraction = NULL; + interface_shader.emissivity = NULL; CHK(sdis_interface_create (dev, solid, solid, &interface_shader, NULL, &solid_solid) == RES_OK); @@ -300,7 +308,7 @@ main(int argc, char** argv) pos[0] = 0.5; pos[1] = 0.5; time = INF; - CHK(sdis_solve_probe( scn, N, pos, time, 1.0, &estimator) == RES_OK); + CHK(sdis_solve_probe( scn, N, pos, time, 1.0, -1, 0, &estimator) == RES_OK); CHK(sdis_estimator_get_realisation_count(estimator, &nreals) == RES_OK); CHK(sdis_estimator_get_failure_count(estimator, &nfails) == RES_OK); CHK(sdis_estimator_get_temperature(estimator, &T) == RES_OK); @@ -325,5 +333,4 @@ main(int argc, char** argv) 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 @@ -131,6 +131,14 @@ interface_get_convection_coef return 0.5; } +static double +interface_null_reflectivity + (const struct sdis_interface_fragment* frag, struct sdis_data* data) +{ + (void)frag, (void)data; + return 0; +} + /******************************************************************************* * Main test ******************************************************************************/ @@ -177,6 +185,8 @@ main(int argc, char** argv) /* Create the solid/fluid interface */ interface_shader.convection_coef = interface_get_convection_coef; interface_shader.temperature = NULL; + interface_shader.emissivity = interface_null_reflectivity; + interface_shader.specular_fraction = interface_null_reflectivity; CHK(sdis_interface_create (dev, solid, fluid, &interface_shader, NULL, &interf) == RES_OK); @@ -197,7 +207,7 @@ main(int argc, char** argv) pos[0] = 0.5; pos[1] = 0.5; time = INF; - CHK(sdis_solve_probe(scn, N, pos, time, 1.0, &estimator) == RES_OK); + CHK(sdis_solve_probe(scn, N, pos, time, 1.0, 0, 0, &estimator) == RES_OK); CHK(sdis_estimator_get_realisation_count(estimator, &nreals) == RES_OK); CHK(sdis_estimator_get_failure_count(estimator, &nfails) == RES_OK); diff --git a/src/test_sdis_utils.h b/src/test_sdis_utils.h @@ -16,9 +16,13 @@ #ifndef TEST_SDIS_UTILS_H #define TEST_SDIS_UTILS_H +#include "sdis.h" + #include <rsys/mem_allocator.h> #include <stdio.h> +#define BOLTZMANN_CONSTANT 5.6696e-8 /* W/m^2/K^4 */ + /******************************************************************************* * Box geometry ******************************************************************************/ @@ -82,7 +86,7 @@ dummy_medium_getter { (void)data; CHK(vert != NULL); - return 1; + return 0; } static INLINE double @@ -91,7 +95,7 @@ dummy_interface_getter { (void)data; CHK(frag != NULL); - return 1; + return 0; } static const struct sdis_solid_shader DUMMY_SOLID_SHADER = { @@ -111,6 +115,8 @@ static const struct sdis_fluid_shader DUMMY_FLUID_SHADER = { static const struct sdis_interface_shader DUMMY_INTERFACE_SHADER = { dummy_interface_getter, + dummy_interface_getter, + dummy_interface_getter, dummy_interface_getter };