star-phor

Radiative transfer solver for photoreactors.
git clone https://www.edstar.cnrs.fr/git/star-phor.git
Log | Files | Refs | README | LICENSE

sphor_sources.c (9787B)


      1 /* Copyright (C) 2024-2026 Centre National de la Recherche Scientifique
      2  * Copyright (C) 2024-2026 Clermont Auvergne INP
      3  * Copyright (C) 2024-2026 INSA Lyon
      4  * Copyright (C) 2024-2026 Institut Mines Télécom Albi-Carmaux
      5  * Copyright (C) 2024-2026 Institut National Polytechnique de Toulouse
      6  * Copyright (C) 2024-2026 |Méso|Star> (contact@meso-star.com)
      7  * Copyright (C) 2024-2026 PhotonLyX (info@photonlyx.com)
      8  * Copyright (C) 2024-2026 Université de Lorraine
      9  * Copyright (C) 2024-2026 Université Paul Sabatier
     10  * Copyright (C) 2024-2026 Université Toulouse - Jean Jaurès
     11  *
     12  * This program is free software: you can redistribute it and/or modify
     13  * it under the terms of the GNU General Public License as published by
     14  * the Free Software Foundation, either version 3 of the License, or
     15  * (at your option) any later version.
     16  *
     17  * This program is distributed in the hope that it will be useful,
     18  * but WITHOUT ANY WARRANTY; without even the implied warranty of
     19  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
     20  * GNU General Public License for more details.
     21  *
     22  * You should have received a copy of the GNU General Public License
     23  * along with this program. If not, see <http://www.gnu.org/licenses/>. */
     24 
     25 #include "sphor_c.h"
     26 #include "sphor_config.h"
     27 #include "sphor_sources.h"
     28 
     29 #include <rsys/double3.h>
     30 #include <rsys/dynamic_array_double.h>
     31 #include <star/s3d.h>
     32 #include <star/sphin.h>
     33 #include <star/ssp.h>
     34 #include <star/suniq.h>
     35 
     36 struct sphin_geometry;
     37 struct sphin_surface;
     38 
     39 /*******************************************************************************
     40  * Helper functions
     41  ******************************************************************************/
     42 static res_T
     43 register_surface_geometry
     44   (struct sphor* sphor,
     45    const struct sphor_create_args* args,
     46    const struct sphin_geometry* geom,
     47    struct suniq* suniq_scene,
     48    struct suniq* suniq,
     49    struct source_view* source)
     50 {
     51   struct sphin_geometry_descriptor geom_desc = SPHIN_GEOMETRY_DESCRIPTOR_NULL;
     52   size_t itri = 0;
     53   size_t id_scene;
     54   size_t id_source;
     55   res_T res = RES_OK;
     56 
     57   ASSERT(NULL != sphor);
     58 
     59   (void)sphor;
     60   (void)args;
     61 
     62   res = sphin_geometry_get_desc(geom, &geom_desc);
     63   if (RES_OK != res) { goto error; }
     64 
     65   FOR_EACH(itri, 0, geom_desc.mesh.triangle_count) {
     66     struct suniq_triangle tri = SUNIQ_TRIANGLE_NULL;
     67 
     68     setup_triangle(&geom_desc, itri, &tri);
     69 
     70     /* Reverse triangle normal if side is back:
     71      *
     72      * Since a geometry can only be declared with one side at a time in sphin
     73      * for the same source, the strategy taken is to store the triangle in the
     74      * scene view in such a way that its normal points always to the hemisphere
     75      * corresponding to the emitting side. In such a way, during path sampling,
     76      * one can simply retrieve the normal of the sampled primitive and it will
     77      * correspond to the emitting direction (subject to the convention: left or
     78      * right-hand of each library)
     79      */
     80 
     81     if (SPHIN_SIDE_BACK == geom_desc.side) {
     82       double tmp[3] = {0};
     83       d3_set(tmp, tri.vertices[0]);
     84       d3_set(tri.vertices[0], tri.vertices[1]);
     85       d3_set(tri.vertices[1], tmp);
     86     }
     87 
     88     res = suniq_register_triangle(suniq, &tri, &id_source);
     89     if (RES_OK != res) { goto error; }
     90 
     91     /* Retrieve the id to the corresponding primitive in the scene */
     92     res = suniq_register_triangle(suniq_scene, &tri, &id_scene);
     93     if (RES_OK != res) { goto error; }
     94 
     95     /* Append scene prim_id to the source <-> scene correspondance array */
     96     if (id_source == darray_size_t_size_get(&source->src2scn)){
     97       res = darray_size_t_push_back(&source->src2scn, &id_scene);
     98       if (RES_OK != res) { goto error; }
     99     }
    100   }
    101 
    102 exit:
    103   return res;
    104 error:
    105   goto exit;
    106 }
    107 
    108 static res_T
    109 setup_emission_spectrum_pdf
    110   (struct sphor* sphor,
    111    struct sphin_surface* surface,
    112    struct source_view* source)
    113 {
    114   struct sphin_source_surface* sphin_source = NULL;
    115   struct sphin_spectral_property_descriptor spectrum =
    116     SPHIN_SPECTRAL_PROPERTY_DESCRIPTOR_NULL;
    117   struct sphin_source_surface_flux_density density =
    118     SPHIN_SOURCE_SURFACE_FLUX_DENSITY_NULL;
    119   res_T res = RES_OK;
    120 
    121   ASSERT(NULL != sphor);
    122   ASSERT(NULL != surface);
    123   ASSERT(NULL != source);
    124 
    125   SPHIN(surface_get_source(surface, &sphin_source));
    126   if (NULL == sphin_source) { res = RES_BAD_ARG; goto error; }
    127 
    128   SPHIN(source_surface_get_flux_density(sphin_source, &density));
    129 
    130   if (NULL == density.emission_spectrum) { res = RES_BAD_ARG; goto error; }
    131 
    132   SPHIN(spectral_property_get_desc(density.emission_spectrum, &spectrum));
    133 
    134   res = ssp_ranst_piecewise_linear_create
    135     (sphor->allocator, &source->emission_spectrum_pdf);
    136   if (RES_OK != res) { goto error; }
    137 
    138   res = ssp_ranst_piecewise_linear_setup
    139     (source->emission_spectrum_pdf,
    140      spectrum.wavelengths,
    141      spectrum.values,
    142      spectrum.data_count);
    143   if (RES_OK != res) { goto error; }
    144 
    145 exit:
    146   return res;
    147 error:
    148   if (source->emission_spectrum_pdf != NULL) {
    149     SSP(ranst_piecewise_linear_ref_put(source->emission_spectrum_pdf));
    150   }
    151   goto exit;
    152 }
    153 
    154 static res_T
    155 setup_source_view
    156   (struct sphor* sphor,
    157    const struct sphor_create_args* args,
    158    struct sphin_surface* surface,
    159    struct suniq* suniq_scene,
    160    struct source_view* source)
    161 {
    162   struct suniq* suniq = NULL;
    163   struct sphin_geometry* geom = NULL;
    164   size_t i_geometry = 0;
    165   size_t geometry_count = 0;
    166   res_T res = RES_OK;
    167 
    168   ASSERT(NULL != sphor);
    169 
    170   res = suniq_create(sphor->allocator, &suniq);
    171   if (RES_OK != res) { goto error; }
    172 
    173   res = sphin_surface_get_geometry_count(surface, &geometry_count);
    174   if (RES_OK != res) { goto error; }
    175 
    176   FOR_EACH(i_geometry, 0, geometry_count) {
    177     res = sphin_surface_get_geometry(surface, i_geometry, &geom);
    178     if (RES_OK != res) { goto error; }
    179 
    180     res = register_surface_geometry
    181       (sphor, args, geom, suniq_scene, suniq, source);
    182     if (RES_OK != res) { goto error; }
    183   }
    184 
    185   res = setup_geometry_accel_struct(sphor, suniq, S3D_SAMPLE, &source->view);
    186   if (RES_OK != res) { goto error; }
    187 
    188   res = setup_emission_spectrum_pdf(sphor, surface, source);
    189   if (RES_OK != res) { goto error; }
    190 
    191 exit:
    192   if (NULL != suniq) { SUNIQ(ref_put(suniq)); }
    193   return res;
    194 error:
    195   goto exit;
    196 }
    197 
    198 static res_T
    199 register_source_view
    200   (struct sphor* sphor,
    201    const struct sphor_create_args* args,
    202    const size_t isurface,
    203    struct suniq* suniq_scene)
    204 {
    205   struct sphin_surface* surface = NULL;
    206   struct sphin_source_surface* source_surface = NULL;
    207   struct source_view source = SOURCE_VIEW_NULL;
    208   res_T res = RES_OK;
    209 
    210   ASSERT(NULL != sphor);
    211   ASSERT(NULL != args);
    212 
    213   source_init(sphor->allocator, &source);
    214 
    215   SPHIN(config_get_surface(sphor->config, isurface, &surface));
    216   SPHIN(surface_get_source(surface, &source_surface));
    217   ASSERT(NULL != source_surface);
    218 
    219   source.sphin_id = isurface;
    220 
    221   res = setup_source_view(sphor, args, surface, suniq_scene, &source);
    222   if (RES_OK != res) { goto error; }
    223 
    224   res = darray_source_view_push_back(&sphor->source_views, &source);
    225   if (RES_OK != res) { goto error; }
    226 
    227 exit:
    228   source_release(&source);
    229   return res;
    230 error:
    231   goto exit;
    232 }
    233 
    234 /*******************************************************************************
    235  * Local functions
    236  ******************************************************************************/
    237 res_T
    238 setup_source_views
    239   (struct sphor* sphor,
    240    const struct sphor_create_args* args,
    241    struct suniq* suniq_scene)
    242 
    243 {
    244   struct sphin_source_surface* source_surface = NULL;
    245   struct sphin_surface* surface = NULL;
    246   size_t surface_count = 0;
    247   size_t i_surface = 0;
    248   res_T res = RES_OK;
    249 
    250   ASSERT(NULL != sphor);
    251   ASSERT(NULL != sphor->config);
    252 
    253   res = sphin_config_get_surface_count(sphor->config, &surface_count);
    254   if (RES_OK != res) { goto error; }
    255 
    256   FOR_EACH(i_surface, 0, surface_count) {
    257     res = sphin_config_get_surface(sphor->config, i_surface, &surface);
    258     if (RES_OK != res) { goto error; }
    259 
    260     res = sphin_surface_get_source(surface, &source_surface);
    261     if (RES_OK != res) { goto error; }
    262 
    263     if (NULL != source_surface) {
    264       res = register_source_view(sphor, args, i_surface, suniq_scene);
    265       if (RES_OK != res) { goto error; }
    266     }
    267   }
    268 
    269 exit:
    270   return res;
    271 error:
    272   goto exit;
    273 }
    274 
    275 res_T
    276 setup_source_distrib_power
    277   (struct sphor* sphor,
    278    const struct sphor_create_args* args)
    279 {
    280   double power = 0;
    281   size_t i_surface = 0;
    282   size_t surface_count = 0;
    283   struct darray_double powers;
    284   struct sphin_source_surface* source_surface = NULL;
    285   struct sphin_surface* surface = NULL;
    286   res_T res = RES_OK;
    287 
    288   ASSERT(NULL != sphor);
    289   ASSERT(NULL != args);
    290 
    291   (void) args;
    292 
    293   darray_double_init(sphor->allocator, &powers);
    294 
    295   res = sphin_config_get_surface_count(sphor->config, &surface_count);
    296   if (RES_OK != res) { goto error; }
    297 
    298   FOR_EACH(i_surface, 0, surface_count) {
    299     res = sphin_config_get_surface(sphor->config, i_surface, &surface);
    300     if (RES_OK != res) { goto error; }
    301 
    302     res = sphin_surface_get_source(surface, &source_surface);
    303     if (RES_OK != res) { goto error; }
    304 
    305     if (NULL != source_surface) {
    306       res = sphin_surface_source_get_power(surface, &power);
    307       if (RES_OK != res) { goto error; }
    308       res = darray_double_push_back(&powers, &power);
    309       if (RES_OK != res) { goto error; }
    310     }
    311   }
    312 
    313   if (0 == darray_double_size_get(&powers)) {
    314     ERROR(sphor,
    315           "No sources defined in input file. "
    316           "Nothing to do.\n");
    317     res = RES_BAD_ARG;
    318     goto error;
    319   }
    320 
    321   res = ssp_ranst_discrete_create
    322     (sphor->allocator, &sphor->source_distrib_power);
    323   if (RES_OK != res) { goto error; }
    324 
    325   res = ssp_ranst_discrete_setup
    326     (sphor->source_distrib_power,
    327      darray_double_cdata_get(&powers),
    328      darray_double_size_get(&powers));
    329   if (RES_OK != res) { goto error; }
    330 
    331 exit:
    332   darray_double_release(&powers);
    333   return res;
    334 error:
    335   goto exit;
    336 }