solstice

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

solparser_sun.c (10448B)


      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 #define _POSIX_C_SOURCE 200112L /* nextafter support */
     18 
     19 #include "solparser_c.h"
     20 #include <math.h> /* nextafter */
     21 
     22 /*******************************************************************************
     23  * Helper functions
     24  ******************************************************************************/
     25 static res_T
     26 parse_buie
     27   (struct solparser* parser,
     28    yaml_document_t* doc,
     29    const yaml_node_t* buie,
     30    struct solparser_sun_buie* sun)
     31 {
     32   enum { CSR };
     33   intptr_t i, n;
     34   int mask = 0; /* Register the parsed attributes */
     35   res_T res = RES_OK;
     36   ASSERT(doc && buie && sun);
     37 
     38   if(buie->type != YAML_MAPPING_NODE) {
     39     log_err(parser, buie,
     40       "expect a buie definition of the sun radial angular distribution.\n");
     41     res = RES_BAD_ARG;
     42     goto error;
     43   }
     44 
     45   n = buie->data.mapping.pairs.top - buie->data.mapping.pairs.start;
     46   FOR_EACH(i, 0, n) {
     47     yaml_node_t* key;
     48     yaml_node_t* val;
     49 
     50     key = yaml_document_get_node(doc, buie->data.mapping.pairs.start[i].key);
     51     val = yaml_document_get_node(doc, buie->data.mapping.pairs.start[i].value);
     52     if(key->type != YAML_SCALAR_NODE) {
     53       log_err(parser, key, "expect a buie parameter.\n");
     54       res = RES_BAD_ARG;
     55       goto error;
     56     }
     57 
     58     if(!strcmp((char*)key->data.scalar.value, "csr")) {
     59       if(mask & BIT(CSR)) {
     60         log_err(parser, key, "the buie `csr' is already defined.\n");
     61         res = RES_BAD_ARG;
     62         goto error;
     63       }
     64       mask |= BIT(CSR);
     65       res = parse_real(parser, val, 1e-6, 0.849, &sun->csr);
     66     } else {
     67       log_err(parser, key, "unknown buie parameter `%s'.\n",
     68         key->data.scalar.value);
     69       res = RES_BAD_ARG;
     70       goto error;
     71     }
     72     if(res != RES_OK) {
     73       log_node(parser, key);
     74       goto error;
     75     }
     76   }
     77 
     78   if(!(mask & BIT(CSR))) {
     79     log_err(parser, buie, "the buie csr parameter is missing.\n");
     80     res = RES_BAD_ARG;
     81     goto error;
     82   }
     83 
     84 exit:
     85   return res;
     86 error:
     87   goto exit;
     88 }
     89 
     90 static res_T
     91 parse_pillbox
     92   (struct solparser* parser,
     93    yaml_document_t* doc,
     94    const yaml_node_t* pillbox,
     95    struct solparser_sun_pillbox* sun)
     96 {
     97   enum { HALF_ANGLE };
     98   intptr_t i, n;
     99   int mask = 0; /* Register the parsed attributes */
    100   res_T res = RES_OK;
    101   ASSERT(doc && pillbox && sun);
    102 
    103   if(pillbox->type != YAML_MAPPING_NODE) {
    104     log_err(parser, pillbox,
    105       "expect a pillbox definition of the sun radial angular distribution.\n");
    106     res = RES_BAD_ARG;
    107     goto error;
    108   }
    109 
    110   n = pillbox->data.mapping.pairs.top - pillbox->data.mapping.pairs.start;
    111   FOR_EACH(i, 0, n) {
    112     yaml_node_t* key;
    113     yaml_node_t* val;
    114 
    115     key = yaml_document_get_node(doc, pillbox->data.mapping.pairs.start[i].key);
    116     val = yaml_document_get_node(doc, pillbox->data.mapping.pairs.start[i].value);
    117     if(key->type != YAML_SCALAR_NODE) {
    118       log_err(parser, key, "expect a pillbox parameter.\n");
    119       res = RES_BAD_ARG;
    120       goto error;
    121     }
    122     if(!strcmp((char*)key->data.scalar.value, "half_angle")) {
    123       if(mask & BIT(HALF_ANGLE)) {
    124         log_err(parser, key, "the pillbox `half_angle' is already defined.\n");
    125         res = RES_BAD_ARG;
    126         goto error;
    127       }
    128       mask |= BIT(HALF_ANGLE);
    129       res = parse_real(parser, val, nextafter(0, 1), 90, &sun->half_angle);
    130     } else {
    131       log_err(parser, pillbox, "unknown pillbox parameter `%s'.\n",
    132         key->data.scalar.value);
    133       res = RES_BAD_ARG;
    134       goto error;
    135     }
    136     if(res != RES_OK) {
    137       log_node(parser, key);
    138       goto error;
    139     }
    140   }
    141 
    142   if(!(mask & BIT(HALF_ANGLE))) {
    143     log_err(parser, pillbox, "the pillbox half_angle parameter is missing.\n");
    144     res = RES_BAD_ARG;
    145     goto error;
    146   }
    147 
    148 exit:
    149   return res;
    150 error:
    151   goto exit;
    152 }
    153 
    154 static res_T
    155 parse_gaussian
    156   (struct solparser* parser,
    157    yaml_document_t* doc,
    158    const yaml_node_t* gaussian,
    159    struct solparser_sun_gaussian* sun)
    160 {
    161   enum { STD_DEV };
    162   intptr_t i, n;
    163   int mask = 0; /* Register the parsed attributes */
    164   res_T res = RES_OK;
    165   ASSERT(doc && gaussian && sun);
    166 
    167   if(gaussian->type != YAML_MAPPING_NODE) {
    168     log_err(parser, gaussian,
    169       "expect a gaussian definition of the sun radial angular distribution.\n");
    170     res = RES_BAD_ARG;
    171     goto error;
    172   }
    173 
    174   n = gaussian->data.mapping.pairs.top - gaussian->data.mapping.pairs.start;
    175   FOR_EACH(i, 0, n) {
    176     yaml_node_t* key;
    177     yaml_node_t* val;
    178 
    179     key = yaml_document_get_node(doc, gaussian->data.mapping.pairs.start[i].key);
    180     val = yaml_document_get_node(doc, gaussian->data.mapping.pairs.start[i].value);
    181     if(key->type != YAML_SCALAR_NODE) {
    182       log_err(parser, key, "expect a gaussian parameter.\n");
    183       res = RES_BAD_ARG;
    184       goto error;
    185     }
    186     if(!strcmp((char*)key->data.scalar.value, "std_dev")) {
    187       if(mask & BIT(STD_DEV)) {
    188         log_err(parser, key, "the gaussian `std_dev' is already defined.\n");
    189         res = RES_BAD_ARG;
    190         goto error;
    191       }
    192       mask |= BIT(STD_DEV);
    193       res = parse_real(parser, val, nextafter(0, 1), 90, &sun->std_dev);
    194     } else {
    195       log_err(parser, gaussian, "unknown gaussian parameter `%s'.\n",
    196         key->data.scalar.value);
    197       res = RES_BAD_ARG;
    198       goto error;
    199     }
    200     if(res != RES_OK) {
    201       log_node(parser, key);
    202       goto error;
    203     }
    204   }
    205 
    206   if(!(mask & BIT(STD_DEV))) {
    207     log_err(parser, gaussian, "the gaussian std_dev parameter is missing.\n");
    208     res = RES_BAD_ARG;
    209     goto error;
    210   }
    211 
    212 exit:
    213   return res;
    214 error:
    215   goto exit;
    216 }
    217 
    218 /*******************************************************************************
    219  * Local functions
    220  ******************************************************************************/
    221 res_T
    222 parse_sun
    223   (struct solparser* parser,
    224    yaml_document_t* doc,
    225    const yaml_node_t* sun,
    226    struct solparser_sun** out_solsun)
    227 {
    228   enum { DNI, RADIAL_ANGULAR_DISTRIB, SPECTRUM };
    229   struct solparser_sun* solsun = NULL;
    230   intptr_t i, n;
    231   int mask = 0; /* Register the parsed attributes */
    232   res_T res = RES_OK;
    233   ASSERT(doc && sun && out_solsun);
    234 
    235   if(sun == parser->sun_key) {
    236     solsun = &parser->sun;
    237     goto exit;
    238   } else if(parser->sun_key != 0) {
    239     log_err(parser, sun,
    240       "a sun is already defined. Previous definition is here %lu:%lu.\n",
    241       (unsigned long)parser->sun_key->start_mark.line+1,
    242       (unsigned long)parser->sun_key->start_mark.column+1);
    243     res = RES_BAD_ARG;
    244     goto error;
    245   } else {
    246     solsun = &parser->sun;
    247     parser->sun_key = sun;
    248     solsun->radang_distrib_type = SOLPARSER_SUN_RADANG_DISTRIB_DIRECTIONAL;
    249   }
    250 
    251   if(sun->type != YAML_MAPPING_NODE) {
    252     log_err(parser, sun, "expect a sun definition.\n");
    253     res = RES_BAD_ARG;
    254     goto error;
    255   }
    256 
    257   n = sun->data.mapping.pairs.top - sun->data.mapping.pairs.start;
    258   FOR_EACH(i, 0, n) {
    259     yaml_node_t* key;
    260     yaml_node_t* val;
    261 
    262     key = yaml_document_get_node(doc, sun->data.mapping.pairs.start[i].key);
    263     val = yaml_document_get_node(doc, sun->data.mapping.pairs.start[i].value);
    264     if(key->type != YAML_SCALAR_NODE) {
    265       log_err(parser, key, "expect sun parameters.\n");
    266       res = RES_BAD_ARG;
    267       goto error;
    268     }
    269     #define SETUP_MASK(Flag, Name) {                                           \
    270       if(mask & BIT(Flag)) {                                                   \
    271         log_err(parser, key, "the sun "Name" is already defined.\n");          \
    272         res = RES_BAD_ARG;                                                     \
    273         goto error;                                                            \
    274       }                                                                        \
    275       mask |= BIT(Flag);                                                       \
    276     } (void)0
    277     if(!strcmp((char*)key->data.scalar.value, "dni")) {
    278       SETUP_MASK(DNI, "dni");
    279       res = parse_real(parser, val, nextafter(0, 1), DBL_MAX, &solsun->dni);
    280     } else if(!strcmp((char*)key->data.scalar.value, "buie")) {
    281       SETUP_MASK(RADIAL_ANGULAR_DISTRIB, "radial angular distribution");
    282       solsun->radang_distrib_type = SOLPARSER_SUN_RADANG_DISTRIB_BUIE;
    283       res = parse_buie(parser, doc, val, &solsun->radang_distrib.buie);
    284     } else if(!strcmp((char*)key->data.scalar.value, "pillbox")) {
    285       SETUP_MASK(RADIAL_ANGULAR_DISTRIB, "radial angular distribution");
    286       solsun->radang_distrib_type = SOLPARSER_SUN_RADANG_DISTRIB_PILLBOX;
    287       res = parse_pillbox(parser, doc, val, &solsun->radang_distrib.pillbox);
    288     } else if(!strcmp((char*)key->data.scalar.value, "gaussian")) {
    289       SETUP_MASK(RADIAL_ANGULAR_DISTRIB, "radial angular distribution");
    290       solsun->radang_distrib_type = SOLPARSER_SUN_RADANG_DISTRIB_GAUSSIAN;
    291       res = parse_gaussian(parser, doc, val, &solsun->radang_distrib.gaussian);
    292     } else if(!strcmp((char*)key->data.scalar.value, "spectrum")) {
    293       SETUP_MASK(SPECTRUM, "spectrum");
    294       res = parse_spectrum(parser, doc, val, 0, DBL_MAX, &solsun->spectrum);
    295     } else {
    296       log_err(parser, key, "unknown sun parameter `%s'.\n",
    297         key->data.scalar.value);
    298       res = RES_BAD_ARG;
    299       goto error;
    300     }
    301     if(res != RES_OK) {
    302       log_node(parser, key);
    303       goto error;
    304     }
    305     #undef SETUP_MASK
    306   }
    307 
    308   #define CHECK_PARAM(Flag, Name)                                              \
    309     if(!(mask & BIT(Flag))) {                                                  \
    310       log_err(parser, sun, "the sun "Name" is missing.\n");                    \
    311       res = RES_BAD_ARG;                                                       \
    312       goto error;                                                              \
    313     } (void)0
    314   CHECK_PARAM(DNI, "dni");
    315   #undef CHECK_PARAM
    316 
    317 exit:
    318   *out_solsun = solsun;
    319   return res;
    320 error:
    321   if(solsun) {
    322     solparser_sun_clear(solsun);
    323     solsun = NULL;
    324     parser->sun_key = 0;
    325   }
    326   goto exit;
    327 }
    328 
    329