sadist_lib_solid_sphere.c (11049B)
1 /* Copyright (C) 2024 |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 <stardis/stardis-prog-properties.h> 17 18 #include <star/s3d.h> 19 #include <star/ssp.h> 20 #include <star/sstl.h> 21 22 #include <rsys/cstr.h> 23 #include <rsys/double3.h> 24 #include <rsys/mem_allocator.h> 25 26 #include <getopt.h> 27 28 struct args { 29 const char* stl; 30 double lambda; /* [W/m/K] */ 31 double rho; /* [kg/m^3] */ 32 double cp; /* [J/K/kg] */ 33 double radius; /* [m/fp_to_meter] */ 34 }; 35 #define ARGS_DEFAULT__ {NULL,1,1,1,1} 36 static const struct args ARGS_DEFAULT = ARGS_DEFAULT__; 37 38 /* Define a solid sphere */ 39 struct solid_sphere { 40 struct s3d_scene_view* view; 41 double lambda; /* [W/m/K] */ 42 double rho; /* [kg/m^3] */ 43 double cp; /* [J/K/kg] */ 44 double radius; /* [m/fp_to_meter] */ 45 }; 46 #define SOLID_SPHERE_NULL__ {NULL,0,0,0,0} 47 static const struct solid_sphere SOLID_SPHERE_NULL = SOLID_SPHERE_NULL__; 48 49 /******************************************************************************* 50 * Helper functions 51 ******************************************************************************/ 52 static void 53 get_indices(const unsigned itri, unsigned ids[3], void* ctx) 54 { 55 const struct sstl_desc* desc = ctx; 56 ASSERT(desc && itri < desc->triangles_count); 57 ids[0] = desc->indices[itri*3+0]; 58 ids[1] = desc->indices[itri*3+1]; 59 ids[2] = desc->indices[itri*3+2]; 60 } 61 62 static void 63 get_position(const unsigned ivert, float pos[3], void* ctx) 64 { 65 const struct sstl_desc* desc = ctx; 66 ASSERT(desc && ivert < desc->vertices_count); 67 pos[0] = desc->vertices[ivert*3+0]; 68 pos[1] = desc->vertices[ivert*3+1]; 69 pos[2] = desc->vertices[ivert*3+2]; 70 } 71 72 static struct s3d_scene_view* 73 create_scene_view(const char* filename) 74 { 75 /* Star-STL */ 76 struct sstl_desc desc; 77 struct sstl* sstl = NULL; 78 79 /* Star3D */ 80 struct s3d_vertex_data vdata = S3D_VERTEX_DATA_NULL; 81 struct s3d_device* dev = NULL; 82 struct s3d_scene* scn = NULL; 83 struct s3d_shape* shape = NULL; 84 struct s3d_scene_view* view = NULL; 85 86 res_T res = RES_OK; 87 ASSERT(filename); 88 89 if((res = sstl_create(NULL, NULL, 1, &sstl)) != RES_OK) goto error; 90 if((res = sstl_load(sstl, filename)) != RES_OK) goto error; 91 if((res = sstl_get_desc(sstl, &desc)) != RES_OK) goto error; 92 93 if((res = s3d_device_create(NULL, NULL, 0, &dev)) != RES_OK) goto error; 94 if((res = s3d_scene_create(dev, &scn)) != RES_OK) goto error; 95 if((res = s3d_shape_create_mesh(dev, &shape)) != RES_OK) goto error; 96 if((res = s3d_scene_attach_shape(scn, shape)) != RES_OK) goto error; 97 98 vdata.usage = S3D_POSITION; 99 vdata.type = S3D_FLOAT3; 100 vdata.get = get_position; 101 res = s3d_mesh_setup_indexed_vertices(shape, 102 (unsigned int)desc.triangles_count, get_indices, 103 (unsigned int)desc.vertices_count, &vdata, 1, &desc); 104 if(res != RES_OK) goto error; 105 106 res = s3d_scene_view_create(scn, S3D_TRACE|S3D_GET_PRIMITIVE, &view); 107 if(res != RES_OK) goto error; 108 109 exit: 110 if(sstl) SSTL(ref_put(sstl)); 111 if(dev) S3D(device_ref_put(dev)); 112 if(scn) S3D(scene_ref_put(scn)); 113 if(shape) S3D(shape_ref_put(shape)); 114 return view; 115 error: 116 if(view) { S3D(scene_view_ref_put(view)); view = NULL; } 117 goto exit; 118 } 119 120 static void 121 print_usage(FILE* stream, const char* name) 122 { 123 ASSERT(name); 124 fprintf(stream, 125 "usage: %s -m mesh [-c capa] [-h] [-l lambda] [-R radius] [-r rho]\n", 126 name); 127 } 128 129 static res_T 130 parse_args 131 (const struct stardis_description_create_context* ctx, 132 struct args* args, 133 const int argc, 134 char* argv[]) 135 { 136 int opt = 0; 137 res_T res = RES_OK; 138 139 /* Check pre-conditions */ 140 ASSERT(ctx && args); 141 *args = ARGS_DEFAULT; 142 143 optind = 1; 144 while((opt = getopt(argc, argv, "c:hl:m:R:r:")) != -1) { 145 switch(opt) { 146 case 'c': 147 res = cstr_to_double(optarg, &args->cp); 148 if(res == RES_OK && args->cp <= 0) res = RES_BAD_ARG; 149 break; 150 case 'h': 151 print_usage(stdout, argv[0]); 152 break; 153 case 'l': 154 res = cstr_to_double(optarg, &args->lambda); 155 if(res == RES_OK && args->lambda <= 0) res = RES_BAD_ARG; 156 break; 157 case 'm': 158 args->stl = optarg; 159 break; 160 case 'R': 161 res = cstr_to_double(optarg, &args->radius); 162 if(res == RES_OK && args->radius <= 0) res = RES_BAD_ARG; 163 break; 164 case 'r': 165 res = cstr_to_double(optarg, &args->rho); 166 if(res == RES_OK && args->rho <= 0) res = RES_BAD_ARG; 167 break; 168 default: res = RES_BAD_ARG; break; 169 } 170 if(res != RES_OK) { 171 if(optarg) { 172 fprintf(stderr, "%s: invalid option argument '%s' -- '%c'\n", 173 ctx->name, optarg, opt); 174 } 175 goto error; 176 } 177 } 178 179 if(!args->stl) { 180 fprintf(stderr, "%s: missing mesh -- option '-m'\n", argv[0]); 181 res = RES_BAD_ARG; 182 goto error; 183 } 184 185 exit: 186 return res; 187 error: 188 goto exit; 189 } 190 191 /******************************************************************************* 192 * Create data 193 ******************************************************************************/ 194 void* 195 stardis_create_data 196 (const struct stardis_description_create_context *ctx, 197 void* libdata, 198 size_t argc, 199 char* argv[]) 200 { 201 struct args args = ARGS_DEFAULT__; 202 struct solid_sphere* solid = NULL; 203 res_T res = RES_OK; 204 (void)libdata; 205 206 solid = mem_alloc(sizeof(*solid)); 207 if(!solid) { 208 fprintf(stderr, "%s:%d: error allocating the solid sphere.\n", 209 __FILE__, __LINE__); 210 goto error; 211 } 212 *solid = SOLID_SPHERE_NULL; 213 214 res = parse_args(ctx, &args, (int)argc, argv); 215 if(res != RES_OK) goto error; 216 217 solid->lambda = args.lambda; 218 solid->rho = args.rho; 219 solid->cp = args.cp; 220 solid->radius = args.radius; 221 222 if(!(solid->view = create_scene_view(args.stl))) goto error; 223 224 exit: 225 return solid; 226 error: 227 if(solid) { 228 stardis_release_data(solid); 229 solid = NULL; 230 } 231 goto exit; 232 } 233 234 void 235 stardis_release_data(void* data) 236 { 237 struct solid_sphere* solid = data; 238 ASSERT(solid); 239 if(solid->view) S3D(scene_view_ref_put(solid->view)); 240 mem_rm(solid); 241 } 242 243 /******************************************************************************* 244 * Solid properties 245 ******************************************************************************/ 246 double 247 stardis_calorific_capacity(const struct stardis_vertex* vtx, void* data) 248 { 249 const struct solid_sphere* sphere = data; 250 (void)vtx; 251 return sphere->cp; 252 } 253 254 double 255 stardis_volumic_mass(const struct stardis_vertex* vtx, void* data) 256 { 257 const struct solid_sphere* sphere = data; 258 (void)vtx; 259 return sphere->rho; 260 } 261 262 double 263 stardis_conductivity(const struct stardis_vertex* vtx, void* data) 264 { 265 const struct solid_sphere* sphere = data; 266 (void)vtx; 267 return sphere->lambda; 268 } 269 270 double 271 stardis_delta_solid(const struct stardis_vertex* vtx, void* data) 272 { 273 const struct solid_sphere* sphere = data; 274 (void)vtx; 275 return sphere->radius/20.0; 276 } 277 278 double 279 stardis_volumic_power(const struct stardis_vertex* vtx, void* data) 280 { 281 (void)vtx, (void)data; 282 return STARDIS_VOLUMIC_POWER_NONE; 283 } 284 285 double 286 stardis_medium_temperature(const struct stardis_vertex* vtx, void* data) 287 { 288 (void)vtx, (void)data; 289 return STARDIS_TEMPERATURE_NONE; 290 } 291 292 int 293 stardis_sample_conductive_path 294 (struct sdis_scene* scn, 295 struct ssp_rng* rng, 296 struct stardis_path* path, 297 void* data) 298 { 299 const struct solid_sphere* sphere = data; 300 struct s3d_hit hit = S3D_HIT_NULL; 301 struct s3d_attrib attr0, attr1, attr2; 302 303 double pos[3]; 304 double epsilon = 0; 305 ASSERT(scn && rng && path && data); 306 (void)scn; 307 308 epsilon = sphere->radius * 1.e-6; /* Epsilon shell */ 309 310 d3_set(pos, path->vtx.P); 311 312 do { 313 /* Distance from the geometry center to the current position */ 314 const double dst = d3_len(pos); 315 316 double dir[3] = {0,0,0}; 317 double r = 0; /* Radius */ 318 319 r = sphere->radius - dst; 320 CHK(dst > 0); 321 322 if(r > epsilon) { 323 /* Uniformly sample a new position on the surrounding sphere */ 324 ssp_ran_sphere_uniform(rng, dir, NULL); 325 326 /* Move to the new position */ 327 d3_muld(dir, dir, r); 328 d3_add(pos, pos, dir); 329 330 /* The current position is in the epsilon shell: 331 * move it to the nearest interface position */ 332 } else { 333 float posf[3]; 334 335 d3_set(dir, pos); 336 d3_normalize(dir, dir); 337 d3_muld(pos, dir, sphere->radius); 338 339 /* Map the position to the sphere geometry */ 340 f3_set_d3(posf, pos); 341 S3D(scene_view_closest_point(sphere->view, posf, (float)INF, NULL, &hit)); 342 } 343 344 /* The calculation is performed in steady state, so the path necessarily stops 345 * at a boundary */ 346 } while(S3D_HIT_NONE(&hit)); 347 348 /* Setup the path state */ 349 d3_set(path->vtx.P, pos); 350 path->weight = 0; 351 path->at_limit = 0; 352 353 /* Configure the intersecting primitive. The vertices must be exactly the same 354 * (i.e. bit-compatible) as those used internally by Stardis, as they are used 355 * as the key to retrieve the corresponding Stardis triangle. Note that 356 * Stardis also uses Star-STL internally to load its geometry. As a result, 357 * the in-memory representation of the loaded data is the same between Stardis 358 * and the current code, i.e. single-precision floating point. And Star-3D 359 * also uses the same representation. We can therefore use Star-3D data 360 * directly to define the coordinates of the vertices of the intersecting 361 * primitive */ 362 S3D(triangle_get_vertex_attrib(&hit.prim, 0, S3D_POSITION, &attr0)); 363 S3D(triangle_get_vertex_attrib(&hit.prim, 1, S3D_POSITION, &attr1)); 364 S3D(triangle_get_vertex_attrib(&hit.prim, 2, S3D_POSITION, &attr2)); 365 d3_set_f3(path->tri.vtx0, attr0.value); 366 d3_set_f3(path->tri.vtx1, attr1.value); 367 d3_set_f3(path->tri.vtx2, attr2.value); 368 369 return RES_OK; 370 } 371 372 /******************************************************************************* 373 * Legal notices 374 ******************************************************************************/ 375 const char* 376 get_copyright_notice(void* data) 377 { 378 (void)data; /* Avoid "unused variable" warnings */ 379 return "Copyright (C) 2024 |Méso|Star> (contact@meso-star.com)"; 380 } 381 382 const char* 383 get_license_short(void* data) 384 { 385 (void)data; /* Avoid "unused variable" warnings */ 386 return "GNU GPL version 3 or later <http://www.gnu.org/licenses/>"; 387 } 388 389 const char* 390 get_license_text(void* data) 391 { 392 (void)data; /* Avoid "unused variable" warnings */ 393 return 394 "This is free software released under the GPL v3+ license: GNU GPL\n" 395 "version 3 or later. You are welcome to redistribute it under certain\n" 396 "conditions; refer to <http://www.gnu.org/licenses/> for details."; 397 }