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