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:
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