stardis

Perform coupled heat transfer calculations
git clone git://git.meso-star.fr/stardis.git
Log | Files | Refs | README | LICENSE

commit acf60477ba402671ffea2918c29bfcd7e9139e2b
parent 10df8073cc1a3f90a082db9b80b7e47c07c85fec
Author: Vincent Forest <vincent.forest@meso-star.com>
Date:   Mon, 26 Feb 2024 16:30:00 +0100

Merge branch 'feature_solve_probe_list' into develop

Diffstat:
M.gitignore | 2++
MMakefile | 15+++++++++++++--
MREADME.md | 144++++++++++++++++++++++++++++++++++++++++++-------------------------------------
Mcmake/CMakeLists.txt | 55+++++++++++++++++++++++++++++++------------------------
Mcmake/stardis-green-types/CMakeLists.txt | 2+-
Mcmake/stardis-prog-properties/CMakeLists.txt | 2+-
Mconfig.mk | 3+++
Ddoc/stardis-input.5 | 363-------------------------------------------------------------------------------
Adoc/stardis-input.5.in | 367+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mdoc/stardis.1.in | 20++++++++++++++++++++
Msrc/stardis-app.c | 10+++++++---
Msrc/stardis-app.h | 3+++
Msrc/stardis-args.c | 395+++++++++++++++++++++++++++++++++++++++++++++++++------------------------------
Dsrc/stardis-args.h | 141-------------------------------------------------------------------------------
Asrc/stardis-args.h.in | 180+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/stardis-compute-probe-boundary.c | 993+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Msrc/stardis-compute.c | 523++++++++++++++-----------------------------------------------------------------
Msrc/stardis-compute.h | 13+++++++++----
Msrc/stardis-green-types.h.in | 4++--
Msrc/stardis-main.c | 15+++++++++------
Msrc/stardis-output.c | 96++++++++++++++++++++++++++++++++++++++++++++++++++++++++-----------------------
Msrc/stardis-output.h | 46+++++++++++++++++++++++++++++-----------------
Msrc/stardis-prog-properties.h.in | 115+++++++++++++++++++++++++++++++++++++++++++++----------------------------------
23 files changed, 2215 insertions(+), 1292 deletions(-)

diff --git a/.gitignore b/.gitignore @@ -5,9 +5,11 @@ *~ tags .config +src/stardis-args.h src/stardis-default.h src/stardis-green-types.h src/stardis-prog-properties.h src/stardis-version.h stardis doc/stardis.1 +doc/stardis-input.5 diff --git a/Makefile b/Makefile @@ -30,6 +30,7 @@ SRC =\ src/stardis-app.c\ src/stardis-args.c\ src/stardis-compute.c\ + src/stardis-compute-probe-boundary.c\ src/stardis-description.c\ src/stardis-fluid.c\ src/stardis-fluid-prog.c\ @@ -55,6 +56,7 @@ SRC =\ # Headers to configure HDR=\ + src/stardis-args.h\ src/stardis-default.h\ src/stardis-green-types.h\ src/stardis-prog-properties.h\ @@ -110,6 +112,10 @@ src/stardis-default.h: config.mk src/stardis-default.h.in -e 's/@STARDIS_ARGS_DEFAULT_VERBOSE_LEVEL@/$(STARDIS_ARGS_DEFAULT_VERBOSE_LEVEL)/' \ $@.in > $@ +src/stardis-args.h: config.mk src/stardis-args.h.in + sed -e 's/@STARDIS_MAX_NAME_LENGTH@/$(STARDIS_MAX_NAME_LENGTH)/' \ + $@.in > $@ + src/stardis-version.h: config.mk src/stardis-version.h.in sed -e 's/@STARDIS_APP_VERSION_MAJOR@/$(VERSION_MAJOR)/' \ -e 's/@STARDIS_APP_VERSION_MINOR@/$(VERSION_MINOR)/' \ @@ -118,6 +124,7 @@ src/stardis-version.h: config.mk src/stardis-version.h.in src/stardis-green-types.h: config.mk src/stardis-green-types.h.in sed -e 's/@STARDIS_GREEN_TYPES_VERSION@/$(GREEN_TYPES_VERSION)/' \ + -e "s/@STARDIS_MAX_NAME_LENGTH@/$$(($(STARDIS_MAX_NAME_LENGTH)-1))/" \ $@.in > $@ src/stardis-prog-properties.h: config.mk src/stardis-prog-properties.h.in @@ -135,7 +142,7 @@ src/stardis-prog-properties.h: config.mk src/stardis-prog-properties.h.in ################################################################################ # Man pages ################################################################################ -man: doc/stardis.1 +man: doc/stardis.1 doc/stardis-input.5 doc/stardis.1: doc/stardis.1.in sed -e 's/@STARDIS_ARGS_DEFAULT_COMPUTE_TIME@/$(STARDIS_ARGS_DEFAULT_COMPUTE_TIME)/' \ @@ -154,6 +161,10 @@ doc/stardis.1: doc/stardis.1.in -e 's/@STARDIS_ARGS_DEFAULT_VERBOSE_LEVEL@/$(STARDIS_ARGS_DEFAULT_VERBOSE_LEVEL)/' \ $@.in > $@ +doc/stardis-input.5: doc/stardis-input.5.in + sed -e "s/@STARDIS_MAX_NAME_LENGTH@/$$(($(STARDIS_MAX_NAME_LENGTH)-1))/" \ + $@.in > $@ + ################################################################################ # Installation ################################################################################ @@ -180,7 +191,7 @@ uninstall: # Miscellaneous targets ################################################################################ clean: - rm -f $(HDR) $(OBJ) .config stardis doc/stardis.1 + rm -f $(HDR) $(OBJ) .config stardis doc/stardis.1 doc/stardis-input.5 distclean: clean rm -f $(DEP) diff --git a/README.md b/README.md @@ -4,83 +4,88 @@ Stardis is a software dedicated to the resolution of coupled convective-conductive-radiative thermal problems in 3D environments. -It is based on [stardis-solver](https://gitlab.com/meso-star/stardis-solver) -and exposes some of the main features of the solver in an easy to use way. -Using stardis is a practical way of carrying out thermal studies on CAD +It is based on +[Stardis Solver](https://gitlab.com/meso-star/stardis-solver) and +exposes some of the main features of the solver in an easy to use way. +Using Stardis is a practical way of carrying out thermal studies on CAD models which can be exported from Salomé or other similar software. -## How to build - -Stardis relies on the [CMake](http://www.cmake.org) and the -[RCMake](https://gitlab.com/vaplv/rcmake/) package to build. -It also depends on the -[RSys](https://gitlab.com/vaplv/rsys/), -[star-3d](https://gitlab.com/meso-star/star-3d/), -[star-enclosures-3d](https://gitlab.com/meso-star/star-enclosures-3d/), -[star-geometry-3d](https://gitlab.com/meso-star/star-geometry-3d/), -[star-stl](https://gitlab.com/meso-star/star-stl) and -[stardis-solver](https://gitlab.com/meso-star/stardis-solver) libraries -as well as on the [OpenMP](http://www.openmp.org) 2.0 specification to -parallelize its computations. It may depend on -[OpenMPI](https://www.open-mpi.org/) 2.0 if distributed memory parallelism -is enabled via the `ENABLE_MPI` variable of the CMake file. - -First ensure that CMake and a C compiler are installed on your system. -Then install the RCMake package as well as all the aforementioned -prerequisites. Finally generate the project from -the `cmake/CMakeLists.txt` file by appending to the `CMAKE_PREFIX_PATH` -variable the install directories of its dependencies. +## Requirements ## Release notes +- C compiler +- POSIX make +- pkg-config +- Message Passing Interface (optional) +- [mandoc](https://mandoc.bsd.lv) +- [RSys](https://gitlab.com/vaplv/rsys) +- [Star 3D](https://gitlab.com/meso-star/star-3d) +- [Stardis Solver](https://gitlab.com/meso-star/stardis-solver) +- [Star Enclosure 3D](https://gitlab.com/meso-star/star-enclosures-3d) +- [Star Geometry 3D](https://gitlab.com/meso-star/star-geometry-3d) +- [Star SamPling](https://gitlab.com/meso-star/star-sp) +- [Star StL](https://gitlab.com/meso-star/star-stl) + +## Installation + +Edit config.mk as needed, then run: + + make clean install + ### Version 0.9 #### Programmable properties -Until now, physical properties as well as boundary and connection conditions -were constant in time and space. In this version, they can be programmed, i.e. -they are variables returned by functions implemented in user-defined libraries -and submitted as dynamically loaded input libraries when Stardis starts. User -libraries must also provide create/release functions that are invoked at -start-up to allow users to load their data and build the internal data -structures required by their libraries at run-time. +Until now, physical properties as well as boundary and connection +conditions were constant in time and space. In this version, they can be +programmed, i.e. they are variables returned by functions implemented +in user-defined libraries and submitted as dynamically loaded input +libraries when Stardis starts. User libraries must also provide +create/release functions that are invoked at start-up to allow users to +load their data and build the internal data structures required by their +libraries at run-time. The `stardis-input` file format has been updated to provide a set of new `_PROG` suffixed keywords used to define these programmed properties and -conditions (e.g. `T_BOUNDARY_FOR_SOLID_PROG` or `H_BOUNDARY_FOR_FLUID_PROG`) +conditions (e.g. `T_BOUNDARY_FOR_SOLID_PROG` or +`H_BOUNDARY_FOR_FLUID_PROG`) #### Miscellaneous -- Addition of the keyword `HF_BOUNDARY_FOR_SOLID` which allows to impose a flux - on a boundary with another condition. For example, a net flux can be defined - in addition to a convective exchange and a radiative transfer. -- Correct the definition of a net flux as a boundary condition: it might not be - defined on the right side of the interface. -- Correct the "subpath type" data of the output paths: as we attach the segment - type to the vertices, we need to locate the type changes along the path on - zero length segments, otherwise the colouring will show a misleading colour - gradient. -- Replace the Mersenne Twister random number generator with Threefry: the - former is much less efficient at rejecting random numbers than the latter, - which is designed for this purpose, a feature on which parallel random number - generations depend heavily +- Addition of the keyword `HF_BOUNDARY_FOR_SOLID` which allows to impose + a flux on a boundary with another condition. For example, a net flux + can be defined in addition to a convective exchange and a radiative + transfer. +- Correct the definition of a net flux as a boundary condition: it might + not be defined on the right side of the interface. +- Correct the "subpath type" data of the output paths: as we attach the + segment type to the vertices, we need to locate the type changes along + the path on zero length segments, otherwise the colouring will show a + misleading colour gradient. +- Replace the Mersenne Twister random number generator with Threefry: + the former is much less efficient at rejecting random numbers than the + latter, which is designed for this purpose, a feature on which + parallel random number generations depend heavily ### Version 0.8 -- Add a new option to support non-linear radiative transfer computations. -- Changes in input file's format to support non-linear radiative transfer by - adding reference temperatures on interfaces. -- Add optional support for MPI (must be enabled at compile time, default is OFF). +- Add a new option to support non-linear radiative transfer + computations. +- Changes in input file's format to support non-linear radiative + transfer by adding reference temperatures on interfaces. +- Add optional support for MPI (must be enabled at compile time, default + is OFF). - Change random number generator type to use Threefry. -- Change the format of binary Green files. A new public header file is now - installed that describes all types involved in binary Green files. +- Change the format of binary Green files. A new public header file is + now installed that describes all types involved in binary Green files. - Fix a crash on an exit-on-error execution path. - Fix parsing of command-line options. ### Version 0.7.2 -Fix the binary file format of the green function: the fileformat has been -updated without incrementing the version of the serialised data. +Fix the binary file format of the green function: the fileformat has +been updated without incrementing the version of the serialised data. ### Version 0.7.1 @@ -88,10 +93,10 @@ Fix debug build. ### Version 0.7 -- Remove the boundary condition `T_BOUNDARY_FOR_FLUID`: it was exactly the same - than `H_BOUNDARY_FOR_FLUID` that should now be used instead. -- Sets the required version of Star-SampPling to 0.12. This version fixes - compilation errors with gcc 11 but introduces API breaks. +- Remove the boundary condition `T_BOUNDARY_FOR_FLUID`: it was exactly + the same than `H_BOUNDARY_FOR_FLUID` that should now be used instead. +- Sets the required version of Star-SampPling to 0.12. This version + fixes compilation errors with gcc 11 but introduces API breaks. ### Version 0.6 @@ -126,14 +131,15 @@ Fix debug build. ### Version 0.3.2 - Add the `solve_probe_boundary` feature. The `solve_probe_boundary` VS - `solve_probe` selection is automated according the probe-geometry distance. - `solve_probe_boundary` is called for probe points closer than 2.1 delta - from geometry. + `solve_probe` selection is automated according the probe-geometry + distance. `solve_probe_boundary` is called for probe points closer + than 2.1 delta from geometry. - Add flux boundary conditions. ### Version 0.3.1 -Add radiative transfer computations. To achieve this, media gain 2 new parameters: +Add radiative transfer computations. To achieve this, media gain 2 new +parameters: - emissivity; - `specular_fraction`. @@ -142,10 +148,11 @@ Add radiative transfer computations. To achieve this, media gain 2 new parameter - Upgrade stardis-solver to v0.3. - Add volumic power sources on solids; -- Allow to use the `fp_to_meter` parameter of the stardis-solver solve function; +- Allow to use the `fp_to_meter` parameter of the stardis-solver solve + function; - Add a dump geometry feature. It outputs the geometry as it is sent to - stardis-solver in VTK format, together with the front and back media and - boundary conditions information. + stardis-solver in VTK format, together with the front and back media + and boundary conditions information. ### Version 0.1 @@ -155,8 +162,9 @@ Add radiative transfer computations. To achieve this, media gain 2 new parameter ## License -Copyright (C) 2018-2023 |Méso|Star> (<contact@meso-star.com>). Stardis is free -software released under the GPL v3+ license: GNU GPL version 3 or later. You -are welcome to redistribute it under certain conditions; refer to the COPYING -file for details. +Copyright (C) 2018-2023 |Méso|Star> (<contact@meso-star.com>) + +Stardis is free software released under the GPL v3+ license: GNU GPL +version 3 or later. You are welcome to redistribute it under certain +conditions; refer to the COPYING file for details. diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt @@ -13,7 +13,7 @@ # You should have received a copy of the GNU General Public License # along with this program. If not, see <http://www.gnu.org/licenses/>. -cmake_minimum_required(VERSION 3.0) +cmake_minimum_required(VERSION 3.5) project(stardis C) set(SDIS_SOURCE_DIR ${PROJECT_SOURCE_DIR}/../src) @@ -89,14 +89,18 @@ configure_file(${SDIS_PRG_DIR}/stardis-prog-properties-config-version.cmake.in ############################################################################### # Check dependencies ############################################################################### +include(FindPkgConfig) + find_package(RCMake 0.4 REQUIRED) -find_package(RSys 0.12 REQUIRED) -find_package(StarGeom3D 0.1 REQUIRED) -find_package(Star3D 0.8 REQUIRED) -find_package(StarEnc3D 0.5 REQUIRED) -find_package(Stardis 0.14 REQUIRED) -find_package(StarSTL 0.4 REQUIRED) -find_package(StarSP 0.13 REQUIRED) + +pkg_check_modules(RSys REQUIRED rsys>=0.14) +pkg_check_modules(Star3D REQUIRED s3d>=0.10) +pkg_check_modules(StarEnc3D REQUIRED senc3d>=0.6) +pkg_check_modules(StarGeom3D REQUIRED sg3d>=0.1) +pkg_check_modules(Stardis REQUIRED sdis>=0.15) +pkg_check_modules(StarSTL REQUIRED sstl>=0.5) +pkg_check_modules(StarSP REQUIRED star-sp>=0.14) + if(MSVC) find_package(MuslGetopt REQUIRED) endif() @@ -108,13 +112,7 @@ endif() include_directories( - ${RSys_INCLUDE_DIR} - ${Star3D_INCLUDE_DIR} ${StarGeom3D_INCLUDE_DIR} - ${StarEnc3D_INCLUDE_DIR} - ${Stardis_INCLUDE_DIR} - ${StarSTL_INCLUDE_DIR} - ${StarSP_INCLUDE_DIR} ${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_CURRENT_BINARY_DIR}/stardis-green-types ${CMAKE_CURRENT_BINARY_DIR}/stardis-prog-properties) @@ -126,15 +124,6 @@ set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${RCMAKE_SOURCE_DIR}) include(rcmake) include(rcmake_runtime) -if(CMAKE_COMPILER_IS_GNUCC) - rcmake_append_runtime_dirs(_runtime_dirs - RSys Stardis Star3D StarGeom3D StarEnc3D StarSTL StarSP) -endif() -if(MSVC) - rcmake_append_runtime_dirs(_runtime_dirs - RSys MuslGetopt Stardis Star3D StarGeom3D StarEnc3D StarSTL StarSP) -endif() - ############################################################################### # Build subprojects ############################################################################### @@ -225,8 +214,26 @@ endif() set_target_properties(stardis PROPERTIES VERSION ${SDIS_VERSION}) +target_compile_options(stardis PUBLIC + ${RSys_CFLAGS} + ${Star3D_CFLAGS} + ${StarEnc3D_CFLAGS} + ${StarGeom3D_CFLAGS} + ${Stardis_CFLAGS} + ${StarSTL_CFLAGS} + ${StarSP_CFLAGS}) + target_link_libraries(stardis - Stardis Star3D StarGeom3D StarEnc3D StarSTL StarSP RSys ${GETOPT_LIB} ${MATH_LIB}) + ${StarGeom3D_LDFLAGS} + ${RSys_LDFLAGS} + ${Star3D_LDFLAGS} + ${StarEnc3D_LDFLAGS} + ${StarGeom3D_LDFLAGS} + ${Stardis_LDFLAGS} + ${StarSTL_LDFLAGS} + ${StarSP_LDFLAGS} + ${GETOPT_LIB} + ${MATH_LIB}) if(ENABLE_MPI) set_target_properties(stardis PROPERTIES COMPILE_DEFINITIONS "STARDIS_ENABLE_MPI") diff --git a/cmake/stardis-green-types/CMakeLists.txt b/cmake/stardis-green-types/CMakeLists.txt @@ -13,7 +13,7 @@ # You should have received a copy of the GNU General Public License # along with this program. If not, see <http://www.gnu.org/licenses/>. -cmake_minimum_required(VERSION 3.0) +cmake_minimum_required(VERSION 3.5) set(STARDIS_SGT_DIR ${PROJECT_SOURCE_DIR}/../stardis-green-types) diff --git a/cmake/stardis-prog-properties/CMakeLists.txt b/cmake/stardis-prog-properties/CMakeLists.txt @@ -13,7 +13,7 @@ # You should have received a copy of the GNU General Public License # along with this program. If not, see <http://www.gnu.org/licenses/>. -cmake_minimum_required(VERSION 3.0) +cmake_minimum_required(VERSION 3.5) set(STARDIS_SPROG_DIR ${PROJECT_SOURCE_DIR}/../stardis-prog-properties) diff --git a/config.mk b/config.mk @@ -42,6 +42,9 @@ STARDIS_ARGS_DEFAULT_SAMPLES_COUNT = 10000 STARDIS_ARGS_DEFAULT_SCALE_FACTOR = 1 STARDIS_ARGS_DEFAULT_VERBOSE_LEVEL = 1 +# Including NULL char +STARDIS_MAX_NAME_LENGTH = 64 + ################################################################################ # Tools ################################################################################ diff --git a/doc/stardis-input.5 b/doc/stardis-input.5 @@ -1,363 +0,0 @@ -.\" Copyright (C) 2018-2023 |Méso|Star> -.\" -.\" 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/>. -.Dd January 31, 2024 -.Dt STARDIS-INPUT 5 -.Os -.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" -.\" Name and short description -.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" -.Sh NAME -.Nm stardis-input -.Nd thermal system description for -.Xr stardis 1 -.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" -.\" Detailed description -.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" -.Sh DESCRIPTION -.Nm -is the format used by the -.Xr stardis 1 -program to describe a thermal system. -It is a line-by-line ASCII syntax. -.Pp -A thermal system is composed of lines of text, each one describing -either a program -.Pq an user-provided shared object , -a medium frontier -.Pq solid or fluid , -a boundary condition, a connection between two media, the scale of the -whole geometry, or the radiative temperature around the system. -In the medium, boundary and connection cases, description lines include -a list of file names that constitute the limit, boundary or connection. -.Xr stardis 1 -only accepts triangle mesh geometry files in STL format. -If a scale is specified, it defines the scaling factor to apply to the -geometry to have it expressed in meters -.Pq e.g. 1e-3 if the geometry is in mm . -.Pp -Any physical quantity involved in descriptions is expected in the -International System of Units -.Pq second, meter, kilogram, kelvin, watt, joule . -However, the geometry provided to -.Xr stardis 1 -can be described in any unit, multiple of meters or not, as long as the -scaling factor is provided. -.Pp -Properties are defined directly as constants in the input file. -Several properties can also be defined by programs, i.e. shared objects -provided by the user -.Pq compiled libraries . -The latter allow user-defined variable properties to be supplied to -.Xr stardis 1 . -Depending on the type of description they use, programs must -export a given list of mandatory functions. -They can also export some other optional functions. -The exact list with names and types can be found in the public header -.Pa stardis-prog.h , -which is installed together with -.Xr stardis 1 -binary. -.Pp -A medium limit, a boundary or a connection description can be split -across files and a single file or description line can describe more -than one frontier -.Pq more than one connex region . -The main semantic constraint on descriptions is that enclosures must be -defined by a single description line, to ensure that every constitutive -part of the system is made from a single medium. -.Pp -Description lines can be submitted to -.Xr stardis 1 -in any order, with the exception of programs that must be -defined before use, and can be split across more than one file, through -multiple use of option -.Fl M . -.Pp -When a description line is parsed, the first step is to split it in -different parts. -.Xr stardis 1 -relies on the -.Xr wordexp 3 -POSIX function for this step. -As a consequence the rules that apply at this stage all come from -the wordexp rules: environment variables can be used and are -substituted, including inside arithmetic expressions, text inside quote -pairs is considered a single item, whitespace characters can be escaped -so that the current item continues past it -.Po see -.Xr wordexp 3 -for details -.Pc . -Note however that both the use of undefined environment variables and -the use of command substitution will be reported as an error as these -features are not enabled in -.Xr stardis 1 . -.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" -.\" Grammar in Backus-Naur form -.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" -.Sh GRAMMAR -In what follows, some lines end with a backslash -.Pq Li \e . -This is used as a convenience to continue a description next line. -However, this trick cannot be used in actual description files and -actual description lines must be kept single-line. -Text introduced by the sharp character -.Pq Li # -in descriptions is a comment and is not part of the description. -.Pp -The file format is as follows: -.Bl -column (description-line) (::) () -.It Ao Va thermal-system Ac Ta ::= Ta Ao Va description-line Ac -.It Ta Ta ... -.It Ao Va description-line Ac Ta ::= Ta Ao Va comment Ac -.It Ta \& \& | Ta Ao Va program Ac Op Ao Va comment Ac -.It Ta \& \& | Ta Ao Va medium Ac Op Ao Va comment Ac -.It Ta \& \& | Ta Ao Va connection Ac Op Ao Va comment Ac -.It Ta \& \& | Ta Ao Va boundary-condition Ac Op Ao Va comment Ac -.It Ta \& \& | Ta Ao Va scaling Ac Op Ao Va comment Ac -# At most once -.It Ta \& \& | Ta Ao Va rad-temps Ac Op Ao Va comment Ac -# At most once -.It \ Ta Ta -.It Ao Va comment Ac Ta ::= Ta Li # Vt string -.It Ao Va program Ac Ta ::= Ta Li PROGRAM Ao Va prog-name Ac Ao Va lib-path Ac Op Ao Va args Ac -.It Ao Va scaling Ac Ta ::= Ta Li SCALE Vt real -# Geometry scaling in ]0, INF) -.It \ Ta Ta -.It Ao Va rad-temps Ac Ta ::= Ta Li TRAD Ao Va temp Ac Ao Va Tref Ac -# Radiative temperatures -.It Ao Va temp Ac Ta ::= Ta Vt real No # Temperature > 0 [K] -.It Ao Va Tref Ac Ta ::= Ta Vt real No # Reference temperature > 0 [K] -.El -.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" -.Ss Media -.Bl -column (description-line) (::) () -.It Ao Va medium Ac Ta ::= Ta Ao Va fluid Ac | Ao Va solid Ac -.It \ Ta Ta -.It Ao Va fluid Ac Ta ::= Ta Ao Va fluid-const Ac | Ao Va fluid-prog Ac -.It Ao Va fluid-const Ac Ta ::= Ta -.Li FLUID Ao Va medium-name Ac Ao Va rho Ac Ao Va cp Ac \e -.It Ta Ta Ao Va initial-temp Ac Ao Va imposed-temp Ac \e -.It Ta Ta Ao Va triangle-sides Ac ... -.It Ao Va fluid-prog Ac Ta ::= Ta Li FLUID_PROG Ao Va medium-name Ac Ao Va prog-desc Ac -.It \ Ta Ta -.It Ao Va solid Ac Ta ::= Ta Ao Va solid-const Ac | Ao Va solid-prog Ac -.It Ao Va solid-const Ac Ta ::= Ta -.Li SOLID Ao Va medium-name Ac Ao Va lambda Ac Ao Va rho Ac Ao Va cp Ac \e -.It Ta Ta Ao Va initial-temp Ac Ao Va imposed-temp Ac \e -.It Ta Ta Ao Va volumic-power Ac Ao Va triangle-sides Ac No ... -.It Ao Va solid-prog Ac Ta ::= Ta Li SOLID_PROG Ao Va medium-name Ac Ao Va prog-desc Ac -.It \ Ta Ta -.It Ao Va lambda Ac Ta ::= Ta Vt real No # Conductivity > 0 [W/m/K] -.It Ao Va rho Ac Ta ::= Ta Vt real No # Volumic mass > 0 [kg/m^3] -.It Ao Va cp Ac Ta ::= Ta Vt real No # Capacity > 0 [J/K/kg] -.It Ao Va volumic-power Ac Ta ::= Ta Vt real No # [W/m^3] -.El -.Pp -Delta is the numerical parameter that defines the length of a conductive -random walk step. -The user can define it manually or let Stardis calculate it -automatically from the volume of the solid. -In the latter case, delta is set to V/(6*A), V and A being the solid's -volume and surface respectively: -.Bl -column (description-line) (::) () -.It Ao Va delta Ac Ta ::= Ta Li AUTO | Vt real -.El -.Pp -Media's descriptions, either solids or fluids, include two possible -temperatures: initial and imposed. -If imposed temperature is set -.Pq that is not Li UNKNOWN , -initial temperature must be defined at the same value. -In other words, one cannot define a medium with an imposed temperature -that changes at -.Li t= Ns Ar 0 : -.Bl -column (description-line) (::) () -.It Ao Va initial-temp Ac Ta ::= Ta Vt real No # Temperature > 0 [K] -.It Ao Va imposed-temp Ac Ta ::= Ta Li UNKNOWN No # Temperature has to be solved -.It Ta \& \& | Ta Vt real No # Temperature > 0 [K] -.El -.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" -.Ss Connection -.Bl -column (description-line) (::) () -.It Ao Va connection Ac Ta ::= Ta Ao Va solid-fluid Ac | Ao Va solid-solid Ac -.It \ Ta Ta -.It Ao Va solid-fluid Ac Ta ::= Ta Ao Va solid-fluid-const Ac | Ao Va solid-fluid-prog Ac -.It Ao Va solid-fluid-const Ac Ta ::= Ta Li SOLID_FLUID_CONNECTION Ao Va connect-name Ac \e -.It Ta Ta Ao Va Tref Ac Ao Va emissivity Ac Ao Va specular-fraction Ac \e -.It Ta Ta Ao Va hc Ac Ao Va triangles Ac ... -.It Ao Va solid-fluid-prog Ac Ta ::= Ta Li SOLID_FLUID_CONNECTION_PROG \e -.It Ta Ta Ao Va connect-name Ac Ao Va prog-desc Ac -.It \ Ta Ta -.It Ao Va solid-solid Ac Ta ::= Ta Ao Va solid-solid-const Ac | Ao Va solid-solid-prog Ac -.It Ao Va solid-solid-const Ac Ta ::= Ta Li SOLID_SOLID_CONNECTION Ao Va connect-name Ac \e -.It Ta Ta Ao Va contact-resistance Ac Ao Va triangles Ac ... -.It Ao Va solid-solid-prog Ac Ta ::= Ta Li SOLID_SOLID_CONNECTION_PROG \e -.It Ta Ta Ao Va connect-name Ac Ao Va prog-desc Ac -.It \ Ta Ta -.It Ao Va emissivity Ac Ta ::= Ta Vt real No # \&In [0,1] -.It Ao Va specular-fraction Ac Ta ::= Ta Vt real No # \&In [0,1] -.It Ao Va hc Ac Ta ::= Ta Vt real No # Convective coefficient > 0 [W/m^2/K] -.It Ao Va contact-resistance Ac Ta ::= Ta Vt real No # > 0 [K/m^-2/W] -.El -.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" -.Ss Boundary conditions -.Bl -column (description-line) (::) () -.It Ao Va boundary-condition Ac Ta ::= Ta -.Aq Va dirichlet -.It Ta \& \& | Ta Aq Va robin -.It Ta \& \& | Ta Aq Va neumann -.It Ta \& \& | Ta Aq Va robin-neumann -.It \ Ta Ta -.\" Dirichlet -.It Ao Va dirichlet Ac Ta ::= Ta Ao Va dirichlet-const Ac | Ao Va dirichlet-prog Ac -.It Ao Va dirichlet-const Ac Ta ::= Ta Li T_BOUNDARY_FOR_SOLID Ao Va bound-name Ac \e -.It Ta Ta Ao Va temp Ac Ao Va triangles Ac ... -.It Ao Va dirichlet-prog Ac Ta ::= Ta Li T_BOUNDARY_FOR_SOLID_PROG Ao Va bound-name Ac \e -.It Ta Ta Ao Va prog-desc Ac -.It \ Ta Ta -.\" Robin -.It Ao Va robin Ac Ta ::= Ta Ao Va robin-fluid Ac | Ao Va robin-solid Ac -.It Ao Va robin-fluid Ac Ta ::= Ta Ao Va robin-fluid-const Ac | Ao Va robin-fluid-prog Ac -.It Ao Va robin-solid Ac Ta ::= Ta Ao Va robin-solid-const Ac | Ao Va robin-solid-prog Ac -.It Ao Va robin-fluid-const Ac Ta ::= Ta Li H_BOUNDARY_FOR_FLUID Ao Va bound-name Ac \e -.It Ta Ta Ao Va robin-const-desc Ac -.It Ao Va robin-solid-const Ac Ta ::= Ta Li H_BOUNDARY_FOR_SOLID Ao Va bound-name Ac \e -.It Ta Ta Ao Va robin-const-desc Ac -.It Ao Va robin-const-desc Ac Ta ::= Ta Ao Va Tref Ac Ao Va emissivity Ac Ao Va specular-fraction Ac -.It Ta Ta Ao Va hc Ac Ao Va outside-temp Ac Ao Va triangles Ac ... -.It Ao Va robin-fluid-prog Ac Ta ::= Ta Li H_BOUNDARY_FOR_FLUID_PROG Ao Va bound-name Ac \e -.It Ta Ta Ao Va prog-desc Ac -.It Ao Va robin-solid-prog Ac Ta ::= Ta Li H_BOUNDARY_FOR_SOLID_PROG Ao Va bound-name Ac \e -.It Ta Ta Ao Va prog-desc Ac -.It \ Ta Ta -.\" Neumann -.It Ao Va neumann Ac Ta ::= Ta Ao Va neumann-const Ac | Ao Va neumann-prog Ac -.It Ao Va neumann-const Ac Ta ::= Ta Li F_BOUNDARY_FOR_SOLID Ao Va bound-name Ac \e -.It Ta Ta Ao Va flux Ac Ao Va triangles Ac ... -.It Ao Va neumann-prog Ac Ta ::= Ta Li F_BOUNDARY_FOR_SOLID_PROG Ao Va bound-name Ac \e -.It Ta Ta Ao Va prog-desc Ac -.It \ Ta Ta -.\" Robin & Neumann -.It Ao Va robin-neumann Ac Ta ::= Ta Ao Va robin-neumann-const Ac -.It Ta \& \& | Ta Ao Va robin-neumann-prog Ac -.It Ao Va robin-neumann-const Ac Ta ::= Ta Li HF_BOUNDARY_FOR_SOLID Ao Va bound-name Ac \e -.It Ta Ta Ao Va Tref Ac Ao Va emissivity Ac Ao Va specular-fraction Ac \e -.It Ta Ta Ao Va hc Ac Ao Va outside-temp Ac Ao Va flux Ac Ao Va triangles Ac ... -.It Ao Va robin-neumann-prog Ac Ta ::= Ta Li HF_BOUNDARY_FOR_SOLID_PROG Ao Va bound-name Ac \e -.It Ta Ta Ao Va prog-desc Ac -.It \ Ta Ta -.It Ao Va flux Ac Ta ::= Ta Vt real No # [W/m^2] -.It Ao Va outside-temp Ac Ta ::= Ta Vt real No # Temperature > 0 [K] -.El -.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" -.Ss Miscellaneous -Names, either file names or description names -.Pq boundary names, medium names, program names, or connection names , -are a sequence of one or more ASCII characters, including -numbers and special characters like -.Ql \&. , -.Ql _ , -or -.Ql - -as one may consider using in standard file names. -Description names are case-sensitive and two different description -lines, either in the same description file or from different description -files, cannot use the same name. -Additionally, description names cannot a number, nor be one of the -keywords defined by the present grammar and their lowercase -counterparts. -Finally, description names cannot be longer than 63 characters. -.Bl -column (description-line) (::) () -.It Ao Va bound-name Ac Ta ::= Ta Vt string -.It Ao Va medium-name Ac Ta ::= Ta Vt string -.It Ao Va prog-name Ac Ta ::= Ta Vt string -.It Ao Va connect-name Ac Ta ::= Ta Vt string -.It \ Ta Ta -.It Ao Va stl-path Ac Ta ::= Ta Pa path -.It Ao Va lib-path Ac Ta ::= Ta Pa path -.It \ Ta Ta -.It Ao Va args Ac Ta ::= Ta Vt string No ... -.It Ao Va prog-desc Ac Ta ::= Ta Ao Va prog-name Ac Ao Va triangle-sides Ac ... \e -.It Ta Ta Op Li PROG_PARAMS Op Ao Va args Ac -.It \ Ta Ta -.It Ao Va triangle-sides Ac Ta ::= Ta Ao Va side-specifier Ac Ao Va triangles Ac -.It Ao Va triangles Ac Ta ::= Ta Ao Va stl-path Ac -.El -.Pp -Side descriptions in side specifiers rely on the following convention: -we first consider the direct triangle's normal (right-hand rule), then -we define the -.Li BACK -side of a triangle to be the side this normal comes out from. -That means that a closed set of triangles with normals pointing outside -should be used with the -.Li FRONT -side specifier to describe inside medium: -.Bl -column (description-line) (::) () -.It Ao Va side-specifier Ac Ta ::= Ta Li FRONT | Li BACK | Li BOTH -.El -.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" -.\" File examples -.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" -.Sh EXAMPLES -Define a system consisting of a solid cube named -.Ql Cube 1 , -with a Robin-type boundary condition and radiative exchange with the -environment. -The cube geometry is read from the file -.Pa cube.stl -and the solid medium properties are -.No lambda= Ns Ar 0.1 No W/m/K , -.No rho= Ns Ar 25 No kg/m^3 , -.No cp= Ns Ar 2 No J/K/kg . -The numerical parameter delta, that is used for solid conductive walks, is -.Ar 0.05 . -The initial temperature of the cube is -.Ar 0 No K , its temperature is unknown -.Pq it has to be solved , -and its volumic power is -.Ar 2.5 No W/m^3 . -The boundary properties are -.No emissivity= Ns Ar 0 , -.No specular-fraction= Ns Ar 0, -.No hc= Ns Ar 10 No W/m^2/K -and -.No external-temperature= Ns Ar 100 No K . -The radiative environment is at -.Ar 300 No K . -Finally, the linearization of radiative transfer involving Robin's -boundary condition uses -.Ar 310 No K -as reference temperature and is set to -.Ar 330 No K -when linearisation involves the radiative environment: -.Bd -literal -offset Ds -SOLID Cube\ 1 0.1 25 2 0.05 0 UNKNOWN 2.5 FRONT cube.stl -H_BOUNDARY_FOR_SOLID HdT 310 0 0 10 100 cube.stl -TRAD 300 330 -.Ed -.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" -.\" External references -.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" -.Sh SEE ALSO -.Xr stardis 1 , -.Xr wordexp 3 -.Rs -.%T The StL Format: Standard Data Format for Fabbers -.%A Marshall Burns -.%D 1993 -.%U https://www.fabbers.com/tech/STL_Format -.Re diff --git a/doc/stardis-input.5.in b/doc/stardis-input.5.in @@ -0,0 +1,367 @@ +.\" Copyright (C) 2018-2023 |Méso|Star> +.\" +.\" 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/>. +.Dd February 19, 2024 +.Dt STARDIS-INPUT 5 +.Os +.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" +.\" Name and short description +.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" +.Sh NAME +.Nm stardis-input +.Nd thermal system description for +.Xr stardis 1 +.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" +.\" Detailed description +.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" +.Sh DESCRIPTION +.Nm +is the format used by the +.Xr stardis 1 +program to describe a thermal system. +It is a line-by-line ASCII syntax. +.Pp +A thermal system is composed of lines of text, each one describing +either a program +.Pq an user-provided shared object , +a medium frontier +.Pq solid or fluid , +a boundary condition, a connection between two media, the scale of the +whole geometry, or the radiative temperature around the system. +In the medium, boundary and connection cases, description lines include +a list of file names that constitute the limit, boundary or connection. +.Xr stardis 1 +only accepts triangle mesh geometry files in STL format. +If a scale is specified, it defines the scaling factor to apply to the +geometry to have it expressed in meters +.Pq e.g. 1e-3 if the geometry is in mm . +.Pp +Any physical quantity involved in descriptions is expected in the +International System of Units +.Pq second, meter, kilogram, kelvin, watt, joule . +However, the geometry provided to +.Xr stardis 1 +can be described in any unit, multiple of meters or not, as long as the +scaling factor is provided. +.Pp +Properties are defined directly as constants in the input file. +Several properties can also be defined by programs, i.e. shared objects +provided by the user +.Pq compiled libraries . +The latter allow user-defined variable properties to be supplied to +.Xr stardis 1 . +Depending on the type of description they use, programs must +export a given list of mandatory functions. +They can also export some other optional functions. +The exact list with names and types can be found in the public header +.Pa stardis-prog-properties.h , +which is installed together with +.Xr stardis 1 +binary. +.Pp +A medium limit, a boundary or a connection description can be split +across files and a single file or description line can describe more +than one frontier +.Pq more than one connex region . +The main semantic constraint on descriptions is that enclosures must be +defined by a single description line, to ensure that every constitutive +part of the system is made from a single medium. +.Pp +Description lines can be submitted to +.Xr stardis 1 +in any order, with the exception of programs that must be +defined before use, and can be split across more than one file, through +multiple use of option +.Fl M . +.Pp +When a description line is parsed, the first step is to split it in +different parts. +.Xr stardis 1 +relies on the +.Xr wordexp 3 +POSIX function for this step. +As a consequence the rules that apply at this stage all come from +the wordexp rules: environment variables can be used and are +substituted, including inside arithmetic expressions, text inside quote +pairs is considered a single item, whitespace characters can be escaped +so that the current item continues past it +.Po see +.Xr wordexp 3 +for details +.Pc . +Note however that both the use of undefined environment variables and +the use of command substitution will be reported as an error as these +features are not enabled in +.Xr stardis 1 . +.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" +.\" Grammar in Backus-Naur form +.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" +.Sh GRAMMAR +In what follows, some lines end with a backslash +.Pq Li \e . +This is used as a convenience to continue a description next line. +However, this trick cannot be used in actual description files and +actual description lines must be kept single-line. +Text introduced by the sharp character +.Pq Li # +in descriptions is a comment and is not part of the description. +.Pp +The file format is as follows: +.Bl -column (description-line) (::) () +.It Ao Va thermal-system Ac Ta ::= Ta Ao Va description-line Ac +.It Ta Ta ... +.It Ao Va description-line Ac Ta ::= Ta Ao Va comment Ac +.It Ta \& \& | Ta Ao Va program Ac Op Ao Va comment Ac +.It Ta \& \& | Ta Ao Va medium Ac Op Ao Va comment Ac +.It Ta \& \& | Ta Ao Va connection Ac Op Ao Va comment Ac +.It Ta \& \& | Ta Ao Va boundary-condition Ac Op Ao Va comment Ac +.It Ta \& \& | Ta Ao Va scaling Ac Op Ao Va comment Ac +# At most once +.It Ta \& \& | Ta Ao Va rad-temps Ac Op Ao Va comment Ac +# At most once +.It \ Ta Ta +.It Ao Va comment Ac Ta ::= Ta Li # Vt string +.It Ao Va program Ac Ta ::= Ta Li PROGRAM Ao Va prog-name Ac Ao Va lib-path Ac Op Ao Va args Ac +.It Ao Va scaling Ac Ta ::= Ta Li SCALE Vt real +# Geometry scaling in ]0, INF) +.It \ Ta Ta +.It Ao Va rad-temps Ac Ta ::= Ta Li TRAD Ao Va temp Ac Ao Va Tref Ac +# Radiative temperatures +.It Ao Va temp Ac Ta ::= Ta Vt real No # Temperature > 0 [K] +.It Ao Va Tref Ac Ta ::= Ta Vt real No # Reference temperature > 0 [K] +.El +.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" +.Ss Media +.Bl -column (description-line) (::) () +.It Ao Va medium Ac Ta ::= Ta Ao Va fluid Ac | Ao Va solid Ac +.It \ Ta Ta +.It Ao Va fluid Ac Ta ::= Ta Ao Va fluid-const Ac | Ao Va fluid-prog Ac +.It Ao Va fluid-const Ac Ta ::= Ta +.Li FLUID Ao Va medium-name Ac Ao Va rho Ac Ao Va cp Ac \e +.It Ta Ta Ao Va initial-temp Ac Ao Va imposed-temp Ac \e +.It Ta Ta Ao Va triangle-sides Ac ... +.It Ao Va fluid-prog Ac Ta ::= Ta Li FLUID_PROG Ao Va medium-name Ac Ao Va prog-desc-sides Ac +.It \ Ta Ta +.It Ao Va solid Ac Ta ::= Ta Ao Va solid-const Ac | Ao Va solid-prog Ac +.It Ao Va solid-const Ac Ta ::= Ta +.Li SOLID Ao Va medium-name Ac Ao Va lambda Ac Ao Va rho Ac Ao Va cp Ac \e +.It Ta Ta Ao Va delta Ac Ao Va initial-temp Ac Ao Va imposed-temp Ac \e +.It Ta Ta Ao Va volumic-power Ac Ao Va triangle-sides Ac No ... +.It Ao Va solid-prog Ac Ta ::= Ta Li SOLID_PROG Ao Va medium-name Ac Ao Va prog-desc-sides Ac +.It \ Ta Ta +.It Ao Va lambda Ac Ta ::= Ta Vt real No # Conductivity > 0 [W/m/K] +.It Ao Va rho Ac Ta ::= Ta Vt real No # Volumic mass > 0 [kg/m^3] +.It Ao Va cp Ac Ta ::= Ta Vt real No # Capacity > 0 [J/K/kg] +.It Ao Va volumic-power Ac Ta ::= Ta Vt real No # [W/m^3] +.El +.Pp +Delta is the numerical parameter that defines the length of a conductive +random walk step. +The user can define it manually or let Stardis calculate it +automatically from the volume of the solid. +In the latter case, delta is set to V/(6*A), V and A being the solid's +volume and surface respectively: +.Bl -column (description-line) (::) () +.It Ao Va delta Ac Ta ::= Ta Li AUTO | Vt real +.El +.Pp +Media's descriptions, either solids or fluids, include two possible +temperatures: initial and imposed. +If imposed temperature is set +.Pq that is not Li UNKNOWN , +initial temperature must be defined at the same value. +In other words, one cannot define a medium with an imposed temperature +that changes at +.Li t= Ns Ar 0 : +.Bl -column (description-line) (::) () +.It Ao Va initial-temp Ac Ta ::= Ta Vt real No # Temperature > 0 [K] +.It Ao Va imposed-temp Ac Ta ::= Ta Li UNKNOWN No # Temperature has to be solved +.It Ta \& \& | Ta Vt real No # Temperature > 0 [K] +.El +.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" +.Ss Connection +.Bl -column (description-line) (::) () +.It Ao Va connection Ac Ta ::= Ta Ao Va solid-fluid Ac | Ao Va solid-solid Ac +.It \ Ta Ta +.It Ao Va solid-fluid Ac Ta ::= Ta Ao Va solid-fluid-const Ac | Ao Va solid-fluid-prog Ac +.It Ao Va solid-fluid-const Ac Ta ::= Ta Li SOLID_FLUID_CONNECTION Ao Va connect-name Ac \e +.It Ta Ta Ao Va Tref Ac Ao Va emissivity Ac Ao Va specular-fraction Ac \e +.It Ta Ta Ao Va hc Ac Ao Va triangles Ac ... +.It Ao Va solid-fluid-prog Ac Ta ::= Ta Li SOLID_FLUID_CONNECTION_PROG \e +.It Ta Ta Ao Va connect-name Ac Ao Va prog-desc Ac +.It \ Ta Ta +.It Ao Va solid-solid Ac Ta ::= Ta Ao Va solid-solid-const Ac | Ao Va solid-solid-prog Ac +.It Ao Va solid-solid-const Ac Ta ::= Ta Li SOLID_SOLID_CONNECTION Ao Va connect-name Ac \e +.It Ta Ta Ao Va contact-resistance Ac Ao Va triangles Ac ... +.It Ao Va solid-solid-prog Ac Ta ::= Ta Li SOLID_SOLID_CONNECTION_PROG \e +.It Ta Ta Ao Va connect-name Ac Ao Va prog-desc Ac +.It \ Ta Ta +.It Ao Va emissivity Ac Ta ::= Ta Vt real No # \&In [0,1] +.It Ao Va specular-fraction Ac Ta ::= Ta Vt real No # \&In [0,1] +.It Ao Va hc Ac Ta ::= Ta Vt real No # Convective coefficient > 0 [W/m^2/K] +.It Ao Va contact-resistance Ac Ta ::= Ta Vt real No # > 0 [K/m^-2/W] +.El +.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" +.Ss Boundary conditions +.Bl -column (description-line) (::) () +.It Ao Va boundary-condition Ac Ta ::= Ta +.Aq Va dirichlet +.It Ta \& \& | Ta Aq Va robin +.It Ta \& \& | Ta Aq Va neumann +.It Ta \& \& | Ta Aq Va robin-neumann +.It \ Ta Ta +.\" Dirichlet +.It Ao Va dirichlet Ac Ta ::= Ta Ao Va dirichlet-const Ac | Ao Va dirichlet-prog Ac +.It Ao Va dirichlet-const Ac Ta ::= Ta Li T_BOUNDARY_FOR_SOLID Ao Va bound-name Ac \e +.It Ta Ta Ao Va temp Ac Ao Va triangles Ac ... +.It Ao Va dirichlet-prog Ac Ta ::= Ta Li T_BOUNDARY_FOR_SOLID_PROG Ao Va bound-name Ac \e +.It Ta Ta Ao Va prog-desc Ac +.It \ Ta Ta +.\" Robin +.It Ao Va robin Ac Ta ::= Ta Ao Va robin-fluid Ac | Ao Va robin-solid Ac +.It Ao Va robin-fluid Ac Ta ::= Ta Ao Va robin-fluid-const Ac | Ao Va robin-fluid-prog Ac +.It Ao Va robin-solid Ac Ta ::= Ta Ao Va robin-solid-const Ac | Ao Va robin-solid-prog Ac +.It Ao Va robin-fluid-const Ac Ta ::= Ta Li H_BOUNDARY_FOR_FLUID Ao Va bound-name Ac \e +.It Ta Ta Ao Va robin-const-desc Ac +.It Ao Va robin-solid-const Ac Ta ::= Ta Li H_BOUNDARY_FOR_SOLID Ao Va bound-name Ac \e +.It Ta Ta Ao Va robin-const-desc Ac +.It Ao Va robin-const-desc Ac Ta ::= Ta Ao Va Tref Ac Ao Va emissivity Ac Ao Va specular-fraction Ac +.It Ta Ta Ao Va hc Ac Ao Va outside-temp Ac Ao Va triangles Ac ... +.It Ao Va robin-fluid-prog Ac Ta ::= Ta Li H_BOUNDARY_FOR_FLUID_PROG Ao Va bound-name Ac \e +.It Ta Ta Ao Va prog-desc Ac +.It Ao Va robin-solid-prog Ac Ta ::= Ta Li H_BOUNDARY_FOR_SOLID_PROG Ao Va bound-name Ac \e +.It Ta Ta Ao Va prog-desc Ac +.It \ Ta Ta +.\" Neumann +.It Ao Va neumann Ac Ta ::= Ta Ao Va neumann-const Ac | Ao Va neumann-prog Ac +.It Ao Va neumann-const Ac Ta ::= Ta Li F_BOUNDARY_FOR_SOLID Ao Va bound-name Ac \e +.It Ta Ta Ao Va flux Ac Ao Va triangles Ac ... +.It Ao Va neumann-prog Ac Ta ::= Ta Li F_BOUNDARY_FOR_SOLID_PROG Ao Va bound-name Ac \e +.It Ta Ta Ao Va prog-desc Ac +.It \ Ta Ta +.\" Robin & Neumann +.It Ao Va robin-neumann Ac Ta ::= Ta Ao Va robin-neumann-const Ac +.It Ta \& \& | Ta Ao Va robin-neumann-prog Ac +.It Ao Va robin-neumann-const Ac Ta ::= Ta Li HF_BOUNDARY_FOR_SOLID Ao Va bound-name Ac \e +.It Ta Ta Ao Va Tref Ac Ao Va emissivity Ac Ao Va specular-fraction Ac \e +.It Ta Ta Ao Va hc Ac Ao Va outside-temp Ac Ao Va flux Ac Ao Va triangles Ac ... +.It Ao Va robin-neumann-prog Ac Ta ::= Ta Li HF_BOUNDARY_FOR_SOLID_PROG Ao Va bound-name Ac \e +.It Ta Ta Ao Va prog-desc Ac +.It \ Ta Ta +.It Ao Va flux Ac Ta ::= Ta Vt real No # [W/m^2] +.It Ao Va outside-temp Ac Ta ::= Ta Vt real No # Temperature > 0 [K] +.El +.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" +.Ss Miscellaneous +Names, either file names or description names +.Pq boundary names, medium names, program names, or connection names , +are a sequence of one or more ASCII characters, including +numbers and special characters like +.Ql \&. , +.Ql _ , +or +.Ql - +as one may consider using in standard file names. +Description names are case-sensitive and two different description +lines, either in the same description file or from different description +files, cannot use the same name. +Additionally, description names cannot a number, nor be one of the +keywords defined by the present grammar and their lowercase +counterparts. +Finally, description names cannot be longer than +@STARDIS_MAX_NAME_LENGTH@ characters. +.Bl -column (description-line) (::) () +.It Ao Va bound-name Ac Ta ::= Ta Vt string +.It Ao Va medium-name Ac Ta ::= Ta Vt string +.It Ao Va prog-name Ac Ta ::= Ta Vt string +.It Ao Va connect-name Ac Ta ::= Ta Vt string +.It \ Ta Ta +.It Ao Va stl-path Ac Ta ::= Ta Pa path +.It Ao Va lib-path Ac Ta ::= Ta Pa path +.It \ Ta Ta +.It Ao Va args Ac Ta ::= Ta Vt string No ... +.It \ Ta Ta +.It Ao Va prog-desc Ac Ta ::= Ta Ao Va prog-name Ac Ao Va triangles Ac ... \e +.It Ta Ta Op Li PROG_PARAMS Op Ao Va args Ac +.It Ao Va prog-desc-sides Ac Ta ::= Ta Ao Va prog-name Ac Ao Va triangles-sides Ac ... \e +.It Ta Ta Op Li PROG_PARAMS Op Ao Va args Ac +.It \ Ta Ta +.It Ao Va triangles Ac Ta ::= Ta Ao Va stl-path Ac +.It Ao Va triangle-sides Ac Ta ::= Ta Ao Va side-specifier Ac Ao Va triangles Ac +.El +.Pp +Side descriptions in side specifiers rely on the following convention: +we first consider the direct triangle's normal (right-hand rule), then +we define the +.Li BACK +side of a triangle to be the side this normal comes out from. +That means that a closed set of triangles with normals pointing outside +should be used with the +.Li FRONT +side specifier to describe inside medium: +.Bl -column (description-line) (::) () +.It Ao Va side-specifier Ac Ta ::= Ta Li FRONT | Li BACK | Li BOTH +.El +.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" +.\" File examples +.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" +.Sh EXAMPLES +Define a system consisting of a solid cube named +.Ql Cube 1 , +with a Robin-type boundary condition and radiative exchange with the +environment. +The cube geometry is read from the file +.Pa cube.stl +and the solid medium properties are +.No lambda= Ns Ar 0.1 No W/m/K , +.No rho= Ns Ar 25 No kg/m^3 , +.No cp= Ns Ar 2 No J/K/kg . +The numerical parameter delta, that is used for solid conductive walks, is +.Ar 0.05 . +The initial temperature of the cube is +.Ar 0 No K , its temperature is unknown +.Pq it has to be solved , +and its volumic power is +.Ar 2.5 No W/m^3 . +The boundary properties are +.No emissivity= Ns Ar 0 , +.No specular-fraction= Ns Ar 0, +.No hc= Ns Ar 10 No W/m^2/K +and +.No external-temperature= Ns Ar 100 No K . +The radiative environment is at +.Ar 300 No K . +Finally, the linearization of radiative transfer involving Robin's +boundary condition uses +.Ar 310 No K +as reference temperature and is set to +.Ar 330 No K +when linearisation involves the radiative environment: +.Bd -literal -offset Ds +SOLID Cube\ 1 0.1 25 2 0.05 0 UNKNOWN 2.5 FRONT cube.stl +H_BOUNDARY_FOR_SOLID HdT 310 0 0 10 100 cube.stl +TRAD 300 330 +.Ed +.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" +.\" External references +.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" +.Sh SEE ALSO +.Xr stardis 1 , +.Xr wordexp 3 +.Rs +.%T The StL Format: Standard Data Format for Fabbers +.%A Marshall Burns +.%D 1993 +.%U https://www.fabbers.com/tech/STL_Format +.Re diff --git a/doc/stardis.1.in b/doc/stardis.1.in @@ -25,6 +25,7 @@ .Op Fl d Ar file_base_name .Op Fl F Pa surface Ns Op , Ns Ar time Ns Op , Ns Ar time .Op Fl G Pa green_bin Ns Op , Ns Pa green_ascii +.Op Fl L Pa interface_probes .Op Fl m Ar medium_name Ns Op , Ns Ar time Ns Op , Ns Ar time .Op Fl n Ar samples_count .Op Fl o Ar picard_order @@ -185,6 +186,25 @@ and cannot be used in conjunction with option .Fl D . .It Fl h Output short help and exit. +.It Fl L Pa interface_probes +Defines a set of interface probes for which +.Nm +calculates the temperature. +The argument file lists the interface probe points. +Each line of this file describes a probe point using the same grammar as +that used to describe a single interface probe +.Pq see Fl P No option . +In addition to this syntax, characters behind the hash mark +.Pq Li # +are considered comments and are therefore ignored, as are empty lines, +i.e. lines with no characters at all or composed solely of spaces and +tabs. +.Pp +Note that this option parallelizes the calculation of the probe list, +and not the calculation of each individual probe. +Its use is therefore more advantageous in terms of load distribution +when the number of probes to be evaluated is large, compared with the +cost of calculating a single probe point. .It Fl M Pa system Read a text file containing a possibly partial description of the system. Can include programs, media enclosures and boundary conditions. diff --git a/src/stardis-app.c b/src/stardis-app.c @@ -260,6 +260,7 @@ stardis_init darray_size_t_init(stardis->allocator, &stardis->compute_surface.primitives); darray_sides_init(stardis->allocator, &stardis->compute_surface.sides); darray_uint_init(stardis->allocator, &stardis->compute_surface.err_triangles); + darray_probe_boundary_init(stardis->allocator, &stardis->probe_boundary_list); stardis->compute_surface.area = 0; stardis->samples = args->samples; stardis->nthreads = args->nthreads; @@ -319,8 +320,10 @@ stardis_init else if(args->mode & MODE_MEDIUM_COMPUTE) { ERR(str_set(&stardis->solve_name, args->medium_name)); } - else if(args->mode & MODE_PROBE_COMPUTE_ON_INTERFACE && args->medium_name) { - ERR(str_set(&stardis->solve_name, args->medium_name)); + else if((args->mode & MODE_PROBE_COMPUTE_ON_INTERFACE) + || (args->mode & MODE_PROBE_LIST_COMPUTE_ON_INTERFACE)) { + ERR(darray_probe_boundary_copy + (&stardis->probe_boundary_list, &args->probe_boundary_list)); } else if(args->mode & SURFACE_COMPUTE_MODES) { ERR(str_set(&stardis->solve_name, args->solve_filename)); @@ -484,7 +487,7 @@ stardis_init /* If computation is on a volume, check medium is known */ if(args->mode & MODE_MEDIUM_COMPUTE) { - if(!find_medium_by_name(stardis, &stardis->solve_name, NULL)) { + if(!find_medium_by_name(stardis, str_cget(&stardis->solve_name), NULL)) { logger_print(stardis->logger, (is_for_compute ? LOG_ERROR : LOG_WARNING), "Cannot find medium '%s'\n", str_cget(&stardis->solve_name)); res = RES_BAD_ARG; @@ -572,6 +575,7 @@ stardis_release if(stardis->dummies.stardis_solid) { release_solid(stardis->dummies.stardis_solid, stardis->allocator); } + darray_probe_boundary_release(&stardis->probe_boundary_list); } unsigned diff --git a/src/stardis-app.h b/src/stardis-app.h @@ -16,6 +16,7 @@ #ifndef STARDIS_APP_H #define STARDIS_APP_H +#include "stardis-args.h" #include "stardis-description.h" #include <star/sg3d.h> @@ -238,6 +239,8 @@ struct stardis { int geometry_initialized; int mpi_initialized; int mpi_rank; + + struct darray_probe_boundary probe_boundary_list; }; unsigned diff --git a/src/stardis-args.c b/src/stardis-args.c @@ -20,11 +20,13 @@ #include "stardis-default.h" #include "stardis-version.h" +#include <sdis_version.h> + #include <rsys/cstr.h> #include <rsys/double2.h> #include <rsys/double3.h> -#include <sdis_version.h> #include <rsys/logger.h> +#include <rsys/text_reader.h> #include <getopt.h> #include <stdlib.h> @@ -102,8 +104,7 @@ split_line } static char -mode_option - (const int m) +mode_option(const int m) { int found = 0; char res = '?'; @@ -115,6 +116,7 @@ mode_option if(m & MODE_GREEN) { found++; res = 'g'; } if(m & MODE_BIN_GREEN) { found++; res = 'G'; } if(m & MODE_DUMP_HELP) { found++; res = 'h'; } + if(m & MODE_PROBE_LIST_COMPUTE_ON_INTERFACE) { found++; res = 'L'; } if(m & MODE_MEDIUM_COMPUTE) { found++; res = 'm'; } if(m & MODE_PROBE_COMPUTE) { found++; res = 'p'; } if(m & MODE_PROBE_COMPUTE_ON_INTERFACE) { found++; res = 'P'; } @@ -152,6 +154,210 @@ print_multiple_modes } while(m < modes); } +static res_T +parse_position_and_time(const char* str, double pos[3], double time[2]) +{ + char buf[128]; + double pos_and_time[5]; + size_t len; + res_T res = RES_OK; + ASSERT(str && pos && time); + + + if(strlen(str) >= sizeof(buf)-1/*NULL char*/) { + fprintf(stderr, + "Could not duplicate the string defining a position and, optionally, " + "a time range `%s'\n", str); + res = RES_MEM_ERR; + goto error; + } + strncpy(buf, str, sizeof(buf)); + + res = cstr_to_list_double(str, ',', pos_and_time, &len, 5); + if(res != RES_OK + || len < 3 /* Invalid position */ + || len > 5 /* Too many fields */) { + fprintf(stderr, + "Error parsing position and optional time range `%s'\n", str); + res = RES_BAD_ARG; + goto error; + } + + pos[0] = pos_and_time[0]; + pos[1] = pos_and_time[1]; + pos[2] = pos_and_time[2]; + + switch(len) { + /* No time was parsed => Steady state */ + case 3: + time[0] = INF; + time[1] = INF; + break; + /* A single time was parsed => the time range is degenerated */ + case 4: + time[0] = pos_and_time[3]; + time[1] = pos_and_time[3]; + break; + /* A time range was parsed and must be not degenerated */ + case 5: + time[0] = pos_and_time[3]; + time[1] = pos_and_time[4]; + if(time[0] > time[1]) { + fprintf(stderr, "Invalid time range [%g, %g}\n", time[0], time[1]); + res = RES_BAD_ARG; + goto error; + } + break; + default: FATAL("Unreachable code\n"); break; + } + +exit: + return res; +error: + goto exit; +} + +static res_T +parse_side_indicator(const char* str, char side_name[STARDIS_MAX_NAME_LENGTH]) +{ + res_T res = RES_OK; + ASSERT(str && side_name); + + if(strlen(str) >= STARDIS_MAX_NAME_LENGTH) { + fprintf(stderr, + "Side indicator could not exceed %d characters `%s'\n", + STARDIS_MAX_NAME_LENGTH-1, str); + res = RES_MEM_ERR; + goto error; + } + strncpy(side_name, str, STARDIS_MAX_NAME_LENGTH); + +exit: + return res; +error: + goto exit; +} + +static res_T +parse_probe_boundary(const char* str, struct stardis_probe_boundary* probe) +{ + char buf[128]; + char* pos_and_time = NULL; + char* side = NULL; + char* ctx = NULL; + res_T res = RES_OK; + ASSERT(str && probe); + + if(strlen(str) >= sizeof(buf)-1/*NULL char*/) { + fprintf(stderr, + "Could not duplicate string defining probe at boundary `%s'\n", str); + res = RES_MEM_ERR; + goto error; + } + strncpy(buf, str, sizeof(buf)); + + pos_and_time = strtok_r(buf, ":", &ctx); + side = strtok_r(NULL, "", &ctx); + + res = parse_position_and_time(pos_and_time, probe->position, probe->time); + if(res != RES_OK) goto error; + + if(side) { + res = parse_side_indicator(side, probe->side); + if(res != RES_OK) goto error; + } + +exit: + return res; +error: + goto exit; +} + +static res_T +allocate_probe_boundary + (struct args* args, + struct stardis_probe_boundary** out_probe) +{ + size_t i = 0; + res_T res = RES_OK; + ASSERT(args && out_probe); + + i = darray_probe_boundary_size_get(&args->probe_boundary_list); + res = darray_probe_boundary_resize(&args->probe_boundary_list, i+1); + if(res != RES_OK) { + logger_print(args->logger, LOG_ERROR, + "Error allocating the probe on the boundary -- %s.\n", + res_to_cstr(res)); + goto error; + } + + *out_probe = darray_probe_boundary_data_get(&args->probe_boundary_list) + i; + +exit: + return res; +error: + darray_probe_boundary_resize(&args->probe_boundary_list, i); /* Deallocate */ + goto exit; +} + +static res_T +parse_probe_boundary_list + (const char* filename, + struct logger* logger, + struct mem_allocator* allocator, + struct darray_probe_boundary* list) +{ + struct txtrdr* txtrdr = NULL; + res_T res = RES_OK; + ASSERT(filename && list); + + res = txtrdr_file(allocator, filename, '#', &txtrdr); + if(res != RES_OK) goto error; + + for(;;) { + struct stardis_probe_boundary probe = STARDIS_PROBE_BOUNDARY_NULL; + const char* line = NULL; + + res = txtrdr_read_line(txtrdr); + if(res != RES_OK) { + logger_print(logger, LOG_ERROR, + "%s: could not read the line `%lu' -- %s.\n", + txtrdr_get_name(txtrdr), (unsigned long)txtrdr_get_line_num(txtrdr), + res_to_cstr(res)); + goto error; + } + + if(!(line = txtrdr_get_cline(txtrdr))) goto exit; /* No line to parse */ + + res = parse_probe_boundary(line, &probe); + if(res != RES_OK) goto error; + + res = darray_probe_boundary_push_back(list, &probe); + if(res != RES_OK) { + logger_print(logger, LOG_ERROR, + "%s:%lu: error registering the probe on the boundary -- %s.\n", + txtrdr_get_name(txtrdr), (unsigned long)txtrdr_get_line_num(txtrdr), + res_to_cstr(res)); + goto error; + } + } + + if(!darray_probe_boundary_size_get(list)) { + logger_print(logger, LOG_ERROR, + "The file `%s' does not list any probes on the boundary.\n", + filename); + res = RES_BAD_ARG; + goto error; + } + +exit: + if(txtrdr) txtrdr_ref_put(txtrdr); + return res; +error: + darray_probe_boundary_clear(list); + goto exit; +} + /******************************************************************************* * Public Functions ******************************************************************************/ @@ -198,6 +404,7 @@ init_args d2(args->pos_and_time+3, STARDIS_DEFAULT_COMPUTE_TIME, STARDIS_DEFAULT_COMPUTE_TIME); args->verbose = STARDIS_DEFAULT_VERBOSE_LEVEL; + darray_probe_boundary_init(allocator, &args->probe_boundary_list); end: *out_args = args; @@ -213,124 +420,24 @@ release_args(struct args* args) { ASSERT(args); darray_str_release(&args->model_files); + darray_probe_boundary_release(&args->probe_boundary_list); free(args); } void -short_help - (FILE* stream, - const char* prog) +usage(FILE* stream) { - const char* name; -#ifdef STARDIS_ENABLE_MPI - int rank; -#endif - ASSERT(stream && prog); - -#ifdef STARDIS_ENABLE_MPI - CHK(MPI_Comm_rank(MPI_COMM_WORLD, &rank) == MPI_SUCCESS); - /* Only master prints */ - if(rank != 0) return; -#endif - -#ifdef COMPILER_GCC - name = strrchr(prog, '/'); -#else - name = strrchr(prog, '\\'); -#endif - - name = name ? name + 1 : prog; - fprintf(stream, - "Usage: %s [OPTIONS]\n" - "\nSolve coupled thermal systems under the linear assumption.\n" - "Refer to stardis(1) man page for more information.\n\n", - name); - print_version(stream); - - fprintf(stream, "\nMandatory options\n"); - fprintf(stream, "-----------------\n"); - - fprintf(stream, "\n -M <FILE>\n"); - fprintf(stream, " Read a text file that contains (partial) description of the model.\n"); - - fprintf(stream, "\nExclusive options\n"); - fprintf(stream, "-----------------\n"); - - fprintf(stream, "\n -F STL_FILE[,TIME-RANGE]\n"); - fprintf(stream, " Compute the mean flux on a given 2D region at a given time.\n"); - - fprintf(stream, "\n -m MEDIUM_NAME[,TIME-RANGE]\n"); - fprintf(stream, " Compute the mean temperature in a given medium at a given time.\n"); - - fprintf(stream, "\n -p X,Y,Z[,TIME-RANGE]\n"); - fprintf(stream, " Compute the temperature at the given probe.\n"); - - fprintf(stream, "\n -P X,Y,Z[,TIME-RANGE]\n"); - fprintf(stream, " Compute the temperature at the given probe on an interface.\n"); - - fprintf(stream, "\n -R [RENDERING_OPTIONS]\n"); - fprintf(stream, " Compute an infra-red image of the model.\n"); - - fprintf(stream, "\n -s STL_FILE[,TIME-RANGE]\n"); - fprintf(stream, " Compute the mean temperature on a given 2D region.\n"); - - fprintf(stream, "\n -S STL_FILE[,TIME-RANGE]\n"); - fprintf(stream, " Compute the by-triangle mean temperature on a given 2D region.\n"); - - fprintf(stream, "\nOther options\n"); - fprintf(stream, "-------------\n"); - - fprintf(stream, "\n -c NAMES_PREFIX\n"); - fprintf(stream, " Dump the geometry and property ids to stdout as C chunks.\n"); - - fprintf(stream, "\n -d FILE_NAME_PREFIX\n"); - fprintf(stream, " Dump the geometry to file <FILE_NAME_PREFIX>.vtk in VTK format along with various properties.\n"); - fprintf(stream, " If merge errors where detected, the corresponding part of the geometry is dumped to file\n" - " <FILE_NAME_PREFIX>_merge_conflicts.obj in OBJ format.\n"); - fprintf(stream, " If property errors where detected, the corresponding part of the geometry is dumped to file\n" - " <FILE_NAME_PREFIX>_property_conflicts.obj in OBJ format.\n"); - - fprintf(stream, "\n -D TYPE,FILE_NAMES_PREFIX\n"); - fprintf(stream, " Write thermal paths of the given TYPE in VTK format.\n"); - - fprintf(stream, "\n -e\n"); - fprintf(stream, " Use extended format to output Monte-Carlo results.\n"); - - fprintf(stream, "\n -g\n"); - fprintf(stream, " Change the computation to produce the green function.\n"); - - fprintf(stream, "\n -G BIN_FILE_NAME[,CSV_FILE_NAME]\n"); - fprintf(stream, " Change the computation to produce the green function and possibly end of paths information.\n"); - - fprintf(stream, "\n -h\n"); - fprintf(stream, " Print this help and exit.\n"); - - fprintf(stream, "\n -n SAMPLE_COUNT\n"); - fprintf(stream, " Set the number of Monte-Carlo samples.\n"); - - fprintf(stream, "\n -o\n"); - fprintf(stream, " Set the order for the Picard linearization of radiative transfer.\n"); - - fprintf(stream, "\n -t NUM_OF_THREADS\n"); - fprintf(stream, " Hint on the number of threads.\n"); - - fprintf(stream, "\n -v\n"); - fprintf(stream, " Print version information and exit.\n"); - - fprintf(stream, "\n -V LEVEL\n"); - fprintf(stream, " Set the verbosity level.\n"); - - fprintf(stream, "\n -x <FILE>\n"); - fprintf(stream, " Use a random generator's state read from a file.\n"); - - fprintf(stream, "\n -X <FILE>\n"); - fprintf(stream, " Save the final random generator's state in a file.\n"); - - fprintf(stream, -"\nCopyright (C) 2018-2023 |Méso|Star> <contact@meso-star.com>.\n" -"stardis is free software released under the GNU GPL license, version 3 or later.\n" -"You are free to change or redistribute it under certain conditions\n" -"<http://gnu.org/licenses/gpl.html>.\n"); + #define PRINT(Msg) fprintf(stream, Msg) + PRINT("stardis [-eghv] [-D path_type,files_name_prefix] [-d file_base_name]\n"); + PRINT(" [-F surface[,time[,time]]] [-G green_bin[,green_ascii]]\n"); + PRINT(" [-L interface_probes] [-m medium_name[,time[,time]]]\n"); + PRINT(" [-n samples_count] [-o picard_order]\n"); + PRINT(" [-P x,y,z[,time[,time]][:side_indicator]]\n"); + PRINT(" [-p x,y,z[,time[,time]]] [-R rendering_opt[:rendering_opt ...]]\n"); + PRINT(" [-S surface[,time[,time]]] [-s surface[,time[,time]]]\n"); + PRINT(" [-t threads_count] [-V verbosity_level] [-X output_rng]\n"); + PRINT(" [-x input_rng] -M system\n"); + #undef PRINT } #define FREE_AARRAY(ARRAY) \ @@ -388,7 +495,7 @@ parse_args { int opt = 0, n_used = 0, o_used = 0; size_t len = 0; - const char option_list[] = "c:d:D:eF:gG:hm:M:n:o:p:P:R:s:S:t:vV:x:X:"; + const char option_list[] = "c:d:D:eF:gG:hL:m:M:n:o:p:P:R:s:S:t:vV:x:X:"; char buf[128]; struct str keep; char** line = NULL; @@ -517,6 +624,19 @@ parse_args args->mode |= MODE_DUMP_HELP; break; + case 'L': + if(args->mode & EXCLUSIVE_MODES) { + logger_print(args->logger, LOG_ERROR, + "Options -%c and -%c are exclusive.\n", + (char)opt, mode_option(args->mode)); + goto error; + } + args->mode |= MODE_PROBE_LIST_COMPUTE_ON_INTERFACE; + res = parse_probe_boundary_list + (optarg, args->logger, args->allocator, &args->probe_boundary_list); + if(res != RES_OK) goto error; + break; + case 'm': { char* ptr; if(args->mode & EXCLUSIVE_MODES) { @@ -585,42 +705,23 @@ parse_args GET_POS_AND_OPTIONAL_TIME_RANGE(optarg, args->pos_and_time, optarg); break; - case 'P': + case 'P': { + struct stardis_probe_boundary* probe = NULL; + if(args->mode & EXCLUSIVE_MODES) { - res = RES_BAD_ARG; logger_print(args->logger, LOG_ERROR, - "Options -%c and -%c are exclusive.\n", - (char)opt, mode_option(args->mode)); - goto error; - } - args->mode |= MODE_PROBE_COMPUTE_ON_INTERFACE; - - ERR(str_set(&keep, optarg)); - line = split_line(optarg, ':'); - if(!line) { - res = RES_MEM_ERR; - str_release(&keep); - goto error; - } - - /* We expect 1 or 2 parts in line */ - if(!line[0] || (line[1] && line[2])) { - logger_print((args->logger), LOG_ERROR, - "Invalid argument for option ""-%c"": %s\n", - opt, str_cget(&keep)); - str_release(&keep); + "Options -%c and -%c are exclusive.\n", + (char)opt, mode_option(args->mode)); res = RES_BAD_ARG; goto error; } - - /* First part is pos and optional time, optional second part is a - * medium name (OK if NULL) */ - GET_POS_AND_OPTIONAL_TIME_RANGE(line[0], args->pos_and_time, - str_cget(&keep)); - if(line[1]) - args->medium_name = optarg + strlen(line[0]) + 1; - + args->mode |= MODE_PROBE_COMPUTE_ON_INTERFACE; + res = allocate_probe_boundary(args, &probe); + if(res != RES_OK) goto error; + res = parse_probe_boundary(optarg, probe); + if(res != RES_OK) goto error; break; + } case 'R': if(args->mode & EXCLUSIVE_MODES) { diff --git a/src/stardis-args.h b/src/stardis-args.h @@ -1,141 +0,0 @@ -/* Copyright (C) 2018-2023 |Méso|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/>. */ - -#ifndef STARDIS_ARGS_H -#define STARDIS_ARGS_H - -#include <sdis.h> - -#include <rsys/rsys.h> -#include <rsys/dynamic_array_str.h> - -struct camera; -struct logger; -struct mem_allocator; -struct stardis; - -enum stardis_mode { - /* Ordered so that print_multiple_modes() prints in alphabetical order */ - UNDEF_MODE = 0, - MODE_DUMP_C_CHUNKS = BIT(0), /* -c */ - MODE_DUMP_PATHS = BIT(1), /* -D */ - MODE_DUMP_MODEL = BIT(2), /* -d */ - MODE_EXTENDED_RESULTS = BIT(3), /* -e */ - MODE_FLUX_BOUNDARY_COMPUTE = BIT(4), /* -F */ - MODE_BIN_GREEN = BIT(5), /* -G */ - MODE_GREEN = BIT(6), /* -g */ - MODE_DUMP_HELP = BIT(7), /* -h */ - MODE_MEDIUM_COMPUTE = BIT(8), /* -m */ - MODE_PROBE_COMPUTE_ON_INTERFACE = BIT(9), /* -P */ - MODE_PROBE_COMPUTE = BIT(10), /* -p */ - MODE_IR_COMPUTE = BIT(11), /* -R */ - MODE_MAP_COMPUTE = BIT(12), /* -S */ - MODE_BOUNDARY_COMPUTE = BIT(13), /* -s */ - MODE_VERBOSITY = BIT(14), /* -V */ - MODE_DUMP_VERSION = BIT(15), /* -v */ - - GREEN_COMPATIBLE_MODES - = MODE_PROBE_COMPUTE | MODE_PROBE_COMPUTE_ON_INTERFACE | MODE_MEDIUM_COMPUTE - | MODE_BOUNDARY_COMPUTE, - - SURFACE_COMPUTE_MODES - = MODE_BOUNDARY_COMPUTE | MODE_FLUX_BOUNDARY_COMPUTE | MODE_MAP_COMPUTE, - - EXT_COMPATIBLE_MODES - = GREEN_COMPATIBLE_MODES | MODE_MEDIUM_COMPUTE | MODE_FLUX_BOUNDARY_COMPUTE, - - REGION_COMPUTE_MODES = SURFACE_COMPUTE_MODES | MODE_MEDIUM_COMPUTE, - - COMPUTE_MODES = GREEN_COMPATIBLE_MODES | MODE_IR_COMPUTE | SURFACE_COMPUTE_MODES, - - EXCLUSIVE_MODES = COMPUTE_MODES, - - SHORT_EXIT_MODES = MODE_DUMP_HELP | MODE_DUMP_VERSION, - - USE_STDOUT_MODES - = MODE_DUMP_C_CHUNKS | MODE_DUMP_HELP | MODE_DUMP_VERSION | MODE_IR_COMPUTE - | MODE_GREEN, - - RANDOM_RW_MODES - = MODE_PROBE_COMPUTE | MODE_PROBE_COMPUTE_ON_INTERFACE | MODE_MEDIUM_COMPUTE - | MODE_BOUNDARY_COMPUTE | MODE_FLUX_BOUNDARY_COMPUTE -}; - -STATIC_ASSERT(GREEN_COMPATIBLE_MODES == (COMPUTE_MODES & GREEN_COMPATIBLE_MODES), - Cannot_have_a_GREEN_COMPATIBLE_MODE_that_is_not_a_COMPUTE_MODE); - -enum dump_path_type { - DUMP_NONE = 0, - DUMP_SUCCESS = BIT(0), - DUMP_ERROR = BIT(1), - DUMP_ALL = DUMP_SUCCESS | DUMP_ERROR -}; - -struct args { - struct logger* logger; - struct mem_allocator* allocator; - struct darray_str model_files; - char* medium_name; - char* solve_filename; - char* bin_green_filename; - char* end_paths_filename; - char* dump_model_filename; - char* paths_filename; - char* rndgen_state_in_filename; - char* rndgen_state_out_filename; - char* chunks_prefix; - char* camera; - size_t samples; - double pos_and_time[5]; - unsigned nthreads; - unsigned picard_order; - int mode; - enum dump_path_type dump_paths; - int verbose; -}; - -res_T -init_args - (struct logger* logger, - struct mem_allocator* mem, - struct args** args); - -void -release_args - (struct args* args); - -void -print_version - (FILE* stream); - -void -short_help - (FILE* stream, - const char* prog); - -res_T -parse_args - (const int argc, - char** argv, - struct args* args, - struct mem_allocator* allocator); - -res_T -parse_camera - (struct logger* logger, - char* cam_param, - struct stardis* stardis); - -#endif /* STRADIS_ARGS_H */ diff --git a/src/stardis-args.h.in b/src/stardis-args.h.in @@ -0,0 +1,180 @@ +/* Copyright (C) 2018-2023 |Méso|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/>. */ + +#ifndef STARDIS_ARGS_H +#define STARDIS_ARGS_H + +#define STARDIS_MAX_NAME_LENGTH @STARDIS_MAX_NAME_LENGTH@ + +#include <sdis.h> + +#include <rsys/rsys.h> +#include <rsys/dynamic_array_str.h> + +struct camera; +struct logger; +struct mem_allocator; +struct stardis; + +struct stardis_probe_boundary { + double position[3]; + double time[2]; /* Observation time */ + char side[STARDIS_MAX_NAME_LENGTH]; +}; +#define STARDIS_PROBE_BOUNDARY_NULL__ {{0,0,0},{0,0},{0}} +static const struct stardis_probe_boundary STARDIS_PROBE_BOUNDARY_NULL = + STARDIS_PROBE_BOUNDARY_NULL__; + +/* Define the dynamic array of probes on the boundary */ +#define DARRAY_NAME probe_boundary +#define DARRAY_DATA struct stardis_probe_boundary +#include <rsys/dynamic_array.h> + +enum stardis_mode { + /* Ordered so that print_multiple_modes() prints in alphabetical order */ + UNDEF_MODE = 0, + MODE_DUMP_C_CHUNKS = BIT(0), /* -c */ + MODE_DUMP_PATHS = BIT(1), /* -D */ + MODE_DUMP_MODEL = BIT(2), /* -d */ + MODE_EXTENDED_RESULTS = BIT(3), /* -e */ + MODE_FLUX_BOUNDARY_COMPUTE = BIT(4), /* -F */ + MODE_BIN_GREEN = BIT(5), /* -G */ + MODE_GREEN = BIT(6), /* -g */ + MODE_DUMP_HELP = BIT(7), /* -h */ + MODE_PROBE_LIST_COMPUTE_ON_INTERFACE = BIT(8), /* -L */ + MODE_MEDIUM_COMPUTE = BIT(9), /* -m */ + MODE_PROBE_COMPUTE_ON_INTERFACE = BIT(10), /* -P */ + MODE_PROBE_COMPUTE = BIT(11), /* -p */ + MODE_IR_COMPUTE = BIT(12), /* -R */ + MODE_MAP_COMPUTE = BIT(13), /* -S */ + MODE_BOUNDARY_COMPUTE = BIT(14), /* -s */ + MODE_VERBOSITY = BIT(15), /* -V */ + MODE_DUMP_VERSION = BIT(16), /* -v */ + + GREEN_COMPATIBLE_MODES = + MODE_PROBE_COMPUTE + | MODE_PROBE_COMPUTE_ON_INTERFACE + | MODE_MEDIUM_COMPUTE + | MODE_BOUNDARY_COMPUTE, + + SURFACE_COMPUTE_MODES = + MODE_BOUNDARY_COMPUTE + | MODE_FLUX_BOUNDARY_COMPUTE + | MODE_MAP_COMPUTE, + + EXT_COMPATIBLE_MODES = + GREEN_COMPATIBLE_MODES + | MODE_MEDIUM_COMPUTE + | MODE_FLUX_BOUNDARY_COMPUTE, + + REGION_COMPUTE_MODES = + SURFACE_COMPUTE_MODES + | MODE_MEDIUM_COMPUTE, + + COMPUTE_MODES = + GREEN_COMPATIBLE_MODES + | MODE_IR_COMPUTE + | SURFACE_COMPUTE_MODES + | MODE_PROBE_LIST_COMPUTE_ON_INTERFACE, + + EXCLUSIVE_MODES = COMPUTE_MODES, + + SHORT_EXIT_MODES = + MODE_DUMP_HELP + | MODE_DUMP_VERSION, + + USE_STDOUT_MODES = + MODE_DUMP_C_CHUNKS + | MODE_DUMP_HELP + | MODE_DUMP_VERSION + | MODE_IR_COMPUTE + | MODE_GREEN, + + RANDOM_RW_MODES = + MODE_PROBE_COMPUTE + | MODE_PROBE_COMPUTE_ON_INTERFACE + | MODE_PROBE_LIST_COMPUTE_ON_INTERFACE + | MODE_MEDIUM_COMPUTE + | MODE_BOUNDARY_COMPUTE + | MODE_FLUX_BOUNDARY_COMPUTE +}; + +STATIC_ASSERT(GREEN_COMPATIBLE_MODES == (COMPUTE_MODES & GREEN_COMPATIBLE_MODES), + Cannot_have_a_GREEN_COMPATIBLE_MODE_that_is_not_a_COMPUTE_MODE); + +enum dump_path_type { + DUMP_NONE = 0, + DUMP_SUCCESS = BIT(0), + DUMP_ERROR = BIT(1), + DUMP_ALL = DUMP_SUCCESS | DUMP_ERROR +}; + +struct args { + struct logger* logger; + struct mem_allocator* allocator; + struct darray_str model_files; + char* medium_name; + char* solve_filename; + char* bin_green_filename; + char* end_paths_filename; + char* dump_model_filename; + char* paths_filename; + char* rndgen_state_in_filename; + char* rndgen_state_out_filename; + char* chunks_prefix; + char* camera; + size_t samples; + double pos_and_time[5]; + unsigned nthreads; + unsigned picard_order; + int mode; + enum dump_path_type dump_paths; + int verbose; + + struct darray_probe_boundary probe_boundary_list; +}; + +extern LOCAL_SYM res_T +init_args + (struct logger* logger, + struct mem_allocator* mem, + struct args** args); + +extern LOCAL_SYM void +release_args + (struct args* args); + +extern LOCAL_SYM void +print_version + (FILE* stream); + +extern LOCAL_SYM void +usage + (FILE* stream); + +extern LOCAL_SYM res_T +parse_args + (const int argc, + char** argv, + struct args* args, + struct mem_allocator* allocator); + +extern LOCAL_SYM res_T +parse_camera + (struct logger* logger, + char* cam_param, + struct stardis* stardis); + +#endif /* STRADIS_ARGS_H */ diff --git a/src/stardis-compute-probe-boundary.c b/src/stardis-compute-probe-boundary.c @@ -0,0 +1,993 @@ +/* Copyright (C) 2018-2023 |Méso|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 "stardis-app.h" +#include "stardis-compute.h" +#include "stardis-output.h" +#include "stardis-prog-properties.h" +#include "stardis-solid.h" +#include "stardis-solid-prog.h" +#include "stardis-ssconnect.h" + +#include <sdis.h> + +#include <star/senc3d.h> +#include <star/ssp.h> + +#include <rsys/logger.h> +#include <rsys/str.h> +#include <rsys/clock_time.h> + +#include <strings.h> + +struct filter_ctx { + float distance; + enum sg3d_property_type side; +}; +#define FILTER_CTX_DEFAULT__ {0.f, SG3D_INTFACE} +static const struct filter_ctx FILTER_CTX_DEFAULT = FILTER_CTX_DEFAULT__; + +/******************************************************************************* + * Helper functions + ******************************************************************************/ +static INLINE const char* +sdis_side_to_cstr(const enum sdis_side side) +{ + const char* cstr = NULL; + switch(side) { + case SDIS_FRONT: cstr = "FRONT"; break; + case SDIS_BACK: cstr = "BACK"; break; + case SDIS_SIDE_NULL__: cstr = "UNDEFINED"; break; + default: FATAL("Unreachable code.\n"); + } + return cstr; +} + +static res_T +read_rng_state + (struct stardis* stardis, + const char* filename, + struct ssp_rng* rng) +{ + FILE* fp = NULL; + res_T res = RES_OK; + ASSERT(stardis && filename && rng); + + if(stardis->mpi_initialized && stardis->mpi_rank != 0) { + goto exit; /* Non master process. Nothing to do */ + } + + if((fp = fopen(filename, "r")) == NULL) { + logger_print(stardis->logger, LOG_ERROR, + "Cannot open generator's state file ('%s').\n", filename); + res = RES_IO_ERR; + goto error; + } + + res = ssp_rng_read(rng, fp); + if(res != RES_OK) { + logger_print(stardis->logger, LOG_ERROR, + "Cannot read random generator's state ('%s').\n", filename); + goto error; + } + +exit: + if(fp) CHK(fclose(fp) == 0); + return res; +error: + goto exit; +} + +static res_T +write_rng_state + (struct stardis* stardis, + const char* filename, + struct ssp_rng* rng_state) +{ + FILE* fp = NULL; + res_T res = RES_OK; + ASSERT(stardis && filename && rng_state); + + if(stardis->mpi_initialized && stardis->mpi_rank != 0) { + goto exit; /* Non master process. Nothing to do */ + } + + if((fp = fopen(filename, "wb")) == NULL) { + logger_print(stardis->logger, LOG_ERROR, + "Cannot open generator's state file ('%s').\n", filename); + res = RES_IO_ERR; + goto error; + } + + res = ssp_rng_write(rng_state, fp); + if(res != RES_OK) { + logger_print(stardis->logger, LOG_ERROR, + "Cannot write random generator's state ('%s').\n", filename); + res = RES_IO_ERR; + goto error; + } + +exit: + if(fp) CHK(fclose(fp) == 0); + return res; +error: + goto exit; +} + +/* Filter used from a point query to determine not only one of the closest + * point, but the better one if there are more than one. In some circumstances + * it is not possible to determine the medium we are in using a given hit, but + * it is possible using another equidistant hit : + * + * + * P C + * +.............+---trg 1--- + * | + * medium 1 trg 2 medium 2 + * | + * + * C is the closest point from P, and 2 different hits at C are possible (one + * on each triangle). However, only hit on trg 2 allows to find out that P is + * in medium 1 using sign(PC.Ntrg1) as PC.Ntrg2 = 0. + * The following filter function aims at selecting the hit on trg2 regardless + * of the order in which the 2 triangles are checked. + * One unexpected case cannot be decided though, but it implies that the + * closest triangle has 2 different media on its sides and that P lies on the + * triangle's plane : + * + * P C medium 1 + * + +---trg--- + * medium 2 */ +static int +hit_filter + (const struct s3d_hit* hit, + const float ray_org[3], + const float ray_dir[3], + const float ray_range[2], + void* ray_data, + void* filter_data) +{ + struct filter_ctx* filter_ctx = ray_data; + + (void)ray_org, (void)ray_range, (void)filter_data; + ASSERT(hit && filter_ctx); + ASSERT(hit->uv[0] == CLAMP(hit->uv[0], 0, 1)); + ASSERT(hit->uv[1] == CLAMP(hit->uv[1], 0, 1)); + + /* That's not the closest point. Keep the previous one if it can be used to + * detect the medium (i.e. side != SG3D_INTFACE) */ + if(filter_ctx->distance == hit->distance && filter_ctx->side != SG3D_INTFACE) { + return 1; /* Skip */ + } + + filter_ctx->distance = hit->distance; + + if(filter_ctx->distance == 0) { + filter_ctx->side = SG3D_INTFACE; + } else { + float sign = 0; + float N[3] = {0,0,0}; /* Normalized normal */ + + /* Calculate the dot product with normalized vectors limits the numerical + * inaccuracies on its sign */ + f3_normalize(N, hit->normal); + sign = f3_dot(ray_dir, N); + + /* Star3D hit normals are left-handed */ + if(sign < 0) filter_ctx->side = SG3D_FRONT; + else if(sign > 0) filter_ctx->side = SG3D_BACK; + else/*sign == 0*/ filter_ctx->side = SG3D_INTFACE; + } + + return 0; /* Keep */ +} + +static INLINE res_T +find_closest_point + (struct stardis* stardis, + const double pos[3], + struct filter_ctx* filter_ctx, + size_t* iprim, + double uv[2]) +{ + struct sdis_scene_find_closest_point_args closest_pt_args = + SDIS_SCENE_FIND_CLOSEST_POINT_ARGS_NULL; + res_T res = RES_OK; + ASSERT(stardis && pos && filter_ctx && iprim && uv); + + /* Find the surface point closest to the input position */ + closest_pt_args.position[0] = pos[0]; + closest_pt_args.position[1] = pos[1]; + closest_pt_args.position[2] = pos[2]; + closest_pt_args.radius = INF; + closest_pt_args.filter_3d = hit_filter; + closest_pt_args.filter_data = filter_ctx; + ERR(sdis_scene_find_closest_point + (stardis->sdis_scn , &closest_pt_args, iprim, uv)); + if(*iprim == SDIS_PRIMITIVE_NONE) { + res = RES_BAD_ARG; + goto error; + } + +exit: + return res; +error: + goto exit; +} + +static res_T +check_move_to_solid_boundary + (const struct stardis* stardis, + const double pos[3], /* Original position */ + const double time, /* [s] */ + const struct description* desc, /* Solid medium in which pos lies */ + const size_t iprim, /* Triangle index to which to move */ + const double uv[2], /* Triangle coordinates to which to move */ + const double distance) /* Move distance */ +{ + struct stardis_vertex vtx = STARDIS_VERTEX_NULL; + const char* prefix = ""; + const char* solid_name = ""; + double delta = 0; + res_T res = RES_OK; + + /* Check pre-conditions */ + ASSERT(stardis && pos && time > 0 && desc && uv && distance >= 0); + + /* Retrieve the delta and define the prefix of the solid for log messages */ + switch(desc->type) { + /* Regular solid, i.e. solid with constant properties */ + case DESC_MAT_SOLID: + delta = desc->d.solid->delta; + prefix = ""; + break; + + /* Solid with programmed properties */ + case DESC_MAT_SOLID_PROG: + vtx.P[0] = pos[0]; + vtx.P[1] = pos[1]; + vtx.P[2] = pos[2]; + vtx.time = time; + delta = desc->d.solid_prog->delta(&vtx, desc->d.solid_prog->prog_data); + prefix = "programmed"; + break; + + default: FATAL("Unreachable code.\n"); + } + + solid_name = str_cget(get_description_name(desc)); + logger_print(stardis->logger, LOG_OUTPUT, "Probe was in %ssolid '%s'.\n", + prefix, solid_name); + + /* The position is closed from the triangle */ + if(distance < 0.5*delta) { + logger_print(stardis->logger, LOG_OUTPUT, + "Probe was %g delta from closest boundary.\n", + distance/delta); + + /* Notice that the position is a little far from the triangle */ + } else if(distance < 2*delta) { + logger_print(stardis->logger, LOG_WARNING, + "Probe was %g delta from closest boundary. " + "Consider using -p instead of -P.\n", + distance/delta); + + /* The position is too far from the triangle */ + } else { + logger_print(stardis->logger, LOG_ERROR, + "Probe moved to (%g, %g, %g), primitive %lu, uv = (%g, %g). " + "Move is %g delta long. Use -p instead of -P.\n", + SPLIT3(pos), (unsigned long)iprim, SPLIT2(uv), distance/delta); + res = RES_BAD_ARG; + goto error; + } + +exit: + return res; +error: + goto exit; +} + +/* This function checks nothing. It only records the status. It is named as the + * one used to check the projection on the solid limit to make it symmetrical, + * and thus simplify the reading of sources */ +static res_T +check_move_to_fluid_boundary + (struct stardis* stardis, + const struct description* desc, /* Fluid medium in which pos lies */ + const double distance) /* Move distance */ +{ + const char* prefix = ""; + const char* fluid_name = ""; + + ASSERT(stardis && desc && distance >= 0); + + switch(desc->type) { + case DESC_MAT_FLUID: prefix = ""; break; + case DESC_MAT_FLUID_PROG: prefix = "programmed"; break; + default: FATAL("Unreachable code.\n"); + } + + fluid_name = str_cget(get_description_name(desc)); + logger_print(stardis->logger, LOG_OUTPUT, + "Probe was in %sfluid '%s'.\n", prefix, fluid_name); + logger_print(stardis->logger, LOG_OUTPUT, + "Probe distance from closest boundary was %g.\n", distance); + + return RES_OK; +} + +static res_T +move_to_boundary + (struct stardis* stardis, + const double pos[3], + const double time, /* [s] */ + size_t* out_iprim, + double uv[2]) +{ + /* Position on boundary */ + struct filter_ctx filter_ctx = FILTER_CTX_DEFAULT; + double proj_pos[3] = {0,0,0}; + size_t iprim = 0; + + /* Properties */ + const struct description* desc_list = NULL; + const struct description* desc = NULL; + unsigned desc_ids[SG3D_PROP_TYPES_COUNT__]; + + /* Miscellaneous */ + size_t nvertices_close = 0; + res_T res = RES_OK; + + /* Check pre-conditions */ + ASSERT(stardis && pos && time >= 0 && out_iprim && uv); + + ERR(find_closest_point(stardis, pos, &filter_ctx, &iprim, uv)); + SG3D(geometry_get_unique_triangle_properties + (stardis->geometry.sg3d, (unsigned)iprim, desc_ids)); + + desc_list = darray_descriptions_cdata_get(&stardis->descriptions); + + /* Undefined medium */ + if(filter_ctx.side == SG3D_INTFACE + || desc_ids[filter_ctx.side] == SG3D_UNSPECIFIED_PROPERTY) { + logger_print(stardis->logger, LOG_WARNING, + "Could not determine the medium probe is in.\n"); + } + + if(filter_ctx.side != SG3D_INTFACE) { + + /* Probe is outside the system */ + if(desc_ids[filter_ctx.side] == SG3D_UNSPECIFIED_PROPERTY) { + logger_print(stardis->logger, LOG_WARNING, + "Probe was outside the system.\n"); + + /* Probe is in a medium */ + } else { + desc = desc_list + desc_ids[filter_ctx.side]; + + switch(desc->type) { + case DESC_MAT_SOLID: + case DESC_MAT_SOLID_PROG: + ERR(check_move_to_solid_boundary + (stardis, pos, time, desc, iprim, uv, filter_ctx.distance)); + break; + case DESC_MAT_FLUID: + case DESC_MAT_FLUID_PROG: + ERR(check_move_to_fluid_boundary + (stardis, desc, filter_ctx.distance)); + break; + default: FATAL("Unreachable code.\n"); + } + } + } + + SDIS(scene_get_boundary_position(stardis->sdis_scn, iprim, uv, proj_pos)); + + /* Count the number of vertices that are close to the boundary position + * and issue a warning if necessary */ + nvertices_close += CLAMP(uv[0], 0.0005, 0.9995) != uv[0]; + nvertices_close += CLAMP(uv[1], 0.0005, 0.9995) != uv[1]; + if(nvertices_close) { + logger_print(stardis->logger, LOG_WARNING, + "Probe %s close to / on %s. " + "If computation fails, try moving it slightly.\n", + filter_ctx.distance == 0 ? "is" : "moved", + nvertices_close == 1 ? "an edge" : "a vertex"); + } + + /* Probe is on a boundary */ + if(filter_ctx.distance == 0) { + logger_print(stardis->logger, LOG_OUTPUT, + "Probe is on primitive %lu, uv = (%g, %g), not moved.\n", + (unsigned long)iprim, SPLIT2(uv)); + + /* Probe was projected on a boundary */ + } else { + logger_print(stardis->logger, LOG_OUTPUT, + "Probe moved to (%g, %g, %g), primitive %lu, uv = (%g, %g).\n", + SPLIT3(proj_pos), (unsigned long)iprim, SPLIT2(uv)); + } + +exit: + *out_iprim = iprim; + return res; +error: + goto exit; +} + +static res_T +setup_probe_side + (struct stardis* stardis, + const unsigned desc_ids[SG3D_PROP_TYPES_COUNT__], + const char* side_str, + const size_t iprim, + enum sdis_side *out_side) +{ + const struct description* desc_list = NULL; + const struct description* desc_front = NULL; + const struct description* desc_back = NULL; + size_t ndescs = 0; + enum sdis_side side = SDIS_SIDE_NULL__; + res_T res = RES_OK; + (void)ndescs; /* Avoid "Unused variable" warnings in release */ + + /* Check pre-conditions */ + ASSERT(stardis && side_str && desc_ids && out_side); + + /* Fetch the properties */ + desc_list = darray_descriptions_cdata_get(&stardis->descriptions); + ndescs = darray_descriptions_size_get(&stardis->descriptions); + desc_front = desc_list + desc_ids[SG3D_FRONT]; + desc_back = desc_list + desc_ids[SG3D_BACK]; + + /* No side specified */ + if(!side_str || !strlen(side_str)) { + side = SDIS_SIDE_NULL__; + + /* Set probe to front side */ + } else if(!strcasecmp(side_str, "FRONT")) { + ASSERT(desc_ids[SG3D_FRONT] < ndescs && DESC_IS_MEDIUM(desc_front)); + side = SDIS_FRONT; + + /* Set probe to back side */ + } else if(!strcasecmp(side_str, "BACK")) { + ASSERT(desc_ids[SG3D_BACK] < ndescs && DESC_IS_MEDIUM(desc_back)); + side = SDIS_BACK; + + /* Set the probe to the side that points to the submitted medium name */ + } else { + unsigned med_id_probe = 0; /* Medium defined on the probe */ + unsigned med_id_front = 0; /* Medium on front side */ + unsigned med_id_back = 0; /* Medium on back side */ + ASSERT(DESC_IS_MEDIUM(desc_front) && DESC_IS_MEDIUM(desc_back)); + + if(!find_medium_by_name(stardis, side_str, &med_id_probe)) { + logger_print(stardis->logger, LOG_ERROR, + "Cannot locate side from medium name '%s' (unknown medium)\n", + side_str); + res = RES_BAD_ARG; + goto error; + } + + description_get_medium_id(desc_front, &med_id_front); + description_get_medium_id(desc_back, &med_id_back); + + /* Invalid probe medium wrt the boundary on which it is located */ + if(med_id_probe != med_id_front + && med_id_probe != med_id_back) { + logger_print(stardis->logger, LOG_ERROR, + "Medium '%s' is not used at this interface (prim id=%lu)\n", + side_str, (unsigned long)iprim); + res = RES_BAD_ARG; + goto error; + } + + /* The same medium is used on both sides: cannot differentiate */ + if(med_id_front == med_id_back) { + unsigned encs[2]; /* Identifier of the enclosures */ + + ERR(senc3d_scene_get_triangle_enclosures + (stardis->senc3d_scn, (unsigned)iprim, encs)); + logger_print(stardis->logger, LOG_ERROR, + "Medium '%s' is used on both sides of this interface (prim id=%lu).\n", + side_str, (unsigned long)iprim); + logger_print(stardis->logger, LOG_ERROR, + "Side must be defined using either FRONT or BACK.\n"); + logger_print(stardis->logger, LOG_ERROR, + "FRONT side is related to enclosure %u, BACK side to enclosure %u.\n", + encs[SENC3D_FRONT], encs[SENC3D_BACK]); + + res = RES_BAD_ARG; + goto error; + } + + side = med_id_probe == med_id_front ? SDIS_FRONT : SDIS_BACK; + } + +exit: + *out_side = side; + return res; +error: + side = SDIS_SIDE_NULL__; + goto exit; +} + +/* This function checks the conformity between the potential thermal contact + * resistance at the probe location and the specified probe side. */ +static res_T +setup_thermal_contact_resistance + (struct stardis* stardis, + const unsigned desc_ids[SG3D_PROP_TYPES_COUNT__], + const enum sdis_side probe_side) +{ + struct str log_msg; + const struct description* desc_list = NULL; + const struct description* desc_front = NULL; + const struct description* desc_back = NULL; + const struct description* desc_intface = NULL; + size_t ndescs = 0; + double tcr = 0; + res_T res = RES_OK; + (void)ndescs; /* Avoid "Unused variable" warnings in release */ + + /* Check pre-conditions */ + ASSERT(stardis && desc_ids); + + str_init(stardis->allocator, &log_msg); + + /* Fetch the properties */ + desc_list = darray_descriptions_cdata_get(&stardis->descriptions); + ndescs = darray_descriptions_size_get(&stardis->descriptions); + desc_front = desc_list + desc_ids[SG3D_FRONT]; + desc_back = desc_list + desc_ids[SG3D_BACK]; + desc_intface = desc_list + desc_ids[SG3D_INTFACE]; + + /* Get the thermal contact resistance between solid/solid connection if any */ + if(desc_ids[SG3D_INTFACE] != SG3D_UNSPECIFIED_PROPERTY + && desc_intface->type == DESC_SOLID_SOLID_CONNECT) { + ASSERT(desc_ids[SG3D_INTFACE] < ndescs); + tcr = desc_intface->d.ss_connect->tcr; + } + + /* Warn if side defined and no resistance defined */ + if(tcr == 0 && probe_side != SDIS_SIDE_NULL__) { + logger_print(stardis->logger, LOG_WARNING, + "Specifying a compute side at an interface with no contact resistance " + "is meaningless.\n"); + } + + #define GET_DESC_NAME(Desc) str_cget(get_description_name(Desc)) + + /* A thermal contact resistance cannot be defined if probe side is NULL */ + if(tcr != 0 && probe_side == SDIS_SIDE_NULL__) { + logger_print(stardis->logger, LOG_ERROR, + "Cannot let probe computation side unspecified on an interface with a " + "non-nul thermal resistance.\n"); + + /* Format the log string */ + if(desc_ids[SG3D_FRONT] != SG3D_UNSPECIFIED_PROPERTY) { + ASSERT(desc_ids[SG3D_FRONT] < ndescs); + ERR(str_append_printf(&log_msg, " FRONT: '%s'", GET_DESC_NAME(desc_front))); + } + if(desc_ids[SG3D_FRONT] != SG3D_UNSPECIFIED_PROPERTY + && desc_ids[SG3D_BACK] != SG3D_UNSPECIFIED_PROPERTY) { + ERR(str_append_char(&log_msg, ',')); + } + if(desc_ids[SG3D_BACK] != SG3D_UNSPECIFIED_PROPERTY) { + ASSERT(desc_ids[SG3D_BACK] < ndescs); + ERR(str_append_printf(&log_msg, " BACK: '%s'", GET_DESC_NAME(desc_back))); + } + + /* Print error message */ + logger_print(stardis->logger, LOG_ERROR, + "Interface '%s',%s, resistance=%g K.m^2/W.\n", + GET_DESC_NAME(desc_intface), str_cget(&log_msg), tcr); + + res = RES_BAD_ARG; + goto error; + } + + /* Log that a calculation is done on a boundary with tcr */ + if(tcr > 0) { + const char* medium_name = probe_side == SDIS_FRONT + ? GET_DESC_NAME(desc_front) + : GET_DESC_NAME(desc_back); + + logger_print(stardis->logger, LOG_OUTPUT, + "Probe computation on an interface with a thermal resistance = %g K.m^2/W " + "on %s side (medium is '%s').\n", + tcr, sdis_side_to_cstr(probe_side), medium_name); + } + + #undef GET_DESC_NAME + +exit: + str_release(&log_msg); + return res; +error: + goto exit; +} + +static res_T +solve + (struct stardis* stardis, + struct time* start, + struct sdis_solve_probe_boundary_args* args, + res_T output[2]) +{ + struct time t0, t1; + struct sdis_mc time = SDIS_MC_NULL; + struct dump_path_context ctx = DUMP_PATH_CONTEXT_NULL; + struct sdis_estimator* estimator = NULL; + const struct str* rng_in = NULL; + const struct str* rng_out = NULL; + struct ssp_rng* rng = NULL; + int is_master_process = 0; + res_T res = RES_OK; + ASSERT(stardis && args && output); + + is_master_process = !stardis->mpi_initialized || stardis->mpi_rank == 0; + + rng_in = &stardis->rndgen_state_in_filename; + rng_out = &stardis->rndgen_state_in_filename; + + /* Read RNG state from file */ + if(!str_is_empty(rng_in)) { + ERR(ssp_rng_create(stardis->allocator, SSP_RNG_THREEFRY, &rng)); + ERR(read_rng_state(stardis, str_cget(rng_in), rng)); + args->rng_state = rng; + } + + /* Run the calculation */ + time_current(&t0); + ERR(sdis_solve_probe_boundary(stardis->sdis_scn, args, &estimator)); + time_current(&t1); + + /* No more to do for non master processes */ + if(!is_master_process) goto exit; + + /* Per per realisation time */ + ERR(sdis_estimator_get_realisation_time(estimator, &time)); + ERR(print_computation_time(&time, stardis, start, &t0, &t1, NULL)); + + /* Write outputs and save their status */ + ctx.stardis = stardis; + ctx.rank = 0; + output[0] = print_single_MC_result(estimator, stardis, stdout); + output[1] = sdis_estimator_for_each_path(estimator, dump_path, &ctx); + + /* Write the resulting RNG state to a file */ + if(!str_is_empty(rng_out)) { + struct ssp_rng* rng_state = NULL; + ERR(sdis_estimator_get_rng_state(estimator, &rng_state)); + ERR(write_rng_state(stardis, str_cget(rng_out), rng_state)); + } + +exit: + if(estimator) SDIS(estimator_ref_put(estimator)); + if(rng) SSP(rng_ref_put(rng)); + return res; +error: + goto exit; +} + +static res_T +solve_list + (struct stardis* stardis, + struct time* start, + struct sdis_solve_probe_boundary_list_args* args, + res_T* output) +{ + struct time t0, t1; + struct sdis_mc time = SDIS_MC_NULL; /* Time per realisation */ + struct sdis_estimator_buffer* buffer = NULL; + size_t i = 0; + size_t def[2] = {0, 0}; + int is_master_process = 0; + res_T res = RES_OK; + ASSERT(stardis && start && args); + + is_master_process = !stardis->mpi_initialized || stardis->mpi_rank == 0; + + /* Run the calculation */ + time_current(&t0); + ERR(sdis_solve_probe_boundary_list(stardis->sdis_scn, args, &buffer)); + time_current(&t1); + + /* No more to do for non master processes */ + if(!is_master_process) goto exit; + + /* Retrieve the number of solved probes */ + ERR(sdis_estimator_buffer_get_definition(buffer, def)); + ASSERT(def[0] == darray_probe_boundary_size_get(&stardis->probe_boundary_list)); + ASSERT(def[1] == 1); + + ERR(sdis_estimator_buffer_get_realisation_time(buffer, &time)); + ERR(print_computation_time(&time, stardis, start, &t0, &t1, NULL)); + + /* Print the estimated temperature of each probe */ + FOR_EACH(i, 0, def[0]) { + const struct stardis_probe_boundary* probe = NULL; + const struct sdis_estimator* estimator = NULL; + res_T res2 = RES_OK; + + probe = darray_probe_boundary_cdata_get(&stardis->probe_boundary_list) + i; + ERR(sdis_estimator_buffer_at(buffer, i, 0, &estimator)); + + res2 = print_single_MC_result_probe_boundary + (stardis, probe, estimator, stdout); + if(res2 != RES_OK && *output == RES_OK) *output = res2; + } + +exit: + if(buffer) SDIS(estimator_buffer_ref_put(buffer)); + return res; +error: + goto exit; +} + +static res_T +solve_green + (struct stardis* stardis, + struct time* start, + struct sdis_solve_probe_boundary_args* args) +{ + struct time t0/*calculation start*/, t1/*calculation end*/, t2/*output end*/; + struct sdis_green_function* green = NULL; + FILE* fp_green = NULL; + FILE* fp_path = NULL; + const struct str* rng_in = NULL; + struct ssp_rng* rng = NULL; + int is_master_process = 0; + res_T res = RES_OK; + + ASSERT(stardis && args); + + is_master_process = !stardis->mpi_initialized || stardis->mpi_rank == 0; + + rng_in = &stardis->rndgen_state_in_filename; + + /* Read RNG state from file */ + if(!str_is_empty(rng_in)) { + ERR(ssp_rng_create(stardis->allocator, SSP_RNG_THREEFRY, &rng)); + ERR(read_rng_state(stardis, str_cget(rng_in), rng)); + args->rng_state = rng; + } + + /* Try to open output files to detect errors early */ + if(is_master_process && (stardis->mode & MODE_BIN_GREEN)) { + const char* green_filename = str_cget(&stardis->bin_green_filename); + const char* path_filename = str_cget(&stardis->end_paths_filename); + + if((fp_green = fopen(green_filename, "wb")) == NULL) { + logger_print(stardis->logger, LOG_ERROR, + "Cannot open file '%s' for binary writing.\n", green_filename); + res = RES_IO_ERR; + goto error; + } + + if(strlen(path_filename) != 0) { + if((fp_path = fopen(path_filename, "w")) == NULL) { + logger_print(stardis->logger, LOG_ERROR, + "Cannot open file '%s' for writing.\n", path_filename); + res = RES_IO_ERR; + goto error; + } + } + } + + /* Run the Green estimation */ + time_current(&t0); /* Calculation starts */ + ERR(sdis_solve_probe_boundary_green_function(stardis->sdis_scn, args, &green)); + time_current(&t1); /* Calculation ends */ + + /* No more to do for non master processes */ + if(is_master_process) goto exit; + + /* Write ASCII Green */ + if(stardis->mode & MODE_GREEN) { + ERR(dump_green_ascii(green, stardis, stdout)); + } + + /* Write binary Green */ + if(stardis->mode & MODE_BIN_GREEN) { + ERR(dump_green_bin(green, stardis, fp_green)); + if(fp_path) { + ERR(dump_paths_end(green, stardis, fp_path)); + } + } + + time_current(&t2); /* Output ends */ + + ERR(print_computation_time(NULL, stardis, start, &t0, &t1, &t2)); + + /* Note that the resulting RNG state is not written in an output file because + * the solver API does not provide a function to recover it. But in fact, the + * green function saves the RNG state after its estimation. Therefore, the API + * can be expected to provide such functionality soon. + * + * TODO write the RNG status of the Green function when it is available */ + +exit: + if(fp_green) CHK(fclose(fp_green) == 0); + if(fp_path) CHK(fclose(fp_path) == 0); + if(green) SDIS(green_function_ref_put(green)); + if(rng) SSP(rng_ref_put(rng)); + return res; +error: + goto exit; +} + +static res_T +setup_solve_probe_boundary_args + (struct stardis* stardis, + const struct stardis_probe_boundary* probe, + struct sdis_solve_probe_boundary_args* args) +{ + enum sdis_side probe_side = SDIS_SIDE_NULL__; + double uv[2] = {0, 0}; + size_t iprim = SIZE_MAX; + unsigned desc_ids[SG3D_PROP_TYPES_COUNT__]; + res_T res = RES_OK; + ASSERT(stardis && probe && args); + + /* Calculate the probe position on the boundary */ + ERR(move_to_boundary(stardis, probe->position, probe->time[0], &iprim, uv)); + + ERR(sg3d_geometry_get_unique_triangle_properties(stardis->geometry.sg3d, + (unsigned)iprim, desc_ids)); + + ERR(setup_probe_side(stardis, desc_ids, probe->side, iprim, &probe_side)); + ERR(setup_thermal_contact_resistance(stardis, desc_ids, probe_side)); + + /* Setup of solve input parameters */ + args->nrealisations = stardis->samples; + args->iprim = iprim; + args->uv[0] = uv[0]; + args->uv[1] = uv[1]; + args->time_range[0] = probe->time[0]; + args->time_range[1] = probe->time[1]; + args->picard_order = stardis->picard_order; + args->side = probe_side; + args->register_paths = stardis->dump_paths; + + /* The solver does not accept that the side of the interface on which the + * probe is placed is invalid. Below, the side is arbitrarily defined because + * at this point, Stardis has already arbitrated that this side does not + * matter (i.e. there is no thermal contact resistance) */ + if(args->side == SDIS_SIDE_NULL__) { + args->side = SDIS_FRONT; + } + +exit: + return res; +error: + goto exit; +} + +static res_T +compute_single_probe_on_interface + (struct stardis* stardis, + struct time* start, + const struct stardis_probe_boundary* probe) +{ + struct sdis_solve_probe_boundary_args args + = SDIS_SOLVE_PROBE_BOUNDARY_ARGS_DEFAULT; + res_T output_status[2] = {RES_OK, RES_OK}; + res_T res = RES_OK; + ASSERT(stardis && start && probe); + + ERR(setup_solve_probe_boundary_args(stardis, probe, &args)); + + /* Run the calculation */ + if(stardis->mode & (MODE_GREEN | MODE_BIN_GREEN)) { + ERR(solve_green(stardis, start, &args)); + } else { + ERR(solve(stardis, start, &args, output_status)); + } + +exit: + res = (res != RES_OK ? res : output_status[0]); + res = (res != RES_OK ? res : output_status[1]); + return res; +error: + goto exit; +} + +static res_T +compute_multiple_probes_on_interface + (struct stardis* stardis, + struct time* start) +{ + /* Probes */ + const struct stardis_probe_boundary* probes = NULL; + struct sdis_solve_probe_boundary_args* solve_args = NULL; + struct sdis_solve_probe_boundary_list_args solve_list_args = + SDIS_SOLVE_PROBE_BOUNDARY_LIST_ARGS_DEFAULT; + size_t nprobes = 0; + + /* Miscellaneous */ + res_T output_status = RES_OK; + res_T res = RES_OK; + size_t i= 0; + ASSERT(stardis && start); + + /* Fetch the list of probes arguments */ + probes = darray_probe_boundary_cdata_get(&stardis->probe_boundary_list); + nprobes = darray_probe_boundary_size_get(&stardis->probe_boundary_list); + ASSERT(nprobes > 1); + + solve_args = MEM_CALLOC(stardis->allocator, nprobes, sizeof(*solve_args)); + if(!probes) { + logger_print(stardis->logger, LOG_ERROR, + "Argument list allocation error for resolving multiple probes " + "on the boundary.\n"); + res = RES_MEM_ERR; + goto error; + } + + /* Setup the solve arguments */ + FOR_EACH(i, 0, nprobes) { + solve_args[i] = SDIS_SOLVE_PROBE_BOUNDARY_ARGS_DEFAULT; + ERR(setup_solve_probe_boundary_args(stardis, &probes[i], &solve_args[i])); + } + solve_list_args.probes = solve_args; + solve_list_args.nprobes = nprobes; + + /* Run calculations */ + ERR(solve_list(stardis, start, &solve_list_args, &output_status)); + +exit: + if(probes) MEM_RM(stardis->allocator, solve_args); + res = (res != RES_OK ? res : output_status); + return res; +error: + goto exit; +} + +/******************************************************************************* + * Local functions + ******************************************************************************/ +res_T +compute_probe_on_interface(struct stardis* stardis, struct time* start) +{ + res_T res = RES_OK; + ASSERT(stardis && start); + ASSERT((stardis->mode & MODE_PROBE_COMPUTE_ON_INTERFACE) + || (stardis->mode & MODE_PROBE_LIST_COMPUTE_ON_INTERFACE)); + + /* Multiple probes */ + if(stardis->mode & MODE_PROBE_LIST_COMPUTE_ON_INTERFACE) { + ASSERT(darray_probe_boundary_size_get(&stardis->probe_boundary_list) > 1); + + res = compute_multiple_probes_on_interface(stardis, start); + if(res != RES_OK) goto error; + + /* Single probe */ + } else if(stardis->mode & MODE_PROBE_COMPUTE_ON_INTERFACE) { + const struct stardis_probe_boundary* probe = NULL; + ASSERT(darray_probe_boundary_size_get(&stardis->probe_boundary_list) == 1); + + probe = darray_probe_boundary_cdata_get(&stardis->probe_boundary_list); + res = compute_single_probe_on_interface(stardis, start, probe); + if(res != RES_OK) goto error; + } + +exit: + return res; +error: + goto exit; +} diff --git a/src/stardis-compute.c b/src/stardis-compute.c @@ -192,7 +192,6 @@ hit_filter static res_T check_probe_conform_to_type (const struct stardis* stardis, - const int move2boundary, double pos[3], double time, unsigned* iprim, @@ -207,7 +206,7 @@ check_probe_conform_to_type struct s3d_vertex_data attribs; struct filter_ctx filter_ctx = FILTER_CTX_DEFAULT__; float origin[3]; - unsigned vcount, tcount, j; + unsigned vcount, tcount; ASSERT(stardis && pos && iprim && uv); @@ -244,175 +243,80 @@ check_probe_conform_to_type } ASSERT(filter_ctx.dist == hit.distance); - if(move2boundary) { - /* Need to move probe to closest boundary */ - int danger = 0; - if(filter_ctx.outside) { - /* Not an error as probe moved to boundary */ - logger_print(stardis->logger, LOG_WARNING, - "Probe was outside the model.\n"); - } - if(!filter_ctx.desc) { - /* Not an error as probe moved to boundary */ - if(!filter_ctx.probe_on_boundary && !filter_ctx.outside) - logger_print(stardis->logger, LOG_WARNING, - "Could not determine the medium probe is in.\n"); - } else { - if(DESC_IS_SOLID(filter_ctx.desc)) { - double delta; - const char* pppp; - if(filter_ctx.desc->type == DESC_MAT_SOLID) { - struct solid* solid = filter_ctx.desc->d.solid; - delta = solid->delta; - pppp = ""; - } else { - struct solid_prog* solid_prog = filter_ctx.desc->d.solid_prog; - struct stardis_vertex vtx; - ASSERT(filter_ctx.desc->type == DESC_MAT_SOLID_PROG); - d3_set(vtx.P, pos); - vtx.time = time; - delta = solid_prog->delta(&vtx, solid_prog->prog_data); - pppp = "programmed "; - } - ASSERT(delta < INF); - logger_print(stardis->logger, LOG_OUTPUT, - "Probe was in %ssolid '%s'.\n", - pppp, str_cget(get_description_name(filter_ctx.desc))); - if(filter_ctx.dist > 2 * delta) { - logger_print(stardis->logger, LOG_ERROR, - "Probe moved to (%g, %g, %g), primitive %u, uv = (%g, %g).\n", - SPLIT3(filter_ctx.pos), hit.prim.prim_id, SPLIT2(hit.uv)); - logger_print(stardis->logger, LOG_ERROR, - "Move is %g delta long. Use -p instead of -P.\n", - filter_ctx.dist / delta); - res = RES_BAD_ARG; - goto error; - } - if(filter_ctx.dist > 0.5 * delta) { - logger_print(stardis->logger, LOG_WARNING, - "Probe was %g delta from closest boundary. " - "Consider using -p instead of -P.\n", - filter_ctx.dist / delta); - } else { - if(filter_ctx.dist != 0) - logger_print(stardis->logger, LOG_OUTPUT, - "Probe was %g delta from closest boundary.\n", - filter_ctx.dist / delta); - } - } else { - const char* pppp; - ASSERT(DESC_IS_FLUID(filter_ctx.desc)); - /* TODO: check move length wrt local geometry? */ - if(filter_ctx.desc->type == DESC_MAT_FLUID) { - pppp = ""; - } else { - ASSERT(filter_ctx.desc->type == DESC_MAT_FLUID_PROG); - pppp = "programmed "; - } - logger_print(stardis->logger, LOG_OUTPUT, - "Probe was in %sfluid '%s'.\n", - pppp, str_cget(get_description_name(filter_ctx.desc))); - logger_print(stardis->logger, LOG_OUTPUT, - "Probe distance from closest boundary was %g.\n", filter_ctx.dist); - } - } - /* Check if moved to vertex/edge */ - FOR_EACH(j, 0, 2) { - if(CLAMP(hit.uv[j], 0.0005, 0.9995) != hit.uv[j]) - danger++; - } - if(danger) { - logger_print(stardis->logger, LOG_WARNING, - "Probe %s close to / on %s. " - "If computation fails, try moving it slightly.\n", - (filter_ctx.dist != 0 ? "moved" : "is"), (danger == 1 ? "an edge" : "a vertex")); - } - if(filter_ctx.probe_on_boundary) { - logger_print(stardis->logger, LOG_OUTPUT, - "Probe is on primitive %u, uv = (%g, %g), not moved.\n", - hit.prim.prim_id, SPLIT2(hit.uv)); + /* Need to check medium */ + if(filter_ctx.outside) { + logger_print(stardis->logger, LOG_ERROR, + "Probe is outside the model.\n"); + logger_print(stardis->logger, LOG_ERROR, + "Closest geometry is primitive %u, uv = (%g, %g), pos (%g, %g, %g).\n", + hit.prim.prim_id, SPLIT2(hit.uv), SPLIT3(filter_ctx.pos)); + res = RES_BAD_ARG; + goto error; + } + if(filter_ctx.probe_on_boundary) { + logger_print(stardis->logger, LOG_ERROR, + "Probe is on primitive %u, uv = (%g, %g). Use -P instead of -p.\n", + hit.prim.prim_id, SPLIT2(hit.uv)); + res = RES_BAD_ARG; + goto error; + } + if(!filter_ctx.desc) { + logger_print(stardis->logger, LOG_ERROR, + "Could not determine the medium probe is in. " + "Try moving it slightly.\n"); + logger_print(stardis->logger, LOG_ERROR, + "Closest geometry is primitive %u, uv = (%g, %g), distance %g.\n", + hit.prim.prim_id, SPLIT2(hit.uv), filter_ctx.dist); + res = RES_BAD_ARG; + goto error; + } + if(DESC_IS_SOLID(filter_ctx.desc)) { + double delta; + if(filter_ctx.desc->type == DESC_MAT_SOLID) { + struct solid* solid = filter_ctx.desc->d.solid; + delta = solid->delta; } else { - logger_print(stardis->logger, LOG_OUTPUT, - "Probe moved to (%g, %g, %g), primitive %u, uv = (%g, %g).\n", - SPLIT3(filter_ctx.pos), hit.prim.prim_id, SPLIT2(hit.uv)); + struct solid_prog* solid_prog = filter_ctx.desc->d.solid_prog; + struct stardis_vertex vtx; + ASSERT(filter_ctx.desc->type == DESC_MAT_SOLID_PROG); + d3_set(vtx.P, pos); + vtx.time = time; + delta = solid_prog->delta(&vtx, solid_prog->prog_data); } - d3_set_f3(pos, filter_ctx.pos); - } else { - /* Need to check medium */ - if(filter_ctx.outside) { + if(filter_ctx.dist < 0.25 * delta) { logger_print(stardis->logger, LOG_ERROR, - "Probe is outside the model.\n"); - logger_print(stardis->logger, LOG_ERROR, - "Closest geometry is primitive %u, uv = (%g, %g), pos (%g, %g, %g).\n", - hit.prim.prim_id, SPLIT2(hit.uv), SPLIT3(filter_ctx.pos)); - res = RES_BAD_ARG; - goto error; - } - if(filter_ctx.probe_on_boundary) { + "Probe is %g delta from closest boundary. Use -P instead of -p.\n", + filter_ctx.dist / delta); logger_print(stardis->logger, LOG_ERROR, - "Probe is on primitive %u, uv = (%g, %g). Use -P instead of -p.\n", + "Closest geometry is primitive %u, uv = (%g, %g).\n", hit.prim.prim_id, SPLIT2(hit.uv)); res = RES_BAD_ARG; goto error; } - if(!filter_ctx.desc) { - logger_print(stardis->logger, LOG_ERROR, - "Could not determine the medium probe is in. " - "Try moving it slightly.\n"); - logger_print(stardis->logger, LOG_ERROR, - "Closest geometry is primitive %u, uv = (%g, %g), distance %g.\n", - hit.prim.prim_id, SPLIT2(hit.uv), filter_ctx.dist); - res = RES_BAD_ARG; - goto error; + if(filter_ctx.dist < 0.5 * delta) { + logger_print(stardis->logger, LOG_WARNING, + "Probe is %g delta from closest boundary. " + "Consider using -P instead of -p.\n", + filter_ctx.dist / delta); + } else { + logger_print(stardis->logger, LOG_OUTPUT, + "Probe is %g delta from closest boundary.\n", + filter_ctx.dist / delta); } - if(DESC_IS_SOLID(filter_ctx.desc)) { - double delta; - if(filter_ctx.desc->type == DESC_MAT_SOLID) { - struct solid* solid = filter_ctx.desc->d.solid; - delta = solid->delta; - } else { - struct solid_prog* solid_prog = filter_ctx.desc->d.solid_prog; - struct stardis_vertex vtx; - ASSERT(filter_ctx.desc->type == DESC_MAT_SOLID_PROG); - d3_set(vtx.P, pos); - vtx.time = time; - delta = solid_prog->delta(&vtx, solid_prog->prog_data); - } - if(filter_ctx.dist < 0.25 * delta) { - logger_print(stardis->logger, LOG_ERROR, - "Probe is %g delta from closest boundary. Use -P instead of -p.\n", - filter_ctx.dist / delta); - logger_print(stardis->logger, LOG_ERROR, - "Closest geometry is primitive %u, uv = (%g, %g).\n", - hit.prim.prim_id, SPLIT2(hit.uv)); - res = RES_BAD_ARG; - goto error; - } - if(filter_ctx.dist < 0.5 * delta) { - logger_print(stardis->logger, LOG_WARNING, - "Probe is %g delta from closest boundary. " - "Consider using -P instead of -p.\n", - filter_ctx.dist / delta); - } else { - logger_print(stardis->logger, LOG_OUTPUT, - "Probe is %g delta from closest boundary.\n", - filter_ctx.dist / delta); - } + } else { + ASSERT(DESC_IS_FLUID(filter_ctx.desc)); + /* In fluid; TODO: check distance wrt local geometry (use 4V/S?) */ + if(filter_ctx.desc->type == DESC_MAT_FLUID) { + logger_print(stardis->logger, LOG_WARNING, + "Probe is in fluid '%s': computing fluid temperature, " + "not using a specific position.\n", + str_cget(&filter_ctx.desc->d.fluid->name)); } else { - ASSERT(DESC_IS_FLUID(filter_ctx.desc)); - /* In fluid; TODO: check distance wrt local geometry (use 4V/S?) */ - if(filter_ctx.desc->type == DESC_MAT_FLUID) { - logger_print(stardis->logger, LOG_WARNING, - "Probe is in fluid '%s': computing fluid temperature, " - "not using a specific position.\n", - str_cget(&filter_ctx.desc->d.fluid->name)); - } else { - ASSERT(filter_ctx.desc->type == DESC_MAT_FLUID_PROG); - logger_print(stardis->logger, LOG_WARNING, - "Probe is in fluid_prog '%s': computing fluid temperature, " - "not using a specific position.\n", - str_cget(&filter_ctx.desc->d.fluid_prog->name)); - } + ASSERT(filter_ctx.desc->type == DESC_MAT_FLUID_PROG); + logger_print(stardis->logger, LOG_WARNING, + "Probe is in fluid_prog '%s': computing fluid temperature, " + "not using a specific position.\n", + str_cget(&filter_ctx.desc->d.fluid_prog->name)); } } @@ -490,7 +394,7 @@ compute_probe(struct stardis* stardis, struct time* start) ASSERT(stardis && start && (stardis->mode & MODE_PROBE_COMPUTE)); - ERR(check_probe_conform_to_type(stardis, 0, stardis->probe, + ERR(check_probe_conform_to_type(stardis, stardis->probe, stardis->time_range[0], &iprim, uv)); args.nrealisations = stardis->samples; @@ -552,274 +456,14 @@ compute_probe(struct stardis* stardis, struct time* start) if(stardis->mpi_initialized && stardis->mpi_rank != 0) { ERR(sdis_solve_probe(stardis->sdis_scn, &args, &estimator)); } else { + struct sdis_mc time = SDIS_MC_NULL; res_T tmp_res1, tmp_res2; time_current(&compute_start); ERR(sdis_solve_probe(stardis->sdis_scn, &args, &estimator)); time_current(&compute_end); - ERR(print_computation_time(estimator, stardis, - start, &compute_start, &compute_end, NULL)); - tmp_res1 = print_single_MC_result(estimator, stardis, stdout); - - /* Dump recorded paths according to user settings */ - dump_ctx.stardis = stardis; - dump_ctx.rank = 0; - tmp_res2 = sdis_estimator_for_each_path(estimator, dump_path, &dump_ctx); - if(tmp_res1 != RES_OK) res = tmp_res1; - else if(tmp_res2 != RES_OK) res = tmp_res2; - } - } - - /* Output random state? */ - WRITE_RANDOM_STATE(&stardis->rndgen_state_out_filename); - -end: - if(stream_r) fclose(stream_r); - if(stream_g) fclose(stream_g); - if(stream_p) fclose(stream_p); - if(estimator) SDIS(estimator_ref_put(estimator)); - if(green) SDIS(green_function_ref_put(green)); - if(args.rng_state) SSP(rng_ref_put(args.rng_state)); - return res; -error: - goto end; -} - -static res_T -compute_probe_on_interface(struct stardis* stardis, struct time* start) -{ - res_T res = RES_OK; - double uv[2] = { 0,0 }; - unsigned iprim = UINT_MAX; - struct sdis_estimator* estimator = NULL; - struct sdis_green_function* green = NULL; - struct dump_path_context dump_ctx; - struct sdis_solve_probe_boundary_args args - = SDIS_SOLVE_PROBE_BOUNDARY_ARGS_DEFAULT; - FILE* stream_r = NULL; - FILE* stream_g = NULL; - FILE* stream_p = NULL; - struct time compute_start, compute_end; - enum sdis_side compute_side; - unsigned prop[3]; - const struct description* descriptions - = darray_descriptions_cdata_get(&stardis->descriptions); - double tcr = 0; - const char* solve_name; - const char* compute_side_name = NULL; - const char* medium_name = NULL; - const struct description* intface_desc = NULL; -#ifndef NDEBUG - const size_t dcount = darray_descriptions_size_get(&stardis->descriptions); -#endif - - ASSERT(stardis && start && (stardis->mode & MODE_PROBE_COMPUTE_ON_INTERFACE)); - ERR(check_probe_conform_to_type(stardis, 1, stardis->probe, - stardis->time_range[0], &iprim, uv)); - ASSERT(iprim != UINT_MAX); - - ERR(sg3d_geometry_get_unique_triangle_properties(stardis->geometry.sg3d, - (unsigned)iprim, prop)); - - if(prop[SG3D_INTFACE] != SG3D_UNSPECIFIED_PROPERTY) { - ASSERT(prop[SG3D_INTFACE] < dcount); - intface_desc = descriptions + prop[SG3D_INTFACE]; - if(intface_desc->type == DESC_SOLID_SOLID_CONNECT) - tcr = intface_desc->d.ss_connect->tcr; - } - - if(str_is_empty(&stardis->solve_name)) { - solve_name = NULL; - compute_side = SDIS_SIDE_NULL__; /* Side is let unspecified */ - } else { - solve_name = str_cget(&stardis->solve_name); - if(0 == strcasecmp(solve_name, "FRONT")) { - const struct description* d; - ASSERT(prop[SG3D_FRONT] < dcount); - d = descriptions + prop[SG3D_FRONT]; - ASSERT(DESC_IS_MEDIUM(d)); - medium_name = str_cget(get_description_name(d)); - compute_side = SDIS_FRONT; - compute_side_name = "FRONT"; - } - else if(0 == strcasecmp(solve_name, "BACK")) { - const struct description* d; - ASSERT(prop[SG3D_BACK] < dcount); - d = descriptions + prop[SG3D_BACK]; - ASSERT(DESC_IS_MEDIUM(d)); - medium_name = str_cget(get_description_name(d)); - compute_side = SDIS_BACK; - compute_side_name = "BACK"; - } else { /* solve_name must be a medium name */ - unsigned med_id, fmat_id, bmat_id; - const struct description* fd; - const struct description* bd; - struct sdis_medium* medium - = find_medium_by_name(stardis, &stardis->solve_name, &med_id); - if(medium == NULL) { /* Not found */ - logger_print(stardis->logger, LOG_ERROR, - "Cannot locate side from medium name '%s' (unknown medium)\n", - solve_name); - res = RES_BAD_ARG; - goto error; - } - - fd = descriptions + prop[SG3D_FRONT]; - bd = descriptions + prop[SG3D_BACK]; - ASSERT(DESC_IS_MEDIUM(fd)); - ASSERT(DESC_IS_MEDIUM(bd)); - description_get_medium_id(fd, &fmat_id); - description_get_medium_id(bd, &bmat_id); - - if(med_id != fmat_id && med_id != bmat_id) { /* Not here */ - logger_print(stardis->logger, LOG_ERROR, - "Medium '%s' is not used at this interface (prim id=%u)\n", - solve_name, iprim); - res = RES_BAD_ARG; - goto error; - } - if(fmat_id == bmat_id) { /* Cannot differentiate */ - unsigned encs[2]; - ERR(senc3d_scene_get_triangle_enclosures(stardis->senc3d_scn, iprim, - encs)); - logger_print(stardis->logger, LOG_ERROR, - "Medium '%s' is used on both sides of this interface (prim id=%u)\n", - solve_name,iprim); - logger_print(stardis->logger, LOG_ERROR, - "Side must be defined using either FRONT or BACK.\n"); - logger_print(stardis->logger, LOG_ERROR, - "FRONT side is related to enclosure %u, BACK side to enclosure %u.\n", - encs[SENC3D_FRONT], encs[SENC3D_BACK]); - res = RES_BAD_ARG; - goto error; - } - medium_name = solve_name; - if(med_id == fmat_id) { - compute_side = SDIS_FRONT; - compute_side_name = "FRONT"; - } else { - compute_side = SDIS_BACK; - compute_side_name = "BACK"; - } - } - } - - if(compute_side == SDIS_SIDE_NULL__) { - /* Cannot have defined a contact resistance here */ - if(tcr != 0) { - const struct description* fdesc = NULL; - const struct description* bdesc = NULL; - if(prop[SG3D_FRONT] != SG3D_UNSPECIFIED_PROPERTY) { - ASSERT(prop[SG3D_FRONT] < dcount); - fdesc = descriptions + prop[SG3D_FRONT]; - } - if(prop[SG3D_BACK] != SG3D_UNSPECIFIED_PROPERTY) { - ASSERT(prop[SG3D_BACK] < dcount); - bdesc = descriptions + prop[SG3D_BACK]; - } - ASSERT(fdesc || bdesc); - logger_print(stardis->logger, LOG_ERROR, - "Cannot let probe computation side unspecified on an interface with a " - "non-nul thermal resistance.\n"); - logger_print(stardis->logger, LOG_ERROR, - "Interface '%s',%s%s%s%s%s%s%s, resistance=%g K.m^2/W.\n", - str_cget(get_description_name(intface_desc)), - (fdesc ? " FRONT:'" : ""), - (fdesc ? str_cget(get_description_name(fdesc)) : ""), - (fdesc ? "'" : ""), - (fdesc && bdesc ? "," : ""), - (bdesc ? " BACK:'" : ""), - (bdesc ? str_cget(get_description_name(bdesc)) : ""), - (bdesc ? "'" : ""), - tcr); - res = RES_BAD_ARG; - goto error; - } - /* Any side is OK as temperature is the same */ - compute_side = SDIS_FRONT; - } else if (tcr == 0) { - /* Warn if side defined and no resistance defined */ - logger_print(stardis->logger, LOG_WARNING, - "Specifying a compute side at an interface with no contact resistance " - "is meaningless.\n"); - } - - if(tcr > 0) { - ASSERT(compute_side_name && medium_name); - logger_print(stardis->logger, LOG_OUTPUT, - "Probe computation on an interface with a thermal resistance = %g K.m^2/W " - "on %s side (medium is '%s').\n", - tcr, compute_side_name, medium_name); - } - - args.nrealisations = stardis->samples; - args.iprim = iprim; - d2_set(args.uv, uv); - args.side = compute_side; - d2_set(args.time_range, stardis->time_range); - - /* Input random state? */ - READ_RANDOM_STATE(&stardis->rndgen_state_in_filename); - - if(stardis->mode & (MODE_BIN_GREEN | MODE_GREEN)) { - if(stardis->mpi_initialized && stardis->mpi_rank != 0) { - ERR(sdis_solve_probe_boundary_green_function(stardis->sdis_scn, &args, - &green)); - } else { - /* Try to open output files to detect errors early */ - if(stardis->mode & MODE_BIN_GREEN) { - ASSERT(!str_is_empty(&stardis->bin_green_filename)); - stream_g = fopen(str_cget(&stardis->bin_green_filename), "wb"); - if(!stream_g) { - logger_print(stardis->logger, LOG_ERROR, - "cannot open file '%s' for binary writing.\n", - str_cget(&stardis->bin_green_filename)); - res = RES_IO_ERR; - goto error; - } - if(str_cget(&stardis->end_paths_filename) - && strlen(str_cget(&stardis->end_paths_filename))) - { - stream_p = fopen(str_cget(&stardis->end_paths_filename), "w"); - if(!stream_p) { - logger_print(stardis->logger, LOG_ERROR, - "cannot open file '%s' for writing.\n", - str_cget(&stardis->end_paths_filename)); - res = RES_IO_ERR; - goto error; - } - } - } - /* Call solve() */ - time_current(&compute_start); - ERR(sdis_solve_probe_boundary_green_function(stardis->sdis_scn, &args, - &green)); - time_current(&compute_end); - if(stardis->mode & MODE_BIN_GREEN) { - struct time output_end; - ERR(dump_green_bin(green, stardis, stream_g)); - if(stream_p) { - ERR(dump_paths_end(green, stardis, stream_p)); - } - time_current(&output_end); - ERR(print_computation_time(NULL, stardis, - start, &compute_start, &compute_end, &output_end)); - } - if(stardis->mode & MODE_GREEN) { - ERR(dump_green_ascii(green, stardis, stdout)); - } - } - } else { - args.register_paths = stardis->dump_paths; - args.picard_order = stardis->picard_order; - if(stardis->mpi_initialized && stardis->mpi_rank != 0) { - ERR(sdis_solve_probe_boundary(stardis->sdis_scn, &args, &estimator)); - } else { - res_T tmp_res1, tmp_res2; - time_current(&compute_start); - ERR(sdis_solve_probe_boundary(stardis->sdis_scn, &args, &estimator)); - time_current(&compute_end); - ERR(print_computation_time(estimator, stardis, - start, &compute_start, &compute_end, NULL)); + ERR(sdis_estimator_get_realisation_time(estimator, &time)); + ERR(print_computation_time + (&time, stardis, start, &compute_start, &compute_end, NULL)); tmp_res1 = print_single_MC_result(estimator, stardis, stdout); /* Dump recorded paths according to user settings */ @@ -1040,7 +684,7 @@ compute_medium(struct stardis* stardis, struct time* start) ASSERT(stardis && start && (stardis->mode & MODE_MEDIUM_COMPUTE)); /* Find medium */ - medium = find_medium_by_name(stardis, &stardis->solve_name, NULL); + medium = find_medium_by_name(stardis, str_cget(&stardis->solve_name), NULL); if(medium == NULL) { /* Not found */ logger_print(stardis->logger, LOG_ERROR, "Cannot solve medium '%s' (unknown medium)\n", @@ -1109,12 +753,15 @@ compute_medium(struct stardis* stardis, struct time* start) if(stardis->mpi_initialized && stardis->mpi_rank != 0) { ERR(sdis_solve_medium(stardis->sdis_scn, &args, &estimator)); } else { + struct sdis_mc time = SDIS_MC_NULL; res_T tmp_res1, tmp_res2; time_current(&compute_start); ERR(sdis_solve_medium(stardis->sdis_scn, &args, &estimator)); time_current(&compute_end); - ERR(print_computation_time(estimator, stardis, - start, &compute_start, &compute_end, NULL)); + + ERR(sdis_estimator_get_realisation_time(estimator, &time)); + ERR(print_computation_time + (&time, stardis, start, &compute_start, &compute_end, NULL)); tmp_res1 = print_single_MC_result(estimator, stardis, stdout); /* Dump recorded paths according to user settings */ dump_ctx.stardis = stardis; @@ -1266,12 +913,14 @@ compute_boundary(struct stardis* stardis, struct time* start) if(stardis->mpi_initialized && stardis->mpi_rank != 0) { ERR(sdis_solve_boundary(stardis->sdis_scn, &args, &estimator)); } else { + struct sdis_mc time = SDIS_MC_NULL; res_T tmp_res1, tmp_res2; time_current(&compute_start); ERR(sdis_solve_boundary(stardis->sdis_scn, &args, &estimator)); time_current(&compute_end); - ERR(print_computation_time(estimator, stardis, - start, &compute_start, &compute_end, NULL)); + ERR(sdis_estimator_get_realisation_time(estimator, &time)); + ERR(print_computation_time + (&time, stardis, start, &compute_start, &compute_end, NULL)); tmp_res1 = print_single_MC_result(estimator, stardis, stdout); /* Dump recorded paths according to user settings */ dump_ctx.stardis = stardis; @@ -1325,12 +974,14 @@ compute_flux_boundary(struct stardis* stardis, struct time* start) if(stardis->mpi_initialized && stardis->mpi_rank != 0) { ERR(sdis_solve_boundary_flux(stardis->sdis_scn, &args, &estimator)); } else { + struct sdis_mc time = SDIS_MC_NULL; res_T tmp_res1, tmp_res2; time_current(&compute_start); ERR(sdis_solve_boundary_flux(stardis->sdis_scn, &args, &estimator)); time_current(&compute_end); - ERR(print_computation_time(estimator, stardis, - start, &compute_start, &compute_end, NULL)); + ERR(sdis_estimator_get_realisation_time(estimator, &time)); + ERR(print_computation_time + (&time, stardis, start, &compute_start, &compute_end, NULL)); tmp_res1 = print_single_MC_result(estimator, stardis, stdout); /* Dump recorded paths according to user settings */ @@ -1418,7 +1069,7 @@ error: struct sdis_medium* find_medium_by_name (struct stardis* stardis, - const struct str* name, + const char* name, unsigned* out_id) { struct sdis_medium* medium = NULL; @@ -1430,7 +1081,7 @@ find_medium_by_name unsigned id; struct description* desc = darray_descriptions_data_get(&stardis->descriptions) + i; - if(!str_eq(name, get_description_name(desc))) + if(strcmp(name, str_cget(get_description_name(desc))) != 0) continue; description_get_medium_id(desc, &id); ASSERT(darray_media_ptr_size_get(&stardis->media) > id); @@ -1529,6 +1180,8 @@ stardis_compute ERR(compute_probe(stardis, start)); else if(stardis->mode & MODE_PROBE_COMPUTE_ON_INTERFACE) ERR(compute_probe_on_interface(stardis, start)); + else if(stardis->mode & MODE_PROBE_LIST_COMPUTE_ON_INTERFACE) + ERR(compute_probe_on_interface(stardis, start)); else if(stardis->mode & MODE_IR_COMPUTE) ERR(compute_camera(stardis, start)); else if(stardis->mode & MODE_MEDIUM_COMPUTE) diff --git a/src/stardis-compute.h b/src/stardis-compute.h @@ -27,19 +27,24 @@ struct str; #define DARRAY_DATA struct sdis_estimator* #include <rsys/dynamic_array.h> -struct sdis_medium* +extern LOCAL_SYM struct sdis_medium* find_medium_by_name (struct stardis* stardis, - const struct str* name, + const char* name, unsigned* id); /* Can be NULL */ -res_T +extern LOCAL_SYM res_T stardis_compute (struct stardis* stardis, struct time* start); -res_T +extern LOCAL_SYM res_T read_compute_surface (struct stardis* stardis); +extern LOCAL_SYM res_T +compute_probe_on_interface + (struct stardis* stardis, + struct time* start); + #endif diff --git a/src/stardis-green-types.h.in b/src/stardis-green-types.h.in @@ -21,8 +21,8 @@ /* The number of the file format as presented thereafter */ #define GREEN_FILE_FORMAT_VERSION @STARDIS_GREEN_TYPES_VERSION@ -/* The max length for a description name */ -#define DESC_NAME_MAX_LEN 63 +/* The max length for a description name *WITHOUT* null char */ +#define DESC_NAME_MAX_LEN @STARDIS_MAX_NAME_LENGTH@ /* The string at the beginning of a binary Green file that identifies it */ #define BIN_FILE_IDENT_STRING "GREEN_BIN_FILE:" diff --git a/src/stardis-main.c b/src/stardis-main.c @@ -33,14 +33,10 @@ #endif int -main - (int argc, - char** argv) +main(int argc, char** argv) { struct args* args = NULL; struct stardis stardis; - int logger_initialized = 0, allocator_initialized = 0, - args_initialized = 0, stardis_initialized = 0, name_initialized = 0; int err = EXIT_SUCCESS; struct mem_allocator allocator; struct logger logger; @@ -50,6 +46,13 @@ main struct str name; res_T res = RES_OK; + /* Initialisation statuses */ + int logger_initialized = 0; + int allocator_initialized = 0; + int args_initialized = 0; + int stardis_initialized = 0; + int name_initialized = 0; + time_current(&start); #ifdef STARDIS_ENABLE_MPI @@ -74,7 +77,7 @@ main mode = (int)args->mode; if(mode & MODE_DUMP_HELP) { - short_help(stdout, argv[0]); + usage(stdout); goto exit; } else if(mode & MODE_DUMP_VERSION) { diff --git a/src/stardis-output.c b/src/stardis-output.c @@ -1551,15 +1551,13 @@ error: res_T print_computation_time - (struct sdis_estimator* estimator, + (struct sdis_mc* time_per_realisation, struct stardis* stardis, struct time* start, struct time* compute_start, struct time* compute_end, struct time* output_end) { - res_T res = RES_OK; - struct sdis_mc time; struct time tmp; char buf[128]; const int flag = TIME_MSEC | TIME_SEC | TIME_MIN | TIME_HOUR | TIME_DAY; @@ -1584,16 +1582,13 @@ print_computation_time "Result output time = %s\n", buf); } - if(estimator) { - ERR(sdis_estimator_get_realisation_time(estimator, &time)); + if(time_per_realisation) { logger_print(stardis->logger, LOG_OUTPUT, - "Time per realisation (in usec) = %g +/- %g\n", time.E, time.SE); + "Time per realisation (in usec) = %g +/- %g\n", + time_per_realisation->E, time_per_realisation->SE); } -exit: - return res; -error: - goto exit; + return RES_OK; } res_T @@ -1644,24 +1639,13 @@ print_single_MC_result else fprintf(stream, "%g %g %lu %lu\n", result.E, result.SE, nfailures, nsamples); break; - case MODE_PROBE_COMPUTE_ON_INTERFACE: - if(stardis->mode & MODE_EXTENDED_RESULTS) { - if(stardis->time_range[0] == stardis->time_range[1]) - fprintf(stream, - "Boundary temperature at [%g, %g, %g] at t=%g = %g K +/- %g\n", - SPLIT3(stardis->probe), stardis->time_range[0], - result.E, /* Expected value */ - result.SE); /* Standard error */ - else - fprintf(stream, - "Boundary temperature at [%g, %g, %g] with t in [%g %g] = %g K +/- %g\n", - SPLIT3(stardis->probe), SPLIT2(stardis->time_range), - result.E, /* Expected value */ - result.SE); /* Standard error */ + case MODE_PROBE_COMPUTE_ON_INTERFACE: { + const struct stardis_probe_boundary* probe = NULL; + probe = darray_probe_boundary_cdata_get(&stardis->probe_boundary_list); + ERR(print_single_MC_result_probe_boundary + (stardis, probe, estimator, stream)); + break; } - else fprintf(stream, "%g %g %lu %lu\n", - result.E, result.SE, nfailures, nsamples); - break; case MODE_MEDIUM_COMPUTE: if(stardis->mode & MODE_EXTENDED_RESULTS) { if(stardis->time_range[0] == stardis->time_range[1]) @@ -1801,6 +1785,61 @@ abort: } res_T +print_single_MC_result_probe_boundary + (struct stardis* stardis, + const struct stardis_probe_boundary* probe, + const struct sdis_estimator* estimator, + FILE* stream) +{ + struct sdis_mc result = SDIS_MC_NULL; + size_t nfailures = 0; + size_t nsamples = 0; + res_T res = RES_OK; + + ASSERT(stardis && probe && estimator); + ASSERT((stardis->mode & MODE_PROBE_COMPUTE_ON_INTERFACE) + || (stardis->mode & MODE_PROBE_LIST_COMPUTE_ON_INTERFACE)); + + /* Only master prints or reads estimators */ + ASSERT(!stardis->mpi_initialized || stardis->mpi_rank == 0); + + /* Fetch the estimation data */ + ERR(sdis_estimator_get_temperature(estimator, &result)); + ERR(sdis_estimator_get_failure_count(estimator, &nfailures)); + nsamples = stardis->samples; + + if(nfailures == nsamples) { + logger_print(stardis->logger, LOG_ERROR, + "All the %lu samples failed. No result to display.\n", nsamples); + res = RES_BAD_OP; + goto error; + } + + /* Raw output */ + if((stardis->mode & MODE_EXTENDED_RESULTS) == 0) { + fprintf(stream, "%g %g %lu %lu\n", + result.E, result.SE, (unsigned long)nfailures, (unsigned long)nsamples); + + /* Extended output */ + } else if(stardis->time_range[0] == stardis->time_range[1]) { + fprintf(stream, + "Boundary temperature at [%g, %g, %g] at t=%g = %g K +/- %g\n", + SPLIT3(probe->position), probe->time[0], result.E, result.SE); + + /* Extended output with time range */ + } else { + fprintf(stream, + "Boundary temperature at [%g, %g, %g] with t in [%g %g] = %g K +/- %g\n", + SPLIT3(probe->position), SPLIT2(probe->time), result.E, result.SE); + } + +exit: + return res; +error: + goto exit; +} + +res_T dump_map (const struct stardis* stardis, const struct darray_estimators* estimators, @@ -1956,7 +1995,8 @@ dump_compute_region_at_the_end_of_vtk const struct description* descriptions; unsigned medium_id; ASSERT(stardis->mode & MODE_MEDIUM_COMPUTE); - medium = find_medium_by_name(stardis, &stardis->solve_name, &medium_id); + medium = find_medium_by_name + (stardis, str_cget(&stardis->solve_name), &medium_id); ASSERT(medium != NULL); (void)medium; descriptions = darray_descriptions_cdata_get(&stardis->descriptions); FOR_EACH(i, 0, tsz) { diff --git a/src/stardis-output.h b/src/stardis-output.h @@ -23,11 +23,13 @@ struct sdis_green_path; struct sdis_heat_path; struct sdis_estimator_buffer; struct sdis_green_function; +struct sdis_mc; struct counts; struct description; struct mem_allocator; struct sdis_estimator; struct stardis; +struct stardis_probe_boundary; struct geometry; struct vertex; struct darray_estimators; @@ -38,72 +40,82 @@ struct dump_path_context { unsigned long rank; struct stardis* stardis; }; +#define DUMP_PATH_CONTEXT_NULL__ {0,NULL} +static const struct dump_path_context DUMP_PATH_CONTEXT_NULL = + DUMP_PATH_CONTEXT_NULL__; -res_T +extern LOCAL_SYM res_T dump_path (const struct sdis_heat_path* path, void* context); -res_T +extern LOCAL_SYM res_T print_sample (struct sdis_green_path* path, void* ctx); -res_T +extern LOCAL_SYM res_T dump_vtk_image (const struct sdis_estimator_buffer* buf, FILE* stream); -res_T +extern LOCAL_SYM res_T dump_ht_image (const struct sdis_estimator_buffer* buf, FILE* stream); -res_T +extern LOCAL_SYM res_T dump_green_ascii (struct sdis_green_function* green, const struct stardis* stardis, FILE* stream); -res_T +extern LOCAL_SYM res_T dump_green_bin (struct sdis_green_function* green, const struct stardis* stardis, FILE* stream); -res_T +extern LOCAL_SYM res_T dump_paths_end (struct sdis_green_function* green, const struct stardis* stardis, FILE* stream); -res_T +extern LOCAL_SYM res_T dump_enclosure_related_stuff_at_the_end_of_vtk (struct stardis* stardis, FILE* stream); -res_T +extern LOCAL_SYM res_T print_computation_time - (struct sdis_estimator* estimator, /* Can be NULL */ + (struct sdis_mc* time_per_realisation, /* Can be NULL */ struct stardis* stardis, - struct time* start, - struct time* computation_start, - struct time* computation_end, - struct time* output_end); /* Can be NULL */ + struct time* start, + struct time* computation_start, + struct time* computation_end, + struct time* output_end); /* Can be NULL */ -res_T +extern LOCAL_SYM res_T print_single_MC_result (struct sdis_estimator* estimator, struct stardis* stardis, FILE* stream); -res_T +extern LOCAL_SYM res_T +print_single_MC_result_probe_boundary + (struct stardis* stardis, + const struct stardis_probe_boundary* probe, + const struct sdis_estimator* estimator, + FILE* stream); + +extern LOCAL_SYM res_T dump_map (const struct stardis* stardis, const struct darray_estimators* estimators, FILE* stream); -res_T +extern LOCAL_SYM res_T dump_boundaries_at_the_end_of_vtk (const struct stardis* stardis, FILE* stream); diff --git a/src/stardis-prog-properties.h.in b/src/stardis-prog-properties.h.in @@ -26,6 +26,12 @@ #include <stddef.h> +#if defined(__GNUC__) + #define STARDIS_API extern __attribute__((visibility("default"))) +#else + #define STARDIS_API extern +#endif + /*****************************************************************************/ /* API types. */ /* The various functions defining programmed descriptions receive arguments */ @@ -36,6 +42,8 @@ struct stardis_vertex { double P[3]; /* World space position */ double time; /* "Time" of the vertex */ }; +#define STARDIS_VERTEX_NULL__ {{0,0,0}, 0} +static const struct stardis_vertex STARDIS_VERTEX_NULL = STARDIS_VERTEX_NULL__; enum stardis_side { FRONT, @@ -71,6 +79,10 @@ struct stardis_description_create_context { const char* name; /* Description name */ }; +#ifdef __cplusplus +extern "C" { +#endif + /******************************************************************************/ /* Optional functions for any programmed library. */ /* Either all 3 or none of the 3 following functions must be defined. */ @@ -83,7 +95,7 @@ struct stardis_description_create_context { * processed. * argc + argv describe the (possibly zero) arguments coming from the stardis * input file in the main-like standard way. */ -extern void* +STARDIS_API void* stardis_create_library_data (const struct stardis_program_context* ctx, size_t argc, @@ -96,7 +108,7 @@ stardis_create_library_data * starts. * lib_data is the pointer returned by stardis_create_library_data for this * library. */ -enum stardis_return_status +STARDIS_API enum stardis_return_status stardis_finalize_library_data (void* lib_data); @@ -105,7 +117,7 @@ stardis_finalize_library_data * descriptions data. * lib_data is the pointer returned by stardis_create_library_data for this * library. */ -extern void +STARDIS_API void stardis_release_library_data (void* lib_data); @@ -121,7 +133,7 @@ stardis_release_library_data * library or NULL if stardis_create_library_data is not defined. * argc + argv describe the (possibly zero) arguments coming from the stardis * input file in the main-like standard way. */ -extern void* +STARDIS_API void* stardis_create_data (const struct stardis_description_create_context *ctx, void* lib_data, @@ -131,28 +143,28 @@ stardis_create_data /* Release the data created by stardis_create_data. * This function is called after the simulation finished. * data is the pointer returned by stardis_create_data for the description. */ -extern void +STARDIS_API void stardis_release_data (void* data); /* Get the copyright notice. * A NULL result is interpreted as an error and ends the program. * data is the pointer returned by stardis_create_data for the description. */ -const char* +STARDIS_API const char* get_copyright_notice (void* data); /* Get single-line (name and link?) version of the license. * A NULL result is interpreted as an error and ends the program. * data is the pointer returned by stardis_create_data for the description. */ -const char* +STARDIS_API const char* get_license_short (void* data); /* Get full license text. * A NULL result is interpreted as an error and ends the program. * data is the pointer returned by stardis_create_data for the description. */ -const char* +STARDIS_API const char* get_license_text (void* data); @@ -170,7 +182,7 @@ get_license_text * This functions is called at every vertex of every path of the computation * crossing this solid. * data is the pointer returned by stardis_create_data for this solid. */ -extern double +STARDIS_API double stardis_calorific_capacity (const struct stardis_vertex* vtx, void* data); @@ -179,7 +191,7 @@ stardis_calorific_capacity * This functions is called at every vertex of every path of the computation * crossing this solid. * data is the pointer returned by stardis_create_data for this solid. */ -extern double +STARDIS_API double stardis_volumic_mass (const struct stardis_vertex* vtx, void* data); @@ -188,7 +200,7 @@ stardis_volumic_mass * This functions is called at every vertex of every path of the computation * crossing this solid. * data is the pointer returned by stardis_create_data for this solid. */ -extern double +STARDIS_API double stardis_conductivity (const struct stardis_vertex* vtx, void* data); @@ -197,7 +209,7 @@ stardis_conductivity * This functions is called at every vertex of every path of the computation * crossing this solid. * data is the pointer returned by stardis_create_data for this solid. */ -extern double +STARDIS_API double stardis_delta_solid (const struct stardis_vertex* vtx, void* data); @@ -206,7 +218,7 @@ stardis_delta_solid * This functions is called at every vertex of every path of the computation * crossing this solid. * data is the pointer returned by stardis_create_data for this solid. */ -extern double +STARDIS_API double stardis_volumic_power (const struct stardis_vertex* vtx, void* data); @@ -216,7 +228,7 @@ stardis_volumic_power * This functions is called at every vertex of every path of the computation * crossing this solid. * data is the pointer returned by stardis_create_data for this solid. */ -extern double +STARDIS_API double stardis_medium_temperature (const struct stardis_vertex* vtx, void* data); @@ -225,7 +237,7 @@ stardis_medium_temperature * This functions is called once when initializing the computation. * data is the pointer returned by stardis_create_data for this solid. * Returns its modified range argument. */ -extern double* +STARDIS_API double* stardis_t_range (void* data, double range[2]); @@ -238,7 +250,7 @@ stardis_t_range * This functions is called at every vertex of every path of the computation * crossing this fluid. * data is the pointer returned by stardis_create_data for this fluid. */ -extern double +STARDIS_API double stardis_calorific_capacity (const struct stardis_vertex* vtx, void* data); @@ -247,7 +259,7 @@ stardis_calorific_capacity * This functions is called at every vertex of every path of the computation * crossing this fluid. * data is the pointer returned by stardis_create_data for this fluid. */ -extern double +STARDIS_API double stardis_volumic_mass (const struct stardis_vertex* vtx, void* data); @@ -257,7 +269,7 @@ stardis_volumic_mass * This functions is called at every vertex of every path of the computation * crossing this fluid. * data is the pointer returned by stardis_create_data for this fluid. */ -extern double +STARDIS_API double stardis_medium_temperature (const struct stardis_vertex* vtx, void* data); @@ -266,7 +278,7 @@ stardis_medium_temperature * This functions is called once when initializing the computation. * data is the pointer returned by stardis_create_data for this fluid. * Returns its modified range argument. */ -extern double* +STARDIS_API double* stardis_t_range (void* data, double range[2]); @@ -279,7 +291,7 @@ stardis_t_range * This functions is called every time a path of the computation reaches * this boundary. * data is the pointer returned by stardis_create_data for this boundary. */ -extern double +STARDIS_API double stardis_boundary_temperature (const struct stardis_interface_fragment* frag, void* data); @@ -288,7 +300,7 @@ stardis_boundary_temperature * This functions is called every time a path of the computation reaches * this boundary. * data is the pointer returned by stardis_create_data for this boundary. */ -extern double +STARDIS_API double stardis_emissivity (const struct stardis_interface_fragment* frag, void* data); @@ -297,7 +309,7 @@ stardis_emissivity * This functions is called every time a path of the computation reaches * this boundary. * data is the pointer returned by stardis_create_data for this boundary. */ -extern double +STARDIS_API double stardis_specular_fraction (const struct stardis_interface_fragment* frag, void* data); @@ -306,7 +318,7 @@ stardis_specular_fraction * This functions is called every time a path of the computation reaches * this boundary. * data is the pointer returned by stardis_create_data for this boundary. */ -extern double +STARDIS_API double stardis_convection_coefficient (const struct stardis_interface_fragment* frag, void* data); @@ -317,7 +329,7 @@ stardis_convection_coefficient * This functions is called every time a path of the computation reaches * this boundary. * data is the pointer returned by stardis_create_data for this boundary. */ -extern double +STARDIS_API double stardis_reference_temperature (const struct stardis_interface_fragment* frag, void* data); @@ -325,7 +337,7 @@ stardis_reference_temperature /* Returns the upper bound of the convection coefficient accross this boundary. * This functions is called once when initializing the computation. * data is the pointer returned by stardis_create_data for this boundary. */ -extern double +STARDIS_API double stardis_max_convection_coefficient (void* data); @@ -333,7 +345,7 @@ stardis_max_convection_coefficient * This functions is called once when initializing the computation. * data is the pointer returned by stardis_create_data for this boundary. * Returns its modified range argument. */ -extern double* +STARDIS_API double* stardis_t_range (void* data, double range[2]); @@ -346,7 +358,7 @@ stardis_t_range * This functions is called every time a path of the computation reaches * this boundary. * data is the pointer returned by stardis_create_data for this boundary. */ -extern double +STARDIS_API double stardis_emissivity (const struct stardis_interface_fragment* frag, void* data); @@ -355,7 +367,7 @@ stardis_emissivity * This functions is called every time a path of the computation reaches * this boundary. * data is the pointer returned by stardis_create_data for this boundary. */ -extern double +STARDIS_API double stardis_specular_fraction (const struct stardis_interface_fragment* frag, void* data); @@ -364,7 +376,7 @@ stardis_specular_fraction * This functions is called every time a path of the computation reaches * this boundary. * data is the pointer returned by stardis_create_data for this boundary. */ -extern double +STARDIS_API double stardis_convection_coefficient (const struct stardis_interface_fragment* frag, void* data); @@ -375,7 +387,7 @@ stardis_convection_coefficient * This functions is called every time a path of the computation reaches * this boundary. * data is the pointer returned by stardis_create_data for this boundary. */ -extern double +STARDIS_API double stardis_reference_temperature (const struct stardis_interface_fragment* frag, void* data); @@ -386,7 +398,7 @@ stardis_reference_temperature * This functions is called at every vertex of every path of the computation * crossing this fluid. * data is the pointer returned by stardis_create_data for this boundary. */ -extern double +STARDIS_API double stardis_medium_temperature (const struct stardis_vertex* vtx, void* data); @@ -394,7 +406,7 @@ stardis_medium_temperature /* Returns the upper bound of the convection coefficient accross this boundary. * This functions is called once when initializing the computation. * data is the pointer returned by stardis_create_data for this boundary. */ -extern double +STARDIS_API double stardis_max_convection_coefficient (void* data); @@ -402,7 +414,7 @@ stardis_max_convection_coefficient * This functions is called once when initializing the computation. * data is the pointer returned by stardis_create_data for this boundary. * Returns its modified range argument. */ -extern double* +STARDIS_API double* stardis_t_range (void* data, double range[2]); @@ -415,7 +427,7 @@ stardis_t_range * This functions is called every time a path of the computation reaches * this boundary. * data is the pointer returned by stardis_create_data for this boundary. */ -extern double +STARDIS_API double stardis_boundary_temperature (const struct stardis_interface_fragment* frag, void* data); @@ -424,7 +436,7 @@ stardis_boundary_temperature * This functions is called once when initializing the computation. * data is the pointer returned by stardis_create_data for this boundary. * Returns its modified range argument. */ -extern double* +STARDIS_API double* stardis_t_range (void* data, double range[2]); @@ -437,7 +449,7 @@ stardis_t_range * This functions is called every time a path of the computation reaches * this boundary. * data is the pointer returned by stardis_create_data for this boundary. */ -extern double +STARDIS_API double stardis_emissivity (const struct stardis_interface_fragment* frag, void* data); @@ -446,7 +458,7 @@ stardis_emissivity * This functions is called every time a path of the computation reaches * this boundary. * data is the pointer returned by stardis_create_data for this boundary. */ -extern double +STARDIS_API double stardis_specular_fraction (const struct stardis_interface_fragment* frag, void* data); @@ -455,7 +467,7 @@ stardis_specular_fraction * This functions is called every time a path of the computation reaches * this boundary. * data is the pointer returned by stardis_create_data for this boundary. */ -extern double +STARDIS_API double stardis_convection_coefficient (const struct stardis_interface_fragment* frag, void* data); @@ -464,7 +476,7 @@ stardis_convection_coefficient * This functions is called every time a path of the computation reaches * this boundary. * data is the pointer returned by stardis_create_data for this boundary. */ -extern double +STARDIS_API double stardis_boundary_flux (const struct stardis_interface_fragment* frag, void* data); @@ -475,7 +487,7 @@ stardis_boundary_flux * This functions is called every time a path of the computation reaches * this boundary. * data is the pointer returned by stardis_create_data for this boundary. */ -extern double +STARDIS_API double stardis_reference_temperature (const struct stardis_interface_fragment* frag, void* data); @@ -486,7 +498,7 @@ stardis_reference_temperature * This functions is called at every vertex of every path of the computation * crossing this fluid. * data is the pointer returned by stardis_create_data for this boundary. */ -extern double +STARDIS_API double stardis_medium_temperature (const struct stardis_vertex* vtx, void* data); @@ -494,7 +506,7 @@ stardis_medium_temperature /* Returns the upper bound of the convection coefficient accross this boundary. * This functions is called once when initializing the computation. * data is the pointer returned by stardis_create_data for this boundary. */ -extern double +STARDIS_API double stardis_max_convection_coefficient (void* data); @@ -502,7 +514,7 @@ stardis_max_convection_coefficient * This functions is called once when initializing the computation. * data is the pointer returned by stardis_create_data for this boundary. * Returns its modified range argument. */ -extern double* +STARDIS_API double* stardis_t_range (void* data, double range[2]); @@ -515,7 +527,7 @@ stardis_t_range * This functions is called every time a path of the computation reaches * this boundary. * data is the pointer returned by stardis_create_data for this boundary. */ -extern double +STARDIS_API double stardis_boundary_flux (const struct stardis_interface_fragment* frag, void* data); @@ -528,7 +540,7 @@ stardis_boundary_flux * This functions is called every time a path of the computation reaches * this connection. * data is the pointer returned by stardis_create_data for this connection. */ -extern double +STARDIS_API double stardis_thermal_contact_resistance (const struct stardis_interface_fragment* frag, void* data); @@ -541,7 +553,7 @@ stardis_thermal_contact_resistance * This functions is called every time a path of the computation reaches * this connection. * data is the pointer returned by stardis_create_data for this connection. */ -extern double +STARDIS_API double stardis_emissivity (const struct stardis_interface_fragment* frag, void* data); @@ -550,7 +562,7 @@ stardis_emissivity * This functions is called every time a path of the computation reaches * this connection. * data is the pointer returned by stardis_create_data for this connection. */ -extern double +STARDIS_API double stardis_specular_fraction (const struct stardis_interface_fragment* frag, void* data); @@ -559,7 +571,7 @@ stardis_specular_fraction * This functions is called every time a path of the computation reaches * this connection. * data is the pointer returned by stardis_create_data for this connection. */ -extern double +STARDIS_API double stardis_convection_coefficient (const struct stardis_interface_fragment* frag, void* data); @@ -567,7 +579,7 @@ stardis_convection_coefficient /* Returns the upper bound of the convection coefficient accross this connection. * This functions is called once when initializing the computation. * data is the pointer returned by stardis_create_data for this connection. */ -extern double +STARDIS_API double stardis_max_convection_coefficient (void* data); @@ -575,10 +587,13 @@ stardis_max_convection_coefficient * This functions is called once when initializing the computation. * data is the pointer returned by stardis_create_data for this connection. * Returns its modified range argument. */ -extern double* +STARDIS_API double* stardis_t_range (void* data, double range[2]); +#ifdef __cplusplus +} /* extern "C" */ #endif +#endif