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:
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);