solstice-solver

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

commit 0fe127c2d514c6290dbf363d0989324eb455ba8b
parent 186d99fa31521ee424ce2f0dc2b1435babc12ed0
Author: Christophe Coustet <christophe.coustet@meso-star.com>
Date:   Wed, 21 Sep 2016 10:45:28 +0200

Add new coherency checks; improve solver test #1

Now detects:
- no sun
- DNI undefined
- no target
- sun and atmosphere spectra mismatch

Test atmosphere models and monochromatic sun

Diffstat:
Msrc/ssol_scene.c | 17++++++++++++++++-
Msrc/ssol_scene_c.h | 4+++-
Msrc/ssol_solver.c | 45++++++++++++++++++++++++++++++++++++++++-----
Msrc/test_ssol_solver1.c | 120+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++----
4 files changed, 173 insertions(+), 13 deletions(-)

diff --git a/src/ssol_scene.c b/src/ssol_scene.c @@ -248,10 +248,14 @@ ssol_scene_detach_atmosphere(struct ssol_scene* scene, struct ssol_atmosphere* a * Local functions ******************************************************************************/ res_T -scene_setup_s3d_sampling_scene(struct ssol_scene* scn) +scene_setup_s3d_sampling_scene + (struct ssol_scene* scn, + char* has_sampled, + char* has_receiver) { struct htable_instance_iterator it, end; res_T res = RES_OK; + char hs = 0, hr = 0; ASSERT(scn); S3D(scene_clear(scn->scn_samp)); @@ -265,7 +269,14 @@ scene_setup_s3d_sampling_scene(struct ssol_scene* scn) unsigned id; htable_instance_iterator_next(&it); + if (!str_is_empty(&inst->receiver_back) + || !str_is_empty(&inst->receiver_front)) + { + hr = 1; + } + if(inst->dont_sample) continue; + hs = 1; /* Attach the instantiated s3d sampling shape to the s3d sampling scene */ res = s3d_scene_attach_shape(scn->scn_samp, inst->shape_samp); @@ -282,10 +293,14 @@ scene_setup_s3d_sampling_scene(struct ssol_scene* scn) } exit: + if (has_sampled) *has_sampled = hs; + if (has_receiver) *has_receiver = hr; return res; error: S3D(scene_clear(scn->scn_samp)); htable_instance_clear(&scn->instances_samp); + has_sampled = NULL; + has_receiver = NULL; goto exit; } diff --git a/src/ssol_scene_c.h b/src/ssol_scene_c.h @@ -50,7 +50,9 @@ struct ssol_scene { /* Fill the Star-3D sampling scene with the Star-3D shape of the mirrors */ extern LOCAL_SYM res_T scene_setup_s3d_sampling_scene - (struct ssol_scene* scn); + (struct ssol_scene* scn, + char* has_sampled, + char* has_receiver); #endif /* SSOL_SCENE_C_H */ diff --git a/src/ssol_solver.c b/src/ssol_solver.c @@ -137,16 +137,21 @@ res_T set_views(struct solver_data* data) { res_T res = RES_OK; - size_t nshapes_samp = 0; + char has_sampled, has_receiver; if (!data) return RES_BAD_ARG; - res = scene_setup_s3d_sampling_scene(data->scene); + res = scene_setup_s3d_sampling_scene(data->scene, &has_sampled, &has_receiver); if(res != RES_OK) goto error; - S3D(scene_get_shapes_count(data->scene->scn_samp, &nshapes_samp)); - if(!nshapes_samp) { - log_error(data->scene->dev, "%s: no mirror geometry defined.\n", FUNC_NAME); + if (!has_sampled) { + log_error(data->scene->dev, "%s: no sampled geometry defined.\n", FUNC_NAME); + res = RES_BAD_ARG; + goto error; + } + + if (!has_receiver) { + log_error(data->scene->dev, "%s: no receiver defined.\n", FUNC_NAME); res = RES_BAD_ARG; goto error; } @@ -637,6 +642,36 @@ ssol_solve if (!scene || !rng || !output || !realisations_count) return RES_BAD_ARG; + if (!scene->sun) { + log_error(scene->dev, "%s: no sun attached.\n", FUNC_NAME); + return RES_BAD_ARG; + } + + if (!scene->sun->spectrum) { + log_error(scene->dev, "%s: sun's spectrum undefined.\n", FUNC_NAME); + return RES_BAD_ARG; + } + + if (scene->sun->dni <= 0) { + log_error(scene->dev, "%s: sun's DNI undefined.\n", FUNC_NAME); + return RES_BAD_ARG; + } + + if (scene->atmosphere) { + switch (scene->atmosphere->type) { + case ATMOS_UNIFORM: { + char ok; + CHECK(spectrum_includes(scene->atmosphere->data.uniform.spectrum, scene->sun->spectrum, &ok), RES_OK); + if (!ok) { + log_error(scene->dev, "%s: sun/atmosphere spectra mismatch.\n", FUNC_NAME); + return RES_BAD_ARG; + } + break; + } + default: FATAL("Unreachable code\n"); break; + } + } + /* init realisation */ res = init_realisation(scene, rng, output, &rs); if (res != RES_OK) goto error; diff --git a/src/test_ssol_solver1.c b/src/test_ssol_solver1.c @@ -49,10 +49,16 @@ main(int argc, char** argv) struct ssol_instance* secondary; struct ssol_instance* target; struct ssol_sun* sun; + struct ssol_sun* sun_mono; struct ssol_spectrum* spectrum; + struct ssol_spectrum* abs; + struct ssol_atmosphere* atm; double dir[3]; double frequencies[3] = { 1, 2, 3 }; + double mismatch[3] = { 1.5, 3.5 }; double intensities[3] = { 1, 0.8, 1 }; + double ka[3] = { 0, 0, 0 }; + double mono = 1.21; double transform1[12]; /* 3x4 column major matrix */ double transform2[12]; /* 3x4 column major matrix */ FILE* tmp = NULL; @@ -130,9 +136,57 @@ main(int argc, char** argv) CHECK(ssol_instance_set_target_mask(target, 0x4, 0), RES_OK); CHECK(ssol_scene_attach_instance(scene, target), RES_OK); + CHECK(ssol_solve(scene, rng, 1, stdout), RES_OK); /* ready to solve! */ + + CHECK(ssol_instance_dont_sample(target, 1), RES_OK); + CHECK(ssol_instance_dont_sample(secondary, 1), RES_OK); + CHECK(ssol_instance_dont_sample(heliostat, 1), RES_OK); + CHECK(ssol_solve(scene, rng, 10, stdout), RES_BAD_ARG); /* no geometry to sample */ + CHECK(ssol_instance_dont_sample(target, 0), RES_OK); + CHECK(ssol_instance_dont_sample(secondary, 0), RES_OK); + CHECK(ssol_instance_dont_sample(heliostat, 0), RES_OK); + + CHECK(ssol_scene_detach_sun(scene, sun), RES_OK); + CHECK(ssol_solve(scene, rng, 10, stdout), RES_BAD_ARG); /* no attached sun */ + CHECK(ssol_sun_ref_put(sun), RES_OK); + + CHECK(ssol_sun_create_directional(dev, &sun), RES_OK); + CHECK(ssol_sun_set_direction(sun, d3(dir, 1, 0, -1)), RES_OK); + CHECK(ssol_sun_set_dni(sun, 1000), RES_OK); + CHECK(ssol_scene_attach_sun(scene, sun), RES_OK); + CHECK(ssol_solve(scene, rng, 10, stdout), RES_BAD_ARG); /* sun with no spectrum */ + CHECK(ssol_scene_detach_sun(scene, sun), RES_OK); + CHECK(ssol_sun_ref_put(sun), RES_OK); + + CHECK(ssol_sun_create_directional(dev, &sun), RES_OK); + CHECK(ssol_sun_set_direction(sun, d3(dir, 1, 0, -1)), RES_OK); + CHECK(ssol_sun_set_spectrum(sun, spectrum), RES_OK); + CHECK(ssol_scene_attach_sun(scene, sun), RES_OK); + CHECK(ssol_solve(scene, rng, 10, stdout), RES_BAD_ARG); /* sun with undefined DNI */ + CHECK(ssol_sun_set_dni(sun, 1000), RES_OK); + + CHECK(ssol_instance_set_receiver(heliostat, NULL, NULL), RES_OK); + CHECK(ssol_instance_set_receiver(secondary, NULL, NULL), RES_OK); + CHECK(ssol_instance_set_receiver(target, NULL, NULL), RES_OK); + CHECK(ssol_solve(scene, rng, 10, stdout), RES_BAD_ARG); /* no receiver in scene */ + CHECK(ssol_instance_set_receiver(heliostat, "miroir", NULL), RES_OK); + CHECK(ssol_instance_set_receiver(secondary, "secondaire", NULL), RES_OK); + CHECK(ssol_instance_set_receiver(target, "cible", NULL), RES_OK); + + CHECK(ssol_spectrum_create(dev, &abs), RES_OK); + CHECK(ssol_spectrum_setup(abs, mismatch, ka, 2), RES_OK); + CHECK(ssol_atmosphere_create_uniform(dev, &atm), RES_OK); + CHECK(ssol_atmosphere_set_uniform_absorbtion(atm, abs), RES_OK); + CHECK(ssol_scene_attach_atmosphere(scene, atm), RES_OK); + CHECK(ssol_solve(scene, rng, 10, stdout), RES_BAD_ARG); /* spectra mismatch */ + CHECK(ssol_scene_detach_atmosphere(scene, atm), RES_OK); + CHECK(ssol_spectrum_ref_put(abs), RES_OK); + CHECK(ssol_atmosphere_ref_put(atm), RES_OK); + + /* can sample any geometry; variance is high */ tmp = tmpfile(); CHECK(!tmp, 0); -#define N 10000 +#define N 5000 CHECK(ssol_solve(scene, rng, N, tmp), RES_OK); CHECK(pp_sum(tmp, "cible", &m, &std), RES_OK); #define DNI_cos (1000 * cos(PI / 4)) @@ -142,23 +196,74 @@ main(int argc, char** argv) logger_print(&logger, LOG_OUTPUT, "\nP = %g +/- %g\n", m, std); CHECK(fclose(tmp), 0); + /* sample primary mirror only; variance is low */ CHECK(ssol_instance_dont_sample(target, 1), RES_OK); CHECK(ssol_instance_dont_sample(secondary, 1), RES_OK); CHECK(ssol_instance_set_target_mask(heliostat, 0, 0), RES_OK); CHECK(ssol_instance_set_target_mask(secondary, 0, 0), RES_OK); CHECK(ssol_instance_set_target_mask(target, 0x1, 0), RES_OK); - CHECK(ssol_solve(scene, rng, 20, stdout), RES_OK); - tmp = tmpfile(); CHECK(ssol_solve(scene, rng, N, tmp), RES_OK); CHECK(pp_sum(tmp, "cible", &m, &std), RES_OK); CHECK(eq_eps(m, 4 * DNI_cos, 4 * DNI_cos * 1e-4), 1); - CHECK(eq_eps(std, sqrt((SQR(4 * DNI_cos) - SQR(4 * DNI_cos)) / N), 1e-4), 1); + CHECK(eq_eps(std, 0, 1e-4), 1); logger_print(&logger, LOG_OUTPUT, "\nP = %g +/- %g\n", m, std); + CHECK(fclose(tmp), 0); - CHECK(ssol_instance_dont_sample(heliostat, 1), RES_OK); - CHECK(ssol_solve(scene, rng, 10, stdout), RES_BAD_ARG); /* no sampled geometry */ + /* check atmosphere model; with no absorbtion result is unchanged */ + CHECK(ssol_spectrum_create(dev, &abs), RES_OK); + CHECK(ssol_spectrum_setup(abs, frequencies, ka, 3), RES_OK); + CHECK(ssol_atmosphere_create_uniform(dev, &atm), RES_OK); + CHECK(ssol_atmosphere_set_uniform_absorbtion(atm, abs), RES_OK); + CHECK(ssol_scene_attach_atmosphere(scene, atm), RES_OK); + + NCHECK(tmp = tmpfile(), 0); + CHECK(ssol_solve(scene, rng, N, tmp), RES_OK); + CHECK(pp_sum(tmp, "cible", &m, &std), RES_OK); + logger_print(&logger, LOG_OUTPUT, "\nP = %g +/- %g\n", m, std); + CHECK(fclose(tmp), 0); + CHECK(eq_eps(m, 4 * DNI_cos, 4 * DNI_cos * 1e-4), 1); + CHECK(eq_eps(std, 0, 1e-4), 1); + CHECK(ssol_scene_detach_atmosphere(scene, atm), RES_OK); + CHECK(ssol_spectrum_ref_put(abs), RES_OK); + CHECK(ssol_atmosphere_ref_put(atm), RES_OK); + + /* check atmosphere model; with absorbtion power decreases */ + ka[0] = ka[1] = ka[2] = 0.1; + CHECK(ssol_spectrum_create(dev, &abs), RES_OK); + CHECK(ssol_spectrum_setup(abs, frequencies, ka, 3), RES_OK); + CHECK(ssol_atmosphere_create_uniform(dev, &atm), RES_OK); + CHECK(ssol_atmosphere_set_uniform_absorbtion(atm, abs), RES_OK); + CHECK(ssol_scene_attach_atmosphere(scene, atm), RES_OK); + + NCHECK(tmp = tmpfile(), 0); + CHECK(ssol_solve(scene, rng, N, tmp), RES_OK); + CHECK(pp_sum(tmp, "cible", &m, &std), RES_OK); + logger_print(&logger, LOG_OUTPUT, "\nP = %g +/- %g\n", m, std); + CHECK(fclose(tmp), 0); +#define K (exp(-0.1 * 2 * sqrt(2))) + CHECK(eq_eps(m, 4 * K * DNI_cos, 4 * K * DNI_cos * 1e-4), 1); + CHECK(eq_eps(std, 0, 1e-4), 1); + + /* check a monochromatic sun */ + CHECK(ssol_spectrum_setup(spectrum, &mono, intensities, 1), RES_OK); + CHECK(ssol_sun_create_directional(dev, &sun_mono), RES_OK); + CHECK(ssol_sun_set_direction(sun_mono, d3(dir, 1, 0, -1)), RES_OK); + CHECK(ssol_sun_set_spectrum(sun_mono, spectrum), RES_OK); + CHECK(ssol_sun_set_dni(sun_mono, 1000), RES_OK); + CHECK(ssol_scene_detach_sun(scene, sun), RES_OK); + CHECK(ssol_scene_attach_sun(scene, sun_mono), RES_OK); + ka[1] = 0.2; + CHECK(ssol_spectrum_setup(abs, frequencies, ka, 2), RES_OK); + NCHECK(tmp = tmpfile(), 0); + CHECK(ssol_solve(scene, rng, N, tmp), RES_OK); + CHECK(pp_sum(tmp, "cible", &m, &std), RES_OK); + logger_print(&logger, LOG_OUTPUT, "\nP = %g +/- %g\n", m, std); + CHECK(fclose(tmp), 0); +#define K2 (exp(-0.121 * 2 * sqrt(2))) + CHECK(eq_eps(m, 4 * K2 * DNI_cos, 4 * DNI_cos * 1e-4), 1); + CHECK(eq_eps(std, 0, 1e-4), 1); /* free data */ @@ -173,8 +278,11 @@ main(int argc, char** argv) 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(abs), RES_OK); + CHECK(ssol_atmosphere_ref_put(atm), RES_OK); CHECK(ssol_spectrum_ref_put(spectrum), RES_OK); CHECK(ssol_sun_ref_put(sun), RES_OK); + CHECK(ssol_sun_ref_put(sun_mono), RES_OK); logger_release(&logger);