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