schiff_optical_properties.c (6440B)
1 /* Copyright (C) 2015, 2016, 2026 Centre National de la Recherche Scientifique 2 * Copyright (C) 2026 Clermont Auvergne INP 3 * Copyright (C) 2026 Institut Mines Télécom Albi-Carmaux 4 * Copyright (C) 2017, 2019-2021, 2026 |Méso|Star> (contact@meso-star.com) 5 * Copyright (C) 2026 Université de Lorraine 6 * Copyright (C) 2026 Université de Toulouse 7 * 8 * This program is free software: you can redistribute it and/or modify 9 * it under the terms of the GNU General Public License as published by 10 * the Free Software Foundation, either version 3 of the License, or 11 * (at your option) any later version. 12 * 13 * This program is distributed in the hope that it will be useful, 14 * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 * GNU General Public License for more details. 17 * 18 * You should have received a copy of the GNU General Public License 19 * along with this program. If not, see <http://www.gnu.org/licenses/>. */ 20 21 #include "schiff_optical_properties.h" 22 #include "schiff_streamline.h" 23 24 #include <rsys/algorithm.h> 25 #include <rsys/cstr.h> 26 #include <rsys/stretchy_array.h> 27 28 #include <star/sschiff.h> 29 30 /******************************************************************************* 31 * Helper functions 32 ******************************************************************************/ 33 static res_T 34 parse_optical_properties 35 (struct schiff_optical_properties* out_props, 36 const char* filename, 37 const size_t iline, 38 const char* str) 39 { 40 char buf[128]; 41 char* tk; 42 int i = 0; 43 double props[4]; 44 res_T res = RES_OK; 45 ASSERT(filename && str && out_props); 46 47 if(strlen(str) >= sizeof(buf) - 1/*NULL char*/) { 48 fprintf(stderr, 49 "%s:%lu: not enough memory: cannot parse the properties `%s'.\n", 50 filename, (unsigned long)iline, str); 51 return RES_MEM_ERR; 52 } 53 54 strncpy(buf, str, sizeof(buf)); 55 for(i=0, tk=strtok(buf, " \t"); tk && i < 4; ++i, tk=strtok(NULL, " \t")) { 56 res = cstr_to_double(tk, props + i); 57 if(res != RES_OK) { 58 fprintf(stderr, 59 "%s:%lu: cannot read the optical property `%s'.\n", 60 filename, (unsigned long)iline, tk); 61 return res; 62 } 63 } 64 if(i < 4) { 65 fprintf(stderr, 66 "%s:%lu: not enough optical properties.\n" 67 "Expect 4 parameters while %d is submitted - `%s'.\n", 68 filename, (unsigned long)iline, i, str); 69 return RES_BAD_ARG; 70 } 71 72 out_props->W = props[0]; 73 out_props->Ne = props[3]; 74 out_props->Nr = props[1] / out_props->Ne; /* Absolute to relative */ 75 out_props->Kr = props[2] / out_props->Ne; /* Absolute to relative */ 76 if(!schiff_optical_properties_check(out_props)) { 77 fprintf(stderr, "%s:%lu: invalid optical properties `%s'.\n", 78 filename, (unsigned long)iline, str); 79 return RES_BAD_ARG; 80 } 81 return RES_OK; 82 } 83 84 static FINLINE int 85 cmp_properties(const void* op0, const void* op1) 86 { 87 const struct schiff_optical_properties* prop0 = op0; 88 const struct schiff_optical_properties* prop1 = op1; 89 return prop0->W < prop1->W ? -1 : (prop0->W > prop1->W ? 1 : 0); 90 } 91 92 static FINLINE int 93 cmp_wavelength_to_properties(const void* wavelength, const void* op) 94 { 95 const double* W = wavelength; 96 const struct schiff_optical_properties* prop = op; 97 return *W < prop->W ? -1 : (*W > prop->W ? 1 : 0); 98 } 99 100 /******************************************************************************* 101 * Local function 102 ******************************************************************************/ 103 res_T 104 schiff_optical_properties_load 105 (struct schiff_optical_properties** props, const char* filename) 106 { 107 FILE* fp = NULL; 108 res_T res = RES_OK; 109 ASSERT(filename && props); 110 111 fp = fopen(filename, "r"); 112 if(!fp) { 113 fprintf(stderr, "Cannot open the file of optical properties `%s'.\n", 114 filename); 115 res = RES_IO_ERR; 116 goto error; 117 } 118 119 res = schiff_optical_properties_load_stream(props, fp, filename); 120 if(res != RES_OK) goto error; 121 122 exit: 123 if(fp) fclose(fp); 124 return res; 125 error: 126 goto exit; 127 } 128 129 res_T 130 schiff_optical_properties_load_stream 131 (struct schiff_optical_properties** out_props, 132 FILE* stream, 133 const char* stream_name) 134 { 135 struct schiff_optical_properties* props = NULL; 136 struct schiff_streamline streamline; 137 size_t iline; 138 char* line; 139 res_T res = RES_OK; 140 ASSERT(out_props && stream && stream_name); 141 142 schiff_streamline_init(&streamline); 143 144 for(iline=1; 145 (res = schiff_streamline_read(&streamline, stream, &line)) != RES_EOF; 146 ++iline) { 147 struct schiff_optical_properties tmp_props; 148 149 if(strcspn(line, "# \t") == 0) /* Empty line */ 150 continue; 151 152 /* Read optical properties */ 153 line = strtok(line, "#"); 154 res = parse_optical_properties(&tmp_props, stream_name, iline, line); 155 if(res == RES_OK) { /* *NO* error */ 156 sa_push(props, tmp_props); 157 } 158 } 159 160 /* Sort the optical properties in ascending order with respect to the 161 * wavelength */ 162 qsort(props, sa_size(props), 163 sizeof(struct schiff_optical_properties), cmp_properties); 164 165 *out_props = props; 166 schiff_streamline_release(&streamline); 167 return RES_OK; 168 } 169 170 void 171 schiff_optical_properties_fetch 172 (struct schiff_optical_properties* properties, /* Stetchy array */ 173 const double wavelength, 174 struct sschiff_material_properties* props) 175 { 176 const size_t nproperties = sa_size(properties); 177 struct schiff_optical_properties* find; 178 double Ne, Kr, Nr; 179 ASSERT(properties && props && wavelength > 0.0); 180 181 /* Assume that properties are sorted in ascending order with respect to the 182 * wavelength. */ 183 find = search_lower_bound(&wavelength, properties, nproperties, 184 sizeof(struct schiff_optical_properties), cmp_wavelength_to_properties); 185 ASSERT(!find || find->W >= wavelength); 186 187 if(!find) /* Clamp to upper wavelength */ 188 find = properties + (nproperties - 1); 189 190 if(find == properties || find == (properties + (nproperties - 1)) 191 || eq_eps(find->W, wavelength, 1.e-12)) { 192 Ne = find[0].Ne; 193 Kr = find[0].Kr; 194 Nr = find[0].Nr; 195 } else { /* Linear interpolation of optical properties */ 196 const double d = find[0].W - find[-1].W; 197 const double u = (wavelength - find[-1].W) / d; 198 const double v = 1.0 - u; 199 Ne = u * find[0].Ne + v * find[-1].Ne; 200 Kr = u * find[0].Kr + v * find[-1].Kr; 201 Nr = u * find[0].Nr + v * find[-1].Nr; 202 } 203 204 props->medium_refractive_index = Ne; 205 props->relative_imaginary_refractive_index = Kr; 206 props->relative_real_refractive_index = Nr; 207 } 208