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_spectrum.c (6777B)


      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 
     21 /*******************************************************************************
     22  * Helper functions
     23  ******************************************************************************/
     24 static int
     25 cmp_spectrum_data(const void* op0, const void* op1)
     26 {
     27   const struct solparser_spectrum_data* a = op0;
     28   const struct solparser_spectrum_data* b = op1;
     29   ASSERT(a && b);
     30   if(a->wavelength < b->wavelength) return -1;
     31   if(a->wavelength > b->wavelength) return 1;
     32   return 0;
     33 }
     34 
     35 static res_T
     36 parse_spectrum_data
     37   (struct solparser* parser,
     38    yaml_document_t* doc,
     39    const yaml_node_t* sdata,
     40    const double lower_bound,
     41    const double upper_bound,
     42    struct solparser_spectrum_data* spectrum_data)
     43 {
     44   enum { DATA, WAVELENGTH };
     45   intptr_t i, n;
     46   int mask = 0; /* Register the parsed attributes */
     47   res_T res = RES_OK;
     48   ASSERT(doc && sdata && spectrum_data);
     49   ASSERT(lower_bound <= upper_bound);
     50 
     51   if(sdata->type != YAML_MAPPING_NODE) {
     52     log_err(parser, sdata, "expect the definition of a spectrum data.\n");
     53     res = RES_BAD_ARG;
     54     goto error;
     55   }
     56 
     57   n = sdata->data.mapping.pairs.top - sdata->data.mapping.pairs.start;
     58   FOR_EACH(i, 0, n) {
     59     yaml_node_t* key;
     60     yaml_node_t* val;
     61 
     62     key = yaml_document_get_node(doc, sdata->data.mapping.pairs.start[i].key);
     63     val = yaml_document_get_node(doc, sdata->data.mapping.pairs.start[i].value);
     64     if(key->type != YAML_SCALAR_NODE) {
     65       log_err(parser, key, "expect a spectrum data parameter.\n");
     66       res = RES_BAD_ARG;
     67       goto error;
     68     }
     69 
     70     #define SETUP_MASK(Flag, Name) {                                           \
     71       if(mask & BIT(Flag)) {                                                   \
     72         log_err(parser, key,                                                   \
     73           "the `"Name"' of the spectrum data is already defined.\n");          \
     74         res = RES_BAD_ARG;                                                     \
     75         goto error;                                                            \
     76       }                                                                        \
     77       mask |= BIT(Flag);                                                       \
     78     } (void)0
     79     if(!strcmp((char*)key->data.scalar.value, "data")) {
     80       SETUP_MASK(DATA, "data");
     81       res = parse_real
     82         (parser, val, lower_bound, upper_bound, &spectrum_data->data);
     83     } else if(!strcmp((char*)key->data.scalar.value, "wavelength")) {
     84       SETUP_MASK(WAVELENGTH, "wavelength");
     85       res = parse_real(parser, val, nextafter(0, DBL_MAX), DBL_MAX,
     86         &spectrum_data->wavelength);
     87     } else {
     88       log_err(parser, key, "unknown spectrum data parameter `%s'.\n",
     89         key->data.scalar.value);
     90       res = RES_BAD_ARG;
     91       goto error;
     92     }
     93     if(res != RES_OK) {
     94       log_node(parser, key);
     95       goto error;
     96     }
     97     #undef SETUP_MASK
     98   }
     99 
    100   #define CHECK_PARAM(Flag, Name)                                              \
    101     if(!(mask & BIT(Flag))) {                                                  \
    102       log_err(parser, sdata,"the "Name" of the spectrum data is missing.\n");  \
    103       res = RES_BAD_ARG;                                                       \
    104       goto error;                                                              \
    105     } (void)0
    106   CHECK_PARAM(DATA, "data");
    107   CHECK_PARAM(WAVELENGTH, "wavelength");
    108   #undef CHECK_PARAM
    109 
    110 exit:
    111   return res;
    112 error:
    113   goto exit;
    114 }
    115 
    116 /*******************************************************************************
    117  * Local functions
    118  ******************************************************************************/
    119 res_T
    120 parse_spectrum
    121   (struct solparser* parser,
    122    yaml_document_t* doc,
    123    const yaml_node_t* spectrum,
    124    const double lower_bound,
    125    const double upper_bound,
    126    struct solparser_spectrum_id* out_ispectrum)
    127 {
    128   struct solparser_spectrum* spec = NULL;
    129   size_t ispec = SIZE_MAX;
    130   intptr_t i, n;
    131   res_T res = RES_OK;
    132   ASSERT(doc && spectrum && out_ispectrum);
    133   ASSERT(lower_bound <= upper_bound);
    134 
    135   if(spectrum->type != YAML_SEQUENCE_NODE) {
    136     log_err(parser, spectrum, "expect a list of spectrum data.\n");
    137     res = RES_BAD_ARG;
    138     goto error;
    139   }
    140 
    141   /* Allocate the spectrum */
    142   ispec = darray_spectrum_size_get(&parser->spectra);
    143   res = darray_spectrum_resize(&parser->spectra, ispec + 1);
    144   if(res != RES_OK) {
    145     log_err(parser, spectrum, "could not allocate the spectrum.\n");
    146     goto error;
    147   }
    148   spec = darray_spectrum_data_get(&parser->spectra) + ispec;
    149 
    150   n = spectrum->data.sequence.items.top - spectrum->data.sequence.items.start;
    151   res = darray_spectrum_data_resize(&spec->data, (size_t)n);
    152   if(res != RES_OK) {
    153     log_err(parser, spectrum, "could not allocate the list of spectrum data.\n");
    154     goto error;
    155   }
    156 
    157   FOR_EACH(i, 0, n) {
    158     yaml_node_t* sdata;
    159     struct solparser_spectrum_data* spectrum_data;
    160 
    161     sdata = yaml_document_get_node(doc, spectrum->data.sequence.items.start[i]);
    162     spectrum_data = darray_spectrum_data_data_get(&spec->data) + i;
    163     res = parse_spectrum_data
    164       (parser, doc, sdata, lower_bound, upper_bound, spectrum_data);
    165     if(res != RES_OK) goto error;
    166   }
    167 
    168   if(n == 1) goto exit;
    169 
    170   qsort
    171     (darray_spectrum_data_data_get(&spec->data),
    172      darray_spectrum_data_size_get(&spec->data),
    173      sizeof(struct solparser_spectrum_data),
    174      cmp_spectrum_data);
    175 
    176   FOR_EACH(i, 1, n) {
    177     const struct solparser_spectrum_data* a;
    178     const struct solparser_spectrum_data* b;
    179     a = darray_spectrum_data_cdata_get(&spec->data) + i - 1;
    180     b = darray_spectrum_data_cdata_get(&spec->data) + i;
    181     ASSERT(cmp_spectrum_data(a, b) <= 0);
    182     if(a->wavelength == b->wavelength) {
    183       log_err(parser, spectrum,
    184         "duplicated spectrum entry for the wavelength %g\n", a->wavelength);
    185       res = RES_BAD_ARG;
    186       goto error;
    187     }
    188   }
    189 
    190 exit:
    191   out_ispectrum->i = ispec;
    192   return res;
    193 error:
    194   if(spec) {
    195     darray_spectrum_pop_back(&parser->spectra);
    196     ispec = SIZE_MAX;
    197   }
    198   goto exit;
    199 }
    200