solstice

Compute collected power and efficiencies of a solar plant
git clone git://git.meso-star.com/solstice.git
Log | Files | Refs | README | LICENSE

commit 78c1c9ae4a38b977eddc8d582a27ad3a184e0973
parent 8d3f3f33dd24cba5b478ad728964b8e23aac8153
Author: Christophe Coustet <christophe.coustet@meso-star.com>
Date:   Wed, 18 Apr 2018 14:48:11 +0200

Allow to output per-primitive incoming and/or absorbed fluxes.

Was previously restricted to incoming flux.

Diffstat:
Mdoc/solstice-receiver.5.txt | 24++++++++++++++++--------
Msrc/receivers/srcvl.c | 40++++++++++++++++++++++++----------------
Msrc/receivers/srcvl.h | 15+++++++++++----
Msrc/receivers/test_srcvl2.c | 32++++++++++++++++++++++----------
Msrc/receivers/yaml/test_ko.yaml | 5++++-
Msrc/receivers/yaml/test_ok.yaml | 2+-
Msrc/solstice.c | 4++--
Msrc/solstice.h | 8++++----
Msrc/solstice_entity.c | 25++++++++++++++++++++-----
Msrc/solstice_solve.c | 77+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++------------------
10 files changed, 163 insertions(+), 69 deletions(-)

diff --git a/doc/solstice-receiver.5.txt b/doc/solstice-receiver.5.txt @@ -47,10 +47,12 @@ that is tracked is defined by the *side* attribute of the receiver. Note that the front and the back side of a geometry can be both considered if the *side* attribute is set to *FRONT_AND_BACK*. Refer to the *solstice-input*(5) specification for informations on which side of the geometry is front facing or -back facing. Finally, if the optional *per_primitive* flag is set to *1*, +back facing. Finally, if the optional *per_primitive* flag is set, *solstice*(1) will estimate the irradiance for each triangle of the receiver and use these data to generate a receiver map as described in -*solstice-output*(5). +*solstice-output*(5). The *per-primitive* flag can be set to *INCOMING*, +*ABSORBED* or *INCOMING_AND_ABSORBED* to produce the incoming flux map, the +absorbed flux map, or both. GRAMMAR ------- @@ -62,12 +64,17 @@ _______ <receiver> ::= name: <entity-identifier> side: <side-identifier> - [ per_primitive: INTEGER ] # in [0, 1] + [ per_primitive: <per-primitive-mode> ] <side-identifier> ::= FRONT | BACK | FRONT_AND_BACK +<per-primitive-mode> ::= NONE + | INCOMING + | ABSORBED + | INCOMING_AND_ABSORBED + <entity-identifier> # Defined in *solstice-input*(5) _______ @@ -75,12 +82,13 @@ EXAMPLES -------- Define that the front and back side of the entity *small_square* are -receivers. For each side, enable the computation of per triangle irradiance. +receivers. For each side, enable the computation of per triangle absorbed +irradiance. ....... - name: small_square side: FRONT_AND_BACK - per_primitive: 1 + per_primitive: ABSORBED ....... Declare that the front side of 3 reflectors are receivers. Use the YAML @@ -93,11 +101,11 @@ compact notation to reduce the number of lines: ...... Declare that the back side of *receiver* is effectively a receiver and enable -the estimation of its associated irradiance map. Make a receiver from the front -side of the reflector named *LFR0.pivot.reflector*: +the estimation of its associated incoming irradiance map. Make a receiver from +the front side of the reflector named *LFR0.pivot.reflector*: ....... -- {name: receiver, side: BACK, per_primitive: 1} +- {name: receiver, side: BACK, per_primitive: INCOMING} - {name: LFR0.pivot.reflector, side: FRONT} ....... diff --git a/src/receivers/srcvl.c b/src/receivers/srcvl.c @@ -28,7 +28,7 @@ struct receiver { struct str name; enum srcvl_side side; - int per_primitive; + enum srcvl_pp_output per_primitive_output; }; static INLINE void @@ -37,7 +37,7 @@ receiver_init(struct mem_allocator* allocator, struct receiver* receiver) ASSERT(receiver); str_init(allocator, &receiver->name); receiver->side = SRCVL_FRONT_AND_BACK; - receiver->per_primitive = 0; + receiver->per_primitive_output = SRCVL_PP_NONE; } static INLINE void @@ -52,7 +52,7 @@ receiver_copy(struct receiver* dst, const struct receiver* src) { ASSERT(dst && src); dst->side = src->side; - dst->per_primitive = src->per_primitive; + dst->per_primitive_output = src->per_primitive_output; return str_copy(&dst->name, &src->name); } @@ -61,7 +61,7 @@ receiver_copy_and_release(struct receiver* dst, struct receiver* src) { ASSERT(dst && src); dst->side = src->side; - dst->per_primitive = src->per_primitive; + dst->per_primitive_output = src->per_primitive_output; return str_copy_and_release(&dst->name, &src->name); } @@ -168,26 +168,34 @@ error: } static res_T -parse_integer(struct srcvl* srcvl, yaml_node_t* integer, int* dst) +parse_pp_output + (struct srcvl* srcvl, + yaml_node_t* side, + enum srcvl_side* out_side) { res_T res = RES_OK; - ASSERT(integer && dst); + ASSERT(side && out_side); - if(integer->type != YAML_SCALAR_NODE - || !strlen((char*)integer->data.scalar.value)) { - log_err(srcvl, integer, "expect an integer.\n"); + if(side->type != YAML_SCALAR_NODE) { + log_err(srcvl, side, "expect a character string.\n"); res = RES_BAD_ARG; goto error; } - res = cstr_to_int((char*)integer->data.scalar.value, dst); - if(res != RES_OK) { - log_err(srcvl, integer, "invalid integer `%s'.\n", - integer->data.scalar.value); + if(!strcmp((char*) side->data.scalar.value, "NONE")) { + *out_side = SRCVL_PP_NONE; + } else if(!strcmp((char*) side->data.scalar.value, "INCOMING")) { + *out_side = SRCVL_PP_INCOMING; + } else if(!strcmp((char*) side->data.scalar.value, "ABSORBED")) { + *out_side = SRCVL_PP_ABSORBED; + } else if(!strcmp((char*) side->data.scalar.value, "INCOMING_AND_ABSORBED")) { + *out_side = SRCVL_PP_INCOMING_AND_ABSORBED; + } else { + log_err(srcvl, side, "unknown per primitive output type value `%s'.\n", + side->data.scalar.value); res = RES_BAD_ARG; goto error; } - exit: return res; error: @@ -251,7 +259,7 @@ parse_receiver res = parse_side(srcvl, val, &solreceiver->side); } else if(!strcmp((char*)key->data.scalar.value, "per_primitive")) { SETUP_MASK(PER_PRIMITIVE, "per_primitive"); - res = parse_integer(srcvl, val, &solreceiver->per_primitive); + res = parse_pp_output(srcvl, val, &solreceiver->per_primitive_output); } else { log_err(srcvl, key, "unknown receiver parameter `%s'.\n", key->data.scalar.value); @@ -461,6 +469,6 @@ srcvl_get r = darray_receiver_cdata_get(&srcvl->receivers) + i; receiver->name = str_cget(&r->name); receiver->side = r->side; - receiver->per_primitive = r->per_primitive; + receiver->per_primitive_output = r->per_primitive_output; } diff --git a/src/receivers/srcvl.h b/src/receivers/srcvl.h @@ -19,15 +19,22 @@ #include <rsys/rsys.h> enum srcvl_side { - SRCVL_FRONT, - SRCVL_BACK, - SRCVL_FRONT_AND_BACK + SRCVL_FRONT = BIT(0), + SRCVL_BACK = BIT(1), + SRCVL_FRONT_AND_BACK = SRCVL_FRONT + SRCVL_BACK +}; + +enum srcvl_pp_output { + SRCVL_PP_NONE = 0, + SRCVL_PP_INCOMING = BIT(0), + SRCVL_PP_ABSORBED = BIT(1), + SRCVL_PP_INCOMING_AND_ABSORBED = SRCVL_PP_INCOMING + SRCVL_PP_ABSORBED }; struct srcvl_receiver { const char* name; enum srcvl_side side; - int per_primitive; /* Define if per primitive receiver is enabled */ + enum srcvl_pp_output per_primitive_output; }; struct mem_allocator; diff --git a/src/receivers/test_srcvl2.c b/src/receivers/test_srcvl2.c @@ -39,48 +39,60 @@ main(int argc, char** argv) fprintf(stream, "- { name: entity3, side: BACK }\n"); fprintf(stream, "- name: entity4\n"); fprintf(stream, " side: FRONT_AND_BACK\n"); - fprintf(stream, "- { name: entity5, side: BACK, per_primitive: 1 }\n"); - fprintf(stream, "- { name: entity6, per_primitive: 0, side: FRONT }\n"); + fprintf(stream, "- { name: entity5, side: BACK, per_primitive: INCOMING }\n"); + fprintf(stream, "- { name: entity6, side: BACK, per_primitive: ABSORBED }\n"); + fprintf(stream, "- { name: entity7, side: BACK, per_primitive: INCOMING_AND_ABSORBED }\n"); + fprintf(stream, "- { name: entity8, per_primitive: NONE, side: FRONT }\n"); rewind(stream); CHK(srcvl_setup_stream(srcvl, NULL, stream) == RES_OK); CHK(srcvl_load(srcvl) == RES_OK); - CHK(srcvl_count(srcvl) == 7); + CHK(srcvl_count(srcvl) == 9); srcvl_get(srcvl, 0, &receiver); CHK(strcmp(receiver.name, "entity0") == 0); CHK(receiver.side == SRCVL_FRONT_AND_BACK); - CHK(receiver.per_primitive == 0); + CHK(receiver.per_primitive_output == SRCVL_PP_NONE); srcvl_get(srcvl, 1, &receiver); CHK(strcmp(receiver.name, "entity1") == 0); CHK(receiver.side == SRCVL_FRONT_AND_BACK); - CHK(receiver.per_primitive == 0); + CHK(receiver.per_primitive_output == SRCVL_PP_NONE); srcvl_get(srcvl, 2, &receiver); CHK(strcmp(receiver.name, "entity2") == 0); CHK(receiver.side == SRCVL_FRONT); - CHK(receiver.per_primitive == 0); + CHK(receiver.per_primitive_output == SRCVL_PP_NONE); srcvl_get(srcvl, 3, &receiver); CHK(strcmp(receiver.name, "entity3") == 0); CHK(receiver.side == SRCVL_BACK); - CHK(receiver.per_primitive == 0); + CHK(receiver.per_primitive_output == SRCVL_PP_NONE); srcvl_get(srcvl, 4, &receiver); CHK(strcmp(receiver.name, "entity4") == 0); CHK(receiver.side == SRCVL_FRONT_AND_BACK); - CHK(receiver.per_primitive == 0); + CHK(receiver.per_primitive_output == SRCVL_PP_NONE); srcvl_get(srcvl, 5, &receiver); CHK(strcmp(receiver.name, "entity5") == 0); CHK(receiver.side == SRCVL_BACK); - CHK(receiver.per_primitive == 1); + CHK(receiver.per_primitive_output == SRCVL_PP_INCOMING); srcvl_get(srcvl, 6, &receiver); CHK(strcmp(receiver.name, "entity6") == 0); + CHK(receiver.side == SRCVL_BACK); + CHK(receiver.per_primitive_output == SRCVL_PP_ABSORBED); + + srcvl_get(srcvl, 7, &receiver); + CHK(strcmp(receiver.name, "entity7") == 0); + CHK(receiver.side == SRCVL_BACK); + CHK(receiver.per_primitive_output == SRCVL_PP_INCOMING_AND_ABSORBED); + + srcvl_get(srcvl, 8, &receiver); + CHK(strcmp(receiver.name, "entity8") == 0); CHK(receiver.side == SRCVL_FRONT); - CHK(receiver.per_primitive == 0); + CHK(receiver.per_primitive_output == SRCVL_PP_NONE); CHK(srcvl_load(srcvl) == RES_BAD_OP); diff --git a/src/receivers/yaml/test_ko.yaml b/src/receivers/yaml/test_ko.yaml @@ -25,4 +25,7 @@ - name: test per_primitive: --- -- per_primitive: 1 +- name: test + per_primitive: NOPE +--- +- per_primitive: NONE diff --git a/src/receivers/yaml/test_ok.yaml b/src/receivers/yaml/test_ok.yaml @@ -13,6 +13,6 @@ {name: test}, {side: FRONT_AND_BACK, name: "Hello world"}, {name: Hello world, side: BACK} - {name: hop, per_primitive: 1} + {name: hop, per_primitive: ABSORBED} {per_primitive: 0, name: test} ] diff --git a/src/solstice.c b/src/solstice.c @@ -357,7 +357,7 @@ setup_sun_dirs(struct solstice* solstice, const struct solstice_args* args) goto error; } res = darray_double_resize(&solstice->sun_angles, args->nsun_dirs*2/*#dims*/); - if (res != RES_OK) { + if(res != RES_OK) { fprintf(stderr, "Could not reserve the list of %lu sun angles.\n", (unsigned long)args->nsun_dirs); @@ -476,7 +476,7 @@ setup_receivers(struct solstice* solstice, struct srcvl* srcvl) receiver->node = NULL; receiver->side = rcv.side; - receiver->per_primitive = rcv.per_primitive; + receiver->per_primitive_output = rcv.per_primitive_output; name = str_cget(&receiver->name); res = htable_receiver_set(&solstice->receivers, &name, &i); diff --git a/src/solstice.h b/src/solstice.h @@ -37,7 +37,7 @@ struct solstice_receiver { struct str name; struct solstice_node* node; enum srcvl_side side; - int per_primitive; + enum srcvl_pp_output per_primitive_output; }; static INLINE void @@ -48,7 +48,7 @@ solstice_receiver_init str_init(allocator, &rcv->name); rcv->node = NULL; rcv->side = SRCVL_FRONT_AND_BACK; - rcv->per_primitive = 0; + rcv->per_primitive_output = SRCVL_PP_NONE; } static INLINE void @@ -66,7 +66,7 @@ solstice_receiver_copy ASSERT(dst && src); dst->node = src->node; dst->side = src->side; - dst->per_primitive = src->per_primitive; + dst->per_primitive_output = src->per_primitive_output; return str_copy(&dst->name, &src->name); } @@ -79,7 +79,7 @@ solstice_receiver_copy_and_release ASSERT(dst && src); dst->node = src->node; dst->side = src->side; - dst->per_primitive = src->per_primitive; + dst->per_primitive_output = src->per_primitive_output; res = str_copy_and_release(&dst->name, &src->name); if(res != RES_OK) return res; solstice_receiver_release(src); diff --git a/src/solstice_entity.c b/src/solstice_entity.c @@ -83,6 +83,20 @@ srcvl_side_to_ssol_mask(const enum srcvl_side side) return mask; } +static INLINE int +srcvl_per_prim_to_bool(const enum srcvl_pp_output output) +{ + int mask = 0; + switch (output) { + case SRCVL_PP_NONE: mask = 0; break; + case SRCVL_PP_INCOMING: mask = 1; break; + case SRCVL_PP_ABSORBED: mask = 1; break; + case SRCVL_PP_INCOMING_AND_ABSORBED: mask = 1; break; + default: FATAL("Unreachable code.\n"); break; + } + return mask; +} + static struct solstice_node* create_empty_node (struct solstice* solstice, const struct solparser_entity* entity) @@ -338,11 +352,11 @@ create_node str_cget(&entity->name)); goto error; } - if (entity->primary) { + if(entity->primary) { struct solstice_primary p; p.node = node; res = htable_primary_set(&solstice->primaries, name, &p); - if (res != RES_OK) { + if(res != RES_OK) { fprintf(stderr, "Could not define the entity `%s' as primary.\n", str_cget(&entity->name)); goto error; @@ -354,13 +368,14 @@ create_node str = str_cget(name); pircv = htable_receiver_find(&solstice->receivers, &str); if(pircv) { - int mask; + int side_mask, output; rcv = darray_receiver_data_get(&solstice->rcvs_list) + *pircv; ASSERT(rcv->node == NULL); /* Receiver is not attached to a node */ - mask = srcvl_side_to_ssol_mask(rcv->side); + side_mask = srcvl_side_to_ssol_mask(rcv->side); + output = srcvl_per_prim_to_bool(rcv->per_primitive_output); - res = solstice_node_geometry_set_receiver(node, mask, rcv->per_primitive); + res = solstice_node_geometry_set_receiver(node, side_mask, output); if(res != RES_OK) { fprintf(stderr, "Could not define the entity `%s' as a receiver.\n", str_cget(&entity->name)); diff --git a/src/solstice_solve.c b/src/solstice_solve.c @@ -136,7 +136,7 @@ write_mc_global(struct solstice* solstice, struct ssol_estimator* estimator) /* Primary-instances' data */ htable_primary_begin(&solstice->primaries, &p_it); htable_primary_end(&solstice->primaries, &p_end); - while (!htable_primary_iterator_eq(&p_it, &p_end)) { + while(!htable_primary_iterator_eq(&p_it, &p_end)) { const struct str* name = htable_primary_iterator_key_get(&p_it); struct solstice_primary* prim = htable_primary_iterator_data_get(&p_it); struct ssol_mc_sampled sampled; @@ -165,7 +165,7 @@ write_mc_global(struct solstice* solstice, struct ssol_estimator* estimator) SSOL(instance_get_id(rcv_inst, &rcv_id)); htable_primary_begin(&solstice->primaries, &p_it); htable_primary_end(&solstice->primaries, &p_end); - while (!htable_primary_iterator_eq(&p_it, &p_end)) { + while(!htable_primary_iterator_eq(&p_it, &p_end)) { struct solstice_primary* prim = htable_primary_iterator_data_get(&p_it); struct ssol_instance* prim_inst = prim->node->instance; struct ssol_mc_receiver front = MC_RCV_NONE__; @@ -259,7 +259,7 @@ dump_shape_triangle_indices } static void -dump_mc_shape +dump_mc_shape_in (struct solstice* solstice, struct ssol_shape* shape, struct ssol_mc_shape* mc_shape) @@ -278,15 +278,36 @@ dump_mc_shape } static void +dump_mc_shape_abs + (struct solstice* solstice, + struct ssol_shape* shape, + struct ssol_mc_shape* mc_shape) +{ + unsigned itri, ntris; + ASSERT(solstice && shape && mc_shape); + + SSOL(shape_get_triangles_count(shape, &ntris)); + FOR_EACH(itri, 0, ntris) { + struct ssol_mc_primitive mc_prim; + SSOL(mc_shape_get_mc_primitive(mc_shape, itri, &mc_prim)); + fprintf(solstice->output, "%g %g\n", + mc_prim.absorbed_flux.E, + mc_prim.absorbed_flux.SE); + } +} + +static void dump_per_primitive_mc_estimations (struct solstice* solstice, struct ssol_estimator* estimator, struct ssol_instance* inst, - const enum ssol_side_flag side) + const enum ssol_side_flag side, + const enum srcvl_pp_output output) { size_t ishape, nshapes; struct ssol_mc_receiver mc_rcv; const char* name; + const char* flux; ASSERT(solstice && estimator && inst); SSOL(estimator_get_mc_receiver(estimator, inst, side, &mc_rcv)); @@ -296,8 +317,13 @@ dump_per_primitive_mc_estimations case SSOL_BACK: name = "Back_faces"; break; default: FATAL("Unreachable code.\n"); break; } + switch (output) { + case SRCVL_PP_INCOMING: flux = "Incoming_flux"; break; + case SRCVL_PP_ABSORBED: flux = "Absorbed_flux"; break; + default: FATAL("Unreachable code.\n"); break; + } - fprintf(solstice->output, "SCALARS %s float 2\n", name); + fprintf(solstice->output, "SCALARS %s__%s float 2\n", name, flux); fprintf(solstice->output, "LOOKUP_TABLE default\n"); SSOL(instance_get_shaded_shapes_count(inst, &nshapes)); @@ -306,7 +332,14 @@ dump_per_primitive_mc_estimations struct ssol_mc_shape mc_shape; SSOL(instance_get_shaded_shape(inst, ishape, &inst_sshape)); SSOL(mc_receiver_get_mc_shape(&mc_rcv, inst_sshape.shape, &mc_shape)); - dump_mc_shape(solstice, inst_sshape.shape, &mc_shape); + switch (output) { + case SRCVL_PP_INCOMING: + dump_mc_shape_in(solstice, inst_sshape.shape, &mc_shape); + break; + case SRCVL_PP_ABSORBED: + dump_mc_shape_abs(solstice, inst_sshape.shape, &mc_shape); + break; + } } } @@ -327,6 +360,7 @@ write_per_receiver_mc_primitive size_t offset; int mask, prim; + ASSERT(rcv->side); SSOL(instance_is_receiver(inst, &mask, &prim)); CHK(mask != 0); if(!prim) continue; @@ -371,18 +405,25 @@ write_per_receiver_mc_primitive /* Write front faces MC estimations */ fprintf(solstice->output, "CELL_DATA %lu\n", (unsigned long)ntris); - switch(rcv->side) { - case SRCVL_FRONT: - dump_per_primitive_mc_estimations(solstice, estimator, inst, SSOL_FRONT); - break; - case SRCVL_BACK: - dump_per_primitive_mc_estimations(solstice, estimator, inst, SSOL_BACK); - break; - case SRCVL_FRONT_AND_BACK: - dump_per_primitive_mc_estimations(solstice, estimator, inst, SSOL_FRONT); - dump_per_primitive_mc_estimations(solstice, estimator, inst, SSOL_BACK); - break; - default: FATAL("Unreachable code.\n"); break; + if(rcv->side & SRCVL_FRONT) { + if(rcv->per_primitive_output & SRCVL_PP_INCOMING) { + dump_per_primitive_mc_estimations(solstice, estimator, inst, + SSOL_FRONT, SRCVL_PP_INCOMING); + } + if(rcv->per_primitive_output & SRCVL_PP_ABSORBED) { + dump_per_primitive_mc_estimations(solstice, estimator, inst, + SSOL_FRONT, SRCVL_PP_ABSORBED); + } + } + if(rcv->side & SRCVL_BACK) { + if(rcv->per_primitive_output & SRCVL_PP_INCOMING) { + dump_per_primitive_mc_estimations(solstice, estimator, inst, + SSOL_BACK, SRCVL_PP_INCOMING); + } + if(rcv->per_primitive_output & SRCVL_PP_ABSORBED) { + dump_per_primitive_mc_estimations(solstice, estimator, inst, + SSOL_BACK, SRCVL_PP_ABSORBED); + } } } }