stardis-solver

Solve coupled heat transfers
git clone git://git.meso-star.fr/stardis-solver.git
Log | Files | Refs | README | LICENSE

sdis_interface.c (10080B)


      1 /* Copyright (C) 2016-2025 |Méso|Star> (contact@meso-star.com)
      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 "sdis.h"
     17 #include "sdis_device_c.h"
     18 #include "sdis_interface_c.h"
     19 #include "sdis_log.h"
     20 #include "sdis_scene_c.h"
     21 
     22 #include <rsys/double2.h>
     23 #include <rsys/double3.h>
     24 #include <rsys/mem_allocator.h>
     25 
     26 #include <star/s2d.h>
     27 #include <star/s3d.h>
     28 
     29 /*******************************************************************************
     30  * Helper functions
     31  ******************************************************************************/
     32 static int
     33 check_interface_shader
     34   (struct sdis_device* dev,
     35    const char* caller_name,
     36    const struct sdis_interface_shader* shader,
     37    const struct sdis_medium* front,
     38    const struct sdis_medium* back)
     39 {
     40   enum sdis_medium_type type[2];
     41   const struct sdis_interface_side_shader* shaders[2];
     42   int i;
     43   ASSERT(dev && caller_name && shader && front && back);
     44 
     45   type[0] = sdis_medium_get_type(front);
     46   type[1] = sdis_medium_get_type(back);
     47   shaders[0] = &shader->front;
     48   shaders[1] = &shader->back;
     49 
     50   /* Fluid<->solid interface */
     51   if(type[0] == SDIS_SOLID
     52   && type[1] == SDIS_SOLID
     53   && shader->convection_coef) {
     54     log_warn(dev,
     55       "%s: a solid/solid interface can't have a convection coefficient. The "
     56       "shader's pointer function for this attribute should be NULL.\n",
     57       caller_name);
     58   }
     59   if(shader->convection_coef_upper_bound < 0) {
     60     log_warn(dev,
     61       "%s: Invalid upper bound for convection coefficient (%g).\n",
     62       caller_name, shader->convection_coef_upper_bound);
     63     if(type[0] == SDIS_FLUID || type[1] == SDIS_FLUID) return 0;
     64   }
     65 
     66   if((type[0] != SDIS_SOLID || type[1] != SDIS_SOLID)
     67   && shader->thermal_contact_resistance) {
     68     log_warn(dev,
     69       "%s: only solid/solid interface can have a thermal contact resistance. The "
     70       "shader's pointer function for this attribute should be NULL.\n",
     71       caller_name);
     72   }
     73 
     74   FOR_EACH(i, 0, 2) {
     75     switch(type[i]) {
     76       case SDIS_FLUID: /* No constraint */ break;
     77       case SDIS_SOLID:
     78         if(shaders[i]->emissivity 
     79         || shaders[i]->specular_fraction
     80         || shaders[i]->reference_temperature) {
     81           log_warn(dev,
     82             "%s: the interface side toward a solid cannot have an emissivity, "
     83             "a specular_fraction or a reference temperature. The shader's "
     84             "pointer functions for these attributes should be NULL.\n",
     85             caller_name);
     86         }
     87         break;
     88       default: FATAL("Unreachable code.\n"); break;
     89     }
     90   }
     91   return 1;
     92 }
     93 
     94 static void
     95 interface_release(ref_T* ref)
     96 {
     97   struct sdis_interface* interf = NULL;
     98   struct sdis_device* dev = NULL;
     99   ASSERT(ref);
    100   interf = CONTAINER_OF(ref, struct sdis_interface, ref);
    101   dev = interf->dev;
    102   if(interf->medium_front) SDIS(medium_ref_put(interf->medium_front));
    103   if(interf->medium_back) SDIS(medium_ref_put(interf->medium_back));
    104   if(interf->data) SDIS(data_ref_put(interf->data));
    105   flist_name_del(&dev->interfaces_names, interf->id);
    106   MEM_RM(dev->allocator, interf);
    107   SDIS(device_ref_put(dev));
    108 }
    109 
    110 /*******************************************************************************
    111  * Exported functions
    112  ******************************************************************************/
    113 res_T
    114 sdis_interface_create
    115   (struct sdis_device* dev,
    116    struct sdis_medium* front,
    117    struct sdis_medium* back,
    118    const struct sdis_interface_shader* shader,
    119    struct sdis_data* data,
    120    struct sdis_interface** out_interface)
    121 {
    122   struct sdis_interface* interf = NULL;
    123   res_T res = RES_OK;
    124 
    125   if(!dev || !front || !back || !shader || !out_interface) {
    126     res = RES_BAD_ARG;
    127     goto error;
    128   }
    129 
    130   if(sdis_medium_get_type(front) == SDIS_FLUID
    131   && sdis_medium_get_type(back) == SDIS_FLUID) {
    132     log_err(dev, "%s: invalid fluid<->fluid interface.\n", FUNC_NAME);
    133     res = RES_BAD_ARG;
    134     goto error;
    135   }
    136 
    137   if(!check_interface_shader(dev, FUNC_NAME, shader, front, back)) {
    138     log_err(dev, "%s: invalid interface shader.\n", FUNC_NAME);
    139     res = RES_BAD_ARG;
    140     goto error;
    141   }
    142 
    143   interf = MEM_CALLOC(dev->allocator, 1, sizeof(struct sdis_interface));
    144   if(!interf) {
    145     log_err(dev, "%s: could not create the interface.\n", FUNC_NAME);
    146     res = RES_MEM_ERR;
    147     goto error;
    148   }
    149   ref_init(&interf->ref);
    150   SDIS(medium_ref_get(front));
    151   SDIS(medium_ref_get(back));
    152   SDIS(device_ref_get(dev));
    153   interf->medium_front = front;
    154   interf->medium_back = back;
    155   interf->dev = dev;
    156   interf->shader = *shader;
    157   interf->id = flist_name_add(&dev->interfaces_names);
    158   flist_name_get(&dev->interfaces_names, interf->id)->mem = interf;
    159 
    160   if(data) {
    161     SDIS(data_ref_get(data));
    162     interf->data = data;
    163   }
    164 
    165 exit:
    166   if(out_interface) *out_interface = interf;
    167   return res;
    168 error:
    169   if(interf) {
    170     SDIS(interface_ref_put(interf));
    171     interf = NULL;
    172   }
    173   goto exit;
    174 }
    175 
    176 res_T
    177 sdis_interface_ref_get(struct sdis_interface* interf)
    178 {
    179   if(!interf) return RES_BAD_ARG;
    180   ref_get(&interf->ref);
    181   return RES_OK;
    182 }
    183 
    184 res_T
    185 sdis_interface_ref_put(struct sdis_interface* interf)
    186 {
    187   if(!interf) return RES_BAD_ARG;
    188   ref_put(&interf->ref, interface_release);
    189   return RES_OK;
    190 }
    191 
    192 SDIS_API res_T
    193 sdis_interface_get_shader
    194   (const struct sdis_interface* interf,
    195    struct sdis_interface_shader* shader)
    196 {
    197   if(!interf || !shader) return RES_BAD_ARG;
    198   *shader = interf->shader;
    199   return RES_OK;
    200 }
    201 
    202 struct sdis_data*
    203 sdis_interface_get_data(struct sdis_interface* interf)
    204 {
    205   ASSERT(interf);
    206   return interf->data;
    207 }
    208 
    209 unsigned
    210 sdis_interface_get_id(const struct sdis_interface* interf)
    211 {
    212   ASSERT(interf);
    213   return interf->id.index;
    214 }
    215 
    216 /*******************************************************************************
    217  * Local function
    218  ******************************************************************************/
    219 struct sdis_medium*
    220 interface_get_medium
    221   (const struct sdis_interface* interf, const enum sdis_side side)
    222 {
    223   struct sdis_medium* mdm = NULL;
    224   ASSERT(interf);
    225   switch(side) {
    226     case SDIS_FRONT: mdm = interf->medium_front; break;
    227     case SDIS_BACK:  mdm = interf->medium_back; break;
    228     default: FATAL("Unreachable code.\n"); break;
    229   }
    230   return mdm;
    231 }
    232 
    233 void
    234 setup_interface_fragment_2d
    235   (struct sdis_interface_fragment* frag,
    236    const struct sdis_rwalk_vertex* vertex,
    237    const struct s2d_hit* hit,
    238    const enum sdis_side side)
    239 {
    240   ASSERT(frag && vertex && hit && !S2D_HIT_NONE(hit));
    241   ASSERT(side == SDIS_FRONT || side == SDIS_BACK);
    242   d2_set(frag->P, vertex->P);
    243   frag->P[2] = 0;
    244   d2_normalize(frag->Ng, d2_set_f2(frag->Ng, hit->normal));
    245   frag->Ng[2] = 0;
    246   frag->uv[0] = hit->u;
    247   frag->time = vertex->time;
    248   frag->side = side;
    249 }
    250 
    251 void
    252 setup_interface_fragment_3d
    253   (struct sdis_interface_fragment* frag,
    254    const struct sdis_rwalk_vertex* vertex,
    255    const struct s3d_hit* hit,
    256    const enum sdis_side side)
    257 {
    258   ASSERT(frag && vertex && hit && !S3D_HIT_NONE(hit));
    259   ASSERT(side == SDIS_FRONT || side == SDIS_BACK);
    260   d3_set(frag->P, vertex->P);
    261   d3_normalize(frag->Ng, d3_set_f3(frag->Ng, hit->normal));
    262   d2_set_f2(frag->uv, hit->uv);
    263   frag->time = vertex->time;
    264   frag->side = side;
    265 }
    266 
    267 res_T
    268 build_interface_fragment_2d
    269   (struct sdis_interface_fragment* frag,
    270    const struct sdis_scene* scn,
    271    const unsigned iprim,
    272    const double uv[1],
    273    const enum sdis_side side)
    274 {
    275   struct s2d_attrib attr_P, attr_N;
    276   struct s2d_primitive prim = S2D_PRIMITIVE_NULL;
    277   struct s2d_hit hit = S2D_HIT_NULL;
    278   struct sdis_rwalk_vertex vtx = SDIS_RWALK_VERTEX_NULL;
    279   float st;
    280   res_T res = RES_OK;
    281 
    282   ASSERT(frag && scn && uv && scene_is_2d(scn));
    283   ASSERT(side == SDIS_FRONT || side == SDIS_BACK);
    284 
    285   st = (float)uv[0];
    286 
    287   #define CALL(Func) { res = Func; if(res != RES_OK) goto error; } (void)0
    288   CALL(s2d_scene_view_get_primitive(scn->s2d_view, iprim, &prim));
    289   CALL(s2d_primitive_get_attrib(&prim, S2D_POSITION, st, &attr_P));
    290   CALL(s2d_primitive_get_attrib(&prim, S2D_GEOMETRY_NORMAL, st, &attr_N));
    291   #undef CALL
    292 
    293   vtx.P[0] = attr_P.value[0];
    294   vtx.P[1] = attr_P.value[1];
    295   vtx.time = NaN;
    296   hit.normal[0] = attr_N.value[0];
    297   hit.normal[1] = attr_N.value[1];
    298   hit.distance = 0;
    299   hit.prim = prim;
    300 
    301   setup_interface_fragment_2d(frag, &vtx, &hit, side);
    302 
    303 exit:
    304   return res;
    305 error:
    306   *frag = SDIS_INTERFACE_FRAGMENT_NULL;
    307   goto exit;
    308 }
    309 
    310 res_T
    311 build_interface_fragment_3d
    312   (struct sdis_interface_fragment* frag,
    313    const struct sdis_scene* scn,
    314    const unsigned iprim,
    315    const double uv[2],
    316    const enum sdis_side side)
    317 {
    318   struct s3d_attrib attr_P, attr_N;
    319   struct s3d_primitive prim = S3D_PRIMITIVE_NULL;
    320   struct s3d_hit hit = S3D_HIT_NULL;
    321   struct sdis_rwalk_vertex vtx = SDIS_RWALK_VERTEX_NULL;
    322   float st[2];
    323   res_T res = RES_OK;
    324 
    325   ASSERT(frag && scn && uv && !scene_is_2d(scn));
    326   ASSERT(side == SDIS_FRONT || side == SDIS_BACK);
    327 
    328   st[0] = (float)uv[0];
    329   st[1] = (float)uv[1];
    330 
    331   #define CALL(Func) { res = Func; if(res != RES_OK) goto error; } (void)0
    332   CALL(s3d_scene_view_get_primitive(scn->s3d_view, iprim, &prim));
    333   CALL(s3d_primitive_get_attrib(&prim, S3D_POSITION, st, &attr_P));
    334   CALL(s3d_primitive_get_attrib(&prim, S3D_GEOMETRY_NORMAL, st, &attr_N));
    335   #undef CALL
    336 
    337   vtx.P[0] = attr_P.value[0];
    338   vtx.P[1] = attr_P.value[1];
    339   vtx.P[2] = attr_P.value[2];
    340   vtx.time = NaN;
    341   hit.normal[0] = attr_N.value[0];
    342   hit.normal[1] = attr_N.value[1];
    343   hit.normal[2] = attr_N.value[2];
    344   hit.distance = 0;
    345   hit.prim = prim;
    346 
    347   setup_interface_fragment_3d(frag, &vtx, &hit, side);
    348 
    349 exit:
    350   return res;
    351 error:
    352   *frag = SDIS_INTERFACE_FRAGMENT_NULL;
    353   goto exit;
    354 }
    355