test_sdis_draw_external_flux.c (13831B)
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 "test_sdis_mesh.h" 18 #include "test_sdis_utils.h" 19 20 #include <star/s3dut.h> 21 22 #define IMG_WIDTH 320 23 #define IMG_HEIGHT 240 24 #define IMG_SPP 64 25 #define SOURCE_POWER 30e6 /* W */ 26 #define EMISSIVITY 0.5 27 #define T_RAD 300 /* [K] */ 28 #define T_REF 300 /* [K] */ 29 30 /* 31 * The system consists of a floor (i.e. a parallelepiped), a super-form floating 32 * above it and a spherical external source. The test attempts to render the 33 * scene and thus verify the entire sampling of conductive-radiative paths 34 * coupled to an external flux from the external source. 35 */ 36 37 /******************************************************************************* 38 * Geometries 39 ******************************************************************************/ 40 static void 41 mesh_add_super_shape(struct mesh* mesh) 42 { 43 struct s3dut_mesh* sshape = NULL; 44 struct s3dut_mesh_data sshape_data; 45 struct s3dut_super_formula f0 = S3DUT_SUPER_FORMULA_NULL; 46 struct s3dut_super_formula f1 = S3DUT_SUPER_FORMULA_NULL; 47 const double radius = 1; 48 const unsigned nslices = 256; 49 50 f0.A = 1.5; f0.B = 1; f0.M = 11.0; f0.N0 = 1; f0.N1 = 1; f0.N2 = 2.0; 51 f1.A = 1.0; f1.B = 2; f1.M = 3.6; f1.N0 = 1; f1.N1 = 2; f1.N2 = 0.7; 52 OK(s3dut_create_super_shape(NULL, &f0, &f1, radius, nslices, nslices/2, &sshape)); 53 OK(s3dut_mesh_get_data(sshape, &sshape_data)); 54 mesh_append(mesh, sshape_data.positions, sshape_data.nvertices, 55 sshape_data.indices, sshape_data.nprimitives, NULL); 56 OK(s3dut_mesh_ref_put(sshape)); 57 } 58 59 static void 60 mesh_add_ground(struct mesh* mesh) 61 { 62 #define DEPTH 2.0 63 const double translate[3] = {0, 0, -DEPTH-1}; 64 65 struct s3dut_mesh* ground = NULL; 66 struct s3dut_mesh_data ground_data; 67 68 OK(s3dut_create_cuboid(NULL, 20, 20, DEPTH, &ground)); 69 OK(s3dut_mesh_get_data(ground, &ground_data)); 70 mesh_append(mesh, ground_data.positions, ground_data.nvertices, 71 ground_data.indices, ground_data.nprimitives, translate); 72 OK(s3dut_mesh_ref_put(ground)); 73 #undef DEPTH 74 } 75 76 /******************************************************************************* 77 * Media & interface 78 ******************************************************************************/ 79 #define MEDIUM_PROP(Type, Prop, Val) \ 80 static double \ 81 Type##_get_##Prop \ 82 (const struct sdis_rwalk_vertex* vtx, \ 83 struct sdis_data* data) \ 84 { \ 85 (void)vtx, (void)data; /* Avoid the "unused variable" warning */ \ 86 return Val; \ 87 } 88 MEDIUM_PROP(solid, calorific_capacity, 500.0) /* [J/K/Kg] */ 89 MEDIUM_PROP(solid, thermal_conductivity, 25.0) /* [W/m/K] */ 90 MEDIUM_PROP(solid, volumic_mass, 7500.0) /* [kg/m^3] */ 91 MEDIUM_PROP(solid, temperature, 310) /* [K] */ 92 MEDIUM_PROP(solid, delta, 1.0/20.0) /* [m] */ 93 MEDIUM_PROP(fluid, calorific_capacity, 2.0) /* [J/K/Kg] */ 94 MEDIUM_PROP(fluid, volumic_mass, 25.0) /* |kg/m^3] */ 95 MEDIUM_PROP(fluid, temperature, SDIS_TEMPERATURE_NONE) /* [K] */ 96 #undef MEDIUM_PROP 97 98 static struct sdis_medium* 99 create_solid(struct sdis_device* sdis) 100 { 101 struct sdis_solid_shader shader = SDIS_SOLID_SHADER_NULL; 102 struct sdis_medium* solid = NULL; 103 104 shader.calorific_capacity = solid_get_calorific_capacity; 105 shader.thermal_conductivity = solid_get_thermal_conductivity; 106 shader.volumic_mass = solid_get_volumic_mass; 107 shader.delta = solid_get_delta; 108 shader.temperature = solid_get_temperature; 109 OK(sdis_solid_create(sdis, &shader, NULL, &solid)); 110 return solid; 111 } 112 113 static struct sdis_medium* 114 create_fluid(struct sdis_device* sdis) 115 { 116 struct sdis_fluid_shader shader = SDIS_FLUID_SHADER_NULL; 117 struct sdis_medium* fluid = NULL; 118 119 shader.calorific_capacity = fluid_get_calorific_capacity; 120 shader.volumic_mass = fluid_get_volumic_mass; 121 shader.temperature = fluid_get_temperature; 122 OK(sdis_fluid_create(sdis, &shader, NULL, &fluid)); 123 return fluid; 124 } 125 126 static double 127 interface_get_reference_temperature 128 (const struct sdis_interface_fragment* frag, 129 struct sdis_data* data) 130 { 131 (void)frag, (void)data; /* Avoid the "unused variable" warning */ 132 return T_REF; 133 } 134 135 static double 136 interface_get_temperature 137 (const struct sdis_interface_fragment* frag, 138 struct sdis_data* data) 139 { 140 (void)frag, (void)data;/* Avoid the "unused variable" warning */ 141 return SDIS_TEMPERATURE_NONE; 142 } 143 144 static double 145 interface_get_emissivity 146 (const struct sdis_interface_fragment* frag, 147 const unsigned source_id, 148 struct sdis_data* data) 149 { 150 /* Avoid the "unused variable" warning */ 151 (void)frag, (void)source_id, (void)data; 152 return EMISSIVITY; 153 } 154 155 static struct sdis_interface* 156 create_interface 157 (struct sdis_device* sdis, 158 struct sdis_medium* front, 159 struct sdis_medium* back) 160 { 161 struct sdis_interface* interf = NULL; 162 struct sdis_interface_shader shader = SDIS_INTERFACE_SHADER_NULL; 163 164 shader.front.temperature = interface_get_temperature; 165 shader.front.reference_temperature = interface_get_reference_temperature; 166 shader.front.emissivity = interface_get_emissivity; 167 shader.back.temperature = interface_get_temperature; 168 OK(sdis_interface_create(sdis, front, back, &shader, NULL, &interf)); 169 return interf; 170 } 171 172 /******************************************************************************* 173 * External source 174 ******************************************************************************/ 175 static void 176 source_get_position 177 (const double time, 178 double pos[3], 179 struct sdis_data* data) 180 { 181 (void)time, (void)data; /* Avoid the "unusued variable" warning */ 182 pos[0] = 5.0; 183 pos[1] = 5.0; 184 pos[2] = 5.0; 185 } 186 187 static double 188 source_get_power(const double time, struct sdis_data* data) 189 { 190 (void)time, (void)data; /* Avoid the "unusued variable" warning */ 191 return SOURCE_POWER; /* [W] */ 192 } 193 194 static double 195 source_get_diffuse_radiance 196 (const double time, 197 const double dir[3], 198 struct sdis_data* data) 199 { 200 (void)time, (void)data; /* Avoid the "unusued variable" warning */ 201 CHK(d3_is_normalized(dir)); 202 return 50; 203 } 204 205 static struct sdis_source* 206 create_source(struct sdis_device* sdis) 207 { 208 struct sdis_spherical_source_shader shader = SDIS_SPHERICAL_SOURCE_SHADER_NULL; 209 struct sdis_source* source = NULL; 210 211 shader.position = source_get_position; 212 shader.power = source_get_power; 213 shader.diffuse_radiance = source_get_diffuse_radiance; 214 shader.radius = 3e-1; /* [m] */ 215 OK(sdis_spherical_source_create(sdis, &shader, NULL, &source)); 216 return source; 217 } 218 219 /******************************************************************************* 220 * Radiative environment 221 ******************************************************************************/ 222 static double 223 radenv_get_temperature 224 (const struct sdis_radiative_ray* ray, 225 struct sdis_data* data) 226 { 227 (void)ray, (void)data; 228 return T_RAD; 229 } 230 231 static double 232 radenv_get_reference_temperature 233 (const struct sdis_radiative_ray* ray, 234 struct sdis_data* data) 235 { 236 (void)ray, (void)data; 237 return T_REF; 238 } 239 240 static struct sdis_radiative_env* 241 create_radenv(struct sdis_device* sdis) 242 { 243 struct sdis_radiative_env_shader shader = SDIS_RADIATIVE_ENV_SHADER_NULL; 244 struct sdis_radiative_env* radenv = NULL; 245 246 shader.temperature = radenv_get_temperature; 247 shader.reference_temperature = radenv_get_reference_temperature; 248 OK(sdis_radiative_env_create(sdis, &shader, NULL, &radenv)); 249 return radenv; 250 } 251 252 /******************************************************************************* 253 * Scene, i.e. the system to simulate 254 ******************************************************************************/ 255 struct scene_context { 256 const struct mesh* mesh; 257 struct sdis_interface* interf; 258 }; 259 static const struct scene_context SCENE_CONTEXT_NULL = {NULL, NULL}; 260 261 static void 262 scene_get_indices(const size_t itri, size_t ids[3], void* ctx) 263 { 264 struct scene_context* context = ctx; 265 CHK(ids && context && itri < mesh_ntriangles(context->mesh)); 266 ids[0] = (unsigned)context->mesh->indices[itri*3+0]; 267 ids[1] = (unsigned)context->mesh->indices[itri*3+1]; 268 ids[2] = (unsigned)context->mesh->indices[itri*3+2]; 269 } 270 271 static void 272 scene_get_interface(const size_t itri, struct sdis_interface** interf, void* ctx) 273 { 274 struct scene_context* context = ctx; 275 CHK(interf && context && itri < mesh_ntriangles(context->mesh)); 276 *interf = context->interf; 277 } 278 279 static void 280 scene_get_position(const size_t ivert, double pos[3], void* ctx) 281 { 282 struct scene_context* context = ctx; 283 CHK(pos && context && ivert < mesh_nvertices(context->mesh)); 284 pos[0] = context->mesh->positions[ivert*3+0]; 285 pos[1] = context->mesh->positions[ivert*3+1]; 286 pos[2] = context->mesh->positions[ivert*3+2]; 287 } 288 289 static struct sdis_scene* 290 create_scene 291 (struct sdis_device* sdis, 292 const struct mesh* mesh, 293 struct sdis_interface* interf, 294 struct sdis_source* source, 295 struct sdis_radiative_env* radenv) 296 { 297 struct sdis_scene* scn = NULL; 298 struct sdis_scene_create_args scn_args = SDIS_SCENE_CREATE_ARGS_DEFAULT; 299 struct scene_context context = SCENE_CONTEXT_NULL; 300 301 context.mesh = mesh; 302 context.interf = interf; 303 304 scn_args.get_indices = scene_get_indices; 305 scn_args.get_interface = scene_get_interface; 306 scn_args.get_position = scene_get_position; 307 scn_args.nprimitives = mesh_ntriangles(mesh); 308 scn_args.nvertices = mesh_nvertices(mesh); 309 scn_args.t_range[0] = MMIN(T_RAD, T_REF); 310 scn_args.t_range[1] = MMAX(T_RAD, T_REF); 311 scn_args.source = source; 312 scn_args.radenv = radenv; 313 scn_args.context = &context; 314 OK(sdis_scene_create(sdis, &scn_args, &scn)); 315 return scn; 316 } 317 318 /******************************************************************************* 319 * Rendering point of view 320 ******************************************************************************/ 321 static struct sdis_camera* 322 create_camera(struct sdis_device* sdis) 323 { 324 const double pos[3] = {-3.81, 11.23, 5.29}; 325 const double tgt[3] = {-0.46, 0, -0.32}; 326 const double up[3] = {0, 0, 1}; 327 struct sdis_camera* cam = NULL; 328 329 OK(sdis_camera_create(sdis, &cam)); 330 OK(sdis_camera_set_proj_ratio(cam, (double)IMG_WIDTH/(double)IMG_HEIGHT)); 331 OK(sdis_camera_set_fov(cam, MDEG2RAD(30))); 332 OK(sdis_camera_look_at(cam, pos, tgt, up)); 333 return cam; 334 } 335 336 /******************************************************************************* 337 * Draw the submitted scene 338 ******************************************************************************/ 339 /* Write an image in htrdr-image(5) format */ 340 static void 341 write_image(FILE* stream, struct sdis_estimator_buffer* image) 342 { 343 size_t x, y; 344 345 /* Header */ 346 fprintf(stream, "%d %d\n", IMG_WIDTH, IMG_HEIGHT); 347 348 /* Pixels ordered by row */ 349 FOR_EACH(y, 0, IMG_HEIGHT) { 350 FOR_EACH(x, 0, IMG_WIDTH) { 351 const struct sdis_estimator* pixel = NULL; 352 struct sdis_mc temperature = SDIS_MC_NULL; 353 354 OK(sdis_estimator_buffer_at(image, x, y, &pixel)); 355 OK(sdis_estimator_get_temperature(pixel, &temperature)); 356 fprintf(stream, "%g %g 0 0 0 0 0 0\n", temperature.E, temperature.SE); 357 } 358 } 359 } 360 361 static void 362 draw(struct sdis_scene* scn, struct sdis_camera* cam) 363 { 364 struct sdis_solve_camera_args args = SDIS_SOLVE_CAMERA_ARGS_DEFAULT; 365 struct sdis_estimator_buffer* image = NULL; 366 367 args.cam = cam; 368 args.image_definition[0] = IMG_WIDTH; 369 args.image_definition[1] = IMG_HEIGHT; 370 args.spp = IMG_SPP; 371 372 OK(sdis_solve_camera(scn, &args, &image)); 373 write_image(stdout, image); 374 OK(sdis_estimator_buffer_ref_put(image)); 375 } 376 377 /******************************************************************************* 378 * The test 379 ******************************************************************************/ 380 int 381 main(int argc, char** argv) 382 { 383 /* Stardis */ 384 struct sdis_camera* cam = NULL; 385 struct sdis_device* dev = NULL; 386 struct sdis_interface* interf = NULL; 387 struct sdis_medium* fluid = NULL; 388 struct sdis_medium* solid = NULL; 389 struct sdis_scene* scn = NULL; 390 struct sdis_source* source = NULL; 391 struct sdis_radiative_env* radenv = NULL; 392 393 /* Miscellaneous */ 394 struct mesh mesh = MESH_NULL; 395 (void)argc, (void)argv; 396 397 OK(sdis_device_create(&SDIS_DEVICE_CREATE_ARGS_DEFAULT, &dev)); 398 399 mesh_init(&mesh); 400 mesh_add_super_shape(&mesh); 401 mesh_add_ground(&mesh); 402 403 solid = create_solid(dev); 404 fluid = create_fluid(dev); 405 interf = create_interface(dev, fluid, solid); 406 source = create_source(dev); 407 radenv = create_radenv(dev); 408 scn = create_scene(dev, &mesh, interf, source, radenv); 409 cam = create_camera(dev); 410 411 draw(scn, cam); 412 413 /* For debug of scene geometry */ 414 /*dump_mesh(stdout, 415 mesh.positions, mesh_nvertices(&mesh), 416 mesh.indices, mesh_ntriangles(&mesh));*/ 417 418 mesh_release(&mesh); 419 OK(sdis_camera_ref_put(cam)); 420 OK(sdis_device_ref_put(dev)); 421 OK(sdis_interface_ref_put(interf)); 422 OK(sdis_medium_ref_put(fluid)); 423 OK(sdis_medium_ref_put(solid)); 424 OK(sdis_scene_ref_put(scn)); 425 OK(sdis_source_ref_put(source)); 426 OK(sdis_radiative_env_ref_put(radenv)); 427 CHK(mem_allocated_size() == 0); 428 return 0; 429 }