solstice-solver

Solver library of the solstice app
git clone git://git.meso-star.com/solstice-solver.git
Log | Files | Refs | README | LICENSE

ssol_spectrum.c (6072B)


      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_spectrum_c.h"
     19 #include "ssol_device_c.h"
     20 
     21 #include <rsys/algorithm.h>
     22 #include <rsys/hash.h>
     23 #include <rsys/math.h>
     24 #include <rsys/mem_allocator.h>
     25 #include <rsys/ref_count.h>
     26 
     27 /*******************************************************************************
     28  * Helper functions
     29  ******************************************************************************/
     30 static void
     31 spectrum_release(ref_T* ref)
     32 {
     33   struct ssol_device* dev;
     34   struct ssol_spectrum* spectrum = CONTAINER_OF(ref, struct ssol_spectrum, ref);
     35   ASSERT(ref);
     36   dev = spectrum->dev;
     37   ASSERT(dev && dev->allocator);
     38   darray_double_release(&spectrum->wavelengths);
     39   darray_double_release(&spectrum->intensities);
     40   MEM_RM(dev->allocator, spectrum);
     41   SSOL(device_ref_put(dev));
     42 }
     43 
     44 static int
     45 eq_dbl(const void* key, const void* base)
     46 {
     47   const double k = *(const double*) key;
     48   const double b = *(const double*) base;
     49   if(k > b) return +1;
     50   if(k < b) return -1;
     51   return 0;
     52 }
     53 
     54 /*******************************************************************************
     55  * Local ssol_spectrum functions
     56  ******************************************************************************/
     57 double
     58 spectrum_interpolate
     59   (const struct ssol_spectrum* spectrum, const double wavelength)
     60 {
     61   const double* wls;
     62   const double* ints;
     63   const double* next;
     64   double slope;
     65   double intensity;
     66   size_t id_next, sz;
     67   ASSERT(spectrum);
     68 
     69   sz = darray_double_size_get(&spectrum->wavelengths);
     70   wls = darray_double_cdata_get(&spectrum->wavelengths);
     71   ints = darray_double_cdata_get(&spectrum->intensities);
     72   next = search_lower_bound(&wavelength, wls, sz, sizeof(double), &eq_dbl);
     73   if(!next) { /* Clamp to upper bound */
     74     return ints[sz-1];
     75   }
     76 
     77   id_next = (size_t)(next - wls);
     78   if(!id_next) { /* Clamp to lower bound */
     79     return ints[0];
     80   }
     81 
     82   ASSERT(id_next); /* because spectrum_includes_point */
     83   ASSERT(wls[id_next] >= wls[id_next - 1]);
     84 
     85   slope = (ints[id_next] - ints[id_next-1]) / (wls[id_next] - wls[id_next-1]);
     86   intensity = ints[id_next-1] + (wavelength - wls[id_next - 1]) * slope;
     87   ASSERT(intensity >= 0);
     88   return intensity;
     89 }
     90 
     91 int
     92 spectrum_check_data
     93   (const struct ssol_spectrum* spectrum, const double lower, const double upper)
     94 {
     95   size_t sz, i;
     96   double current_wl = 0;
     97   ASSERT(spectrum && lower <= upper);
     98   sz = darray_double_size_get(&spectrum->intensities);
     99   if(!sz) return 0;
    100   if(sz != darray_double_size_get(&spectrum->wavelengths)) return 0;
    101   FOR_EACH(i, 0, sz) {
    102     const double wl = darray_double_cdata_get(&spectrum->wavelengths)[i];
    103     const double data = darray_double_cdata_get(&spectrum->intensities)[i];
    104     if(data < lower || data > upper) return 0;
    105     if(wl <= 0) return 0;
    106     if(wl <= current_wl) return 0;
    107     current_wl = wl;
    108   }
    109   return 1;
    110 }
    111 
    112 /*******************************************************************************
    113  * Exported ssol_spectrum functions
    114  ******************************************************************************/
    115 res_T
    116 ssol_spectrum_create
    117   (struct ssol_device* dev, struct ssol_spectrum** out_spectrum)
    118 {
    119   struct ssol_spectrum* spectrum = NULL;
    120   res_T res = RES_OK;
    121 
    122   if(!dev || !out_spectrum) {
    123     res = RES_BAD_ARG;
    124     goto error;
    125   }
    126 
    127   spectrum = MEM_CALLOC(dev->allocator, 1, sizeof(struct ssol_spectrum));
    128   if(!spectrum) {
    129     res = RES_MEM_ERR;
    130     goto error;
    131   }
    132 
    133   SSOL(device_ref_get(dev));
    134   spectrum->dev = dev;
    135   ref_init(&spectrum->ref);
    136   darray_double_init(dev->allocator, &spectrum->wavelengths);
    137   darray_double_init(dev->allocator, &spectrum->intensities);
    138 
    139 exit:
    140   if(out_spectrum) *out_spectrum = spectrum;
    141   return res;
    142 error:
    143   if(spectrum) {
    144     SSOL(spectrum_ref_put(spectrum));
    145     spectrum = NULL;
    146   }
    147   goto exit;
    148 }
    149 
    150 res_T
    151 ssol_spectrum_ref_get(struct ssol_spectrum* spectrum)
    152 {
    153   if(!spectrum) return RES_BAD_ARG;
    154   ref_get(&spectrum->ref);
    155   return RES_OK;
    156 }
    157 
    158 res_T
    159 ssol_spectrum_ref_put(struct ssol_spectrum* spectrum)
    160 {
    161   if(!spectrum) return RES_BAD_ARG;
    162   ref_put(&spectrum->ref, spectrum_release);
    163   return RES_OK;
    164 }
    165 
    166 SSOL_API res_T
    167 ssol_spectrum_setup
    168   (struct ssol_spectrum* spectrum,
    169    void (*get)(const size_t iwlen, double* wlen, double* data, void* ctx),
    170    const size_t nwlens,
    171    void* ctx)
    172 {
    173   double* wavelengths;
    174   double* intensities;
    175   double current_wl = 0;
    176   size_t i;
    177   res_T res = RES_OK;
    178 
    179   if(!spectrum || !nwlens || !get) {
    180     res = RES_BAD_ARG;
    181     goto error;
    182   }
    183 
    184   res = darray_double_resize(&spectrum->wavelengths, nwlens);
    185   if(res != RES_OK) goto error;
    186   res = darray_double_resize(&spectrum->intensities, nwlens);
    187   if(res != RES_OK) goto error;
    188 
    189   wavelengths = darray_double_data_get(&spectrum->wavelengths);
    190   intensities = darray_double_data_get(&spectrum->intensities);
    191   FOR_EACH(i, 0, nwlens) {
    192     get(i, wavelengths + i, intensities + i, ctx);
    193     if(wavelengths[i] <= current_wl || intensities[i] < 0) {
    194       res = RES_BAD_ARG;
    195       goto error;
    196     }
    197     current_wl = *(wavelengths + i);
    198   }
    199 
    200   spectrum->checksum[0] = hash_fnv64(wavelengths, nwlens*sizeof(double));
    201   spectrum->checksum[1] = hash_fnv64(intensities, nwlens*sizeof(double));
    202 
    203 exit:
    204   return res;
    205 error:
    206   if(spectrum) {
    207     darray_double_clear(&spectrum->wavelengths);
    208     darray_double_clear(&spectrum->intensities);
    209     spectrum->checksum[0] = 0;
    210     spectrum->checksum[1] = 0;
    211   }
    212   goto exit;
    213 }
    214