stardis-solver

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

commit 06dd9e032859f25f0ace8f6951ff4fb197536fef
parent e09b940a13509665828e227f55dcd99720353c0a
Author: Vincent Forest <vincent.forest@meso-star.com>
Date:   Mon,  4 Apr 2022 15:01:35 +0200

Add the test_sdis_flux2 test

It tests the imposition of a net boundary flux in combination with other
boundary conditions.

Diffstat:
Mcmake/CMakeLists.txt | 1+
Asrc/test_sdis_flux2.c | 542+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 543 insertions(+), 0 deletions(-)

diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt @@ -212,6 +212,7 @@ if(NOT NO_TEST) new_test(test_sdis_data) new_test(test_sdis_device) new_test(test_sdis_flux) + new_test(test_sdis_flux2) new_test(test_sdis_interface) new_test(test_sdis_medium) new_test(test_sdis_picard) diff --git a/src/test_sdis_flux2.c b/src/test_sdis_flux2.c @@ -0,0 +1,542 @@ +/* Copyright (C) 2016-2022 |Meso|Star> (contact@meso-star.com) + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. */ + +#include "sdis.h" +#include "test_sdis_utils.h" + +#define UNKNOWN_TEMPERATURE -1 + +/* This test consists in solving the temperature profile in a solid slab + * surrounded by two different convective and radiative temperatures. The + * conductivity of the solid material is known, as well as its thickness. A net + * flux is fixed on the left side of the slab. + * + * + * Y ////(0.1,1,1) 280K + * | +----------+-------+ (1.1,1,1) + * o--- X /##########/'E=1 /| + * / +----------+-------+ | + * Z /_ |##########|*' _\ | | + * ---> \ \ E=1|##########|*'/ / |280K + * 320K-> \__/ |##########|*'\__/ | | + * ---> 330K |##########|*'290K | | + * --\|##########|*+.... |.+ + * 10000W.m^-2 --/|##########|/ |/ + * (-1,-1,-1) +----------+-------+ + * (0,-1,-1)/////// 280K + * + */ + +enum interface_type { + ADIABATIC, + FIXED_TEMPERATURE, + SOLID_FLUID_WITH_FLUX, + SOLID_FLUID, + INTERFACES_COUNT__ +}; + +struct probe { + double x; + double time; + double ref; /* Analytically computed temperature */ +}; + +/******************************************************************************* + * Geometry + ******************************************************************************/ +struct geometry { + const double* positions; + const size_t* indices; + struct sdis_interface** interfaces; +}; + +static const double vertices_3d[12/*#vertices*/*3/*#coords per vertex*/] = { + 0.0,-1.0,-1.0, + 0.1,-1.0,-1.0, + 0.0, 1.0,-1.0, + 0.1, 1.0,-1.0, + 0.0,-1.0, 1.0, + 0.1,-1.0, 1.0, + 0.0, 1.0, 1.0, + 0.1, 1.0, 1.0, + 1.1,-1.0,-1.0, + 1.1, 1.0,-1.0, + 1.1,-1.0, 1.0, + 1.1, 1.0, 1.0 +}; +static const size_t nvertices_3d = sizeof(vertices_3d) / (sizeof(double)*3); + +static const size_t indices_3d[22/*#triangles*/*3/*#indices per triangle*/] = { + 0, 2, 1, 1, 2, 3, /* Solid -Z */ + 0, 4, 2, 2, 4, 6, /* Solid -X */ + 4, 5, 6, 6, 5, 7, /* Solid +Z */ + 3, 7, 1, 1, 7, 5, /* Solid +X */ + 2, 6, 3, 3, 6, 7, /* Solid +Y */ + 0, 1, 4, 4, 1, 5, /* Solid -Y */ + + 1, 3, 8, 8, 3, 9, /* Right fluid -Z */ + 5, 10, 7, 7, 10, 11, /* Right fluid +Z */ + 9, 11, 8, 8, 11, 10, /* Right fluid +X */ + 3, 7, 9, 9, 7, 11, /* Right fluid +Y */ + 1, 8, 5, 5, 8, 10 /* Right fluid -Y */ +}; +static const size_t nprimitives_3d = sizeof(indices_3d) / (sizeof(size_t)*3); + +static void +get_indices_3d(const size_t itri, size_t ids[3], void* ctx) +{ + struct geometry* geom = ctx; + CHK(ctx != NULL); + ids[0] = geom->indices[itri*3+0]; + ids[1] = geom->indices[itri*3+1]; + ids[2] = geom->indices[itri*3+2]; +} + +static void +get_position_3d(const size_t ivert, double pos[3], void* ctx) +{ + struct geometry* geom = ctx; + CHK(ctx != NULL); + pos[0] = geom->positions[ivert*3+0]; + pos[1] = geom->positions[ivert*3+1]; + pos[2] = geom->positions[ivert*3+2]; +} + +static void +get_interface(const size_t iprim, struct sdis_interface** bound, void* ctx) +{ + struct geometry* geom = ctx; + CHK(ctx != NULL); + *bound = geom->interfaces[iprim]; +} + +/******************************************************************************* + * Solid media + ******************************************************************************/ +struct solid { + double lambda; + double rho; + double cp; + double volumic_power; +}; + +static double +solid_get_calorific_capacity + (const struct sdis_rwalk_vertex* vtx, struct sdis_data* data) +{ + const struct solid* solid = sdis_data_cget(data); + CHK(vtx && solid); + return solid->cp; +} + +static double +solid_get_thermal_conductivity + (const struct sdis_rwalk_vertex* vtx, struct sdis_data* data) +{ + const struct solid* solid = sdis_data_cget(data); + CHK(vtx && solid); + return solid->lambda; +} + +static double +solid_get_volumic_mass + (const struct sdis_rwalk_vertex* vtx, struct sdis_data* data) +{ + const struct solid* solid = sdis_data_cget(data); + CHK(vtx && solid); + return solid->rho; +} + +static double +solid_get_delta + (const struct sdis_rwalk_vertex* vtx, struct sdis_data* data) +{ + CHK(vtx && data); + return 0.005; +} + +static double +solid_get_temperature + (const struct sdis_rwalk_vertex* vtx, struct sdis_data* data) +{ + const struct solid* solid = sdis_data_cget(data); + CHK(vtx && solid); + + if(vtx->time > 0) { + return UNKNOWN_TEMPERATURE; + } else { + /* The initial temperature is a linear profile between T1 and T2, where T1 + * and T2 are the temperature on the left and right slab boundary, + * respectively. */ + const double T1 = 306.334; + const double T2 = 294.941; + const double u = CLAMP(vtx->P[0] / 0.1, 0.0, 1.0); + return u*(T2 - T1) + T1; + } +} + +static void +create_solid + (struct sdis_device* dev, + const struct solid* solid_props, + struct sdis_medium** solid) +{ + struct sdis_data* data = NULL; + struct sdis_solid_shader shader = SDIS_SOLID_SHADER_NULL; + CHK(dev && solid_props && solid); + + OK(sdis_data_create + (dev, sizeof(struct solid), ALIGNOF(struct solid), NULL, &data)); + memcpy(sdis_data_get(data), solid_props, sizeof(struct solid)); + shader.calorific_capacity = solid_get_calorific_capacity; + shader.thermal_conductivity = solid_get_thermal_conductivity; + shader.volumic_mass = solid_get_volumic_mass; + shader.delta = solid_get_delta; + shader.temperature = solid_get_temperature; + OK(sdis_solid_create(dev, &shader, data, solid)); + OK(sdis_data_ref_put(data)); +} + +/******************************************************************************* + * Fluid media + ******************************************************************************/ +struct fluid { + double temperature; +}; + +static double +fluid_get_temperature + (const struct sdis_rwalk_vertex* vtx, struct sdis_data* data) +{ + const struct fluid* fluid = sdis_data_cget(data); + CHK(vtx && fluid); + return fluid->temperature; +} + +static void +create_fluid + (struct sdis_device* dev, + const struct fluid* fluid_props, + struct sdis_medium** fluid) +{ + struct sdis_data* data = NULL; + struct sdis_fluid_shader shader = DUMMY_FLUID_SHADER; + CHK(dev && fluid_props && fluid); + + OK(sdis_data_create + (dev, sizeof(struct fluid), ALIGNOF(struct fluid), NULL, &data)); + memcpy(sdis_data_get(data), fluid_props, sizeof(struct fluid)); + shader.temperature = fluid_get_temperature; + OK(sdis_fluid_create(dev, &shader, data, fluid)); + OK(sdis_data_ref_put(data)); +} + +/******************************************************************************* + * Interface + ******************************************************************************/ +struct interf { + double h; + double emissivity; + double phi; + double temperature; + double Tref; +}; + +static double +interface_get_temperature + (const struct sdis_interface_fragment* frag, struct sdis_data* data) +{ + const struct interf* interf = sdis_data_cget(data); + CHK(frag && data); + return interf->temperature; +} + +static double +interface_get_reference_temperature + (const struct sdis_interface_fragment* frag, struct sdis_data* data) +{ + const struct interf* interf = sdis_data_cget(data); + CHK(frag && interf); + return interf->Tref; +} + +static double +interface_get_convection_coef + (const struct sdis_interface_fragment* frag, struct sdis_data* data) +{ + const struct interf* interf = sdis_data_cget(data); + CHK(frag && interf); + return interf->h; +} + +static double +interface_get_emissivity + (const struct sdis_interface_fragment* frag, struct sdis_data* data) +{ + const struct interf* interf = sdis_data_cget(data); + CHK(frag && interf); + return interf->emissivity; +} + +static double +interface_get_specular_fraction + (const struct sdis_interface_fragment* frag, struct sdis_data* data) +{ + CHK(frag && data); + return 0; /* Unused */ +} + +static double +interface_get_flux + (const struct sdis_interface_fragment* frag, struct sdis_data* data) +{ + const struct interf* interf = sdis_data_cget(data); + CHK(frag && interf); + return interf->phi; +} + +static void +create_interface + (struct sdis_device* dev, + struct sdis_medium* front, + struct sdis_medium* back, + const struct interf* interf, + struct sdis_interface** out_interf) +{ + struct sdis_interface_shader shader = SDIS_INTERFACE_SHADER_NULL; + struct sdis_data* data = NULL; + + CHK(interf != NULL); + + shader.front.temperature = interface_get_temperature; + shader.back.temperature = interface_get_temperature; + shader.front.flux = interface_get_flux; + shader.back.flux = interface_get_flux; + + if(sdis_medium_get_type(front) != sdis_medium_get_type(back)) { + shader.convection_coef = interface_get_convection_coef; + } + if(sdis_medium_get_type(front) == SDIS_FLUID) { + shader.front.emissivity = interface_get_emissivity; + shader.front.specular_fraction = interface_get_specular_fraction; + shader.front.reference_temperature = interface_get_reference_temperature; + } + if(sdis_medium_get_type(back) == SDIS_FLUID) { + shader.back.emissivity = interface_get_emissivity; + shader.back.specular_fraction = interface_get_specular_fraction; + shader.back.reference_temperature = interface_get_reference_temperature; + } + shader.convection_coef_upper_bound = MMAX(0, interf->h); + + OK(sdis_data_create + (dev, sizeof(struct interf), ALIGNOF(struct interf), NULL, &data)); + memcpy(sdis_data_get(data), interf, sizeof(*interf)); + + OK(sdis_interface_create(dev, front, back, &shader, data, out_interf)); + OK(sdis_data_ref_put(data)); +} + +/******************************************************************************* + * Create scene + ******************************************************************************/ +static void +create_scene_3d + (struct sdis_device* dev, + struct sdis_interface* interfaces[INTERFACES_COUNT__], + struct sdis_scene** scn) +{ + struct geometry geom; + struct sdis_interface* prim_interfaces[32]; + struct sdis_scene_create_args scn_args = SDIS_SCENE_CREATE_ARGS_DEFAULT; + + CHK(dev && interfaces && scn); + + /* Setup the per primitive interface of the solid medium */ + prim_interfaces[0] = prim_interfaces[1] = interfaces[ADIABATIC]; + prim_interfaces[2] = prim_interfaces[3] = interfaces[SOLID_FLUID_WITH_FLUX]; + prim_interfaces[4] = prim_interfaces[5] = interfaces[ADIABATIC]; + prim_interfaces[6] = prim_interfaces[7] = interfaces[SOLID_FLUID]; + prim_interfaces[8] = prim_interfaces[9] = interfaces[ADIABATIC]; + prim_interfaces[10] = prim_interfaces[11] = interfaces[ADIABATIC]; + + /* Setup the per primitive interface for the right fluid */ + prim_interfaces[12] = prim_interfaces[13] = interfaces[FIXED_TEMPERATURE]; + prim_interfaces[14] = prim_interfaces[15] = interfaces[FIXED_TEMPERATURE]; + prim_interfaces[16] = prim_interfaces[17] = interfaces[FIXED_TEMPERATURE]; + prim_interfaces[18] = prim_interfaces[19] = interfaces[FIXED_TEMPERATURE]; + prim_interfaces[20] = prim_interfaces[21] = interfaces[FIXED_TEMPERATURE]; + + /* Create the scene */ + geom.positions = vertices_3d; + geom.indices = indices_3d; + geom.interfaces = prim_interfaces; + scn_args.get_indices = get_indices_3d; + scn_args.get_interface = get_interface; + scn_args.get_position = get_position_3d; + scn_args.nprimitives = nprimitives_3d; + scn_args.nvertices = nvertices_3d; + scn_args.t_range[0] = 300; + scn_args.t_range[1] = 300; + scn_args.context = &geom; + scn_args.trad.temperature = 320; + scn_args.trad.reference = 300; + OK(sdis_scene_create(dev, &scn_args, scn)); +} + +/******************************************************************************* + * Helper functions + ******************************************************************************/ +static void +check(struct sdis_scene* scn, const struct probe* probe) +{ + struct sdis_solve_probe_args args = SDIS_SOLVE_PROBE_ARGS_DEFAULT; + struct sdis_estimator* estimator = NULL; + struct sdis_mc T = SDIS_MC_NULL; + + CHK(scn && probe); + + args.nrealisations = 10000; + args.picard_order = 1; + args.position[0] = probe->x; + args.position[1] = 0; + args.position[2] = 0; + args.time_range[0] = probe->time; + args.time_range[1] = probe->time; + + OK(sdis_solve_probe(scn, &args, &estimator)); + OK(sdis_estimator_get_temperature(estimator, &T)); + OK(sdis_estimator_ref_put(estimator)); + + printf("Temperature at x=%g, t=%g: %g ~ %g +/- %g\n", + probe->x, probe->time, probe->ref, T.E, T.SE); + + CHK(eq_eps(probe->ref, T.E, T.SE*3)); +} + +/******************************************************************************* + * Test + ******************************************************************************/ +int +main(int argc, char** argv) +{ + struct sdis_device* dev = NULL; + struct sdis_scene* scn_3d = NULL; + struct sdis_medium* solid = NULL; + struct sdis_medium* dummy = NULL; + struct sdis_medium* fluid1 = NULL; + struct sdis_medium* fluid2 = NULL; + struct sdis_interface* interfaces[INTERFACES_COUNT__]; + + struct solid solid_props; + struct fluid fluid_props; + struct interf interf_props; + + const struct probe probes[] = { + {0.01, 1000.0, 481.72005748728628}, + {0.05, 1000.0, 335.19469995601020}, + {0.09, 1000.0, 299.94436943411478}, + {0.01, 2000.0, 563.21759568607558}, + {0.05, 2000.0, 392.79827670626440}, + {0.09, 2000.0, 324.89742556243448}, + {0.01, 3000.0, 620.25242712533577}, + {0.05, 3000.0, 444.73414407361213}, + {0.09, 3000.0, 359.44045704073852}, + {0.01, 4000.0, 665.65935222224493}, + {0.05, 4000.0, 490.32470982110840}, + {0.09, 4000.0, 393.89924931902408}, + {0.01, 10000.0, 830.44439052891505}, + {0.05, 10000.0, 664.82771620162805}, + {0.09, 10000.0, 533.92442748613928} + }; + const size_t nprobes = sizeof(probes)/sizeof(*probes); + size_t iprobe; + + (void)argc, (void)argv; + + OK(sdis_device_create(&SDIS_DEVICE_CREATE_ARGS_DEFAULT, &dev)); + + /* Solid medium */ + solid_props.lambda = 1.15; + solid_props.rho = 1700; + solid_props.cp = 800; + create_solid(dev, &solid_props, &solid); + + /* Dummy solid medium */ + solid_props.lambda = 0; + solid_props.rho = 1700; + solid_props.cp = 800; + create_solid(dev, &solid_props, &dummy); + + /* Fluid media */ + fluid_props.temperature = 330; + create_fluid(dev, &fluid_props, &fluid1); + fluid_props.temperature = 290; + create_fluid(dev, &fluid_props, &fluid2); + + /* Adiabatic interfaces */ + interf_props.h = 0; + interf_props.emissivity = 0; + interf_props.phi = SDIS_FLUX_NONE; + interf_props.temperature = UNKNOWN_TEMPERATURE; + interf_props.Tref = UNKNOWN_TEMPERATURE; + create_interface(dev, solid, dummy, &interf_props, &interfaces[ADIABATIC]); + + /* Interfaces with a fixed temperature */ + interf_props.h = 1; + interf_props.emissivity = 1; + interf_props.phi = SDIS_FLUX_NONE; + interf_props.temperature = 280; + interf_props.Tref = 300; + create_interface + (dev, fluid2, dummy, &interf_props, &interfaces[FIXED_TEMPERATURE]); + + /* Interfaces with a fixed flux */ + interf_props.h = 2; + interf_props.emissivity = 1; + interf_props.phi = 10000; + interf_props.temperature = UNKNOWN_TEMPERATURE; + interf_props.Tref = 300; + create_interface + (dev, solid, fluid1, &interf_props, &interfaces[SOLID_FLUID_WITH_FLUX]); + + interf_props.h = 8; + interf_props.emissivity = 1; + interf_props.phi = SDIS_FLUX_NONE; + interf_props.temperature = UNKNOWN_TEMPERATURE; + interf_props.Tref = 300; + create_interface + (dev, solid, fluid2, &interf_props, &interfaces[SOLID_FLUID]); + + create_scene_3d(dev, interfaces, &scn_3d); + + FOR_EACH(iprobe, 0, nprobes) { + check(scn_3d, &probes[iprobe]); + } + + /* Release memory */ + OK(sdis_scene_ref_put(scn_3d)); + OK(sdis_medium_ref_put(solid)); + OK(sdis_medium_ref_put(dummy)); + OK(sdis_medium_ref_put(fluid1)); + OK(sdis_medium_ref_put(fluid2)); + OK(sdis_interface_ref_put(interfaces[ADIABATIC])); + OK(sdis_interface_ref_put(interfaces[FIXED_TEMPERATURE])); + OK(sdis_interface_ref_put(interfaces[SOLID_FLUID_WITH_FLUX])); + OK(sdis_interface_ref_put(interfaces[SOLID_FLUID])); + OK(sdis_device_ref_put(dev)); + + CHK(mem_allocated_size() == 0); + return 0; +}