1 #define _POSIX_C_SOURCE 200809L // for getline()
7 #include "qpms_error.h"
9 #define SQ(x) ((x)*(x))
11 qpms_permittivity_interpolator_t
*qpms_permittivity_interpolator_create(
12 const size_t incount
, const double *wavelen_m
, const double *n
, const double *k
,
13 const gsl_interp_type
*iptype
)
15 if (incount
<= 0) return NULL
;
16 qpms_permittivity_interpolator_t
*ip
;
17 QPMS_CRASHING_MALLOC(ip
, sizeof(qpms_permittivity_interpolator_t
));
19 QPMS_CRASHING_MALLOC(ip
->wavelength_m
, incount
* sizeof(double));
20 QPMS_CRASHING_MALLOC(ip
->n
, incount
* sizeof(double));
21 QPMS_CRASHING_MALLOC(ip
->k
, incount
* sizeof(double));
22 memcpy(ip
->wavelength_m
, wavelen_m
, incount
*sizeof(double));
23 memcpy(ip
->k
, k
, incount
*sizeof(double));
24 memcpy(ip
->n
, n
, incount
*sizeof(double));
25 ip
->interp_n
= gsl_interp_alloc(iptype
, incount
);
26 ip
->interp_k
= gsl_interp_alloc(iptype
, incount
);
27 QPMS_ENSURE_SUCCESS(gsl_interp_init(ip
->interp_n
, ip
->wavelength_m
, ip
->n
, incount
));
28 QPMS_ENSURE_SUCCESS(gsl_interp_init(ip
->interp_k
, ip
->wavelength_m
, ip
->k
, incount
));
32 void qpms_permittivity_interpolator_free(qpms_permittivity_interpolator_t
*interp
)
35 gsl_interp_free(interp
->interp_n
);
36 gsl_interp_free(interp
->interp_k
);
39 free(interp
->wavelength_m
);
44 qpms_errno_t
qpms_read_refractiveindex_yml(
45 FILE *f
, ///< file handle
46 size_t *const count
, ///< Number of successfully loaded triples.
47 double* *const lambdas_m
, ///< Vacuum wavelengths in metres.
48 double* *const n
, ///< Read refraction indices.
49 double* *const k
///< Read attenuation coeffs.
52 QPMS_ENSURE(f
&& lambdas_m
&& n
&& k
,"f, lambdas_m, n, k are mandatory arguments and must not be NULL.");
53 int count_alloc
= 128; // First chunk to allocate
55 QPMS_CRASHING_MALLOC(*lambdas_m
, count_alloc
* sizeof(double));
56 QPMS_CRASHING_MALLOC(*n
, count_alloc
* sizeof(double));
57 QPMS_CRASHING_MALLOC(*k
, count_alloc
* sizeof(double));
58 size_t linebufsz
= 256;
60 QPMS_CRASHING_MALLOC(linebuf
, linebufsz
);
62 bool data_started
= false;
63 while((readchars
= getline(&linebuf
, &linebufsz
, f
)) != -1) {
64 if (linebuf
[0] == '#') continue;
65 // We need to find the beginning of the tabulated data; everything before that is ignored.
67 char *test
= strstr(linebuf
, "data: |");
68 if(test
) data_started
= true;
72 if (3 == sscanf(linebuf
, "%lf %lf %lf", *lambdas_m
+ *count
, *n
+ *count
, *k
+ *count
)) {
73 (*lambdas_m
)[*count
] *= 1e-6; // The original data is in micrometres.
75 if (*count
> count_alloc
) {
77 QPMS_CRASHING_REALLOC(*lambdas_m
, count_alloc
* sizeof(double));
78 QPMS_CRASHING_REALLOC(*n
, count_alloc
* sizeof(double));
79 QPMS_CRASHING_REALLOC(*k
, count_alloc
* sizeof(double));
83 QPMS_ENSURE(*count
> 0, "Could not read any refractive index data; the format must be wrong!");
88 qpms_errno_t
qpms_load_refractiveindex_yml(
90 size_t *const count
, ///< Number of successfully loaded triples.
91 double* *const lambdas_m
, ///< Vacuum wavelengths in metres.
92 double* *const n
, ///< Read refraction indices.
93 double* *const k
///< Read attenuation coeffs.
96 FILE *f
= fopen(path
, "r");
97 QPMS_ENSURE(f
, "Could not open refractive index file %s", path
);
99 qpms_read_refractiveindex_yml(f
, count
, lambdas_m
, n
, k
);
100 QPMS_ENSURE_SUCCESS(fclose(f
));
104 qpms_permittivity_interpolator_t
*qpms_permittivity_interpolator_from_yml(
105 const char *path
, ///< Path to the yml file.
106 const gsl_interp_type
*iptype
///< GSL interpolator type
110 double *lambdas_m
, *n
, *k
;
111 QPMS_ENSURE_SUCCESS(qpms_load_refractiveindex_yml(path
, &count
, &lambdas_m
, &n
, &k
));
112 qpms_permittivity_interpolator_t
*ip
= qpms_permittivity_interpolator_create(
113 count
, lambdas_m
, n
, k
, iptype
);
120 complex double qpms_permittivity_interpolator_eps_at_omega(
121 const qpms_permittivity_interpolator_t
*ip
, double omega_SI
)
124 lambda
= 2*M_PI
*SPEED_OF_LIGHT
/omega_SI
;
125 n
= gsl_interp_eval(ip
->interp_n
, ip
->wavelength_m
, ip
->n
, lambda
, NULL
);
126 k
= gsl_interp_eval(ip
->interp_k
, ip
->wavelength_m
, ip
->k
, lambda
, NULL
);
127 complex double epsilon
= n
*n
- k
*k
+ 2*n
*k
*I
;
131 qpms_epsmu_t
qpms_permittivity_interpolator_epsmu_g(
132 complex double omega
, const void *p
)
134 const qpms_permittivity_interpolator_t
*interp
= p
;
135 static bool imag_already_bitched
= false;
136 if(cimag(omega
) && !imag_already_bitched
)
137 QPMS_WARN("Complex frequencies not supported by qpms_permittivity_interpolator_t. Imaginary parts will be discarded!");
139 em
.eps
= qpms_permittivity_interpolator_eps_at_omega(interp
, omega
);
144 double qpms_permittivity_interpolator_omega_max(
145 const qpms_permittivity_interpolator_t
*ip
)
147 return 2*M_PI
*SPEED_OF_LIGHT
/ ip
->wavelength_m
[0];
150 double qpms_permittivity_interpolator_omega_min(
151 const qpms_permittivity_interpolator_t
*ip
)
153 return 2*M_PI
*SPEED_OF_LIGHT
/ ip
->wavelength_m
[ip
->size
-1];
156 complex double qpms_lorentzdrude_eps(complex double omega
, const qpms_ldparams_t
*p
)
158 complex double eps
= 0;
159 for(size_t j
= 0; j
< p
->n
; ++j
) {
160 const qpms_ldparams_triple_t d
= p
->data
[j
];
161 eps
+= d
.f
* SQ(p
->omega_p
) / (SQ(d
.omega
) - SQ(omega
) - I
*omega
*d
.gamma
);
166 qpms_epsmu_t
qpms_lorentzdrude_epsmu(complex double omega
, const qpms_ldparams_t
*p
)
169 em
.eps
= qpms_lorentzdrude_eps(omega
, p
);
174 qpms_epsmu_t
qpms_lorentzdrude_epsmu_g(complex double omega
, const void *p
)
176 return qpms_lorentzdrude_epsmu(omega
, (const qpms_ldparams_t
*)p
);
179 qpms_epsmu_t
qpms_epsmu_const_g(complex double omega
, const void *p
)
181 return *(const qpms_epsmu_t
*)p
;