solstice-solver

Solver library of the solstice app
git clone git://git.meso-star.com/solstice-solver.git
Log | Files | Refs | README | LICENSE

commit 43e47fdf51a03eb559a82c921c67886502795f0c
parent 214403f413875775f5b346d568ba96a34b3ea9fd
Author: Christophe Coustet <christophe.coustet@meso-star.com>
Date:   Fri,  8 Dec 2017 16:00:25 +0100

Add gaussian shunshape ans associated test.

Diffstat:
Mcmake/CMakeLists.txt | 1+
Msrc/ssol.h | 11+++++++++++
Msrc/ssol_ranst_sun_dir.c | 43+++++++++++++++++++++++++++++++++++++++++++
Msrc/ssol_ranst_sun_dir.h | 6++++++
Msrc/ssol_sun.c | 19+++++++++++++++++++
Msrc/ssol_sun_c.h | 6++++++
Asrc/test_ssol_solver12.c | 202+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Msrc/test_ssol_sun.c | 67+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
8 files changed, 355 insertions(+), 0 deletions(-)

diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt @@ -183,6 +183,7 @@ if(NOT NO_TEST) new_test(test_ssol_solver9) new_test(test_ssol_solver10) new_test(test_ssol_solver11) + new_test(test_ssol_solver12) new_test(test_ssol_sun) build_test(test_ssol_draw) diff --git a/src/ssol.h b/src/ssol.h @@ -996,6 +996,12 @@ ssol_sun_create_pillbox (struct ssol_device* dev, struct ssol_sun** sun); +/* The sun disk intensity has a gaussian shape */ +SSOL_API res_T +ssol_sun_create_gaussian + (struct ssol_device* dev, + struct ssol_sun** sun); + /* The sun disk intensity is controlled by a circumsolar ratio. From the paper * "Sunshape distributions for terrestrial solar simulations". D. Buie, A.G. * Monger, C.J. Dey */ @@ -1045,6 +1051,11 @@ ssol_sun_pillbox_set_half_angle const double half_angle); /* In ]0, PI/2], in radian */ SSOL_API res_T +ssol_sun_gaussian_set_std_dev + (struct ssol_sun* sun, + const double std_dev); /* In ]0, +Inf[, in radian */ + +SSOL_API res_T ssol_sun_set_buie_param (struct ssol_sun* sun, const double param); /* In ]0, 1[ */ diff --git a/src/ssol_ranst_sun_dir.c b/src/ssol_ranst_sun_dir.c @@ -44,6 +44,11 @@ struct ran_pillbox_state { double basis[9]; }; +struct ran_gaussian_state { + double std_dev; + double basis[9]; +}; + struct ran_dirac_state { double dir[3]; }; @@ -56,6 +61,7 @@ struct ranst_sun_dir { union { struct ran_buie_state buie; struct ran_pillbox_state pillbox; + struct ran_gaussian_state gaussian; struct ran_dirac_state dirac; } state; @@ -260,6 +266,30 @@ ran_pillbox_get } /******************************************************************************* +* Gaussian random variate +******************************************************************************/ +static double* +ran_gaussian_get + (const struct ranst_sun_dir* ran, + struct ssp_rng* rng, + double dir[3]) +{ + double pt[3]; + double phi, theta, sin_theta; + + ASSERT(ran && 0 <= ran->state.gaussian.std_dev); + theta = ssp_ran_gaussian(rng, 0, ran->state.gaussian.std_dev); + sin_theta = sin(theta); + phi = ssp_rng_uniform_double(rng, 0, 2 * PI); + pt[0] = cos(phi) * sin_theta; + pt[1] = sin(phi) * sin_theta; + pt[2] = cos(theta); + d33_muld3(dir, ran->state.pillbox.basis, pt); + d3_normalize(dir, dir); + return dir; +} + +/******************************************************************************* * Dirac distribution ******************************************************************************/ static double* @@ -358,6 +388,19 @@ ranst_sun_dir_pillbox_setup } res_T +ranst_sun_dir_gaussian_setup + (struct ranst_sun_dir* ran, + const double std_dev, + const double dir[3]) +{ + if(!ran || !dir || std_dev <= 0) return RES_BAD_ARG; + ran->get = ran_gaussian_get; + ran->state.gaussian.std_dev = std_dev; + d33_basis(ran->state.pillbox.basis, dir); + return RES_OK; +} + +res_T ranst_sun_dir_dirac_setup (struct ranst_sun_dir* ran, const double dir[3]) diff --git a/src/ssol_ranst_sun_dir.h b/src/ssol_ranst_sun_dir.h @@ -55,6 +55,12 @@ ranst_sun_dir_pillbox_setup const double dir[3]); extern LOCAL_SYM res_T +ranst_sun_dir_gaussian_setup + (struct ranst_sun_dir* ran, + const double std_dev, + const double dir[3]); + +extern LOCAL_SYM res_T ranst_sun_dir_dirac_setup (struct ranst_sun_dir* ran, const double dir[3]); diff --git a/src/ssol_sun.c b/src/ssol_sun.c @@ -93,6 +93,12 @@ ssol_sun_create_pillbox(struct ssol_device* dev, struct ssol_sun** out_sun) } res_T +ssol_sun_create_gaussian(struct ssol_device* dev, struct ssol_sun** out_sun) +{ + return sun_create(dev, out_sun, SUN_GAUSSIAN); +} + +res_T ssol_sun_create_buie (struct ssol_device* dev, struct ssol_sun** out_sun) { @@ -179,6 +185,15 @@ ssol_sun_pillbox_set_half_angle(struct ssol_sun* sun, const double half_angle) } res_T +ssol_sun_gaussian_set_std_dev(struct ssol_sun* sun, const double std_dev) +{ + if(!sun || std_dev <= 0 || sun->type != SUN_GAUSSIAN) + return RES_BAD_ARG; + sun->data.gaussian.std_dev = std_dev; + return RES_OK; +} + +res_T ssol_sun_set_buie_param (struct ssol_sun* sun, const double ratio) @@ -213,6 +228,10 @@ sun_create_direction_distribution res = ranst_sun_dir_pillbox_setup (ran_dir, sun->data.pillbox.half_angle, sun->direction); break; + case SUN_GAUSSIAN: + res = ranst_sun_dir_gaussian_setup + (ran_dir, sun->data.gaussian.std_dev, sun->direction); + break; case SUN_BUIE: res = ranst_sun_dir_buie_setup (ran_dir, sun->data.csr.ratio, sun->direction); diff --git a/src/ssol_sun_c.h b/src/ssol_sun_c.h @@ -26,6 +26,7 @@ struct ranst_sun_wl; enum sun_type { SUN_DIRECTIONAL, SUN_PILLBOX, + SUN_GAUSSIAN, SUN_BUIE, SUN_TYPES_COUNT__ }; @@ -34,6 +35,10 @@ struct pillbox { double half_angle; }; +struct gaussian { + double std_dev; +}; + struct buie { double ratio; }; @@ -46,6 +51,7 @@ struct ssol_sun { enum sun_type type; union { struct pillbox pillbox; + struct gaussian gaussian; struct buie csr; } data; diff --git a/src/test_ssol_solver12.c b/src/test_ssol_solver12.c @@ -0,0 +1,202 @@ +/* Copyright (C) CNRS 2016-2017 + * + * 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 "ssol.h" +#include "test_ssol_utils.h" +#define REFLECTIVITY 0 +#include "test_ssol_materials.h" + +#include <rsys/math.h> + +#define X_SZ 10 +#define Y_SZ 10 +#define PLANE_NAME SQUARE +#define HALF_X (X_SZ / 2) +#define HALF_Y (Y_SZ / 2) +STATIC_ASSERT((HALF_X * 2 == X_SZ), ONLY_ENVEN_VALUES_FOR_SQUARE_X); +STATIC_ASSERT((HALF_Y * 2 == Y_SZ), ONLY_ENVEN_VALUES_FOR_SQUARE_Y); +#include "test_ssol_rect_geometry.h" + +#define POLYGON_NAME POLY +#define HALF_X (X_SZ / 2) +#define HALF_Y (Y_SZ / 2) +STATIC_ASSERT((HALF_X * 2 == X_SZ), ONLY_ENVEN_VALUES_FOR_X_SZ); +STATIC_ASSERT((HALF_Y * 2 == Y_SZ), ONLY_ENVEN_VALUES_FOR_Y_SZ); +#include "test_ssol_rect2D_geometry.h" + +#include <rsys/double33.h> + +#include <star/s3d.h> +#include <star/ssp.h> + +static void +get_wlen(const size_t i, double* wlen, double* data, void* ctx) +{ + double wavelengths[3] = { 1, 2, 3 }; + double intensities[3] = { 1, 0.8, 1 }; + CHECK(i < 3, 1); + (void) ctx; + *wlen = wavelengths[i]; + *data = intensities[i]; +} + +int +main(int argc, char** argv) +{ + struct mem_allocator allocator; + struct ssol_device* dev; + struct ssp_rng* rng; + struct ssol_scene* scene; + struct ssol_shape* square; + struct ssol_shape* parabol; + struct ssol_vertex_data attribs[1] = { SSOL_VERTEX_DATA_NULL__ }; + struct ssol_material* m_mtl; + struct ssol_matte_shader shader = SSOL_MATTE_SHADER_NULL; + struct ssol_object* m_object; + struct ssol_object* q_object; + struct ssol_carving carving = SSOL_CARVING_NULL; + struct ssol_quadric quadric = SSOL_QUADRIC_DEFAULT; + struct ssol_punched_surface punched = SSOL_PUNCHED_SURFACE_NULL; + struct ssol_instance* geom1; + struct ssol_instance* geom2; + struct ssol_sun* sun; + struct ssol_spectrum* spectrum; + struct ssol_estimator* estimator; + struct ssol_mc_global mc_global1; + struct ssol_mc_global mc_global2; + struct ssol_mc_receiver mc_rcv1; + struct ssol_mc_receiver mc_rcv2; + double dir[3]; + double transform[12]; /* 3x4 column major matrix */ + size_t count; + + (void) argc, (void) argv; + mem_init_proxy_allocator(&allocator, &mem_default_allocator); + + d33_set_identity(transform); + + CHECK(ssol_device_create + (NULL, &allocator, SSOL_NTHREADS_DEFAULT, 0, &dev), RES_OK); + +#define DNI 1000 + CHECK(ssp_rng_create(&allocator, &ssp_rng_threefry, &rng), RES_OK); + CHECK(ssol_spectrum_create(dev, &spectrum), RES_OK); + CHECK(ssol_spectrum_setup(spectrum, get_wlen, 3, NULL), RES_OK); + CHECK(ssol_sun_create_gaussian(dev, &sun), RES_OK); + CHECK(ssol_sun_gaussian_set_std_dev(sun, 0.01), RES_OK); + CHECK(ssol_sun_set_direction(sun, d3(dir, 0, 0, -1)), RES_OK); + CHECK(ssol_sun_set_spectrum(sun, spectrum), RES_OK); + CHECK(ssol_sun_set_dni(sun, DNI), RES_OK); + CHECK(ssol_scene_create(dev, &scene), RES_OK); + CHECK(ssol_scene_attach_sun(scene, sun), RES_OK); + + /* Create scene content */ + + CHECK(ssol_shape_create_mesh(dev, &square), RES_OK); + attribs[0].usage = SSOL_POSITION; + attribs[0].get = get_position; + CHECK(ssol_mesh_setup(square, SQUARE_NTRIS__, get_ids, + SQUARE_NVERTS__, attribs, 1, (void*) &SQUARE_DESC__), RES_OK); + + CHECK(ssol_material_create_matte(dev, &m_mtl), RES_OK); + shader.normal = get_shader_normal; + shader.reflectivity = get_shader_reflectivity_2; + CHECK(ssol_matte_setup(m_mtl, &shader), RES_OK); + + CHECK(ssol_object_create(dev, &m_object), RES_OK); + CHECK(ssol_object_add_shaded_shape(m_object, square, m_mtl, m_mtl), RES_OK); + CHECK(ssol_object_instantiate(m_object, &geom1), RES_OK); + CHECK(ssol_instance_set_receiver(geom1, SSOL_FRONT, 0), RES_OK); + d3_splat(transform + 9, 0); + transform[9] = -10; + CHECK(ssol_instance_set_transform(geom1, transform), RES_OK); + CHECK(ssol_scene_attach_instance(scene, geom1), RES_OK); + +#define N1__ 10000 +#define GET_MC_RCV ssol_estimator_get_mc_receiver + CHECK(ssol_solve(scene, rng, N1__, 0, NULL, &estimator), RES_OK); + CHECK(ssol_estimator_get_realisation_count(estimator, &count), RES_OK); + CHECK(count, N1__); + CHECK(ssol_estimator_get_failed_count(estimator, &count), RES_OK); + CHECK(count, 0); +#define DNI_S (DNI * X_SZ * Y_SZ) + CHECK(ssol_estimator_get_mc_global(estimator, &mc_global1), RES_OK); + CHECK(GET_MC_RCV(estimator, geom1, SSOL_FRONT, &mc_rcv1), RES_OK); + + PRINT_GLOBAL(mc_global1); + PRINT_RCV(mc_rcv1); + CHECK(mc_global1.cos_factor.E, 1); + CHECK(mc_global1.cos_factor.SE, 0); + CHECK(mc_global1.absorbed_by_receivers.E, DNI_S); + CHECK(mc_global1.absorbed_by_receivers.SE, 0); + + CHECK(ssol_shape_create_punched_surface(dev, &parabol), RES_OK); + carving.get = get_polygon_vertices; + carving.operation = SSOL_AND; + carving.nb_vertices = POLY_NVERTS__; + carving.context = &POLY_EDGES__; + quadric.type = SSOL_QUADRIC_PARABOL; + quadric.data.parabol.focal = 10; + punched.nb_carvings = 1; + punched.quadric = &quadric; + punched.carvings = &carving; + CHECK(ssol_punched_surface_setup(parabol, &punched), RES_OK); + + CHECK(ssol_object_create(dev, &q_object), RES_OK); + CHECK(ssol_object_add_shaded_shape(q_object, parabol, m_mtl, m_mtl), RES_OK); + CHECK(ssol_object_instantiate(q_object, &geom2), RES_OK); + CHECK(ssol_instance_set_receiver(geom2, SSOL_FRONT, 0), RES_OK); + d3_splat(transform + 9, 0); + transform[9] = +10; + CHECK(ssol_instance_set_transform(geom2, transform), RES_OK); + CHECK(ssol_scene_attach_instance(scene, geom2), RES_OK); + + CHECK(ssol_scene_detach_instance(scene, geom1), RES_OK); + CHECK(ssol_estimator_ref_put(estimator), RES_OK); + +#define N2__ 100000 + CHECK(ssol_solve(scene, rng, N2__, 0, NULL, &estimator), RES_OK); + CHECK(ssol_estimator_get_realisation_count(estimator, &count), RES_OK); + CHECK(count, N2__); + CHECK(ssol_estimator_get_failed_count(estimator, &count), RES_OK); + CHECK(count, 0); + CHECK(ssol_estimator_get_mc_global(estimator, &mc_global2), RES_OK); + CHECK(GET_MC_RCV(estimator, geom2, SSOL_FRONT, &mc_rcv2), RES_OK); + + PRINT_GLOBAL(mc_global2); + PRINT_RCV(mc_rcv2); + CHECK(eq_eps(mc_global2.absorbed_by_receivers.E, DNI_S, 3 * mc_global2.absorbed_by_receivers.SE), 1); + + /* Free data */ + CHECK(ssol_instance_ref_put(geom1), RES_OK); + CHECK(ssol_instance_ref_put(geom2), RES_OK); + CHECK(ssol_object_ref_put(m_object), RES_OK); + CHECK(ssol_object_ref_put(q_object), RES_OK); + CHECK(ssol_shape_ref_put(square), RES_OK); + CHECK(ssol_shape_ref_put(parabol), RES_OK); + CHECK(ssol_material_ref_put(m_mtl), RES_OK); + CHECK(ssol_estimator_ref_put(estimator), RES_OK); + CHECK(ssol_device_ref_put(dev), RES_OK); + CHECK(ssol_scene_ref_put(scene), RES_OK); + CHECK(ssp_rng_ref_put(rng), RES_OK); + CHECK(ssol_spectrum_ref_put(spectrum), RES_OK); + CHECK(ssol_sun_ref_put(sun), RES_OK); + + check_memory_allocator(&allocator); + mem_shutdown_proxy_allocator(&allocator); + CHECK(mem_allocated_size(), 0); + + return 0; +} diff --git a/src/test_ssol_sun.c b/src/test_ssol_sun.c @@ -81,6 +81,10 @@ main(int argc, char** argv) CHECK(ssol_sun_pillbox_set_half_angle(sun, 999), RES_BAD_ARG); CHECK(ssol_sun_pillbox_set_half_angle(sun, 0.1), RES_BAD_ARG); + CHECK(ssol_sun_gaussian_set_std_dev(NULL, 0.1), RES_BAD_ARG); + CHECK(ssol_sun_gaussian_set_std_dev(sun, -0.1), RES_BAD_ARG); + CHECK(ssol_sun_gaussian_set_std_dev(sun, 0.1), RES_BAD_ARG); + CHECK(ssol_sun_set_buie_param(NULL, 0.1), RES_BAD_ARG); CHECK(ssol_sun_set_buie_param(sun, -0.1), RES_BAD_ARG); CHECK(ssol_sun_set_buie_param(sun, 999), RES_BAD_ARG); @@ -131,6 +135,65 @@ main(int argc, char** argv) CHECK(ssol_sun_pillbox_set_half_angle(sun, 0.1), RES_OK); CHECK(ssol_sun_pillbox_set_half_angle(sun, 0.1), RES_OK); + CHECK(ssol_sun_gaussian_set_std_dev(NULL, 0.1), RES_BAD_ARG); + CHECK(ssol_sun_gaussian_set_std_dev(sun, -0.1), RES_BAD_ARG); + CHECK(ssol_sun_gaussian_set_std_dev(sun, 0.1), RES_BAD_ARG); + + CHECK(ssol_sun_set_buie_param(NULL, 0.1), RES_BAD_ARG); + CHECK(ssol_sun_set_buie_param(sun, -0.1), RES_BAD_ARG); + CHECK(ssol_sun_set_buie_param(sun, 999), RES_BAD_ARG); + CHECK(ssol_sun_set_buie_param(sun, 0.1), RES_BAD_ARG); + + CHECK(ssol_sun_ref_put(sun), RES_OK); + + CHECK(ssol_sun_create_gaussian(NULL, &sun), RES_BAD_ARG); + CHECK(ssol_sun_create_gaussian(dev, NULL), RES_BAD_ARG); + CHECK(ssol_sun_create_gaussian(dev, &sun), RES_OK); + + CHECK(ssol_sun_ref_get(NULL), RES_BAD_ARG); + CHECK(ssol_sun_ref_get(sun), RES_OK); + + CHECK(ssol_sun_ref_put(NULL), RES_BAD_ARG); + CHECK(ssol_sun_ref_put(sun), RES_OK); + + CHECK(ssol_sun_set_spectrum(NULL, spectrum), RES_BAD_ARG); + CHECK(ssol_sun_set_spectrum(sun, NULL), RES_BAD_ARG); + CHECK(ssol_sun_set_spectrum(sun, spectrum), RES_OK); + CHECK(ssol_sun_set_spectrum(sun, spectrum2), RES_OK); + CHECK(ssol_sun_set_spectrum(sun, spectrum2), RES_OK); + + CHECK(ssol_sun_set_direction(NULL, dir), RES_BAD_ARG); + CHECK(ssol_sun_set_direction(sun, NULL), RES_BAD_ARG); + CHECK(ssol_sun_set_direction(sun, dir0), RES_BAD_ARG); + CHECK(ssol_sun_set_direction(sun, dir), RES_OK); + CHECK(ssol_sun_set_direction(sun, dir), RES_OK); + + CHECK(ssol_sun_get_direction(NULL, tmp), RES_BAD_ARG); + CHECK(ssol_sun_get_direction(sun, NULL), RES_BAD_ARG); + CHECK(ssol_sun_get_direction(sun, tmp), RES_OK); + CHECK(d3_eq(dir, tmp), 1); + + CHECK(ssol_sun_set_dni(NULL, 1000), RES_BAD_ARG); + CHECK(ssol_sun_set_dni(sun, 0), RES_BAD_ARG); + CHECK(ssol_sun_set_dni(sun, 1000), RES_OK); + CHECK(ssol_sun_set_dni(sun, 1000), RES_OK); + + CHECK(ssol_sun_get_dni(NULL, &dni), RES_BAD_ARG); + CHECK(ssol_sun_get_dni(sun, NULL), RES_BAD_ARG); + CHECK(ssol_sun_get_dni(sun, &dni), RES_OK); + CHECK(dni, 1000); + + CHECK(ssol_sun_pillbox_set_half_angle(NULL, 0.1), RES_BAD_ARG); + CHECK(ssol_sun_pillbox_set_half_angle(sun, -0.1), RES_BAD_ARG); + CHECK(ssol_sun_pillbox_set_half_angle(sun, 999), RES_BAD_ARG); + CHECK(ssol_sun_pillbox_set_half_angle(sun, 0.1), RES_BAD_ARG); + CHECK(ssol_sun_pillbox_set_half_angle(sun, 0.1), RES_BAD_ARG); + + CHECK(ssol_sun_gaussian_set_std_dev(NULL, 0.1), RES_BAD_ARG); + CHECK(ssol_sun_gaussian_set_std_dev(sun, -0.1), RES_BAD_ARG); + CHECK(ssol_sun_gaussian_set_std_dev(sun, 0.1), RES_OK); + CHECK(ssol_sun_gaussian_set_std_dev(sun, 0.1), RES_OK); + CHECK(ssol_sun_set_buie_param(NULL, 0.1), RES_BAD_ARG); CHECK(ssol_sun_set_buie_param(sun, -0.1), RES_BAD_ARG); CHECK(ssol_sun_set_buie_param(sun, 999), RES_BAD_ARG); @@ -179,6 +242,10 @@ main(int argc, char** argv) CHECK(ssol_sun_pillbox_set_half_angle(sun, 999), RES_BAD_ARG); CHECK(ssol_sun_pillbox_set_half_angle(sun, 0.1), RES_BAD_ARG); + CHECK(ssol_sun_gaussian_set_std_dev(NULL, 0.1), RES_BAD_ARG); + CHECK(ssol_sun_gaussian_set_std_dev(sun, -0.1), RES_BAD_ARG); + CHECK(ssol_sun_gaussian_set_std_dev(sun, 0.1), RES_BAD_ARG); + CHECK(ssol_sun_set_buie_param(NULL, 0.1), RES_BAD_ARG); CHECK(ssol_sun_set_buie_param(sun, -0.1), RES_BAD_ARG); CHECK(ssol_sun_set_buie_param(sun, 999), RES_BAD_ARG);