ssol_sun.c (6845B)
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 "ssol.h" 18 #include "ssol_device_c.h" 19 #include "ssol_sun_c.h" 20 #include "ssol_ranst_sun_dir.h" 21 #include "ssol_ranst_sun_wl.h" 22 #include "ssol_spectrum_c.h" 23 24 #include <rsys/rsys.h> 25 #include <rsys/mem_allocator.h> 26 #include <rsys/ref_count.h> 27 #include <rsys/math.h> 28 #include <rsys/double3.h> 29 30 #include <string.h> 31 32 /******************************************************************************* 33 * Helper functions 34 ******************************************************************************/ 35 static void 36 sun_release(ref_T* ref) 37 { 38 struct ssol_device* dev; 39 struct ssol_sun* sun = CONTAINER_OF(ref, struct ssol_sun, ref); 40 ASSERT(ref); 41 dev = sun->dev; 42 ASSERT(dev && dev->allocator); 43 if(sun->spectrum) SSOL(spectrum_ref_put(sun->spectrum)); 44 MEM_RM(dev->allocator, sun); 45 SSOL(device_ref_put(dev)); 46 } 47 48 static res_T 49 sun_create 50 (struct ssol_device* dev, struct ssol_sun** out_sun, enum sun_type type) 51 { 52 struct ssol_sun* sun = NULL; 53 res_T res = RES_OK; 54 if(!dev || !out_sun || type >= SUN_TYPES_COUNT__) { 55 return RES_BAD_ARG; 56 } 57 58 sun = (struct ssol_sun*)MEM_CALLOC 59 (dev->allocator, 1, sizeof(struct ssol_sun)); 60 if(!sun) { 61 res = RES_MEM_ERR; 62 goto error; 63 } 64 65 SSOL(device_ref_get(dev)); 66 sun->dev = dev; 67 sun->type = type; 68 ref_init(&sun->ref); 69 70 exit: 71 if(out_sun) *out_sun = sun; 72 return res; 73 error: 74 if(sun) { 75 SSOL(sun_ref_put(sun)); 76 sun = NULL; 77 } 78 goto exit; 79 } 80 81 /******************************************************************************* 82 * Exported ssol_image functions 83 ******************************************************************************/ 84 res_T 85 ssol_sun_create_directional(struct ssol_device* dev, struct ssol_sun** out_sun) 86 { 87 return sun_create(dev, out_sun, SUN_DIRECTIONAL); 88 } 89 90 res_T 91 ssol_sun_create_pillbox(struct ssol_device* dev, struct ssol_sun** out_sun) 92 { 93 return sun_create(dev, out_sun, SUN_PILLBOX); 94 } 95 96 res_T 97 ssol_sun_create_gaussian(struct ssol_device* dev, struct ssol_sun** out_sun) 98 { 99 return sun_create(dev, out_sun, SUN_GAUSSIAN); 100 } 101 102 res_T 103 ssol_sun_create_buie 104 (struct ssol_device* dev, struct ssol_sun** out_sun) 105 { 106 return sun_create(dev, out_sun, SUN_BUIE); 107 } 108 109 res_T 110 ssol_sun_ref_get(struct ssol_sun* sun) 111 { 112 if(!sun) 113 return RES_BAD_ARG; 114 ref_get(&sun->ref); 115 return RES_OK; 116 } 117 118 res_T 119 ssol_sun_ref_put(struct ssol_sun* sun) 120 { 121 if(!sun) 122 return RES_BAD_ARG; 123 ref_put(&sun->ref, sun_release); 124 return RES_OK; 125 } 126 127 res_T 128 ssol_sun_set_direction(struct ssol_sun* sun, const double direction[3]) 129 { 130 if(!sun || !direction) 131 return RES_BAD_ARG; 132 if(0 == d3_normalize(sun->direction, direction)) 133 /* zero vector */ 134 return RES_BAD_ARG; 135 return RES_OK; 136 } 137 138 res_T 139 ssol_sun_get_direction(const struct ssol_sun* sun, double direction[3]) 140 { 141 if(!sun || !direction) 142 return RES_BAD_ARG; 143 d3_set(direction, sun->direction); 144 return RES_OK; 145 } 146 147 res_T 148 ssol_sun_set_dni(struct ssol_sun* sun, const double dni) 149 { 150 if(!sun || dni <= 0) 151 return RES_BAD_ARG; 152 sun->dni = dni; 153 return RES_OK; 154 } 155 156 res_T 157 ssol_sun_get_dni(const struct ssol_sun* sun, double* dni) 158 { 159 if(!sun || !dni) 160 return RES_BAD_ARG; 161 *dni = sun->dni; 162 return RES_OK; 163 } 164 165 res_T 166 ssol_sun_set_spectrum(struct ssol_sun* sun, struct ssol_spectrum* spectrum) 167 { 168 if(!sun || !spectrum) 169 return RES_BAD_ARG; 170 if(spectrum == sun->spectrum) /* no change */ 171 return RES_OK; 172 if(sun->spectrum) 173 SSOL(spectrum_ref_put(sun->spectrum)); 174 SSOL(spectrum_ref_get(spectrum)); 175 sun->spectrum = spectrum; 176 return RES_OK; 177 } 178 179 res_T 180 ssol_sun_pillbox_set_half_angle(struct ssol_sun* sun, const double half_angle) 181 { 182 if(!sun || half_angle <= 0 || half_angle > PI * 0.5 || sun->type != SUN_PILLBOX) 183 return RES_BAD_ARG; 184 sun->data.pillbox.half_angle = half_angle; 185 return RES_OK; 186 } 187 188 res_T 189 ssol_sun_gaussian_set_std_dev(struct ssol_sun* sun, const double std_dev) 190 { 191 if(!sun || std_dev <= 0 || sun->type != SUN_GAUSSIAN) 192 return RES_BAD_ARG; 193 sun->data.gaussian.std_dev = std_dev; 194 return RES_OK; 195 } 196 197 res_T 198 ssol_sun_set_buie_param 199 (struct ssol_sun* sun, 200 const double ratio) 201 { 202 if(!sun 203 || ratio <= 0 204 || ratio >= 1 205 || sun->type != SUN_BUIE) 206 return RES_BAD_ARG; 207 sun->data.csr.ratio = ratio; 208 return RES_OK; 209 } 210 211 /******************************************************************************* 212 * Local function 213 ******************************************************************************/ 214 res_T 215 sun_create_direction_distribution 216 (struct ssol_sun* sun, struct ranst_sun_dir** out_ran_dir) 217 { 218 struct ranst_sun_dir* ran_dir = NULL; 219 res_T res = RES_OK; 220 ASSERT(sun && out_ran_dir); 221 222 res = ranst_sun_dir_create(sun->dev->allocator, &ran_dir); 223 if(res != RES_OK) goto error; 224 switch(sun->type) { 225 case SUN_DIRECTIONAL: 226 res = ranst_sun_dir_dirac_setup(ran_dir, sun->direction); 227 break; 228 case SUN_PILLBOX: 229 res = ranst_sun_dir_pillbox_setup 230 (ran_dir, sun->data.pillbox.half_angle, sun->direction); 231 break; 232 case SUN_GAUSSIAN: 233 res = ranst_sun_dir_gaussian_setup 234 (ran_dir, sun->data.gaussian.std_dev, sun->direction); 235 break; 236 case SUN_BUIE: 237 res = ranst_sun_dir_buie_setup 238 (ran_dir, sun->data.csr.ratio, sun->direction); 239 break; 240 default: FATAL("Unreachable code\n"); break; 241 } 242 exit: 243 *out_ran_dir = ran_dir; 244 return res; 245 error: 246 if(ran_dir) { 247 CHK(ranst_sun_dir_ref_put(ran_dir) == RES_OK); 248 ran_dir = NULL; 249 } 250 goto exit; 251 } 252 253 res_T 254 sun_create_wavelength_distribution 255 (struct ssol_sun* sun, struct ranst_sun_wl** out_ran_wl) 256 { 257 struct ranst_sun_wl* ran_wl = NULL; 258 res_T res = RES_OK; 259 ASSERT(sun && out_ran_wl); 260 261 res = ranst_sun_wl_create(sun->dev->allocator, &ran_wl); 262 if(res != RES_OK) goto error; 263 264 res = ranst_sun_wl_setup(ran_wl, 265 darray_double_cdata_get(&sun->spectrum->wavelengths), 266 darray_double_cdata_get(&sun->spectrum->intensities), 267 darray_double_size_get(&sun->spectrum->wavelengths)); 268 if(res != RES_OK) goto error; 269 270 exit: 271 *out_ran_wl = ran_wl; 272 return res; 273 error: 274 if(ran_wl) { 275 CHK(ranst_sun_wl_ref_put(ran_wl) == RES_OK); 276 ran_wl = NULL; 277 } 278 goto exit; 279 }