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