solstice

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

solstice_entity.c (14724B)


      1 /* Copyright (C) 2018-2026 |Meso|Star> (contact@meso-star.com)
      2  * Copyright (C) 2016-2018 CNRS
      3  *
      4  * This program is free software: you can redistribute it and/or modify
      5  * it under the terms of the GNU General Public License as published by
      6  * the Free Software Foundation, either version 3 of the License, or
      7  * (at your option) any later version.
      8  *
      9  * This program is distributed in the hope that it will be useful,
     10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
     11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
     12  * GNU General Public License for more details.
     13  *
     14  * You should have received a copy of the GNU General Public License
     15  * along with this program. If not, see <http://www.gnu.org/licenses/>. */
     16 
     17 #include "solstice.h"
     18 #include "solstice_c.h"
     19 
     20 #include <solstice/ssol.h>
     21 #include <solstice/sanim.h>
     22 
     23 #include <rsys/double33.h>
     24 
     25 /*******************************************************************************
     26  * Helper function
     27  ******************************************************************************/
     28 static res_T
     29 update_instance_transform
     30   (const struct sanim_node* n, const double transform[12], void* data)
     31 {
     32   res_T res = RES_OK;
     33   struct solstice_node* node;
     34   ASSERT(n && transform && data);
     35   (void)data;
     36   node = CONTAINER_OF(n, struct solstice_node, anim);
     37   if(node->type != SOLSTICE_NODE_GEOMETRY) return RES_OK;
     38   res = ssol_instance_set_transform(node->instance, transform);
     39   if(res != RES_OK) goto error;
     40 
     41 exit:
     42   return res;
     43 error:
     44   goto exit;
     45 }
     46 
     47 static res_T
     48 merge_name
     49   (struct str* output,
     50    const struct str* name0,
     51    const struct str* name1)
     52 {
     53   res_T res = RES_OK;
     54   ASSERT(output && name0 && name1);
     55   ASSERT(output != name0 && output != name1);
     56 
     57   res = str_copy(output, name0);
     58   if(res != RES_OK) goto error;
     59 
     60   res = str_append_char(output, '.');
     61   if(res != RES_OK) goto error;
     62 
     63   res = str_append(output, str_cget(name1));
     64   if(res != RES_OK) goto error;
     65 
     66 exit:
     67   return res;
     68 error:
     69   fprintf(stderr, "Could not build the name from `%s' and `%s'.\n",
     70     str_cget(name0), str_cget(name1));
     71   goto exit;
     72 }
     73 
     74 static INLINE int
     75 srcvl_side_to_ssol_mask(const enum srcvl_side side)
     76 {
     77   int mask = 0;
     78   switch(side) {
     79     case SRCVL_BACK: mask = SSOL_BACK; break;
     80     case SRCVL_FRONT: mask = SSOL_FRONT; break;
     81     case SRCVL_FRONT_AND_BACK: mask = SSOL_BACK | SSOL_FRONT; break;
     82     default: FATAL("Unreachable code.\n"); break;
     83   }
     84   return mask;
     85 }
     86 
     87 static INLINE int
     88 srcvl_per_prim_to_bool(const enum srcvl_pp_output output)
     89 {
     90   int mask = 0;
     91   switch (output) {
     92     case SRCVL_PP_NONE: mask = 0; break;
     93     case SRCVL_PP_INCOMING: mask = 1; break;
     94     case SRCVL_PP_ABSORBED: mask = 1; break;
     95     case SRCVL_PP_INCOMING_AND_ABSORBED: mask = 1; break;
     96     default: FATAL("Unreachable code.\n"); break;
     97   }
     98   return mask;
     99 }
    100 
    101 static struct solstice_node*
    102 create_empty_node
    103   (struct solstice* solstice, const struct solparser_entity* entity)
    104 {
    105   struct solstice_node* node = NULL;
    106   res_T res = RES_OK;
    107   ASSERT(solstice && entity);
    108   (void)entity;
    109 
    110   res = solstice_node_empty_create(solstice->allocator, &node);
    111   if(res != RES_OK) goto error;
    112 
    113 exit:
    114   return node;
    115 error:
    116   if(node) {
    117     solstice_node_ref_put(node);
    118     node = NULL;
    119   }
    120   goto exit;
    121 }
    122 
    123 static struct solstice_node*
    124 create_geometry_node
    125   (struct solstice* solstice, const struct solparser_entity* entity)
    126 {
    127   struct solstice_node* node = NULL;
    128   struct ssol_instance* instance = NULL;
    129   res_T res = RES_OK;
    130   ASSERT(solstice && entity);
    131 
    132   res = solstice_instantiate_geometry
    133     (solstice, entity->data.geometry, &instance);
    134   if(res != RES_OK) goto error;
    135 
    136   res = solstice_node_geometry_create(solstice->allocator, instance, &node);
    137   if(res != RES_OK) goto error;
    138 
    139 exit:
    140   if(instance) SSOL(instance_ref_put(instance));
    141   return node;
    142 error:
    143   if(node) {
    144     solstice_node_ref_put(node);
    145     node = NULL;
    146   }
    147   goto exit;
    148 }
    149 
    150 static res_T
    151 get_anchor_node
    152   (struct solstice* solstice,
    153    const struct solparser_anchor_id anchor_id,
    154    struct solstice_node** out_node)
    155 {
    156   struct solstice_node* node = NULL;
    157   struct solstice_node** pnode = NULL;
    158   res_T res = RES_OK;
    159   ASSERT(solstice && out_node);
    160 
    161   pnode = htable_anchor_find(&solstice->anchors, &anchor_id.i);
    162   if(pnode) {
    163     node = *pnode;
    164   } else {
    165     res = solstice_node_target_create(solstice->allocator, &node);
    166     if(res != RES_OK) goto error;
    167     res = htable_anchor_set(&solstice->anchors, &anchor_id.i, &node);
    168     if(res != RES_OK) goto error;
    169   }
    170 
    171 exit:
    172   *out_node = node;
    173   return res;
    174 error:
    175   if(node) solstice_node_ref_put(node);
    176   goto exit;
    177 }
    178 
    179 static res_T
    180 setup_tracking
    181   (struct solstice* solstice,
    182    struct sanim_tracking* tracking,
    183    const struct solparser_target* target)
    184 {
    185   struct solstice_node* anchor_node = NULL;
    186   struct str anchor_name;
    187   res_T res = RES_OK;
    188   ASSERT(solstice && tracking && target);
    189 
    190   str_init(solstice->allocator, &anchor_name);
    191 
    192   switch(target->type) {
    193     case SOLPARSER_TARGET_ANCHOR:
    194       tracking->policy = TRACKING_NODE_TARGET;
    195       res = get_anchor_node(solstice, target->data.anchor, &anchor_node);
    196       if(res != RES_OK) goto error;
    197       solstice_node_target_get_tracking(anchor_node, tracking);
    198       break;
    199     case SOLPARSER_TARGET_DIRECTION:
    200       tracking->policy = TRACKING_OUT_DIR;
    201       d3_set(tracking->data.out_dir.u, target->data.direction);
    202       break;
    203     case SOLPARSER_TARGET_POSITION:
    204       tracking->policy = TRACKING_POINT;
    205       d3_set(tracking->data.point.target, target->data.position);
    206       tracking->data.point.target_is_local = 0;
    207       break;
    208     case SOLPARSER_TARGET_SUN:
    209       tracking->policy = TRACKING_SUN;
    210       break;
    211     default: FATAL("Unreachable code.\n"); break;
    212   }
    213 
    214 exit:
    215   str_release(&anchor_name);
    216   return res;
    217 error:
    218   goto exit;
    219 }
    220 
    221 
    222 static struct solstice_node*
    223 create_x_pivot_node
    224   (struct solstice* solstice,
    225    const struct solparser_entity* entity)
    226 {
    227   double n[3];
    228   struct solstice_node* node = NULL;
    229   const struct solparser_x_pivot* parser_x_pivot = NULL;
    230   struct sanim_pivot anim_pivot = SANIM_PIVOT_NULL;
    231   struct sanim_tracking anim_tracking = SANIM_TRACKING_NULL;
    232   res_T res = RES_OK;
    233   ASSERT(solstice && entity);
    234 
    235   parser_x_pivot = solparser_get_x_pivot(solstice->parser, entity->data.x_pivot);
    236 
    237   anim_pivot.type = PIVOT_SINGLE_AXIS;
    238   d3_set(anim_pivot.data.pivot1.ref_normal, d3(n, 0, 0, 1));
    239   d3_set(anim_pivot.data.pivot1.ref_point, parser_x_pivot->ref_point);
    240 
    241   res = setup_tracking(solstice, &anim_tracking, &parser_x_pivot->target);
    242   if(res != RES_OK) goto error;
    243 
    244   res = solstice_node_pivot_create
    245     (solstice->allocator, &anim_pivot, &anim_tracking, &node);
    246   if(res != RES_OK) goto error;
    247 
    248   res = darray_nodes_push_back(&solstice->pivots, &node);
    249   if(res != RES_OK) goto error;
    250 
    251 exit:
    252   return node;
    253 error:
    254   if(node) {
    255     solstice_node_ref_put(node);
    256     node = NULL;
    257   }
    258   goto exit;
    259 }
    260 
    261 static struct solstice_node*
    262 create_zx_pivot_node
    263   (struct solstice* solstice,
    264    const struct solparser_entity* entity)
    265 {
    266   struct solstice_node* node = NULL;
    267   const struct solparser_zx_pivot* parser_zx_pivot = NULL;
    268   struct sanim_pivot anim_pivot = SANIM_PIVOT_NULL;
    269   struct sanim_tracking anim_tracking = SANIM_TRACKING_NULL;
    270   res_T res = RES_OK;
    271   ASSERT(solstice && entity);
    272 
    273   parser_zx_pivot = solparser_get_zx_pivot(solstice->parser, entity->data.zx_pivot);
    274 
    275   anim_pivot.type = PIVOT_TWO_AXIS;
    276   anim_pivot.data.pivot2.spacing = parser_zx_pivot->spacing;
    277   d3_set(anim_pivot.data.pivot2.ref_point, parser_zx_pivot->ref_point);
    278 
    279   res = setup_tracking(solstice, &anim_tracking, &parser_zx_pivot->target);
    280   if(res != RES_OK) goto error;
    281 
    282   res = solstice_node_pivot_create
    283     (solstice->allocator, &anim_pivot, &anim_tracking, &node);
    284   if(res != RES_OK) goto error;
    285 
    286   res = darray_nodes_push_back(&solstice->pivots, &node);
    287   if(res != RES_OK) goto error;
    288 
    289 exit:
    290   return node;
    291 error:
    292   if (node) {
    293     solstice_node_ref_put(node);
    294     node = NULL;
    295   }
    296   goto exit;
    297 }
    298 
    299 static struct solstice_node*
    300 create_node
    301   (struct solstice* solstice,
    302    const struct solparser_entity* entity,
    303    const struct str* name)
    304 {
    305   struct solstice_node* node = NULL;
    306   struct solstice_node* child = NULL;
    307   struct solstice_receiver* rcv = NULL;
    308   const char* str = NULL;
    309   size_t* pircv = NULL;
    310   struct str child_name;
    311   struct str anchor_name;
    312   double rotation[3];
    313   size_t i;
    314   res_T res = RES_OK;
    315   ASSERT(solstice && entity && name);
    316 
    317   str_init(solstice->allocator, &child_name);
    318   str_init(solstice->allocator, &anchor_name);
    319 
    320   /* Create the entity node */
    321   switch(entity->type) {
    322     case SOLPARSER_ENTITY_EMPTY:
    323       node = create_empty_node(solstice, entity);
    324       break;
    325     case SOLPARSER_ENTITY_GEOMETRY:
    326       node = create_geometry_node(solstice, entity);
    327       break;
    328     case SOLPARSER_ENTITY_X_PIVOT:
    329       node = create_x_pivot_node(solstice, entity);
    330       break;
    331     case SOLPARSER_ENTITY_ZX_PIVOT:
    332       node = create_zx_pivot_node(solstice, entity);
    333       break;
    334     default: FATAL("Unreachable code.\n"); break;
    335   }
    336   if(!node) {
    337     fprintf(stderr, "Could not setup the entity node.\n");
    338     goto error;
    339   }
    340 
    341   res = solstice_node_set_name(node, str_cget(name));
    342   if(res != RES_OK) {
    343     fprintf(stderr, "Could not setup the solstice node name.\n");
    344     goto error;
    345   }
    346 
    347   /* Setup the primary parameter for the geometry entity */
    348   if(entity->type == SOLPARSER_ENTITY_GEOMETRY) {
    349     res = solstice_node_geometry_set_primary(node, entity->primary);
    350     if(res != RES_OK) {
    351       fprintf(stderr,
    352         "Could not define the primary parameter of the entity `%s'.\n",
    353         str_cget(&entity->name));
    354       goto error;
    355     }
    356     if(entity->primary) {
    357       struct solstice_primary p;
    358       p.node = node;
    359       res = htable_primary_set(&solstice->primaries, name, &p);
    360       if(res != RES_OK) {
    361         fprintf(stderr, "Could not define the entity `%s' as primary.\n",
    362           str_cget(&entity->name));
    363         goto error;
    364       }
    365     }
    366   }
    367 
    368   /* Setup the entity receiver flags */
    369   str = str_cget(name);
    370   pircv = htable_receiver_find(&solstice->receivers, &str);
    371   if(pircv) {
    372     int side_mask, output;
    373     rcv = darray_receiver_data_get(&solstice->rcvs_list) + *pircv;
    374     ASSERT(rcv->node == NULL); /* Receiver is not attached to a node */
    375 
    376     side_mask = srcvl_side_to_ssol_mask(rcv->side);
    377     output = srcvl_per_prim_to_bool(rcv->per_primitive_output);
    378 
    379     res = solstice_node_geometry_set_receiver(node, side_mask, output);
    380     if(res != RES_OK) {
    381       fprintf(stderr, "Could not define the entity `%s' as a receiver.\n",
    382         str_cget(&entity->name));
    383       goto error;
    384     }
    385     rcv->node = node;
    386   }
    387 
    388   /* Setup the entity transform */
    389   rotation[0] = MDEG2RAD(entity->rotation[0]);
    390   rotation[1] = MDEG2RAD(entity->rotation[1]);
    391   rotation[2] = MDEG2RAD(entity->rotation[2]);
    392   solstice_node_set_translation(node, entity->translation);
    393   solstice_node_set_rotations(node, rotation);
    394 
    395   /* Register entity anchors */
    396   FOR_EACH(i, 0, solparser_entity_get_anchors_count(entity)) {
    397     struct solstice_node* tgt = NULL;
    398     struct solparser_anchor_id id;
    399     const struct solparser_anchor* anchor;
    400 
    401     id = solparser_entity_get_anchor(entity, i);
    402     anchor = solparser_get_anchor(solstice->parser, id);
    403 
    404     res = merge_name(&anchor_name, name, &anchor->name);
    405     if(res != RES_OK) goto error;
    406 
    407     res = get_anchor_node(solstice, id, &tgt);
    408     if(res != RES_OK) goto error;
    409 
    410     solstice_node_set_translation(tgt, anchor->position);
    411 
    412     res = solstice_node_add_child(node, tgt);
    413     if(res != RES_OK) goto error;
    414   }
    415 
    416   /* Setup children */
    417   FOR_EACH(i, 0, solparser_entity_get_children_count(entity)) {
    418     struct solparser_entity_id id;
    419     const struct solparser_entity* child_entity;
    420 
    421     id = solparser_entity_get_child(entity, i);
    422     child_entity = solparser_get_entity(solstice->parser, id);
    423 
    424     res = merge_name(&child_name, name, &child_entity->name);
    425     if(res != RES_OK) goto error;
    426 
    427     child = create_node(solstice, child_entity, &child_name);
    428     if(!child) goto error;
    429 
    430     res = solstice_node_add_child(node, child);
    431     if(res != RES_OK) goto error;
    432 
    433     solstice_node_ref_put(child);
    434     child = NULL;
    435   }
    436 
    437 exit:
    438   str_release(&child_name);
    439   str_release(&anchor_name);
    440   return node;
    441 error:
    442   if(child) solstice_node_ref_put(child);
    443   if(node) solstice_node_ref_put(node);
    444   node = NULL;
    445   goto exit;
    446 }
    447 
    448 /*******************************************************************************
    449  * Local functions
    450  ******************************************************************************/
    451 res_T
    452 solstice_setup_entities(struct solstice* solstice)
    453 {
    454   struct solparser_entity_iterator it, it_end;
    455   struct solstice_node* root = NULL;
    456   struct str name;
    457   const double dummy_sun_dir[3] = {0, 0, -1};
    458   res_T res = RES_OK;
    459   ASSERT(solstice);
    460 
    461   str_init(solstice->allocator, &name);
    462 
    463   /* (re) create the list of roots from entities */
    464   solparser_entity_iterator_begin(solstice->parser, &it);
    465   solparser_entity_iterator_end(solstice->parser, &it_end);
    466   while(!solparser_entity_iterator_eq(&it, &it_end)) {
    467     struct solparser_entity_id entity_id;
    468     const struct solparser_entity* entity;
    469 
    470     str_clear(&name);
    471     entity_id = solparser_entity_iterator_get(&it);
    472     entity = solparser_get_entity(solstice->parser, entity_id);
    473 
    474     res = str_copy(&name, &entity->name);
    475     if(res != RES_OK) {
    476       fprintf(stderr, "Could not initialise the absolute entity name.\n");
    477       goto error;
    478     }
    479 
    480     root = create_node(solstice, entity, &name);
    481     if(!root) {
    482       res = RES_BAD_ARG;
    483       goto error;
    484     }
    485 
    486     res = darray_nodes_push_back(&solstice->roots, &root);
    487     if(res != RES_OK) {
    488       fprintf(stderr, "Could not register a root entity.\n");
    489       goto error;
    490     }
    491 
    492     solparser_entity_iterator_next(&it);
    493     root = NULL;
    494   }
    495 
    496   /* Initialise the world space position of the geometries */
    497   res = solstice_update_entities(solstice, dummy_sun_dir);
    498   if(res != RES_OK) {
    499     fprintf(stderr, "Could not setup the initial position of the entities.\n");
    500     goto error;
    501   }
    502 
    503 exit:
    504   str_release(&name);
    505   return res;
    506 error:
    507   if(root) solstice_node_ref_put(root);
    508   goto exit;
    509 }
    510 
    511 res_T
    512 solstice_update_entities(struct solstice* solstice, const double sun_dir[3])
    513 {
    514   size_t i, n;
    515   res_T res = RES_OK;
    516   ASSERT(solstice && sun_dir);
    517 
    518   n = darray_nodes_size_get(&solstice->roots);
    519   FOR_EACH(i, 0, n) {
    520     struct solstice_node* node = darray_nodes_data_get(&solstice->roots)[i];
    521 
    522     res = sanim_node_visit_tree
    523       (&node->anim, sun_dir, solstice, update_instance_transform);
    524     if(res != RES_OK) {
    525       fprintf(stderr,
    526         "Could not update the transformation of the entity geometries.\n");
    527       goto error;
    528     }
    529   }
    530 
    531 exit:
    532   return res;
    533 error:
    534   goto exit;
    535 }
    536