commit 42824c2474a58cbcd24e72fefd685013a62f022d
parent 124f1ba33703524a312711f844859e4f012ac394
Author: Christophe Coustet <christophe.coustet@meso-star.com>
Date: Thu, 19 Nov 2020 17:58:47 +0100
Merge branch 'release_0.5'
Diffstat:
| A | .gitignore | | | 11 | +++++++++++ |
| M | README.md | | | 104 | +++++++++++++++++++++++++++++++++++++++++++++++++------------------------------- |
| M | cmake/CMakeLists.txt | | | 164 | +++++++++++++++++++++++++++++++++++++++++++++++++++++-------------------------- |
| A | cmake/doc/CMakeLists.txt | | | 149 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
| A | doc/stardis-input.5.txt | | | 207 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
| A | doc/stardis-man.css | | | 96 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
| A | doc/stardis-output.5.txt | | | 942 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
| A | doc/stardis.1.txt.in | | | 320 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
| D | pp/green2xslx.pl | | | 567 | ------------------------------------------------------------------------------- |
| D | src/args.h | | | 373 | ------------------------------------------------------------------------------- |
| D | src/b_T_1.stl | | | 16 | ---------------- |
| D | src/b_T_2.stl | | | 30 | ------------------------------ |
| D | src/b_h_1.stl | | | 156 | ------------------------------------------------------------------------------- |
| D | src/bc.txt | | | 5 | ----- |
| D | src/m_1.stl | | | 114 | ------------------------------------------------------------------------------- |
| D | src/m_2.stl | | | 86 | ------------------------------------------------------------------------------- |
| D | src/m_3.stl | | | 86 | ------------------------------------------------------------------------------- |
| D | src/main.c | | | 48 | ------------------------------------------------ |
| D | src/material.txt | | | 4 | ---- |
| M | src/stardis-app.c | | | 1476 | ++++++++++++++++++++++++++++--------------------------------------------------- |
| M | src/stardis-app.h | | | 1465 | +++++++++++++++++++++++++++++++++---------------------------------------------- |
| M | src/stardis-compute.c | | | 2754 | ++++++++++++++++++++++++++----------------------------------------------------- |
| A | src/stardis-compute.h | | | 44 | ++++++++++++++++++++++++++++++++++++++++++++ |
| A | src/stardis-default.h.in | | | 37 | +++++++++++++++++++++++++++++++++++++ |
| A | src/stardis-fluid.c | | | 164 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
| A | src/stardis-fluid.h | | | 59 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
| A | src/stardis-intface.c | | | 364 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
| A | src/stardis-intface.h | | | 67 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
| A | src/stardis-main.c | | | 125 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
| A | src/stardis-output.c | | | 1727 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
| A | src/stardis-output.h | | | 110 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
| A | src/stardis-parsing.c | | | 1820 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
| A | src/stardis-parsing.h | | | 203 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
| A | src/stardis-solid.c | | | 221 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
| A | src/stardis-solid.h | | | 60 | ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
| A | src/stardis-version.h.in | | | 24 | ++++++++++++++++++++++++ |
| D | tinyexpr/tinyexpr.c | | | 890 | ------------------------------------------------------------------------------- |
| D | tinyexpr/tinyexpr.h | | | 197 | ------------------------------------------------------------------------------- |
38 files changed, 8957 insertions(+), 6328 deletions(-)
diff --git a/.gitignore b/.gitignore
@@ -0,0 +1,11 @@
+.gitignore
+CMakeCache.txt
+CMakeFiles
+Makefile
+tmp
+[Bb]uild*
+*.sw[po]
+*.[ao]
+*~
+tags
+
diff --git a/README.md b/README.md
@@ -1,58 +1,81 @@
-#stardis-app : Prototype d'application Stardis
+# stardis
-stardis-app est un prototype d'applicatif mettant en oeuvre la bibliothèque
-stardis-solver (https://gitlab.com/meso-star/stardis-solver) avec comme objectif
-de faire la jonction entre un outil de CAO telle que Salome et le solver.
+## Overview
-Pour compiler il suffit de taper `make` après avoir préalablement renseigner
-dans le makefile la variable SDIS_SDK qui est le chemin du SDK de Stardis. Voir
-les notes de version en ci-dessous pour avoir la bonne version du SDK.
+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
+models which can be exported from Salomé or other similar software.
-# Note de versions
+## How to build
-## v0.4
+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.
-- Conformité C99.
-- Build Windows.
-- Passage à stardis-solver 0.5 ; l'intégration temporelle n'est toutefois pas
- encore accessible.
-- Passage à cmake
-## v0.3.2
+First ensure that CMake and a C99 compiler that implements the OpenMP 2.0
+specification 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.
-- Ajout de la fonctionnalité solve_probe_boundary. La fonction solve est
- automatiquement selectionnée en fonction de la distance à la primitive la plus
- proche. Si la distance est inférieure à 2.1 delta, la fonction
- solve_probe_boundary sera utilisée.
-- Ajout des conditions limites en flux.
+## Note de versions
-## v0.3.1
+### v0.5
-Ajout du tranfert radiatif. Ce qui ajoute deux nouveaux parametrès par medium :
+- Ensure C89 compliance.
+- New output format for infra-red rendering.
+- Use new stardis-solver 0.11.
+- Replace fixed dates by time-ranges as time arguments
+ for computations.
+- Allow unsteady Green's function computations.
+- Model files now include scale parameter.
+
+### v0.4
+
+- Improve C99 compliance.
+- Build on Windows systems.
+- Use new stardis-solver 0.5.
+- Transition to cmake to manage builds.
+
+### v0.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.
+- Add flux boundary conditions.
+
+### v0.3.1
+
+Add radiative transfer computations. To achieve this, media gain 2 new parameters:
- emissivity;
- specular_fraction.
-## v0.3
-
-Passage à la version 0.3.0 du SDK de stardis-solver. La version modifié du SDK
-est disponible sur le NAS
-(meso-star/repo/Stardis-0.1.0-GNU-Linux64_modified.tar.gz). Trois fonctionnalités
-ont été ajoutés :
+### v0.3
- - la puissance volumique;
- - la possibilité de renseigner l'argument fp_to_meter de la fonction solve de
- stardis-solver;
- - une option pour dumper la géométrie après analyse au format VTK avec des tags
- medium front/back et id des conditions limites.
+- 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;
+- 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.
-## v0.1
+### v0.1
-Evalue une température sonde uniquement, pour un système purement conductif.Les
-conditions aux limites peuvent être de type dirichlet ou de type échange. Cette
-version repose sur le SDK de Stardis modifié 0.1.0 disponible sur la NAS
-(meso-star/repo/Stardis-0.1.0-GNU-Linux64_modified.tar.gz). La modification
-consiste en l'ajout de la bibliothèqe sstl et tinyexpr
-(https://github.com/codeplea/tinyexpr (https://github.com/codeplea/tinyexpr)
+- Allow probe computations on conductive-only thermal systems.
+- Allow Dirichlet and h.dT boundary conditions.
+\ No newline at end of file
diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt
@@ -1,4 +1,4 @@
-# Copyright (C) 2016-2018 |Meso|Star>
+# Copyright (C) 2018-2020 |Meso|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
@@ -14,29 +14,80 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.
cmake_minimum_required(VERSION 3.0)
-project(stardis-app C)
+project(stardis C)
set(SDIS_SOURCE_DIR ${PROJECT_SOURCE_DIR}/../src)
-################################################################################
+if(CMAKE_HOST_UNIX)
+ set(STARDIS_DOC "TROFF" CACHE STRING
+ "Type of documentation to generate and install.")
+else()
+ set(STARDIS_DOC "HTML" CACHE STRING
+ "Type of documentation to generate and install.")
+endif()
+
+set_property(CACHE STARDIS_DOC PROPERTY STRINGS
+ "HTML"
+ "TROFF"
+ "TROFF & HTML"
+ "NONE")
+
+###############################################################################
+# Generate files
+###############################################################################
+set(STARDIS_ARGS_DEFAULT_AMBIENT_TEMP "300")
+set(STARDIS_ARGS_DEFAULT_COMPUTE_TIME "INF, INF")
+set(STARDIS_ARGS_DEFAULT_RENDERING_FOV "70") # degrees
+set(STARDIS_ARGS_DEFAULT_RENDERING_IMG_HEIGHT "480")
+set(STARDIS_ARGS_DEFAULT_RENDERING_IMG_WIDTH "640")
+set(STARDIS_ARGS_DEFAULT_RENDERING_OUTPUT_FILE_FMT "HT") # VTK or HT
+set(STARDIS_ARGS_DEFAULT_RENDERING_POS "1, 1, 1")
+set(STARDIS_ARGS_DEFAULT_RENDERING_SPP "4")
+set(STARDIS_ARGS_DEFAULT_RENDERING_TGT "0, 0, 0")
+set(STARDIS_ARGS_DEFAULT_RENDERING_TIME "INF, INF")
+set(STARDIS_ARGS_DEFAULT_RENDERING_UP "0, 0, 1")
+set(STARDIS_ARGS_DEFAULT_REFERENCE_TEMP "300")
+set(STARDIS_ARGS_DEFAULT_SAMPLES_COUNT "10000")
+set(STARDIS_ARGS_DEFAULT_SCALE_FACTOR "1")
+set(STARDIS_ARGS_DEFAULT_VERBOSE_LEVEL "1")
+
+configure_file(${SDIS_SOURCE_DIR}/../doc/stardis.1.txt.in
+ ${CMAKE_CURRENT_BINARY_DIR}/doc/stardis.1.txt @ONLY)
+
+set(SDIS_VERSION_MAJOR 0)
+set(SDIS_VERSION_MINOR 5)
+set(SDIS_VERSION_PATCH 0)
+set(SDIS_VERSION ${SDIS_VERSION_MAJOR}.${SDIS_VERSION_MINOR}.${SDIS_VERSION_PATCH})
+
+configure_file(${SDIS_SOURCE_DIR}/stardis-default.h.in
+ ${CMAKE_CURRENT_BINARY_DIR}/stardis-default.h @ONLY)
+
+configure_file(${SDIS_SOURCE_DIR}/stardis-version.h.in
+ ${CMAKE_CURRENT_BINARY_DIR}/stardis-version.h @ONLY)
+
+###############################################################################
# Check dependencies
-################################################################################
+###############################################################################
find_package(RCMake 0.4 REQUIRED)
-find_package(RSys 0.8.1 REQUIRED)
-find_package(StarEnc 0.3.1 REQUIRED)
-find_package(Stardis 0.7.1 REQUIRED)
+find_package(RSys 0.11 REQUIRED)
+find_package(StarGeom3D 0.1 REQUIRED)
+find_package(Star3D 0.7.1 REQUIRED)
+find_package(StarEnc3D 0.4.2 REQUIRED)
+find_package(Stardis 0.11 REQUIRED)
find_package(StarSTL 0.3 REQUIRED)
-
-set(TINYEXPR_SOURCE_DIR "${PROJECT_SOURCE_DIR}/../tinyexpr" CACHE PATH "Directory for TinyExpr source files")
+if(MSVC)
+ find_package(MuslGetopt REQUIRED)
+endif()
include_directories(
${RSys_INCLUDE_DIR}
- ${StarEnc_INCLUDE_DIR}
+ ${Star3D_INCLUDE_DIR}
+ ${StarGeom3D_INCLUDE_DIR}
+ ${StarEnc3D_INCLUDE_DIR}
${Stardis_INCLUDE_DIR}
${StarSTL_INCLUDE_DIR}
- ${TINYEXPR_SOURCE_DIR})
+ ${CMAKE_CURRENT_BINARY_DIR})
if(MSVC)
- find_package(MuslGetopt REQUIRED)
include_directories(${MuslGetopt_INCLUDE_DIR})
endif()
@@ -44,24 +95,45 @@ set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${RCMAKE_SOURCE_DIR})
include(rcmake)
include(rcmake_runtime)
-rcmake_append_runtime_dirs(_runtime_dirs RSys Stardis StarEnc StarSTL)
+if(CMAKE_COMPILER_IS_GNUCC)
+ rcmake_append_runtime_dirs(_runtime_dirs
+ RSys Stardis Star3D StarGeom3D StarEnc3D StarSTL)
+endif()
+if(MSVC)
+ rcmake_append_runtime_dirs(_runtime_dirs
+ RSys MuslGetopt Stardis Star3D StarGeom3D StarEnc3D StarSTL)
+endif()
+
+###############################################################################
+# Build subprojects
+###############################################################################
+if(NOT STARDIS_DOC STREQUAL "NONE")
+ add_subdirectory(doc)
+endif()
-################################################################################
+###############################################################################
# Configure and define targets
-################################################################################
-set(VERSION_MAJOR 0)
-set(VERSION_MINOR 4)
-set(VERSION_PATCH 0)
-set(VERSION ${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_PATCH})
-
+###############################################################################
set(SDIS_FILES_SRC
stardis-app.c
stardis-compute.c
- main.c)
+ stardis-fluid.c
+ stardis-intface.c
+ stardis-main.c
+ stardis-output.c
+ stardis-parsing.c
+ stardis-solid.c)
set(SDIS_FILES_INC
stardis-app.h
- args.h)
+ stardis-compute.h
+ stardis-default.h.in
+ stardis-fluid.h
+ stardis-intface.h
+ stardis-output.h
+ stardis-parsing.h
+ stardis-solid.h
+ stardis-version.h.in)
set(SDIS_FILES_DOC COPYING README.md)
@@ -70,46 +142,30 @@ rcmake_prepend_path(SDIS_FILES_SRC ${SDIS_SOURCE_DIR})
rcmake_prepend_path(SDIS_FILES_INC ${SDIS_SOURCE_DIR})
rcmake_prepend_path(SDIS_FILES_DOC ${PROJECT_SOURCE_DIR}/../)
-# Default is right to left pow and log is natural log
-# Build tinyExpr without closure support and with function_1 to function_3 support only
-# (these ones cannot be disabled as predefined functions require them).
-set(TE_DEFAULTS
- "-DTE_POW_FROM_RIGHT -DTE_NAT_LOG -DTE_WITHOUT_CLOSURES -DTE_WITHOUT_FUNCTION_0 -DTE_MAX_FUNCTION_ARITY=3")
-
-ADD_LIBRARY(tinyexpr STATIC
- ${TINYEXPR_SOURCE_DIR}/tinyexpr.c ${TINYEXPR_SOURCE_DIR}/tinyexpr.h)
-
-if(CMAKE_COMPILER_IS_GNUCC)
- set_target_properties(tinyexpr PROPERTIES
- COMPILE_FLAGS "-std=c99 ${TE_DEFAULTS}")
-elseif(MSVC)
- set_target_properties(tinyexpr PROPERTIES
- COMPILE_FLAGS ${TE_DEFAULTS})
-endif()
-
-add_executable(sdis-app
+add_executable(stardis
${SDIS_FILES_SRC}
${SDIS_FILES_INC})
-
+
if(CMAKE_COMPILER_IS_GNUCC)
- set_target_properties(sdis-app PROPERTIES
- COMPILE_FLAGS "-std=c99 ${TE_DEFAULTS}"
- VERSION ${VERSION})
- target_link_libraries(sdis-app Stardis StarEnc StarSTL RSys tinyexpr m)
+ set(MATH_LIB m)
elseif(MSVC)
- set_target_properties(sdis-app PROPERTIES
- COMPILE_FLAGS "${TE_DEFAULTS}"
- VERSION ${VERSION})
- target_link_libraries(sdis-app Stardis StarEnc StarSTL RSys tinyexpr MuslGetopt)
+ set(GETOPT_LIB MuslGetopt)
endif()
-rcmake_copy_runtime_libraries(sdis-app)
+set_target_properties(stardis
+ PROPERTIES VERSION ${SDIS_VERSION})
-################################################################################
+target_link_libraries(stardis
+ Stardis Star3D StarGeom3D StarEnc3D StarSTL RSys ${GETOPT_LIB} ${MATH_LIB})
+
+###############################################################################
# Define output & install directories
-################################################################################
-install(TARGETS sdis-app
+###############################################################################
+install(TARGETS stardis
ARCHIVE DESTINATION bin
LIBRARY DESTINATION lib
RUNTIME DESTINATION bin)
-install(FILES ${SDIS_FILES_DOC} DESTINATION share/doc/stardis-app)
+
+install(FILES ${SDIS_FILES_DOC} DESTINATION share/doc/stardis)
+
+rcmake_copy_runtime_libraries(stardis)
diff --git a/cmake/doc/CMakeLists.txt b/cmake/doc/CMakeLists.txt
@@ -0,0 +1,149 @@
+# Copyright (C) 2018-2020 |Meso|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/>.
+
+cmake_minimum_required(VERSION 3.0)
+
+string(REGEX MATCH ".*HTML.*" _html ${STARDIS_DOC})
+string(REGEX MATCH ".*ROFF.*" _roff ${STARDIS_DOC})
+
+set(STARDIS_DOC_DIR ${PROJECT_SOURCE_DIR}/../doc)
+
+################################################################################
+# Look for asciidoc and a2x programs
+################################################################################
+if(_html)
+ find_program(ASCIIDOC NAMES asciidoc asciidoc.py)
+ if(NOT ASCIIDOC)
+ unset(_html)
+ message(WARNING
+ "The `asciidoc' program is missing. "
+ "The stardis HTML documentation cannot be generated.")
+ endif()
+endif()
+
+if(_roff)
+ find_program(A2X NAMES a2x a2x.py)
+ if(NOT A2X)
+ unset(_roff)
+ message(WARNING
+ "The `a2x' program is missing. "
+ "The stardis man pages cannot be generated.")
+ endif()
+endif()
+
+################################################################################
+# Copy doc files
+################################################################################
+set(MAN_NAMES
+ stardis-input.5
+ stardis-output.5)
+
+if(_roff OR _html)
+ set(MAN_FILES)
+ foreach(_name IN LISTS MAN_NAMES)
+ set(_src ${STARDIS_DOC_DIR}/${_name}.txt)
+ set(_dst ${CMAKE_CURRENT_BINARY_DIR}/${_name}.txt)
+ add_custom_command(
+ OUTPUT ${_dst}
+ COMMAND ${CMAKE_COMMAND} -E copy ${_src} ${_dst}
+ DEPENDS ${_src}
+ COMMENT "Copy the asciidoc ${_src}"
+ VERBATIM)
+ list(APPEND MAN_FILES ${_dst})
+ endforeach()
+ add_custom_target(man-copy ALL DEPENDS ${MAN_FILES})
+endif()
+
+list(APPEND MAN_NAMES stardis.1)
+
+################################################################################
+# ROFF man pages
+################################################################################
+if(_roff)
+ set(A2X_OPTS -dmanpage -fmanpage)
+ set(MAN_FILES)
+ set(MAN5_FILES)
+ set(MAN1_FILES)
+ foreach(_name IN LISTS MAN_NAMES)
+ set(_man ${CMAKE_CURRENT_BINARY_DIR}/${_name})
+ set(_txt ${CMAKE_CURRENT_BINARY_DIR}/${_name}.txt)
+
+ add_custom_command(
+ OUTPUT ${_man}
+ COMMAND ${A2X} ${A2X_OPTS} ${_txt}
+ DEPENDS man-copy ${_txt}
+ WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
+ COMMENT "Build ROFF man page ${_man}"
+ VERBATIM)
+ list(APPEND MAN_FILES ${_man})
+
+ string(REGEX MATCH "^.*.5$" _man5 ${_man})
+ string(REGEX MATCH "^.*.1$" _man1 ${_man})
+ if(_man1)
+ list(APPEND MAN1_FILES ${_man1})
+ elseif(_man5)
+ list(APPEND MAN5_FILES ${_man5})
+ else()
+ message(FATAL_ERROR "Unexpected man type")
+ endif()
+ endforeach()
+ add_custom_target(man-roff ALL DEPENDS ${MAN_FILES})
+
+ install(FILES ${MAN1_FILES} DESTINATION share/man/man1)
+ install(FILES ${MAN5_FILES} DESTINATION share/man/man5)
+endif()
+
+################################################################################
+# HTML documentation
+################################################################################
+if(_html)
+ set(ASCIIDOC_OPTS
+ -bxhtml11
+ -dmanpage
+ --attribute themedir=${STARDIS_DOC_DIR}
+ --theme=stardis-man)
+
+ set(MAN_FILES)
+ set(MAN5_FILES)
+ set(MAN1_FILES)
+ foreach(_name IN LISTS MAN_NAMES)
+ set(_man ${CMAKE_CURRENT_BINARY_DIR}/${_name}.html)
+ set(_txt ${CMAKE_CURRENT_BINARY_DIR}/${_name}.txt)
+
+ add_custom_command(
+ OUTPUT ${_man}
+ COMMAND ${ASCIIDOC} ${ASCIIDOC_OPTS} ${_txt}
+ DEPENDS man-copy ${_txt} ${STARDIS_DOC_DIR}/stardis-man.css
+ WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
+ COMMENT "Build HTML man page ${_man}"
+ VERBATIM)
+ list(APPEND MAN_FILES ${_man})
+
+ string(REGEX MATCH "^.*.5.html$" _man5 ${_man})
+ string(REGEX MATCH "^.*.1.html$" _man1 ${_man})
+ if(_man1)
+ list(APPEND MAN1_FILES ${_man1})
+ elseif(_man5)
+ list(APPEND MAN5_FILES ${_man5})
+ else()
+ message(FATAL_ERROR "Unexpected man type")
+ endif()
+ endforeach()
+ add_custom_target(man-html ALL DEPENDS ${MAN_FILES})
+
+ install(FILES ${MAN1_FILES} DESTINATION share/doc/stardis/html)
+ install(FILES ${MAN5_FILES} DESTINATION share/doc/stardis/html)
+endif()
+
diff --git a/doc/stardis-input.5.txt b/doc/stardis-input.5.txt
@@ -0,0 +1,207 @@
+// Copyright (C) 2018-2020 |Meso|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/>.
+
+:toc:
+
+stardis-input(5)
+=================
+
+NAME
+----
+stardis-input - thermal system description for stardis(1)
+
+DESCRIPTION
+-----------
+*stardis-input* is the format used by the *stardis*(1) program to describe a
+thermal system. It relies on a line-based ad-hoc syntax.
+
+A thermal system is composed of lines of text, each one describing either a
+medium (solid or fluid) frontier, a boundary (limit condition or connection
+between two media), or the scale of the geometry. In the medium or boundary
+cases, description lines include a list of file names that constitute the
+limit or boundary. The current version of *stardis* 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 (e.g.
+1e-3 if the geometry is in mm).
+
+A medium limit or a boundary description can be split accross files and a
+single file or description line can describe more than one frontier (more than
+one connex region). The main semantic constraint on descriptions is that any
+enclosure must be defined by a single description line, to ensure that any
+part in the system is made from a single medium.
+
+Finally, description lines can be submitted to the *stardis*(1) program in
+any order and can be split accross more than one file, through multiple use
+of option *-M*.
+
+UNITS
+-----
+Any physical quantity involved in descriptions is expected in the
+International System of Units (second, metre, kilogram, kelvin, watt, joule);
+the same applies to *stardis(1)* outputs as described in *stardis-output(5)*.
+
+However, the geometry provided to *stardis*(1) can be described in any unit,
+multiple of meters or not, as long as the scaling factor is provided.
+
+TINIT VS TIMPOSED
+-----------------
+Media's descriptions, either solids or fluids, include two possible
+temperatures: initial and imposed. If imposed temperature is set (that is not
+"UNKNOWN"), initial temperature must be defined at the same value. As a
+consequence, one cannot define a medium with an imposed temperature that
+changes at t=0.
+
+GRAMMAR
+-------
+In what follows, some lines end in *\*. 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.
+Also, text appearing between quote marks has to be used verbatim in the input,
+except the quote characters. Finally, text introduced by the *#* character in
+descriptions, when not verbatim, is a comment and is not part of the
+description.
+
+[verse]
+_______
+<thermal-system> ::= <description-lines>
+ [ <scaling-factor> ]
+
+<description-lines> ::= <description-line>
+ [ <description-lines> ]
+
+<description-line> ::= [ <medium-frontier> ] [ <comment> ]
+ | [ <medium-boundary> ] [ <comment> ]
+ | [ <media-connection> ] [ <comment> ]
+
+<scaling-factor> ::= "SCALE" <scaling_factor> [ <comment> ]
+
+-------------------------------------
+
+<medium-frontier> ::= <solid-frontier>
+ | <fluid-frontier>
+
+<medium-boundary> ::= <t-bound-for-solid>
+ | <t-bound-for-fluid>
+ | <h-bound-for-solid>
+ | <h-bound-for-fluid>
+ | <f-bound-for-solid>
+
+<media-connection> ::= <solid-fluid-connect>
+
+<comment> ::= "#" Any text introduced by the # character
+
+<scaling_factor> ::= REAL # scaling factor to apply to the geometry ; in ]0 INF)
+
+<solid-frontier> ::= "SOLID" <medium-name> <lambda> <rho> <cp> <delta> \
+ <initial-temp> <imposed-temperature> <volumic-power> \
+ <triangle-sides>
+
+<fluid-frontier> ::= "FLUID" <medium-name> <rho> <cp> <initial-temp> \
+ <imposed-temperature> <triangle-sides>
+
+<t-bound-for-solid> ::= "T_BOUNDARY_FOR_SOLID" <bound-name> <temperature> <triangles>
+
+<t-bound-for-fluid> ::= "T_BOUNDARY_FOR_FLUID" <bound-name> <temperature> \
+ <emissivity> <specular-fraction> <hc> <triangles>
+
+<h-bound-for-solid> ::= "H_BOUNDARY_FOR_SOLID" <bound-name> <emissivity> \
+ <specular-fraction> <hc> <outside-temperature> <triangles>
+
+<h-bound-for-fluid> ::= "H_BOUNDARY_FOR_FLUID" <bound-name> <emissivity> \
+ <specular-fraction> <hc> <outside-temperature> <triangles>
+
+<f-bound-for-solid> ::= "F_BOUNDARY_FOR_SOLID" <bound-name> <flux> <triangles>
+
+<solid-fluid-connect> ::= "SOLID_FLUID_CONNECTION" <bound-name> <emissivity> \
+ <specular-fraction> <hc> <triangles>
+
+-------------------------------------
+
+<medium-name> ::= STRING # no space allowed
+
+<lambda> ::= REAL # conductivity in W/(m.K); in ]0, INF)
+
+<rho> ::= REAL # volumic mass,in kg/m3; in ]0, INF)
+
+<cp> ::= REAL # capacity, in J/(kg.K) or kg.m2/(s2.K); in ]0, INF)
+
+<delta> ::= "AUTO" # delta is automatically set to V/6A (V and A being
+ # respectively the solid volume and its boundary area)
+ | REAL # delta*scaling_factor in m; in [0, INF)
+
+<initial-temp> ::= REAL # in K; in [0, INF)
+
+<imposed-temperature> ::= "UNKNOWN" # temperature has to be solved
+ | REAL # in K; in [0, INF)
+
+<outside-temperature> ::= REAL # in K; in [0, INF)
+
+<volumic-power> ::= REAL # in W/m3; in (-INF , INF)
+
+<triangle-sides> ::= <side-specifier> <file-name> [ <triangle-sides> ]
+
+<bound-name> ::= STRING # no space allowed
+
+<emissivity> ::= REAL # in [0, 1]
+
+<specular-fraction> ::= REAL # in [0, 1]
+
+<hc> ::= REAL # in W/(m2.K); in [0, INF)
+
+<flux> ::= REAL # in W/m2; in (-INF , INF)
+
+<triangles> ::= <file-name> [ <triangles> ]
+
+-------------------------------------
+
+<side-specifier> ::= "FRONT" | "BACK" | "BOTH"
+
+<file-name> ::= STRING # no space allowed
+
+______________
+
+TRIANGLE SIDES
+--------------
+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 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 FRONT side specifier to describe inside medium.
+
+NAMES
+-----
+Names, either file names, medium names or boundary names, are a sequence of
+one or ore ASCII characters, including numbers and special characters like
+*.* *_* *-* as one may consider using in standard file names, *without any
+spacing* either escaped or not. Names are case-sensitive anf two different
+description lines, either in the same description file or from different
+description files, cannot use the same name.
+
+EXAMPLES
+--------
+Define a solid named Cube with a h boundary. The cube geometry is read from
+the file cube.stl and the solid medium properties are lambda=0.1, rho=25, cp=2.
+The numerical parameter delta, that is used for solid conductive walks, is
+0.05. The initial temperature of the cube is 0°K and its volumic power is 0.
+The boundary properties are emisivity=0, specular-fraction=0, h=10 and
+external-temperature = 100°K.
+.......
+SOLID Cube 0.1 25 2 0.05 0 0 FRONT cube.stl
+H_BOUNDARY_FOR_SOLID HdT 0 0 10 100 cube.stl
+.......
+
+SEE ALSO
+--------
+*stardis*(1)
diff --git a/doc/stardis-man.css b/doc/stardis-man.css
@@ -0,0 +1,96 @@
+/* Copyright (C) 2016-2018 CNRS
+ *
+ * This is free style sheet: 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 CSS 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/. */
+
+body.manpage {
+ font-family:"Liberation Sans",sans-serif;
+ font-size:10pt;
+ text-align: justify;
+ max-width: 55em;
+ margin: 1em;
+ background: #ffffff
+}
+
+body.manpage .monospaced, .literalblock {
+ margin: 2em;
+ color: #636261
+}
+
+body.manpage em {
+ color: #660000
+}
+
+body.manpage div.verseblock > pre.content {
+ font-family: "Liberation Mono",monospace;
+}
+
+body.manpage h1 {
+ padding-bottom: 0.5em;
+}
+body.manpage h2 {
+ border-style: none;
+}
+body.manpage div.sectionbody {
+ margin-left: 3em;
+}
+
+body.manpage code {
+ font-family: "Liberation Mono",monospace;
+}
+
+body.manpage #footer { display: none; }
+
+body.manpage div#toctitle { display: none; }
+
+body.manpage div#toc {
+ display: block;
+ position:fixed;
+ top:0;
+ left:60em;
+ height:100%;
+ width: 100%;
+ padding:3em 0 0 0;
+ border-left:1px solid #dbdbdb;
+ background: #eeeeee
+}
+
+body.manpage a {
+ font-weight: bold;
+ color: #225588;
+}
+
+body.manpage div#toc a, div#toc a:link, div#toc a:visited {
+ margin:0;
+ padding-left: 2em;
+ color:#999999;
+ text-decoration:none;
+ font-weight: normal;
+}
+
+body.manpage div.toclevel1 {
+ line-height: 1.5em;
+}
+
+body.manpage div.toclevel2 {
+ margin-left: 2em;
+}
+
+body.manpage div#toc a:hover {
+ color:#666666;
+}
+
+@media print {
+ body.manpage div#toc { display: none; }
+}
+
diff --git a/doc/stardis-output.5.txt b/doc/stardis-output.5.txt
@@ -0,0 +1,941 @@
+// Copyright (C) 2018-2020 |Meso|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/>.
+
+:toc:
+
+= stardis-output(5)
+
+== NAME
+
+stardis-output - output format of stardis(1) results
+
+== DESCRIPTION
+
+*stardis-output* describes the output format of the *stardis*(1) program.
+Any *stardis*(1) result is written to _standard output_, even though some
+additional information can be written in files.
+
+The type of the data that are generated depends on the options used when
+*stardis*(1) is invoked. When invoked with one of the basic computation options
+(*-p*, *-P*, *-m*, *-s* or *-F*), *stardis*(1) outputs a single Monte-Carlo
+result. On the opposite, *stardis*(1) ouputs compound results when invoked with
+option *-S* or *-R*. Additionally, options *-g* and *-G* make *stardis*(1)
+compute and output a Green function and possibly information on heat paths'
+ends. Most of the complex data output is in VTK [1] format that can be
+displayed and manipulated by the open-source software Paraview [2].
+
+Finaly, some special options (*-v*, *-h* or *-d*) that does not involve any
+computation produce output including information on the *stardis*(1) software
+(their ouputs will not be described thereafter) or the provided thermal system.
+
+== UNITS
+
+As with the values in *stardis-input*(5), any physical quantity in output is in
+the International System of Units (second, metre, kilogram, kelvin) except the
+coordinates that are in same system as the geometry.
+
+== OPTIONS
+
+Every top-level item of the output listed below is produced by one or more
+specific options of the *stardis*(1) program. The following list gives the
+correspondance:
+
+*-p* or *-P*: produce <probe-temp>
+
+*-m*: produces <medium-temp>
+
+*-s*: produces <mean-temp>
+
+*-F*: produces <mean-flux>
+
+*-p*, *-P*, *-m* or *-s* with *-g* or *-G*: produce <ascii-green> or
+<binary-green> and possibly <heat-paths-ends> respectively.
+
+*-D*: produces <heat-path> files in addition to the simulation output
+
+*-R*: produces <infrared-image>
+
+*-d*: produces <geometry-dump>
+
+== GRAMMAR
+
+In what follows, some lines end in *\*. This is used as a convenience to
+continue a description next line. However, this trick is not part of the
+actual output, that continues on a single line. On the other hand, multiple
+lines not using the *\* convenience in multi-lines descriptions are truly
+different lines of output. Also, text appearing between quote marks is a
+verbatim part of the output, except the quote characters, *#something*
+denotes a count (the number of something), and the math symbols '*\+*'
+and '***', when not verbatim, are used with the usual meaning (like in
+#something+1). Finally, text introduced by the *#* character in a description,
+when neither verbatim nor count, is a comment and is not part of the output.
+
+== OUTPUT
+
+[verse]
+_______
+
+<output> ::= <single-MC-result>
+ | <binary-green>
+ | <heat-paths-ends>
+ | <ascii-green>
+ | <geometry-dump>
+ | <infrared-image>
+_______
+
+== SINGLE MONTE CARLO
+
+When *stardis*(1) is used to produce a single Monte-Carlo result, either
+temperature or flux, this result is output first to _standard output_, possibly
+followed by some of the heat paths involved in the computation if option *-D*
+was used too.
+
+Two different formats are possible: a compact, numbers only format (the default)
+or an extended format that mixes numbers and their descriptions (if option *-e*
+is used).
+
+[verse]
+_______
+<single-MC-result> ::= <single-MC-result>
+ | <ext-single-MC-result>
+
+<single-MC-result> ::= <probe-temp>
+ | <medium-temp>
+ | <mean-temp>
+ | <mean-flux>
+
+<ext-single-MC-result> ::= <ext-probe-temp>
+ | <ext-medium-temp>
+ | <ext-mean-temp>
+ | <ext-mean-flux>
+
+-------------------------------------
+
+<probe-temp> ::= <MC-estimate> <failures-report>
+
+<mean-temp> ::= <MC-estimate> <failures-report>
+
+<mean-flux> ::= <MC-estimate> <MC-estimate> <MC-estimate> <MC-estimate> \
+ <MC-estimate> <failures-report>
+ # MC estimates order is: temperature, convective flux,
+ # radiative flux, imposed flux, total flux
+
+<medium-temp> ::= <MC-estimate> <failures-report>
+
+<MC-estimate> ::= <expected-value> <standard-deviation>
+
+<failures-report> ::= <error-count> <success-count>
+
+<ext-probe-temp> ::= "Temperature at" <probe-position> <time> <MC-estimate>
+ <failures-report>
+
+<ext-mean-temp> ::= "Temperature at boundary" <file-name> <time> <MC-estimate>
+ <failures-report>
+
+<ext-mean-flux> ::= "Temperature at boundary" <file-name> <time> <MC-estimate>
+ "Convective flux at boundary " <file-name> <time> \
+ <MC-estimate>
+ "Radiative flux at boundary" <file-name> <time> <MC-estimate>
+ "Imposed flux at boundary" <file-name> <time> <MC-estimate>
+ "Total flux at boundary" <file-name> <time> <MC-estimate>
+ <failures-report>
+
+<ext-medium-temp> ::= "Temperature in medium" <medium-name> <time> <MC-estimate>
+ <failures-report>
+
+<ext-probe-position> ::= "[" <x-value> "," <y-value> "," <z-value> "]"
+
+<ext-time> ::= "at t=" <time-value> "="
+
+<ext-MC-estimate> ::= <expected-value> "+/-" <standard-deviation>
+
+<ext-failures-report> ::= "#failures:" <error-count> "/" <success-count>
+
+<ext-file-name> ::= STRING # as provided in input data
+
+<ext-medium-name> ::= STRING # as provided in input data
+
+-------------------------------------
+
+<x-value> ::= REAL
+
+<y-value> ::= REAL
+
+<z-value> ::= REAL
+
+<time-value> ::= REAL # in [0, INF)
+
+<error-count> ::= INTEGER # in [0, #samples]
+
+<success-count> ::= INTEGER # in [0, #samples]
+
+<expected-value> ::= REAL # depending on value semantics, range can be restricted
+
+<standard-deviation> ::= REAL # in [0, INF)
+
+_______
+
+== GREEN
+
+The Green function is generated, either in binary or ascii format, when a
+green-compatible *stardis*(1) simulation option is used in conjuction with
+option *-G* for a binary output, or option *-g* for an ascii output. For
+every successful heat path sampled carrying out the simulation, the solver
+records all the elements of the path history relevant to link the various
+imposed temperature, fluxe and volumic power values to the simulation result.
+Note that to be able to explore different values of volumic power when
+applying the Green function, it must have been generated with these values
+being non-zero. On the other hand, any temperature or flux value in boundary
+descriptions can be modified when applying the Green function, as well as the
+ambient temperature.
+
+The output in green mode is made of tables containing the different media and
+boundaries and their imposed temperature, flux and volumic power values,
+followed by the heat paths' history. Also, option *-G* make it possible to
+output heat paths' end information on an ascii, csv formated file.
+
+The Monte-Carlo estimate and standard deviation for a given set of settings can
+be computed as the mean and standard deviation of the samples of the *Green
+function* computed using these settings. Each sample can be computed as
+follows:
+
+* Get the temperature of the ending boundary, medium or ambient;
+* Add the temperature gain of each power term;
+* Add the temperature gain of each flux term.
+
+=== BINARY GREEN
+
+Thereafter is the format of binary Green outputs. This output is produced by
+fwrite calls and does not take care of endianness. Comments include the C type
+of the written data.
+
+[verse]
+_______
+<binary-green> ::= "BINGREEN" # char[8]
+ #descriptions # unsigned
+ #solids # unsigned
+ #fluids # unsigned
+ #t-boundaries # unsigned
+ #h-boundaries # unsigned
+ #flux-boundaries # unsigned
+ #solid-fluid-connections # unsigned
+ names-pool-size # size of concatenated description names: unsigned
+ #ok-samples # size_t
+ #failed-samples # size_t
+ <descriptions>
+ <concatenated-names> # char[names-pool-size]
+ ambient-temperature # double
+ reference-temperature # double
+ time-range # double[2]
+ <samples>
+
+<descriptions> ::= description # struct description
+ <descriptions> # #descriptions descriptions
+
+<samples> ::= <sample>
+ <samples> # #ok-samples samples
+
+---------------------
+
+<sample> ::= <sample-header> # struct path_header
+ <ids> # unsigned[header.pcount + header.fcount]
+ <weights> # double[header.pcount + header.fcount]
+_______
+
+[literal]
+ /* The content of stuct str name members in descriptions is meaningless.
+ * The name of the ith description is the ith nul-terminated string in
+ * <concatenated-names>.
+ * As a convenience, one could use char* baz to store a pointer to the
+ * description's name into <concatenated-names>. */
+ struct str {
+ void* foo;
+ size_t bar;
+ char* baz;
+ char qux[16];
+ };
+
+ struct mat_fluid {
+ struct str name;
+ double rho;
+ double cp;
+ double tinit;
+ double imposed_temperature;
+ double t0;
+ int is_outside;
+ int is_green;
+ unsigned desc_id;
+ unsigned fluid_id;
+ };
+
+ struct mat_solid {
+ struct str name;
+ double lambda;
+ double rho;
+ double cp;
+ double delta;
+ double tinit;
+ double imposed_temperature;
+ double vpower;
+ double t0;
+ int is_outside;
+ int is_green;
+ unsigned desc_id;
+ unsigned solid_id;
+ };
+
+ struct t_boundary {
+ struct str name;
+ double emissivity;
+ double specular_fraction;
+ double hc;
+ double imposed_temperature;
+ unsigned mat_id;
+ };
+
+ struct h_boundary {
+ struct str name;
+ double emissivity;
+ double specular_fraction;
+ double hc;
+ double imposed_temperature;
+ unsigned mat_id;
+ };
+
+ struct solid_fluid_connect {
+ struct str name;
+ double emissivity;
+ double specular_fraction;
+ double hc;
+ unsigned connection_id;
+ };
+
+ enum description_type {
+ DESC_MAT_SOLID,
+ DESC_MAT_FLUID,
+ DESC_BOUND_H_FOR_FLUID,
+ DESC_BOUND_H_FOR_SOLID,
+ DESC_BOUND_T_FOR_FLUID,
+ DESC_BOUND_T_FOR_SOLID,
+ DESC_BOUND_F_FOR_SOLID,
+ DESC_SOLID_FLUID_CONNECT,
+ DESCRIPTION_TYPE_COUNT__,
+ DESC_OUTSIDE
+ };
+
+ struct f_boundary {
+ struct str name;
+ double imposed_flux;
+ unsigned mat_id;
+ };
+
+ struct description {
+ enum description_type type;
+ union {
+ struct mat_fluid fluid;
+ struct mat_solid solid;
+ struct t_boundary t_boundary;
+ struct f_boundary f_boundary;
+ struct h_boundary h_boundary;
+ struct solid_fluid_connect sf_connect;
+ } d;
+ };
+
+ struct path_header {
+ unsigned id;
+ unsigned pcount, fcount;
+ char at_initial;
+ };
+
+=== ASCII GREEN
+
+Thereafter is the format of ascii Green outputs.
+
+[verse]
+_______
+<ascii-green> ::= "---BEGIN GREEN---"
+ "# time range"
+ <time-range>
+ "# #solids #fluids #t_boundaries #h_boundaries #f_boundaries \
+ #ok #failures"
+ #solids #fluids #t_boundaries #h_boundaries #f_boundaries \
+ #ok #failures
+ "# Solids"
+ "# ID Name lambda rho cp power"
+ <solids>
+ "# Fluids"
+ "# ID Name rho cp"
+ <fluids>
+ "# T Boundaries"
+ "# ID Name temperature"
+ <t-bounds>
+ "# H Boundaries"
+ "# ID Name emissivity specular_fraction hc T_env"
+ <h-bounds>
+ "# F Boundaries"
+ "# ID Name flux"
+ <f-bounds>
+ "# Radiative Temperatures"
+ "# ID Rad_Temp Lin_Temp"
+ <rad-temps>
+ "# Samples"
+ "# end #power_terms #flux_terms power_term_1 ... power_term_n \
+ flux_term_1 ... flux_term_n"
+ "# end = end_type end_id; end_type = T | H | X | R | F | S"
+ "# power_term_i = power_id_i factor_i"
+ "# flux_term_i = flux_id_i factor_i"
+ <samples>
+ "---END GREEN---"
+
+<time-range> ::= <REAL> <REAL> # in [0, INF) x [first REAL, INF)
+
+<solids> ::= <solid>
+ <solids> # #solids solid descriptions
+
+<fluids> ::= <fluid>
+ <fluids> # #fluids fluid descriptions
+
+<t-bounds> ::= <t-bound>
+ <t-bounds> # #t-bounds t-bound descriptions
+
+<h-bounds> ::= <h-bound>
+ <h-bounds> # #h-bounds h-bound descriptions
+
+<f-bounds> ::= <f-bound>
+ <f-bounds> # #f-bounds f-bound descriptions
+
+<rad-temps> ::= <green-id> <rad-temp> <lin-temp>
+
+<samples> ::= <sample>
+ <samples> # #samples sample descriptions
+
+-------------------------------------
+
+<sample> ::= <end-spec> <power-count> <flux-count> <power-terms> <flux-terms>
+
+<solid> ::= <green-id> <name> <lambda> <rho> <cp> <power> <initial-temp> <imposed-temp>
+
+<fluid> ::= <green-id> <name> <rho> <cp> <initial-temp> <imposed-temp>
+
+<t-bound> ::= <green-id> <name> <temperature>
+
+<h-bound> ::= <green-id> <name> <emissivity> <specular_fraction> <hc> \
+ <temperature>
+
+<f-bound> ::= <green-id> <name> <flux>
+
+<rad-temps> ::= <green-id> <ambient-temp> <lin-temp>
+
+<name> ::= STRING # no space allowed
+
+<lambda> ::= REAL # in ]0, INF)
+
+<rho> ::= REAL # in ]0, INF)
+
+<cp> ::= REAL # in ]0, INF)
+
+<power> ::= REAL # in (-INF , INF)
+
+<initial-temp> ::= REAL # in [0 , INF)
+ | "NONE" if not imposed
+
+<imposed-temp> ::= REAL # in [0 , INF)
+ | "NONE" if not imposed
+
+<temperature> ::= REAL # in [0, INF)
+
+<emissivity> ::= REAL # in [0, 1]
+
+<specular-fraction> ::= REAL # in [0, 1]
+
+<hc> ::= REAL # in [0, INF)
+
+<flux> ::= REAL # in (-INF, INF)
+
+<ambient-temp> ::= REAL # in [0, INF)
+
+<lin-temp> ::= REAL # in [0, INF)
+
+<green-id> ::= INTEGER # in [0 #green-sources[
+
+-------------------------------------
+
+<end-spec> ::= <end-type> <green-id>
+<end-type> ::= "T" # sample ends at an t-bound
+ | "H" # sample ends at an h-bound
+ # a sample cannot end at an f-bound
+ | "A" # sample ends with ambient temperature
+ | "F" # sample ends in a fluid with known temperature
+ | "S" # sample ends in a solid with known temperature
+
+<power-count> ::= INTEGER # in [0 INF)
+
+<flux-count> ::= INTEGER # in [0 INF)
+
+<power-terms> ::= <power-term>
+ <power-terms> # <power-count> power terms
+
+<flux-terms> ::= <flux-term>
+ <flux-terms> # <flux-count> flux terms
+
+-------------------------------------
+
+<power-term> ::= <green-id> <power-factor>
+
+<flux-term> ::= <green-id> <flux-factor>
+
+<power-factor> ::= REAL # in ]0, INF)
+ # the temperature gain is power-factor * Power(green-id)
+
+<flux-factor> ::= REAL # in ]0, INF)
+ # the temperature gain is flux-factor * Flux(green-id)
+_______
+
+== HEAT PATHS' ENDS
+
+When computing the Green function in binary mode, stardis can output partial
+information ot the sampled heat paths. Opposed to what the *-D* option outputs,
+that is the complete history of selected heat paths, here the information
+output is restricted to paths' ends to allow the inclusion of all the sampled
+heat paths, allowing statistical analysis.
+
+Note that in wath follows, the meaning of external quotes is as usual: what is
+inside is verbatim, including quotes.
+
+[verse]
+_______
+<heat-paths-ends> ::= ""End", "End ID", "X", "Y", "Z", "Elapsed time""
+ <heat-path-end-list>
+
+<heat-path-end-list> ::= <end-name> ", " <endid> ", " <x> ", " <y> ", " \
+ <z> ", " <elapsed-time>
+ <heat-path-end-list> # #samples heat path ends
+
+-------------------------------------
+
+<end-name> ::= STRING # the name of the boundary at the end of the
+ # heat path, or AMBIANT for radiative ending
+
+<end-id> ::= INTEGER # in [0 #boundaries]
+ # order is the order in the description file,
+ # AMBIANT's id being #boundaries
+
+<x> ::= REAL
+
+<y> ::= REAL
+
+<z> ::= REAL
+
+<elapsed-time> ::= REAL # in [0, INF)
+_______
+
+== GEOMETRY DUMP
+
+A *geometry-file* is generated when *stardis*(1) is invoked with option *-d*.
+In this mode, *stardis*(1) outputs the system geometry, as submitted in
+*stardis-input*(5) description, to _standard output_ in VTK [1] format.
+The output geometry is not the concatenation of the various geometry files
+used in *stardis-input*(5) description. It is the result of a deduplication
+process that removes duplicate and degenerated triangles from the submited
+geometry.
+
+Additionaly, as permitted by the VTK [1] format, the output geometry is
+decorated with many different properties provided to help users understand
+the description processing, including possible errors.
+
+If errors are detected, some optional error-related data fields are included
+in the geometry file. Some errors report a by-triangle error status, other
+errors report a by-enclosure error status.
+
+Also, holes in the geometry, if any, are reported in geometry dumps. A hole is
+defined by its frontier that is a collection of triangles surrounding the hole.
+Such triangles are detected as having their 2 sides in the same enclosure, but
+with a different medium on each side.
+
+Media information is provided in two different flavours. First the medium on
+front and back sides of triangles can be found through the Front_medium and
+Back_medium fields. These fields use the special value 4294967295 (INT_MAX) for
+sides with no defined medium, as one can expect on boundary triangles. On the
+other hand, medium information provided by the Enclosures_internal_media
+field displays the id of the medium created to hold boundary information for
+boundary triangles. In either case, media numbering information can be found
+in log messages if option -V 3 is used in conjunction with the -d dump option.
+
+[verse]
+_______
+<geometry-file> ::= "# vtk DataFile Version 2.0"
+ "Dump of star-geometry-3d geometry"
+ "ASCII"
+ "DATASET POLYDATA"
+ <vertices>
+ <triangles>
+ "CELL_DATA" #triangles
+ <front-media>
+ <back-media>
+ <interfaces>
+ <unique-ids>
+ <user-ids>
+ [ <merge-conflicts> ] # if some merge conflict occured
+ [ <property-conflicts> ] # if some property conflict occured
+ <file-ids>
+ <boundaries>
+ [ <compute-region> ] # if defined
+ <encl-or-overlaps>
+
+<vertices> ::= "POINTS" #vertices "double"
+ <vertex-list>
+
+<triangles> ::= "POLYGONS" #triangles #triangles*4
+ <triangle-list>
+
+<front-media> ::= "SCALARS Front_medium unsigned_int 1"
+ "LOOKUP_TABLE default"
+ <front-medium-ids>
+
+<back-media> ::= "SCALARS Back_medium unsigned_int 1"
+ "LOOKUP_TABLE default"
+ <back-medium-ids>
+
+<interfaces> ::= "SCALARS Interface unsigned_int 1"
+ "LOOKUP_TABLE default"
+ <interface-ids>
+
+<unique-ids> ::= "SCALARS Unique_ID unsigned_int 1"
+ "LOOKUP_TABLE default"
+ <trg-unique-ids>
+
+<user-ids> ::= "SCALARS User_ID unsigned_int 1"
+ "LOOKUP_TABLE default"
+ <trg-user-ids>
+
+<merge-conflicts> ::= "SCALARS Merge_conflict int 1"
+ "LOOKUP_TABLE default"
+ <trg-merge-conflicts>
+
+<property-conflicts> ::= "SCALARS Property_conflict int 1"
+ "LOOKUP_TABLE default"
+ <trg-prop-conflicts>
+
+<file-ids> ::= "SCALARS Created_at_sg3d_geometry_add unsigned_int 1"
+ "LOOKUP_TABLE default"
+ <file-ranks>
+
+<boundaries> ::= "SCALARS Boundaries unsigned_int 1"
+ "LOOKUP_TABLE default"
+ <boundary-ids>
+
+<compute-region> ::= "SCALARS Compute_region unsigned_int 1"
+ "LOOKUP_TABLE default"
+ <region-membership>
+
+<encl-or-overlaps> ::= <encl-information> # if enclosure extraction was possible
+ | <overlaps> # if overlapping triangles where detected
+
+-----------------
+
+<vertex-list> ::= "3" <vertice_id> <vertice_id> <vertice_id>
+ <vertex-list> # #vertices vertices
+
+<triangle-list> ::= <real3>
+ <triangle-list> # #triangles triangles
+
+<front-medium-ids> ::= <medium-id> | <undef-medium>
+ <front-medium-ids> # #triangles ids
+
+<back-medium-ids> ::= <medium-id> | <undef-medium>
+ <back-medium-ids> # #triangles ids
+
+<interface-ids> ::= INTEGER # in [0 #interface[
+ <interface-ids> # #triangles ids
+
+<trg-unique-ids> ::= INTEGER # in [0 #triangles[
+ <trg-unique-ids> # #triangles ids
+
+<trg-user-ids> ::= INTEGER # in [0 #submitted triangles[
+ <trg-user-ids> # #triangles ids
+
+<trg-merge-conflicts> ::= "0" # triangle without any merge conflict
+ | "1" # triangle with a merge conflict
+ <trg-merge-conflicts> # #triangles statuses
+
+<trg-prop-conflicts> ::= "0" # triangle with no property conflict
+ | "1" # H_BOUNDARY_FOR_FLUID between 2 defined media
+ | "2" # H_BOUNDARY_FOR_FLUID between 2 undefined media
+ | "3" # H_BOUNDARY_FOR_FLUID enclosing a solid
+ | "4" # H_BOUNDARY_FOR_SOLID between 2 defined media
+ | "5" # H_BOUNDARY_FOR_SOLID between 2 undefined media
+ | "6" # H_BOUNDARY_FOR_SOLID enclosing a fluid
+ | "7" # T_BOUNDARY_FOR_FLUID between 2 defined media
+ | "8" # T_BOUNDARY_FOR_FLUID between 2 undefined media
+ | "9" # T_BOUNDARY_FOR_FLUID enclosing a solid
+ | "10" # T_BOUNDARY_FOR_SOLID between 2 defined media
+ | "11" # T_BOUNDARY_FOR_SOLID between 2 undefined media
+ | "12" # T_BOUNDARY_FOR_SOLID enclosing a fluid
+ | "13" # F_BOUNDARY_FOR_FLUID between 2 defined media
+ | "14" # F_BOUNDARY_FOR_FLUID between 2 undefined media
+ | "15" # F_BOUNDARY_FOR_SOLID enclosing a fluid
+ | "16" # SOLID_FLUID_CONNECTION between 2 solids
+ | "17" # SOLID_FLUID_CONNECTION between 2 fluids
+ | "18" # SOLID_FLUID_CONNECTION used as boundary
+ | "19" # SOLID_FLUID_CONNECTION between 2 undefined media
+ | "20" # no connexion between 2 fluids
+ | "21" # no connexion between a solid and a fluid
+ | "22" # no boundary around a fluid
+ | "23" # no boundary around a solid
+ | "24" # invalid part of a compute surface
+ <trg-prop-conflicts> # #triangles statuses
+
+<real3> ::= REAL REAL REAL
+
+<vertice-id> ::= INTEGER # in [0 #vertices[
+
+<file-ranks> ::= INTEGER # in [0 #submitted files[
+ <file-ranks> # #triangles ranks
+
+<boundary-ids> ::= INTEGER # in [0 #submitted descriptions[
+ <boundary-ids> # #triangles ids
+
+<region-membership> ::= <reg-not-member> # triangle not part of the compute region
+ | <reg-member> # triangle is part of the compute region
+ <region-membership> # #triangles membership status
+
+<encl-information> ::= [ <holes> ] # if there are holes
+ <enclosures>
+
+<overlaps> ::= "SCALARS Overlapping_triangles unsigned_int 1"
+ "LOOKUP_TABLE default"
+ <overlapping-status>
+
+<holes> ::= "SCALARS Hole_frontiers unsigned_int 1"
+ "LOOKUP_TABLE default"
+ <hole-memberships>
+
+<enclosures> ::= "FIELD FieldData 2"
+ "Enclosures" #enclosures #triangles "unsigned_char"
+ <encl-memberships>
+ "Enclosures_internal_media" #enclosures #triangles "unsigned_int"
+ <encl-media>
+
+-----------------
+
+<hole-memberships> ::= "0" # triangle not surrounding a hole
+ | "1" # triangle surrounding a hole
+ <hole-memberships> # #triangles hole memberships
+
+<encl-memberships> ::= <enclosure-status 0> ... <enclosure-status #enclosures-1>
+ <encl-memberships> # #triangles enclosure memberships
+
+<encl-media> ::= <enclosure 0 medium> ... <enclosure #enclosures-1 medium>
+ <encl-media> # #triangles enclosure media
+
+<medium-id> ::= INTEGER # in [0, #medium[
+
+<undef-medium> ::= "4294967295"
+
+<reg-not-member> ::= "0"
+
+<reg-member> ::= "1" # the FRONT side is member of the region
+ | "2" # the BACK side is member of the region
+ | "3" # both sides are member of the region
+ | "4294967295" # the triangle is an invalid part of the region
+
+<overlapping-status> ::= "0" # triangle not overlapping another triangle
+ | "1" # triangle overlapping another triangle
+ <overlapping-status> # #triangles overlapping status
+
+<enclosure-status i> ::= <encl-not-member> # the triangle is not part of the ith enclosure
+ | <encl-member> # the triangle is part of the ith enclosure
+
+<enclosure i medium> ::= <medium-id> # the triangle is part of the ith enclosure and
+ # has this medium in the involved side(s)
+ | "4294967293" # the triangle is part of the ith enclosure and
+ # has no defined medium in the involved side(s)
+ | "4294967294" # the 2 sides of the triangle are part of the ith
+ # enclosure, but have 2 different media
+ | "4294967295" # the triangle is not part of the ith enclosure
+
+-----------------
+
+<encl-not-member> ::= "0"
+
+<encl-member> ::= "1" # valid enclosure
+ | "3" # invalid enclosure: more than 1 medium
+ | "5" # invalid enclosure: some triangles with no defined medium
+ | "7" # invalid enclosure: more than 1 "medium", including undefined
+_______
+
+== INFRARED IMAGE
+
+When invoked with option *-R*, *stardis*(1) generates an infrared image of
+the system and write it to _standard output_. Depending on the *fmt*
+sub-option, this file can be either in VTK [1] format on in *htrdr-image*(5)
+format.
+
+=== HTRDR-IMAGE INFRARED IMAGE
+If the output image is in htrdr-image format, it comply with the *lw* section
+of the format, with only the temperature fields being informed. The resulting
+format is as follows:
+
+[verse]
+_______
+<htrdr-image> ::= <definition>
+ <pixel>
+ [ <pixel> ... ]
+
+<definition> ::= <width> <height>
+<width> ::= INTEGER
+<height> ::= INTEGER
+
+<pixel> ::= <temperature> 0 0 0 0 <time>
+
+<temperature> ::= <estimate>
+<time> ::= <estimate>
+
+<estimate> ::= <expected-value> <standard-error>
+<expected-value> ::= REAL
+<standard-error> ::= REAL
+_______
+
+These files can be post-processed using the *htpp*(1) tool, that is part of
+the high-tune project.
+
+=== VTK INFRARED IMAGE
+If the output image is in VTK format, it is on an XY plane with coordinates in
+the [0 pixel_count[ range. By convention, the origine (0,0) pixel is at the
+top-left corner of the image.
+
+The result not only includes the computed temperature image, but also includes
+a per-pixel computation time image as well as a per-pixel path error count
+image and per-pixel standard deviation images for both temperature and
+computation time.
+
+[verse]
+_______
+<infrared-image> ::= "# vtk DataFile Version 2.0"
+ "Infrared Image"
+ "ASCII"
+ "DATASET STRUCTURED_POINTS"
+ "DIMENSIONS" <image-width> <image-height> "1"
+ "ORIGIN 0 0 0"
+ "SPACING 1 1 1"
+ "POINT_DATA" <image-width>*<image-height>
+ "SCALARS temperature_estimate float 1"
+ "LOOKUP_TABLE default"
+ <temperatures>
+ "SCALARS temperature_std_dev float 1"
+ "LOOKUP_TABLE default"
+ <temp_std_devs>
+ "SCALARS computation_time float 1"
+ "LOOKUP_TABLE default"
+ <computation_times>
+ "SCALARS computation_time_std_dev float 1"
+ "LOOKUP_TABLE default"
+ <com_time_std_devs>
+ "SCALARS failures_count unsigned_long_long 1"
+ "LOOKUP_TABLE default"
+ <failures_counts>
+
+<temperatures> ::= REAL # in [0, INF)
+ <temperatures> # <image-width>*<image-height> temperatures
+
+<temp_std_devs> ::= REAL # in [0, INF)
+ <temperature_std_devs> # <image-width>*<image-height> std_devs
+
+<computation_times> ::= REAL # in [0, INF)
+ <computation_times> # <image-width>*<image-height> times
+
+<comp_time_std_devs> ::= REAL # in [0, INF)
+ <comp_time_std_devs> # <image-width>*<image-height> std_devs
+
+<failures_counts> ::= INTEGER # in [0, SAMPLES_COUNT]
+ <failures_counts> # <image-width>*<image-height> failures_counts
+_______
+
+== DUMP HEAT PATHS
+
+When the *stardis*(1) option *-D* is used in conjunction with an option that
+computes a result, some of the heat paths (successful paths, erroneous paths,
+or both) sampled during the simulation are written to files. Each path is
+written in VTK [1] format, one VTK file per path. The path description can
+include vertices' time if it makes sense, that is if the computation time is
+not INF.
+
+[verse]
+_______
+
+<heat-path> ::= "# vtk DataFile Version 2.0"
+ "Heat path"
+ "ASCII"
+ "DATASET POLYDATA"
+ "POINTS" #vertices "double"
+ <path-vertices>
+ "LINES 1" #vertices+1
+ <heat-path>
+ "POINT_DATA" #vertices
+ "SCALARS Vertex_Type unsigned_char 1"
+ "LOOKUP_TABLE default"
+ <vertices-types>
+ "CELL_DATA 1"
+ "SCALAR Path_type unsigned_char 1"
+ "LOOKUP_TABLE default"
+ <path-type>
+ "SCALARS Weight double 1"
+ "LOOKUP_TABLE default"
+ <weigths>
+ [ <vertices-time> ] # if not steady
+
+<path-vertices> ::= <real3>
+ <path-vertices> # #vertices vertices
+
+<heat-path> ::= #vertices "0" "1" ... #vertices-1
+
+<vertices-types> ::= <vertice-type>
+ <vertices-types> # #vertices types
+
+<weigths> ::= REAL
+ <weigths> # #vertices weigths
+
+<vertices-time> ::= "SCALARS Time double 1"
+ "LOOKUP_TABLE default"
+ <durations>
+
+-----------------
+
+<real3> ::= REAL REAL REAL
+
+<durations> ::= REAL # in [0, INF)
+ <durations> # #vertices durations
+
+<vertice-type> ::= "0" # CONDUCTION
+ | "1" # CONVECTION
+ | "2" # RADIATIVE
+
+<path-type> ::= "0" # SUCCESS
+ | "1" # FAILURE
+
+_______
+
+== NOTES
+
+1. VTK file format -
+ <http://www.vtk.org/wp-content/uploads/2015/04/file-formats.pdf>
+
+2. Paraview softawre -
+ <https://www.paraview.org/>
+
+== SEE ALSO
+
+*stardis*(1),
+*stardis-input*(5)
+\ No newline at end of file
diff --git a/doc/stardis.1.txt.in b/doc/stardis.1.txt.in
@@ -0,0 +1,320 @@
+// Copyright (C) 2018-2020 |Meso|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/>.
+
+:toc:
+
+stardis(1)
+===========
+
+NAME
+----
+stardis - statistical solving of coupled thermal systems
+
+SYNOPSIS
+--------
+[verse]
+*stardis* [_option_]
+*stardis* *-M* <__file__> [_option_]
+
+DESCRIPTION
+-----------
+*stardis* solves coupled thermal systems under the linear assumption. Here
+coupled refers to conductive, convective and radiative transfers, and linear
+means that each phenomena is represented using a model that is linear
+with temperature. *stardis* can deal with complex geometries as well as
+high-frequency external solicitations over a very long period of time,
+relative to the characteristic time of the system. The provided system
+description should comply with the *stardis-input*(5) format.
+
+*stardis* can compute a thermal observable, like temperature or flux, at a
+probe point and date or the mean value of an observable over a given surface,
+volume, or time range. When a time range *t1, t2* is provided, the computed
+value is the mean value over the time range. To compute the value at a given
+time, simply provide a single value *t*. In addition, *stardis* gives access to
+the evaluation of the propagator (a.k.a the *Green function*).
+
+The propagator is of great value for thermicist engineers as it gives some
+crucial information to analyse heat transfers in the system. It helps engineers
+answer questions like _"Where from does the heat come at this location?"_.
+Propagators seamlessly agregate all the provided geometrical and physical
+information on the system in an unbiased and very-fast statistical model.
+
+*stardis*(1) also provides two additional functionalities: converting the
+*stardis-input*(5) geometry into a VTK file and rendering an infrared image
+of the submitted system.
+
+Stardis' algorithms are based on state-of-the-art Monte-Carlo method applied
+to radiative transfer physics (Delatorre [1]) combined with conduction's
+statistical formulation (Kac [2] and Muller [3]). Thanks to recent advances in
+computer graphics technology which has already been a game changer in the
+cinema industry (FX and animated movies), this theoretical framework can now
+be practically used on the most geometrically complex systems. While this
+capability is part of the StarEngine Star3D library, it is internally powered
+by Intel® Rendering Framework: Embree.
+
+Everytime the linear assumption is relevant, this theoretical framework allows
+to encompass all the heat transfer mecanisms (conductive-convective-radiative)
+in an unified statistical model. Such systems can be solved by a Monte-Carlo
+approach just by sampling heat paths. This can be seen as an extension of
+Monte-Carlo algorithms that solve radiative transfer by sampling optical paths.
+A main property of this approach is that the resulting algorithms does not rely
+on a volume mesh of the system.
+
+[1] Delatorre et al., Monte Carlo advances and concentrated solar applications,
+Solar Energy, 2014
+
+[2] Kac, On Distributions of Certain Wiener Functionals. The Annals of
+Mathematical Statistics, 1949.
+
+[3] Muller, Some continuous Monte-Carlo Methods for the Dirichlet Problem,
+Transactions of the American Mathematical Society, 1956.
+
+MANDATORY OPTIONS
+-----------------
+*-M* _file_::
+ Read a text file containing a possibly partial description of the system.
+ Can include both media enclosures and boundary conditions, in any order.
+ Can be used more than once if the description is split across different
+ files.
+
+EXCLUSIVE OPTIONS
+-----------------
+*-p* _x,y,z[,time-range]_::
+ Compute the temperature at the given probe at a given time. By default the
+ compute time range is @STARDIS_ARGS_DEFAULT_COMPUTE_TIME@. The probe must
+ be in a medium. The probe coordinates must be in the same system as the
+ geometry.
+
+*-P* _x,y,z[,time-range]_::
+ Compute the temperature at the given probe on an interface at a given time.
+ By default the compute time range is @STARDIS_ARGS_DEFAULT_COMPUTE_TIME@. The
+ probe is supposed to be on an interface and is moved to the closest point of
+ the closest interface before the computation start. The probe coordinates
+ must be in the same system as the geometry.
+
+*-m* _medium_name[,time-range]_::
+ Compute the mean temperature in a given medium at a given time. The medium
+ name must be part of the system description. By default the compute time
+ range is @STARDIS_ARGS_DEFAULT_COMPUTE_TIME@. The medium does not need to be
+ connex.
+
+*-s* _file[,time-range]_::
+ Compute the mean temperature on a given 2D region at a given time, the region
+ being defined as the front sides of the triangles in the provided *STL* file.
+ By default the compute time range is @STARDIS_ARGS_DEFAULT_COMPUTE_TIME@.
+ These triangles are not added to the geometry, but must be part of it. The
+ region does not need to be connex.
+
+*-S* _file[,time-range]_::
+ Compute the by-triangle mean temperature on a given 2D region at a given
+ time, the region being defined as the front sides of the triangles in the
+ provided *VTK* file. These triangles are not added to the geometry, but must
+ be part of it. By default the compute time range is
+ @STARDIS_ARGS_DEFAULT_COMPUTE_TIME@. The region does not need to be connex.
+
+*-F* _file[,time-range]_::
+ Compute the mean flux on a given 2D region at a given time, the region
+ being defined as the front sides of the triangles in the provided *VTK* file.
+ These triangles are not added to the geometry, but must be part of it. Flux
+ is accounted positive when going from the front side to the back side, at a
+ single-triangle level. By default the compute time range is
+ @STARDIS_ARGS_DEFAULT_COMPUTE_TIME@. The region does not need to be connex,
+ but it can currently only include geometry appearing in description lines
+ starting with H_BOUNDARY_FOR_SOLID, H_BOUNDARY_FOR_FLUID,
+ F_BOUNDARY_FOR_SOLID or SOLID_FLUID_CONNECTION (see *stardis-input*(5)).
+
+*-R* [__sub-option__:...]::
+ Render an infrared image of the system through a pinhole camera and write it
+ to _standard output_. One can use all-default sub-options by
+ simply providing the colon character (*:*) alone as an argument. Please note
+ that the camera position must be outside the geometry or in a fluid.
+ Available sub-options are:
+
+ **fmt=**_image_file_format_;;
+ Format of the image file in output. Can be *VTK* or *HT*. Default
+ _image_file_format_ is @STARDIS_ARGS_DEFAULT_RENDERING_OUTPUT_FILE_FMT@.
+
+ **fov=**_angle_;;
+ Horizontal field of view of the camera in [30, 120] degrees. By default
+ _angle_ is @STARDIS_ARGS_DEFAULT_RENDERING_FOV@ degrees.
+
+ **img=**_width_**x**_height_;;
+ Definition of the rendered image in pixels. By default the image definition
+ is @STARDIS_ARGS_DEFAULT_RENDERING_IMG_WIDTH@x@STARDIS_ARGS_DEFAULT_RENDERING_IMG_HEIGHT@.
+
+ **pos=**_x_**,**_y_**,**_z_;;
+ Position of the camera. By default it is set to
+ { @STARDIS_ARGS_DEFAULT_RENDERING_POS@ } or it is automatically computed to
+ ensure that the whole scene is visible, whether *tgt* is set or not,
+ respectively.
+
+ **spp=**_samples-count_;;
+ Number of samples per pixel.
+ By default, use @STARDIS_ARGS_DEFAULT_RENDERING_SPP@ samples per pixel.
+
+ **t=**_time-range_;;
+ Rendering time range. By default _time-range_ is
+ @STARDIS_ARGS_DEFAULT_RENDERING_TIME@.
+
+ **tgt=**_x_**,**_y_**,**_z_;;
+ Position targeted by the camera. By default, it is set to
+ { @STARDIS_ARGS_DEFAULT_RENDERING_TGT@ } or it is automatically computed to
+ ensure that the whole scene is visible, whether *pos* is set or not,
+ respectively.
+
+ **up=**_x_**,**_y_**,**_z_;;
+ Up vector of the camera. By default, it is set to
+ { @STARDIS_ARGS_DEFAULT_RENDERING_UP@ }.
+
+OTHER OPTIONS
+-------------
+*-a* _ambient_::
+ Set the ambient radiative temperature for the whole system, in Kelvin. By
+ default *ambient* is @STARDIS_ARGS_DEFAULT_AMBIENT_TEMP@.
+
+*-d*::
+ Write the geometry to _standard output_ in VTK format along with various
+ properties, including possible errors. If this option is used, no
+ computation occurs.
++
+Using this option in conjunction with an option that
+specifies a compute region (-F, -S, -s) has the effect to include the
+region in the output. This option cannot be used in conjunction with other
+options that write to _standard output_ (-g, -h, -R, -v).
+
+*-D* _type,files_name_prefix_::
+ Write sampled heat paths of the given *type* to files in VTK format, one
+ file per path. Possible values for *type* are *error* (write paths ending
+ in error), *success* (write successful paths), and *all* (write all paths).
+ Actual file names are produced by appending *files_name_prefix* and the path
+ rank starting at index 00000000, and possibly followed by *_err* for failure
+ paths: prefix00000000.vtk, prefix00000001_err.vtk, ...
++
+This option can only be used in conjuction with options that compute a
+result (-F, -m, -P, -p, -R, -S, -s) and cannot be used in conjunction with
+options -g or -G.
+
+*-e*::
+ Use extended format to output Monte-Carlo results. Can only be used in
+ conjunction with options that compute a single Monte-Carlo (-F, -m, -P, -p,
+ or -s without options -g or -G).
+
+*-g*::
+ Compute the Green function at the specified time and write it in ASCII to
+ _standard output_.
++
+This option can only be used in conjunction with one these options: -p, -P,
+-m, -s and cannot be used in conjunction with option -D.
+
+*-G* _file_name_[,__file_name__]::
+ Compute the Green function at the specified time and write it to a binary
+ file. If a second file name is provided, information on heat paths' ends
+ is also written in this second file in ascii csv format.
++
+This option can only be used in conjunction with one these options: -p, -P,
+-m, -s and cannot be used in conjunction with option -D.
++
+The resulting file can be further used through the *sgreen*(1) command to apply
+different temperature, flux or volumic power values.
+
+*-h*::
+ Output short help and exit.
+
+*-n* _samples-count_::
+ Number of Monte-Carlo samples. By default *samples-count* is set to
+ @STARDIS_ARGS_DEFAULT_SAMPLES_COUNT@.
+
+*-r* _reference_::
+ Set the reference temperature used for the linearization of the radiative
+ transfer, in Kelvin. By default *reference*
+ is @STARDIS_ARGS_DEFAULT_REFERENCE_TEMP@.
+
+*-t* _threads-count_::
+ Hint on the number of threads to use. By default use as many threads as CPU
+ cores.
+
+*-v*::
+ Output version information and exit.
+
+*-V* _level_::
+ Set the verbosity level. Possible values are *0* (no message), *1* (error
+ messages only), *2* (error and warning messages), and *3* (error, warning
+ and informative messages). All the messages are written to _standard error_.
+ Default verbosity *level* is @STARDIS_ARGS_DEFAULT_VERBOSE_LEVEL@.
+
+EXAMPLES
+--------
+Preprocess the system as described in *scene 5.txt* when intending to compute
+the mean flux on the triangles from the file *edge.stl*, and write its geometry
+in the file *scene.vtk*. Verbosity level is set to *3*:
+
+ $ stardis -M "scene 5.txt" -F edge.stl -d -V 3 > scene.vtk
+
+Compute the temperature at the probe point *0, 0.5, 0* at steady state. The
+system is read from the file *model.txt* and the number of samples is set to
+*1000000*:
+
+ $ stardis -M model.txt -p 0,0.5,0 -n 1000000
+
+Compute the mean temperature in the medium *med05* at *t=100* s. The system is
+read from the file *model.txt* and the result is output with extended format:
+
+ $ stardis -M model.txt -m med05,100 -e
+
+Compute the temperature at the probe point *0, 0, 0* at *t=2500*. The system is
+read from the 2 files *media.txt* and *bounds.txt* and the number of samples is
+set to *1000000*:
+
+ $ stardis -M media.txt -M bounds.txt -p 0,0,0,2500 -n 1000000
+
+Compute the mean temperature at the probe point *1, 2.5, 0* over the *50, 5000*
+time range. The system is read from the file *model.txt*:
+
+ $ stardis -M model.txt -p 1,2.5,0,50,5000
+
+Render the system as described in *scene.txt* with default settings:
+
+ $ stardis -M scene.txt -R :
+
+Render the system as described in *scn.txt* at *t=100*, *spp=2*,
+*img=800x600*, with output format *fmt=ht* and all other settings set to their
+default values. The output is redirected to the *img.ht* file. If the
+computation encounters erroneous heat paths, they will be dumped to VTK files
+named err_path_00000000.vtk, err_path_00000001.vtk, etc. The image file is then
+post-processed using *htpp*(1) with default settings to obtain a png file.
+
+ $ stardis -M scn.txt -R t=100:spp=2:img=800x600:fmt=ht -D error,err_path_ > img.ht
+ $ htpp -o img.pgn -v -m default img.ht
+
+Compute the Green fonction that computes the temperature at the probe point
+*0, 0, 0* at steady state. The system is read from the file *model.txt* and
+the Green function is written to the *probe.green file* and the heat paths'
+ends are written to the *probe_ends.csv* file:
+
+ $ stardis -M model.txt -p 0,0,0 -G probe.green,probe_ends.csv
+
+COPYRIGHT
+---------
+Copyright © 2018-2020 |Meso|Star>. License GPLv3+: GNU GPL
+version 3 or later <http://gnu.org/licenses/gpl.html>. This is free software.
+You are free to change and redistribute it. There is NO WARRANTY, to the extent
+permitted by law.
+
+SEE ALSO
+--------
+*stardis-input*(5),
+*stardis-output*(5),
+*sgreen*(1),
+*htpp*(1)
diff --git a/pp/green2xslx.pl b/pp/green2xslx.pl
@@ -1,567 +0,0 @@
-#!/usr/bin/perl
-use strict;
-use warnings;
-
-use Excel::Writer::XLSX;
-use Data::Dumper;
-
-#
-# Read and parse STDIN
-#
-
-# Drop warnings and text until leading '---BEGIN GREEN---'
-my $found_start = 0;
-my $line;
-while ($line = <STDIN>) {
- chomp $line;
- if ($line eq "---BEGIN GREEN---") { $found_start = 1; last;}
-}
-die 'No green found!' unless $found_start;
-
-# Read counters
-my $solids_rk=0;
-my $fluids_rk=1;
-my $tbounds_rk=2;
-my $hbounds_rk=3;
-my $fbounds_rk=4;
-my $ok_rk=5;
-my $failed_rk=6;
-$line = <STDIN>;
-chomp $line;
-die "Unexpected content found ($line)!" unless $line eq "# #solids #fluids #t_boundaries #h_boundaries #f_boundaries #ok #failures";
-$line = <STDIN>;
-chomp $line;
-my @counts = $line =~ /(\d+)/g;
-
-# Need at least 1 successful sample to proceed!
-die "No successful samples in this green ($counts[$failed_rk] ) failed samples\n" unless $counts[$ok_rk];
-
-my $last_id = -1;
-my @seen_id_types;
-
-# Read Solids
-my @solids;
-if ($counts[$solids_rk] > 0) {
- $line = <STDIN>;
- chomp $line;
- die "Unexpected content found ($line)!" unless ($line eq "# Solids");
- $line = <STDIN>;
- chomp $line;
- die "Unexpected content found ($line)!" unless ($line eq "# ID Name lambda rho cp power");
- for (my $s = 0; $s < $counts[$solids_rk] ; $s++) {
- $line = <STDIN>;
- chomp $line;
- my @tmp = split("\t", $line);
- die "Wrong number of values!" unless (scalar(@tmp) == 6);
- die "Wrong ID" unless ($tmp[0] >= 0) && (! defined $seen_id_types[$tmp[0]]);
- $seen_id_types[$tmp[0]] = 'S';
- my %new_elt = (
- ID=>$tmp[0],
- TEMP=>-1, # Imposed temperature for solids not yet in Stardis-app
- NAME=>$tmp[1],
- LAMBDA=>$tmp[2],
- RHO=>$tmp[3],
- CP=>$tmp[4],
- POWER=>$tmp[5]
- );
- push @solids, \%new_elt;
- }
-}
-
-# Read Fluids
-my @fluids;
-if ($counts[$fluids_rk] > 0) {
- $line = <STDIN>;
- chomp $line;
- die "Unexpected content found ($line)!" unless ($line eq "# Fluids");
- $line = <STDIN>;
- chomp $line;
- die "Unexpected content found ($line)!" unless ($line eq "# ID Name rho cp");
- for (my $f = 0; $f < $counts[$fluids_rk] ; $f++) {
- $line = <STDIN>;
- chomp $line;
- my @tmp = split("\t", $line);
- die "Wrong number of values!" unless (scalar(@tmp) == 4);
- die "Wrong ID" unless ($tmp[0] >= 0) && (! defined $seen_id_types[$tmp[0]]);
- $seen_id_types[$tmp[0]] = 'F';
- my %new_elt = (
- ID=>$tmp[0],
- TEMP=>-1, # Imposed temperature for fluids not yet in Stardis-app
- NAME=>$tmp[1],
- RHO=>$tmp[2],
- CP=>$tmp[3],
- POWER=>0 # Volumic Power for fluids not yet in Stardis-app
- );
- push @fluids, \%new_elt;
- }
-}
-
-# Read T Boundaries
-my @t_boundaries;
-if ($counts[$tbounds_rk] > 0) {
- $line = <STDIN>;
- chomp $line;
- die "Unexpected content found ($line)!" unless ($line eq "# T Boundaries");
- $line = <STDIN>;
- chomp $line;
- die "Unexpected content found ($line)!" unless ($line eq "# ID Name temperature");
- for (my $b = 0; $b < $counts[$tbounds_rk] ; $b++) {
- $line = <STDIN>;
- chomp $line;
- my @tmp = split("\t", $line);
- die "Wrong number of values!" unless (scalar(@tmp) == 3);
- die "Wrong ID" unless ($tmp[0] >= 0) && (! defined $seen_id_types[$tmp[0]]);
- $seen_id_types[$tmp[0]] = 'T';
- my %new_elt = (
- ID=>$tmp[0],
- NAME=>$tmp[1],
- TEMP=>$tmp[2]
- );
- push @t_boundaries, \%new_elt;
- }
-}
-
-# Read H Boundaries
-my @h_boundaries;
-if ($counts[$hbounds_rk] > 0) {
- $line = <STDIN>;
- chomp $line;
- die "Unexpected content found ($line)!" unless ($line eq "# H Boundaries");
- $line = <STDIN>;
- chomp $line;
- die "Unexpected content found ($line)!" unless ($line eq "# ID Name emissivity specular_fraction hc hc_max T_env");
- for (my $b = 0; $b < $counts[$hbounds_rk] ; $b++) {
- $line = <STDIN>;
- chomp $line;
- my @tmp = split("\t", $line);
- die "Wrong number of values!" unless (scalar(@tmp) == 7);
- die "Wrong ID" unless ($tmp[0] >= 0) && (! defined $seen_id_types[$tmp[0]]);
- $seen_id_types[$tmp[0]] = 'H';
- my %new_elt = (
- ID=>$tmp[0],
- NAME=>$tmp[1],
- EMISSIVITY=>$tmp[2],
- SPEC_FRACTION=>$tmp[3],
- HC=>$tmp[4],
- HC_MAX=>$tmp[5],
- T_ENV=>$tmp[6]
- );
- push @h_boundaries, \%new_elt;
- }
-}
-
-# Read F Boundaries
-my @f_boundaries;
-if ($counts[$fbounds_rk] > 0) {
- $line = <STDIN>;
- chomp $line;
- die "Unexpected content found ($line)!" unless ($line eq "# F Boundaries");
- $line = <STDIN>;
- chomp $line;
- die "Unexpected content found ($line)!" unless ($line eq "# ID Name flux");
- for (my $b = 0; $b < $counts[$fbounds_rk] ; $b++) {
- $line = <STDIN>;
- chomp $line;
- my @tmp = split("\t", $line);
- die "Wrong number of values!" unless (scalar(@tmp) == 3);
- die "Wrong ID" unless ($tmp[0] >= 0) && (! defined $seen_id_types[$tmp[0]]);
- $seen_id_types[$tmp[0]] = 'X';
- my %new_elt = (
- ID=>$tmp[0],
- NAME=>$tmp[1],
- FLUX=>$tmp[2]
- );
- push @f_boundaries, \%new_elt;
- }
-}
-
-# Read Radiative Temperatures
-my $radiative_temp;
-my $linear_temp;
-my $rad_temp_id;
-{
- $line = <STDIN>;
- chomp $line;
- die "Unexpected content found ($line)!" unless ($line eq "# Radiative Temperatures");
- $line = <STDIN>;
- chomp $line;
- die "Unexpected content found ($line)!" unless ($line eq "# ID Rad_Temp Lin_Temp");
- $line = <STDIN>;
- chomp $line;
- my @tmp = split("\t", $line);
- die "Wrong number of values!" unless (scalar(@tmp) == 3);
- die "Wrong ID" unless ($tmp[0] >= 0) && (! defined $seen_id_types[$tmp[0]]);
- $seen_id_types[$tmp[0]] = 'R';
- die "Wrong Temperature!" unless ($tmp[1] >= 0) && ($tmp[2] >= 0);
- $radiative_temp = $tmp[1];
- $linear_temp = $tmp[2];
- $rad_temp_id = $tmp[0];
-}
-
-# Read Samples headers
-$line = <STDIN>;
-chomp $line;
-die "Unexpected content found ($line)!" unless ($line eq "# Samples");
-$line = <STDIN>;
-chomp $line;
-die "Unexpected content found ($line)!" unless ($line eq "# end #power_terms #flux_terms power_term_1 ... power_term_n flux_term_1 ... flux_term_n");
-$line = <STDIN>;
-chomp $line;
-die "Unexpected content found ($line)!" unless ($line eq "# end = end_type end_id; end_type = T | H | X | R | F | S");
-$line = <STDIN>;
-chomp $line;
-die "Unexpected content found ($line)!" unless ($line eq "# power_term_i = power_type_i power_id_i factor_i");
-$line = <STDIN>;
-chomp $line;
-die "Unexpected content found ($line)!" unless ($line eq "# flux_term_i = flux_id_i factor_i");
-
-# read samples
-my @samples;
-for(my $s=0; $s < $counts[$ok_rk]; $s++) {
- $line = <STDIN>;
- die "Unexpected end of data ($s samples read)" unless $line;
- chomp $line;
- my @tmp = split("\t", $line);
-
- # Check read data
- die "Wrong number of values!" unless (scalar(@tmp) >= 4);
- my $pw_count = $tmp[2];
- my $fx_count = $tmp[3];
- die "Wrong power_terms count!" unless ($pw_count >=0);
- die "Wrong flux_terms count!" unless ($fx_count >= 0);
- die "Wrong number of terms!" unless (scalar(@tmp) == 4 + $pw_count * 3 + $fx_count * 2);
-
- my @pw_types;
- my @pw_ids;
- my @pw_factors;
- my @fx_ids;
- my @fx_factors;
- for(my $n = 0; $n < $pw_count; $n++) {
- my $ty = $tmp[4+3*$n] ;
- my $id = $tmp[5+3*$n];
- my $fc =$tmp[6+3*$n];
- die "Wrong ID" unless ($id >= 0) && (defined $seen_id_types[$id]) && ($seen_id_types[$id] eq $ty);
- die "Wrong power_term factor!" unless ($fc > 0);
- push @pw_types, $ty;
- push @pw_ids, $id;
- push @pw_factors, $fc;
- }
- for(my $n = 0; $n < $fx_count; $n++) {
- my $id = $tmp[4+$pw_count*3+2*$n];
- my $fc =$tmp[5+$pw_count*3+2*$n];
- die "Wrong ID" unless ($id >= 0) && (defined $seen_id_types[$id]) && ($seen_id_types[$id] eq 'X');
- die "Wrong power_term factor!" unless ($fc > 0);
- push @fx_ids, $id;
- push @fx_factors, $fc;
- }
- my %new_elt = (
- END_TYPE=>$tmp[0],
- END_ID=>$tmp[1],
- PW_COUNT=>$tmp[2],
- FX_COUNT=>$tmp[3],
- PW_TYPES=>\@pw_types,
- PW_IDS=>\@pw_ids,
- PW_FACTORS=>\@pw_factors,
- FX_IDS=>\@fx_ids,
- FX_FACTORS=>\@fx_factors
- );
- push @samples, \%new_elt;
-}
-
-# Check end of data
-$line = <STDIN>;
-chomp $line;
-die "Unexpected content in file" unless ($line eq "---END GREEN---");
-
-#
-# Export data into an xlsx file
-#
-
-binmode( STDOUT );
-my $workbook = Excel::Writer::XLSX->new( \*STDOUT );
-$workbook->set_properties(
- title => 'Green calculator',
- author => 'meso-star.com',
- comments => 'Created with Perl, Excel::Writer::XLSX and Stardis-app Post-Process',
- );
-
-my $title = $workbook->add_format();
-$title->set_locked(1);
-$title->set_bold();
-$title->set_top(5);
-$title->set_bottom(2);
-my $locked = $workbook->add_format();
-$locked->set_locked(1);
-$locked->set_bg_color('#F2F2F2'); #light gray
-my $unlocked = $workbook->add_format();
-$unlocked->set_locked(0);
-
-my $model_current_line = 0;
-my @id_end_cells;
-my @id_pw_cells;
-my @id_fx_cells;
-my @cpt_end_cells;
-my @cpt_pw_cells;
-my @cpt_fx_cells;
-my @name_end_cells;
-my @name_pw_cells;
-my @name_fx_cells;
-
-# One sheet for all but samples
-my $model = $workbook->add_worksheet('Model');
-$model->protect(); # Cannot edit cells unless unlocked
-$model->set_column(0, 5, 24); # Column 0 to 5: width = 24
-
-# Create table for solids
-if($counts[$solids_rk] > 0) {
- my @solid_colnames = ('Solid Name', 'Imposed Temperature', 'Lambda', 'Rho', 'Cp', 'Volumic Power');
- $model->write($model_current_line, 0, \@solid_colnames, $title);
- $model_current_line++;
- for(my $s = 0; $s < $counts[$solids_rk] ; $s++) {
- my $solid = $solids[$s];
- my $temp = $solid->{TEMP};
- my $pw = $solid->{POWER};
- my $name = $solid->{NAME};
- $model->write($model_current_line, 0, $name, $locked);
- $model->write_number($model_current_line, 1, $temp, ($temp >= 0) ? $unlocked : $locked);
- $model->write_number($model_current_line, 2, $solid->{LAMBDA}, $locked);
- $model->write_number($model_current_line, 3, $solid->{RHO}, $locked);
- $model->write_number($model_current_line, 4, $solid->{CP}, $locked);
- $model->write_number($model_current_line, 5, $pw, ($pw > 0) ? $unlocked : $locked);
- $model_current_line++;
- my $id = $solid->{ID};
- die "Inconsistency!" unless ($id >= 0) && (defined $seen_id_types[$id]) && ($seen_id_types[$id] eq 'S');
- die "Inconsistency!" unless (!defined $id_end_cells[$id]) && (!defined $cpt_end_cells[$id]) && (!defined $name_end_cells[$id]);
- die "Inconsistency!" unless (!defined $id_pw_cells[$id]) && (!defined $cpt_pw_cells[$id]) && (!defined $name_pw_cells[$id]);
- if ($temp >= 0) {
- $id_end_cells[$id] = "B$model_current_line";
- $cpt_end_cells[$id] = 0;
- $name_end_cells[$id] = "$name.Imposed_Temperature";
- }
- $id_pw_cells[$id] = "F$model_current_line";
- $cpt_pw_cells[$id] = 0;
- $name_pw_cells[$id] = "$name.Volumic_Power";
- }
- $model_current_line++;
-}
-
-# Create table for fluids
-if($counts[$fluids_rk] > 0) {
- my @fluid_colnames = ('Fluid Name', 'Imposed Temperature', 'Rho', 'Cp', 'Volumic Power');
- $model->write($model_current_line, 0, \@fluid_colnames, $title);
- $model_current_line++;
- for(my $f = 0; $f < $counts[$fluids_rk] ; $f++) {
- my $fluid = $fluids[$f];
- my $temp = $fluid->{TEMP};
- my $pw = $fluid->{POWER};
- my $name = $fluid->{NAME};
- $model->write($model_current_line, 0, $name, $locked);
- $model->write_number($model_current_line, 1, $temp, ($temp >= 0) ? $unlocked : $locked);
- $model->write_number($model_current_line, 2, $fluid->{RHO}, $locked);
- $model->write_number($model_current_line, 3, $fluid->{CP}, $locked);
- $model->write_number($model_current_line, 4, $pw, ($pw > 0) ? $unlocked : $locked);
- $model_current_line++;
- my $id = $fluid->{ID};
- die "Inconsistency!" unless ($id >= 0) && (defined $seen_id_types[$id]) && ($seen_id_types[$id] eq 'F');
- die "Inconsistency!" unless (!defined $id_end_cells[$id]) && (!defined $cpt_end_cells[$id]) && (!defined $name_end_cells[$id]);
- die "Inconsistency!" unless (!defined $id_pw_cells[$id]) && (!defined $cpt_pw_cells[$id]) && (!defined $name_pw_cells[$id]);
- if ($temp >= 0) {
- $id_end_cells[$id] = "B$model_current_line";
- $cpt_end_cells[$id] = 0;
- $name_end_cells[$id] = "$name.Imposed_Temperature";
- }
- $id_pw_cells[$id] = "E$model_current_line";
- $cpt_pw_cells[$id] = 0;
- $name_pw_cells[$id] = "$name.Volumic_Power";
- }
- $model_current_line++;
-}
-
-# Create table for T boundaries
-if($counts[$tbounds_rk] > 0) {
- my @tbound_colnames = ('T Boundary Name', 'Temperature');
- $model->write($model_current_line, 0, \@tbound_colnames, $title);
- $model_current_line++;
- for(my $b = 0; $b < $counts[$tbounds_rk] ; $b++) {
- my $tbound = $t_boundaries[$b];
- my $temp = $tbound->{TEMP};
- my $name = $tbound->{NAME};
- $model->write($model_current_line, 0, $name, $locked);
- $model->write_number($model_current_line, 1, $temp, ($temp >= 0) ? $unlocked : $locked);
- $model_current_line++;
- my $id = $tbound->{ID};
- die "Inconsistency!" unless ($id >= 0) && (defined $seen_id_types[$id]) && ($seen_id_types[$id] eq 'T');
- die "Inconsistency!" unless (!defined $id_end_cells[$id]) && (!defined $cpt_end_cells[$id]) && (!defined $name_end_cells[$id]);
- $id_end_cells[$id] = "B$model_current_line";
- $cpt_end_cells[$id] = 0;
- $name_end_cells[$id] = "$name.Temperature";
- # No volumic power at boundaries!
- }
- $model_current_line++;
-}
-
-# Create table for H boundaries
-if($counts[$hbounds_rk] > 0) {
- my @hbound_colnames = ('H Boundary Name', 'Emissivity', 'Specular Fraction', 'Hc', 'Hc Max', 'Environment Temperature');
- $model->write($model_current_line, 0, \@hbound_colnames, $title);
- $model_current_line++;
- for(my $b = 0; $b < $counts[$hbounds_rk] ; $b++) {
- my $hbound = $h_boundaries[$b];
- my $name = $hbound->{NAME};
- $model->write($model_current_line, 0, $name, $locked);
- $model->write_number($model_current_line, 1, $hbound->{EMISSIVITY}, $locked);
- $model->write_number($model_current_line, 2, $hbound->{SPEC_FRACTION}, $locked);
- $model->write_number($model_current_line, 3, $hbound->{HC}, $locked);
- $model->write_number($model_current_line, 4, $hbound->{HC_MAX}, $locked);
- $model->write_number($model_current_line, 5, $hbound->{T_ENV}, $unlocked);
- $model_current_line++;
- my $id = $hbound->{ID};
- die "Inconsistency!" unless ($id >= 0) && (defined $seen_id_types[$id]) && ($seen_id_types[$id] eq 'H');
- die "Inconsistency!" unless (!defined $id_end_cells[$id]) && (!defined $cpt_end_cells[$id]) && (!defined $name_end_cells[$id]);
- $id_end_cells[$id] = "F$model_current_line";
- $cpt_end_cells[$id] = 0;
- $name_end_cells[$id] = "$name.Environment_Temperature";
- # No volumic power at boundaries!
- }
- $model_current_line++;
-}
-
-# Create table for F boundaries
-if($counts[$fbounds_rk] > 0) {
- my @fbound_colnames = ('F Boundary Name', 'Flux');
- $model->write($model_current_line, 0, \@fbound_colnames, $title);
- $model_current_line++;
- for(my $b = 0; $b < $counts[$fbounds_rk] ; $b++) {
- my $fbound = $f_boundaries[$b];
- my $name = $fbound->{NAME};
- $model->write($model_current_line, 0, $name, $locked);
- $model->write_number($model_current_line, 1, $fbound->{FLUX}, $unlocked);
- $model_current_line++;
- my $id = $fbound->{ID};
- die "Inconsistency!" unless ($id >= 0) && (defined $seen_id_types[$id]) && ($seen_id_types[$id] eq 'X');
- die "Inconsistency!" unless (!defined $id_fx_cells[$id]) && (!defined $cpt_fx_cells[$id]) && (!defined $name_fx_cells[$id]);
- $id_fx_cells[$id] = "B$model_current_line";
- $cpt_fx_cells[$id] = 0;
- $name_fx_cells[$id] = "$name.Flux";
- # Cannot end at F boundaries
- # No volumic power at boundaries!
- }
- $model_current_line++;
-}
-
-# Create table for Radiative Temperatures
-{
- my @radiative_colnames = ('Radiative Temperature', 'Linearisation Temperature');
- $model->write($model_current_line, 0, \@radiative_colnames, $title);
- $model_current_line++;
- $model->write_number($model_current_line, 0, $radiative_temp, $unlocked);
- $model->write_number($model_current_line, 1, $linear_temp, $locked);
- $model_current_line++;
- die "Inconsistency!" unless (!defined $id_end_cells[$rad_temp_id]) && (!defined $cpt_end_cells[$rad_temp_id]) && (!defined $name_end_cells[$rad_temp_id]);
- $id_end_cells[$rad_temp_id]= "A$model_current_line";
- $cpt_end_cells[$rad_temp_id] = 0;
- $name_end_cells[$rad_temp_id] = 'Radiative_Temperature';
- # No volumic power at infinity!
- $model_current_line++;
-}
-
-# One sheet for samples
-my $green = $workbook->add_worksheet('Samples');
-$green->protect();
-
-my $samples_current_line = 0;
-if($counts[$ok_rk] > 0) {
- my @samples_colnames = ('T(sample)');
- $green->write($samples_current_line, 0, \@samples_colnames, $title);
- $samples_current_line++;
- for(my $s = 0; $s < $counts[$ok_rk] ; $s++) {
- my $sample = $samples[$s];
- my $end_type = $sample->{END_TYPE};
- my $end_id = $sample->{END_ID};
- my $pw_count = $sample->{PW_COUNT};
- my $pw_types = $sample->{PW_TYPES};
- my $pw_ids = $sample->{PW_IDS};
- my $pw_factors = $sample->{PW_FACTORS};
- my $fx_count = $sample->{FX_COUNT};
- my $fx_ids = $sample->{FX_IDS};
- my $fx_factors = $sample->{FX_FACTORS};
-
- # create a cell with formula:
- # end_temp + pw_term_1 + ... + pw_term_n + fx_term_1 + ... + fx_term_n
- unless (($end_id >= 0) && ($end_id < scalar(@seen_id_types)) && (defined $seen_id_types[$end_id]) && ($seen_id_types[$end_id] eq $end_type)) {
- print STDERR "Sample: ", Dumper($sample);
- print STDERR "END ID: $end_id\n";
- print STDERR "END TYPE: $seen_id_types[$end_id] VS $end_type\n";
- print STDERR "END TYPES: @seen_id_types\n";
- die "Invalid ID!" ;
- }
- unless ((defined $id_end_cells[$end_id]) && (defined $cpt_end_cells[$end_id])) {
- print STDERR "Sample: ", Dumper($sample);
- print STDERR "END ID: $end_id\n";
- print STDERR "END END CELLS: @id_end_cells\n";
- die "Inconsistency!"
- }
- my $formula = "=Model!$id_end_cells[$end_id]";
- $cpt_end_cells[$end_id] += 1;
- for(my $n = 0; $n < $pw_count; $n++) {
- my $ty = @$pw_types[$n];
- my $id = @$pw_ids[$n];
- my $fc = @$pw_factors[$n];
- die "Invalid ID ($id)!" unless ($id >= 0) && (defined $seen_id_types[$id]) && ($seen_id_types[$id] eq $ty);
- die "Inconsistency!" unless (defined $id_pw_cells[$id]) && ($fc > 0);
- $formula = $formula."+Model!$id_pw_cells[$id]*$fc";
- $cpt_pw_cells[$id] += $fc;
- }
- for(my $n = 0; $n < $fx_count; $n++) {
- my $id = @$fx_ids[$n];
- my $fc = @$fx_factors[$n];
- die "Invalid ID ($id)!" unless ($id >= 0) && (defined $seen_id_types[$id]);
- die "Inconsistency!" unless (defined $id_fx_cells[$id]) && ($fc > 0);
- $formula = $formula."+Model!$id_fx_cells[$id]*$fc";
- $cpt_fx_cells[$id] += $fc;
- }
- $green->write_formula($samples_current_line, 0, $formula, $locked);
- $samples_current_line++;
- }
-}
-
-# Create the polynom for temperature
-my $sep ="";
-my $poly = "T = ";
-for (my $n = 0; $n < scalar(@cpt_end_cells); $n++) {
- if (defined $cpt_end_cells[$n] && $cpt_end_cells[$n] != 0) {
- my $w = $cpt_end_cells[$n] / $counts[$ok_rk];
- $poly .= $sep . $w . " * $name_end_cells[$n]";
- $sep = " + ";
- }
-}
-for(my $n = 0; $n < scalar(@cpt_pw_cells); $n++) {
- if (defined $cpt_pw_cells[$n] && $cpt_pw_cells[$n] != 0) {
- my $w = $cpt_pw_cells[$n] / $counts[$ok_rk];
- $poly .= $sep . $w . " * $name_pw_cells[$n]";
- $sep = " + ";
- }
-}
-for(my $n = 0; $n < scalar(@cpt_fx_cells); $n++) {
- if (defined $cpt_fx_cells[$n] && $cpt_fx_cells[$n] != 0) {
- my $w = $cpt_fx_cells[$n] / $counts[$ok_rk];
- $poly .= $sep . $w . " * $name_fx_cells[$n]";
- $sep = " + ";
- }
-}
-
-
-# The MC Estimator and STDERR table
-my @result_colnames = ('Estimate', 'Sigma');
-$model->write($model_current_line, 0, \@result_colnames, $title);
-$model_current_line++;
-$model->write_formula($model_current_line, 0, "AVERAGE(Samples!A2:A$samples_current_line)", $locked);
-# Here we use STDEVP (Standard dev for a entire population) to remains coherent with stardis-solver
-# One could consider STDEV (Standard dev for a sampling of the population) more appropriate
-$model->write_formula($model_current_line, 1, "STDEVP(Samples!A2:A$samples_current_line)/SQRT($samples_current_line-1)", $locked);
-$model_current_line++;
-
-$model->write_string($model_current_line, 0, $poly);
-$workbook->close();
-
-print STDERR "$poly\n";
diff --git a/src/args.h b/src/args.h
@@ -1,373 +0,0 @@
-/* Copyright (C) 2018 |Meso|Star> (contact@meso-star.com)*/
-
-#ifndef ARGS_H
-#define ARGS_H
-
-#include <getopt.h>
-#include <stdlib.h>
-
-#include <rsys/rsys.h>
-#include <rsys/cstr.h>
-#include <sdis_version.h>
-
-enum stardis_mode {
- UNDEF_MODE = 0,
- PROBE_COMPUTE = BIT(0),
- MEDIUM_COMPUTE = BIT(1),
- BOUNDARY_COMPUTE = BIT(2),
- GREEN_MODE = BIT(3),
- IR_COMPUTE = BIT(4),
- DUMP_VTK = BIT(5),
- PROBE_COMPUTE_ON_INTERFACE = BIT(6),
- COMPUTE_MODES = PROBE_COMPUTE | MEDIUM_COMPUTE | BOUNDARY_COMPUTE | IR_COMPUTE | DUMP_VTK | PROBE_COMPUTE_ON_INTERFACE
-};
-
-static char mode_option(const enum stardis_mode m) {
- int found = 0;
- char res = '?';
- if (m & PROBE_COMPUTE) { found++; res = 'p'; }
- if (m & MEDIUM_COMPUTE) { found++; res = 'm'; }
- if (m & BOUNDARY_COMPUTE) { found++; res = 'b'; }
- if (m & IR_COMPUTE) { found++; res = 'R'; }
- if (m & DUMP_VTK) { found++; res = 'd'; }
- if (m & PROBE_COMPUTE_ON_INTERFACE) { found++; res = 'P'; }
- ASSERT(found == 1);
- return res;
-}
-
-enum dump_path_type {
- DUMP_NONE = 0,
- DUMP_SUCCESS = BIT(0),
- DUMP_ERROR = BIT(1),
- DUMP_ALL = DUMP_SUCCESS | DUMP_ERROR,
-};
-
-struct args{
- char* medium_filename;
- char* bc_filename;
- char* medium_name;
- char* solve_boundary_filename;
- size_t N;
- unsigned nthreads;
- union u { /* Trick to allow static initialization with INF */
- struct pt { double p[3]; uint64_t t; } pt;
- double probe[4];
- } u;
- enum stardis_mode mode;
- double scale_factor;
- double radiative_temp[2];
- char* camera;
- enum dump_path_type dump_paths;
- int just_help;
-};
-#ifdef NDEBUG
-#define DEFAULT_NTHREADS SDIS_NTHREADS_DEFAULT
-#else
-#define DEFAULT_NTHREADS 1
-#endif
-#define ARGS_DEFAULT__ {\
- NULL, NULL, NULL, NULL, 10000, DEFAULT_NTHREADS,\
- { { {0.0, 0.0, 0.0}, 0x7FF0000000000000 /* probe[3]=INF */}},\
- UNDEF_MODE, 1.0, {300.0, 300.0}, NULL, DUMP_NONE, 0}
-static const struct args ARGS_DEFAULT = ARGS_DEFAULT__;
-
-static void
-print_help(char* prog)
-{
- printf("stardis-app built-on stardis library version %i.%i.%i\n",
- Stardis_VERSION_MAJOR,Stardis_VERSION_MINOR,Stardis_VERSION_PATCH);
- printf("usage: \n%s -M MEDIUM.txt -B BOUNDARY.txt\n", prog);
- printf("[ -p X,Y,Z,TIME | -m MEDIUM_NAME,TIME | -d | -b SURFACE.vtk,TIME\n");
- printf(" | -R t=TIME:spp=SPP:fov=FOV:up=XUP,YUP,ZUP:pos=X,Y,Z:tgt=XT,YT,ZT:img=WxH ]\n");
- printf("[ -g] [-s SCALE_FACTOR] [-D {all | error | success}] -d\n");
- printf("[-n NUM_OF_REALIZATIONS] [-t NUM_OF_THREADS]\n");
- printf("[-r AMBIENT_RAD_TEMP:REFERENCE_TEMP]\n");
- printf("\n -h: print this help.\n");
- printf("\nMandatory arguments\n");
- printf("---------\n");
- printf("\n -M MEDIUM.txt:\n");
- printf(" MEDIUM.txt is a text file which contains the description of the\n");
- printf(" media.\n");
- printf("\n -B BOUNDARY.txt:\n");
- printf(" BOUNDARY.txt is a text file which contains the description of the\n");
- printf(" boundary conditions.\n");
- printf("\nExclusive arguments\n");
- printf("-------------------\n");
- printf("\n -p X:Y:Z:TIME:\n");
- printf(" Compute the temperature at the given probe.\n");
- printf(" The probe must be in a medium.\n");
- printf(" If some boundary conditions are time-dependant, TIME cannot be INF.\n");
- printf("\n -P X:Y:Z:TIME:\n");
- printf(" Compute the temperature at the given probe on an interface.\n");
- printf(" The probe must be in a medium and is moved to the closest interface.\n");
- printf(" If some boundary conditions are time-dependant, TIME cannot be INF.\n");
- printf("\n -m MEDIUM_NAME,TIME:\n");
- printf(" Compute the mean temperature in a given medium at a given time.\n");
- printf(" If some boundary conditions are time-dependant, TIME cannot be INF.\n");
- printf("\n -d:\n");
- printf(" Dump the geometry in VTK format with medium front/back id and\n");
- printf(" boundary id.\n");
- printf("\n -b SURFACE.vtk,TIME:\n");
- printf(" Compute the mean temperature on a given 2D shape at a given time.\n");
- printf(" Mean temperature is computed on the front sides of the primitives\n");
- printf(" listed in SURFACE.vtk. These primitives are not added to the geometry,\n");
- printf(" but must be already known. The shape doesn't need to be connex.\n");
- printf(" If some boundary conditions are time-dependant, TIME cannot be INF.\n");
- printf("\n -R t=TIME:spp=SPP:fov=FOV:up=XUP,YUP,ZUP:pos=X,Y,Z:tgt=XT,YT,ZT:img=WxH:\n");
- printf(" The infra-red rendering mode.\n");
- printf(" t is the rendering time (default: INF).\n");
- printf(" spp is the number of samples per pixel (default: 4).\n");
- printf(" fov is the field of view (default: 70 degrees).\n");
- printf(" up is the up direction (default: 0,0,1).\n");
- printf(" pos is the position of camera (default: 1,1,1).\n");
- printf(" tgt is the target (default: 0,0,0).\n");
- printf(" img is the resolution (default: 640x480).\n");
- printf("\nOptionnal arguments\n");
- printf("-------------------\n");
- printf("\n -g:\n");
- printf(" Compute the green function.\n");
- printf(" Must be used in conjonction with one the -p, -m or -b options.\n");
- printf(" Provided TIME is silently ignored.\n");
- printf("\n -s SCALE_FACTOR:\n");
- printf(" default value: 1.0.\n");
- printf("\n -D { all | error | success }:\n");
- printf(" dump paths in VTK format.\n");
- printf("\n -n NUM_OF_REALIZATIONS:\n");
- printf(" Number of Monte-Carlo realizations.\n");
- printf(" default value: 10000.\n");
- printf("\n -t NUM_OF_THREADS:\n");
- printf(" Number of threads; default value is all threads available.\n");
- printf("\n -r AMBIENT_RAD_TEMP,REFERENCE_TEMP:\n");
- printf(" Parameters for the radiative transfer.\n");
- printf(" AMBIENT_RAD_TEMP is the ambient radiative temperature .\n");
- printf(" REFERENCE_TEMP is the temperature used for the linearization\n");
- printf(" of the radiative transfer.\n");
-}
-
-
-static INLINE res_T
-parse_args(const int argc, char** argv, struct args* args)
-{
- int opt = 0;
- size_t len = 0;
- res_T res = RES_OK;
-
- if (argc == 1) {
- print_help(argv[0]);
- res = RES_BAD_ARG;
- goto error;
- }
-
- opterr = 0; /* No default error messages */
- while((opt = getopt(argc, argv, "hgn:t:b:B:M:m:p:P:dD:s:r:R:")) != -1) {
- switch(opt) {
- case '?': /* Unreconised option */
- res = RES_BAD_ARG;
- fprintf(stderr, "Invalid option -%c\n", optopt);
- goto error;
-
- case 'h':
- print_help(argv[0]);
- args->just_help = 1;
- goto exit;
-
- case 'g':
- args->mode |= GREEN_MODE;
- break;
-
- case 'n': {
- unsigned long n;
- res = cstr_to_ulong(optarg, &n);
- if (res != RES_OK || n == 0) {
- res = RES_BAD_ARG;
- fprintf(stderr, "Invalid argument -%c %s\n", opt, optarg);
- goto error;
- }
- args->N = n;
- break;
- }
-
- case 'B':
- args->bc_filename = optarg;
- break;
-
- case 'M':
- args->medium_filename = optarg;
- break;
-
- case 't':
- res = cstr_to_uint(optarg, &args->nthreads);
- if (res != RES_OK
- || args->nthreads <= 0){
- res = RES_BAD_ARG;
- fprintf(stderr, "Invalid argument -%c %s\n", opt, optarg);
- goto error;
- }
- break;
-
- case 'p':
- if (args->mode & COMPUTE_MODES) {
- res = RES_BAD_ARG;
- fprintf(stderr, "Cannot specify multiple modes: -%c and -%c\n",
- (char)opt, mode_option(args->mode));
- goto error;
- }
- args->mode |= PROBE_COMPUTE;
- cstr_to_list_double(optarg, ',', args->u.probe, &len, 4);
- if (len != 4
- || res != RES_OK
- || args->u.probe[3] < 0)
- {
- res = RES_BAD_ARG;
- fprintf(stderr, "Invalid argument -%c %s\n", opt, optarg);
- goto error;
- }
- break;
-
- case 'P':
- if (args->mode & COMPUTE_MODES) {
- res = RES_BAD_ARG;
- fprintf(stderr, "Cannot specify multiple modes: -%c and -%c\n",
- (char)opt, mode_option(args->mode));
- goto error;
- }
- args->mode |= PROBE_COMPUTE_ON_INTERFACE;
- cstr_to_list_double(optarg, ',', args->u.probe, &len, 4);
- if(len != 4
- || res != RES_OK
- || args->u.probe[3] < 0)
- {
- res = RES_BAD_ARG;
- fprintf(stderr, "Invalid argument -%c %s\n", opt, optarg);
- goto error;
- }
- break;
-
- case 'b': {
- int err = 0;
- char *ptr;
- if (args->mode & COMPUTE_MODES) {
- res = RES_BAD_ARG;
- fprintf(stderr, "Cannot specify multiple modes: -%c and -%c\n",
- (char)opt, mode_option(args->mode));
- goto error;
- }
- args->mode |= BOUNDARY_COMPUTE;
- ptr = strrchr(optarg, ',');
- /* Single ',' allowed */
- if (!ptr || ptr != strchr(optarg, ','))
- err = 1;
- else {
- *ptr = '\0';
- ptr++;
- args->solve_boundary_filename = optarg;
- err = (RES_OK != cstr_to_double(ptr, args->u.probe + 3) || args->u.probe[3] < 0);
- }
- if (err) {
- res = RES_BAD_ARG;
- fprintf(stderr, "Invalid argument -%c %s\n", opt, optarg);
- goto error;
- }
- break;
- }
-
- case 'm': {
- char* ptr;
- if (args->mode & COMPUTE_MODES) {
- res = RES_BAD_ARG;
- fprintf(stderr, "Cannot specify multiple modes: -%c and -%c\n",
- (char)opt, mode_option(args->mode));
- goto error;
- }
- args->mode |= MEDIUM_COMPUTE;
- ptr = strpbrk(optarg, ",");
- if (! ptr || ptr == optarg)
- res = RES_BAD_ARG;
- else res = cstr_to_double(ptr+1, args->u.probe+3);
- if (res != RES_OK) {
- fprintf(stderr, "Invalid argument -%c %s\n", opt, optarg);
- goto error;
- }
- *ptr = '\0';
- args->medium_name = optarg;
- break;
- }
-
- case 'd':
- if (args->mode & COMPUTE_MODES) {
- res = RES_BAD_ARG;
- fprintf(stderr, "Cannot specify multiple modes: -%c and -%c\n",
- (char)opt, mode_option(args->mode));
- goto error;
- }
- args->mode |= DUMP_VTK;
- break;
-
- case 'D':
- if (0 == strcmp(optarg, "all")) {
- args->dump_paths = DUMP_ALL;
- } else if(0 == strcmp(optarg, "error")) {
- args->dump_paths = DUMP_ERROR;
- } else if(0 == strcmp(optarg, "success")) {
- args->dump_paths = DUMP_SUCCESS;
- } else {
- res = RES_BAD_ARG;
- fprintf(stderr, "Invalid argument -%c %s\n", opt, optarg);
- goto error;
- }
- break;
-
- case 's':
- cstr_to_double(optarg, &args->scale_factor);
- if (res != RES_OK
- || args->scale_factor <=0){
- res = RES_BAD_ARG;
- fprintf(stderr, "Invalid argument -%c %s\n", opt, optarg);
- goto error;
- }
- break;
-
- case 'r':
- cstr_to_list_double(optarg, ',', args->radiative_temp, &len, 2);
- if (res != RES_OK
- || len != 2
- || args->radiative_temp[0] <=0
- || args->radiative_temp[1] <=0){
- res = RES_BAD_ARG;
- fprintf(stderr, "Invalid argument -%c %s\n", opt, optarg);
- goto error;
- }
- break;
-
- case 'R':
- if (args->mode & COMPUTE_MODES) {
- res = RES_BAD_ARG;
- fprintf(stderr, "Cannot specify multiple modes: -%c and -%c\n",
- (char)opt, mode_option(args->mode));
- goto error;
- }
- args->mode |= IR_COMPUTE;
- args->camera = optarg;
- break;
- }
- }
-
-if (!args->medium_filename){
- fprintf(stderr, "Argument required -m\n");
- res = RES_BAD_ARG;
- goto error;
-}
-
-if (!args->bc_filename){
- fprintf(stderr, "Argument required -b\n");
- res = RES_BAD_ARG;
- goto error;
-}
-
-exit:
- return res;
-error:
- goto exit;
-}
-
-#endif /*ARGS_H*/
diff --git a/src/b_T_1.stl b/src/b_T_1.stl
@@ -1,16 +0,0 @@
-solid shape, STL ascii file, created with Open CASCADE Technology
- facet normal -0.000000e+00 0.000000e+00 -1.000000e+00
- outer loop
- vertex 1.000000e+00 1.000000e+00 0.000000e+00
- vertex 0.000000e+00 0.000000e+00 0.000000e+00
- vertex 0.000000e+00 1.000000e+00 0.000000e+00
- endloop
- endfacet
- facet normal 0.000000e+00 -0.000000e+00 -1.000000e+00
- outer loop
- vertex 1.000000e+00 1.000000e+00 0.000000e+00
- vertex 1.000000e+00 0.000000e+00 0.000000e+00
- vertex 0.000000e+00 0.000000e+00 0.000000e+00
- endloop
- endfacet
-endsolid shape
diff --git a/src/b_T_2.stl b/src/b_T_2.stl
@@ -1,30 +0,0 @@
-solid shape, STL ascii file, created with Open CASCADE Technology
- facet normal 0.000000e+00 0.000000e+00 1.000000e+00
- outer loop
- vertex 1.000000e+00 5.000000e-01 2.000000e+00
- vertex 0.000000e+00 5.000000e-01 2.000000e+00
- vertex 0.000000e+00 0.000000e+00 2.000000e+00
- endloop
- endfacet
- facet normal 0.000000e+00 0.000000e+00 1.000000e+00
- outer loop
- vertex 1.000000e+00 5.000000e-01 2.000000e+00
- vertex 0.000000e+00 0.000000e+00 2.000000e+00
- vertex 1.000000e+00 0.000000e+00 2.000000e+00
- endloop
- endfacet
- facet normal 0.000000e+00 0.000000e+00 1.000000e+00
- outer loop
- vertex 1.000000e+00 1.000000e+00 2.000000e+00
- vertex 0.000000e+00 1.000000e+00 2.000000e+00
- vertex 0.000000e+00 5.000000e-01 2.000000e+00
- endloop
- endfacet
- facet normal 0.000000e+00 0.000000e+00 1.000000e+00
- outer loop
- vertex 1.000000e+00 1.000000e+00 2.000000e+00
- vertex 0.000000e+00 5.000000e-01 2.000000e+00
- vertex 1.000000e+00 5.000000e-01 2.000000e+00
- endloop
- endfacet
-endsolid shape
diff --git a/src/b_h_1.stl b/src/b_h_1.stl
@@ -1,156 +0,0 @@
-solid shape, STL ascii file, created with Open CASCADE Technology
- facet normal 1.000000e+00 0.000000e+00 0.000000e+00
- outer loop
- vertex 1.000000e+00 1.000000e+00 1.000000e+00
- vertex 1.000000e+00 5.000000e-01 2.000000e+00
- vertex 1.000000e+00 5.000000e-01 1.000000e+00
- endloop
- endfacet
- facet normal 1.000000e+00 0.000000e+00 -0.000000e+00
- outer loop
- vertex 1.000000e+00 1.000000e+00 1.000000e+00
- vertex 1.000000e+00 1.000000e+00 2.000000e+00
- vertex 1.000000e+00 5.000000e-01 2.000000e+00
- endloop
- endfacet
- facet normal 0.000000e+00 -1.000000e+00 0.000000e+00
- outer loop
- vertex 1.000000e+00 0.000000e+00 1.000000e+00
- vertex 1.000000e+00 0.000000e+00 2.000000e+00
- vertex 0.000000e+00 0.000000e+00 2.000000e+00
- endloop
- endfacet
- facet normal 0.000000e+00 -1.000000e+00 0.000000e+00
- outer loop
- vertex 1.000000e+00 0.000000e+00 1.000000e+00
- vertex 0.000000e+00 0.000000e+00 2.000000e+00
- vertex 0.000000e+00 0.000000e+00 1.000000e+00
- endloop
- endfacet
- facet normal 1.000000e+00 0.000000e+00 0.000000e+00
- outer loop
- vertex 1.000000e+00 5.000000e-01 1.000000e+00
- vertex 1.000000e+00 0.000000e+00 2.000000e+00
- vertex 1.000000e+00 0.000000e+00 1.000000e+00
- endloop
- endfacet
- facet normal 1.000000e+00 0.000000e+00 -0.000000e+00
- outer loop
- vertex 1.000000e+00 5.000000e-01 1.000000e+00
- vertex 1.000000e+00 5.000000e-01 2.000000e+00
- vertex 1.000000e+00 0.000000e+00 2.000000e+00
- endloop
- endfacet
- facet normal 0.000000e+00 -1.000000e+00 -0.000000e+00
- outer loop
- vertex 1.000000e+00 0.000000e+00 1.000000e+00
- vertex 0.000000e+00 0.000000e+00 0.000000e+00
- vertex 1.000000e+00 0.000000e+00 0.000000e+00
- endloop
- endfacet
- facet normal -0.000000e+00 -1.000000e+00 0.000000e+00
- outer loop
- vertex 1.000000e+00 0.000000e+00 1.000000e+00
- vertex 0.000000e+00 0.000000e+00 1.000000e+00
- vertex 0.000000e+00 0.000000e+00 0.000000e+00
- endloop
- endfacet
- facet normal 1.000000e+00 0.000000e+00 0.000000e+00
- outer loop
- vertex 1.000000e+00 5.000000e-01 1.000000e+00
- vertex 1.000000e+00 0.000000e+00 0.000000e+00
- vertex 1.000000e+00 1.000000e+00 0.000000e+00
- endloop
- endfacet
- facet normal 1.000000e+00 -0.000000e+00 0.000000e+00
- outer loop
- vertex 1.000000e+00 5.000000e-01 1.000000e+00
- vertex 1.000000e+00 1.000000e+00 0.000000e+00
- vertex 1.000000e+00 1.000000e+00 1.000000e+00
- endloop
- endfacet
- facet normal 1.000000e+00 -0.000000e+00 0.000000e+00
- outer loop
- vertex 1.000000e+00 0.000000e+00 1.000000e+00
- vertex 1.000000e+00 0.000000e+00 0.000000e+00
- vertex 1.000000e+00 5.000000e-01 1.000000e+00
- endloop
- endfacet
- facet normal -1.000000e+00 0.000000e+00 0.000000e+00
- outer loop
- vertex 0.000000e+00 1.000000e+00 1.000000e+00
- vertex 0.000000e+00 5.000000e-01 1.000000e+00
- vertex 0.000000e+00 5.000000e-01 2.000000e+00
- endloop
- endfacet
- facet normal -1.000000e+00 0.000000e+00 0.000000e+00
- outer loop
- vertex 0.000000e+00 1.000000e+00 1.000000e+00
- vertex 0.000000e+00 5.000000e-01 2.000000e+00
- vertex 0.000000e+00 1.000000e+00 2.000000e+00
- endloop
- endfacet
- facet normal -1.000000e+00 0.000000e+00 0.000000e+00
- outer loop
- vertex 0.000000e+00 5.000000e-01 1.000000e+00
- vertex 0.000000e+00 0.000000e+00 1.000000e+00
- vertex 0.000000e+00 0.000000e+00 2.000000e+00
- endloop
- endfacet
- facet normal -1.000000e+00 0.000000e+00 0.000000e+00
- outer loop
- vertex 0.000000e+00 5.000000e-01 1.000000e+00
- vertex 0.000000e+00 0.000000e+00 2.000000e+00
- vertex 0.000000e+00 5.000000e-01 2.000000e+00
- endloop
- endfacet
- facet normal -1.000000e+00 0.000000e+00 -0.000000e+00
- outer loop
- vertex 0.000000e+00 5.000000e-01 1.000000e+00
- vertex 0.000000e+00 1.000000e+00 0.000000e+00
- vertex 0.000000e+00 0.000000e+00 0.000000e+00
- endloop
- endfacet
- facet normal -1.000000e+00 0.000000e+00 0.000000e+00
- outer loop
- vertex 0.000000e+00 5.000000e-01 1.000000e+00
- vertex 0.000000e+00 1.000000e+00 1.000000e+00
- vertex 0.000000e+00 1.000000e+00 0.000000e+00
- endloop
- endfacet
- facet normal -1.000000e+00 0.000000e+00 0.000000e+00
- outer loop
- vertex 0.000000e+00 0.000000e+00 1.000000e+00
- vertex 0.000000e+00 5.000000e-01 1.000000e+00
- vertex 0.000000e+00 0.000000e+00 0.000000e+00
- endloop
- endfacet
- facet normal 0.000000e+00 1.000000e+00 0.000000e+00
- outer loop
- vertex 1.000000e+00 1.000000e+00 1.000000e+00
- vertex 1.000000e+00 1.000000e+00 0.000000e+00
- vertex 0.000000e+00 1.000000e+00 0.000000e+00
- endloop
- endfacet
- facet normal 0.000000e+00 1.000000e+00 0.000000e+00
- outer loop
- vertex 1.000000e+00 1.000000e+00 1.000000e+00
- vertex 0.000000e+00 1.000000e+00 0.000000e+00
- vertex 0.000000e+00 1.000000e+00 1.000000e+00
- endloop
- endfacet
- facet normal 0.000000e+00 1.000000e+00 -0.000000e+00
- outer loop
- vertex 1.000000e+00 1.000000e+00 1.000000e+00
- vertex 0.000000e+00 1.000000e+00 2.000000e+00
- vertex 1.000000e+00 1.000000e+00 2.000000e+00
- endloop
- endfacet
- facet normal 0.000000e+00 1.000000e+00 0.000000e+00
- outer loop
- vertex 1.000000e+00 1.000000e+00 1.000000e+00
- vertex 0.000000e+00 1.000000e+00 1.000000e+00
- vertex 0.000000e+00 1.000000e+00 2.000000e+00
- endloop
- endfacet
-endsolid shape
diff --git a/src/bc.txt b/src/bc.txt
@@ -1,5 +0,0 @@
-#STL_filename h h_coeff T_env(x,y,z,t) | STL_filename T T_value(x,y,z,t) | STL_filename F F_value(x,y,z,t)
-b_h_1.stl h 0 "300"
-#b_h_1.stl F "100"
-b_T_1.stl T "300"
-b_T_2.stl T "300"
diff --git a/src/m_1.stl b/src/m_1.stl
@@ -1,114 +0,0 @@
-solid shape, STL ascii file, created with Open CASCADE Technology
- facet normal -1.000000e+00 0.000000e+00 -0.000000e+00
- outer loop
- vertex 0.000000e+00 5.000000e-01 1.000000e+00
- vertex 0.000000e+00 1.000000e+00 0.000000e+00
- vertex 0.000000e+00 0.000000e+00 0.000000e+00
- endloop
- endfacet
- facet normal -1.000000e+00 0.000000e+00 0.000000e+00
- outer loop
- vertex 0.000000e+00 5.000000e-01 1.000000e+00
- vertex 0.000000e+00 1.000000e+00 1.000000e+00
- vertex 0.000000e+00 1.000000e+00 0.000000e+00
- endloop
- endfacet
- facet normal -1.000000e+00 0.000000e+00 0.000000e+00
- outer loop
- vertex 0.000000e+00 0.000000e+00 1.000000e+00
- vertex 0.000000e+00 5.000000e-01 1.000000e+00
- vertex 0.000000e+00 0.000000e+00 0.000000e+00
- endloop
- endfacet
- facet normal 0.000000e+00 -1.000000e+00 -0.000000e+00
- outer loop
- vertex 1.000000e+00 0.000000e+00 1.000000e+00
- vertex 0.000000e+00 0.000000e+00 0.000000e+00
- vertex 1.000000e+00 0.000000e+00 0.000000e+00
- endloop
- endfacet
- facet normal -0.000000e+00 -1.000000e+00 0.000000e+00
- outer loop
- vertex 1.000000e+00 0.000000e+00 1.000000e+00
- vertex 0.000000e+00 0.000000e+00 1.000000e+00
- vertex 0.000000e+00 0.000000e+00 0.000000e+00
- endloop
- endfacet
- facet normal -0.000000e+00 0.000000e+00 -1.000000e+00
- outer loop
- vertex 1.000000e+00 1.000000e+00 0.000000e+00
- vertex 0.000000e+00 0.000000e+00 0.000000e+00
- vertex 0.000000e+00 1.000000e+00 0.000000e+00
- endloop
- endfacet
- facet normal 0.000000e+00 -0.000000e+00 -1.000000e+00
- outer loop
- vertex 1.000000e+00 1.000000e+00 0.000000e+00
- vertex 1.000000e+00 0.000000e+00 0.000000e+00
- vertex 0.000000e+00 0.000000e+00 0.000000e+00
- endloop
- endfacet
- facet normal 0.000000e+00 0.000000e+00 1.000000e+00
- outer loop
- vertex 1.000000e+00 5.000000e-01 1.000000e+00
- vertex 0.000000e+00 5.000000e-01 1.000000e+00
- vertex 0.000000e+00 0.000000e+00 1.000000e+00
- endloop
- endfacet
- facet normal 0.000000e+00 0.000000e+00 1.000000e+00
- outer loop
- vertex 1.000000e+00 5.000000e-01 1.000000e+00
- vertex 0.000000e+00 0.000000e+00 1.000000e+00
- vertex 1.000000e+00 0.000000e+00 1.000000e+00
- endloop
- endfacet
- facet normal 0.000000e+00 1.000000e+00 0.000000e+00
- outer loop
- vertex 1.000000e+00 1.000000e+00 1.000000e+00
- vertex 1.000000e+00 1.000000e+00 0.000000e+00
- vertex 0.000000e+00 1.000000e+00 0.000000e+00
- endloop
- endfacet
- facet normal 0.000000e+00 1.000000e+00 0.000000e+00
- outer loop
- vertex 1.000000e+00 1.000000e+00 1.000000e+00
- vertex 0.000000e+00 1.000000e+00 0.000000e+00
- vertex 0.000000e+00 1.000000e+00 1.000000e+00
- endloop
- endfacet
- facet normal 0.000000e+00 0.000000e+00 1.000000e+00
- outer loop
- vertex 1.000000e+00 1.000000e+00 1.000000e+00
- vertex 0.000000e+00 1.000000e+00 1.000000e+00
- vertex 0.000000e+00 5.000000e-01 1.000000e+00
- endloop
- endfacet
- facet normal 0.000000e+00 0.000000e+00 1.000000e+00
- outer loop
- vertex 1.000000e+00 1.000000e+00 1.000000e+00
- vertex 0.000000e+00 5.000000e-01 1.000000e+00
- vertex 1.000000e+00 5.000000e-01 1.000000e+00
- endloop
- endfacet
- facet normal 1.000000e+00 0.000000e+00 0.000000e+00
- outer loop
- vertex 1.000000e+00 5.000000e-01 1.000000e+00
- vertex 1.000000e+00 0.000000e+00 0.000000e+00
- vertex 1.000000e+00 1.000000e+00 0.000000e+00
- endloop
- endfacet
- facet normal 1.000000e+00 -0.000000e+00 0.000000e+00
- outer loop
- vertex 1.000000e+00 5.000000e-01 1.000000e+00
- vertex 1.000000e+00 1.000000e+00 0.000000e+00
- vertex 1.000000e+00 1.000000e+00 1.000000e+00
- endloop
- endfacet
- facet normal 1.000000e+00 -0.000000e+00 0.000000e+00
- outer loop
- vertex 1.000000e+00 0.000000e+00 1.000000e+00
- vertex 1.000000e+00 0.000000e+00 0.000000e+00
- vertex 1.000000e+00 5.000000e-01 1.000000e+00
- endloop
- endfacet
-endsolid shape
diff --git a/src/m_2.stl b/src/m_2.stl
@@ -1,86 +0,0 @@
-solid shape, STL ascii file, created with Open CASCADE Technology
- facet normal -1.000000e+00 0.000000e+00 0.000000e+00
- outer loop
- vertex 0.000000e+00 5.000000e-01 1.000000e+00
- vertex 0.000000e+00 0.000000e+00 1.000000e+00
- vertex 0.000000e+00 0.000000e+00 2.000000e+00
- endloop
- endfacet
- facet normal -1.000000e+00 0.000000e+00 0.000000e+00
- outer loop
- vertex 0.000000e+00 5.000000e-01 1.000000e+00
- vertex 0.000000e+00 0.000000e+00 2.000000e+00
- vertex 0.000000e+00 5.000000e-01 2.000000e+00
- endloop
- endfacet
- facet normal 0.000000e+00 -1.000000e+00 0.000000e+00
- outer loop
- vertex 1.000000e+00 0.000000e+00 1.000000e+00
- vertex 1.000000e+00 0.000000e+00 2.000000e+00
- vertex 0.000000e+00 0.000000e+00 2.000000e+00
- endloop
- endfacet
- facet normal 0.000000e+00 -1.000000e+00 0.000000e+00
- outer loop
- vertex 1.000000e+00 0.000000e+00 1.000000e+00
- vertex 0.000000e+00 0.000000e+00 2.000000e+00
- vertex 0.000000e+00 0.000000e+00 1.000000e+00
- endloop
- endfacet
- facet normal -0.000000e+00 0.000000e+00 -1.000000e+00
- outer loop
- vertex 1.000000e+00 5.000000e-01 1.000000e+00
- vertex 0.000000e+00 0.000000e+00 1.000000e+00
- vertex 0.000000e+00 5.000000e-01 1.000000e+00
- endloop
- endfacet
- facet normal 0.000000e+00 -0.000000e+00 -1.000000e+00
- outer loop
- vertex 1.000000e+00 5.000000e-01 1.000000e+00
- vertex 1.000000e+00 0.000000e+00 1.000000e+00
- vertex 0.000000e+00 0.000000e+00 1.000000e+00
- endloop
- endfacet
- facet normal 0.000000e+00 0.000000e+00 1.000000e+00
- outer loop
- vertex 1.000000e+00 5.000000e-01 2.000000e+00
- vertex 0.000000e+00 5.000000e-01 2.000000e+00
- vertex 0.000000e+00 0.000000e+00 2.000000e+00
- endloop
- endfacet
- facet normal 0.000000e+00 0.000000e+00 1.000000e+00
- outer loop
- vertex 1.000000e+00 5.000000e-01 2.000000e+00
- vertex 0.000000e+00 0.000000e+00 2.000000e+00
- vertex 1.000000e+00 0.000000e+00 2.000000e+00
- endloop
- endfacet
- facet normal 0.000000e+00 1.000000e+00 0.000000e+00
- outer loop
- vertex 0.000000e+00 5.000000e-01 1.000000e+00
- vertex 1.000000e+00 5.000000e-01 2.000000e+00
- vertex 1.000000e+00 5.000000e-01 1.000000e+00
- endloop
- endfacet
- facet normal 0.000000e+00 1.000000e+00 0.000000e+00
- outer loop
- vertex 0.000000e+00 5.000000e-01 1.000000e+00
- vertex 0.000000e+00 5.000000e-01 2.000000e+00
- vertex 1.000000e+00 5.000000e-01 2.000000e+00
- endloop
- endfacet
- facet normal 1.000000e+00 0.000000e+00 0.000000e+00
- outer loop
- vertex 1.000000e+00 5.000000e-01 1.000000e+00
- vertex 1.000000e+00 0.000000e+00 2.000000e+00
- vertex 1.000000e+00 0.000000e+00 1.000000e+00
- endloop
- endfacet
- facet normal 1.000000e+00 0.000000e+00 -0.000000e+00
- outer loop
- vertex 1.000000e+00 5.000000e-01 1.000000e+00
- vertex 1.000000e+00 5.000000e-01 2.000000e+00
- vertex 1.000000e+00 0.000000e+00 2.000000e+00
- endloop
- endfacet
-endsolid shape
diff --git a/src/m_3.stl b/src/m_3.stl
@@ -1,86 +0,0 @@
-solid shape, STL ascii file, created with Open CASCADE Technology
- facet normal -1.000000e+00 0.000000e+00 0.000000e+00
- outer loop
- vertex 0.000000e+00 1.000000e+00 1.000000e+00
- vertex 0.000000e+00 5.000000e-01 1.000000e+00
- vertex 0.000000e+00 5.000000e-01 2.000000e+00
- endloop
- endfacet
- facet normal -1.000000e+00 0.000000e+00 0.000000e+00
- outer loop
- vertex 0.000000e+00 1.000000e+00 1.000000e+00
- vertex 0.000000e+00 5.000000e-01 2.000000e+00
- vertex 0.000000e+00 1.000000e+00 2.000000e+00
- endloop
- endfacet
- facet normal 0.000000e+00 -1.000000e+00 0.000000e+00
- outer loop
- vertex 0.000000e+00 5.000000e-01 1.000000e+00
- vertex 1.000000e+00 5.000000e-01 1.000000e+00
- vertex 1.000000e+00 5.000000e-01 2.000000e+00
- endloop
- endfacet
- facet normal 0.000000e+00 -1.000000e+00 0.000000e+00
- outer loop
- vertex 0.000000e+00 5.000000e-01 1.000000e+00
- vertex 1.000000e+00 5.000000e-01 2.000000e+00
- vertex 0.000000e+00 5.000000e-01 2.000000e+00
- endloop
- endfacet
- facet normal -0.000000e+00 0.000000e+00 -1.000000e+00
- outer loop
- vertex 1.000000e+00 1.000000e+00 1.000000e+00
- vertex 0.000000e+00 5.000000e-01 1.000000e+00
- vertex 0.000000e+00 1.000000e+00 1.000000e+00
- endloop
- endfacet
- facet normal 0.000000e+00 -0.000000e+00 -1.000000e+00
- outer loop
- vertex 1.000000e+00 1.000000e+00 1.000000e+00
- vertex 1.000000e+00 5.000000e-01 1.000000e+00
- vertex 0.000000e+00 5.000000e-01 1.000000e+00
- endloop
- endfacet
- facet normal 0.000000e+00 0.000000e+00 1.000000e+00
- outer loop
- vertex 1.000000e+00 1.000000e+00 2.000000e+00
- vertex 0.000000e+00 1.000000e+00 2.000000e+00
- vertex 0.000000e+00 5.000000e-01 2.000000e+00
- endloop
- endfacet
- facet normal 0.000000e+00 0.000000e+00 1.000000e+00
- outer loop
- vertex 1.000000e+00 1.000000e+00 2.000000e+00
- vertex 0.000000e+00 5.000000e-01 2.000000e+00
- vertex 1.000000e+00 5.000000e-01 2.000000e+00
- endloop
- endfacet
- facet normal 0.000000e+00 1.000000e+00 -0.000000e+00
- outer loop
- vertex 1.000000e+00 1.000000e+00 1.000000e+00
- vertex 0.000000e+00 1.000000e+00 2.000000e+00
- vertex 1.000000e+00 1.000000e+00 2.000000e+00
- endloop
- endfacet
- facet normal 0.000000e+00 1.000000e+00 0.000000e+00
- outer loop
- vertex 1.000000e+00 1.000000e+00 1.000000e+00
- vertex 0.000000e+00 1.000000e+00 1.000000e+00
- vertex 0.000000e+00 1.000000e+00 2.000000e+00
- endloop
- endfacet
- facet normal 1.000000e+00 0.000000e+00 0.000000e+00
- outer loop
- vertex 1.000000e+00 1.000000e+00 1.000000e+00
- vertex 1.000000e+00 5.000000e-01 2.000000e+00
- vertex 1.000000e+00 5.000000e-01 1.000000e+00
- endloop
- endfacet
- facet normal 1.000000e+00 0.000000e+00 -0.000000e+00
- outer loop
- vertex 1.000000e+00 1.000000e+00 1.000000e+00
- vertex 1.000000e+00 1.000000e+00 2.000000e+00
- vertex 1.000000e+00 5.000000e-01 2.000000e+00
- endloop
- endfacet
-endsolid shape
diff --git a/src/main.c b/src/main.c
@@ -1,48 +0,0 @@
-/* Copyright (C) 2018 |Meso|Star> (contact@meso-star.com) */
-
-#include "stardis-app.h"
-
-int main(int argc, char** argv){
-
- struct args args = ARGS_DEFAULT;
- struct stardis stardis = NULL_STARDIS;
- size_t memsz = 0;
- int err = 0;
- res_T res = RES_OK;
-
- /* Check proper init for ARGS_DEFAULT */
- ASSERT(ARGS_DEFAULT.u.probe[3] == INF);
-
- res = parse_args(argc, argv, &args);
- if (res != RES_OK) goto error;
- if (args.just_help) goto exit;
-
- res = stardis_init(&args, &stardis);
- if (res != RES_OK) goto error;
-
- if (args.mode & DUMP_VTK) {
- res = dump_vtk(stdout, &stardis.geometry);
- if (res != RES_OK) goto error;
- goto exit;
- }
-
- res = stardis_compute(&stardis, args.mode);
- if (res != RES_OK) goto error;
-
-exit:
- stardis_release(&stardis);
- if(stardis.allocator_initialized
- && (memsz = MEM_ALLOCATED_SIZE(&stardis.allocator)) != 0)
- {
- char dump[4096] = { '\0' };
- MEM_DUMP(&stardis.allocator, dump, sizeof(dump));
- fprintf(stderr, "%s\n", dump);
- fprintf(stderr, "Memory leaks: %lu Bytes\n", (unsigned long)memsz);
- }
- mem_shutdown_proxy_allocator(&stardis.allocator);
- CHK(mem_allocated_size() == 0);
- return err;
-error:
- err = -1;
- goto exit;
-}
diff --git a/src/material.txt b/src/material.txt
@@ -1,4 +0,0 @@
-#STL_filename lambda rho cp delta emissivity specular_fraction Tinit(x,y,z) volumic_power(x,y,z,t)
-m_1.stl 1.0 1.0 1.0 0.05 1.0 0.0 "300" "0"
-m_2.stl 1.0 1.0 1.0 0.05 1.0 0.0 "300" "0"
-m_3.stl 1.0 1.0 1.0 0.05 1.0 0.0 "300" "0"
diff --git a/src/stardis-app.c b/src/stardis-app.c
@@ -1,1032 +1,608 @@
-/* Copyright (C) 2018 |Meso|Star> (contact@meso-star.com) */
+/* Copyright (C) 2018-2020 |Meso|Star> (contact@meso-star.com)
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>. */
-#define _GNU_SOURCE 1
-#include <string.h>
-#include <ctype.h>
#include "stardis-app.h"
+#include "stardis-output.h"
+#include "stardis-compute.h"
+#include "stardis-intface.h"
+#include "stardis-fluid.h"
+#include "stardis-solid.h"
+
+#include <star/senc3d.h>
+#include <star/sg3d_sencXd_helper.h>
+#include <star/sg3d_sdisXd_helper.h>
+
+#include <rsys/str.h>
+#include <rsys/text_reader.h>
+#include <rsys/logger.h>
+#include <rsys/double2.h>
+#include <rsys/double3.h>
+#include <string.h>
-#include <rsys/hash_table.h>
-#define HTABLE_NAME descriptions
-#define HTABLE_KEY struct description
-#define HTABLE_DATA unsigned
-#define HTABLE_KEY_FUNCTOR_EQ eq_description
-#define HTABLE_KEY_FUNCTOR_HASH hash_description
-#include <rsys/hash_table.h>
+static const struct dummies DUMMIES_NULL = DUMMIES_NULL__;
+
+static const struct counts COUNTS_NULL = COUNTS_NULL__;
/*******************************************************************************
- *
+ * Local Functions
******************************************************************************/
-static INLINE char*
-read_line(char** pb, FILE* stream)
-{
- const int chunk_sz = 32;
- char* buf = *pb;
- size_t idx;
-
- if(!buf) buf = sa_add(buf, 128);
-
- do {
- /* Read stream until EOL, EOF or up to sa_size(b) */
- if(!fgets(buf, (int)sa_size(buf) + 1, stream)) return NULL;
-
- /* Ensure that he whole line is read */
- while(!strrchr(buf, '\n') && !feof(stream)) {
- /* Add some room to buffer */
- char* more = sa_add(buf, (size_t)chunk_sz);
- /* Continue reading chunk_sz more characters until EOL or EOF */
- fgets(more, chunk_sz + 1, stream);
- }
- /* Search idx of first occurence of comment char or EOL */
- idx = strcspn(buf, "#\n\r");
- /* Remove meaningless text */
- buf[idx] = '\0';
- /* Find first text */
- idx = strspn(buf, " \t");
- } while(buf[idx] == '\0'); /* Skip empty lines */
- *pb = buf;
- return buf;
-}
-
-static char** split_line(char* a_str, const char a_delim)
-{
- char** result = 0;
- size_t count = 0;
- char* tmp = a_str;
- char* last_comma = 0;
- char delim[2];
- delim[0] = a_delim;
- delim[1] = 0;
-
- /* Count how many elements will be extracted. */
- while (*tmp)
- {
- if (a_delim == *tmp)
- {
- count++;
- last_comma = tmp;
- }
- tmp++;
- }
-
- /* Add space for trailing token. */
- count += last_comma < (a_str + strlen(a_str) - 1);
-
- /* Add space for terminating null string so caller
- knows where the list of returned strings ends. */
- count++;
-
- result = malloc(sizeof(char*) * count);
-
- if (result)
- {
- size_t idx = 0;
- char* token = strtok(a_str, delim);
-
- while (token)
- {
- ASSERT(idx < count);
-#ifdef COMPILER_CL
- *(result + idx++) = _strdup(token);
-#else
- *(result + idx++) = strdup(token);
-#endif
- token = strtok(0, delim);
- }
- ASSERT(idx == count - 1);
- *(result + idx) = 0;
- }
-
- return result;
-}
-
-#ifdef COMPILER_GCC
-static char*
-_strupr(char* s)
-{
- char* ptr;
- for (ptr = s; *ptr; ++ptr) {
- int tmp = toupper(*ptr);
- ASSERT(tmp == (char)tmp);
- *ptr = (char)tmp;
- }
- return s;
-}
-#endif
-
-
-/* Read medium line; should be one of:
- * SOLID medium_name STL_filename lambda rho cp delta "Tinit(x,y,z)" [ "volumic_power(x,y,z,t)" ]
- * FLUID medium_name STL_filename rho cp "Tinit(x,y,z)"
-*/
static res_T
-parse_medium_line(char* line, char** stl_filename, struct description* desc)
+read_model
+ (const struct darray_str* model_files,
+ struct stardis* stardis,
+ struct dummies* dummies)
{
- char* tk = NULL;
res_T res = RES_OK;
-
-#define CHK_TOK(x, Name) if ((tk = (x)) == NULL) {\
- fprintf(stderr, "Invalid data (missing token " Name ")\n");\
- res = RES_BAD_ARG;\
- goto exit;\
- } (void)0
- CHK_TOK(_strupr(strtok(line, " ")), "medium type");
- if (strcmp(tk, "SOLID") == 0) {
- desc->type = DESC_MAT_SOLID;
- desc->d.solid = NULL_SOLID;
-
- CHK_TOK(strtok(NULL, " "), "medium name");
- if (strlen(tk) >= sizeof(desc->d.solid.name)) {
- fprintf(stderr, "Medium name is too long: %s\n", tk);
- res = RES_BAD_ARG;
- goto exit;
- }
- strncpy(desc->d.solid.name, tk, sizeof(desc->d.solid.name));
-
- CHK_TOK(strtok(NULL, " "), "file name");
- *stl_filename = malloc(strlen(tk) + 1);
- strcpy(*stl_filename, tk);
-
- CHK_TOK(strtok(NULL, " "), "lambda");
- res = cstr_to_double(tk, &desc->d.solid.lambda);
- if (res != RES_OK || desc->d.solid.lambda <= 0) {
- fprintf(stderr, "Invalid lambda: %s\n", tk);
- res = RES_BAD_ARG;
- goto exit;
- }
- CHK_TOK(strtok(NULL, " "), "rho");
- res = cstr_to_double(tk, &desc->d.solid.rho);
- if (res != RES_OK || desc->d.solid.rho <= 0) {
- fprintf(stderr, "Invalid rho: %s\n", tk);
- res = RES_BAD_ARG;
- goto exit;
- }
- CHK_TOK(strtok(NULL, " "), "cp");
- res = cstr_to_double(tk, &desc->d.solid.cp);
- if (res != RES_OK || desc->d.solid.cp <= 0) {
- fprintf(stderr, "Invalid cp: %s\n", tk);
- res = RES_BAD_ARG;
- goto exit;
- }
- CHK_TOK(strtok(NULL, " "), "delta");
- res = cstr_to_double(tk, &desc->d.solid.delta);
- if (res != RES_OK || desc->d.solid.delta <= 0) {
- fprintf(stderr, "Invalid delta: %s\n", tk);
- res = RES_BAD_ARG;
- goto exit;
- }
- /* Depending of the number of spaces before '"' strtok should
- * be called once or twice */
- CHK_TOK(strtok(NULL, "\""), "Tinit");
- if (*(tk + strspn(tk, " \t")) == '\0') {
- CHK_TOK(strtok(NULL, "\""), "Tinit");
- }
- desc->d.solid.Tinit = malloc(strlen(tk) + 1);
- strcpy(desc->d.solid.Tinit, tk);
- /* Closing " fot Tinit; can return NULL if line ends just after "Tinit" */
- tk = strtok(NULL, "\"");
-
- /* Volumic Power is optional */
- if (tk && *(tk + strspn(tk, " \t")) == '\0') {
- /* Depending of the number of spaces before '"' strtok should
- * be called once or twice */
- tk = strtok(NULL, "\"");
- }
- if (tk) {
- desc->d.solid.power = malloc(strlen(tk) + 1);
- strcpy(desc->d.solid.power, tk);
- /* Can be changed aftwerwards if compiled to constant 0 */
- desc->d.solid.has_power = 1;
- }
- }
- else if (strcmp(tk, "FLUID") == 0) {
- desc->type = DESC_MAT_FLUID;
- desc->d.fluid = NULL_FLUID;
-
- CHK_TOK(strtok(NULL, " "), "medium name");
- if (strlen(tk) >= sizeof(desc->d.fluid.name)) {
- fprintf(stderr, "Medium name is too long: %s\n", tk);
- res = RES_BAD_ARG;
- goto exit;
- }
- strncpy(desc->d.fluid.name, tk, sizeof(desc->d.fluid.name));
-
- CHK_TOK(strtok(NULL, " "), "file name");
- *stl_filename = malloc(strlen(tk) + 1);
- strcpy(*stl_filename, tk);
-
- CHK_TOK(strtok(NULL, " "), "rho");
- res = cstr_to_double(tk, &desc->d.fluid.rho);
- if (res != RES_OK || desc->d.fluid.rho <= 0) {
- fprintf(stderr, "Invalid rho: %s\n", tk);
- res = RES_BAD_ARG;
- goto exit;
- }
- CHK_TOK(strtok(NULL, " "), "cp");
- res = cstr_to_double(tk, &desc->d.fluid.cp);
- if (res != RES_OK || desc->d.fluid.cp <= 0) {
- fprintf(stderr, "Invalid cp: %s\n", tk);
- res = RES_BAD_ARG;
- goto exit;
- }
- /* Depending of the number of spaces before '"' strtok should
- * be called once or twice */
- CHK_TOK(strtok(NULL, "\""), "Tinit");
- if (*(tk + strspn(tk, " \t")) == '\0') {
- CHK_TOK(strtok(NULL, "\""), "Tinit");
- }
- desc->d.fluid.Tinit = malloc(strlen(tk) + 1);
- strcpy(desc->d.fluid.Tinit, tk);
- }
- else {
- res = RES_BAD_ARG;
- fprintf(stderr, "Invalid medium type: %s\n", tk);
- }
-
-#undef CHK_TOK
+ const struct str* files = NULL;
+ size_t i;
+ FILE* f = NULL;
+ struct txtrdr* txtrdr = NULL;
+
+ ASSERT(model_files && stardis && dummies);
+ files = darray_str_cdata_get(model_files);
+ FOR_EACH(i, 0, darray_str_size_get(model_files)) {
+ const char* name = str_cget(files + i);
+ f = fopen(name, "r");
+ if(!f) {
+ logger_print(stardis->logger, LOG_ERROR,
+ "Cannot open model file '%s'\n",
+ name);
+ res = RES_IO_ERR;
+ goto error;
+ }
+ txtrdr_stream(stardis->allocator, f, name, '#', &txtrdr);
+ for(;;) {
+ char* line;
+ ERR(txtrdr_read_line(txtrdr));
+ line = txtrdr_get_line(txtrdr);
+ if(!line) break;
+ ERR(process_model_line(name, line, stardis, dummies));
+ }
+ txtrdr_ref_put(txtrdr);
+ txtrdr = NULL;
+ fclose(f);
+ f = NULL;
+ }
+ if(stardis->scale_factor <= 0)
+ stardis->scale_factor = STARDIS_DEFAULT_SCALE_FACTOR;
+ logger_print(stardis->logger, LOG_OUTPUT,
+ "Scaling factor is %g\n", stardis->scale_factor);
+
+ ASSERT(!f && !txtrdr);
exit:
return res;
+error:
+ if(f) fclose(f);
+ if(txtrdr) txtrdr_ref_put(txtrdr);
+ goto exit;
}
-/* Read boundary line; should be one of:
-# H_BOUNDARY_FOR_SOLID Boundary_name STL_filename emissivity specular_fraction hc hc_max "T_env(x,y,z,t)"
-# | H_BOUNDARY_FOR_FLUID Boundary_name STL_filename emissivity specular_fraction hc hc_max "T_env(x,y,z,t)"
-# | T_BOUNDARY_FOR_SOLID Boundary_name STL_filename "T_value(x,y,z,t)"
-# | T_BOUNDARY_FOR_FLUID Boundary_name STL_filename "T_value(x,y,z,t)" hc hc_max
-# | F_BOUNDARY_FOR_SOLID Boundary_name STL_filename "F_value(x,y,z,t)"
-# ; no F_BOUNDARY_FOR_FLUID
-# | SOLID_FLUID_CONNECTION Connection_name STL_filename emissivity specular_fraction hc hc_max
- */
-static res_T
-parse_boundary_line(char* line, char** stl_filename, struct description* desc)
+static struct sdis_interface*
+geometry_get_interface
+ (const size_t itri, void* ctx)
{
- char* tk = NULL;
- int h_solid = 0, h_fluid = 0;
- int t_solid = 0, t_fluid = 0;
- int f_solid = 0;
- int sf_connect = 0;
- res_T res = RES_OK;
-
-#define CHK_TOK(x, Name) if ((tk = (x)) == NULL) {\
- fprintf(stderr, "Invalid data (missing token " Name ")\n");\
- res = RES_BAD_ARG;\
- goto exit;\
- } (void)0
- CHK_TOK(strtok(line, " "), "boundary type");
- h_solid = (0 == strcmp(tk, "H_BOUNDARY_FOR_SOLID"));
- if (!h_solid) {
- h_fluid = (0 == strcmp(tk, "H_BOUNDARY_FOR_FLUID"));
- if (!h_fluid) {
- t_solid = (0 == strcmp(tk, "T_BOUNDARY_FOR_SOLID"));
- if (!t_solid) {
- t_fluid = (0 == strcmp(tk, "T_BOUNDARY_FOR_FLUID"));
- if (!t_fluid) {
- f_solid = (0 == strcmp(tk, "F_BOUNDARY_FOR_SOLID"));
- if (!f_solid) {
- sf_connect = (0 == strcmp(tk, "SOLID_FLUID_CONNECTION"));
- }
- }
- }
- }
- }
-
- if (h_solid || h_fluid) {
- desc->type = h_solid ? DESC_BOUND_H_FOR_SOLID : DESC_BOUND_H_FOR_FLUID;
- desc->d.h_boundary = NULL_HBOUND;
-
- CHK_TOK(strtok(NULL, " "), "boundary name");
- if (strlen(tk) >= sizeof(desc->d.h_boundary.name)) {
- fprintf(stderr, "Boundary name is too long: %s\n", tk);
- res = RES_BAD_ARG;
- goto exit;
- }
- strncpy(desc->d.h_boundary.name, tk, sizeof(desc->d.h_boundary.name));
-
- /* The description is parsed the same way for both types */
- CHK_TOK(strtok(NULL, " "), "file name");
- *stl_filename = malloc(strlen(tk) + 1);
- strcpy(*stl_filename, tk);
-
- CHK_TOK(strtok(NULL, " "), "emissivity");
- res = cstr_to_double(tk, &desc->d.h_boundary.emissivity);
- if (res != RES_OK ||
- desc->d.h_boundary.emissivity < 0 || desc->d.h_boundary.emissivity > 1) {
- fprintf(stderr, "Invalid emissivity: %s\n", tk);
- res = RES_BAD_ARG;
- goto exit;
- }
- desc->d.h_boundary.has_emissivity = (desc->d.h_boundary.emissivity > 0);
- CHK_TOK(strtok(NULL, " "), "specular fraction");
- res = cstr_to_double(tk, &desc->d.h_boundary.specular_fraction);
- if (res != RES_OK
- || desc->d.h_boundary.specular_fraction < 0.0
- || desc->d.h_boundary.specular_fraction > 1.0) {
- fprintf(stderr, "Invalid specular_fraction: %s\n", tk);
- res = RES_BAD_ARG;
- goto exit;
- }
- CHK_TOK(strtok(NULL, " "), "hc");
- res = cstr_to_double(tk, &desc->d.h_boundary.hc);
- if (res != RES_OK || desc->d.h_boundary.hc < 0) {
- fprintf(stderr, "Invalid hc value: %s\n", tk);
- res = RES_BAD_ARG;
- goto exit;
- }
- desc->d.h_boundary.has_hc = (desc->d.h_boundary.hc > 0);
- CHK_TOK(strtok(NULL, " "), "hc max");
- res = cstr_to_double(tk, &desc->d.h_boundary.hc_max);
- if (res != RES_OK
- || desc->d.h_boundary.hc_max < desc->d.h_boundary.hc
- || desc->d.h_boundary.hc_max < 0) {
- fprintf(stderr, "Invalid hc_max value: %s\n", tk);
- res = RES_BAD_ARG;
- goto exit;
- }
- /* Depending of the number of spaces before '"' strtok should
- * be called once or twice */
- CHK_TOK(strtok(NULL, "\""), "temperature");
- if (*(tk + strspn(tk, " \t")) == '\0') {
- CHK_TOK(strtok(NULL, "\""), "temperature");
- }
- desc->d.h_boundary.T = malloc(strlen(tk) + 1);
- strcpy(desc->d.h_boundary.T, tk);
- }
- else if (t_solid || t_fluid) {
- desc->type = t_solid ? DESC_BOUND_T_FOR_SOLID : DESC_BOUND_T_FOR_FLUID;
- desc->d.t_boundary = NULL_TBOUND;
-
- CHK_TOK(strtok(NULL, " "), "boundary name");
- if (strlen(tk) >= sizeof(desc->d.t_boundary.name)) {
- fprintf(stderr, "Boundary name is too long: %s\n", tk);
- res = RES_BAD_ARG;
- goto exit;
- }
- strncpy(desc->d.t_boundary.name, tk, sizeof(desc->d.t_boundary.name));
-
- /* This part of the description is parsed the same way for both types */
- CHK_TOK(strtok(NULL, " "), "file name");
- *stl_filename = malloc(strlen(tk) + 1);
- strcpy(*stl_filename, tk);
-
- /* Depending of the number of spaces before '"' strtok should
- * be called once or twice */
- CHK_TOK(strtok(NULL, "\""), "temperature");
- if (*(tk + strspn(tk, " \t")) == '\0') {
- CHK_TOK(strtok(NULL, "\""), "temperature");
- }
- desc->d.t_boundary.T = malloc(strlen(tk) + 1);
- strcpy(desc->d.t_boundary.T, tk);
-
- /* Parse hc + hc_max only if fluid */
- if (t_fluid) {
- CHK_TOK(strtok(NULL, " "), "hc");
- res = cstr_to_double(tk, &desc->d.t_boundary.hc);
- if (res != RES_OK || desc->d.t_boundary.hc < 0) {
- fprintf(stderr, "Invalid hc value: %s\n", tk);
- res = RES_BAD_ARG;
- goto exit;
- }
- desc->d.t_boundary.has_hc = (desc->d.t_boundary.hc > 0);
- CHK_TOK(strtok(NULL, " "), "hc max");
- res = cstr_to_double(tk, &desc->d.t_boundary.hc_max);
- if (res != RES_OK
- || desc->d.t_boundary.hc_max < desc->d.t_boundary.hc
- || desc->d.t_boundary.hc_max < 0) {
- fprintf(stderr, "Invalid hc_max value: %s\n", tk);
- res = RES_BAD_ARG;
- goto exit;
- }
- }
- else desc->d.t_boundary.has_hc = 0;
- }
- else if (f_solid) {
- desc->type = DESC_BOUND_F_FOR_SOLID;
- desc->d.f_boundary = NULL_FBOUND;
-
- CHK_TOK(strtok(NULL, " "), "boundary name");
- if (strlen(tk) >= sizeof(desc->d.f_boundary.name)) {
- fprintf(stderr, "Boundary name is too long: %s\n", tk);
- res = RES_BAD_ARG;
- goto exit;
- }
- strncpy(desc->d.f_boundary.name, tk, sizeof(desc->d.f_boundary.name));
-
- CHK_TOK(strtok(NULL, " "), "file name");
- *stl_filename = malloc(strlen(tk) + 1);
- strcpy(*stl_filename, tk);
-
- /* Depending of the number of spaces before '"' strtok should
- * be called once or twice */
- CHK_TOK(strtok(NULL, "\""), "flux");
- if (*(tk + strspn(tk, " \t")) == '\0') {
- CHK_TOK(strtok(NULL, "\""), "flux");
- }
- desc->d.f_boundary.flux = malloc(strlen(tk) + 1);
- strcpy(desc->d.f_boundary.flux, tk);
- }
- else if (sf_connect) {
- desc->type = DESC_SOLID_FLUID_CONNECT;
- desc->d.sf_connect = NULL_SFCONNECT;
-
- CHK_TOK(strtok(NULL, " "), "boundary name");
- if (strlen(tk) >= sizeof(desc->d.sf_connect.name)) {
- fprintf(stderr, "Boundary name is too long: %s\n", tk);
- res = RES_BAD_ARG;
- goto exit;
- }
- strncpy(desc->d.sf_connect.name, tk, sizeof(desc->d.sf_connect.name));
-
- CHK_TOK(strtok(NULL, " "), "file name");
- *stl_filename = malloc(strlen(tk) + 1);
- strcpy(*stl_filename, tk);
-
- CHK_TOK(strtok(NULL, " "), "emissivity");
- res = cstr_to_double(tk, &desc->d.sf_connect.emissivity);
- if (res != RES_OK ||
- desc->d.sf_connect.emissivity < 0 || desc->d.sf_connect.emissivity > 1) {
- fprintf(stderr, "Invalid emissivity: %s\n", tk);
- res = RES_BAD_ARG;
- goto exit;
- }
- desc->d.sf_connect.has_emissivity = (desc->d.sf_connect.emissivity > 0);
- CHK_TOK(strtok(NULL, " "), "specular fraction");
- res = cstr_to_double(tk, &desc->d.sf_connect.specular_fraction);
- if (res != RES_OK
- || desc->d.sf_connect.specular_fraction < 0.0
- || desc->d.sf_connect.specular_fraction > 1.0) {
- fprintf(stderr, "Invalid specular_fraction: %s\n", tk);
- res = RES_BAD_ARG;
- goto exit;
- }
- CHK_TOK(strtok(NULL, " "), "hc");
- res = cstr_to_double(tk, &desc->d.sf_connect.hc);
- if (res != RES_OK || desc->d.sf_connect.hc < 0) {
- fprintf(stderr, "Invalid hc value: %s\n", tk);
- res = RES_BAD_ARG;
- goto exit;
- }
- desc->d.sf_connect.has_hc = (desc->d.sf_connect.hc > 0);
- CHK_TOK(strtok(NULL, " "), "hc max");
- res = cstr_to_double(tk, &desc->d.h_boundary.hc_max);
- if (res != RES_OK
- || desc->d.h_boundary.hc_max < desc->d.h_boundary.hc
- || desc->d.h_boundary.hc_max < 0) {
- fprintf(stderr, "Invalid hc_max value: %s\n", tk);
- res = RES_BAD_ARG;
- goto exit;
- }
- } else {
- fprintf(stderr, "Invalid boundary type: %s", tk);
- res = RES_BAD_ARG;
- goto exit;
- }
-
-#undef CHK_TOK
-exit:
- return res;
+ struct darray_interface_ptrs* app_interface_data = ctx;
+ ASSERT(app_interface_data
+ && itri < darray_interface_ptrs_size_get(app_interface_data));
+ return darray_interface_ptrs_cdata_get(app_interface_data)[itri];
}
static res_T
-read_vertices
- (struct sstl_desc* desc,
- struct htable_vertex* vertex2id,
- unsigned** id2id,
- struct geometry* geometry)
+check_delta_and_create_solid
+ (struct stardis* stardis,
+ struct description* description)
{
res_T res = RES_OK;
- unsigned vtx_index = 0;
-
- for (vtx_index = 0; vtx_index < desc->vertices_count; ++vtx_index){
- struct vertex vtx = NULL_VERTEX;
- unsigned *found_id = NULL;
-
- vtx.xyz[0] = desc->vertices[3*vtx_index + 0];
- vtx.xyz[1] = desc->vertices[3*vtx_index + 1];
- vtx.xyz[2] = desc->vertices[3*vtx_index + 2];
- found_id = htable_vertex_find(vertex2id, &vtx);
-
- if (found_id){
- sa_push(*id2id, *found_id);
+ struct senc3d_enclosure* enc = NULL;
+ double ratio, delta_range[2] = { DBL_MAX, -DBL_MAX };
+ const double acceptance_ratio = 3;
+ struct senc3d_enclosure_header header;
+
+ ASSERT(stardis && description && description->type == DESC_MAT_SOLID);
+
+ /* Create solid to have ID informed */
+ /* Check if delta can fit possible multiple enclosures */
+ if(stardis->senc3d_scn) {
+ /* Due to previous errors, senc3d_scn can be unavailable */
+ unsigned e, ecount = 0;
+ const unsigned desc_id = description->d.solid.desc_id;
+
+ /* The enclosures where created using description ids */
+ ERR(senc3d_scene_get_enclosure_count_by_medium(stardis->senc3d_scn,
+ desc_id, &ecount));
+ if(ecount == 0) {
+ unsigned ccount;
+ ERR(sg3d_geometry_get_unique_triangles_with_properties_conflict_count(
+ stardis->geometry.sg3d, &ccount));
+ CHK(ccount == 0); /* This solid can only be unused if in conflict*/
} else {
- size_t sz = htable_vertex_size_get(vertex2id);
- unsigned size;
- ASSERT(sz < UINT_MAX);
- size = (unsigned)sz;
- res = htable_vertex_set(vertex2id, &vtx, &size);
- if (res != RES_OK) return res;
- sa_push(geometry->vertex, vtx);
- sa_push(*id2id, size);
- }
- }
-
- return res;
-}
-
-static int
-indices_to_key(struct unsigned3* key, const struct unsigned3* indices)
-{
- int i, reversed = 0;
- FOR_EACH(i, 0, 3) key->data[i] = indices->data[i];
- if (key->data[0] > key->data[1]) {
- reversed = !reversed;
- SWAP(unsigned, key->data[0], key->data[1]);
- }
- if (key->data[1] > key->data[2]) {
- reversed = !reversed;
- SWAP(unsigned, key->data[1], key->data[2]);
- }
- if (key->data[0] > key->data[1]) {
- reversed = !reversed;
- SWAP(unsigned, key->data[0], key->data[1]);
- }
- return reversed;
-}
-
-static res_T
-read_triangles
- (struct sstl_desc* stl_desc,
- struct htable_triangle* triangle2id,
- const char* stl_filename,
- const unsigned* id2id,
- const enum content_type file_type,
- const unsigned desc_id,
- struct geometry* geometry,
- struct solve_boundary* boundary)
-{
- res_T res = RES_OK;
- unsigned* packed_indices = NULL;
- float* packed_normals = NULL;
- unsigned tri_index = 0, drop_cpt = 0;
- for (tri_index = 0; tri_index < stl_desc->triangles_count; ++tri_index) {
- struct triangle tri = NULL_TRIANGLE;
- const unsigned *found_id = NULL;
- unsigned i, id;
- struct unsigned3 key;
- int reversed;
- int drop = 0;
- enum sdis_side current_side = SDIS_FRONT;
- unsigned* side_desc_ptr = NULL;
- float coord[3][3];
-
- FOR_EACH(i, 0, 3)
- tri.indices.data[i] = id2id[stl_desc->indices[3*tri_index + i]];
- reversed = indices_to_key(&key, &tri.indices);
-
- FOR_EACH(i, 0, 3) {
- unsigned j;
- f3_set(coord[i], geometry->vertex[key.data[i]].xyz);
- FOR_EACH(j, 0, i) {
- if (f3_eq(coord[i], coord[j])) {
- drop = 1;
- drop_cpt++;
+ int external = 0;
+ FOR_EACH(e, 0, ecount) {
+ ERR(senc3d_scene_get_enclosure_by_medium(stardis->senc3d_scn, desc_id,
+ e, &enc));
+ ERR(senc3d_enclosure_get_header(enc, &header));
+ if(header.is_infinite) {
+ /* External solid, volume is negative and no delta walk expected */
+ external = 1;
+ } else {
+ double d = header.volume / (header.area * 6);
+ ASSERT(d >= 0);
+ delta_range[0] = MMIN(delta_range[0], d);
+ delta_range[1] = MMAX(delta_range[1], d);
}
+ ERR(senc3d_enclosure_ref_put(enc));
+ enc = NULL;
}
- }
- if (drop) continue;
- FOR_EACH(i, 0, 3) {
- sa_push(packed_indices, stl_desc->indices[3 * tri_index + i]);
- sa_push(packed_normals, stl_desc->normals[3 * tri_index + i]);
- }
-
- /* Find triangle if already known, or insert it in known list */
- found_id = htable_triangle_find(triangle2id, &key);
- if (found_id) {
- struct triangle* original_tri;
- int original_reversed;
- id = *found_id;
- original_tri = geometry->triangle + id;
- original_reversed = indices_to_key(&key, &original_tri->indices);
- current_side = (reversed == original_reversed) ? SDIS_FRONT : SDIS_BACK;
- ASSERT(id < sa_size(geometry->triangle));
- } else {
- size_t sz;
- if (file_type == CONTENT_BOUNDARY) {
- /* Cannot create new geometry! */
- fprintf(stderr,
- "Triangle %u from file %s cannot compute temperature on this surface\n"
- "Not part of the model\n",
- tri_index, stl_filename);
- return RES_BAD_ARG;
+ if(ecount > 1 || !external) {
+ ASSERT(0 < delta_range[0] && delta_range[0] <= delta_range[1]);
+ ratio = delta_range[1] / delta_range[0];
+ if(ratio > acceptance_ratio)
+ logger_print(stardis->logger, LOG_WARNING,
+ "Solid '%s' is used in %u different enclosures that have different "
+ "delta requirements.\n",
+ str_cget(&description->d.solid.name), ecount);
+ /* Delta needs to be substituted with actual value */
+ if(description->d.solid.delta == DELTA_AUTO) {
+ description->d.solid.delta = delta_range[0];
+ logger_print(stardis->logger, LOG_OUTPUT,
+ "Auto delta for solid '%s' set to %g\n",
+ str_cget(&description->d.solid.name), description->d.solid.delta);
+ } else {
+ int too_small
+ = (delta_range[0] > description->d.solid.delta * acceptance_ratio);
+ int too_big
+ = (delta_range[0] * acceptance_ratio < description->d.solid.delta);
+ /* Check if user delta is OK */
+ if(too_small || too_big) {
+ logger_print(stardis->logger, LOG_WARNING,
+ "User delta for solid '%s' seems too %s: %g; "
+ "auto delta would have set it to %g.\n",
+ str_cget(&description->d.solid.name), (too_big ? "big" : "small"),
+ description->d.solid.delta, delta_range[0]);
+ }
+ }
}
- sz = htable_triangle_size_get(triangle2id);
- ASSERT(sz == sa_size(geometry->triangle));
- ASSERT(sz < UINT_MAX);
- id = (unsigned)sz;
- /* Store tri as described by stl_desc regardless of key order */
- res = htable_triangle_set(triangle2id, &key, &id);
- if (res != RES_OK) goto error;
- sa_push(geometry->triangle, tri);
}
-
- switch (file_type) {
- case CONTENT_CONNECTION:
- side_desc_ptr = &geometry->triangle[id].connection_description;
- break;
- case CONTENT_GEOMETRY:
- /* Is the triangle in triangle list reversed wrt stl_desc? */
- side_desc_ptr = (current_side == SDIS_FRONT) ?
- &geometry->triangle[id].front_description
- : &geometry->triangle[id].back_description;
- break;
- case CONTENT_BOUNDARY:
- sa_push(boundary->primitives, id);
- sa_push(boundary->sides, current_side);
- continue; /* Next triangle */
- break;
- default: FATAL("Invalid type.\n");
- }
- if (*side_desc_ptr != UINT_MAX && *side_desc_ptr != desc_id) {
- /* Already described with a different description! */
- fprintf(stderr, "Triangle %u %s from file %s with 2 different descriptions\n",
- tri_index,
- (file_type == CONTENT_CONNECTION
- ? "connection" : (current_side == SDIS_FRONT ? "front" : "back")),
- stl_filename);
- print_trg_as_obj(stderr, (const struct vertex*)stl_desc->vertices, stl_desc->indices + (3 * tri_index));
- return RES_BAD_ARG;
- }
- /* Everithing is OK: store description */
- *side_desc_ptr = desc_id;
- }
- ASSERT(drop_cpt == 0 || packed_indices != NULL);
- if (drop_cpt) {
- fprintf(stderr, "File '%s' includes %u degenerate triangles (dropped)\n",
- stl_filename, drop_cpt);
- /* Keep only valid triangles */
- ASSERT(sa_size(packed_indices) % 3 == 0);
- ASSERT(sa_size(packed_indices) == sa_size(packed_normals));
- ASSERT(sa_size(packed_indices) + 3 * drop_cpt == sa_size(stl_desc->indices));
- /* Don't sa_release stl_desc->indices or stl_desc->normals as they have
- * their own release mechanism */
- stl_desc->indices = packed_indices;
- stl_desc->normals = packed_normals;
- stl_desc->triangles_count = sa_size(stl_desc->indices) / 3;
- }
- else {
- sa_release(packed_indices);
- sa_release(packed_normals);
- packed_indices = NULL;
- packed_normals = NULL;
}
+ ERR(create_solver_solid(stardis, &description->d.solid));
end:
- sa_release(packed_indices);
- sa_release(packed_normals);
-
- return res;
- error:
- goto end;
-}
-
-res_T
-read_stl
- (const unsigned desc_id,
- const enum content_type file_type,
- const char* stl_filename,
- struct htable_vertex* vertex2id,
- struct htable_triangle* triangle2id,
- struct stardis* stardis)
-{
- res_T res = RES_OK;
- struct sstl* sstl = NULL;
- struct sstl_desc stl_desc;
- unsigned* id2id = NULL;
-
- if (!stl_filename) return RES_BAD_ARG;
-
- SSTL(create(NULL, &stardis->allocator, 0, &sstl));
-
- res = sstl_load(sstl, stl_filename);
- if (res != RES_OK) {
- fprintf(stderr, "Cannot read STL file: %s\n", stl_filename);
- goto error;
- }
- SSTL(get_desc(sstl, &stl_desc));
-
- res = read_vertices(&stl_desc, vertex2id, &id2id, &stardis->geometry);
- if (res != RES_OK) goto error;
- res = read_triangles(&stl_desc, triangle2id, stl_filename, id2id, file_type,
- desc_id, &stardis->geometry, &stardis->boundary);
- if (res != RES_OK) goto error;
-
-end:
- sa_release(id2id);
- SSTL(ref_put(sstl));
+ if(enc) SENC3D(enclosure_ref_put(enc));
return res;
error:
goto end;
}
/*******************************************************************************
- *
+ * Public Functions
******************************************************************************/
-static res_T
-geometry_analyse
- (const char* medium_filename,
- const char* bc_filename,
- const char* bound_filename, /* Can be NULL */
+res_T
+stardis_init
+ (const struct args* args,
+ struct logger* logger,
+ struct mem_allocator* allocator,
struct stardis* stardis)
{
- res_T res = RES_OK;
- FILE* input = NULL;
- char* line = NULL;
- unsigned sz = (unsigned)sa_size(stardis->descriptions);
- struct htable_vertex vertex2id;
- struct htable_triangle triangle2id;
- struct htable_descriptions descriptions;
- int tables_initialised = 0;
- unsigned desc_id;
- unsigned *p_desc;
- ASSERT(sz == sa_size(stardis->descriptions));
-
- stardis->geometry = NULL_GEOMETRY;
-
- /* parse medium files */
- input = fopen(medium_filename,"r");
- if (!input){
- fprintf(stderr,"Cannot open %s\n", medium_filename);
- res = RES_IO_ERR;
- goto error;
- }
-
- htable_vertex_init(&stardis->allocator, &vertex2id);
- htable_triangle_init(&stardis->allocator, &triangle2id);
- htable_descriptions_init(&stardis->allocator, &descriptions);
- tables_initialised = 1;
- /* loop on media */
- while (read_line(&line, input)){
- char* stl_filename = NULL;
- struct description desc;
-
- init_description(&desc);
- res = parse_medium_line(line, &stl_filename, &desc);
- if (res != RES_OK) goto error;
-
- /* Deduplicate media: find if the same description already exists
- * (including name) */
- p_desc = htable_descriptions_find(&descriptions, &desc);
- if (!p_desc) {
- sa_push(stardis->descriptions, desc);
- desc_id = sz++;
- ASSERT(sz == sa_size(stardis->descriptions));
- /* Register new medium description */
- res = htable_descriptions_set(&descriptions, &desc, &desc_id);
- if (res != RES_OK) goto error;
- } else {
- fprintf(stderr, "Duplicate media description found: deduplicated.\n");
- desc_id = *p_desc;
+ res_T tmp_res, res = RES_OK;
+ struct sg3d_sdisXd_scene_create_context create_context;
+ struct dummies dummies = DUMMIES_NULL;
+ struct htable_intface htable_interfaces;
+ struct str str;
+ unsigned i, vcount, tcount, ocount, count;
+ int is_for_compute;
+
+ ASSERT(args && logger && allocator && stardis);
+
+ str_init(allocator, &str);
+ /* Init everithing that cannot fail */
+ stardis->logger = logger;
+ stardis->allocator = allocator;
+ htable_intface_init(stardis->allocator, &htable_interfaces);
+ darray_descriptions_init(stardis->allocator, &stardis->descriptions);
+ d3_set(stardis->probe, args->pos_and_time);
+ d2_set(stardis->time_range, args->pos_and_time + 3);
+ stardis->dev = NULL;
+ stardis->sdis_scn = NULL;
+ stardis->senc3d_scn = NULL;
+ stardis->mode = args->mode;
+ stardis->counts = COUNTS_NULL;
+ init_camera(&stardis->camera);
+ str_init(stardis->allocator, &stardis->solve_name);
+ str_init(stardis->allocator, &stardis->paths_filename);
+ str_init(stardis->allocator, &stardis->bin_green_filename);
+ str_init(stardis->allocator, &stardis->end_paths_filename);
+ str_init(stardis->allocator, &stardis->chunks_prefix);
+ 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);
+ stardis->samples = args->samples;
+ stardis->nthreads = args->nthreads;
+ stardis->scale_factor = -1; /* invalid value */
+ stardis->ambient_temp = args->ambient_temp;
+ stardis->ref_temp = args->ref_temp;
+ stardis->dump_paths = SDIS_HEAT_PATH_NONE;
+ if(args->dump_paths & DUMP_ERROR)
+ stardis->dump_paths |= SDIS_HEAT_PATH_FAILURE;
+ if(args->dump_paths & DUMP_SUCCESS)
+ stardis->dump_paths |= SDIS_HEAT_PATH_SUCCESS;
+ stardis->next_medium_id = 0;
+ stardis->undefined_medium_behind_boundary_id = SENC3D_UNSPECIFIED_MEDIUM;
+ stardis->verbose = args->verbose;
+ darray_media_ptr_init(stardis->allocator, &stardis->media);
+
+ /* If a dump is expected, we won't process any computation */
+ is_for_compute =
+ (stardis->mode & COMPUTE_MODES) && !(stardis->mode & MODE_DUMP_VTK);
+
+ ERR(sdis_device_create(stardis->logger, stardis->allocator, stardis->nthreads,
+ args->verbose, &stardis->dev));
+
+ ERR(init_geometry(stardis->logger, stardis->allocator, stardis->verbose,
+ &stardis->geometry));
+
+ if(args->mode & MODE_IR_COMPUTE) {
+ ERR(parse_camera(stardis->logger, args->camera, stardis));
+ }
+ else if(args->mode & MODE_MEDIUM_COMPUTE) {
+ ERR(str_set(&stardis->solve_name, args->medium_name));
+ }
+ else if(args->mode & SURFACE_COMPUTE_MODES) {
+ ERR(str_set(&stardis->solve_name, args->solve_filename));
+ }
+ else if(args->mode & MODE_DUMP_C_CHUNKS) {
+ ERR(str_set(&stardis->chunks_prefix, args->chunks_prefix));
+ }
+ ERR(read_model(&args->model_files, stardis, &dummies));
+
+ create_context.geometry = stardis->geometry.sg3d;
+ create_context.app_interface_getter = geometry_get_interface;
+ create_context.app_interface_data = &stardis->geometry.interf_bytrg;
+ ERR(sg3d_geometry_get_unique_vertices_count(stardis->geometry.sg3d, &vcount));
+ ERR(sg3d_geometry_get_unique_triangles_count(stardis->geometry.sg3d, &tcount));
+
+ ERR(sg3d_geometry_validate_properties(stardis->geometry.sg3d,
+ validate_properties, stardis));
+ ERR(sg3d_geometry_get_unique_triangles_with_properties_conflict_count(
+ stardis->geometry.sg3d, &count));
+ if(count) {
+ logger_print(stardis->logger, (is_for_compute ? LOG_ERROR : LOG_WARNING),
+ "Property conflicts found in the model (%u triangles).\n", count);
+ if(is_for_compute) {
+ res = RES_BAD_ARG;
+ goto error;
+ }
+ }
+
+ /* If computation is on a compute surface, read it */
+ if(args->mode & SURFACE_COMPUTE_MODES) {
+ unsigned save_count = count;
+ ASSERT(!str_is_empty(&stardis->solve_name));
+ ERR(read_compute_surface(stardis));
+ /* Check compute surface */
+ ERR(sg3d_geometry_validate_properties(stardis->geometry.sg3d,
+ validate_properties, stardis));
+ ERR(sg3d_geometry_get_unique_triangles_with_properties_conflict_count(
+ stardis->geometry.sg3d, &count));
+ ASSERT(count >= save_count);
+ if(save_count != count) {
+ logger_print(stardis->logger, (is_for_compute ? LOG_ERROR : LOG_WARNING),
+ "Invalid compute region defined by file '%s'.\n",
+ str_cget(&stardis->solve_name));
+ logger_print(stardis->logger, (is_for_compute ? LOG_ERROR : LOG_WARNING),
+ "The file contains %u triangles not in the model.\n", count - save_count);
+ if(is_for_compute) {
+ res = RES_BAD_ARG;
+ goto error;
+ }
}
-
- res = read_stl(sz-1, CONTENT_GEOMETRY, stl_filename, &vertex2id,
- &triangle2id, stardis);
- if (stl_filename) free(stl_filename);
- if (res != RES_OK) goto error;
}
- fclose(input);
- input = NULL;
- /* parse boundary files */
- input = fopen(bc_filename,"r");
- if (!input){
- fprintf(stderr,"Cannot open %s\n", bc_filename);
- res = RES_IO_ERR;
+ /* Create enclosures */
+ tmp_res = init_enclosures(stardis);
+ if(tmp_res != RES_OK && is_for_compute) {
+ res = tmp_res;
goto error;
}
-
- /* loop on boundaries */
- while (read_line(&line, input)){
- char* stl_filename = NULL;
- struct description desc;
-
- init_description(&desc);
- res = parse_boundary_line(line, &stl_filename, &desc);
- if (res != RES_OK) goto error;
-
- /* Deduplicate media: find if the same description already exists
- * (including name) */
- p_desc = htable_descriptions_find(&descriptions, &desc);
- if (!p_desc) {
- sa_push(stardis->descriptions, desc);
- desc_id = sz++;
- ASSERT(sz == sa_size(stardis->descriptions));
- /* Register new boundary description */
- res = htable_descriptions_set(&descriptions, &desc, &desc_id);
- if (res != RES_OK) goto error;
- } else {
- fprintf(stderr, "Duplicate boundary description found: deduplicated.\n");
- desc_id = *p_desc;
+ ERR(senc3d_scene_get_overlapping_triangles_count(stardis->senc3d_scn, &ocount));
+ if(ocount) {
+ logger_print(stardis->logger, (is_for_compute ? LOG_ERROR : LOG_WARNING),
+ "Scene contains %u overlapping triangles.\n",
+ ocount);
+ if(is_for_compute) {
+ res = RES_BAD_ARG;
+ goto error;
}
-
- res = read_stl(desc_id, CONTENT_CONNECTION, stl_filename, &vertex2id,
- &triangle2id, stardis);
- if (stl_filename) free(stl_filename);
- if (res != RES_OK) goto error;
}
- fclose(input);
- input = NULL;
- /* Process vtk file describing boundary compute */
- if (bound_filename) {
- res = read_stl(0, CONTENT_BOUNDARY, bound_filename, &vertex2id,
- &triangle2id, stardis);
- if (res != RES_OK) goto error;
+ /* Create solids and log model information */
+ for(i = 0; i < darray_descriptions_size_get(&stardis->descriptions); i++) {
+ struct description* desc =
+ darray_descriptions_data_get(&stardis->descriptions) + i;
+ if(desc->type == DESC_MAT_SOLID) {
+ tmp_res = check_delta_and_create_solid(stardis, desc);
+ if(tmp_res != RES_OK && is_for_compute) {
+ res = tmp_res;
+ goto error;
+ }
+ }
+ ERR(str_print_description(&str, i, desc));
+ logger_print(stardis->logger, LOG_OUTPUT, "%s\n", str_cget(&str));
}
-exit:
- if(input) fclose(input);
- if (tables_initialised) {
- htable_descriptions_release(&descriptions);
- htable_vertex_release(&vertex2id);
- htable_triangle_release(&triangle2id);
+ if(is_for_compute) {
+ for(i = 0; i < tcount; ++i) {
+ ERR(create_intface(stardis, i, &htable_interfaces));
+ }
+ if(args->paths_filename) {
+ ERR(str_set(&stardis->paths_filename, args->paths_filename));
+ }
+ if(args->bin_green_filename) {
+ ERR(str_set(&stardis->bin_green_filename, args->bin_green_filename));
+ }
+ if(args->end_paths_filename) {
+ ERR(str_set(&stardis->end_paths_filename, args->end_paths_filename));
+ }
}
- sa_release(line);
- return res;
-error:
- goto exit;
-}
-
-static res_T
-parse_camera
- (char* cam_param, struct camera* cam)
-{
- char** line = NULL;
- char** opt = NULL;
- res_T res = RES_OK;
- line = split_line(cam_param,':');
-
- if (line)
- {
- int i = 0;
- for (i = 0; *(line + i); i++)
- {
- size_t len = 0;
- opt = split_line(line[i],'=');
- if (strcmp(opt[0], "t") == 0) {
- res = cstr_to_double(opt[1], &cam->u.time);
- if (res != RES_OK) goto error;
- } else if (strcmp(opt[0],"fov")==0){
- res = cstr_to_double(opt[1], &cam->fov);
- if (res != RES_OK) goto error;
- } else if (strcmp(opt[0],"up")==0) {
- res = cstr_to_list_double(opt[1], ',', cam->up, &len, 3);
- if (res != RES_OK || len != 3) goto error;
- } else if (strcmp(opt[0],"tgt")==0) {
- res = cstr_to_list_double(opt[1], ',', cam->tgt, &len, 3);
- if (res != RES_OK || len != 3) goto error;
- } else if (strcmp(opt[0],"pos")==0) {
- res = cstr_to_list_double(opt[1], ',', cam->pos, &len, 3);
- if (res != RES_OK || len != 3) goto error;
- } else if (strcmp(opt[0],"img")==0) {
- res = cstr_to_list_uint(opt[1], 'x', cam->img, &len, 2);
- if (res != RES_OK || len != 2) goto error;
- } else if (strcmp(opt[0],"spp")==0) {
- res = cstr_to_uint(opt[1], &cam->spp);
- if (res != RES_OK) goto error;
- }
+ /* 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)) {
+ 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;
+ goto error;
+ }
+ }
+
+ if(is_for_compute) {
+ struct sdis_scene_create_args scn_args = SDIS_SCENE_CREATE_ARGS_DEFAULT;
+ ASSERT(darray_interface_ptrs_size_get(&stardis->geometry.interf_bytrg)
+ == tcount);
+ /* Can release enclosures as they are no longer needed if compute */
+ SENC3D(scene_ref_put(stardis->senc3d_scn));
+ stardis->senc3d_scn = NULL;
+ scn_args.get_indices = sg3d_sdisXd_geometry_get_indices;
+ scn_args.get_interface = sg3d_sdisXd_geometry_get_interface;
+ scn_args.get_position = sg3d_sdisXd_geometry_get_position;
+ scn_args.nprimitives = tcount;
+ scn_args.nvertices = vcount;
+ scn_args.fp_to_meter = stardis->scale_factor;
+ scn_args.trad = stardis->ambient_temp;
+ scn_args.tref = stardis->ref_temp;
+ scn_args.context = &create_context;
+ res = sdis_scene_create(stardis->dev, &scn_args, &stardis->sdis_scn);
+ if(res != RES_OK) {
+ logger_print(stardis->logger, LOG_ERROR,
+ "Cannot create the stardis solver scene.\n");
+ goto error;
}
}
exit:
- FREE_AARRAY(line)
- FREE_AARRAY(opt)
-
+ str_release(&str);
+ htable_intface_release(&htable_interfaces);
return res;
error:
+ stardis_release(stardis);
goto exit;
}
-/*******************************************************************************
- *
- ******************************************************************************/
+void
+stardis_release
+ (struct stardis* stardis)
+{
+ size_t i;
+
+ ASSERT(stardis);
+
+ if(stardis->dev) SDIS(device_ref_put(stardis->dev));
+ if(stardis->sdis_scn) SDIS(scene_ref_put(stardis->sdis_scn));
+ if(stardis->senc3d_scn) SENC3D(scene_ref_put(stardis->senc3d_scn));
+ str_release(&stardis->solve_name);
+ str_release(&stardis->paths_filename);
+ str_release(&stardis->bin_green_filename);
+ str_release(&stardis->end_paths_filename);
+ str_release(&stardis->chunks_prefix);
+ darray_descriptions_release(&stardis->descriptions);
+ release_geometry(&stardis->geometry);
+ darray_size_t_release(&stardis->compute_surface.primitives);
+ darray_sides_release(&stardis->compute_surface.sides);
+ darray_uint_release(&stardis->compute_surface.err_triangles);
+ FOR_EACH(i, 0, darray_media_ptr_size_get(&stardis->media)) {
+ if(darray_media_ptr_data_get(&stardis->media)[i])
+ SDIS(medium_ref_put(darray_media_ptr_data_get(&stardis->media)[i]));
+ }
+ darray_media_ptr_release(&stardis->media);
+}
res_T
-stardis_init
- (const struct args* args,
- struct stardis* stardis)
+init_enclosures
+ (struct stardis* stardis)
{
res_T res = RES_OK;
-
- res = mem_init_proxy_allocator(&stardis->allocator,
- &mem_default_allocator);
- if (res != RES_OK) goto error;
-
- res = geometry_analyse(args->medium_filename,
- args->bc_filename, args->solve_boundary_filename, stardis);
- if (res != RES_OK) goto error;
-
- stardis->N = args->N;
- stardis->nthreads = args->nthreads;
- stardis->probe[0] = args->u.probe[0];
- stardis->probe[1] = args->u.probe[1];
- stardis->probe[2] = args->u.probe[2];
- stardis->probe[3] = args->u.probe[3];
- stardis->scale_factor = args->scale_factor;
- stardis->radiative_temp[0] = args->radiative_temp[0];
- stardis->radiative_temp[1] = args->radiative_temp[1];
- stardis->dump_paths = SDIS_HEAT_PATH_NONE;
- if (args->dump_paths & DUMP_ERROR)
- stardis->dump_paths |= SDIS_HEAT_PATH_FAILED;
- if (args->dump_paths & DUMP_SUCCESS)
- stardis->dump_paths |= SDIS_HEAT_PATH_SUCCEED;
-
- if (args->mode & IR_COMPUTE){
- res = parse_camera(args->camera, &stardis->camera);
- if (res != RES_OK) goto error;
- }
- else if (args->mode & MEDIUM_COMPUTE) {
- strcpy(stardis->solve_name, args->medium_name);
- }
- else if (args->mode & BOUNDARY_COMPUTE) {
- strcpy(stardis->solve_name, args->solve_boundary_filename);
- }
-
+ unsigned tsz, vsz;
+ struct senc3d_device* senc_dev = NULL;
+
+ ERR(sg3d_geometry_get_unique_triangles_count(stardis->geometry.sg3d, &tsz));
+ ERR(sg3d_geometry_get_unique_vertices_count(stardis->geometry.sg3d, &vsz));
+ ERR(senc3d_device_create(stardis->logger, stardis->allocator,
+ stardis->nthreads, stardis->verbose, &senc_dev));
+ stardis->undefined_medium_behind_boundary_id
+ = allocate_stardis_medium_id(stardis);
+ ERR(senc3d_scene_create(senc_dev,
+ SENC3D_CONVENTION_NORMAL_BACK | SENC3D_CONVENTION_NORMAL_OUTSIDE,
+ tsz, sg3d_sencXd_geometry_get_indices, sg3d_sencXd_geometry_get_media,
+ vsz, sg3d_sencXd_geometry_get_position, stardis->geometry.sg3d,
+ &stardis->senc3d_scn));
exit:
+ if(senc_dev) senc3d_device_ref_put(senc_dev);
return res;
error:
goto exit;
}
-void
-stardis_release(struct stardis* stardis)
-{
- size_t i = 0;
+#define COUNT_SIDE(Rank) {\
+ if(properties[(Rank)] == SG3D_UNSPECIFIED_PROPERTY) undef_count++;\
+ else {\
+ ASSERT(properties[(Rank)] < darray_descriptions_size_get(&stardis->descriptions));\
+ ASSERT(descs[properties[(Rank)]].type == DESC_MAT_SOLID\
+ || descs[properties[(Rank)]].type == DESC_MAT_FLUID);\
+ if(descs[properties[(Rank)]].type == DESC_MAT_SOLID) solid_count++;\
+ else fluid_count++;\
+ }\
+}
- for (i=0; i<sa_size(stardis->descriptions); ++i) {
- struct description* desc = &stardis->descriptions[i];
- switch (desc->type) {
- case DESC_MAT_SOLID:
- free(desc->d.solid.power);
- free(desc->d.solid.Tinit);
- free(desc->d.solid.Temp);
- break;
- case DESC_MAT_FLUID:
- free(desc->d.fluid.Tinit);
- free(desc->d.fluid.Temp);
+res_T
+validate_properties
+ (const unsigned itri,
+ const unsigned properties[SG3D_PROP_TYPES_COUNT__],
+ void* context,
+ int* properties_conflict_status)
+{
+ res_T res = RES_OK;
+ struct stardis* stardis = context;
+ unsigned undef_count, solid_count, fluid_count, intface_count;
+ const struct description* descs;
+ const struct description* intface = NULL;
+
+ (void)itri;
+ ASSERT(stardis && properties_conflict_status);
+ descs = darray_descriptions_cdata_get(&stardis->descriptions);
+ *properties_conflict_status = NO_PROPERTY_CONFLICT;
+ undef_count = solid_count = fluid_count = intface_count = 0;
+
+ COUNT_SIDE(SG3D_FRONT);
+ COUNT_SIDE(SG3D_BACK);
+ if(properties[SG3D_INTFACE] == SG3D_UNSPECIFIED_PROPERTY)
+ undef_count++;
+ else intface_count++;
+
+ ASSERT(solid_count <= 2 && fluid_count <= 2 && intface_count <= 1);
+ ASSERT(undef_count + solid_count + fluid_count + intface_count == 3);
+ if(intface_count) {
+ ASSERT(properties[SG3D_INTFACE]
+ < darray_descriptions_size_get(&stardis->descriptions));
+ intface = descs + properties[SG3D_INTFACE];
+ switch (intface->type) {
+ case DESC_BOUND_H_FOR_FLUID:
+ if(!(solid_count == 0 && fluid_count == 1)) {
+ if(solid_count + fluid_count == 2)
+ *properties_conflict_status = BOUND_H_FOR_FLUID_BETWEEN_2_DEFS;
+ else if(solid_count + fluid_count == 0)
+ *properties_conflict_status = BOUND_H_FOR_FLUID_BETWEEN_2_UNDEFS;
+ else if(solid_count == 1)
+ *properties_conflict_status = BOUND_H_FOR_FLUID_ENCLOSING_SOLID;
+ else FATAL("error:" STR(__FILE__) ":" STR(__LINE__)"\n");
+ goto end;
+ }
break;
case DESC_BOUND_H_FOR_SOLID:
- case DESC_BOUND_H_FOR_FLUID:
- free(desc->d.h_boundary.T);
+ if(!(solid_count == 1 && fluid_count == 0)) {
+ if(solid_count + fluid_count == 2)
+ *properties_conflict_status = BOUND_H_FOR_SOLID_BETWEEN_2_DEFS;
+ else if(solid_count + fluid_count == 0)
+ *properties_conflict_status = BOUND_H_FOR_SOLID_BETWEEN_2_UNDEFS;
+ else if(fluid_count == 1)
+ *properties_conflict_status = BOUND_H_FOR_SOLID_ENCLOSING_FLUID;
+ else FATAL("error:" STR(__FILE__) ":" STR(__LINE__)"\n");
+ goto end;
+ }
break;
- case DESC_BOUND_T_FOR_SOLID:
case DESC_BOUND_T_FOR_FLUID:
- free(desc->d.t_boundary.T);
- te_free(desc->d.t_boundary.te_temperature);
+ if(!(solid_count == 0 && fluid_count == 1)) {
+ if(solid_count + fluid_count == 2)
+ *properties_conflict_status = BOUND_T_FOR_FLUID_BETWEEN_2_DEFS;
+ else if(solid_count + fluid_count == 0)
+ *properties_conflict_status = BOUND_T_FOR_FLUID_BETWEEN_2_UNDEFS;
+ else if(solid_count == 1)
+ *properties_conflict_status = BOUND_T_FOR_FLUID_ENCLOSING_SOLID;
+ else FATAL("error:" STR(__FILE__) ":" STR(__LINE__)"\n");
+ goto end;
+ }
+ break;
+ case DESC_BOUND_T_FOR_SOLID:
+ if(!(solid_count == 1 && fluid_count == 0)) {
+ if(solid_count + fluid_count == 2)
+ *properties_conflict_status = BOUND_T_FOR_SOLID_BETWEEN_2_DEFS;
+ else if(solid_count + fluid_count == 0)
+ *properties_conflict_status = BOUND_T_FOR_SOLID_BETWEEN_2_UNDEFS;
+ else if(fluid_count == 1)
+ *properties_conflict_status = BOUND_T_FOR_SOLID_ENCLOSING_FLUID;
+ else FATAL("error:" STR(__FILE__) ":" STR(__LINE__)"\n");
+ goto end;
+ }
break;
case DESC_BOUND_F_FOR_SOLID:
- free(desc->d.f_boundary.flux);
- te_free(desc->d.f_boundary.te_flux);
+ if(!(solid_count == 1 && fluid_count == 0)) {
+ if(solid_count + fluid_count == 2)
+ *properties_conflict_status = BOUND_F_FOR_SOLID_BETWEEN_2_DEFS;
+ else if(solid_count + fluid_count == 0)
+ *properties_conflict_status = BOUND_F_FOR_SOLID_BETWEEN_2_UNDEFS;
+ else if(fluid_count == 1)
+ *properties_conflict_status = BOUND_F_FOR_SOLID_ENCLOSING_FLUID;
+ else FATAL("error:" STR(__FILE__) ":" STR(__LINE__)"\n");
+ goto end;
+ }
break;
- default: FATAL("Invalid type.\n");
+ case DESC_SOLID_FLUID_CONNECT:
+ if(solid_count != 1 || fluid_count != 1) {
+ if(solid_count == 2)
+ *properties_conflict_status = SFCONNECT_BETWEEN_2_SOLIDS;
+ else if(fluid_count == 2)
+ *properties_conflict_status = SFCONNECT_BETWEEN_2_FLUIDS;
+ else if(solid_count + fluid_count == 1)
+ *properties_conflict_status = SFCONNECT_USED_AS_BOUNDARY;
+ else if(solid_count + fluid_count == 0)
+ *properties_conflict_status = SFCONNECT_BETWEEN_2_UNDEFS;
+ else FATAL("error:" STR(__FILE__) ":" STR(__LINE__)"\n");
+ goto end;
+ }
+ break;
+ default:
+ FATAL("error:" STR(__FILE__) ":" STR(__LINE__)": Invalid type.\n");
}
- }
- sa_release(stardis->descriptions);
- release_geometry(&stardis->geometry);
- sa_release(stardis->boundary.primitives);
- sa_release(stardis->boundary.sides);
-}
-
-/* TODO: rewrite dump! */
-res_T
-dump_vtk
- (FILE* output,
- const struct geometry* geometry)
-{
- res_T res = RES_OK;
- unsigned i;
- struct vertex* vtx = geometry->vertex;
- struct triangle* tri = geometry->triangle;
-
- if (!output){
- fprintf(stderr, "Invalid output file to dump vtk.\n");
- res = RES_BAD_ARG;
- goto error;
- }
-
- fprintf(output,"# vtk DataFile Version 2.0\nvtk output\nASCII\nDATASET POLYDATA\n");
- fprintf(output,"POINTS %i float\n\n", (int)sa_size(vtx));
- for (i=0; i<sa_size(vtx); ++i){
- fprintf(output,"%f %f %f\n",SPLIT3(vtx[i].xyz));
- }
- fprintf(output,"\nPOLYGONS %i %i\n", (int)sa_size(tri), (int)(4*sa_size(tri)));
- for (i=0; i<sa_size(tri); ++i){
- fprintf(output,"3 %i %i %i\n",SPLIT3(tri[i].indices.data));
- }
- fprintf(output,"\nCELL_DATA %i \n", (int)sa_size(tri));
- fprintf(output,"SCALARS front_description float 1\n");
- fprintf(output,"LOOKUP_TABLE default\n");
- for (i=0; i<sa_size(tri); ++i) {
- fprintf(output,"%i\n",tri[i].front_description);
- }
- fprintf(output,"SCALARS back_description float 1\n");
- fprintf(output,"LOOKUP_TABLE default\n");
- for (i=0; i<sa_size(tri); ++i) {
- fprintf(output,"%i\n",tri[i].back_description);
+ } else {
+ /* No interface defined */
+ ASSERT(intface_count == 0 && undef_count >= 1);
+ if(undef_count == 3) {
+ *properties_conflict_status = TRG_WITH_NO_PROPERTY;
+ goto end;
+ }
+ if(fluid_count == 2) {
+ *properties_conflict_status = NO_CONNECTION_BETWEEN_2_FLUIDS;
+ goto end;
+ }
+ if(undef_count == 2) {
+ ASSERT(fluid_count + solid_count == 1);
+ if(fluid_count)
+ *properties_conflict_status = NO_BOUND_BETWEEN_FLUID_AND_UNDEF;
+ else *properties_conflict_status = NO_BOUND_BETWEEN_SOLID_AND_UNDEF;
+ goto end;
+ }
+ if(undef_count == 1 && solid_count == 1 && fluid_count == 1) {
+ *properties_conflict_status = NO_CONNECTION_BETWEEN_SOLID_AND_FLUID;
+ goto end;
+ }
+ /* Undef interface between solids is OK */
+ CHK(solid_count == 2);
}
-exit:
+end:
return res;
-error:
- goto exit;
}
+
+#undef COUNT_SIDE
diff --git a/src/stardis-app.h b/src/stardis-app.h
@@ -1,24 +1,100 @@
-/* Copyright (C) 2018 |Meso|Star> (contact@meso-star.com)*/
+/* Copyright (C) 2018-2020 |Meso|Star> (contact@meso-star.com)
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>. */
#ifndef STARDIS_APP_H
#define STARDIS_APP_H
+#include "stardis-parsing.h"
+#include "stardis-default.h"
+#include "stardis-solid.h"
+#include "stardis-fluid.h"
+
#include <star/sstl.h>
+#include <star/sg3d.h>
+
#include <rsys/rsys.h>
#include <rsys/float3.h>
-#include <rsys/stretchy_array.h>
-#include <rsys/hash_table.h>
+#include <rsys/double2.h>
+#include <rsys/double3.h>
+#include <rsys/dynamic_array_size_t.h>
+#include <rsys/dynamic_array.h>
+#include <rsys/str.h>
+
#include <sdis.h>
-#include <tinyexpr.h>
-#include "args.h"
-
-#define FREE_AARRAY(ARRAY) if (ARRAY) {\
- int i = 0; \
- for (i=0; *(ARRAY+i);i++){\
- free(ARRAY[i]);\
- }\
- free(ARRAY);\
-}
+
+#include <limits.h>
+#include <stdarg.h>
+
+/* Forward declarations */
+struct logger;
+struct mem_allocator;
+struct sdis_medium;
+
+/* Utility macros */
+#define ERR(Expr) if((res = (Expr)) != RES_OK) goto error; else (void)0
+
+#define STR_APPEND_PRINTF(Accum, Fmt, Args) \
+{ \
+ struct str tmp; \
+ str_init((Accum)->allocator, &tmp); \
+ res = str_printf(&tmp, Fmt COMMA_##Args LIST_##Args); \
+ if(res == RES_OK) res = str_append((Accum), str_cget(&tmp)); \
+ str_release(&tmp); \
+ if(res != RES_OK) goto error; \
+} (void)0
+
+
+#define VFATAL(Fmt, Args) \
+ { \
+ fprintf(stderr, Fmt COMMA_##Args LIST_##Args); \
+ ASSERT(0); \
+ abort(); \
+ } (void)0
+
+
+#define DELTA_AUTO INF /* Placeholder until actual value is substituted */
+#define UNKNOWN_MEDIUM_TEMPERATURE -1 /* Unknown for stadis solver is -1 */
+
+enum properties_conflict_t {
+ NO_PROPERTY_CONFLICT,
+ BOUND_H_FOR_FLUID_BETWEEN_2_DEFS,
+ BOUND_H_FOR_FLUID_BETWEEN_2_UNDEFS,
+ BOUND_H_FOR_FLUID_ENCLOSING_SOLID,
+ BOUND_H_FOR_SOLID_BETWEEN_2_DEFS,
+ BOUND_H_FOR_SOLID_BETWEEN_2_UNDEFS,
+ BOUND_H_FOR_SOLID_ENCLOSING_FLUID,
+ BOUND_T_FOR_FLUID_BETWEEN_2_DEFS,
+ BOUND_T_FOR_FLUID_BETWEEN_2_UNDEFS,
+ BOUND_T_FOR_FLUID_ENCLOSING_SOLID,
+ BOUND_T_FOR_SOLID_BETWEEN_2_DEFS,
+ BOUND_T_FOR_SOLID_BETWEEN_2_UNDEFS,
+ BOUND_T_FOR_SOLID_ENCLOSING_FLUID,
+ BOUND_F_FOR_SOLID_BETWEEN_2_DEFS,
+ BOUND_F_FOR_SOLID_BETWEEN_2_UNDEFS,
+ BOUND_F_FOR_SOLID_ENCLOSING_FLUID,
+ SFCONNECT_BETWEEN_2_SOLIDS,
+ SFCONNECT_BETWEEN_2_FLUIDS,
+ SFCONNECT_USED_AS_BOUNDARY,
+ SFCONNECT_BETWEEN_2_UNDEFS,
+ NO_CONNECTION_BETWEEN_2_FLUIDS,
+ NO_CONNECTION_BETWEEN_SOLID_AND_FLUID,
+ NO_BOUND_BETWEEN_FLUID_AND_UNDEF,
+ NO_BOUND_BETWEEN_SOLID_AND_UNDEF,
+ TRG_WITH_NO_PROPERTY,
+ PROPERTIES_CONFLICT_COUNT__
+};
/* Different types of descriptions */
enum description_type {
@@ -34,841 +110,316 @@ enum description_type {
DESC_OUTSIDE
};
-struct vertex{
- float xyz[3];
-};
-#define NULL_VERTEX__ {{0.0 ,0.0 ,0.0}}
-static const struct vertex NULL_VERTEX = NULL_VERTEX__;
-
-static INLINE char
-eq_vertex(const struct vertex* a, const struct vertex* b)
-{
- return (char)f3_eq(a->xyz, b->xyz);
-}
-
-/* Declare the hash table that map a vertex to its index */
-#define HTABLE_NAME vertex
-#define HTABLE_DATA unsigned
-#define HTABLE_KEY struct vertex
-#define HTABLE_KEY_FUNCTOR_EQ eq_vertex
-#include <rsys/hash_table.h>
-
-struct unsigned3 { unsigned data[3]; };
-struct triangle {
- struct unsigned3 indices;
- unsigned front_description;
- unsigned back_description;
- unsigned connection_description;
+#define DESC_IS_H(D) \
+ ((D) == DESC_BOUND_H_FOR_SOLID || (D) == DESC_BOUND_H_FOR_FLUID)
+#define DESC_IS_T(D) \
+ ((D) == DESC_BOUND_T_FOR_SOLID || (D) == DESC_BOUND_T_FOR_FLUID)
+#define DESC_IS_F(D) \
+ ((D) == DESC_BOUND_F_FOR_SOLID)
+#define DESC_IS_MEDIUM(D) \
+ ((D) == DESC_MAT_SOLID || (D) == DESC_MAT_FLUID)
+#define DESC_IS_BOUNDARY(D) \
+ (DESC_IS_H(D) || DESC_IS_T(D) || DESC_IS_F(D))
+
+#define DARRAY_NAME interface_ptrs
+#define DARRAY_DATA struct sdis_interface*
+#include <rsys/dynamic_array.h>
+
+struct dummies {
+ struct sdis_medium* dummy_fluid;
+ unsigned dummy_fluid_id;
+ struct sdis_medium* dummy_solid;
+ unsigned dummy_solid_id;
};
-#define NULL_TRIANGLE__ {{{0, 0, 0}}, UINT_MAX, UINT_MAX, UINT_MAX }
-static const struct triangle NULL_TRIANGLE = NULL_TRIANGLE__;
-
-static INLINE void
-print_trg_as_obj
- (FILE* stream,
- const struct vertex* vertices,
- const unsigned* indices)
-{
- ASSERT(stream && vertices && indices);
- fprintf(stream, "v %.8f %.8f %.8f\nv %.8f %.8f %.8f\nv %.8f %.8f %.8f\nf 1 2 3\n",
- SPLIT3(vertices[indices[0]].xyz),
- SPLIT3(vertices[indices[1]].xyz),
- SPLIT3(vertices[indices[2]].xyz));
-}
-
-static INLINE char
-eq_indices(const struct unsigned3* a, const struct unsigned3* b)
-{
- return a->data[0] == b->data[0]
- && a->data[1] == b->data[1]
- && a->data[2] == b->data[2];
+#define DUMMIES_NULL__ {\
+ NULL, UINT_MAX, NULL, UINT_MAX\
}
-static INLINE res_T
-cp_indices(struct unsigned3* dst, const struct unsigned3* src)
+static FINLINE void
+init_media_ptr
+ (struct mem_allocator* alloc,
+ struct sdis_medium** data)
{
- int i;
- FOR_EACH(i, 0, 3) dst->data[i] = src->data[i];
- return RES_OK;
+ ASSERT(data); (void)alloc;
+ *data = NULL;
}
-/* Declare the hash table that maps a triangle id to its index */
-#define HTABLE_NAME triangle
-#define HTABLE_DATA unsigned
-#define HTABLE_KEY struct unsigned3
-#define HTABLE_KEY_FUNCTOR_EQ eq_indices
-#define HTABLE_KEY_FUNCTOR_COPY cp_indices
-#include <rsys/hash_table.h>
+#define DARRAY_NAME media_ptr
+#define DARRAY_DATA struct sdis_medium*
+#define DARRAY_FUNCTOR_INIT init_media_ptr
+#include <rsys/dynamic_array.h>
struct geometry {
- struct vertex* vertex;
- struct triangle* triangle;
- struct sdis_interface** interf_bytrg;
- struct sdis_interface** interfaces;
+ struct sg3d_geometry* sg3d;
+ struct darray_interface_ptrs interf_bytrg;
+ struct darray_interface_ptrs interfaces;
};
-#define NULL_GEOMETRY__ {NULL, NULL, NULL, NULL }
-static const struct geometry NULL_GEOMETRY = NULL_GEOMETRY__;
static INLINE void
release_geometry(struct geometry* geom)
{
size_t i;
- for (i = 0; i < sa_size(geom->interfaces); ++i)
- SDIS(interface_ref_put(geom->interfaces[i]));
- sa_release(geom->vertex); geom->vertex = NULL;
- sa_release(geom->triangle); geom->triangle = NULL;
- sa_release(geom->interfaces); geom->interfaces = NULL;
- sa_release(geom->interf_bytrg); geom->interf_bytrg = NULL;
+ struct sdis_interface
+ ** intf = darray_interface_ptrs_data_get(&geom->interfaces);
+ if(geom->sg3d) SG3D(geometry_ref_put(geom->sg3d));
+ for(i = 0; i < darray_interface_ptrs_size_get(&geom->interfaces); ++i)
+ SDIS(interface_ref_put(intf[i]));
+ darray_interface_ptrs_release(&geom->interfaces);
+ darray_interface_ptrs_release(&geom->interf_bytrg);
}
-struct mat_fluid {
- char name[32];
- unsigned fluid_id;
- double rho;
- double cp;
- char* Tinit;
- char* Temp;
-};
-#define NULL_FLUID__ { "", UINT_MAX, 0, 0, NULL, NULL }
-static const struct mat_fluid NULL_FLUID = NULL_FLUID__;
-
-static void
-print_fluid(FILE* stream, const struct mat_fluid* f)
+static INLINE res_T
+init_geometry
+ (struct logger* logger,
+ struct mem_allocator* allocator,
+ const int verbose,
+ struct geometry* geom)
{
- ASSERT(stream && f);
- fprintf(stream, "Fluid '%s': cp=%g rho=%g",
- f->name, f->cp, f->rho);
- if (f->Tinit) fprintf(stream, " Tinit='%s'", f->Tinit);
- if (f->Temp) fprintf(stream, " Temp='%s'", f->Temp);
- fprintf(stream, "\n");
+ res_T res = RES_OK;
+ struct sg3d_device* sg3d_dev = NULL;
+
+ ASSERT(allocator && geom);
+
+ geom->sg3d = NULL;
+ darray_interface_ptrs_init(allocator, &geom->interfaces);
+ darray_interface_ptrs_init(allocator, &geom->interf_bytrg);
+ ERR(sg3d_device_create(logger, allocator, verbose, &sg3d_dev));
+ ERR(sg3d_geometry_create(sg3d_dev, &geom->sg3d));
+
+exit:
+ if(sg3d_dev) SG3D(device_ref_put(sg3d_dev));
+ return res;
+error:
+ release_geometry(geom);
+ goto exit;
}
-static char
-eq_fluid(const struct mat_fluid* a, const struct mat_fluid* b)
-{
- if (strcmp(a->name, b->name)
- || a->fluid_id != b->fluid_id
- || a->rho != b->rho
- || a->cp != b->cp
- || strcmp(a->Tinit, b->Tinit)
- || strcmp(a->Temp, b->Temp))
- return 0;
- return 1;
-}
+/******************************************************************************/
-static size_t
-hash_fluid(const struct mat_fluid* key)
-{
-#ifdef ARCH_32BITS
- /* 32-bits Fowler/Noll/Vo hash function */
- const uint32_t FNV32_PRIME =
- (uint32_t) (((uint32_t) 1 << 24) + ((uint32_t) 1 << 8) + 0x93);
- const uint32_t OFFSET32_BASIS = 2166136261u;
- uint32_t hash = OFFSET32_BASIS;
- size_t i;
- ASSERT(key);
- FOR_EACH(i, 0, sizeof(key->name)) {
- hash = hash ^ (uint32_t)((unsigned char)((const char*)&key->name)[i]);
- hash = hash * FNV32_PRIME;
- }
- FOR_EACH(i, 0, sizeof(key->fluid_id)) {
- hash = hash ^ (uint32_t)((unsigned char)((const char*)&key->fluid_id)[i]);
- hash = hash * FNV32_PRIME;
- }
- FOR_EACH(i, 0, sizeof(key->rho)) {
- hash = hash ^ (uint32_t)((unsigned char)((const char*)&key->rho)[i]);
- hash = hash * FNV32_PRIME;
- }
- FOR_EACH(i, 0, sizeof(key->cp)) {
- hash = hash ^ (uint32_t)((unsigned char)((const char*)&key->cp)[i]);
- hash = hash * FNV32_PRIME;
- }
- hash = hash ^ (uint32_t)((unsigned char)(key->Tinit == 0));
- hash = hash * FNV32_PRIME;
- FOR_EACH(i, 0, key->Tinit ? strlen(key->Tinit) * sizeof(*key->Tinit) : 0) {
- hash = hash ^ (uint32_t)((unsigned char)((const char*)key->Tinit)[i]);
- hash = hash * FNV32_PRIME;
- }
- hash = hash ^ (uint32_t)((unsigned char)(key->Temp == 0));
- hash = hash * FNV32_PRIME;
- FOR_EACH(i, 0, key->Temp ? strlen(key->Temp) * sizeof(*key->Temp) : 0) {
- hash = hash ^ (uint32_t)((unsigned char)((const char*)key->Temp)[i]);
- hash = hash * FNV32_PRIME;
- }
- return hash;
-#elif defined(ARCH_64BITS)
- /* 64-bits Fowler/Noll/Vo hash function */
- const uint64_t FNV64_PRIME =
- (uint64_t) (((uint64_t) 1 << 40) + ((uint64_t) 1 << 8) + 0xB3);
- const uint64_t OFFSET64_BASIS = (uint64_t) 14695981039346656037u;
- uint64_t hash = OFFSET64_BASIS;
- size_t i;
- ASSERT(key);
- FOR_EACH(i, 0, sizeof(key->name)) {
- hash = hash ^ (uint64_t)((unsigned char)((const char*)&key->name)[i]);
- hash = hash * FNV64_PRIME;
- }
- FOR_EACH(i, 0, sizeof(key->fluid_id)) {
- hash = hash ^ (uint64_t)((unsigned char)((const char*)&key->fluid_id)[i]);
- hash = hash * FNV64_PRIME;
- }
- FOR_EACH(i, 0, sizeof(key->rho)) {
- hash = hash ^ (uint64_t) ((unsigned char)((const char*)&key->rho)[i]);
- hash = hash * FNV64_PRIME;
- }
- FOR_EACH(i, 0, sizeof(key->cp)) {
- hash = hash ^ (uint64_t)((unsigned char)((const char*)&key->cp)[i]);
- hash = hash * FNV64_PRIME;
- }
- hash = hash ^ (uint64_t)((unsigned char)(key->Tinit == 0));
- hash = hash * FNV64_PRIME;
- FOR_EACH(i, 0, key->Tinit ? strlen(key->Tinit)*sizeof(*key->Tinit) : 0) {
- hash = hash ^ (uint64_t)((unsigned char) ((const char*)key->Tinit)[i]);
- hash = hash * FNV64_PRIME;
- }
- hash = hash ^ (uint64_t)((unsigned char)(key->Temp == 0));
- hash = hash * FNV64_PRIME;
- FOR_EACH(i, 0, key->Temp ? strlen(key->Temp) * sizeof(*key->Temp) : 0) {
- hash = hash ^ (uint64_t)((unsigned char)((const char*)key->Temp)[i]);
- hash = hash * FNV64_PRIME;
- }
- return hash;
-#else
-#error "Unexpected architecture"
-#endif
-}
-
-struct mat_solid {
- char name[32];
- unsigned solid_id;
- double lambda;
- double rho;
- double cp;
- double delta;
- char* Tinit;
- char* Temp;
- char* power;
- int has_power;
+struct h_boundary {
+ struct str name;
+ double emissivity;
+ double specular_fraction;
+ double hc;
+ double imposed_temperature;
+ unsigned mat_id;
};
-#define NULL_SOLID__ { "", UINT_MAX, 0, 0, 0, 0, NULL, NULL, NULL, 0}
-static const struct mat_solid NULL_SOLID = NULL_SOLID__;
-static void
-print_solid(FILE* stream, const struct mat_solid* s)
+static FINLINE void
+init_h(struct mem_allocator* allocator, struct h_boundary* dst)
{
- ASSERT(stream && s);
- fprintf(stream,
- "Solid '%s': lambda=%g cp=%g rho=%g delta=%g Power='%s'",
- s->name, s->lambda, s->cp, s->rho, s->delta,
- (s->has_power ? s->power : "0"));
- if (s->Tinit) fprintf(stream, " Tinit='%s'", s->Tinit);
- if (s->Temp) fprintf(stream, " Temp='%s'", s->Temp);
- fprintf(stream, "\n");
+ str_init(allocator, &dst->name);
+ dst->emissivity = 0;
+ dst->specular_fraction = 0;
+ dst->hc = 0;
+ dst->imposed_temperature = -1;
+ dst->mat_id = UINT_MAX;
}
-static char
-eq_solid(const struct mat_solid* a, const struct mat_solid* b)
+static FINLINE void
+release_h_boundary(struct h_boundary* bound)
{
- if (strcmp(a->name, b->name)
- || a->solid_id != b->solid_id
- || a->lambda != b->lambda
- || a->rho != b->rho
- || a->cp != b->cp
- || a->delta != b->delta
- || strcmp(a->Tinit, b->Tinit)
- || strcmp(a->Temp, b->Temp)
- || a->has_power != b->has_power)
- return 0;
- if (a->has_power && a->power != b->power) return 0;
- return 1;
-}
-
-static size_t
-hash_solid(const struct mat_solid* key)
-{
-#ifdef ARCH_32BITS
- /* 32-bits Fowler/Noll/Vo hash function */
- const uint32_t FNV32_PRIME =
- (uint32_t) (((uint32_t) 1 << 24) + ((uint32_t) 1 << 8) + 0x93);
- const uint32_t OFFSET32_BASIS = 2166136261u;
- uint32_t hash = OFFSET32_BASIS;
- size_t i;
- ASSERT(key);
- FOR_EACH(i, 0, sizeof(key->name)) {
- hash = hash ^ (uint32_t)((unsigned char)((const char*)&key->name)[i]);
- hash = hash * FNV32_PRIME;
- }
- FOR_EACH(i, 0, sizeof(key->solid_id)) {
- hash = hash ^ (uint32_t)((unsigned char)((const char*)&key->solid_id)[i]);
- hash = hash * FNV32_PRIME;
- }
- FOR_EACH(i, 0, sizeof(key->lambda)) {
- hash = hash ^ (uint32_t)((unsigned char)((const char*)&key->lambda)[i]);
- hash = hash * FNV32_PRIME;
- }
- FOR_EACH(i, 0, sizeof(key->rho)) {
- hash = hash ^ (uint32_t)((unsigned char)((const char*)&key->rho)[i]);
- hash = hash * FNV32_PRIME;
- }
- FOR_EACH(i, 0, sizeof(key->cp)) {
- hash = hash ^ (uint32_t)((unsigned char)((const char*)&key->cp)[i]);
- hash = hash * FNV32_PRIME;
- }
- FOR_EACH(i, 0, sizeof(key->delta)) {
- hash = hash ^ (uint32_t)((unsigned char)((const char*)&key->delta)[i]);
- hash = hash * FNV32_PRIME;
- }
- hash = hash ^ (uint32_t)((unsigned char)(key->Tinit == 0));
- hash = hash * FNV32_PRIME;
- FOR_EACH(i, 0, key->Tinit ? strlen(key->Tinit) * sizeof(*key->Tinit) : 0) {
- hash = hash ^ (uint32_t)((unsigned char)((const char*)key->Tinit)[i]);
- hash = hash * FNV32_PRIME;
- }
- hash = hash ^ (uint32_t)((unsigned char)(key->Temp == 0));
- hash = hash * FNV32_PRIME;
- FOR_EACH(i, 0, key->Temp ? strlen(key->Temp) * sizeof(*key->Temp) : 0) {
- hash = hash ^ (uint32_t)((unsigned char)((const char*)key->Temp)[i]);
- hash = hash * FNV32_PRIME;
- }
- FOR_EACH(i, 0, sizeof(key->has_power)) {
- hash = hash ^ (uint32_t)((unsigned char)((const char*)&key->has_power)[i]);
- hash = hash * FNV32_PRIME;
- }
- if (!key->has_power) return hash;
- FOR_EACH(i, 0, strlen(key->Tinit) * sizeof(*key->power)) {
- hash = hash ^ (uint32_t) ((unsigned char) ((const char*) key->power)[i]);
- hash = hash * FNV32_PRIME;
- }
- return hash;
-#elif defined(ARCH_64BITS)
- /* 64-bits Fowler/Noll/Vo hash function */
- const uint64_t FNV64_PRIME =
- (uint64_t) (((uint64_t) 1 << 40) + ((uint64_t) 1 << 8) + 0xB3);
- const uint64_t OFFSET64_BASIS = (uint64_t) 14695981039346656037u;
- uint64_t hash = OFFSET64_BASIS;
- size_t i;
- ASSERT(key);
- FOR_EACH(i, 0, sizeof(key->name)) {
- hash = hash ^ (uint64_t)((unsigned char)((const char*)&key->name)[i]);
- hash = hash * FNV64_PRIME;
- }
- FOR_EACH(i, 0, sizeof(key->solid_id)) {
- hash = hash ^ (uint64_t)((unsigned char)((const char*)&key->solid_id)[i]);
- hash = hash * FNV64_PRIME;
- }
- FOR_EACH(i, 0, sizeof(key->lambda)) {
- hash = hash ^ (uint64_t)((unsigned char)((const char*)&key->lambda)[i]);
- hash = hash * FNV64_PRIME;
- }
- FOR_EACH(i, 0, sizeof(key->rho)) {
- hash = hash ^ (uint64_t)((unsigned char)((const char*)&key->rho)[i]);
- hash = hash * FNV64_PRIME;
- }
- FOR_EACH(i, 0, sizeof(key->cp)) {
- hash = hash ^ (uint64_t)((unsigned char)((const char*)&key->cp)[i]);
- hash = hash * FNV64_PRIME;
- }
- FOR_EACH(i, 0, sizeof(key->delta)) {
- hash = hash ^ (uint64_t)((unsigned char)((const char*)&key->delta)[i]);
- hash = hash * FNV64_PRIME;
- }
- hash = hash ^ (uint64_t)((unsigned char)(key->Tinit == 0));
- hash = hash * FNV64_PRIME;
- FOR_EACH(i, 0, key->Tinit ? strlen(key->Tinit) * sizeof(*key->Tinit) : 0) {
- hash = hash ^ (uint64_t)((unsigned char)((const char*)key->Tinit)[i]);
- hash = hash * FNV64_PRIME;
- }
- hash = hash ^ (uint64_t)((unsigned char)(key->Temp == 0));
- hash = hash * FNV64_PRIME;
- FOR_EACH(i, 0, key->Temp ? strlen(key->Temp) * sizeof(*key->Temp) : 0) {
- hash = hash ^ (uint64_t)((unsigned char)((const char*)key->Temp)[i]);
- hash = hash * FNV64_PRIME;
- }
- FOR_EACH(i, 0, sizeof(key->has_power)) {
- hash = hash ^ (uint64_t) ((unsigned char) ((const char*) &key->has_power)[i]);
- hash = hash * FNV64_PRIME;
- }
- if (!key->has_power) return hash;
- FOR_EACH(i, 0, strlen(key->power) * sizeof(*key->power)) {
- hash = hash ^ (uint64_t)((unsigned char)((const char*)key->power)[i]);
- hash = hash * FNV64_PRIME;
- }
- return hash;
-#else
-#error "Unexpected architecture"
-#endif
+ str_release(&bound->name);
}
-struct h_boundary {
- char name[32];
- unsigned mat_id;
- double emissivity;
- double specular_fraction;
- double hc;
- double hc_max;
- char* T;
- int has_emissivity, has_hc;
-};
-#define NULL_HBOUND__ { "", UINT_MAX, 0, 0, 0, 0, NULL, 0, 0}
-static const struct h_boundary NULL_HBOUND = NULL_HBOUND__;
-
-static void
-print_h_boundary
- (FILE* stream,
+static res_T
+str_print_h_boundary
+ (struct str* str,
const struct h_boundary* b,
const enum description_type type)
{
- ASSERT(stream && b
- && (type == DESC_BOUND_H_FOR_SOLID || type == DESC_BOUND_H_FOR_FLUID));
- fprintf(stream,
- "H boundary %s for %s: emissivity=%g specular_fraction=%g hc=%g hc_max=%g T='%s'\n",
- b->name,
- (type == DESC_BOUND_H_FOR_SOLID ? "solid" : "fluid"),
- (b->has_emissivity ? b->emissivity : 0),
- (b->has_emissivity ? b->specular_fraction : 0),
- (b->has_hc ? b->hc : 0),
- (b->has_hc ? b->hc_max : 0),
- (b->T ? b->T : "0"));
+ res_T res = RES_OK;
+ ASSERT(str && b && DESC_IS_H(type));
+ STR_APPEND_PRINTF(str,
+ "H boundary for %s '%s': emissivity=%g specular_fraction=%g hc=%g T=%g "
+ "(using medium %u as external medium)",
+ ARG7( (type == DESC_BOUND_H_FOR_SOLID ? "solid" : "fluid"), str_cget(&b->name),
+ b->emissivity, b->specular_fraction, b->hc, b->imposed_temperature, b->mat_id ) );
+end:
+ return res;
+error:
+ goto end;
}
-static char
-eq_h_boundary
- (const struct h_boundary* a,
- const struct h_boundary* b)
+static FINLINE res_T
+cp_h_boundary(struct h_boundary* dst, const struct h_boundary* src)
{
- if (a->mat_id != b->mat_id
- || strcmp(a->name, b->name)
- || a->specular_fraction != b->specular_fraction
- || strcmp(a->T, b->T)
- || a->has_emissivity != b->has_emissivity
- || a->has_hc != b->has_hc)
- return 0;
- if (a->has_emissivity && a->emissivity != b->emissivity) return 0;
- if (a->has_hc && (a->hc != b->hc || a->hc_max != b->hc_max)) return 0;
- return 1;
-}
-
-static size_t
-hash_h_boundary(const struct h_boundary* key)
-{
-#ifdef ARCH_32BITS
- /* 32-bits Fowler/Noll/Vo hash function */
- const uint32_t FNV32_PRIME =
- (uint32_t) (((uint32_t) 1 << 24) + ((uint32_t) 1 << 8) + 0x93);
- const uint32_t OFFSET32_BASIS = 2166136261u;
- uint32_t hash = OFFSET32_BASIS;
- size_t i;
- ASSERT(key);
- FOR_EACH(i, 0, sizeof(key->name)) {
- hash = hash ^ (uint32_t)((unsigned char)((const char*)&key->name)[i]);
- hash = hash * FNV32_PRIME;
- }
- FOR_EACH(i, 0, sizeof(key->mat_id)) {
- hash = hash ^ (uint32_t)((unsigned char)((const char*)&key->mat_id)[i]);
- hash = hash * FNV32_PRIME;
- }
- FOR_EACH(i, 0, sizeof(key->emissivity)) {
- hash = hash ^ (uint32_t)((unsigned char)((const char*)&key->emissivity)[i]);
- hash = hash * FNV32_PRIME;
- }
- FOR_EACH(i, 0, sizeof(key->specular_fraction)) {
- hash = hash ^ (uint32_t)((unsigned char)((const char*)&key->specular_fraction)[i]);
- hash = hash * FNV32_PRIME;
- }
- FOR_EACH(i, 0, strlen(key->T) * sizeof(*key->T)) {
- hash = hash ^ (uint32_t)((unsigned char)((const char*)key->T)[i]);
- hash = hash * FNV32_PRIME;
- }
- FOR_EACH(i, 0, sizeof(key->has_emissivity)) {
- hash = hash ^ (uint32_t)((unsigned char)((const char*)&key->has_emissivity)[i]);
- hash = hash * FNV32_PRIME;
- }
- FOR_EACH(i, 0, sizeof(key->has_hc)) {
- hash = hash ^ (uint32_t) ((unsigned char) ((const char*) &key->has_hc)[i]);
- hash = hash * FNV32_PRIME;
- }
- if (!key->has_hc) return hash;
- FOR_EACH(i, 0, sizeof(key->hc)) {
- hash = hash ^ (uint32_t) ((unsigned char) ((const char*) &key->hc)[i]);
- hash = hash * FNV32_PRIME;
- }
- FOR_EACH(i, 0, sizeof(key->hc_max)) {
- hash = hash ^ (uint32_t) ((unsigned char) ((const char*) &key->hc_max)[i]);
- hash = hash * FNV32_PRIME;
- }
- return hash;
-#elif defined(ARCH_64BITS)
- /* 64-bits Fowler/Noll/Vo hash function */
- const uint64_t FNV64_PRIME =
- (uint64_t) (((uint64_t) 1 << 40) + ((uint64_t) 1 << 8) + 0xB3);
- const uint64_t OFFSET64_BASIS = (uint64_t) 14695981039346656037u;
- uint64_t hash = OFFSET64_BASIS;
- size_t i;
- ASSERT(key);
- FOR_EACH(i, 0, sizeof(key->name)) {
- hash = hash ^ (uint64_t)((unsigned char)((const char*)&key->name)[i]);
- hash = hash * FNV64_PRIME;
- }
- FOR_EACH(i, 0, sizeof(key->mat_id)) {
- hash = hash ^ (uint32_t)((unsigned char)((const char*)&key->mat_id)[i]);
- hash = hash * FNV64_PRIME;
- }
- FOR_EACH(i, 0, sizeof(key->emissivity)) {
- hash = hash ^ (uint32_t)((unsigned char)((const char*)&key->emissivity)[i]);
- hash = hash * FNV64_PRIME;
- }
- FOR_EACH(i, 0, sizeof(key->specular_fraction)) {
- hash = hash ^ (uint32_t)((unsigned char)((const char*)&key->specular_fraction)[i]);
- hash = hash * FNV64_PRIME;
- }
- FOR_EACH(i, 0, strlen(key->T) * sizeof(*key->T)) {
- hash = hash ^ (uint32_t)((unsigned char)((const char*)key->T)[i]);
- hash = hash * FNV64_PRIME;
- }
- FOR_EACH(i, 0, sizeof(key->has_emissivity)) {
- hash = hash ^ (uint32_t)((unsigned char)((const char*)&key->has_emissivity)[i]);
- hash = hash * FNV64_PRIME;
- }
- FOR_EACH(i, 0, sizeof(key->has_hc)) {
- hash = hash ^ (uint32_t) ((unsigned char) ((const char*) &key->has_hc)[i]);
- hash = hash * FNV64_PRIME;
- }
- if (!key->has_hc) return hash;
- FOR_EACH(i, 0, sizeof(key->hc)) {
- hash = hash ^ (uint32_t) ((unsigned char) ((const char*) &key->hc)[i]);
- hash = hash * FNV64_PRIME;
- }
- FOR_EACH(i, 0, sizeof(key->hc_max)) {
- hash = hash ^ (uint32_t) ((unsigned char) ((const char*) &key->hc_max)[i]);
- hash = hash * FNV64_PRIME;
- }
- return hash;
-#else
-#error "Unexpected architecture"
-#endif
+ dst->specular_fraction = src->specular_fraction;
+ dst->imposed_temperature = src->imposed_temperature;
+ dst->emissivity = src->emissivity;
+ dst->hc = src->hc;
+ dst->mat_id = src->mat_id;
+ return str_copy(&dst->name, &src->name);
}
struct t_boundary {
- char name[32];
- unsigned mat_id;
- char* T;
- struct te_expr* te_temperature;
+ struct str name;
+ double emissivity;
+ double specular_fraction;
double hc;
- double hc_max;
- int has_hc;
+ double imposed_temperature;
+ unsigned mat_id;
};
-#define NULL_TBOUND__ { "", UINT_MAX, NULL, NULL, 0, 0, 0}
-static const struct t_boundary NULL_TBOUND = NULL_TBOUND__;
-static void
-print_t_boundary
- (FILE* stream,
- const struct t_boundary* b,
- const enum description_type type)
+static FINLINE void
+init_t(struct mem_allocator* allocator, struct t_boundary* dst)
+{
+ str_init(allocator, &dst->name);
+ dst->emissivity = 0;
+ dst->specular_fraction = 0;
+ dst->hc = 0;
+ dst->imposed_temperature = -1;
+ dst->mat_id = UINT_MAX;
+}
+
+static FINLINE void
+release_t_boundary(struct t_boundary* bound)
{
- ASSERT(stream && b
- && (type == DESC_BOUND_T_FOR_SOLID || type == DESC_BOUND_T_FOR_FLUID));
- fprintf(stream,
- "T boundary %s for %s: hc=%g hc_max=%g T='%s'\n",
- b->name,
- (type == DESC_BOUND_T_FOR_SOLID ? "solid" : "fluid"),
- (b->has_hc ? b->hc : 0),
- (b->has_hc ? b->hc_max : 0),
- (b->T ? b->T : "0"));
+ str_release(&bound->name);
}
-static char
-eq_t_boundary
- (const struct t_boundary* a,
+static res_T
+str_print_t_boundary
+ (struct str* str,
const struct t_boundary* b,
const enum description_type type)
{
- ASSERT(type == DESC_BOUND_T_FOR_SOLID || type == DESC_BOUND_T_FOR_FLUID);
- /* These fields are meaningful by both types */
- if (strcmp(a->name, b->name))
- return 0;
- if (a->mat_id != b->mat_id || strcmp(a->T, b->T))
- return 0;
- if (type != DESC_BOUND_T_FOR_FLUID)
- return 1;
- /* These ones are only relevant for fluids */
- if (a->has_hc != b->has_hc)
- return 0;
- if (a->has_hc && (a->hc != b->hc || a->hc_max != b->hc_max))
- return 0;
- return 1;
+ res_T res = RES_OK;
+ ASSERT(str && b && DESC_IS_T(type));
+ STR_APPEND_PRINTF(str, "T boundary for %s '%s': T=%g ",
+ ARG3( (type == DESC_BOUND_T_FOR_SOLID ? "solid" : "fluid"),
+ str_cget(&b->name), b->imposed_temperature ) );
+
+ if(type == DESC_BOUND_T_FOR_FLUID) {
+ STR_APPEND_PRINTF(str, "emissivity=%g, specular_fraction=%g hc=%g ",
+ ARG3( b->emissivity, b->specular_fraction, b->hc ) );
+ }
+ STR_APPEND_PRINTF(str, "(using medium %u as external medium)",
+ ARG1( b->mat_id ) );
+end:
+ return res;
+error:
+ goto end;
}
-static size_t
-hash_t_boundary
- (const struct t_boundary* key,
- const enum description_type type)
+static FINLINE res_T
+cp_t_boundary(struct t_boundary* dst, const struct t_boundary* src)
{
- (void)type;
- ASSERT(type == DESC_BOUND_T_FOR_SOLID || type == DESC_BOUND_T_FOR_FLUID);
-#ifdef ARCH_32BITS
- /* 32-bits Fowler/Noll/Vo hash function */
- const uint32_t FNV32_PRIME =
- (uint32_t) (((uint32_t) 1 << 24) + ((uint32_t) 1 << 8) + 0x93);
- const uint32_t OFFSET32_BASIS = 2166136261u;
- uint32_t hash = OFFSET32_BASIS;
- size_t i;
- ASSERT(key);
- FOR_EACH(i, 0, sizeof(key->name)) {
- hash = hash ^ (uint32_t)((unsigned char)((const char*)&key->name)[i]);
- hash = hash * FNV32_PRIME;
- }
- FOR_EACH(i, 0, sizeof(key->mat_id)) {
- hash = hash ^ (uint32_t)((unsigned char)((const char*)&key->mat_id)[i]);
- hash = hash * FNV32_PRIME;
- }
- FOR_EACH(i, 0, sizeof(key->has_hc)) {
- hash = hash ^ (uint32_t) ((unsigned char) ((const char*) &key->has_hc)[i]);
- hash = hash * FNV32_PRIME;
- }
- FOR_EACH(i, 0, strlen(key->T) * sizeof(*key->T)) {
- hash = hash ^ (uint32_t) ((unsigned char) ((const char*) key->T)[i]);
- hash = hash * FNV32_PRIME;
- }
- if (!key->has_hc) return hash;
- FOR_EACH(i, 0, sizeof(key->hc)) {
- hash = hash ^ (uint32_t) ((unsigned char) ((const char*) &key->hc)[i]);
- hash = hash * FNV32_PRIME;
- }
- FOR_EACH(i, 0, sizeof(key->hc_max)) {
- hash = hash ^ (uint32_t)((unsigned char)((const char*)&key->hc_max)[i]);
- hash = hash * FNV32_PRIME;
- }
- return hash;
-#elif defined(ARCH_64BITS)
- /* 64-bits Fowler/Noll/Vo hash function */
- const uint64_t FNV64_PRIME =
- (uint64_t) (((uint64_t) 1 << 40) + ((uint64_t) 1 << 8) + 0xB3);
- const uint64_t OFFSET64_BASIS = (uint64_t) 14695981039346656037u;
- uint64_t hash = OFFSET64_BASIS;
- size_t i;
- ASSERT(key);
- FOR_EACH(i, 0, sizeof(key->name)) {
- hash = hash ^ (uint64_t)((unsigned char)((const char*)&key->name)[i]);
- hash = hash * FNV64_PRIME;
- }
- FOR_EACH(i, 0, sizeof(key->mat_id)) {
- hash = hash ^ (uint32_t)((unsigned char)((const char*)&key->mat_id)[i]);
- hash = hash * FNV64_PRIME;
- }
- FOR_EACH(i, 0, sizeof(key->has_hc)) {
- hash = hash ^ (uint32_t) ((unsigned char) ((const char*) &key->has_hc)[i]);
- hash = hash * FNV64_PRIME;
- }
- FOR_EACH(i, 0, strlen(key->T) * sizeof(*key->T)) {
- hash = hash ^ (uint32_t) ((unsigned char) ((const char*) key->T)[i]);
- hash = hash * FNV64_PRIME;
- }
- if (!key->has_hc) return hash;
- FOR_EACH(i, 0, sizeof(key->hc)) {
- hash = hash ^ (uint32_t)((unsigned char)((const char*)&key->hc)[i]);
- hash = hash * FNV64_PRIME;
- }
- FOR_EACH(i, 0, sizeof(key->hc_max)) {
- hash = hash ^ (uint32_t)((unsigned char)((const char*)&key->hc_max)[i]);
- hash = hash * FNV64_PRIME;
- }
- return hash;
-#else
-#error "Unexpected architecture"
-#endif
+ dst->emissivity = src->emissivity;
+ dst->specular_fraction = src->specular_fraction;
+ dst->hc = src->hc;
+ dst->imposed_temperature = src->imposed_temperature;
+ dst->mat_id = src->mat_id;
+ return str_copy(&dst->name, &src->name);
}
struct f_boundary {
- char name[32];
+ struct str name;
+ double imposed_flux;
unsigned mat_id;
- char* flux;
- struct te_expr* te_flux;
};
-#define NULL_FBOUND__ { "", UINT_MAX, NULL, NULL}
-static const struct f_boundary NULL_FBOUND = NULL_FBOUND__;
-static void
-print_f_boundary
- (FILE* stream,
- const struct f_boundary* b,
- const enum description_type type)
+static FINLINE void
+init_f(struct mem_allocator* allocator, struct f_boundary* dst)
{
- ASSERT(stream && b && type == DESC_BOUND_F_FOR_SOLID); (void)type;
- fprintf(stream,
- "F boundary %s for SOLID: flux='%s'\n",
- b->name,
- (b->flux ? b->flux : "0"));
+ str_init(allocator, &dst->name);
+ dst->mat_id = UINT_MAX;
+ dst->imposed_flux = -1;
}
-static char
-eq_f_boundary(const struct f_boundary* a, const struct f_boundary* b)
+static FINLINE void
+release_f_boundary(struct f_boundary* bound)
{
- return (a->mat_id == b->mat_id
- && 0 == strcmp(a->name, b->name)
- && 0 == strcmp(a->flux, b->flux));
+ str_release(&bound->name);
}
-static size_t
-hash_f_boundary(const struct f_boundary* key)
+static res_T
+str_print_f_boundary
+ (struct str* str,
+ const struct f_boundary* b)
{
-#ifdef ARCH_32BITS
- /* 32-bits Fowler/Noll/Vo hash function */
- const uint32_t FNV32_PRIME =
- (uint32_t) (((uint32_t) 1 << 24) + ((uint32_t) 1 << 8) + 0x93);
- const uint32_t OFFSET32_BASIS = 2166136261u;
- uint32_t hash = OFFSET32_BASIS;
- size_t i;
- ASSERT(key);
- FOR_EACH(i, 0, sizeof(key->name)) {
- hash = hash ^ (uint32_t)((unsigned char)((const char*)&key->name)[i]);
- hash = hash * FNV32_PRIME;
- }
- FOR_EACH(i, 0, sizeof(key->mat_id)) {
- hash = hash ^ (uint32_t)((unsigned char)((const char*)&key->mat_id)[i]);
- hash = hash * FNV32_PRIME;
- }
- FOR_EACH(i, 0, strlen(key->flux) * sizeof(*key->flux)) {
- hash = hash ^ (uint32_t)((unsigned char)((const char*)key->flux)[i]);
- hash = hash * FNV32_PRIME;
- }
- return hash;
-#elif defined(ARCH_64BITS)
- /* 64-bits Fowler/Noll/Vo hash function */
- const uint64_t FNV64_PRIME =
- (uint64_t) (((uint64_t) 1 << 40) + ((uint64_t) 1 << 8) + 0xB3);
- const uint64_t OFFSET64_BASIS = (uint64_t) 14695981039346656037u;
- uint64_t hash = OFFSET64_BASIS;
- size_t i;
- ASSERT(key);
- FOR_EACH(i, 0, sizeof(key->name)) {
- hash = hash ^ (uint64_t)((unsigned char)((const char*)&key->name)[i]);
- hash = hash * FNV64_PRIME;
- }
- FOR_EACH(i, 0, sizeof(key->mat_id)) {
- hash = hash ^ (uint32_t)((unsigned char)((const char*)&key->mat_id)[i]);
- hash = hash * FNV64_PRIME;
- }
- FOR_EACH(i, 0, strlen(key->flux) * sizeof(*key->flux)) {
- hash = hash ^ (uint32_t)((unsigned char)((const char*)key->flux)[i]);
- hash = hash * FNV64_PRIME;
- }
- return hash;
-#else
-#error "Unexpected architecture"
-#endif
+ res_T res = RES_OK;
+ ASSERT(str && b);
+ STR_APPEND_PRINTF(str,
+ "F boundary for SOLID '%s': flux=%g (using medium %u as external medium)",
+ ARG3( str_cget(&b->name), b->imposed_flux, b->mat_id ) );
+end:
+ return res;
+error:
+ goto end;
+}
+
+static FINLINE res_T
+cp_f_boundary(struct f_boundary* dst, const struct f_boundary* src)
+{
+ dst->imposed_flux = src->imposed_flux;
+ dst->mat_id = src->mat_id;
+ return str_copy(&dst->name, &src->name);
}
struct solid_fluid_connect {
- char name[32];
+ struct str name;
double emissivity;
double specular_fraction;
double hc;
- double hc_max;
- int has_emissivity, has_hc;
+ unsigned connection_id;
};
-#define NULL_SFCONNECT__ { "", 0, 0, 0, 0, 0, 0}
-static const struct solid_fluid_connect NULL_SFCONNECT = NULL_SFCONNECT__;
-static char
-eq_sf_connect(const struct solid_fluid_connect* a, const struct solid_fluid_connect* b)
+static FINLINE void
+release_sf_connect(struct solid_fluid_connect* connect)
{
- return (char)(!strcmp(a->name, b->name)
- && a->emissivity == b->emissivity
- && a->specular_fraction == b->specular_fraction
- && a->hc == b->hc
- && a->hc_max == b->hc_max
- && a->has_emissivity == b->has_emissivity
- && a->has_hc == b->has_hc);
+ str_release(&connect->name);
}
-static size_t
-hash_sf_connect(const struct solid_fluid_connect* key)
+static FINLINE void
+init_sf(struct mem_allocator* allocator, struct solid_fluid_connect* dst)
{
-#ifdef ARCH_32BITS
- /* 32-bits Fowler/Noll/Vo hash function */
- const uint32_t FNV32_PRIME =
- (uint32_t) (((uint32_t) 1 << 24) + ((uint32_t) 1 << 8) + 0x93);
- const uint32_t OFFSET32_BASIS = 2166136261u;
- uint32_t hash = OFFSET32_BASIS;
- size_t i;
- ASSERT(key);
- FOR_EACH(i, 0, sizeof(key->name)) {
- hash = hash ^ (uint32_t)((unsigned char)((const char*)&key->name)[i]);
- hash = hash * FNV32_PRIME;
- }
- FOR_EACH(i, 0, sizeof(key->emissivity)) {
- hash = hash ^ (uint32_t)((unsigned char)((const char*)&key->emissivity)[i]);
- hash = hash * FNV32_PRIME;
- }
- FOR_EACH(i, 0, sizeof(key->specular_fraction)) {
- hash = hash ^ (uint32_t)((unsigned char)((const char*)&key->specular_fraction)[i]);
- hash = hash * FNV32_PRIME;
- }
- FOR_EACH(i, 0, sizeof(key->hc)) {
- hash = hash ^ (uint32_t)((unsigned char)((const char*)&key->hc)[i]);
- hash = hash * FNV32_PRIME;
- }
- FOR_EACH(i, 0, sizeof(key->hc_max)) {
- hash = hash ^ (uint32_t)((unsigned char)((const char*)&key->hc_max)[i]);
- hash = hash * FNV32_PRIME;
- }
- FOR_EACH(i, 0, sizeof(key->has_emissivity)) {
- hash = hash ^ (uint32_t)((unsigned char)((const char*)&key->has_emissivity)[i]);
- hash = hash * FNV32_PRIME;
- }
- FOR_EACH(i, 0, sizeof(key->has_hc)) {
- hash = hash ^ (uint32_t)((unsigned char)((const char*)&key->has_hc)[i]);
- hash = hash * FNV32_PRIME;
- }
- return hash;
-#elif defined(ARCH_64BITS)
- /* 64-bits Fowler/Noll/Vo hash function */
- const uint64_t FNV64_PRIME =
- (uint64_t) (((uint64_t) 1 << 40) + ((uint64_t) 1 << 8) + 0xB3);
- const uint64_t OFFSET64_BASIS = (uint64_t) 14695981039346656037u;
- uint64_t hash = OFFSET64_BASIS;
- size_t i;
- ASSERT(key);
- FOR_EACH(i, 0, sizeof(key->name)) {
- hash = hash ^ (uint64_t)((unsigned char)((const char*)&key->name)[i]);
- hash = hash * FNV64_PRIME;
- }
- FOR_EACH(i, 0, sizeof(key->emissivity)) {
- hash = hash ^ (uint32_t)((unsigned char)((const char*)&key->emissivity)[i]);
- hash = hash * FNV64_PRIME;
- }
- FOR_EACH(i, 0, sizeof(key->specular_fraction)) {
- hash = hash ^ (uint32_t)((unsigned char)((const char*)&key->specular_fraction)[i]);
- hash = hash * FNV64_PRIME;
- }
- FOR_EACH(i, 0, sizeof(key->hc)) {
- hash = hash ^ (uint32_t)((unsigned char)((const char*)&key->hc)[i]);
- hash = hash * FNV64_PRIME;
- }
- FOR_EACH(i, 0, sizeof(key->hc_max)) {
- hash = hash ^ (uint32_t)((unsigned char)((const char*)&key->hc_max)[i]);
- hash = hash * FNV64_PRIME;
- }
- FOR_EACH(i, 0, sizeof(key->has_emissivity)) {
- hash = hash ^ (uint32_t)((unsigned char)((const char*)&key->has_emissivity)[i]);
- hash = hash * FNV64_PRIME;
- }
- FOR_EACH(i, 0, sizeof(key->has_hc)) {
- hash = hash ^ (uint32_t)((unsigned char)((const char*)&key->has_hc)[i]);
- hash = hash * FNV64_PRIME;
- }
- return hash;
-#else
-#error "Unexpected architecture"
-#endif
+ str_init(allocator, &dst->name);
+ dst->emissivity = 0;
+ dst->specular_fraction = 0;
+ dst->hc = 0;
+ dst->connection_id = UINT_MAX;
+}
+
+static res_T
+str_print_sf_connect
+ (struct str* str,
+ const struct solid_fluid_connect* c)
+{
+ res_T res = RES_OK;
+ ASSERT(str && c);
+ STR_APPEND_PRINTF(str, "Solid-Fluid connection '%s':", ARG1( str_cget(&c->name) ) );
+ STR_APPEND_PRINTF(str, " emissivity=%g, specular_fraction=%g hc=%g",
+ ARG3( c->emissivity, c->specular_fraction, c->hc ) );
+end:
+ return res;
+error:
+ goto end;
+}
+
+static FINLINE res_T
+cp_sf_connect
+ (struct solid_fluid_connect* dst, const struct solid_fluid_connect* src)
+{
+ dst->connection_id = src->connection_id;
+ dst->specular_fraction = src->specular_fraction;
+ dst->emissivity = src->emissivity;
+ dst->hc = src->hc;
+ return str_copy(&dst->name, &src->name);
+}
+
+static FINLINE res_T
+cp_release_sf_connect
+ (struct solid_fluid_connect* dst, struct solid_fluid_connect* src)
+{
+ return cp_sf_connect(dst, src);
}
struct description {
enum description_type type;
- union d {
- struct mat_fluid fluid;
- struct mat_solid solid;
+ union {
+ struct fluid fluid;
+ struct solid solid;
struct t_boundary t_boundary;
struct f_boundary f_boundary;
struct h_boundary h_boundary;
@@ -876,163 +427,355 @@ struct description {
} d;
};
-FINLINE void
-init_description(struct description* desc) {
+static FINLINE res_T
+init_description(struct mem_allocator* alloc, struct description* desc)
+{
ASSERT(desc);
+ (void)alloc;
desc->type = DESCRIPTION_TYPE_COUNT__;
+ return RES_OK;
}
-static INLINE void
-print_description
- (FILE* stream,
- struct description* desc)
+static FINLINE void
+release_description(struct description* desc)
+{
+ switch (desc->type) {
+ case DESC_MAT_SOLID:
+ release_solid(&desc->d.solid);
+ break;
+ case DESC_MAT_FLUID:
+ release_fluid(&desc->d.fluid);
+ break;
+ case DESC_BOUND_H_FOR_SOLID:
+ case DESC_BOUND_H_FOR_FLUID:
+ release_h_boundary(&desc->d.h_boundary);
+ break;
+ case DESC_BOUND_T_FOR_SOLID:
+ case DESC_BOUND_T_FOR_FLUID:
+ release_t_boundary(&desc->d.t_boundary);
+ break;
+ case DESC_BOUND_F_FOR_SOLID:
+ release_f_boundary(&desc->d.f_boundary);
+ break;
+ case DESC_SOLID_FLUID_CONNECT:
+ release_sf_connect(&desc->d.sf_connect);
+ break;
+ default:
+ FATAL("error:" STR(__FILE__) ":" STR(__LINE__)": Invalid type.\n");
+ }
+}
+
+static INLINE res_T
+str_print_description
+ (struct str* str,
+ const unsigned rank,
+ const struct description* desc)
{
- ASSERT(stream && desc);
+ res_T res = RES_OK;
+ ASSERT(str && desc);
+ str_clear(str);
+ ERR(str_printf(str, "Description %u: ", rank));
switch (desc->type) {
case DESC_MAT_SOLID:
- print_solid(stream, &desc->d.solid);
+ ERR(str_print_solid(str, &desc->d.solid));
break;
case DESC_MAT_FLUID:
- print_fluid(stream, &desc->d.fluid);
+ ERR(str_print_fluid(str, &desc->d.fluid));
break;
case DESC_BOUND_T_FOR_SOLID:
case DESC_BOUND_T_FOR_FLUID:
- print_t_boundary(stream, &desc->d.t_boundary, desc->type);
+ ERR(str_print_t_boundary(str, &desc->d.t_boundary, desc->type));
break;
case DESC_BOUND_H_FOR_SOLID:
case DESC_BOUND_H_FOR_FLUID:
- print_h_boundary(stream, &desc->d.h_boundary, desc->type);
+ ERR(str_print_h_boundary(str, &desc->d.h_boundary, desc->type));
break;
case DESC_BOUND_F_FOR_SOLID:
- print_f_boundary(stream, &desc->d.f_boundary, desc->type);
+ ERR(str_print_f_boundary(str, &desc->d.f_boundary));
+ break;
+ case DESC_SOLID_FLUID_CONNECT:
+ ERR(str_print_sf_connect(str, &desc->d.sf_connect));
break;
- default: FATAL("Invalid type.\n");
+ default:
+ FATAL("error:" STR(__FILE__) ":" STR(__LINE__)": Invalid type.\n");
+ }
+end:
+ return res;
+error:
+ goto end;
+}
+
+static INLINE const struct str*
+get_description_name
+ (const struct description* desc)
+{
+ ASSERT(desc);
+ switch (desc->type) {
+ case DESC_MAT_SOLID:
+ return &desc->d.solid.name;
+ case DESC_MAT_FLUID:
+ return &desc->d.fluid.name;
+ case DESC_BOUND_T_FOR_SOLID:
+ case DESC_BOUND_T_FOR_FLUID:
+ return &desc->d.t_boundary.name;
+ case DESC_BOUND_H_FOR_SOLID:
+ case DESC_BOUND_H_FOR_FLUID:
+ return &desc->d.h_boundary.name;
+ case DESC_BOUND_F_FOR_SOLID:
+ return &desc->d.f_boundary.name;
+ case DESC_SOLID_FLUID_CONNECT:
+ return &desc->d.sf_connect.name;
+ default:
+ FATAL("error:" STR(__FILE__) ":" STR(__LINE__)": Invalid type.\n");
}
}
-static INLINE char
-eq_description(const struct description* a, const struct description* b)
+static FINLINE res_T
+cp_description
+ (struct description* dst,
+ const struct description* src)
{
- if (a->type != b->type) return 0;
- switch (a->type) {
+ res_T res = RES_OK;
+ ASSERT(src && dst);
+ switch (src->type) {
case DESC_MAT_SOLID:
- return eq_solid(&a->d.solid, &b->d.solid);
+ if(dst->type == DESCRIPTION_TYPE_COUNT__) {
+ dst->type = src->type;
+ init_solid(src->d.solid.name.allocator, &dst->d.solid);
+ }
+ ERR(cp_solid(&dst->d.solid, &src->d.solid));
+ break;
case DESC_MAT_FLUID:
- return eq_fluid(&a->d.fluid, &b->d.fluid);
+ if(dst->type == DESCRIPTION_TYPE_COUNT__) {
+ dst->type = src->type;
+ init_fluid(src->d.fluid.name.allocator, &dst->d.fluid);
+ }
+ ERR(cp_fluid(&dst->d.fluid, &src->d.fluid));
+ break;
case DESC_BOUND_H_FOR_SOLID:
case DESC_BOUND_H_FOR_FLUID:
- return eq_h_boundary(&a->d.h_boundary, &b->d.h_boundary);
+ if(dst->type == DESCRIPTION_TYPE_COUNT__) {
+ dst->type = src->type;
+ init_h(src->d.h_boundary.name.allocator, &dst->d.h_boundary);
+ }
+ ERR(cp_h_boundary(&dst->d.h_boundary, &src->d.h_boundary));
+ break;
case DESC_BOUND_T_FOR_SOLID:
case DESC_BOUND_T_FOR_FLUID:
- return eq_t_boundary(&a->d.t_boundary, &b->d.t_boundary, a->type);
+ if(dst->type == DESCRIPTION_TYPE_COUNT__) {
+ dst->type = src->type;
+ init_t(src->d.t_boundary.name.allocator, &dst->d.t_boundary);
+ }
+ ERR(cp_t_boundary(&dst->d.t_boundary, &src->d.t_boundary));
+ break;
case DESC_BOUND_F_FOR_SOLID:
- return eq_f_boundary(&a->d.f_boundary, &b->d.f_boundary);
+ if(dst->type == DESCRIPTION_TYPE_COUNT__) {
+ dst->type = src->type;
+ init_f(src->d.f_boundary.name.allocator, &dst->d.f_boundary);
+ }
+ ERR(cp_f_boundary(&dst->d.f_boundary, &src->d.f_boundary));
+ break;
case DESC_SOLID_FLUID_CONNECT:
- return eq_sf_connect(&a->d.sf_connect, &b->d.sf_connect);
- default: FATAL("Invalid type.\n");
+ if(dst->type == DESCRIPTION_TYPE_COUNT__) {
+ dst->type = src->type;
+ init_sf(src->d.sf_connect.name.allocator, &dst->d.sf_connect);
+ }
+ ERR(cp_sf_connect(&dst->d.sf_connect, &src->d.sf_connect));
+ break;
+ default:
+ FATAL("error:" STR(__FILE__) ":" STR(__LINE__)": Invalid type.\n");
}
+end:
+ return res;
+error:
+ goto end;
}
-static INLINE size_t
-hash_description(const struct description* key)
+static FINLINE void
+description_get_medium_id
+ (const struct description* desc,
+ unsigned* id)
{
- switch (key->type) {
+ ASSERT(desc && id);
+ switch (desc->type) {
case DESC_MAT_SOLID:
- return hash_solid(&key->d.solid);
+ *id = desc->d.solid.solid_id;
+ return;
case DESC_MAT_FLUID:
- return hash_fluid(&key->d.fluid);
+ *id = desc->d.fluid.fluid_id;
+ return;
case DESC_BOUND_H_FOR_SOLID:
case DESC_BOUND_H_FOR_FLUID:
- return hash_h_boundary(&key->d.h_boundary);
+ *id = desc->d.h_boundary.mat_id;
+ return;
case DESC_BOUND_T_FOR_SOLID:
case DESC_BOUND_T_FOR_FLUID:
- return hash_t_boundary(&key->d.t_boundary, key->type);
+ *id = desc->d.t_boundary.mat_id;
+ return;
case DESC_BOUND_F_FOR_SOLID:
- return hash_f_boundary(&key->d.f_boundary);
- case DESC_SOLID_FLUID_CONNECT:
- return hash_sf_connect(&key->d.sf_connect);
- default: FATAL("Invalid type.\n");
+ *id = desc->d.f_boundary.mat_id;
+ return;
+ case DESC_SOLID_FLUID_CONNECT: /* No medium linked to SF */
+ default:
+ FATAL("error:" STR(__FILE__) ":" STR(__LINE__)": Invalid type.\n");
}
}
+enum stardis_output_fmt {
+ STARDIS_RENDERING_OUTPUT_FILE_FMT_VTK,
+ STARDIS_RENDERING_OUTPUT_FILE_FMT_HT
+};
+
struct camera {
double pos[3];
double tgt[3];
double up[3];
+ enum stardis_output_fmt fmt;
double fov;
+ double time_range[2];
unsigned spp;
- unsigned img[2];
- union { /* Trick to allow static initialization with INF */
- uint64_t t;
- double time;
- } u;
+ unsigned img_width, img_height;
+ int auto_look_at;
};
-#define NULL_CAMERA__ {\
- {1,1,1},{0,0,0},{0,0,1},30,4,{640,480},\
- { 0x7FF0000000000000 } /* time=INF */\
-}
-static const struct camera NULL_CAMERA = NULL_CAMERA__;
-
-struct solve_boundary {
- size_t* primitives;
- enum sdis_side* sides;
+
+static INLINE void
+init_camera(struct camera* cam) {
+ d3(cam->pos, STARDIS_DEFAULT_RENDERING_POS);
+ d3(cam->tgt, STARDIS_DEFAULT_RENDERING_TGT);
+ d3(cam->up, STARDIS_DEFAULT_RENDERING_UP);
+ cam->fmt = STARDIS_DEFAULT_RENDERING_OUTPUT_FILE_FMT;
+ cam->fov = STARDIS_DEFAULT_RENDERING_FOV;
+ cam->spp = STARDIS_DEFAULT_RENDERING_SPP;
+ cam->img_width = STARDIS_DEFAULT_RENDERING_IMG_WIDTH;
+ cam->img_height = STARDIS_DEFAULT_RENDERING_IMG_HEIGHT;
+ d2(cam->time_range, STARDIS_DEFAULT_RENDERING_TIME);
+ cam->auto_look_at = 1;
+}
+
+static INLINE void
+log_err_fn(const char* msg, void* ctx)
+{
+ ASSERT(msg);
+ (void)ctx;
+#ifdef OS_WINDOWS
+ fprintf(stderr, "error: %s", msg);
+#else
+ fprintf(stderr, "\x1b[31merror:\x1b[0m %s", msg);
+#endif
+}
+
+static INLINE void
+log_warn_fn(const char* msg, void* ctx)
+{
+ ASSERT(msg);
+ (void)ctx;
+#ifdef OS_WINDOWS
+ fprintf(stderr, "warning: %s", msg);
+#else
+ fprintf(stderr, "\x1b[33mwarning:\x1b[0m %s", msg);
+#endif
+}
+
+static INLINE void
+log_prt_fn(const char* msg, void* ctx)
+{
+ ASSERT(msg);
+ (void)ctx;
+#ifdef OS_WINDOWS
+ fprintf(stderr, "message: %s", msg);
+#else
+ fprintf(stderr, "\x1b[32moutput:\x1b[0m %s", msg);
+#endif
+}
+
+struct counts {
+ unsigned smed_count, fmed_count, tbound_count, hbound_count,
+ fbound_count, sfconnect_count;
+};
+#define COUNTS_NULL__ {\
+ 0, 0, 0, 0, 0, 0\
+ }
+
+/* Type to store the primitives of a compute region */
+#define DARRAY_NAME sides
+#define DARRAY_DATA enum sdis_side
+#include <rsys/dynamic_array.h>
+
+#define DARRAY_NAME descriptions
+#define DARRAY_DATA struct description
+#define DARRAY_FUNCTOR_INIT init_description
+#define DARRAY_FUNCTOR_COPY cp_description
+#define DARRAY_FUNCTOR_RELEASE release_description
+#include <rsys/dynamic_array.h>
+
+struct compute_surface {
+ struct darray_size_t primitives;
+ struct darray_sides sides;
+ struct darray_uint err_triangles;
};
struct stardis {
struct geometry geometry;
- struct description* descriptions; /*array of materials and boundaries */
-
- double probe[4]; /* x,y,z,t of probe when mode is PROBE_COMPUTE */
+ struct sdis_scene* sdis_scn; /* The solver scene */
+ struct darray_descriptions descriptions; /* Materials and boundaries */
+ struct darray_media_ptr media;
+ struct senc3d_scene* senc3d_scn;
+ struct counts counts;
+
+ double probe[3]; /* x,y,z of probe when mode is PROBE_COMPUTE */
+ double time_range[2]; /* compute time */
struct camera camera; /* camera when mode is IR_COMPUTE */
- char solve_name[64]; /* medium name when mode is MEDIUM_COMPUTE,
- boundary file name when BOUNDARY_COMPUTE*/
- struct solve_boundary boundary; /* Boundary to solve when mode
- is BOUNDARY_COMPUTE */
-
- size_t N; /*number of MC realizations*/
+ struct str solve_name; /* medium name when mode is MEDIUM_COMPUTE,
+ boundary file name when [FLUX_]BOUNDARY_COMPUTE
+ map file name when MAP_COMPUTE */
+ struct compute_surface compute_surface; /* 2D compute region when mode is
+ [FLUX_]BOUNDARY_COMPUTE
+ or MAP_COMPUTE */
+ struct str paths_filename;
+ struct str bin_green_filename;
+ struct str end_paths_filename;
+ struct str chunks_prefix;
+ int mode;
+ size_t samples;
unsigned nthreads;
double scale_factor;
- double radiative_temp[2];
- struct mem_allocator allocator;
- int allocator_initialized;
- enum sdis_heat_path_flag dump_paths;
-};
-#define NULL_ALLOCATOR__ {NULL}
-#define NULL_STARDIS__ {\
- NULL_GEOMETRY__, NULL,\
- {0,0,0,0}, NULL_CAMERA__, "", {NULL,NULL},\
- 0, 0, 0, {300,300}, NULL_ALLOCATOR__, 0, SDIS_HEAT_PATH_NONE}
-static const struct stardis NULL_STARDIS = NULL_STARDIS__;
-
-enum content_type {
- CONTENT_GEOMETRY,
- CONTENT_CONNECTION,
- CONTENT_BOUNDARY,
- CONTENT_TYPES_COUNT
+ double ambient_temp, ref_temp;
+ struct mem_allocator* allocator;
+ struct logger* logger;
+ struct sdis_device* dev;
+ unsigned next_medium_id;
+ unsigned undefined_medium_behind_boundary_id;
+ int dump_paths;
+ int verbose;
};
+static INLINE unsigned
+allocate_stardis_medium_id(struct stardis* stardis)
+{
+ ASSERT(stardis);
+ return stardis->next_medium_id++;
+}
-extern res_T
+extern LOCAL_SYM res_T
stardis_init
(const struct args* args,
+ struct logger* logger,
+ struct mem_allocator* allocator,
struct stardis* stardis);
-extern res_T
-stardis_compute(struct stardis* stardis, enum stardis_mode mode);
-
-extern void
-stardis_release(struct stardis* stardis);
+extern LOCAL_SYM void
+stardis_release
+ (struct stardis* stardis);
-extern res_T
-dump_vtk(FILE* output, const struct geometry* geometry);
+extern LOCAL_SYM res_T
+init_enclosures
+ (struct stardis* stardis);
-extern res_T
-read_stl
- (const unsigned desc_id,
- const enum content_type file_type,
- const char* stl_filename,
- struct htable_vertex* vertex2id,
- struct htable_triangle* triangle2id,
- struct stardis* stardis);
+extern LOCAL_SYM res_T
+validate_properties
+ (const unsigned itri,
+ const unsigned properties[SG3D_PROP_TYPES_COUNT__],
+ void* context,
+ int* properties_conflict_status);
#endif /*STARDIS-APP_H*/
diff --git a/src/stardis-compute.c b/src/stardis-compute.c
@@ -1,1995 +1,1047 @@
-/* Copyright (C) 2018 |Meso|Star> (contact@meso-star.com)*/
+/* Copyright (C) 2018-2020 |Meso|Star> (contact@meso-star.com)
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>. */
#include "stardis-app.h"
+#include "stardis-output.h"
+#include "stardis-compute.h"
+#include "stardis-fluid.h"
+#include "stardis-solid.h"
+
#include <sdis.h>
#include <sdis_version.h>
+
+#include <star/s3d.h>
+#include <star/sg3d_sXd_helper.h>
+
#include <rsys/double3.h>
#include <rsys/double2.h>
-#include <rsys/dynamic_array_uint.h>
-
+#include <rsys/logger.h>
#include <rsys/image.h>
-#include<star/senc.h>
-
-#include <rsys/hash_table.h>
-#define HTABLE_NAME vrtx_rank
-#define HTABLE_DATA unsigned
-#define HTABLE_KEY unsigned
-#include <rsys/hash_table.h>
-
-#define HTABLE_NAME weigth
-#define HTABLE_DATA double
-#define HTABLE_KEY unsigned
-#include <rsys/hash_table.h>
-
-struct w_ctx {
- struct description* desc;
- struct htable_weigth weigths;
-};
-
-/* A type to limit variable use in tinyexpr expressions */
-enum var_prohibited_t {
- ALL_VARS_ALLOWED = 0,
- T_PROHIBITED = BIT(4),
- XYZ_PROHIBITED = BIT(5),
- NO_VAR_ALLOWED = T_PROHIBITED | XYZ_PROHIBITED
-};
-
-static void
-geometry_get_position
- (const size_t ivert,
- double pos[3],
- void* context)
-{
- struct geometry* geom = context;
- pos[0] = geom->vertex[ivert].xyz[0];
- pos[1] = geom->vertex[ivert].xyz[1];
- pos[2] = geom->vertex[ivert].xyz[2];
-}
-
-static void
-geometry_get_indices
- (const size_t itri,
- size_t ids[3],
- void* context)
-{
- struct geometry* geom = context;
- ids[0] = geom->triangle[itri].indices.data[0];
- ids[1] = geom->triangle[itri].indices.data[1];
- ids[2] = geom->triangle[itri].indices.data[2];
-}
-
-static void
-geometry_get_interface
- (const size_t itri,
- struct sdis_interface** interf,
- void* context)
-{
- struct geometry* geom = context;
- *interf = geom->interf_bytrg[itri];
-}
-
-static res_T
-compile_expr_to_fn
- (struct te_expr** f,
- const char* math_expr,
- const int prohibited,
- int* is_zero)
-{
- te_variable vars[4] = {
- TE_DEF_OFFSET("x", offsetof(struct sdis_rwalk_vertex, P[0])),
- TE_DEF_OFFSET("y", offsetof(struct sdis_rwalk_vertex, P[1])),
- TE_DEF_OFFSET("z", offsetof(struct sdis_rwalk_vertex, P[2])),
- TE_DEF_OFFSET("t", offsetof(struct sdis_rwalk_vertex, time))
- };
- int fst = 0, lst = 4;
- ASSERT(math_expr);
- ASSERT(prohibited == (prohibited & NO_VAR_ALLOWED)); /* Use only defined flags */
- if (prohibited & XYZ_PROHIBITED) fst = 3;
- if(prohibited & T_PROHIBITED) lst = 3;
- *f = te_compile(math_expr, vars+fst, lst-fst, NULL);
- if (!*f) {
- if ((prohibited != ALL_VARS_ALLOWED)
- && te_compile(math_expr, vars, 4, NULL))
- fprintf(stderr, "Expression %s use a probibited variable ", math_expr);
- if (prohibited == NO_VAR_ALLOWED)
- fprintf(stderr, "(no variable allowed)\n");
- else if (prohibited == XYZ_PROHIBITED)
- fprintf(stderr, "(xyz prohibited)\n");
- else {
- ASSERT(prohibited == T_PROHIBITED);
- fprintf(stderr, "(t prohibited)\n");
- }
- return RES_BAD_ARG;
- }
- if (is_zero) *is_zero = !((*f)->type == TE_CONSTANT && (*f)->v.value == 0);
- return RES_OK;
-}
/*******************************************************************************
- * Fluid data
+ * Local Functions
******************************************************************************/
-struct fluid {
- char name[32];
- double cp; /* Calorific capacity */
- double rho; /* Volumic mass */
- /* Compute mode */
- int is_green, is_outside;
- double t0;
- /* TinyExpr stuff to compute temperature */
- struct te_expr *temp;
- struct te_expr *t_init;
- /* ID */
- unsigned id;
-};
-static double
-fluid_get_calorific_capacity
- (const struct sdis_rwalk_vertex* vtx, struct sdis_data* data)
-{
- const struct fluid* fluid_props = sdis_data_cget(data);
- (void)vtx;
- return fluid_props->cp;
-}
+struct filter_ctx {
+ const struct stardis* stardis;
+ unsigned prim;
+ const struct description* desc;
+ float pos[3];
+ float dist;
+ int outside;
+ int probe_on_boundary;
+};
-static double
-fluid_get_volumic_mass
- (const struct sdis_rwalk_vertex* vtx, struct sdis_data* data)
-{
- const struct fluid* fluid_props = sdis_data_cget(data);
- (void)vtx;
- return fluid_props->rho;
-}
+#define FILTER_CTX_DEFAULT__ \
+ { NULL, S3D_INVALID_ID, NULL, { 0, 0, 0 }, FLT_MAX, 0, 0 }
-static double
-fluid_get_temperature
- (const struct sdis_rwalk_vertex* vtx, struct sdis_data* data)
+/* 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* invalid_, /* In closest_point queries ray_dir is not informed */
+ void* ray_data,
+ void* filter_data)
{
- const struct fluid* fluid_props = sdis_data_cget(data);
- char msg[128];
- ASSERT(fluid_props->t_init || fluid_props->temp);
- if (fluid_props->is_green || vtx->time > fluid_props->t0) {
- /* Always use temp for Green mode, regardless of time */
- if (fluid_props->temp)
- return te_eval(fluid_props->temp, vtx);
- else return -1;
+ struct filter_ctx* filter_ctx = ray_data;
+ float s, dir[3];
+ enum senc3d_side hit_side;
+ struct s3d_attrib interf_pos;
+ const struct description* descriptions;
+ unsigned descr[SG3D_PROP_TYPES_COUNT__];
+ const struct stardis* stardis;
+
+ (void)ray_org; (void)invalid_; (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));
+
+ if(filter_ctx->dist == hit->distance && filter_ctx->desc) {
+ /* Cannot improve: keep previous!
+ * Or we could end with a NULL desc */
+ return 1; /* Skip */
}
- /* Time is t0: use t_init */
- if (fluid_props->t_init)
- return te_eval(fluid_props->t_init, vtx);
- /* Must have had t_init defined: error! */
- if (fluid_props->name[0])
- sprintf(msg,
- "fluid_get_temperature: getting undefined Tinit (fluid '%s')\n",
- fluid_props->name);
- else
- sprintf(msg, "fluid_get_temperature: getting undefined Tinit\n");
- FATAL(msg);
-}
-
-static void
-release_fluid_data(void* f)
-{
- struct fluid* fluid = (struct fluid*)f;
- te_free(fluid->t_init);
- te_free(fluid->temp);
-}
-/*******************************************************************************
- * Solid data
- ******************************************************************************/
-struct solid {
- char name[32];
- double cp; /* Calorific capacity */
- double lambda; /* Conductivity */
- double rho; /* Volumic mass */
- double delta; /* Numerical parameter */
- /* Compute mode */
- int is_green, is_outside;
- double t0;
- /* TinyExpr stuff to compute temperature & power */
- struct te_expr *temp;
- struct te_expr *t_init;
- struct te_expr *power;
- /* ID */
- unsigned id;
-};
+ stardis = filter_ctx->stardis;
+ descriptions = darray_descriptions_cdata_get(&stardis->descriptions);
-static double
-solid_get_calorific_capacity
- (const struct sdis_rwalk_vertex* vtx, struct sdis_data* data)
-{
- const struct solid* solid_props = sdis_data_cget(data);
- (void)vtx;
- return solid_props->cp;
-}
+ CHK(s3d_primitive_get_attrib(&hit->prim, S3D_POSITION, hit->uv, &interf_pos)
+ == RES_OK);
-static double
-solid_get_thermal_conductivity
- (const struct sdis_rwalk_vertex* vtx, struct sdis_data* data)
-{
- const struct solid* solid_props = sdis_data_cget(data);
- (void)vtx;
- return solid_props->lambda;
-}
+ if(hit->distance == 0) {
+ filter_ctx->prim = hit->prim.prim_id;
+ filter_ctx->desc = NULL; /* Not apply */
+ f3_set(filter_ctx->pos, interf_pos.value);
+ filter_ctx->dist = hit->distance;
+ filter_ctx->outside = 0;
+ filter_ctx->probe_on_boundary = 1;
+ return 0; /* Keep */
+ }
-static double
-solid_get_volumic_mass
- (const struct sdis_rwalk_vertex* vtx, struct sdis_data* data)
-{
- const struct solid* solid_props = sdis_data_cget(data);
- (void)vtx;
- return solid_props->rho;
-}
+ /* Get the description IDs for this triangle */
+ CHK(sg3d_geometry_get_unique_triangle_properties(stardis->geometry.sg3d,
+ hit->prim.prim_id, descr) == RES_OK);
+
+ if(descr[SG3D_FRONT] == descr[SG3D_BACK]) {
+ /* Don't need to bother with sides */
+ filter_ctx->prim = hit->prim.prim_id;
+ filter_ctx->desc = (descr[SG3D_FRONT] == SG3D_UNSPECIFIED_PROPERTY)
+ ? NULL : descriptions + descr[SG3D_FRONT];
+ f3_set(filter_ctx->pos, interf_pos.value);
+ filter_ctx->dist = hit->distance;
+ filter_ctx->outside = (descr[SG3D_FRONT] == SG3D_UNSPECIFIED_PROPERTY);
+ filter_ctx->probe_on_boundary = 0;
+ return 0; /* Keep */
+ }
-static double
-solid_get_delta
- (const struct sdis_rwalk_vertex* vtx, struct sdis_data* data)
-{
- const struct solid* solid_props = sdis_data_cget(data);
- (void)vtx;
- return solid_props->delta;
-}
+ f3_sub(dir, interf_pos.value, ray_org);
+ s = f3_dot(dir, hit->normal);
-#if Stardis_VERSION_MINOR == 3
-static double
-solid_get_delta_boundary
- (const struct sdis_rwalk_vertex* vtx, struct sdis_data* data)
-{
- const struct solid* solid_props = sdis_data_cget(data);
- return solid_props->delta
- /* Emperical scale factor that ensures that delta_boundary > delta withouht
- * being an exact multiple of delta. */
- /** 2.1 */;
-}
-#endif
+ if(s == 0) {
+ filter_ctx->prim = hit->prim.prim_id;
+ filter_ctx->desc = NULL; /* Cannot decide side */
+ f3_set(filter_ctx->pos, interf_pos.value);
+ filter_ctx->dist = hit->distance;
+ filter_ctx->outside = 0;
+ filter_ctx->probe_on_boundary = 0;
+ }
-static double
-solid_get_temperature
- (const struct sdis_rwalk_vertex* vtx, struct sdis_data* data)
-{
- const struct solid* solid_props = sdis_data_cget(data);
- char msg[128];
- ASSERT(solid_props->t_init || solid_props->temp);
- if (solid_props->is_green || vtx->time > solid_props->t0) {
- /* Always use temp for Green mode, regardless of time */
- if (solid_props->temp)
- return te_eval(solid_props->temp, vtx);
- else return -1;
+ /* Determine which side was hit
+ * Warning: following Embree 2 convention for geometrical normals,
+ * the Star3D hit normals are left-handed */
+ hit_side = (s > 0) ? SG3D_BACK : SG3D_FRONT;
+ if(descr[hit_side] == SG3D_UNSPECIFIED_PROPERTY) {
+ filter_ctx->prim = hit->prim.prim_id;
+ filter_ctx->desc = NULL;
+ f3_set(filter_ctx->pos, interf_pos.value);
+ filter_ctx->dist = hit->distance;
+ filter_ctx->outside = 1;
+ filter_ctx->probe_on_boundary = 0;
+ } else {
+ filter_ctx->prim = hit->prim.prim_id;
+ filter_ctx->desc = descriptions + descr[hit_side];
+ f3_set(filter_ctx->pos, interf_pos.value);
+ filter_ctx->dist = hit->distance;
+ filter_ctx->outside = 0;
+ filter_ctx->probe_on_boundary = 0;
}
- /* Time is t0: use t_init */
- if (solid_props->t_init)
- return te_eval(solid_props->t_init, vtx);
- /* Must have had t_init defined: error! */
- if (solid_props->name[0])
- sprintf(msg,
- "solid_get_temperature: getting undefined Tinit (solid '%s')\n",
- solid_props->name);
- else
- sprintf(msg, "solid_get_temperature: getting undefined Tinit\n");
- FATAL(msg);
-}
-static double
-solid_get_power
- (const struct sdis_rwalk_vertex* vtx, struct sdis_data* data)
-{
- const struct solid* solid_props = sdis_data_cget(data);
- return te_eval(solid_props->power, vtx);
+ return 0; /* Keep */
}
-static void
-release_solid_data(void* s)
+/* Check probe position and move it to the closest point on an interface
+ * if on_interface is set */
+static res_T
+check_probe_conform_to_type
+ (const struct stardis* stardis,
+ const int move2boundary,
+ double pos[3],
+ size_t* iprim,
+ double uv[2])
{
- struct solid* solid = (struct solid*)s;
- te_free(solid->t_init);
- te_free(solid->power);
-}
+ res_T res = RES_OK;
+ struct s3d_device* s3d = NULL;
+ struct s3d_scene* s3d_scn = NULL;
+ struct s3d_shape* s3d_shp = NULL;
+ struct s3d_scene_view* s3d_view = NULL;
+ struct s3d_hit hit = S3D_HIT_NULL;
+ struct s3d_vertex_data attribs;
+ struct filter_ctx filter_ctx = FILTER_CTX_DEFAULT__;
+ float origin[3];
+ unsigned vcount, tcount, j;
+
+ ASSERT(stardis && pos && iprim && uv);
+
+ attribs.type = S3D_FLOAT3;
+ attribs.usage = S3D_POSITION;
+ attribs.get = sg3d_sXd_geometry_get_position;
+
+ ERR(s3d_device_create(stardis->logger, stardis->allocator, 0, &s3d));
+ ERR(s3d_scene_create(s3d, &s3d_scn));
+ ERR(s3d_shape_create_mesh(s3d, &s3d_shp));
+
+ /* Back to s3d API type for ntris and nverts */
+ ERR(sg3d_geometry_get_unique_triangles_count(stardis->geometry.sg3d, &tcount));
+ ERR(sg3d_geometry_get_unique_vertices_count(stardis->geometry.sg3d, &vcount));
+ ERR(s3d_mesh_setup_indexed_vertices(s3d_shp,
+ tcount, sg3d_sXd_geometry_get_indices,
+ vcount, &attribs, 1, stardis->geometry.sg3d));
+ /* Need a filter to sort out some tricky configurations (see filter comments) */
+ ERR(s3d_mesh_set_hit_filter_function(s3d_shp, hit_filter, NULL));
+ ERR(s3d_scene_attach_shape(s3d_scn, s3d_shp));
+ ERR(s3d_scene_view_create(s3d_scn, S3D_TRACE, &s3d_view));
+
+ S3D(device_ref_put(s3d)); s3d = NULL;
+ S3D(scene_ref_put(s3d_scn)); s3d_scn = NULL;
+ S3D(shape_ref_put(s3d_shp)); s3d_shp = NULL;
+
+ f3_set_d3(origin, pos);
+ filter_ctx.stardis = stardis;
+ ERR(s3d_scene_view_closest_point(s3d_view, origin, FLT_MAX, &filter_ctx, &hit));
+ S3D(scene_view_ref_put(s3d_view)); s3d_view = NULL;
+ if(S3D_HIT_NONE(&hit)) {
+ res = RES_BAD_ARG;
+ goto error;
+ }
+ 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(filter_ctx.desc->type == DESC_MAT_SOLID) {
+ double delta = filter_ctx.desc->d.solid.delta;
+ ASSERT(delta < INF);
+ logger_print(stardis->logger, LOG_OUTPUT,
+ "Probe was in solid '%s'.\n", str_cget(&filter_ctx.desc->d.solid.name));
+ 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 {
+ /* TODO: check move length wrt local geometry? */
+ logger_print(stardis->logger, LOG_OUTPUT,
+ "Probe was in fluid '%s'.\n", str_cget(&filter_ctx.desc->d.fluid.name));
+ 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));
+ } 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));
+ }
+ d3_set_f3(pos, filter_ctx.pos);
+ } else {
+ /* 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;
+ }
+ logger_print(stardis->logger, LOG_OUTPUT,
+ "Probe is in solid '%s'.\n", str_cget(&filter_ctx.desc->d.solid.name));
+ if(filter_ctx.desc->type == DESC_MAT_SOLID) {
+ double delta = filter_ctx.desc->d.solid.delta;
+ 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 {
+ 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));
+ /* In fluid; TODO: check distance wrt local geometry (use 4V/S?) */
+ }
+ }
-/*******************************************************************************
- * Interface data
- ******************************************************************************/
-struct intface {
- double hc; /* Convection coefficient */
- double emissivity;
- double alpha;
- /* TinyExpr stuff to compute temperature & flux */
- struct te_expr *temperature;
- struct te_expr *flux;
- /* IDs */
- unsigned front_boundary_id, back_boundary_id;
-};
+ *iprim = hit.prim.prim_id;
+ d2_set_f2(uv, hit.uv);
+end:
+ if(s3d) S3D(device_ref_put(s3d));
+ if(s3d_scn) S3D(scene_ref_put(s3d_scn));
+ if(s3d_shp) S3D(shape_ref_put(s3d_shp));
+ if(s3d_view) S3D(scene_view_ref_put(s3d_view));
-static double
-interface_get_convection_coef
- (const struct sdis_interface_fragment* frag, struct sdis_data* data)
-{
- const struct intface* interface_props = sdis_data_cget(data);
- (void)frag;
- return interface_props->hc;
+ return res;
+error:
+ goto end;
}
-static double
-interface_get_temperature
- (const struct sdis_interface_fragment* frag, struct sdis_data* data)
+static res_T
+compute_probe(struct stardis* stardis)
{
- const struct intface* interface_props = sdis_data_cget(data);
-
- if (interface_props->temperature == NULL)
- return -1;
-
- return te_eval(interface_props->temperature, frag);
-}
+ res_T res = RES_OK;
+ double uv[2] = { 0,0 };
+ size_t iprim = SIZE_MAX;
+ struct sdis_green_function* green = NULL;
+ struct sdis_estimator* estimator = NULL;
+ struct dump_path_context dump_ctx;
+ struct sdis_solve_probe_args args = SDIS_SOLVE_PROBE_ARGS_DEFAULT;
+ FILE* stream = NULL;
-static double
-interface_get_flux
- (const struct sdis_interface_fragment* frag, struct sdis_data* data)
-{
- const struct intface* interface_props = sdis_data_cget(data);
+ ASSERT(stardis && (stardis->mode & MODE_PROBE_COMPUTE));
- if (interface_props->flux == NULL)
- return SDIS_FLUX_NONE;
-
- return te_eval(interface_props->flux, frag);
-}
+ ERR(check_probe_conform_to_type(stardis, 0, stardis->probe, &iprim, uv));
-static void
-release_interface_data(void* s)
-{
- struct intface* intface = (struct intface*)s;
- te_free(intface->temperature);
- te_free(intface->flux);
-}
+ args.nrealisations = stardis->samples;
+ d3_set(args.position, stardis->probe);
+ d2_set(args.time_range, stardis->time_range);
-static double
-interface_get_emissivity
- (const struct sdis_interface_fragment* frag, struct sdis_data* data)
-{
- const struct intface* interface_props = sdis_data_cget(data);
- (void)frag;
- return interface_props->emissivity;
-}
+ if(stardis->mode & (MODE_BIN_GREEN | MODE_GREEN)) {
+ ERR(sdis_solve_probe_green_function(stardis->sdis_scn, &args, &green));
+ if(stardis->mode & MODE_BIN_GREEN) {
+ ASSERT(!str_is_empty(&stardis->bin_green_filename));
+ stream = fopen(str_cget(&stardis->bin_green_filename), "wb");
+ if(!stream) {
+ res = RES_IO_ERR;
+ goto error;
+ }
+ ERR(dump_green_bin(green, stardis, stream));
+ fclose(stream); stream = NULL;
+ if(str_cget(&stardis->end_paths_filename)
+ && strlen(str_cget(&stardis->end_paths_filename)))
+ {
+ stream = fopen(str_cget(&stardis->end_paths_filename), "w");
+ if(!stream) {
+ res = RES_IO_ERR;
+ goto error;
+ }
+ ERR(dump_paths_end(green, stardis, stream));
+ fclose(stream); stream = NULL;
+ }
+ }
+ if(stardis->mode & MODE_GREEN) {
+ ERR(dump_green_ascii(green, stardis, stdout));
+ }
+ } else {
+ args.register_paths = stardis->dump_paths;
+ ERR(sdis_solve_probe(stardis->sdis_scn, &args, &estimator));
+ ERR(print_single_MC_result(estimator, stardis, stdout));
+ /* Dump paths recorded according to user settings */
+ dump_ctx.stardis = stardis;
+ dump_ctx.rank = 0;
+ ERR(sdis_estimator_for_each_path(estimator, dump_path, &dump_ctx));
+ }
-static INLINE double
-interface_get_alpha
- (const struct sdis_interface_fragment* frag, struct sdis_data* data)
-{
- const struct intface* interface_props = sdis_data_cget(data);
- (void)frag;
- return interface_props->alpha;
+end:
+ if(stream) fclose(stream);
+ if(estimator) SDIS(estimator_ref_put(estimator));
+ if(green) SDIS(green_function_ref_put(green));
+ return res;
+error:
+ goto end;
}
static res_T
-select_probe_type
- (const struct sdis_scene* scn,
- const struct triangle* triangle,
- const struct vertex* vertex,
- const struct description* descriptions,
- const int on_interface,
- double pos[3],
- size_t* iprim,
- double uv[2])
+compute_probe_on_interface(struct stardis* stardis)
{
res_T res = RES_OK;
- double min_d = DBL_MAX, min_delta = DBL_MAX, new_pos[3], tmp_uv[2], min_uv[2];
- const struct description *min_desc = NULL;
- size_t i = 0, found = SIZE_MAX;
- enum description_type min_type = DESCRIPTION_TYPE_COUNT__;
-
- for (i = 0; i < sa_size(triangle); ++i) {
- const struct triangle* tr = triangle + i;
- double dp[3], d, projected_pos[3], nn[3];
- float v0[3], v1[3], v2[3], e1[3], e2[3], n[3];
- const struct description *desc = NULL;
- enum sdis_side s;
-
- res = sdis_scene_boundary_project_position(scn, i, pos, tmp_uv);
- if (res != RES_OK) return res;
- res = sdis_scene_get_boundary_position(scn, i, tmp_uv, projected_pos);
- if (res != RES_OK) return res;
- d3_sub(dp, projected_pos, pos);
- d = d3_len(dp);
-
- if (d == 0) {
- /* Best possible match */
- found = i;
- fprintf(stderr,
- "The probe is on the primitive %llu.\n", (long long int)*iprim);
- break;
- }
- if (d >= min_d) {
- /* No improvement */
- continue;
- }
- min_d = d;
- d2_set(min_uv, tmp_uv);
-
- /* Find side */
- f3_set(v0, vertex[tr->indices.data[0]].xyz);
- f3_set(v1, vertex[tr->indices.data[1]].xyz);
- f3_set(v2, vertex[tr->indices.data[2]].xyz);
- f3_sub(e1, v1, v0);
- f3_sub(e2, v2, v0);
- f3_cross(n, e1, e2);
-
- /* Stardis solver convention is triangle normal is back side */
- d3_set_f3(nn, n);
- s = (d3_dot(nn, dp) < 0) ? SDIS_BACK : SDIS_FRONT;
-
- if (s == SDIS_FRONT) {
- if (tr->front_description != UINT_MAX) {
- desc = descriptions + tr->front_description;
+ double uv[2] = { 0,0 };
+ size_t iprim = SIZE_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 = NULL;
+
+ ASSERT(stardis && (stardis->mode & MODE_PROBE_COMPUTE_ON_INTERFACE));
+ ERR(check_probe_conform_to_type(stardis, 1, stardis->probe, &iprim, uv));
+ ASSERT(iprim != SIZE_MAX);
+
+ args.nrealisations = stardis->samples;
+ args.iprim = iprim;
+ d3_set(args.uv, uv);
+ args.side = SDIS_FRONT;
+ d2_set(args.time_range, stardis->time_range);
+
+ if(stardis->mode & (MODE_BIN_GREEN | MODE_GREEN)) {
+ ERR(sdis_solve_probe_boundary_green_function(stardis->sdis_scn, &args,
+ &green));
+ if(stardis->mode & MODE_BIN_GREEN) {
+ ASSERT(!str_is_empty(&stardis->bin_green_filename));
+ stream = fopen(str_cget(&stardis->bin_green_filename), "wb");
+ if(!stream) {
+ res = RES_IO_ERR;
+ goto error;
}
- } else {
- if (tr->back_description != UINT_MAX) {
- desc = descriptions + tr->back_description;
+ ERR(dump_green_bin(green, stardis, stream));
+ fclose(stream); stream = NULL;
+ if(str_cget(&stardis->end_paths_filename)
+ && strlen(str_cget(&stardis->end_paths_filename)))
+ {
+ stream = fopen(str_cget(&stardis->end_paths_filename), "w");
+ if(!stream) {
+ res = RES_IO_ERR;
+ goto error;
+ }
+ ERR(dump_paths_end(green, stardis, stream));
+ fclose(stream); stream = NULL;
}
}
-
- min_desc = desc;
- if (!desc) continue;
-
- min_type = desc->type;
- if (desc->type == DESC_MAT_SOLID) {
- found = i;
- min_delta = desc->d.solid.delta;
- d3_set(new_pos, projected_pos);
+ if(stardis->mode & MODE_GREEN) {
+ ERR(dump_green_ascii(green, stardis, stdout));
}
- }
-
- if (!min_desc) {
- /* Don't manage pos is outside the model
- * but very close and could be considered on the boundary */
- fprintf(stderr, "The probe is outside the model.\n");
- return RES_BAD_ARG;
- }
-
- if (on_interface) {
- *iprim = found;
- if (min_type == DESC_MAT_FLUID)
- fprintf(stderr, "Probe was on a fluid.\n");
- fprintf(stderr, "The probe is moved to %g,%g,%g (primitive %llu)\n",
- SPLIT3(new_pos), (long long int)*iprim);
- if (min_type == DESC_MAT_SOLID && min_d > min_delta)
- fprintf(stderr, "WARNING: The probe move is %.1f delta long.\n", min_d / min_delta);
- d3_set(pos, new_pos);
- d2_set(uv, min_uv);
} else {
- if (min_type == DESC_MAT_FLUID)
- fprintf(stderr,
- "The probe is in a fluid: computing fluid temperature, not using a specific position.\n");
- if (min_type == DESC_MAT_SOLID && min_d < min_delta) {
- fprintf(stderr,
- "WARNING: The probe is very close to the primitive %llu (%.1f delta).\n",
- (long long int)found, min_d / min_delta);
- fprintf(stderr,
- "To have this probe moved on the closest interface use -P instead of -p\n");
- }
+ args.register_paths = stardis->dump_paths;
+ ERR(sdis_solve_probe_boundary(stardis->sdis_scn, &args, &estimator));
+ ERR(print_single_MC_result(estimator, stardis, stdout));
+ /* Dump paths recorded according to user settings */
+ dump_ctx.stardis = stardis;
+ dump_ctx.rank = 0;
+ ERR(sdis_estimator_for_each_path(estimator, dump_path, &dump_ctx));
}
+end:
+ if(stream) fclose(stream);
+ if(estimator) SDIS(estimator_ref_put(estimator));
+ if(green) SDIS(green_function_ref_put(green));
return res;
+error:
+ goto end;
}
-static void
-dump_image(const struct sdis_estimator_buffer* buf)
+static res_T
+auto_look_at
+ (struct sdis_scene* scn,
+ const double fov_x, /* Horizontal field of view in radian */
+ const double proj_ratio, /* Width / height */
+ const double up[3], /* Up vector */
+ double position[3],
+ double target[3])
{
- size_t definition[2];
- double* temps = NULL;
- size_t ix, iy;
-
- CHK(buf != NULL);
- CHK(sdis_estimator_buffer_get_definition(buf, definition) == RES_OK);
-
- temps = mem_alloc(definition[0] * definition[1] *sizeof(double));
- CHK(temps != NULL);
-
- /* Compute the per pixel temperature */
- fprintf(stdout,"# vtk DataFile Version 2.0\nvtk output\nASCII\nDATASET STRUCTURED_POINTS\n");
- fprintf(stdout,"DIMENSIONS %zu %zu 1\n", definition[0], definition[1]);
- fprintf(stdout,"ORIGIN 0 0 0\n");
- fprintf(stdout,"SPACING 1 1 1\n");
- fprintf(stdout,"POINT_DATA %zu\n", definition[0] * definition[1]);
- fprintf(stdout,"SCALARS temperature_estimate float 1\n");
- fprintf(stdout,"LOOKUP_TABLE default\n");
- FOR_EACH(iy, 0, definition[1]) {
- FOR_EACH(ix, 0, definition[0]) {
- const struct sdis_estimator* estimator;
- struct sdis_mc T;
- CHK(sdis_estimator_buffer_at(buf, ix, iy, &estimator) == RES_OK);
- CHK(sdis_estimator_get_temperature(estimator, &T) == RES_OK);
- fprintf(stdout,"%f\n", T.E);
- }
- }
- fprintf(stdout, "SCALARS temperature_std_dev float 1\n");
- fprintf(stdout, "LOOKUP_TABLE default\n");
- FOR_EACH(iy, 0, definition[1]) {
- FOR_EACH(ix, 0, definition[0]) {
- const struct sdis_estimator* estimator;
- struct sdis_mc T;
- CHK(sdis_estimator_buffer_at(buf, ix, iy, &estimator) == RES_OK);
- CHK(sdis_estimator_get_temperature(estimator, &T) == RES_OK);
- fprintf(stdout, "%f\n", T.SE);
- }
- }
- fprintf(stdout, "SCALARS computation_time float 1\n");
- fprintf(stdout, "LOOKUP_TABLE default\n");
- FOR_EACH(iy, 0, definition[1]) {
- FOR_EACH(ix, 0, definition[0]) {
- const struct sdis_estimator* estimator;
- struct sdis_mc time;
- CHK(sdis_estimator_buffer_at(buf, ix, iy, &estimator) == RES_OK);
- CHK(sdis_estimator_get_realisation_time(estimator, &time) == RES_OK);
- fprintf(stdout, "%f\n", time.E);
- }
+ double lower[3], upper[3];
+ double up_abs[3];
+ double axis_min[3];
+ double axis_x[3];
+ double axis_z[3];
+ double tmp[3];
+ double radius;
+ double depth;
+ res_T res;
+ ASSERT(scn && fov_x && proj_ratio && up);
+
+ ERR(sdis_scene_get_aabb(scn, lower, upper));
+
+ if(lower[0] > upper[0] || lower[1] > upper[1] || lower[2] > upper[2]) {
+ /* Empty scene */
+ d3(position, STARDIS_DEFAULT_RENDERING_POS);
+ d3(target, STARDIS_DEFAULT_RENDERING_TGT);
+ goto exit;
}
- fprintf(stdout, "SCALARS computation_time_std_dev float 1\n");
- fprintf(stdout, "LOOKUP_TABLE default\n");
- FOR_EACH(iy, 0, definition[1]) {
- FOR_EACH(ix, 0, definition[0]) {
- const struct sdis_estimator* estimator;
- struct sdis_mc time;
- CHK(sdis_estimator_buffer_at(buf, ix, iy, &estimator) == RES_OK);
- CHK(sdis_estimator_get_realisation_time(estimator, &time) == RES_OK);
- fprintf(stdout, "%f\n", time.SE);
- }
+
+ /* The target is the scene centroid */
+ d3_muld(target, d3_add(target, lower, upper), 0.5);
+
+ /* Define which up dimension is minimal and use its unit vector to compute a
+ * vector orthogonal to `up'. This ensures that the unit vector and `up' are
+ * not collinear so that their cross product is not a zero vector. */
+ up_abs[0] = fabs(up[0]);
+ up_abs[1] = fabs(up[1]);
+ up_abs[2] = fabs(up[2]);
+ if(up_abs[0] < up_abs[1]) {
+ if(up_abs[0] < up_abs[2]) d3(axis_min, 1, 0, 0);
+ else d3(axis_min, 0, 0, 1);
+ } else {
+ if(up_abs[1] < up_abs[2]) d3(axis_min, 0, 1, 0);
+ else d3(axis_min, 0, 0, 1);
}
- fprintf(stdout, "SCALARS temperature_failures_count int 1\n");
- fprintf(stdout, "LOOKUP_TABLE default\n");
- FOR_EACH(iy, 0, definition[1]) {
- FOR_EACH(ix, 0, definition[0]) {
- const struct sdis_estimator* estimator;
- size_t nfails;
- CHK(sdis_estimator_buffer_at(buf, ix, iy, &estimator) == RES_OK);
- CHK(sdis_estimator_get_failure_count(estimator, &nfails) == RES_OK);
- fprintf(stdout, "%zu\n", nfails);
- }
+ d3_normalize(axis_x, d3_cross(axis_x, up, axis_min));
+ d3_normalize(axis_z, d3_cross(axis_z, up, axis_x));
+
+ /* Find whether the XYZ or the ZYX basis maximise the model's visibility */
+ if(fabs(d3_dot(axis_x, upper)) < fabs(d3_dot(axis_z, upper))) {
+ SWAP(double, axis_x[0], axis_z[0]);
+ SWAP(double, axis_x[1], axis_z[1]);
+ SWAP(double, axis_x[2], axis_z[2]);
}
- mem_rm(temps);
-}
-
-/*******************************************************************************
- *
- ******************************************************************************/
+ /* Ensure that the whole model is visible */
+ radius = d3_len(d3_sub(tmp, upper, lower)) * 0.5;
+ if(proj_ratio < 1) {
+ depth = radius / sin(fov_x / 2.0);
+ } else {
+ depth = radius / sin(fov_x / (2.0 * proj_ratio));
+ }
-struct int_descs {
- unsigned front, back, connect;
-};
-#define INT_DESCS_NULL__ { UINT_MAX, UINT_MAX, UINT_MAX }
-static const struct int_descs INT_DESCS_NULL = INT_DESCS_NULL__;
+ /* Define the camera position */
+ d3_sub(position, target, d3_muld(tmp, axis_z, depth));
-static INLINE char
-eq_desc(const struct int_descs* a, const struct int_descs* b)
-{
- return (char)(a->front == b->front && a->back == b->back
- && a->connect == b->connect);
-}
+ /* Empirically move the position to find a better point of view */
+ d3_add(position, position, d3_muld(tmp, up, radius)); /*Empirical offset*/
+ d3_add(position, position, d3_muld(tmp, axis_x, radius)); /*Empirical offset*/
+ d3_normalize(tmp, d3_sub(tmp, target, position));
+ d3_sub(position, target, d3_muld(tmp, tmp, depth));
-static INLINE size_t
-hash_desc(struct int_descs const* key)
-{
-#ifdef ARCH_32BITS
- return (size_t)hash_fnv32(key, 3 * sizeof(unsigned));
-#elif defined(ARCH_64BITS)
- return (size_t)hash_fnv64(key, 3 * sizeof(unsigned));
-#else
-#error "Unexpected architecture"
-#endif
+exit:
+ return res;
+error:
+ goto exit;
}
-#include <rsys/hash_table.h>
-/* Declare the hash table that map a vertex to its index */
-#define HTABLE_NAME intface
-#define HTABLE_DATA struct sdis_interface*
-#define HTABLE_KEY struct int_descs
-#define HTABLE_KEY_FUNCTOR_EQ eq_desc
-#define HTABLE_KEY_FUNCTOR_HASH hash_desc
-#include <rsys/hash_table.h>
-
static res_T
-create_fluid
- (struct sdis_device* dev,
- const char* name,
- const double rho,
- const double cp,
- const int is_green,
- const int is_outside,
- const char* tinit_expr,
- const char* t_expr,
- struct sdis_medium*** media_ptr,
- unsigned* out_id)
+compute_camera(struct stardis* stardis)
{
res_T res = RES_OK;
- struct sdis_fluid_shader fluid_shader = SDIS_FLUID_SHADER_NULL;
- struct sdis_data* data = NULL;
- struct fluid* fluid_props;
- size_t sz;
- /* Could be less restrictive if green output included positions/dates */
- int prohibited = is_green ? NO_VAR_ALLOWED : ALL_VARS_ALLOWED;
-
- ASSERT(dev && rho >= 0 && cp >= 0 && media_ptr && out_id);
- fluid_shader.calorific_capacity = fluid_get_calorific_capacity;
- fluid_shader.volumic_mass = fluid_get_volumic_mass;
- fluid_shader.temperature = fluid_get_temperature;
- res = sdis_data_create(dev, sizeof(struct fluid), ALIGNOF(struct fluid),
- release_fluid_data, &data);
- if (res != RES_OK) goto error;
-
- sz = sa_size(*media_ptr);
- ASSERT(sz < INT_MAX);
- fluid_props = sdis_data_get(data); /* Fetch the allocated memory space */
- if (name) strncpy(fluid_props->name, name, sizeof(fluid_props->name));
- else fluid_props->name[0] = '\0';
- fluid_props->cp = cp;
- fluid_props->rho = rho;
- fluid_props->t_init = NULL;
- fluid_props->temp = NULL;
- fluid_props->is_green = is_green;
- fluid_props->is_outside = is_outside;
- fluid_props->t0 = 0;
- fluid_props->id = (unsigned)sz;
-
- if (tinit_expr) {
- res = compile_expr_to_fn(&fluid_props->t_init, tinit_expr,
- prohibited | T_PROHIBITED, NULL);
- if (res != RES_OK) {
- fprintf(stderr, "Invalid initial temperature expression: %s\n",
- tinit_expr);
- goto error;
- }
+ double proj_ratio;
+ size_t width, height;
+ struct sdis_estimator_buffer* buf = NULL;
+ struct sdis_solve_camera_args args = SDIS_SOLVE_CAMERA_ARGS_DEFAULT;
+ struct sdis_camera* cam = NULL;
+ struct dump_path_context dump_ctx;
+ size_t definition[2];
+ size_t ix, iy;
+
+ ASSERT(stardis
+ && !(stardis->mode & (MODE_BIN_GREEN | MODE_GREEN))
+ && (stardis->mode & MODE_IR_COMPUTE));
+
+ width = (size_t)stardis->camera.img_width;
+ height = (size_t)stardis->camera.img_height;
+ proj_ratio = (double)width / (double)height;
+ /* Setup the camera */
+ ERR(sdis_camera_create(stardis->dev, &cam));
+ ERR(sdis_camera_set_proj_ratio(cam, proj_ratio));
+ ERR(sdis_camera_set_fov(cam, MDEG2RAD(stardis->camera.fov)));
+ if(stardis->camera.auto_look_at) {
+ ERR(auto_look_at(stardis->sdis_scn, MDEG2RAD(stardis->camera.fov), proj_ratio,
+ stardis->camera.up, stardis->camera.pos, stardis->camera.tgt));
+ logger_print(stardis->logger, LOG_OUTPUT,
+ "Camera auto-look at: position=%g,%g,%g target=%g,%g,%g.\n",
+ SPLIT3(stardis->camera.pos), SPLIT3(stardis->camera.tgt));
}
- if (t_expr) {
- res = compile_expr_to_fn(&fluid_props->temp, t_expr, prohibited, NULL);
- if (res != RES_OK) {
- fprintf(stderr, "Invalid temperature expression: %s\n",
- t_expr);
- goto error;
+ ERR(sdis_camera_look_at(cam,
+ stardis->camera.pos,
+ stardis->camera.tgt,
+ stardis->camera.up));
+
+ args.cam = cam;
+ d2_set(args.time_range, stardis->camera.time_range);
+ args.image_resolution[0] = width;
+ args.image_resolution[1] = height;
+ args.spp = (size_t)stardis->camera.spp;
+ args.register_paths = stardis->dump_paths;
+
+ /* Launch the simulation */
+ ERR(sdis_solve_camera(stardis->sdis_scn, &args, &buf));
+
+ /* Write the image */
+ ASSERT(stardis->camera.fmt == STARDIS_RENDERING_OUTPUT_FILE_FMT_VTK
+ || stardis->camera.fmt == STARDIS_RENDERING_OUTPUT_FILE_FMT_HT);
+ if(stardis->camera.fmt == STARDIS_RENDERING_OUTPUT_FILE_FMT_VTK)
+ ERR(dump_vtk_image(buf, stdout));
+ else ERR(dump_ht_image(buf, stdout));
+
+ /* Dump paths recorded according to user settings */
+ dump_ctx.stardis = stardis;
+ dump_ctx.rank = 0;
+ ERR(sdis_estimator_buffer_get_definition(buf, definition));
+ FOR_EACH(iy, 0, definition[1]) {
+ FOR_EACH(ix, 0, definition[0]) {
+ const struct sdis_estimator* estimator;
+ ERR(sdis_estimator_buffer_at(buf, ix, iy, &estimator));
+ ERR(sdis_estimator_for_each_path(estimator, dump_path, &dump_ctx));
}
}
- res = sdis_fluid_create(dev, &fluid_shader, data, sa_add(*media_ptr, 1));
- if (res != RES_OK) goto error;
- *out_id = fluid_props->id;
end:
- if (data) SDIS(data_ref_put(data));
+ if(cam) SDIS(camera_ref_put(cam));
+ if(buf) SDIS(estimator_buffer_ref_put(buf));
return res;
error:
goto end;
}
static res_T
-create_solid
- (struct sdis_device* dev,
- const char* name,
- const double lambda,
- const double rho,
- const double cp,
- const double delta,
- const int is_green,
- const int is_outside,
- const char* tinit_expr, /* Can be NULL if not used by getter */
- const char* t_expr, /* Can be NULL if not used by getter */
- const char* power_expr, /* Can be NULL */
- struct sdis_medium*** media_ptr,
- int* out_has_power, /* Can be NULL */
- unsigned* out_id)
+compute_medium(struct stardis* stardis)
{
res_T res = RES_OK;
- struct sdis_solid_shader solid_shader = SDIS_SOLID_SHADER_NULL;
- struct sdis_data* data = NULL;
- struct solid* solid_props;
- size_t sz;
- /* Could be less restrictive if green output included positions/dates */
- int prohibited = is_green ? NO_VAR_ALLOWED : ALL_VARS_ALLOWED;
-
- ASSERT(dev && lambda >= 0 && rho >= 0 && cp >= 0 && delta > 0
- && media_ptr && out_id);
- solid_shader.calorific_capacity = solid_get_calorific_capacity;
- solid_shader.thermal_conductivity = solid_get_thermal_conductivity;
- solid_shader.volumic_mass = solid_get_volumic_mass;
- solid_shader.delta_solid = solid_get_delta;
-#if Stardis_VERSION_MINOR == 3
- solid_shader.delta_boundary = solid_get_delta_boundary;
-#endif
- solid_shader.temperature = solid_get_temperature;
- res = sdis_data_create(dev, sizeof(struct solid), ALIGNOF(struct solid),
- release_solid_data, &data);
- if (res != RES_OK) goto error;
-
- sz = sa_size(*media_ptr);
- ASSERT(sz < INT_MAX);
- solid_props = sdis_data_get(data); /* Fetch the allocated memory space */
- if (name) strncpy(solid_props->name, name, sizeof(solid_props->name));
- else solid_props->name[0] = '\0';
- solid_props->lambda = lambda;
- solid_props->rho = rho;
- solid_props->cp = cp;
- solid_props->delta = delta;
- solid_props->t_init = NULL;
- solid_props->temp = NULL;
- solid_props->power = NULL;
- solid_props->is_green = is_green;
- solid_props->is_outside = is_outside;
- solid_props->t0 = 0;
- solid_props->id = (unsigned)sz;
- if (tinit_expr) {
- res = compile_expr_to_fn(&solid_props->t_init, tinit_expr,
- prohibited | T_PROHIBITED, NULL);
- if (res != RES_OK) {
- fprintf(stderr, "Invalid initial temperature expression: %s\n",
- tinit_expr);
- goto error;
- }
+ struct sdis_medium* medium = NULL;
+ struct sdis_estimator* estimator = NULL;
+ struct sdis_green_function* green = NULL;
+ struct sdis_solve_medium_args args = SDIS_SOLVE_MEDIUM_ARGS_DEFAULT;
+ struct dump_path_context dump_ctx;
+ FILE* stream = NULL;
+
+ ASSERT(stardis && (stardis->mode & MODE_MEDIUM_COMPUTE));
+
+ /* Find medium */
+ medium = find_medium_by_name(stardis, &stardis->solve_name, NULL);
+ if(medium == NULL) { /* Not found */
+ logger_print(stardis->logger, LOG_ERROR,
+ "Cannot solve medium '%s' (unknown medium)\n",
+ str_cget(&stardis->solve_name));
+ res = RES_BAD_ARG;
+ goto error;
}
- if (t_expr) {
- res = compile_expr_to_fn(&solid_props->temp, t_expr, prohibited, NULL);
- if (res != RES_OK) {
- fprintf(stderr, "Invalid temperature expression: %s\n",
- t_expr);
- goto error;
+
+ args.nrealisations = stardis->samples;
+ args.medium = medium;
+ d2_set(args.time_range, stardis->time_range);
+
+ if(stardis->mode & (MODE_BIN_GREEN | MODE_GREEN)) {
+ ERR(sdis_solve_medium_green_function(stardis->sdis_scn, &args, &green));
+ if(stardis->mode & MODE_BIN_GREEN) {
+ ASSERT(!str_is_empty(&stardis->bin_green_filename));
+ stream = fopen(str_cget(&stardis->bin_green_filename), "wb");
+ if(!stream) {
+ res = RES_IO_ERR;
+ goto error;
+ }
+ ERR(dump_green_bin(green, stardis, stream));
+ fclose(stream); stream = NULL;
+ if(str_cget(&stardis->end_paths_filename)
+ && strlen(str_cget(&stardis->end_paths_filename)))
+ {
+ stream = fopen(str_cget(&stardis->end_paths_filename), "w");
+ if(!stream) {
+ res = RES_IO_ERR;
+ goto error;
+ }
+ ERR(dump_paths_end(green, stardis, stream));
+ fclose(stream); stream = NULL;
+ }
}
- }
- if (power_expr) {
- int has_power;
- res = compile_expr_to_fn(&solid_props->power, power_expr, prohibited, &has_power);
- if (res != RES_OK) {
- fprintf(stderr, "Invalid volumic power expression: %s\n",
- power_expr);
- goto error;
+ if(stardis->mode & MODE_GREEN) {
+ ERR(dump_green_ascii(green, stardis, stdout));
}
- if (out_has_power) *out_has_power = has_power;
- if(has_power) solid_shader.volumic_power = solid_get_power;
- }
- else {
- if (out_has_power) *out_has_power = 0;
+ } else {
+ args.register_paths = stardis->dump_paths;
+ ERR(sdis_solve_medium(stardis->sdis_scn, &args, &estimator));
+ ERR(print_single_MC_result(estimator, stardis, stdout));
+ /* Dump paths recorded according to user settings */
+ dump_ctx.stardis = stardis;
+ dump_ctx.rank = 0;
+ ERR(sdis_estimator_for_each_path(estimator, dump_path, &dump_ctx));
}
- res = sdis_solid_create(dev, &solid_shader, data, sa_add(*media_ptr, 1));
- if (res != RES_OK) goto error;
- *out_id = solid_props->id;
end:
- if (data) SDIS(data_ref_put(data));
+ if(stream) fclose(stream);
+ if(estimator) SDIS(estimator_ref_put(estimator));
+ if(green) SDIS(green_function_ref_put(green));
return res;
error:
goto end;
}
static res_T
-create_edge_file_if
- (struct sdis_scene* scn,
- struct mem_allocator* allocator)
+add_compute_surface_triangle
+ (const unsigned unique_id, const unsigned itri, void* context)
{
res_T res = RES_OK;
- unsigned i, comp, scount, vcount;
- char name[64];
- FILE* obj = NULL;
- struct htable_vrtx_rank ranks;
- char structs_initialized = 0;
- struct senc_descriptor* analyze = NULL;
- struct darray_uint comps;
- struct darray_uint edges;
- unsigned cc_count = 0;
- unsigned *cc, *ee, uimax = UINT_MAX;
-
- res = sdis_scene_get_analysis(scn, &analyze);
- if (res != RES_OK) goto error;
- res = sdis_scene_release_analysis(scn);
- if (res != RES_OK) goto error;
-
- ASSERT(scn && allocator);
-
- res = senc_descriptor_get_frontier_segments_count(analyze, &scount);
- if (res != RES_OK) goto error;
-
- if(scount == 0)
- /* No edge to exit */
- goto end;
-
- fprintf(stderr, "Some frontier edges found: create OBJ files\n");
-
- htable_vrtx_rank_init(allocator, &ranks);
- darray_uint_init(allocator, &comps);
- darray_uint_init(allocator, &edges);
- structs_initialized = 1;
-
- /* Exit vertices, with a new numbering scheme */
- vcount = 0;
- FOR_EACH(i, 0, scount) {
- unsigned v, edge[2], rk[2];
- res = senc_descriptor_get_frontier_segment(analyze, i, edge);
- if(res != RES_OK) goto error;
- FOR_EACH(v, 0, 2) {
- unsigned* p_rank;
- p_rank = htable_vrtx_rank_find(&ranks, edge + v);
- if(p_rank) {
- rk[v] = *p_rank;
- } else {
- /* First appearance: allocate a rank and exit it */
- unsigned rank;
- size_t tmp = htable_vrtx_rank_size_get(&ranks);
- ASSERT(tmp < UINT_MAX);
- rank = (unsigned) tmp;
- res = htable_vrtx_rank_set(&ranks, edge + v, &rank);
- if (res != RES_OK) goto error;
- rk[v] = rank;
- darray_uint_push_back(&comps, &uimax);
- darray_uint_push_back(&edges, edge + v);
- vcount++;
- }
- /* Manage components */
- cc = darray_uint_data_get(&comps);
- if(cc[rk[0]] != UINT_MAX || cc[rk[1]] != UINT_MAX) {
- /* If both components known, they must be the same */
- ASSERT(cc[rk[0]] == UINT_MAX || cc[rk[1]] == UINT_MAX
- || cc[rk[0]] == cc[rk[1]]);
- FOR_EACH(v, 0, 2) {
- unsigned w = 1 - v; /* The other vertex */
- if (cc[rk[v]] == UINT_MAX) cc[rk[v]] = cc[rk[w]];
- }
- } else {
- /* None are in a know component: create a new one */
- cc[rk[0]] = cc[rk[1]] = cc_count++;
- }
- }
- }
-
- /* Exit segments by component using the new numbering scheme */
- cc = darray_uint_data_get(&comps);
- ee = darray_uint_data_get(&edges);
- FOR_EACH(comp, 0, cc_count) {
- unsigned v;
- snprintf(name, sizeof(name), "frontier_component_%u.obj", comp);
- obj = fopen(name, "w");
- if(!obj) goto error;
- /* Exit all vertices even unused
- * (same numbering scheme for all components) */
- FOR_EACH(v, 0, vcount) {
- double coord[3];
- res = senc_descriptor_get_global_vertex(analyze, ee[v], coord);
- if(res != RES_OK) goto error;
- fprintf(obj, "v %f %f %f\n", SPLIT3(coord));
- }
- FOR_EACH(i, 0, scount) {
- unsigned edge[2], new_ranks[2];
- res = senc_descriptor_get_frontier_segment(analyze, i, edge);
- if(res != RES_OK) goto error;
- ASSERT(cc[edge[0]] == cc[edge[1]]);
- if(cc[edge[0]] != comp)
- /* Segment not in this component */
- continue;
- FOR_EACH(v, 0, 2) {
- unsigned* p_rank;
- p_rank = htable_vrtx_rank_find(&ranks, edge + v);
- ASSERT(p_rank && *p_rank < vcount);
- new_ranks[v] = *p_rank;
- }
-#define OBJ_IDX(Rank) ((Rank)+1)
- fprintf(obj, "l %u %u\n", OBJ_IDX(new_ranks[0]), OBJ_IDX(new_ranks[1]));
-#undef OBJ_IDX
- }
- fclose(obj); obj = NULL;
- }
+ const struct add_geom_ctx* ctx = context;
+ struct compute_surface* region;
+ ASSERT(ctx); (void)itri;
+ region = ctx->custom;
+ /* The triangle should be already in the model, but is not
+ * Keep it in err_triangles to allow dumps */
+ ERR(darray_uint_push_back(®ion->err_triangles, &unique_id));
end:
- if(obj) fclose(obj);
- if(analyze) senc_descriptor_ref_put(analyze);
- if(structs_initialized) {
- htable_vrtx_rank_release(&ranks);
- darray_uint_release(&comps);
- darray_uint_release(&edges);
- }
return res;
error:
goto end;
}
static res_T
-dump_path
- (const struct sdis_heat_path* path,
- void* context)
-{
- FILE* stream = context;
- enum sdis_heat_path_flag status = SDIS_HEAT_PATH_NONE;
- size_t i, vcount;
-
- /* Header */
- fprintf(stream, "---\n");
- fprintf(stream, "# vtk DataFile Version 2.0\n");
- fprintf(stream, "Heat paths\n");
- fprintf(stream, "ASCII\n");
- fprintf(stream, "DATASET POLYDATA\n");
- /* Write path positions */
- sdis_heat_path_get_vertices_count(path, &vcount);
- fprintf(stream, "POINTS %lu double\n", (unsigned long)vcount);
- FOR_EACH(i, 0, vcount) {
- struct sdis_heat_vertex vtx;
- CHK(sdis_heat_path_get_vertex(path, i, &vtx) == RES_OK);
- fprintf(stream, "%g %g %g\n", SPLIT3(vtx.P));
- }
- /* Write the segment of the path */
- fprintf(stream, "LINES %lu %lu\n", 1lu, (unsigned long)(1 + vcount));
- fprintf(stream, "%lu", (unsigned long)vcount);
- FOR_EACH(i, 0, vcount) fprintf(stream, " %lu", (unsigned long)i);
- fprintf(stream, "\n");
- fprintf(stream, "POINT_DATA %lu\n", (unsigned long)vcount);
- /* Write the type of the random walk vertices */
- fprintf(stream, "SCALARS Vertex_Type float 1\n");
- fprintf(stream, "LOOKUP_TABLE vertex_type\n");
- FOR_EACH(i, 0, vcount) {
- struct sdis_heat_vertex vtx;
- CHK(sdis_heat_path_get_vertex(path, i, &vtx) == RES_OK);
- switch (vtx.type) {
- case SDIS_HEAT_VERTEX_CONDUCTION: fprintf(stream, "0.0\n"); break;
- case SDIS_HEAT_VERTEX_CONVECTION: fprintf(stream, "0.5\n"); break;
- case SDIS_HEAT_VERTEX_RADIATIVE: fprintf(stream, "1.0\n"); break;
- default: FATAL("Unreachable code.\n"); break;
- }
- }
- fprintf(stream, "LOOKUP_TABLE vertex_type 3\n");
- fprintf(stream, "0.0 1.0 1.0 1.0\n"); /* 0.0 = Magenta: conduction */
- fprintf(stream, "1.0 1.0 0.0 1.0\n"); /* 0.5 = Yellow: convection */
- fprintf(stream, "1.0 0.0 1.0 1.0\n"); /* 1.0 = Purple: radiative */
- /* Write the weights of the random walk vertices */
- fprintf(stream, "SCALARS Weight double 1\n");
- fprintf(stream, "LOOKUP_TABLE default\n");
- FOR_EACH(i, 0, vcount) {
- struct sdis_heat_vertex vtx;
- CHK(sdis_heat_path_get_vertex(path, i, &vtx) == RES_OK);
- fprintf(stream, "%g\n", vtx.weight);
- }
- /* Write the time of the random walk vertices */
- fprintf(stream, "SCALARS Time double 1\n");
- fprintf(stream, "LOOKUP_TABLE default\n");
- FOR_EACH(i, 0, vcount) {
- struct sdis_heat_vertex vtx;
- CHK(sdis_heat_path_get_vertex(path, i, &vtx) == RES_OK);
- fprintf(stream, "%g\n", IS_INF(vtx.time) ? FLT_MAX : vtx.time);
- }
- /* Write path type */
- fprintf(stream, "CELL_DATA %lu\n", 1lu);
- fprintf(stream, "SCALARS Path_Type float 1\n");
- fprintf(stream, "LOOKUP_TABLE path_type\n");
- CHK(sdis_heat_path_get_status(path, &status) == RES_OK);
- switch (status) {
- case SDIS_HEAT_PATH_SUCCEED: fprintf(stream, "0.0\n"); break;
- case SDIS_HEAT_PATH_FAILED: fprintf(stream, "1.0\n"); break;
- default: FATAL("Unreachable code.\n"); break;
- }
- fprintf(stream, "LOOKUP_TABLE path_type 2\n");
- fprintf(stream, "0.0 0.0 1.0 1.0\n"); /* 0.0 = Blue: success */
- fprintf(stream, "1.0 0.0 0.0 1.0\n"); /* 1.0 = Red: failure */
- return RES_OK;
-}
-
-static res_T
-print_power_term
- (struct sdis_medium* mdm,
- const double power_term,
- void* ctx)
+merge_compute_surface_triangle
+ (const unsigned unique_id,
+ const unsigned itri,
+ const int reversed_triangle,
+ unsigned triangle_properties[SG3D_PROP_TYPES_COUNT__],
+ const unsigned merged_properties[SG3D_PROP_TYPES_COUNT__],
+ void* context,
+ int* merge_conflict_status)
{
- struct sdis_data* data = NULL;
- enum sdis_medium_type type;
- unsigned id;
- struct w_ctx* w_ctx = ctx;
- (void)w_ctx;
- CHK(mdm && ctx);
-
- data = sdis_medium_get_data(mdm);
- type = sdis_medium_get_type(mdm);
-
- switch (type) {
- case SDIS_FLUID: {
- FATAL("Unexpected power term in fluid");
-#if 0
- struct fluid* d__ = sdis_data_get(data);
- id = d__->id;
- desc = (struct description*)ctx + id;
- ASSERT(id == desc->d.fluid.fluid_id);
- printf("\tF\t%u\t%g", id, power_term);
- break;
-#endif
- }
- case SDIS_SOLID: {
- struct solid* d__ = sdis_data_get(data);
- id = d__->id;
- ASSERT(id == w_ctx->desc[id].d.solid.solid_id);
- printf("\tS\t%u\t%g", id, power_term);
- break;
- }
- default: FATAL("Unreachable code.\n"); break;
- }
- return RES_OK;
+ res_T res = RES_OK;
+ const struct add_geom_ctx* ctx = context;
+ struct compute_surface* region;
+ size_t uid;
+ enum sdis_side side = reversed_triangle ? SDIS_BACK : SDIS_FRONT;
+ ASSERT(ctx);
+ (void)itri; (void)reversed_triangle; (void)triangle_properties;
+ (void)merged_properties; (void)merge_conflict_status;
+ region = ctx->custom;
+ /* Build the compute region */
+ uid = unique_id;
+ ERR(darray_size_t_push_back(®ion->primitives, &uid));
+ ERR(darray_sides_push_back(®ion->sides, &side));
+end:
+ return res;
+error:
+ goto end;
}
static res_T
-get_flux_terms
- (struct sdis_interface* interf,
- const enum sdis_side side,
- const double flux_term,
- void* ctx)
+compute_boundary(struct stardis* stardis)
{
- struct sdis_data* data = NULL;
- struct intface* d__;
- unsigned id;
- struct w_ctx* w_ctx = ctx;
res_T res = RES_OK;
-
- CHK(interf && ctx);
-
- data = sdis_interface_get_data(interf);
- d__ = sdis_data_get(data);
- id = (side == SDIS_FRONT) ? d__->front_boundary_id : d__->back_boundary_id;
-
- switch (w_ctx->desc[id].type) {
- case DESC_BOUND_T_FOR_SOLID:
- case DESC_BOUND_T_FOR_FLUID:
- case DESC_BOUND_H_FOR_SOLID:
- case DESC_BOUND_H_FOR_FLUID:
- FATAL("Cannot have a flux term here.\n"); break;
- case DESC_BOUND_F_FOR_SOLID: {
- double* w;
- ASSERT(id == w_ctx->desc[id].d.f_boundary.mat_id);
- w = htable_weigth_find(&w_ctx->weigths, &id);
- if (w)
- *w += flux_term;
- else {
- res = htable_weigth_set(&w_ctx->weigths, &id, &flux_term);
+ struct sdis_green_function* green = NULL;
+ struct sdis_estimator* estimator = NULL;
+ struct dump_path_context dump_ctx;
+ struct sdis_solve_boundary_args args = SDIS_SOLVE_BOUNDARY_ARGS_DEFAULT;
+ FILE* stream = NULL;
+
+ ASSERT(stardis && (stardis->mode & MODE_BOUNDARY_COMPUTE));
+
+ args.nrealisations = stardis->samples;
+ args.primitives
+ = darray_size_t_cdata_get(&stardis->compute_surface.primitives);
+ args.sides = darray_sides_cdata_get(&stardis->compute_surface.sides);
+ args.nprimitives
+ = darray_size_t_size_get(&stardis->compute_surface.primitives);
+ d2_set(args.time_range, stardis->time_range);
+
+ if(stardis->mode & (MODE_BIN_GREEN | MODE_GREEN)) {
+ ERR(sdis_solve_boundary_green_function(stardis->sdis_scn, &args, &green));
+ if(stardis->mode & MODE_BIN_GREEN) {
+ ASSERT(!str_is_empty(&stardis->bin_green_filename));
+ stream = fopen(str_cget(&stardis->bin_green_filename), "wb");
+ if(!stream) {
+ res = RES_IO_ERR;
+ goto error;
+ }
+ ERR(dump_green_bin(green, stardis, stream));
+ fclose(stream); stream = NULL;
+ if(str_cget(&stardis->end_paths_filename)
+ && strlen(str_cget(&stardis->end_paths_filename)))
+ {
+ stream = fopen(str_cget(&stardis->end_paths_filename), "w");
+ if(!stream) {
+ res = RES_IO_ERR;
+ goto error;
+ }
+ ERR(dump_paths_end(green, stardis, stream));
+ fclose(stream); stream = NULL;
+ }
}
- break;
- }
- default: FATAL("Unreachable code.\n"); break;
+ if(stardis->mode & MODE_GREEN) {
+ ERR(dump_green_ascii(green, stardis, stdout));
+ }
+ } else {
+ args.register_paths = stardis->dump_paths;
+ ERR(sdis_solve_boundary(stardis->sdis_scn, &args, &estimator));
+ ERR(print_single_MC_result(estimator, stardis, stdout));
+ /* Dump paths recorded according to user settings */
+ dump_ctx.stardis = stardis;
+ dump_ctx.rank = 0;
+ ERR(sdis_estimator_for_each_path(estimator, dump_path, &dump_ctx));
}
+
+end:
+ if(stream) fclose(stream);
+ if(estimator) SDIS(estimator_ref_put(estimator));
+ if(green) SDIS(green_function_ref_put(green));
return res;
+error:
+ goto end;
}
static res_T
-print_sample
- (struct sdis_green_path* path,
- void* ctx)
+compute_flux_boundary(struct stardis* stardis)
{
- struct sdis_point pt = SDIS_POINT_NULL;
- struct sdis_data* data = NULL;
- enum sdis_medium_type type;
- struct htable_weigth_iterator it, end;
- unsigned id;
- size_t pcount, fcount;
- struct w_ctx* w_ctx = ctx;
res_T res = RES_OK;
- CHK(path && ctx);
-
- res = sdis_green_path_get_limit_point(path, &pt);
- if (res != RES_OK) goto error;
-
-
- /* For each path, prints:
- * # end #power_terms #flux_terms power_term_1 ... power_term_n flux_term_1 ... flux_term_n
- * with:
- * - end = end_type end_id; end_type = T | H | X | R | F | S
- * - power_term_i = power_type_i power_id_i factor_i
- * - flux_term_i = flux_id_i factor_i
- */
-
- switch (pt.type) {
- case SDIS_FRAGMENT: {
- struct intface* d__;
- data = sdis_interface_get_data(pt.data.itfrag.intface);
- d__ = sdis_data_get(data);
- id = (pt.data.itfrag.fragment.side == SDIS_FRONT)
- ? d__->front_boundary_id : d__->back_boundary_id;
- ASSERT(id != UINT_MAX);
- switch (w_ctx->desc[id].type) {
- case DESC_BOUND_T_FOR_SOLID:
- case DESC_BOUND_T_FOR_FLUID:
- ASSERT(id == w_ctx->desc[id].d.t_boundary.mat_id);
- printf("T\t%u", id);
- break;
- case DESC_BOUND_H_FOR_SOLID:
- case DESC_BOUND_H_FOR_FLUID:
- ASSERT(id == w_ctx->desc[id].d.h_boundary.mat_id);
- printf("H\t%u", id);
- break;
- case DESC_BOUND_F_FOR_SOLID:
- ASSERT(id == w_ctx->desc[id].d.f_boundary.mat_id);
- printf("X\t%u", id);
- break;
- default: FATAL("Unreachable code.\n"); break;
- }
- break;
- }
- case SDIS_VERTEX:
- type = sdis_medium_get_type(pt.data.mdmvert.medium);
- data = sdis_medium_get_data(pt.data.mdmvert.medium);
- if (pt.data.mdmvert.vertex.P[0] == INF) {
- /* Radiative output */
- printf("R\t%u", (unsigned)sa_size(w_ctx->desc));
- }
- else if (type == SDIS_FLUID) {
- struct fluid* d__ = sdis_data_get(data);
- id = d__->id;
- ASSERT(id == w_ctx->desc[id].d.fluid.fluid_id);
- if (d__->is_outside)
- /* If outside the model and in a fluid with known temperature,
- * its a fluid attached to a H boundary */
- printf("H\t%u", id);
- /* In a standard fluid with known temperature */
- else printf("F\t%u", id);
-
- } else {
- struct solid* d__ = sdis_data_get(data);
- ASSERT(type == SDIS_SOLID);
- id = d__->id;
- ASSERT(id == w_ctx->desc[id].d.solid.solid_id);
- ASSERT(!d__->is_outside); /* FIXME: what if in external solid? */
- printf("S\t%u", id);
- }
- break;
- default: FATAL("Unreachable code.\n"); break;
- }
-
- res = sdis_green_function_get_power_terms_count(path, &pcount);
- if (res != RES_OK) goto error;
+ struct sdis_green_function* green = NULL;
+ struct sdis_estimator* estimator = NULL;
+ struct sdis_solve_boundary_flux_args args
+ = SDIS_SOLVE_BOUNDARY_FLUX_ARGS_DEFAULT;
+ struct dump_path_context dump_ctx;
- htable_weigth_clear(&w_ctx->weigths);
- res = sdis_green_path_for_each_flux_term(path, get_flux_terms, w_ctx);
- if (res != RES_OK) goto error;
- fcount = htable_weigth_size_get(&w_ctx->weigths);
+ ASSERT(stardis && (stardis->mode & MODE_FLUX_BOUNDARY_COMPUTE));
- printf("\t%zu\t%zu", pcount, fcount);
+ args.nrealisations = stardis->samples;
+ args.primitives
+ = darray_size_t_cdata_get(&stardis->compute_surface.primitives);
+ args.nprimitives
+ = darray_size_t_size_get(&stardis->compute_surface.primitives);
+ d2_set(args.time_range, stardis->time_range);
- res = sdis_green_path_for_each_power_term(path, print_power_term, ctx);
- if (res != RES_OK) goto error;
+ ERR(sdis_solve_boundary_flux(stardis->sdis_scn, &args, &estimator));
+ ERR(print_single_MC_result(estimator, stardis, stdout));
- htable_weigth_begin(&w_ctx->weigths, &it);
- htable_weigth_end(&w_ctx->weigths, &end);
- while (!htable_weigth_iterator_eq(&it, &end)) {
- double* w = htable_weigth_iterator_data_get(&it);
- unsigned* k = htable_weigth_iterator_key_get(&it);
- printf("\t%u\t%g", *k, *w);
- htable_weigth_iterator_next(&it);
- }
- printf("\n");
+ /* Dump paths recorded according to user settings */
+ dump_ctx.stardis = stardis;
+ dump_ctx.rank = 0;
+ ERR(sdis_estimator_for_each_path(estimator, dump_path, &dump_ctx));
-error:
+end:
+ if(estimator) SDIS(estimator_ref_put(estimator));
+ if(green) SDIS(green_function_ref_put(green));
return res;
+error:
+ goto end;
}
-res_T
-stardis_compute(struct stardis* stardis, enum stardis_mode mode)
+static res_T
+compute_map(struct stardis* stardis)
{
res_T res = RES_OK;
- struct sdis_device* dev = NULL;
- struct sdis_medium** media = NULL;
- struct sdis_interface** interfaces = NULL;
- struct sdis_interface** interf_bytrg = NULL;
- struct sdis_data* data = NULL;
-
- struct sdis_scene* scn = NULL;
- struct sdis_estimator* estimator = NULL;
- struct sdis_mc temperature;
- struct sdis_estimator_buffer* buf = NULL;
- struct sdis_camera* cam = NULL;
-
- struct sdis_medium* dummy_fluid = NULL;
- unsigned dummy_fluid_id = UINT_MAX;
- struct sdis_medium* dummy_solid = NULL;
- unsigned dummy_solid_id = UINT_MAX;
-
- struct htable_intface htable_interfaces;
- int htable_interfaces_initialised = 0;
- double pos[3] = { 0,0,0 };
- double time[2] = { 0, 0 };
- size_t nfailures;
- size_t smed_count = 0, fmed_count = 0,
- tbound_count = 0, hbound_count = 0, fbound_count = 0, sfconnect_count = 0;
- unsigned i = 0;
-
- res = sdis_device_create(NULL, &stardis->allocator, stardis->nthreads, 1, &dev);
- if (res != RES_OK) goto error;
-
- /* Create media and property holders found in descriptions */
- for (i = 0; i < sa_size(stardis->descriptions); ++i) {
- struct description* desc = stardis->descriptions + i;
- /* Could be less restrictive if green output included positions/dates */
- int prohibited = (mode & GREEN_MODE) ? NO_VAR_ALLOWED : ALL_VARS_ALLOWED;
-
- switch (desc->type) {
- case DESC_BOUND_H_FOR_SOLID:
- hbound_count++;
- /* Create an external fluid with bound temp as fluid temp */
- res = create_fluid(dev, NULL, 1, 1, (mode & GREEN_MODE), 1, NULL,
- desc->d.h_boundary.T, &media, &desc->d.h_boundary.mat_id);
- if (res != RES_OK) goto error;
- break;
- case DESC_BOUND_H_FOR_FLUID:
- /* Create an external solid with bound temp as solid temp */
- hbound_count++;
- res = create_solid(dev, NULL, INF, 1, 1, 1, (mode & GREEN_MODE), 1, NULL,
- desc->d.h_boundary.T, NULL, &media, NULL, &desc->d.h_boundary.mat_id);
- if (res != RES_OK) goto error;
- break;
- case DESC_BOUND_T_FOR_SOLID:
- tbound_count++;
- ASSERT(desc->d.t_boundary.T != NULL);
- res = compile_expr_to_fn(&desc->d.t_boundary.te_temperature,
- desc->d.t_boundary.T, prohibited, NULL);
- if (res != RES_OK) {
- fprintf(stderr, "Invalid boundary temperature expression: %s\n",
- desc->d.t_boundary.T);
- goto error;
- }
- if (dummy_fluid) {
- /* Reuse external dummy fluid */
- desc->d.t_boundary.mat_id = dummy_fluid_id;
- } else {
- /* Create dummy fluid */
- res = create_fluid(dev, NULL, 1, 1, (mode & GREEN_MODE), 1, NULL,
- NULL, &media, &desc->d.t_boundary.mat_id);
- if (res != RES_OK) goto error;
- dummy_fluid = sa_last(media);
- dummy_fluid_id = desc->d.t_boundary.mat_id;
- }
- break;
- case DESC_BOUND_T_FOR_FLUID:
- tbound_count++;
- ASSERT(desc->d.t_boundary.T != NULL);
- res = compile_expr_to_fn(&desc->d.t_boundary.te_temperature,
- desc->d.t_boundary.T, prohibited, NULL);
- if (res != RES_OK) {
- fprintf(stderr, "Invalid boundary temperature expression: %s\n",
- desc->d.t_boundary.T);
- goto error;
- }
- if (dummy_solid) {
- /* Reuse external dummy solid */
- desc->d.t_boundary.mat_id = dummy_solid_id;
- } else {
- /* Create dummy solid */
- res = create_solid(dev, NULL, 1, 1, 1, 1, (mode & GREEN_MODE), 1, NULL,
- NULL, NULL, &media, NULL, &desc->d.t_boundary.mat_id);
- if (res != RES_OK) goto error;
- dummy_solid = sa_last(media);
- dummy_solid_id = desc->d.t_boundary.mat_id;
- }
- break;
- case DESC_BOUND_F_FOR_SOLID:
- fbound_count++;
- ASSERT(desc->d.f_boundary.flux != NULL);
- res = compile_expr_to_fn(&desc->d.f_boundary.te_flux,
- desc->d.f_boundary.flux, 1, NULL);
- if (res != RES_OK) {
- fprintf(stderr, "Invalid boundary flux expression: %s\n",
- desc->d.f_boundary.flux);
- goto error;
- }
- if (dummy_fluid) {
- /* Reuse external dummy fluid */
- desc->d.f_boundary.mat_id = dummy_fluid_id;
- } else {
- /* Create dummy fluid */
- res = create_fluid(dev, NULL, 1, 1, (mode & GREEN_MODE), 1, NULL, NULL,
- &media, &desc->d.f_boundary.mat_id);
- if (res != RES_OK) goto error;
- dummy_fluid = sa_last(media);
- dummy_fluid_id = desc->d.f_boundary.mat_id;
- }
- break;
- case DESC_SOLID_FLUID_CONNECT:
- sfconnect_count++;
- ASSERT(desc->d.sf_connect.specular_fraction >= 0
- && desc->d.sf_connect.specular_fraction <= 1);
- ASSERT(desc->d.sf_connect.emissivity >= 0);
- ASSERT(desc->d.sf_connect.hc >= 0);
- break;
- case DESC_MAT_SOLID:
- smed_count++;
- res = create_solid(dev,
- stardis->descriptions[i].d.solid.name,
- stardis->descriptions[i].d.solid.lambda,
- stardis->descriptions[i].d.solid.rho,
- stardis->descriptions[i].d.solid.cp,
- stardis->descriptions[i].d.solid.delta,
- (mode & GREEN_MODE),
- 0,
- stardis->descriptions[i].d.solid.Tinit,
- stardis->descriptions[i].d.solid.Temp,
- stardis->descriptions[i].d.solid.power,
- &media,
- &stardis->descriptions[i].d.solid.has_power,
- &desc->d.solid.solid_id);
- if (res != RES_OK) goto error;
- break;
- case DESC_MAT_FLUID:
- fmed_count++;
- res = create_fluid(dev,
- stardis->descriptions[i].d.fluid.name,
- stardis->descriptions[i].d.fluid.rho,
- stardis->descriptions[i].d.fluid.cp,
- (mode & GREEN_MODE),
- 0,
- stardis->descriptions[i].d.fluid.Tinit,
- stardis->descriptions[i].d.fluid.Temp,
- &media,
- &desc->d.fluid.fluid_id);
- if (res != RES_OK) goto error;
-
- break;
- default: FATAL("Invalid type.\n");
- }
+ struct sdis_green_function* green = NULL;
+ struct sdis_solve_boundary_args args = SDIS_SOLVE_BOUNDARY_ARGS_DEFAULT;
+ struct darray_estimators estimators;
+ int estimators_initialized = 0;
+ size_t p;
+
+ ASSERT(stardis
+ && (stardis->mode & MODE_MAP_COMPUTE)
+ && !(stardis->mode & (MODE_BIN_GREEN | MODE_GREEN)));
+
+ darray_estimators_init(stardis->allocator, &estimators);
+ estimators_initialized = 1;
+
+ ERR(darray_estimators_resize(&estimators,
+ darray_estimators_size_get(&estimators) +
+ darray_size_t_size_get(&stardis->compute_surface.primitives)));
+
+ FOR_EACH(p, 0, darray_size_t_size_get(&stardis->compute_surface.primitives)) {
+
+ args.nrealisations = stardis->samples;
+ args.primitives
+ = darray_size_t_cdata_get(&stardis->compute_surface.primitives);
+ args.sides = darray_sides_cdata_get(&stardis->compute_surface.sides);
+ args.nprimitives
+ = darray_size_t_size_get(&stardis->compute_surface.primitives);
+ d2_set(args.time_range, stardis->time_range);
+ args.register_paths = stardis->dump_paths;
+
+ ERR(sdis_solve_boundary(stardis->sdis_scn, &args,
+ darray_estimators_data_get(&estimators) + p));
}
+ dump_map(stardis, &estimators, stdout);
- /* Create interfaces */
- htable_intface_init(&stardis->allocator, &htable_interfaces);
- htable_interfaces_initialised = 1;
- for (i = 0; i < sa_size(stardis->geometry.triangle); ++i) {
- struct triangle *trg = stardis->geometry.triangle + i;
- struct int_descs int_descs = INT_DESCS_NULL;
- struct sdis_interface** p_intface;
- struct sdis_interface* intface;
- struct sdis_medium* front_med = NULL;
- struct sdis_medium* back_med = NULL;
- struct sdis_interface_side_shader* fluid_side_shader = NULL;
- unsigned fd = trg->front_description;
- unsigned bd = trg->back_description;
- unsigned cd = trg->connection_description;
- int fluid_count = 0, solid_count = 0;
- int solid_fluid_connection_count = 0, connection_count = 0, boundary_count = 0;
-
- /* Create key */
- int_descs.front = fd;
- int_descs.back = bd;
- int_descs.connect = trg->connection_description;
-
- /* Search if interface already exists, or create it */
- p_intface = htable_intface_find(&htable_interfaces, &int_descs);
- if (p_intface) {
- intface = *p_intface;
- } else {
- /* create new interface and register */
- struct sdis_interface_shader interface_shader = SDIS_INTERFACE_SHADER_NULL;
- struct intface* interface_props = NULL;
- unsigned id;
- int front_defined = (fd != UINT_MAX);
- int back_defined = (bd != UINT_MAX);
- int connect_defined = (cd != UINT_MAX);
-
- SDIS(data_create(dev, sizeof(struct intface), ALIGNOF(struct intface),
- release_interface_data, &data));
- interface_props = sdis_data_get(data);
- interface_props->temperature = NULL;
- interface_props->flux = NULL;
- interface_props->front_boundary_id = UINT_MAX;
- interface_props->back_boundary_id = UINT_MAX;
-
- if (front_defined) {
- switch (stardis->descriptions[fd].type) {
- case DESC_MAT_SOLID:
- id = stardis->descriptions[fd].d.solid.solid_id;
- solid_count++;
- front_med = media[id];
- break;
- case DESC_MAT_FLUID:
- fluid_count++;
- id = stardis->descriptions[fd].d.fluid.fluid_id;
- front_med = media[id];
- fluid_side_shader = &interface_shader.front;
- break;
- default: FATAL("Invalid type.\n");
- }
- }
- if (back_defined) {
- switch (stardis->descriptions[bd].type) {
- case DESC_MAT_SOLID:
- id = stardis->descriptions[bd].d.solid.solid_id;
- solid_count++;
- back_med = media[id];
- break;
- case DESC_MAT_FLUID:
- fluid_count++;
- id = stardis->descriptions[bd].d.fluid.fluid_id;
- back_med = media[id];
- fluid_side_shader = &interface_shader.back;
- break;
- default: FATAL("Invalid type.\n");
- }
- }
- if (connect_defined) {
- const struct description* connect = stardis->descriptions + cd;
- int type_checked = 0;
- struct sdis_medium* def_medium = NULL;
- unsigned ext_id;
- if (connect->type == DESC_SOLID_FLUID_CONNECT) {
- if (solid_count != 1 || fluid_count != 1) {
- ASSERT(front_defined && back_defined);
- fprintf(stderr,
- "Can only define a DESC_SOLID_FLUID_CONNECT between a fluid and a solid\n");
- res = RES_BAD_ARG;
- goto error;
- }
- } else {
- if (front_defined == back_defined) {
- fprintf(stderr,
- "Cannot define a boundary between 2 %s regions\n",
- front_defined ? "defined" : "undefined");
- res = RES_BAD_ARG;
- goto error;
- }
- def_medium = front_defined ? front_med : back_med;
- if (front_defined)
- interface_props->front_boundary_id = cd;
- else interface_props->back_boundary_id = cd;
- }
- switch (connect->type) {
- case DESC_BOUND_H_FOR_FLUID:
- if (sdis_medium_get_type(def_medium) != SDIS_FLUID) {
- fprintf(stderr,
- "Can only define a DESC_BOUND_H_FOR_FLUID boundary for a fluid region\n");
- res = RES_BAD_ARG;
- goto error;
- }
- type_checked = 1;
- /* fall through */
- case DESC_BOUND_H_FOR_SOLID:
- if (!type_checked
- && sdis_medium_get_type(def_medium) != SDIS_SOLID) {
- fprintf(stderr,
- "Can only define a DESC_BOUND_H_FOR_SOLID boundary for a solid region\n");
- res = RES_BAD_ARG;
- goto error;
- }
- ext_id = connect->d.h_boundary.mat_id; /* External material id */
- ASSERT(ext_id < sa_size(media));
- ASSERT(sdis_medium_get_type(media[ext_id]) ==
- (connect->type == DESC_BOUND_H_FOR_SOLID ? SDIS_FLUID : SDIS_SOLID));
- connection_count++;
- boundary_count++;
- if (front_defined) back_med = media[ext_id];
- else front_med = media[ext_id];
- interface_shader.convection_coef = interface_get_convection_coef;
- interface_shader.convection_coef_upper_bound = connect->d.h_boundary.hc_max;
- interface_props->hc = connect->d.h_boundary.hc;
- ASSERT(!fluid_side_shader); /* Cause defined medium is solid */
- if (connect->d.h_boundary.has_emissivity) {
- fluid_side_shader =
- front_defined ? &interface_shader.back : &interface_shader.front;
- fluid_side_shader->emissivity = interface_get_emissivity;
- interface_props->emissivity = connect->d.h_boundary.emissivity;
- interface_props->alpha = connect->d.h_boundary.specular_fraction;
- }
- break;
- case DESC_BOUND_T_FOR_FLUID:
- if (sdis_medium_get_type(def_medium) != SDIS_FLUID) {
- fprintf(stderr,
- "Can only define a DESC_BOUND_T_FOR_FLUID boundary for a fluid region\n");
- res = RES_BAD_ARG;
- goto error;
- }
- type_checked = 1;
- /* fall through */
- case DESC_BOUND_T_FOR_SOLID:
- if (!type_checked
- && sdis_medium_get_type(def_medium) != SDIS_SOLID) {
- fprintf(stderr,
- "Can only define a DESC_BOUND_T_FOR_SOLID boundary for a solid region\n");
- res = RES_BAD_ARG;
- goto error;
- }
- ext_id = connect->d.t_boundary.mat_id; /* External material id */
- ASSERT(ext_id < sa_size(media));
- ASSERT(sdis_medium_get_type(media[ext_id]) == SDIS_FLUID);
- connection_count++;
- boundary_count++;
- if (front_defined) {
- back_med = media[ext_id];
- /* We set the known T inside
- * TODO: should be outside to allow contact resistances */
- interface_shader.front.temperature = interface_get_temperature;
- } else {
- front_med = media[ext_id];
- /* We set the known T inside
- * TODO: should be outside to allow contact resistances */
- interface_shader.back.temperature = interface_get_temperature;
- }
- ASSERT(connect->d.t_boundary.te_temperature);
- interface_props->temperature
- = te_duplicate(connect->d.t_boundary.te_temperature);
- if (connect->d.t_boundary.has_hc) {
- ASSERT(connect->type == DESC_BOUND_T_FOR_FLUID);
- interface_shader.convection_coef = interface_get_convection_coef;
- interface_shader.convection_coef_upper_bound = connect->d.t_boundary.hc_max;
- interface_props->hc = connect->d.t_boundary.hc;
- }
- break;
- case DESC_BOUND_F_FOR_SOLID:
- if (sdis_medium_get_type(def_medium) != SDIS_SOLID) {
- fprintf(stderr,
- "Can only define a DESC_BOUND_F_FOR_SOLID boundary for a solid region\n");
- res = RES_BAD_ARG;
- goto error;
- }
- connection_count++;
- boundary_count++;
- if (front_defined) {
- back_med = media[connect->d.f_boundary.mat_id];
- interface_shader.front.flux = interface_get_flux;
- } else {
- front_med = media[connect->d.f_boundary.mat_id];
- interface_shader.back.flux = interface_get_flux;
- }
- ASSERT(connect->d.f_boundary.te_flux);
- interface_props->flux = te_duplicate(connect->d.f_boundary.te_flux);
- break;
- case DESC_SOLID_FLUID_CONNECT:
- /* Both front and back should be defined;
- * if not will raise an error below */
- connection_count++;
- solid_fluid_connection_count++;
- ASSERT(fluid_side_shader);
- if (connect->d.sf_connect.has_hc) {
- interface_shader.convection_coef = interface_get_convection_coef;
- interface_shader.convection_coef_upper_bound = connect->d.sf_connect.hc_max;
- interface_props->hc = connect->d.sf_connect.hc;
- }
- if (connect->d.sf_connect.has_emissivity) {
- fluid_side_shader->emissivity = interface_get_emissivity;
- interface_props->emissivity = connect->d.sf_connect.emissivity;
- interface_props->alpha = connect->d.sf_connect.specular_fraction;
- }
- break;
- default: FATAL("Invalid type.\n");
- }
- }
-
- if ((fluid_count == 2)
- || (fluid_count + solid_count + connection_count < 2)
- || (boundary_count ?
- (fluid_count + solid_count != 1) : (fluid_count + solid_count != 2))
- || (solid_fluid_connection_count && (fluid_count != 1 || solid_count != 1)))
- {
- /* Incoherent triangle description */
- fprintf(stderr, "Incoherent triangle description (%u)\n", i);
- print_trg_as_obj(stderr, stardis->geometry.vertex, trg->indices.data);
- fprintf(stderr, "Front: ");
- if (!front_defined) fprintf(stderr, "undefined\n");
- else print_description(stderr, &stardis->descriptions[fd]);
- fprintf(stderr, "Back: ");
- if (!back_defined) fprintf(stderr, "undefined\n");
- else print_description(stderr, &stardis->descriptions[bd]);
- fprintf(stderr, "Connection: ");
- if (!connect_defined) fprintf(stderr, "undefined\n");
- else print_description(stderr, &stardis->descriptions[cd]);
- res = RES_BAD_ARG;
- goto error;
- }
-
- res = sdis_interface_create(dev, front_med, back_med,
- &interface_shader, data, &intface);
- SDIS(data_ref_put(data)); data = NULL;
- if (res != RES_OK) {
- fprintf(stderr,
- "Cannot create interface associated to triangle %u\n", i);
- goto error;
- }
- sa_push(interfaces, intface);
- res = htable_intface_set(&htable_interfaces, &int_descs, &intface);
- if (res != RES_OK) goto error;
+end:
+ if(estimators_initialized) {
+ struct sdis_estimator** est = darray_estimators_data_get(&estimators);
+ FOR_EACH(p, 0, darray_size_t_size_get(&stardis->compute_surface.primitives)) {
+ SDIS(estimator_ref_put(est[p]));
}
- sa_push(interf_bytrg, intface);
+ darray_estimators_release(&estimators);
}
- stardis->geometry.interf_bytrg = interf_bytrg;
- stardis->geometry.interfaces = interfaces;
-
- res = sdis_scene_create(dev,
- sa_size(stardis->geometry.triangle),
- geometry_get_indices, geometry_get_interface,
- sa_size(stardis->geometry.vertex),
- geometry_get_position, &stardis->geometry, &scn);
- if (res != RES_OK) goto error;
-
- res = create_edge_file_if(scn, &stardis->allocator);
- if (res != RES_OK) goto error;
-
- if (mode & GREEN_MODE) {
- struct sdis_green_function* green = NULL;
- size_t ok_count, failed_count;
- struct w_ctx w_ctx;
- ASSERT((mode & PROBE_COMPUTE) || (mode & PROBE_COMPUTE_ON_INTERFACE)
- || (mode & BOUNDARY_COMPUTE) || (mode & MEDIUM_COMPUTE));
-
- if (mode & PROBE_COMPUTE || mode & PROBE_COMPUTE_ON_INTERFACE) {
- double uv[2] = { 0,0 };
- size_t iprim = SIZE_MAX;
- /* Launch the probe simulation */
- pos[0] = stardis->probe[0];
- pos[1] = stardis->probe[1];
- pos[2] = stardis->probe[2];
-
- res = select_probe_type(scn,
- stardis->geometry.triangle,
- stardis->geometry.vertex,
- stardis->descriptions,
- (mode & PROBE_COMPUTE_ON_INTERFACE),
- pos,
- &iprim,
- uv);
- if (res != RES_OK) goto error;
-
- if (iprim == SIZE_MAX) {
- res = sdis_solve_probe_green_function(scn,
- stardis->N,
- pos,
- stardis->scale_factor,
- stardis->radiative_temp[0],
- stardis->radiative_temp[1],
- &green);
- } else {
- res = sdis_solve_probe_boundary_green_function(scn,
- stardis->N,
- iprim,
- uv,
- SDIS_FRONT,
- stardis->scale_factor,
- stardis->radiative_temp[0],
- stardis->radiative_temp[1],
- &green);
- }
- }
- else if (mode & BOUNDARY_COMPUTE) {
- ASSERT(sa_size(stardis->boundary.primitives)
- == sa_size(stardis->boundary.sides));
- if (sa_size(stardis->boundary.sides) == 0) {
- fprintf(stderr, "Cannot solve boundary %s (empty geometry)\n",
- stardis->solve_name);
- }
+ if(green) SDIS(green_function_ref_put(green));
+ return res;
+error:
+ goto end;
+}
- res = sdis_solve_boundary_green_function(scn,
- stardis->N,
- stardis->boundary.primitives,
- stardis->boundary.sides,
- sa_size(stardis->boundary.sides),
- stardis->scale_factor,
- stardis->radiative_temp[0],
- stardis->radiative_temp[1],
- &green);
- }
- else if (mode & MEDIUM_COMPUTE) {
- size_t sz, ii;
- struct sdis_medium* medium = NULL;
- /* Find medium */
- sz = sa_size(stardis->descriptions);
- FOR_EACH(ii, 0, sz) {
- struct description* desc = stardis->descriptions + ii;
- if (desc->type == DESC_MAT_SOLID) {
- if (0 == strcmp(stardis->solve_name, desc->d.solid.name)) {
- ASSERT(sa_size(media) > ii);
- medium = media[ii];
- break;
- }
- }
- else if (desc->type == DESC_MAT_FLUID) {
- if (0 == strcmp(stardis->solve_name, desc->d.fluid.name)) {
- ASSERT(sa_size(media) > ii);
- medium = media[ii];
- break;
- }
- }
- }
- if (medium == NULL) {
- /* Not found */
- fprintf(stderr, "Cannot solve medium %s (unknown medium)\n",
- stardis->solve_name);
- res = RES_BAD_ARG;
- goto error;
- }
- res = sdis_solve_medium_green_function(scn,
- stardis->N,
- medium,
- stardis->scale_factor,
- stardis->radiative_temp[0],
- stardis->radiative_temp[1],
- &green);
- }
- if (res != RES_OK) goto error;
-
- /* Output the green function */
- CHK(sdis_green_function_get_invalid_paths_count(green, &failed_count) == RES_OK);
- CHK(sdis_green_function_get_paths_count(green, &ok_count) == RES_OK);
-
- /* Output counts */
- printf("---BEGIN GREEN---\n");
- printf("# #solids #fluids #t_boundaries #h_boundaries #f_boundaries #ok #failures\n");
- printf("%zu %zu %zu %zu %zu %zu %zu\n",
- smed_count, fmed_count,
- tbound_count, hbound_count, fbound_count,
- ok_count, failed_count);
-
- /* List Media */
- if (smed_count) {
- printf("# Solids\n");
- printf("# ID Name lambda rho cp power\n");
- FOR_EACH(i, 0, (unsigned)sa_size(stardis->descriptions)) {
- struct description* desc = stardis->descriptions + i;
- struct mat_solid* sl;
- if (desc->type != DESC_MAT_SOLID) continue;
- sl = &desc->d.solid;
- printf("%u\t%s\t%g\t%g\t%g\t%s\n",
- i, sl->name, sl->lambda, sl->rho, sl->cp, (sl->has_power ? sl->power : "0"));
- }
- }
- if (fmed_count) {
- printf("# Fluids\n");
- printf("# ID Name rho cp\n");
- FOR_EACH(i, 0, sa_size(stardis->descriptions)) {
- struct description* desc = stardis->descriptions + i;
- struct mat_fluid* fl;
- fl = &desc->d.fluid;
- printf("%u\t%s\t%g\t%g\n", i, fl->name, fl->rho, fl->cp);
- }
- }
+/*******************************************************************************
+ * Public Functions
+ ******************************************************************************/
- /* List Boundaries */
- if (tbound_count) {
- printf("# T Boundaries\n");
- printf("# ID Name temperature\n");
- FOR_EACH(i, 0, sa_size(stardis->descriptions)) {
- struct description* desc = stardis->descriptions + i;
- struct t_boundary* bd;
- if (desc->type != DESC_BOUND_T_FOR_SOLID
- && desc->type != DESC_BOUND_T_FOR_FLUID) continue;
- bd = &desc->d.t_boundary;
- printf("%u\t%s\t%s\n", i, bd->name, bd->T);
- }
- }
- if (hbound_count) {
- printf("# H Boundaries\n");
- printf("# ID Name emissivity specular_fraction hc hc_max T_env\n");
- FOR_EACH(i, 0, sa_size(stardis->descriptions)) {
- struct description* desc = stardis->descriptions + i;
- struct h_boundary* bd;
- if (desc->type != DESC_BOUND_H_FOR_SOLID
- && desc->type != DESC_BOUND_H_FOR_FLUID) continue;
- bd = &desc->d.h_boundary;
- printf("%u\t%s\t%g\t%g\t%g\t%g\t%s\n",
- i, bd->name, (bd->has_emissivity ? bd->emissivity : 0),
- (bd->has_emissivity ? bd->specular_fraction : 0),
- (bd->has_hc ? bd->hc : 0), (bd->has_hc ? bd->hc_max : 0), bd->T);
+struct sdis_medium*
+find_medium_by_name
+ (struct stardis* stardis,
+ const struct str* name,
+ unsigned* out_id)
+{
+ struct sdis_medium* medium = NULL;
+ size_t i;
+
+ ASSERT(stardis && name);
+
+ FOR_EACH(i, 0, darray_descriptions_size_get(&stardis->descriptions)) {
+ struct description*
+ desc = darray_descriptions_data_get(&stardis->descriptions) + i;
+ if(desc->type == DESC_MAT_SOLID) {
+ if(str_eq(name, &desc->d.solid.name)) {
+ unsigned id = desc->d.solid.solid_id;
+ ASSERT(darray_media_ptr_size_get(&stardis->media) > id);
+ medium = darray_media_ptr_data_get(&stardis->media)[id];
+ if(out_id) *out_id = id;
+ break;
}
}
- if (fbound_count) {
- printf("# F Boundaries\n");
- printf("# ID Name flux\n");
- FOR_EACH(i, 0, sa_size(stardis->descriptions)) {
- struct description* desc = stardis->descriptions + i;
- struct f_boundary* bd;
- if (desc->type != DESC_BOUND_F_FOR_SOLID) continue;
- bd = &desc->d.f_boundary;
- printf("%u\t%s\t%s\n",
- i, bd->name, bd->flux);
+ else if(desc->type == DESC_MAT_FLUID) {
+ if(str_eq(name, &desc->d.fluid.name)) {
+ unsigned id = desc->d.fluid.fluid_id;
+ ASSERT(darray_media_ptr_size_get(&stardis->media) > id);
+ medium = darray_media_ptr_data_get(&stardis->media)[id];
+ if(out_id) *out_id = id;
+ break;
}
}
+ }
+ return medium;
+}
- /* Radiative Temperatures */
- printf("# Radiative Temperatures\n");
- printf("# ID Rad_Temp Lin_Temp\n");
- printf("%u\t%g\t%g\n", (unsigned)sa_size(stardis->descriptions),
- stardis->radiative_temp[0], stardis->radiative_temp[1]);
-
- printf("# Samples\n");
- printf("# end #power_terms #flux_terms power_term_1 ... power_term_n flux_term_1 ... flux_term_n\n");
- printf("# end = end_type end_id; end_type = T | H | X | R | F | S\n");
- printf("# power_term_i = power_type_i power_id_i factor_i\n");
- printf("# flux_term_i = flux_id_i factor_i\n");
-
- w_ctx.desc = stardis->descriptions;
- htable_weigth_init(NULL, &w_ctx.weigths);
-
- res = sdis_green_function_for_each_path(green, print_sample, &w_ctx);
- htable_weigth_release(&w_ctx.weigths);
- if (res != RES_OK) goto error;
-
-
- printf("---END GREEN---\n");
+/* Process an STL file describing a compute region
+ * Triangles must be members of the geometry already */
+res_T
+read_compute_surface
+ (struct stardis* stardis)
+{
+ res_T res = RES_OK;
+ struct sstl* sstl = NULL;
+ struct add_geom_ctx add_geom_ctx;
+ struct sg3d_geometry_add_callbacks callbacks = SG3D_ADD_CALLBACKS_NULL__;
+ const char* file;
+
+ ASSERT(stardis);
+
+ file = str_cget(&stardis->solve_name);
+ callbacks.get_indices = add_geom_ctx_indices;
+ callbacks.get_position = add_geom_ctx_position;
+ callbacks.add_triangle = add_compute_surface_triangle;
+ callbacks.merge_triangle = merge_compute_surface_triangle;
+
+ ERR(sstl_create(stardis->logger, stardis->allocator, 0, &sstl));
+ res = sstl_load(sstl, file);
+ if(res != RES_OK) {
+ logger_print(stardis->logger, LOG_ERROR,
+ "Cannot read STL file: '%s'\n", file);
+ goto error;
+ }
+ ERR(sstl_get_desc(sstl, &add_geom_ctx.stl_desc));
+ ASSERT(add_geom_ctx.stl_desc.vertices_count <= UINT_MAX
+ && add_geom_ctx.stl_desc.triangles_count <= UINT_MAX);
+
+ add_geom_ctx.custom = &stardis->compute_surface;
+
+ res = sg3d_geometry_add(
+ stardis->geometry.sg3d,
+ (unsigned)add_geom_ctx.stl_desc.vertices_count,
+ (unsigned)add_geom_ctx.stl_desc.triangles_count,
+ &callbacks,
+ &add_geom_ctx);
+ if(res != RES_OK) {
+ logger_print(stardis->logger, LOG_ERROR,
+ "Cannot add file content: '%s'\n", file);
+ goto error;
+ }
- CHK(sdis_green_function_ref_put(green) == RES_OK);
- } else {
- if (mode & IR_COMPUTE) {
- size_t width = (size_t)stardis->camera.img[0];
- size_t height = (size_t)stardis->camera.img[1];
-
- /* Setup the camera */
- SDIS(camera_create(dev, &cam));
- SDIS(camera_set_proj_ratio(cam, (double)width / (double)height));
- SDIS(camera_set_fov(cam, MDEG2RAD(stardis->camera.fov)));
- SDIS(camera_look_at(cam,
- stardis->camera.pos,
- stardis->camera.tgt,
- stardis->camera.up));
-
- /* Launch the simulation */
- time[0] = time[1] = stardis->camera.u.time;
- res = sdis_solve_camera(scn,
- cam,
- time,
- stardis->scale_factor,
- stardis->radiative_temp[0],
- stardis->radiative_temp[1],
- width,
- height,
- (size_t)stardis->camera.spp,
- stardis->dump_paths,
- &buf);
- if (res != RES_OK) goto error;
-
- /* Write the image */
- dump_image(buf);
- }
- else if (mode & PROBE_COMPUTE || mode & PROBE_COMPUTE_ON_INTERFACE) {
- double uv[2] = { 0,0 };
- size_t iprim = SIZE_MAX;
- /* Launch the probe simulation */
- pos[0] = stardis->probe[0];
- pos[1] = stardis->probe[1];
- pos[2] = stardis->probe[2];
- time[0] = time[1] = stardis->probe[3];
-
- res = select_probe_type(scn,
- stardis->geometry.triangle,
- stardis->geometry.vertex,
- stardis->descriptions,
- (mode & PROBE_COMPUTE_ON_INTERFACE),
- pos,
- &iprim,
- uv);
- if (res != RES_OK) goto error;
-
- if (iprim == SIZE_MAX) {
- res = sdis_solve_probe(scn,
- stardis->N,
- pos,
- time,
- stardis->scale_factor,
- stardis->radiative_temp[0],
- stardis->radiative_temp[1],
- stardis->dump_paths,
- &estimator);
- } else {
- res = sdis_solve_probe_boundary(scn,
- stardis->N,
- iprim,
- uv,
- time,
- SDIS_FRONT,
- stardis->scale_factor,
- stardis->radiative_temp[0],
- stardis->radiative_temp[1],
- stardis->dump_paths,
- &estimator);
- }
- }
- else if (mode & MEDIUM_COMPUTE) {
- size_t sz, ii;
- struct sdis_medium* medium = NULL;
- /* Find medium */
- sz = sa_size(stardis->descriptions);
- FOR_EACH(ii, 0, sz) {
- struct description* desc = stardis->descriptions + ii;
- if (desc->type == DESC_MAT_SOLID) {
- if (0 == strcmp(stardis->solve_name, desc->d.solid.name)) {
- ASSERT(sa_size(media) > ii);
- medium = media[ii];
- break;
- }
- }
- else if (desc->type == DESC_MAT_FLUID) {
- if (0 == strcmp(stardis->solve_name, desc->d.fluid.name)) {
- ASSERT(sa_size(media) > ii);
- medium = media[ii];
- break;
- }
- }
- }
- if (medium == NULL) {
- /* Not found */
- fprintf(stderr, "Cannot solve medium %s (unknown medium)\n",
- stardis->solve_name);
- res = RES_BAD_ARG;
- goto error;
- }
- time[0] = time[1] = stardis->probe[3];
- res = sdis_solve_medium(scn,
- stardis->N,
- medium,
- time,
- stardis->scale_factor,
- stardis->radiative_temp[0],
- stardis->radiative_temp[1],
- stardis->dump_paths,
- &estimator);
- }
- else if (mode & BOUNDARY_COMPUTE) {
- ASSERT(sa_size(stardis->boundary.primitives)
- == sa_size(stardis->boundary.sides));
- if (sa_size(stardis->boundary.sides) == 0) {
- fprintf(stderr, "Cannot solve boundary %s (empty geometry)\n",
- stardis->solve_name);
- }
+end:
+ if(sstl) SSTL(ref_put(sstl));
+ return res;
+error:
+ goto end;
+}
- time[0] = time[1] = stardis->probe[3];
- res = sdis_solve_boundary(scn,
- stardis->N,
- stardis->boundary.primitives,
- stardis->boundary.sides,
- sa_size(stardis->boundary.sides),
- time,
- stardis->scale_factor,
- stardis->radiative_temp[0],
- stardis->radiative_temp[1],
- stardis->dump_paths,
- &estimator);
- } else {
- CHK(0);
- }
- if (res != RES_OK) goto error;
- if (mode & PROBE_COMPUTE
- || mode & PROBE_COMPUTE_ON_INTERFACE
- || mode & MEDIUM_COMPUTE
- || mode & BOUNDARY_COMPUTE) {
- /* Fetch the estimation data */
- SDIS(estimator_get_temperature(estimator, &temperature));
- SDIS(estimator_get_failure_count(estimator, &nfailures));
-
- /* Print the results */
- switch (mode & COMPUTE_MODES) {
- case PROBE_COMPUTE:
- case PROBE_COMPUTE_ON_INTERFACE:
- printf("Temperature at t=[%g, %g, %g, %g] = %g +/- %g\n",
- pos[0], pos[1], pos[2], time[0],
- temperature.E, /* Expected value */
- temperature.SE); /* Standard error */
- break;
- case MEDIUM_COMPUTE:
- printf("Temperature in medium %s at t=%g = %g +/- %g\n",
- stardis->solve_name, time[0],
- temperature.E, /* Expected value */
- temperature.SE); /* Standard error */
- break;
- case BOUNDARY_COMPUTE:
- printf("Temperature at boundary %s at t=%g = %g +/- %g\n",
- stardis->solve_name, time[0],
- temperature.E, /* Expected value */
- temperature.SE); /* Standard error */
- break;
- default: FATAL("Invalid mode.");
- }
- printf("#failures: %lu/%lu\n",
- (unsigned long)nfailures,
- (unsigned long)stardis->N);
+res_T
+stardis_compute
+ (struct stardis* stardis)
+{
+ res_T res = RES_OK;
- /* Dump paths according to user settings */
- sdis_estimator_for_each_path(estimator, dump_path, stdout);
- }
- }
+ ASSERT(stardis && (stardis->mode & COMPUTE_MODES));
+
+ /* Compute */
+ if(stardis->mode & MODE_PROBE_COMPUTE)
+ ERR(compute_probe(stardis));
+ else if(stardis->mode & MODE_PROBE_COMPUTE_ON_INTERFACE)
+ ERR(compute_probe_on_interface(stardis));
+ else if(stardis->mode & MODE_IR_COMPUTE)
+ ERR(compute_camera(stardis));
+ else if(stardis->mode & MODE_MEDIUM_COMPUTE)
+ ERR(compute_medium(stardis));
+ else if(stardis->mode & MODE_BOUNDARY_COMPUTE)
+ ERR(compute_boundary(stardis));
+ else if(stardis->mode & MODE_FLUX_BOUNDARY_COMPUTE)
+ ERR(compute_flux_boundary(stardis));
+ else if(stardis->mode & MODE_MAP_COMPUTE)
+ ERR(compute_map(stardis));
+ else FATAL("Unknown mode.\n");
end:
- if (data) SDIS(data_ref_put(data));
- if (interfaces) {
- for (i = 0; i < sa_size(interfaces); ++i)
- SDIS(interface_ref_put(interfaces[i]));
- sa_release(interfaces);
- stardis->geometry.interfaces = NULL;
- }
- sa_release(interf_bytrg);
- stardis->geometry.interf_bytrg = NULL;
- if (htable_interfaces_initialised) htable_intface_release(&htable_interfaces);
- for (i = 0; i < sa_size(media); ++i)
- SDIS(medium_ref_put(media[i]));
- sa_release(media);
-
- if (cam) SDIS(camera_ref_put(cam));
- if (buf) SDIS(estimator_buffer_ref_put(buf));
- if (estimator) SDIS(estimator_ref_put(estimator));
- if (scn) SDIS(scene_ref_put(scn));
- if (dev) SDIS(device_ref_put(dev));
-
return res;
error:
+ logger_print(stardis->logger, LOG_ERROR,
+ "%s: computation failed!\n", FUNC_NAME);
goto end;
}
diff --git a/src/stardis-compute.h b/src/stardis-compute.h
@@ -0,0 +1,43 @@
+/* Copyright (C) 2018-2020 |Meso|Star> (contact@meso-star.com)
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+#ifndef SDIS_COMPUTE_H
+#define SDIS_COMPUTE_H
+
+#include <rsys/rsys.h>
+#include <rsys/dynamic_array.h>
+
+struct stardis;
+struct str;
+
+#define DARRAY_NAME estimators
+#define DARRAY_DATA struct sdis_estimator*
+#include <rsys/dynamic_array.h>
+
+struct sdis_medium*
+find_medium_by_name
+ (struct stardis* stardis,
+ const struct str* name,
+ unsigned* id); /* Can be NULL */
+
+extern LOCAL_SYM res_T
+stardis_compute
+ (struct stardis* stardis);
+
+extern LOCAL_SYM res_T
+read_compute_surface
+ (struct stardis* stardis);
+
+#endif
+\ No newline at end of file
diff --git a/src/stardis-default.h.in b/src/stardis-default.h.in
@@ -0,0 +1,37 @@
+/* Copyright (C) 2018-2020 |Meso|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/>. */
+
+#ifndef STARDIS_DEFAULT_H
+#define STARDIS_DEFAULT_H
+#define STARDIS_RENDERING_FMT(Fmt) STARDIS_RENDERING_OUTPUT_FILE_FMT_ ## Fmt
+
+#define STARDIS_DEFAULT_AMBIENT_TEMP @STARDIS_ARGS_DEFAULT_AMBIENT_TEMP@
+#define STARDIS_DEFAULT_COMPUTE_TIME @STARDIS_ARGS_DEFAULT_COMPUTE_TIME@
+#define STARDIS_DEFAULT_RENDERING_FOV @STARDIS_ARGS_DEFAULT_RENDERING_FOV@
+#define STARDIS_DEFAULT_RENDERING_IMG_HEIGHT @STARDIS_ARGS_DEFAULT_RENDERING_IMG_HEIGHT@
+#define STARDIS_DEFAULT_RENDERING_IMG_WIDTH @STARDIS_ARGS_DEFAULT_RENDERING_IMG_WIDTH@
+#define STARDIS_DEFAULT_RENDERING_OUTPUT_FILE_FMT STARDIS_RENDERING_FMT( @STARDIS_ARGS_DEFAULT_RENDERING_OUTPUT_FILE_FMT@ )
+#define STARDIS_DEFAULT_RENDERING_POS @STARDIS_ARGS_DEFAULT_RENDERING_POS@
+#define STARDIS_DEFAULT_RENDERING_SPP @STARDIS_ARGS_DEFAULT_RENDERING_SPP@
+#define STARDIS_DEFAULT_RENDERING_TGT @STARDIS_ARGS_DEFAULT_RENDERING_TGT@
+#define STARDIS_DEFAULT_RENDERING_TIME @STARDIS_ARGS_DEFAULT_RENDERING_TIME@
+#define STARDIS_DEFAULT_RENDERING_UP @STARDIS_ARGS_DEFAULT_RENDERING_UP@
+#define STARDIS_DEFAULT_REFERENCE_TEMP @STARDIS_ARGS_DEFAULT_REFERENCE_TEMP@
+#define STARDIS_DEFAULT_SAMPLES_COUNT @STARDIS_ARGS_DEFAULT_SAMPLES_COUNT@
+#define STARDIS_DEFAULT_SCALE_FACTOR @STARDIS_ARGS_DEFAULT_SCALE_FACTOR@
+#define STARDIS_DEFAULT_VERBOSE_LEVEL @STARDIS_ARGS_DEFAULT_VERBOSE_LEVEL@
+
+#endif /* STARDIS_DEFAULT_H */
+
diff --git a/src/stardis-fluid.c b/src/stardis-fluid.c
@@ -0,0 +1,164 @@
+/* Copyright (C) 2018-2020 |Meso|Star> (contact@meso-star.com)
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+#include "stardis-fluid.h"
+#include "stardis-compute.h"
+#include "stardis-app.h"
+
+#include <sdis.h>
+
+#include <limits.h>
+
+/*******************************************************************************
+ * Local Functions
+ ******************************************************************************/
+
+static double
+fluid_get_calorific_capacity
+ (const struct sdis_rwalk_vertex* vtx,
+ struct sdis_data* data)
+{
+ const struct fluid* fluid_props = sdis_data_cget(data);
+ (void)vtx;
+ return fluid_props->cp;
+}
+
+static double
+fluid_get_volumic_mass
+ (const struct sdis_rwalk_vertex* vtx,
+ struct sdis_data* data)
+{
+ const struct fluid* fluid_props = sdis_data_cget(data);
+ (void)vtx;
+ return fluid_props->rho;
+}
+
+static double
+fluid_get_temperature
+ (const struct sdis_rwalk_vertex* vtx,
+ struct sdis_data* data)
+{
+ const struct fluid* fluid_props = sdis_data_cget(data);
+ if(fluid_props->imposed_temperature >= 0)
+ /* If there is an imposed temp, it is imposed regardless of time */
+ return fluid_props->imposed_temperature;
+ if(vtx->time <= fluid_props->t0) {
+ /* If time is <= t0: use tinit */
+ if(fluid_props->tinit < 0) {
+ if(str_is_empty(&fluid_props->name)) {
+ FATAL("fluid_get_temperature: getting undefined Tinit\n");
+ } else {
+ VFATAL("fluid_get_temperature: getting undefined Tinit (fluid '%s')\n",
+ ARG1(str_cget(&fluid_props->name)));
+ }
+ }
+ return fluid_props->tinit;
+ }
+ return -1; /* Unknown temperature */
+}
+
+/*******************************************************************************
+ * Public Functions
+ ******************************************************************************/
+
+res_T
+create_solver_fluid
+ (struct stardis* stardis,
+ const struct fluid* fluid_props)
+{
+ res_T res = RES_OK;
+ struct sdis_fluid_shader fluid_shader = SDIS_FLUID_SHADER_NULL;
+ struct sdis_data* data = NULL;
+ struct fluid* props;
+
+ ASSERT(stardis && fluid_props);
+ fluid_shader.calorific_capacity = fluid_get_calorific_capacity;
+ fluid_shader.volumic_mass = fluid_get_volumic_mass;
+ fluid_shader.temperature = fluid_get_temperature;
+ ERR(sdis_data_create(stardis->dev, sizeof(struct fluid), ALIGNOF(struct fluid),
+ NULL, &data));
+
+ props = sdis_data_get(data); /* Fetch the allocated memory space */
+ init_fluid(stardis->allocator, props);
+ cp_fluid(props, fluid_props);
+ if(fluid_props->fluid_id >= darray_media_ptr_size_get(&stardis->media)) {
+ ERR(darray_media_ptr_resize(&stardis->media, fluid_props->fluid_id + 1));
+ }
+ ASSERT(darray_media_ptr_data_get(&stardis->media)[fluid_props->fluid_id] == NULL);
+ ERR(sdis_fluid_create(stardis->dev, &fluid_shader, data,
+ darray_media_ptr_data_get(&stardis->media) + fluid_props->fluid_id));
+
+end:
+ if(data) SDIS(data_ref_put(data));
+ return res;
+error:
+ goto end;
+}
+
+void
+init_fluid(struct mem_allocator* allocator, struct fluid* dst)
+{
+ str_init(allocator, &dst->name);
+ dst->rho = 1;
+ dst->cp = 1;
+ dst->tinit = -1;
+ dst->imposed_temperature = -1;
+ dst->t0 = 0;
+ dst->is_outside = 0;
+ dst->is_green = 0;
+ dst->desc_id = UINT_MAX;
+ dst->fluid_id = UINT_MAX;
+}
+
+void
+release_fluid(struct fluid* fluid)
+{
+ str_release(&fluid->name);
+}
+
+res_T
+str_print_fluid(struct str* str, const struct fluid* f)
+{
+ res_T res = RES_OK;
+ ASSERT(str && f);
+ STR_APPEND_PRINTF(str, "Fluid '%s': rho=%g cp=%g",
+ ARG3( str_cget(&f->name), f->rho, f->cp ) );
+ if(f->tinit >= 0) {
+ STR_APPEND_PRINTF(str, " Tinit=%g", ARG1( f->tinit ) );
+ }
+ if(f->imposed_temperature >= 0) {
+ STR_APPEND_PRINTF(str, " Temp=%g", ARG1( f->imposed_temperature ) );
+ }
+ STR_APPEND_PRINTF(str, " (it is medium %u)", ARG1( f->fluid_id ) );
+end:
+ return res;
+error:
+ goto end;
+}
+
+res_T
+cp_fluid(struct fluid* dst, const struct fluid* src)
+{
+ dst->rho = src->rho;
+ dst->cp = src->cp;
+ dst->tinit = src->tinit;
+ dst->imposed_temperature = src->imposed_temperature;
+ dst->t0 = src->t0;
+ dst->is_outside = src->is_outside;
+ dst->is_green = src->is_green;
+ dst->desc_id = src->desc_id;
+ dst->fluid_id = src->fluid_id;
+ return str_copy(&dst->name, &src->name);
+}
diff --git a/src/stardis-fluid.h b/src/stardis-fluid.h
@@ -0,0 +1,59 @@
+/* Copyright (C) 2018-2020 |Meso|Star> (contact@meso-star.com)
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+#ifndef SDIS_FLUID_H
+#define SDIS_FLUID_H
+
+#include <sdis.h>
+
+#include <rsys/rsys.h>
+#include <rsys/str.h>
+
+struct stardis;
+
+/*******************************************************************************
+ * Fluid data
+ ******************************************************************************/
+struct fluid {
+ struct str name;
+ double rho; /* Volumic mass */
+ double cp; /* Calorific capacity */
+ double tinit;
+ double imposed_temperature;
+ double t0; /* End time of tinit */
+ int is_outside; /* the fluid is used for a boundary */
+ int is_green; /* green computation (nothing to do with fluid itself) */
+ unsigned desc_id; /* id of the boundary; meaningful if is_outside */
+ unsigned fluid_id;
+};
+
+res_T
+create_solver_fluid
+ (struct stardis* stardis,
+ const struct fluid* fluid_props);
+
+LOCAL_SYM void
+init_fluid(struct mem_allocator* allocator, struct fluid* dst);
+
+LOCAL_SYM void
+release_fluid(struct fluid* fluid);
+
+LOCAL_SYM res_T
+str_print_fluid(struct str* str, const struct fluid* s);
+
+LOCAL_SYM res_T
+cp_fluid(struct fluid* dst, const struct fluid* src);
+
+#endif
diff --git a/src/stardis-intface.c b/src/stardis-intface.c
@@ -0,0 +1,364 @@
+/* Copyright (C) 2018-2020 |Meso|Star> (contact@meso-star.com)
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+#include "stardis-intface.h"
+#include "stardis-app.h"
+#include "stardis-compute.h"
+#include "stardis-output.h"
+#include "stardis-solid.h"
+
+#include <sdis.h>
+
+/*******************************************************************************
+ * Local Functions
+ ******************************************************************************/
+
+static double
+interface_get_convection_coef
+ (const struct sdis_interface_fragment* frag,
+ struct sdis_data* data)
+{
+ const struct intface* interface_props = sdis_data_cget(data);
+ (void)frag;
+ return interface_props->hc;
+}
+
+static double
+interface_get_temperature
+ (const struct sdis_interface_fragment* frag,
+ struct sdis_data* data)
+{
+ const struct intface* interface_props = sdis_data_cget(data);
+ (void)frag;
+ return interface_props->imposed_temperature;
+}
+
+static double
+interface_get_flux
+ (const struct sdis_interface_fragment* frag,
+ struct sdis_data* data)
+{
+ const struct intface* interface_props = sdis_data_cget(data);
+ (void)frag;
+ return interface_props->imposed_flux;
+}
+
+static double
+interface_get_emissivity
+ (const struct sdis_interface_fragment* frag,
+ struct sdis_data* data)
+{
+ const struct intface* interface_props = sdis_data_cget(data);
+ (void)frag;
+ return interface_props->emissivity;
+}
+
+static double
+interface_get_alpha
+ (const struct sdis_interface_fragment* frag,
+ struct sdis_data* data)
+{
+ const struct intface* interface_props = sdis_data_cget(data);
+ (void)frag;
+ return interface_props->alpha;
+}
+
+/*******************************************************************************
+ * Public Functions
+ ******************************************************************************/
+
+res_T
+create_intface
+ (struct stardis* stardis,
+ unsigned itri,
+ struct htable_intface* htable_interfaces)
+{
+ struct int_descs int_descs = INT_DESCS_NULL;
+ struct sdis_interface** p_intface;
+ struct sdis_interface* intface;
+ struct sdis_medium* front_med = NULL;
+ struct sdis_medium* back_med = NULL;
+ struct sdis_interface_side_shader* fluid_side_shader = NULL;
+ struct sdis_data* data = NULL;
+ unsigned fd, bd, cd, descr[SG3D_PROP_TYPES_COUNT__];
+ int fluid_count = 0, solid_count = 0;
+ int solid_fluid_connection_count = 0, connection_count = 0, boundary_count = 0;
+ const struct description* descriptions;
+ struct sdis_medium** media;
+ res_T res = RES_OK;
+
+ ASSERT(stardis && htable_interfaces);
+
+ /* Get the description IDs for this triangle */
+ ERR(sg3d_geometry_get_unique_triangle_properties(stardis->geometry.sg3d,
+ itri, descr));
+
+ descriptions = darray_descriptions_cdata_get(&stardis->descriptions);
+ media = darray_media_ptr_data_get(&stardis->media);
+
+ /* Create key */
+ int_descs.front = fd = descr[SG3D_FRONT];
+ int_descs.back = bd = descr[SG3D_BACK];
+ int_descs.connect = cd = descr[SG3D_INTFACE];
+
+ /* Search if interface already exists, or create it */
+ p_intface = htable_intface_find(htable_interfaces, &int_descs);
+ if(p_intface) {
+ intface = *p_intface;
+ } else {
+ /* create new interface and register */
+ struct sdis_interface_shader interface_shader = SDIS_INTERFACE_SHADER_NULL;
+ struct intface* interface_props = NULL;
+ unsigned id;
+ int front_defined = (fd != SG3D_UNSPECIFIED_PROPERTY);
+ int back_defined = (bd != SG3D_UNSPECIFIED_PROPERTY);
+ int connect_defined = (cd != SG3D_UNSPECIFIED_PROPERTY);
+
+ ERR(sdis_data_create(stardis->dev, sizeof(struct intface),
+ ALIGNOF(struct intface), NULL, &data));
+ interface_props = sdis_data_get(data);
+ interface_props->imposed_temperature = -1;
+ interface_props->imposed_flux = SDIS_FLUX_NONE;
+ interface_props->front_medium_id = UINT_MAX;
+ interface_props->back_medium_id = UINT_MAX;
+ interface_props->desc_id = UINT_MAX;
+
+ if(front_defined) {
+ switch (descriptions[fd].type) {
+ case DESC_MAT_SOLID:
+ id = descriptions[fd].d.solid.solid_id;
+ solid_count++;
+ interface_props->front_medium_id = id;
+ front_med = media[id];
+ break;
+ case DESC_MAT_FLUID:
+ fluid_count++;
+ id = descriptions[fd].d.fluid.fluid_id;
+ interface_props->front_medium_id = id;
+ front_med = media[id];
+ fluid_side_shader = &interface_shader.front;
+ break;
+ default:
+ FATAL("error:" STR(__FILE__) ":" STR(__LINE__)": Invalid type.\n");
+ }
+ }
+ if(back_defined) {
+ switch (descriptions[bd].type) {
+ case DESC_MAT_SOLID:
+ id = descriptions[bd].d.solid.solid_id;
+ solid_count++;
+ interface_props->back_medium_id = id;
+ back_med = media[id];
+ break;
+ case DESC_MAT_FLUID:
+ fluid_count++;
+ id = descriptions[bd].d.fluid.fluid_id;
+ interface_props->back_medium_id = id;
+ back_med = media[id];
+ /* Can overwrite fluid_side_shader. However it would imply two
+ * fluids and this case lead to an error */
+ fluid_side_shader = &interface_shader.back;
+ break;
+ default:
+ FATAL("error:" STR(__FILE__) ":" STR(__LINE__)": Invalid type.\n");
+ }
+ }
+ if(fluid_count == 2) {
+ res = RES_BAD_ARG;
+ goto error;
+ }
+ if(connect_defined) {
+ const struct description* connect = descriptions + cd;
+ int type_checked = 0;
+ struct sdis_medium* def_medium = NULL;
+ unsigned ext_id;
+ if(connect->type != DESC_SOLID_FLUID_CONNECT
+ && front_defined == back_defined)
+ {
+ /* 1 and only 1 defined */
+ res = RES_BAD_ARG;
+ goto error;
+ }
+ if(front_defined) {
+ def_medium = front_med;
+ fluid_side_shader = (descriptions[fd].type == DESC_MAT_FLUID)
+ ? &interface_shader.front : &interface_shader.back;
+ } else {
+ ASSERT(back_defined);
+ def_medium = back_med;
+ fluid_side_shader = (descriptions[bd].type == DESC_MAT_FLUID)
+ ? &interface_shader.back : &interface_shader.front;
+ }
+ interface_props->desc_id = cd;
+ switch(connect->type) {
+ case DESC_BOUND_H_FOR_FLUID:
+ if(sdis_medium_get_type(def_medium) != SDIS_FLUID) {
+ res = RES_BAD_ARG;
+ goto error;
+ }
+ type_checked = 1;
+ ASSERT(connect->d.h_boundary.imposed_temperature >= 0);
+ interface_props->imposed_temperature
+ = connect->d.h_boundary.imposed_temperature;
+ ASSERT(fluid_side_shader);
+ fluid_side_shader->temperature = interface_get_temperature;
+ /* fall through */
+ case DESC_BOUND_H_FOR_SOLID:
+ if(!type_checked
+ && sdis_medium_get_type(def_medium) != SDIS_SOLID)
+ {
+ res = RES_BAD_ARG; goto error;
+ }
+ ext_id = connect->d.h_boundary.mat_id; /* External material id */
+ ASSERT(ext_id < darray_media_ptr_size_get(&stardis->media));
+ ASSERT(sdis_medium_get_type(media[ext_id]) ==
+ (connect->type == DESC_BOUND_H_FOR_SOLID ? SDIS_FLUID : SDIS_SOLID));
+ connection_count++;
+ boundary_count++;
+ if(front_defined) back_med = media[ext_id];
+ else front_med = media[ext_id];
+ interface_shader.convection_coef_upper_bound = connect->d.h_boundary.hc;
+ interface_props->hc = connect->d.h_boundary.hc;
+ interface_props->emissivity = connect->d.h_boundary.emissivity;
+ interface_props->alpha = connect->d.h_boundary.specular_fraction;
+ if(connect->d.h_boundary.hc > 0) {
+ interface_shader.convection_coef = interface_get_convection_coef;
+ }
+ if(connect->d.h_boundary.emissivity > 0) {
+ ASSERT(fluid_side_shader);
+ fluid_side_shader->emissivity = interface_get_emissivity;
+ fluid_side_shader->specular_fraction = interface_get_alpha;
+ }
+ break;
+ case DESC_BOUND_T_FOR_FLUID:
+ if(sdis_medium_get_type(def_medium) != SDIS_FLUID) {
+ res = RES_BAD_ARG;
+ goto error;
+ }
+ type_checked = 1;
+ interface_shader.convection_coef_upper_bound = connect->d.t_boundary.hc;
+ interface_props->hc = connect->d.t_boundary.hc;
+ if(connect->d.t_boundary.hc > 0) {
+ ASSERT(connect->type == DESC_BOUND_T_FOR_FLUID);
+ interface_shader.convection_coef = interface_get_convection_coef;
+ }
+ interface_props->emissivity = connect->d.t_boundary.emissivity;
+ interface_props->alpha = connect->d.t_boundary.specular_fraction;
+ if(connect->d.t_boundary.emissivity > 0) {
+ ASSERT(fluid_side_shader);
+ fluid_side_shader->emissivity = interface_get_emissivity;
+ fluid_side_shader->specular_fraction = interface_get_alpha;
+ }
+ /* fall through */
+ case DESC_BOUND_T_FOR_SOLID:
+ if(!type_checked
+ && sdis_medium_get_type(def_medium) != SDIS_SOLID)
+ {
+ res = RES_BAD_ARG;
+ goto error;
+ }
+ ext_id = connect->d.t_boundary.mat_id; /* External material id */
+ ASSERT(ext_id < darray_media_ptr_size_get(&stardis->media));
+ ASSERT(sdis_medium_get_type(media[ext_id])
+ == (connect->type == DESC_BOUND_T_FOR_FLUID ? SDIS_SOLID: SDIS_FLUID));
+ connection_count++;
+ boundary_count++;
+ if(front_defined) {
+ ASSERT(!back_med);
+ back_med = media[ext_id];
+ } else {
+ ASSERT(!front_med);
+ front_med = media[ext_id];
+ }
+ /* The imposed T is for the 2 sides (until there is contact resistnces) */
+ interface_shader.front.temperature = interface_get_temperature;
+ interface_shader.back.temperature = interface_get_temperature;
+ if(connect->type == DESC_BOUND_T_FOR_SOLID) {
+ /* Set emissivity to 1 to allow radiative paths comming from
+ * a possible external fluid to 'see' the imposed T */
+ ASSERT(fluid_side_shader);
+ fluid_side_shader->emissivity = interface_get_emissivity;
+ interface_props->emissivity = 1;
+ }
+ ASSERT(connect->d.t_boundary.imposed_temperature >= 0);
+ interface_props->imposed_temperature
+ = connect->d.t_boundary.imposed_temperature;
+ break;
+ case DESC_BOUND_F_FOR_SOLID:
+ if(sdis_medium_get_type(def_medium) != SDIS_SOLID) {
+ res = RES_BAD_ARG;
+ goto error;
+ }
+ connection_count++;
+ boundary_count++;
+ if(front_defined) {
+ back_med = media[connect->d.f_boundary.mat_id];
+ interface_shader.front.flux = interface_get_flux;
+ } else {
+ front_med = media[connect->d.f_boundary.mat_id];
+ interface_shader.back.flux = interface_get_flux;
+ }
+ ASSERT(connect->d.f_boundary.imposed_flux != SDIS_FLUX_NONE);
+ interface_props->imposed_flux = connect->d.f_boundary.imposed_flux;
+ break;
+ case DESC_SOLID_FLUID_CONNECT:
+ /* Both front and back should be defined */
+ if(solid_count != 1 || fluid_count != 1) {
+ res = RES_BAD_ARG;
+ goto error;
+ }
+ ASSERT(front_defined && back_defined);
+ connection_count++;
+ solid_fluid_connection_count++;
+ interface_shader.convection_coef_upper_bound = connect->d.sf_connect.hc;
+ interface_props->hc = connect->d.sf_connect.hc;
+ interface_props->emissivity = connect->d.sf_connect.emissivity;
+ interface_props->alpha = connect->d.sf_connect.specular_fraction;
+ if(connect->d.sf_connect.hc > 0) {
+ interface_shader.convection_coef = interface_get_convection_coef;
+ }
+ if(connect->d.sf_connect.emissivity > 0) {
+ ASSERT(fluid_side_shader);
+ fluid_side_shader->emissivity = interface_get_emissivity;
+ fluid_side_shader->specular_fraction = interface_get_alpha;
+ }
+ break;
+ default:
+ FATAL("error:" STR(__FILE__) ":" STR(__LINE__)": Invalid type.\n");
+ }
+ }
+
+ if((fluid_count + solid_count + connection_count < 2)
+ || (boundary_count && (fluid_count + solid_count != 1)))
+ {
+ res = RES_BAD_ARG;
+ goto error;
+ }
+
+ ERR(sdis_interface_create(stardis->dev, front_med, back_med,
+ &interface_shader, data, &intface));
+ SDIS(data_ref_put(data)); data = NULL;
+ ERR(darray_interface_ptrs_push_back(&stardis->geometry.interfaces, &intface));
+ ERR(htable_intface_set(htable_interfaces, &int_descs, &intface));
+ }
+ ERR(darray_interface_ptrs_push_back(&stardis->geometry.interf_bytrg, &intface));
+
+end:
+ if(data) SDIS(data_ref_put(data));
+ return res;
+error:
+ goto end;
+}
+
diff --git a/src/stardis-intface.h b/src/stardis-intface.h
@@ -0,0 +1,67 @@
+/* Copyright (C) 2018-2020 |Meso|Star> (contact@meso-star.com)
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+#ifndef SDIS_INTFACE_H
+#define SDIS_INTFACE_H
+
+#include <rsys/hash_table.h>
+
+#include <limits.h>
+
+struct stardis;
+struct dummies;
+
+/*******************************************************************************
+ * Interface data
+ ******************************************************************************/
+struct intface {
+ double hc;
+ double emissivity;
+ double alpha;
+ /* Imposed compute temperature & flux */
+ double imposed_temperature;
+ double imposed_flux;
+ /* IDs */
+ unsigned front_medium_id, back_medium_id;
+ unsigned desc_id; /* The description this interfaces comes from */
+};
+
+/* Declare the hash table that map an interface to its descriptor */
+struct int_descs {
+ unsigned front, back, connect;
+};
+#define INT_DESCS_NULL__ { UINT_MAX, UINT_MAX, UINT_MAX }
+static const struct int_descs INT_DESCS_NULL = INT_DESCS_NULL__;
+
+static INLINE char
+eq_desc(const struct int_descs* a, const struct int_descs* b)
+{
+ return (char)(a->front == b->front && a->back == b->back
+ && a->connect == b->connect);
+}
+
+#define HTABLE_NAME intface
+#define HTABLE_DATA struct sdis_interface*
+#define HTABLE_KEY struct int_descs
+#define HTABLE_KEY_FUNCTOR_EQ eq_desc
+#include <rsys/hash_table.h>
+
+extern res_T
+create_intface
+ (struct stardis* stardis,
+ unsigned tr_idx,
+ struct htable_intface* htable_interfaces);
+
+#endif
diff --git a/src/stardis-main.c b/src/stardis-main.c
@@ -0,0 +1,125 @@
+/* Copyright (C) 2018-2020 |Meso|Star> (contact@meso-star.com)
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+#include "stardis-app.h"
+#include "stardis-parsing.h"
+#include "stardis-output.h"
+#include "stardis-compute.h"
+
+#include <rsys/rsys.h>
+#include <rsys/mem_allocator.h>
+#include <rsys/logger.h>
+
+#include <stdlib.h>
+#include <stdio.h>
+
+int
+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;
+ int err = EXIT_SUCCESS;
+ struct mem_allocator allocator;
+ struct logger logger;
+ int mode = 0;
+ res_T res = RES_OK;
+
+ ERR(mem_init_proxy_allocator(&allocator, &mem_default_allocator));
+ allocator_initialized = 1;
+
+ ERR(logger_init(&allocator, &logger));
+ logger_initialized = 1;
+ /* Active loggin for args pasing */
+ logger_set_stream(&logger, LOG_ERROR, log_err_fn, NULL);
+ logger_set_stream(&logger, LOG_WARNING, log_warn_fn, NULL);
+ logger_set_stream(&logger, LOG_OUTPUT, log_prt_fn, NULL);
+
+ ERR(init_args(&logger, &allocator, &args));
+ args_initialized = 1;
+ ERR(parse_args(argc, argv, args));
+ mode = args->mode;
+
+ if(mode & MODE_DUMP_HELP) {
+ short_help(stdout, argv[0]);
+ goto exit;
+ }
+ else if(mode & MODE_DUMP_VERSION) {
+ print_version(stdout);
+ goto exit;
+ }
+
+ /* Deactivate some loggin according to the -V arg */
+ if(args->verbose < 1)
+ logger_set_stream(&logger, LOG_ERROR, NULL, NULL);
+ if(args->verbose < 2)
+ logger_set_stream(&logger, LOG_WARNING, NULL, NULL);
+ if(args->verbose < 3)
+ logger_set_stream(&logger, LOG_OUTPUT, NULL, NULL);
+
+ ERR(stardis_init(args, &logger, &allocator, &stardis));
+ stardis_initialized = 1;
+ release_args(args);
+ args_initialized = 0;
+
+ if(mode & MODE_DUMP_VTK) {
+ /* Dump all the app-independent information */
+ ERR(sg3d_geometry_dump_as_vtk(stardis.geometry.sg3d, stdout));
+ /* Dump boundaries
+ * Should we dump connections too? */
+ ERR(dump_boundaries_at_the_end_of_vtk(&stardis, stdout));
+ /* Dump the compute region if any */
+ if(mode & REGION_COMPUTE_MODES) {
+ ERR(dump_compute_region_at_the_end_of_vtk(&stardis, stdout));
+ }
+ ERR(dump_enclosure_related_stuff_at_the_end_of_vtk(&stardis, stdout));
+
+ /* If dump, exit after dump done */
+ goto exit;
+ }
+ else if(mode & MODE_DUMP_C_CHUNKS) {
+ ERR(dump_model_as_c_chunks(&stardis, stdout));
+ /* If dump, exit after dump done */
+ goto exit;
+ }
+
+ ASSERT(mode & COMPUTE_MODES);
+ ERR(stardis_compute(&stardis));
+
+exit:
+ if(args_initialized) release_args(args);
+ if(stardis_initialized) stardis_release(&stardis);
+ if(logger_initialized) logger_release(&logger);
+ if(allocator_initialized) {
+ if(MEM_ALLOCATED_SIZE(&allocator) != 0) {
+ char dump[4096] = { '\0' };
+ MEM_DUMP(&allocator, dump, sizeof(dump));
+ fprintf(stderr, "%s\n", dump);
+ fprintf(stderr, "\nMemory leaks: %lu Bytes\n",
+ (unsigned long)MEM_ALLOCATED_SIZE(&allocator));
+ }
+ mem_shutdown_proxy_allocator(&allocator);
+ }
+ return err;
+error:
+ if(mode & COMPUTE_MODES)
+ logger_print(&logger, LOG_ERROR,
+ "No computation possible.\n");
+ err = EXIT_FAILURE;
+ goto exit;
+}
diff --git a/src/stardis-output.c b/src/stardis-output.c
@@ -0,0 +1,1727 @@
+/* Copyright (C) 2018-2020 |Meso|Star> (contact@meso-star.com)
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+#define _POSIX_C_SOURCE 200112L /* snprintf */
+#include "stardis-output.h"
+#include "stardis-compute.h"
+#include "stardis-fluid.h"
+#include "stardis-solid.h"
+#include "stardis-intface.h"
+#include "stardis-app.h"
+
+#include <sdis.h>
+
+#include<star/senc3d.h>
+#include<star/sg3d.h>
+
+#include <rsys/math.h>
+#include <rsys/mem_allocator.h>
+#include <rsys/dynamic_array_uint.h>
+#include <rsys/hash_table.h>
+#include <rsys/logger.h>
+#include <rsys/str.h>
+
+#include <limits.h>
+#include <string.h>
+#include <stdio.h>
+
+#define HTABLE_NAME weigth
+#define HTABLE_DATA double
+#define HTABLE_KEY unsigned
+#include <rsys/hash_table.h>
+
+struct w_ctx {
+ struct mem_allocator* alloc;
+ const struct darray_descriptions* desc;
+ struct htable_weigth pw;
+ struct htable_weigth flux;
+ FILE* stream;
+};
+
+struct e_ctx {
+ const struct darray_descriptions* desc;
+ FILE* stream;
+};
+
+/*******************************************************************************
+ * Local Type; for documentation purpose
+ * These values are used in dumps
+ ******************************************************************************/
+enum enclosure_errors_t {
+ NO_ENCLOSURE_ERROR = BIT(0),
+ ENCLOSURE_WITH_N_MEDIA = BIT(1),
+ ENCLOSURE_WITH_UNDEF_MEDIUM = BIT(2)
+};
+
+/*******************************************************************************
+ * Local Functions
+ ******************************************************************************/
+
+static res_T
+merge_flux_terms
+ (struct sdis_interface* interf,
+ const enum sdis_side side,
+ const double flux_term,
+ void* ctx)
+{
+ res_T res = RES_OK;
+ struct sdis_data* data = NULL;
+ struct intface* d__;
+ unsigned desc_id;
+ struct w_ctx* w_ctx = ctx;
+ const struct description* descs;
+
+ ASSERT(interf && w_ctx);
+ (void)side;
+
+ data = sdis_interface_get_data(interf);
+ d__ = sdis_data_get(data);
+ desc_id = d__->desc_id;
+ descs = darray_descriptions_cdata_get(w_ctx->desc);
+
+ switch (descs[desc_id].type) {
+ case DESC_BOUND_T_FOR_SOLID:
+ case DESC_BOUND_T_FOR_FLUID:
+ case DESC_BOUND_H_FOR_SOLID:
+ case DESC_BOUND_H_FOR_FLUID:
+ FATAL("Cannot have a flux term here.\n"); break;
+ case DESC_BOUND_F_FOR_SOLID: {
+ double* w;
+ w = htable_weigth_find(&w_ctx->flux, &desc_id);
+ if(w) *w += flux_term;
+ else ERR(htable_weigth_set(&w_ctx->flux, &desc_id, &flux_term));
+ break;
+ }
+ default: FATAL("Unreachable code.\n"); break;
+ }
+end:
+ return res;
+error:
+ goto end;
+}
+
+static res_T
+merge_power_terms
+ (struct sdis_medium* mdm,
+ const double power_term,
+ void* ctx)
+{
+ res_T res = RES_OK;
+ struct sdis_data* data = NULL;
+ enum sdis_medium_type type;
+ struct w_ctx* w_ctx = ctx;
+
+ ASSERT(mdm && w_ctx);
+
+ data = sdis_medium_get_data(mdm);
+ type = sdis_medium_get_type(mdm);
+
+ switch (type) {
+ case SDIS_FLUID: {
+ /* Could be OK, but unimplemented in stardis */
+ FATAL("Unexpected power term in fluid");
+ }
+ case SDIS_SOLID: {
+ struct solid* d__ = sdis_data_get(data);
+ double* w;
+ unsigned id = d__->desc_id;
+ w = htable_weigth_find(&w_ctx->pw, &id);
+ if(w) *w += power_term;
+ else ERR(htable_weigth_set(&w_ctx->pw, &id, &power_term));
+ break;
+ }
+ default: FATAL("Unreachable code.\n"); break;
+ }
+end:
+ return res;
+error:
+ goto end;
+}
+
+/*******************************************************************************
+ * Public Functions
+ ******************************************************************************/
+
+res_T
+dump_path
+ (const struct sdis_heat_path* path,
+ void* context)
+{
+ res_T res = RES_OK;
+ struct dump_path_context* dump_ctx = context;
+ FILE* stream = NULL;
+ char* name = NULL;
+ enum sdis_heat_path_flag status = SDIS_HEAT_PATH_NONE;
+ size_t vcount_, name_sz;
+ unsigned long i, vcount;
+
+ ASSERT(path && dump_ctx
+ && dump_ctx->stardis
+ && !str_is_empty(&dump_ctx->stardis->paths_filename));
+
+ ERR(sdis_heat_path_get_status(path, &status));
+
+ name_sz = 20 + str_len(&dump_ctx->stardis->paths_filename);
+ name = MEM_CALLOC(dump_ctx->stardis->allocator, name_sz, sizeof(*name));
+ if(!name) {
+ res = RES_MEM_ERR;
+ goto error;
+ }
+ snprintf(name, name_sz, "%s%08lu%s.vtk",
+ str_cget(&dump_ctx->stardis->paths_filename), dump_ctx->rank++,
+ (status == SDIS_HEAT_PATH_FAILURE ? "_err" : ""));
+
+ stream = fopen(name, "w");
+ if(!stream) {
+ res = RES_IO_ERR;
+ goto error;
+ }
+ /* Header */
+ fprintf(stream, "# vtk DataFile Version 2.0\n");
+ fprintf(stream, "Heat path\n");
+ fprintf(stream, "ASCII\n");
+ fprintf(stream, "DATASET POLYDATA\n");
+ /* Write path positions */
+ sdis_heat_path_get_vertices_count(path, &vcount_);
+ ASSERT(vcount_ < ULONG_MAX);
+ vcount = (unsigned long)vcount_;
+ fprintf(stream, "POINTS %lu double\n", vcount);
+ FOR_EACH(i, 0, vcount) {
+ struct sdis_heat_vertex vtx;
+ ERR(sdis_heat_path_get_vertex(path, i, &vtx));
+ fprintf(stream, "%g %g %g\n", SPLIT3(vtx.P));
+ }
+ /* Write the segment of the path */
+ fprintf(stream, "LINES %d %lu\n", 1, 1 + vcount);
+ fprintf(stream, "%lu", vcount);
+ FOR_EACH(i, 0, vcount) fprintf(stream, " %lu", i);
+ fprintf(stream, "\n");
+
+ /* Write path type */
+ fprintf(stream, "CELL_DATA %d\n", 1);
+ fprintf(stream, "SCALARS Path_Type unsigned_char 1\n");
+ fprintf(stream, "LOOKUP_TABLE default\n");
+ switch (status) {
+ case SDIS_HEAT_PATH_SUCCESS: fprintf(stream, "0\n"); break;
+ case SDIS_HEAT_PATH_FAILURE: fprintf(stream, "1\n"); break;
+ default: FATAL("Unreachable code.\n"); break;
+ }
+
+ fprintf(stream, "POINT_DATA %lu\n", vcount);
+ /* Write the type of the random walk vertices */
+ fprintf(stream, "SCALARS Vertex_Type unsigned_char 1\n");
+ fprintf(stream, "LOOKUP_TABLE default\n");
+ FOR_EACH(i, 0, vcount) {
+ struct sdis_heat_vertex vtx;
+ ERR(sdis_heat_path_get_vertex(path, i, &vtx));
+ ASSERT((size_t)vtx.type <= UCHAR_MAX);
+ fprintf(stream, "%d\n", vtx.type);
+ }
+ /* Write the weights of the random walk vertices */
+ fprintf(stream, "SCALARS Weight double 1\n");
+ fprintf(stream, "LOOKUP_TABLE default\n");
+ FOR_EACH(i, 0, vcount) {
+ struct sdis_heat_vertex vtx;
+ ERR(sdis_heat_path_get_vertex(path, i, &vtx));
+ fprintf(stream, "%g\n", vtx.weight);
+ }
+ /* If computation time is not INF for every vertex,
+ * write the time of the random walk vertices */
+ FOR_EACH(i, 0, vcount) {
+ struct sdis_heat_vertex vtx;
+ ERR(sdis_heat_path_get_vertex(path, i, &vtx));
+ if(i == 0) {
+ if(IS_INF(vtx.time)) break;
+ fprintf(stream, "SCALARS Time double 1\n");
+ fprintf(stream, "LOOKUP_TABLE default\n");
+ }
+ ASSERT(!IS_INF(vtx.time));
+ fprintf(stream, "%g\n", vtx.time);
+ }
+
+end:
+ MEM_RM(dump_ctx->stardis->allocator, name);
+ if(stream) fclose(stream);
+ return res;
+error:
+ goto end;
+}
+
+res_T
+dump_vtk_image
+ (const struct sdis_estimator_buffer* buf,
+ FILE* stream)
+{
+ res_T res = RES_OK;
+ size_t def[2];
+ unsigned long definition[2];
+ double* temps = NULL;
+ size_t ix, iy;
+
+ ASSERT(buf && stream);
+ ERR(sdis_estimator_buffer_get_definition(buf, def));
+ ASSERT(def[0] != 0 && def[1] != 0 && def[0] * def[1] <= ULONG_MAX);
+ definition[0] = (unsigned long)def[0];
+ definition[1] = (unsigned long)def[1];
+
+ temps = mem_alloc(definition[0] * definition[1] * sizeof(double));
+ if(temps == NULL) {
+ res = RES_MEM_ERR;
+ goto error;
+ }
+
+ /* Compute the per pixel temperature */
+ fprintf(stream, "# vtk DataFile Version 2.0\n");
+ fprintf(stream, "Infrared Image\n");
+ fprintf(stream, "ASCII\n");
+ fprintf(stream, "DATASET STRUCTURED_POINTS\n");
+ fprintf(stream, "DIMENSIONS %lu %lu 1\n", definition[0], definition[1]);
+ fprintf(stream, "ORIGIN 0 0 0\n");
+ fprintf(stream, "SPACING 1 1 1\n");
+ fprintf(stream, "POINT_DATA %lu\n", definition[0] * definition[1]);
+ fprintf(stream, "SCALARS temperature_estimate float 1\n");
+ fprintf(stream, "LOOKUP_TABLE default\n");
+ FOR_EACH(iy, 0, definition[1]) {
+ FOR_EACH(ix, 0, definition[0]) {
+ const struct sdis_estimator* estimator;
+ struct sdis_mc T;
+ ERR(sdis_estimator_buffer_at(buf, ix, iy, &estimator));
+ ERR(sdis_estimator_get_temperature(estimator, &T));
+ fprintf(stream, "%f\n", T.E);
+ }
+ }
+ fprintf(stream, "SCALARS temperature_std_dev float 1\n");
+ fprintf(stream, "LOOKUP_TABLE default\n");
+ FOR_EACH(iy, 0, definition[1]) {
+ FOR_EACH(ix, 0, definition[0]) {
+ const struct sdis_estimator* estimator;
+ struct sdis_mc T;
+ ERR(sdis_estimator_buffer_at(buf, ix, iy, &estimator));
+ ERR(sdis_estimator_get_temperature(estimator, &T));
+ fprintf(stream, "%f\n", T.SE);
+ }
+ }
+ fprintf(stream, "SCALARS computation_time float 1\n");
+ fprintf(stream, "LOOKUP_TABLE default\n");
+ FOR_EACH(iy, 0, definition[1]) {
+ FOR_EACH(ix, 0, definition[0]) {
+ const struct sdis_estimator* estimator;
+ struct sdis_mc time;
+ ERR(sdis_estimator_buffer_at(buf, ix, iy, &estimator));
+ ERR(sdis_estimator_get_realisation_time(estimator, &time));
+ fprintf(stream, "%f\n", time.E);
+ }
+ }
+ fprintf(stream, "SCALARS computation_time_std_dev float 1\n");
+ fprintf(stream, "LOOKUP_TABLE default\n");
+ FOR_EACH(iy, 0, definition[1]) {
+ FOR_EACH(ix, 0, definition[0]) {
+ const struct sdis_estimator* estimator;
+ struct sdis_mc time;
+ ERR(sdis_estimator_buffer_at(buf, ix, iy, &estimator));
+ ERR(sdis_estimator_get_realisation_time(estimator, &time));
+ fprintf(stream, "%f\n", time.SE);
+ }
+ }
+ fprintf(stream, "SCALARS failures_count unsigned_long_long 1\n");
+ fprintf(stream, "LOOKUP_TABLE default\n");
+ FOR_EACH(iy, 0, definition[1]) {
+ FOR_EACH(ix, 0, definition[0]) {
+ const struct sdis_estimator* estimator;
+ size_t nfails;
+ ERR(sdis_estimator_buffer_at(buf, ix, iy, &estimator));
+ ERR(sdis_estimator_get_failure_count(estimator, &nfails));
+ ASSERT(nfails <= ULONG_MAX);
+ fprintf(stream, "%lu\n", (unsigned long)nfails);
+ }
+ }
+ mem_rm(temps);
+
+end:
+ return res;
+error:
+ goto end;
+}
+
+res_T
+dump_ht_image
+ (const struct sdis_estimator_buffer* buf,
+ FILE* stream)
+{
+ res_T res = RES_OK;
+ size_t def[2];
+ unsigned long definition[2];
+ size_t ix, iy;
+
+ ASSERT(buf && stream);
+ ERR(sdis_estimator_buffer_get_definition(buf, def));
+ ASSERT(def[0] <= ULONG_MAX && def[1] <= ULONG_MAX);
+ definition[0] = (unsigned long)def[0];
+ definition[1] = (unsigned long)def[1];
+
+ fprintf(stream, "%lu %lu\n", definition[0], definition[1]);
+ FOR_EACH(iy, 0, definition[1]) {
+ FOR_EACH(ix, 0, definition[0]) {
+ const struct sdis_estimator* estimator;
+ struct sdis_mc T;
+ struct sdis_mc time;
+ ERR(sdis_estimator_buffer_at(buf, ix, iy, &estimator));
+ ERR(sdis_estimator_get_realisation_time(estimator, &time));
+ ERR(sdis_estimator_get_temperature(estimator, &T));
+ fprintf(stream, "%f %f 0 0 0 0 %f %f\n",
+ T.E, T.SE, time.E, time.SE);
+ }
+ };
+
+end:
+ return res;
+error:
+ goto end;
+}
+
+#define FW(Ptr, Count) \
+ if((Count) != fwrite((Ptr), sizeof(*(Ptr)), (Count), stream)) { \
+ res = RES_IO_ERR; \
+ goto error; \
+ }
+
+struct path_header {
+ unsigned id;
+ unsigned pcount, fcount;
+ char at_initial;
+};
+
+static FINLINE double
+medium_get_t0
+ (struct sdis_medium* medium)
+{
+ struct sdis_data* data = NULL;
+ enum sdis_medium_type type;
+ ASSERT(medium);
+ type = sdis_medium_get_type(medium);
+ data = sdis_medium_get_data(medium);
+ if(type == SDIS_FLUID) {
+ const struct fluid* fluid_props = sdis_data_cget(data);
+ return fluid_props->t0;
+ } else {
+ const struct solid* solid_props = sdis_data_cget(data);
+ ASSERT(type == SDIS_SOLID);
+ return solid_props->t0;
+ }
+}
+
+static res_T
+dump_sample_end
+ (struct sdis_green_path* path,
+ void* ctx)
+{
+ res_T res = RES_OK;
+ struct sdis_point pt = SDIS_POINT_NULL;
+ struct sdis_data* data = NULL;
+ enum sdis_medium_type type;
+ struct e_ctx* e_ctx = ctx;
+ const struct description* descs;
+ FILE* stream;
+ double elapsed;
+ double* pos;
+ unsigned id;
+
+ CHK(path && ctx);
+
+ stream = e_ctx->stream;
+ ERR(sdis_green_path_get_limit_point(path, &pt));
+ ERR(sdis_green_path_get_elapsed_time(path, &elapsed));
+
+ descs = darray_descriptions_cdata_get(e_ctx->desc);
+ switch (pt.type) {
+ case SDIS_FRAGMENT: {
+ struct intface* d__;
+ data = sdis_interface_get_data(pt.data.itfrag.intface);
+ pos = pt.data.itfrag.fragment.P;
+ d__ = sdis_data_get(data);
+ id = d__->desc_id;
+ CHK(DESC_IS_T(descs[id].type) || DESC_IS_H(descs[id].type));
+ break;
+ }
+ case SDIS_VERTEX:
+ type = sdis_medium_get_type(pt.data.mdmvert.medium);
+ data = sdis_medium_get_data(pt.data.mdmvert.medium);
+ pos = pt.data.mdmvert.vertex.P;
+ if(pt.data.mdmvert.vertex.P[0] == INF) {
+ /* Radiative output (ambient temperature) */
+ size_t sz = darray_descriptions_size_get(e_ctx->desc);
+ ASSERT(sz <= UINT_MAX);
+ id = (unsigned)sz; /* Ambient ID */
+ }
+ else if(type == SDIS_FLUID) {
+ struct fluid* d__ = sdis_data_get(data);
+ id = d__->desc_id;
+ } else {
+ struct solid* d__ = sdis_data_get(data);
+ ASSERT(type == SDIS_SOLID);
+ ASSERT(!d__->is_outside); /* FIXME: what if in external solid? */
+ id = d__->desc_id;
+ }
+ break;
+ default: FATAL("Unreachable code.\n"); break;
+ }
+
+ /* End, End ID, X, Y, Z, Elapsed time */
+ if(pt.data.mdmvert.vertex.P[0] == INF) {
+ fprintf(stream, "AMBIANT, %u, 0, 0, 0, %g\n",
+ id, elapsed);
+ } else {
+ fprintf(stream, "%s, %u, %g, %g, %g, %g\n",
+ str_cget(get_description_name(descs + id)), id, SPLIT3(pos), elapsed);
+ }
+
+end:
+ return res;
+error:
+ goto end;
+}
+
+static res_T
+dump_sample
+ (struct sdis_green_path* path,
+ void* ctx)
+{
+ res_T res = RES_OK;
+ struct sdis_point pt = SDIS_POINT_NULL;
+ struct sdis_data* data = NULL;
+ enum sdis_medium_type type;
+ struct htable_weigth_iterator it, end;
+ struct path_header header;
+ struct w_ctx* w_ctx = ctx;
+ const struct description* descs;
+ FILE* stream;
+ unsigned* ids = NULL;
+ double* weights = NULL;
+ size_t sz, i;
+ double t0;
+
+ CHK(path && ctx);
+
+ stream = w_ctx->stream;
+ ERR(sdis_green_path_get_limit_point(path, &pt));
+
+ /* For each path, dump:
+ * # end_id #power_terms #flux_terms
+ * power_id_1 ... power_id_n flux_id_1 ... flux_id_n
+ * power_factor_1 ... power_factor_n flux_factor_1 ... flux_factor_n
+ */
+
+ descs = darray_descriptions_cdata_get(w_ctx->desc);
+ switch (pt.type) {
+ case SDIS_FRAGMENT: {
+ struct intface* d__;
+ unsigned desc_id;
+ data = sdis_interface_get_data(pt.data.itfrag.intface);
+ d__ = sdis_data_get(data);
+ desc_id = d__->desc_id;
+ CHK(DESC_IS_T(descs[desc_id].type) || DESC_IS_H(descs[desc_id].type));
+ header.id = desc_id;
+ header.at_initial = 0;
+ break;
+ }
+ case SDIS_VERTEX:
+ type = sdis_medium_get_type(pt.data.mdmvert.medium);
+ data = sdis_medium_get_data(pt.data.mdmvert.medium);
+ t0 = medium_get_t0(pt.data.mdmvert.medium);
+ header.at_initial = (pt.data.mdmvert.vertex.time <= t0);
+ if(pt.data.mdmvert.vertex.P[0] == INF) {
+ /* Radiative output (ambient temperature) */
+ sz = darray_descriptions_size_get(w_ctx->desc);
+ ASSERT(sz <= UINT_MAX);
+ header.id = (unsigned)sz; /* Ambient ID */
+ }
+ else if(type == SDIS_FLUID) {
+ struct fluid* d__ = sdis_data_get(data);
+ header.id = d__->desc_id;
+ } else {
+ struct solid* d__ = sdis_data_get(data);
+ ASSERT(type == SDIS_SOLID);
+ ASSERT(!d__->is_outside); /* FIXME: what if in external solid? */
+ header.id = d__->desc_id;
+ }
+ break;
+ default: FATAL("Unreachable code.\n"); break;
+ }
+
+ /* Merge power and flux terms */
+ htable_weigth_clear(&w_ctx->pw);
+ htable_weigth_clear(&w_ctx->flux);
+ ERR(sdis_green_path_for_each_power_term(path, merge_power_terms, w_ctx));
+ ERR(sdis_green_path_for_each_flux_term(path, merge_flux_terms, w_ctx));
+ sz = htable_weigth_size_get(&w_ctx->pw);
+ ASSERT(sz <= UINT_MAX);
+ header.pcount = (unsigned)sz;
+ sz = htable_weigth_size_get(&w_ctx->flux);
+ ASSERT(sz <= UINT_MAX);
+ header.fcount = (unsigned)sz;
+
+ /* Write path's header */
+ FW(&header, 1);
+
+ /* Allocate buffers */
+ sz = header.pcount + header.fcount;
+ ids = MEM_CALLOC(w_ctx->alloc, sz, sizeof(*ids));
+ weights = MEM_CALLOC(w_ctx->alloc, sz, sizeof(*weights));
+ if(!ids || !weights) {
+ res = RES_MEM_ERR;
+ goto error;
+ }
+
+ /* Write terms */
+ htable_weigth_begin(&w_ctx->pw, &it);
+ htable_weigth_end(&w_ctx->pw, &end);
+ i = 0;
+ while(!htable_weigth_iterator_eq(&it, &end)) {
+ double* w = htable_weigth_iterator_data_get(&it);
+ unsigned* k = htable_weigth_iterator_key_get(&it);
+ ids[i] = *k;
+ weights[i] = *w;
+ htable_weigth_iterator_next(&it);
+ i++;
+ }
+ CHK(i == header.pcount);
+
+ htable_weigth_begin(&w_ctx->flux, &it);
+ htable_weigth_end(&w_ctx->flux, &end);
+ while (!htable_weigth_iterator_eq(&it, &end)) {
+ double* w = htable_weigth_iterator_data_get(&it);
+ unsigned* k = htable_weigth_iterator_key_get(&it);
+ ids[i] = *k;
+ weights[i] = *w;
+ htable_weigth_iterator_next(&it);
+ i++;
+ }
+ CHK(i == header.pcount + header.fcount);
+
+ FW(ids, sz);
+ FW(weights, sz);
+
+end:
+ MEM_RM(w_ctx->alloc, ids);
+ MEM_RM(w_ctx->alloc, weights);
+ return res;
+error:
+ goto end;
+}
+
+res_T
+dump_green_bin
+ (struct sdis_green_function* green,
+ const struct stardis* stardis,
+ FILE* stream)
+{
+ res_T res = RES_OK;
+ size_t ok_count, failed_count;
+ size_t sz;
+ struct w_ctx w_ctx;
+ int table_initialized = 0;
+ unsigned i, szd;
+ const struct description* descs;
+ unsigned name_pool_sz = 0;
+ char* name_pool = NULL;
+ char* pool_ptr;
+ char green_string[] = "BINGREEN";
+
+ ASSERT(green && stardis && stream);
+
+ ERR(sdis_green_function_get_paths_count(green, &ok_count));
+ ERR(sdis_green_function_get_invalid_paths_count(green, &failed_count));
+ sz = darray_descriptions_size_get(&stardis->descriptions);
+ ASSERT(sz <= UINT_MAX);
+ szd = (unsigned)sz;
+ descs = darray_descriptions_cdata_get(&stardis->descriptions);
+
+ /* Save names that do not fit inplace */
+ FOR_EACH(i, 0, szd) {
+ const struct description* desc = descs + i;
+ const struct str* name = get_description_name(desc);
+ const size_t len = str_len(name);
+ ASSERT(name_pool_sz + len + 1 <= UINT_MAX);
+ name_pool_sz += (unsigned)(len + 1);
+ }
+ pool_ptr = name_pool = MEM_ALLOC(stardis->allocator, name_pool_sz);
+ if(!name_pool) {
+ res = RES_MEM_ERR;
+ goto error;
+ }
+ FOR_EACH(i, 0, szd) {
+ const struct description* desc = descs + i;
+ const struct str* name = get_description_name(desc);
+ const size_t len = str_len(name);
+ strcpy(pool_ptr, name->cstr);
+ pool_ptr += len + 1;
+ }
+ ASSERT(pool_ptr == name_pool + name_pool_sz);
+ /* Write Green string */
+ FW(green_string, sizeof(green_string));
+
+ /* Write counts */
+ FW(&szd, 1);
+ FW(&stardis->counts, 1);
+ FW(&name_pool_sz, 1);
+ FW(&ok_count, 1);
+ FW(&failed_count, 1);
+
+ /* Write descriptions*/
+ FW(descs, szd);
+
+ /* Write names */
+ if(name_pool_sz)
+ FW(name_pool, name_pool_sz);
+
+ /* Write radiative temperatures */
+ FW(&stardis->ambient_temp, 1);
+ FW(&stardis->ref_temp, 1);
+
+ /* Write time range */
+ FW(&stardis->time_range, 2);
+
+ w_ctx.alloc = stardis->allocator;
+ w_ctx.desc = &stardis->descriptions;
+ htable_weigth_init(NULL, &w_ctx.pw);
+ htable_weigth_init(NULL, &w_ctx.flux);
+ w_ctx.stream = stream;
+ table_initialized = 1;
+
+ /* Write samples */
+ ERR(sdis_green_function_for_each_path(green, dump_sample, &w_ctx));
+
+end:
+ MEM_RM(stardis->allocator, name_pool);
+ if(table_initialized) htable_weigth_release(&w_ctx.pw);
+ if(table_initialized) htable_weigth_release(&w_ctx.flux);
+ return res;
+error:
+ goto end;
+}
+
+res_T
+dump_paths_end
+ (struct sdis_green_function* green,
+ const struct stardis* stardis,
+ FILE* stream)
+{
+ res_T res = RES_OK;
+ struct e_ctx e_ctx = { 0 };
+
+ ASSERT(green && stardis && stream);
+
+ e_ctx.desc = &stardis->descriptions;
+ e_ctx.stream = stream;
+
+ fprintf(stream, "\"End\", \"End ID\", \"X\", \"Y\", \"Z\", \"Elapsed time\"\n");
+ ERR(sdis_green_function_for_each_path(green, dump_sample_end, &e_ctx));
+
+end:
+ return res;
+error:
+ goto end;
+}
+
+res_T
+print_sample
+ (struct sdis_green_path* path,
+ void* ctx)
+{
+ res_T res = RES_OK;
+ struct sdis_point pt = SDIS_POINT_NULL;
+ struct sdis_data* data = NULL;
+ enum sdis_medium_type type;
+ struct htable_weigth_iterator it, end;
+ unsigned desc_id;
+ size_t pcount, fcount;
+ struct w_ctx* w_ctx = ctx;
+ const struct description* descs;
+ CHK(path && ctx);
+
+ ERR(sdis_green_path_get_limit_point(path, &pt));
+
+ /* For each path, prints:
+ * # end #power_terms #flux_terms power_term_1 ... power_term_n flux_term_1 ... flux_term_n
+ * with:
+ * - end = end_type end_id; end_type = T | H | A | F | S
+ * - power_term_i = power_type_i power_id_i factor_i
+ * - flux_term_i = flux_id_i factor_i
+ */
+
+ descs = darray_descriptions_cdata_get(w_ctx->desc);
+ switch (pt.type) {
+ case SDIS_FRAGMENT: {
+ struct intface* d__;
+ data = sdis_interface_get_data(pt.data.itfrag.intface);
+ d__ = sdis_data_get(data);
+ desc_id = d__->desc_id;
+ switch (descs[desc_id].type) {
+ case DESC_BOUND_T_FOR_SOLID:
+ case DESC_BOUND_T_FOR_FLUID:
+ fprintf(w_ctx->stream, "T\t%u", desc_id);
+ break;
+ case DESC_BOUND_H_FOR_SOLID:
+ case DESC_BOUND_H_FOR_FLUID:
+ fprintf(w_ctx->stream, "H\t%u", desc_id);
+ break;
+ case DESC_BOUND_F_FOR_SOLID:
+ FATAL("Heat path cannot end at a flux boundary.\n"); break;
+ break;
+ default: FATAL("Unreachable code.\n"); break;
+ }
+ break;
+ }
+ case SDIS_VERTEX:
+ type = sdis_medium_get_type(pt.data.mdmvert.medium);
+ data = sdis_medium_get_data(pt.data.mdmvert.medium);
+ if(pt.data.mdmvert.vertex.P[0] == INF) {
+ /* Radiative output (ambient temperature)*/
+ size_t sz = darray_descriptions_size_get(w_ctx->desc);
+ ASSERT(sz <= UINT_MAX);
+ fprintf(w_ctx->stream, "A\t%u", (unsigned)sz);
+ }
+ else if(type == SDIS_FLUID) {
+ struct fluid* d__ = sdis_data_get(data);
+ desc_id = d__->desc_id;
+ if(d__->is_outside)
+ /* If outside the model and in a fluid with known temperature,
+ * its a fluid attached to a H boundary */
+ fprintf(w_ctx->stream, "H\t%u", desc_id);
+ /* In a standard fluid with known temperature */
+ else fprintf(w_ctx->stream, "F\t%u", desc_id);
+ } else {
+ struct solid* d__ = sdis_data_get(data);
+ ASSERT(type == SDIS_SOLID);
+ ASSERT(!d__->is_outside); /* FIXME: what if in external solid? */
+ desc_id = d__->desc_id;
+ fprintf(w_ctx->stream, "S\t%u", desc_id);
+ }
+ break;
+ default: FATAL("Unreachable code.\n"); break;
+ }
+
+ ERR(sdis_green_function_get_power_terms_count(path, &pcount));
+
+ htable_weigth_clear(&w_ctx->pw);
+ htable_weigth_clear(&w_ctx->flux);
+ ERR(sdis_green_path_for_each_power_term(path, merge_power_terms, w_ctx));
+ ERR(sdis_green_path_for_each_flux_term(path, merge_flux_terms, w_ctx));
+ fcount = htable_weigth_size_get(&w_ctx->flux);
+
+ ASSERT(pcount <= ULONG_MAX && fcount <= ULONG_MAX);
+ fprintf(w_ctx->stream, "\t%lu\t%lu",
+ (unsigned long)pcount, (unsigned long)fcount);
+
+ htable_weigth_begin(&w_ctx->pw, &it);
+ htable_weigth_end(&w_ctx->pw, &end);
+ while(!htable_weigth_iterator_eq(&it, &end)) {
+ double* w = htable_weigth_iterator_data_get(&it);
+ unsigned* k = htable_weigth_iterator_key_get(&it);
+ fprintf(w_ctx->stream, "\t%u\t%g", *k, *w);
+ htable_weigth_iterator_next(&it);
+ }
+
+ htable_weigth_begin(&w_ctx->flux, &it);
+ htable_weigth_end(&w_ctx->flux, &end);
+ while (!htable_weigth_iterator_eq(&it, &end)) {
+ double* w = htable_weigth_iterator_data_get(&it);
+ unsigned* k = htable_weigth_iterator_key_get(&it);
+ fprintf(w_ctx->stream, "\t%u\t%g", *k, *w);
+ htable_weigth_iterator_next(&it);
+ }
+ fprintf(w_ctx->stream, "\n");
+
+end:
+ return res;
+error:
+ goto end;
+}
+
+res_T
+dump_green_ascii
+ (struct sdis_green_function* green,
+ const struct stardis* stardis,
+ FILE* stream)
+{
+ res_T res = RES_OK;
+ unsigned ok_count, failed_count;
+ size_t sz;
+ struct w_ctx w_ctx;
+ int table_initialized = 0;
+ unsigned i, szd;
+ const struct description* descs;
+
+ ASSERT(green && stardis && stream);
+
+ ERR(sdis_green_function_get_paths_count(green, &sz));
+ ASSERT(sz <= UINT_MAX);
+ ok_count = (unsigned)sz;
+ ERR(sdis_green_function_get_invalid_paths_count(green, &sz));
+ ASSERT(sz <= UINT_MAX);
+ failed_count = (unsigned)sz;
+ sz = darray_descriptions_size_get(&stardis->descriptions);
+ ASSERT(sz <= UINT_MAX);
+ szd = (unsigned)sz;
+ descs = darray_descriptions_cdata_get(&stardis->descriptions);
+
+ /* Output counts */
+ fprintf(stream, "---BEGIN GREEN---\n");
+ fprintf(stream, "# time range\n");
+ fprintf(stream, "%g %g\n",
+ SPLIT2(stardis->time_range));
+ fprintf(stream,
+ "# #solids #fluids #t_boundaries #h_boundaries #f_boundaries #ok #failures\n");
+ fprintf(stream, "%u %u %u %u %u %u %u\n",
+ stardis->counts.smed_count, stardis->counts.fmed_count,
+ stardis->counts.tbound_count, stardis->counts.hbound_count,
+ stardis->counts.fbound_count, ok_count, failed_count);
+
+ /* List Media */
+ if(stardis->counts.smed_count) {
+ fprintf(stream, "# Solids\n");
+ fprintf(stream, "# ID Name lambda rho cp power initial_temp imposed_temp\n");
+ FOR_EACH(i, 0, szd) {
+ const struct description* desc = descs + i;
+ const struct solid* sl;
+ if(desc->type != DESC_MAT_SOLID) continue;
+ sl = &desc->d.solid;
+ fprintf(stream, "%u\t%s\t%g\t%g\t%g\t%g",
+ i, str_cget(&sl->name), sl->lambda, sl->rho, sl->cp, sl->vpower);
+ if(sl->tinit >= 0) {
+ fprintf(stream, "\t%g", sl->tinit);
+ } else {
+ fprintf(stream, "\tNONE");
+ }
+ if(sl->imposed_temperature >= 0) {
+ fprintf(stream, "\t%g\n", sl->imposed_temperature);
+ } else {
+ fprintf(stream, "\tNONE\n");
+ }
+ }
+ }
+ if(stardis->counts.fmed_count) {
+ fprintf(stream, "# Fluids\n");
+ fprintf(stream, "# ID Name rho cp initial_temp imposed_temp\n");
+ FOR_EACH(i, 0, szd) {
+ const struct description* desc = descs + i;
+ const struct fluid* fl;
+ if(desc->type != DESC_MAT_FLUID) continue;
+ fl = &desc->d.fluid;
+ if(fl->imposed_temperature >= 0) {
+ fprintf(stream, "%u\t%s\t%g\t%g",
+ i, str_cget(&fl->name), fl->rho, fl->cp);
+ } else {
+ fprintf(stream, "%u\t%s\t%g\t%g",
+ i, str_cget(&fl->name), fl->rho, fl->cp);
+ }
+ if(fl->tinit >= 0) {
+ fprintf(stream, "\t%g", fl->tinit);
+ } else {
+ fprintf(stream, "\tNONE");
+ }
+ if(fl->imposed_temperature >= 0) {
+ fprintf(stream, "\t%g\n", fl->imposed_temperature);
+ } else {
+ fprintf(stream, "\tNONE\n");
+ }
+ }
+ }
+
+ /* List Boundaries */
+ if(stardis->counts.tbound_count) {
+ fprintf(stream, "# T Boundaries\n");
+ fprintf(stream, "# ID Name temperature\n");
+ FOR_EACH(i, 0, szd) {
+ const struct description* desc = descs + i;
+ const struct t_boundary* bd;
+ if(desc->type != DESC_BOUND_T_FOR_SOLID
+ && desc->type != DESC_BOUND_T_FOR_FLUID) continue;
+ bd = &desc->d.t_boundary;
+ fprintf(stream, "%u\t%s\t%g\n",
+ i, str_cget(&bd->name), bd->imposed_temperature);
+ }
+ }
+ if(stardis->counts.hbound_count) {
+ fprintf(stream, "# H Boundaries\n");
+ fprintf(stream, "# ID Name emissivity specular_fraction hc T_env\n");
+ FOR_EACH(i, 0, szd) {
+ const struct description* desc = descs + i;
+ const struct h_boundary* bd;
+ if(desc->type != DESC_BOUND_H_FOR_SOLID
+ && desc->type != DESC_BOUND_H_FOR_FLUID) continue;
+ bd = &desc->d.h_boundary;
+ fprintf(stream, "%u\t%s\t%g\t%g\t%g\t%g\n",
+ i, str_cget(&bd->name), bd->emissivity, bd->specular_fraction,
+ bd->hc, bd->imposed_temperature);
+ }
+ }
+ if(stardis->counts.fbound_count) {
+ fprintf(stream, "# F Boundaries\n");
+ fprintf(stream, "# ID Name flux\n");
+ FOR_EACH(i, 0, szd) {
+ const struct description* desc = descs + i;
+ const struct f_boundary* bd;
+ if(desc->type != DESC_BOUND_F_FOR_SOLID) continue;
+ bd = &desc->d.f_boundary;
+ fprintf(stream, "%u\t%s\t%g\n",
+ i, str_cget(&bd->name), bd->imposed_flux);
+ }
+ }
+
+ /* Radiative Temperatures */
+ fprintf(stream, "# Radiative Temperatures\n");
+ fprintf(stream, "# ID Amb_Temp Lin_Temp\n");
+ fprintf(stream, "%u\t%g\t%g\n",
+ szd, stardis->ambient_temp, stardis->ref_temp);
+
+ fprintf(stream, "# Samples\n");
+ fprintf(stream,
+ "# end #power_terms #flux_terms power_term_1 ... power_term_n flux_term_1 ... flux_term_n\n");
+ fprintf(stream, "# end = end_type end_id; end_type = T | H | A | F | S\n");
+ fprintf(stream, "# power_term_i = power_id_i factor_i\n");
+ fprintf(stream, "# flux_term_i = flux_id_i factor_i\n");
+
+ w_ctx.alloc = stardis->allocator;
+ w_ctx.desc = &stardis->descriptions;
+ htable_weigth_init(NULL, &w_ctx.pw);
+ htable_weigth_init(NULL, &w_ctx.flux);
+ w_ctx.stream = stream;
+ table_initialized = 1;
+
+ ERR(sdis_green_function_for_each_path(green, print_sample, &w_ctx));
+
+ fprintf(stream, "---END GREEN---\n");
+
+end:
+ if(table_initialized) htable_weigth_release(&w_ctx.pw);
+ if(table_initialized) htable_weigth_release(&w_ctx.flux);
+ return res;
+error:
+ goto end;
+}
+
+res_T
+dump_boundaries_at_the_end_of_vtk
+ (const struct stardis* stardis,
+ FILE* stream)
+{
+ res_T res = RES_OK;
+ const struct description* descriptions;
+ unsigned tsz, t;
+ ASSERT(stardis && stream);
+
+ ERR(sg3d_geometry_get_unique_triangles_count(stardis->geometry.sg3d, &tsz));
+ descriptions = darray_descriptions_cdata_get(&stardis->descriptions);
+
+ fprintf(stream, "SCALARS Boundaries unsigned_int 1\n");
+ fprintf(stream, "LOOKUP_TABLE default\n");
+ FOR_EACH(t, 0, tsz) {
+ unsigned descr[SG3D_PROP_TYPES_COUNT__];
+ ERR(sg3d_geometry_get_unique_triangle_properties(stardis->geometry.sg3d, t,
+ descr));
+ if(descr[SG3D_INTFACE] != SG3D_UNSPECIFIED_PROPERTY
+ && DESC_IS_BOUNDARY(descriptions[descr[SG3D_INTFACE]].type))
+ /* Descriptions are numbered from 1 in the log (so the 1+ below) */
+ fprintf(stream, "%u\n", 1 + descr[SG3D_INTFACE]);
+ else fprintf(stream, "%u\n", SG3D_UNSPECIFIED_PROPERTY);
+ }
+
+exit:
+ return res;
+error:
+ goto exit;
+}
+
+res_T
+dump_enclosure_related_stuff_at_the_end_of_vtk
+ (struct stardis* stardis,
+ FILE* stream)
+{
+ res_T res = RES_OK;
+ unsigned* trgs = NULL;
+ struct senc3d_enclosure* enc = NULL;
+ unsigned tsz, e, s, t, scount, ecount, ocount;
+ int* enc_status = NULL;
+ const struct description* descriptions;
+ int invalid_enclosures_count = 0;
+ ASSERT(stardis && stream);
+
+ descriptions = darray_descriptions_cdata_get(&stardis->descriptions);
+ ERR(sg3d_geometry_get_unique_triangles_count(stardis->geometry.sg3d, &tsz));
+ trgs = MEM_CALLOC(stardis->allocator, tsz, sizeof(*trgs));
+ if(!trgs) {
+ res = RES_MEM_ERR;
+ goto error;
+ }
+
+ /* If enclosure where not extracted, dump only errors */
+ ERR(senc3d_scene_get_overlapping_triangles_count(stardis->senc3d_scn, &ocount));
+ if(ocount) {
+ FOR_EACH(t, 0, tsz) trgs[t] = 0;
+ FOR_EACH(t, 0, ocount) {
+ unsigned trid;
+ ERR(senc3d_scene_get_overlapping_triangle(stardis->senc3d_scn, t, &trid));
+ trgs[trid] = 1;
+ }
+ fprintf(stream, "SCALARS Overlapping_triangles unsigned_int 1\n");
+ fprintf(stream, "LOOKUP_TABLE default\n");
+ FOR_EACH(t, 0, tsz) fprintf(stream, "%u\n", trgs[t]);
+ goto exit;
+ }
+
+ /* Keep the segments involved in holes (not the vertices) */
+ ERR(senc3d_scene_get_frontier_segments_count(stardis->senc3d_scn, &scount));
+ if(scount) {
+ /* Room to store frontier triangles */
+ FOR_EACH(s, 0, scount) {
+ unsigned vrtc[2], trid;
+ ERR(senc3d_scene_get_frontier_segment(stardis->senc3d_scn, s, vrtc, &trid));
+ trgs[trid] = 1;
+ }
+ logger_print(stardis->logger, LOG_WARNING, "Model contains hole(s).\n");
+ fprintf(stream, "SCALARS Hole_frontiers unsigned_int 1\n");
+ fprintf(stream, "LOOKUP_TABLE default\n");
+ FOR_EACH(t, 0, tsz) fprintf(stream, "%u\n", trgs[t]);
+ }
+
+ /* Dump enclosure information */
+ ERR(senc3d_scene_get_enclosure_count(stardis->senc3d_scn, &ecount));
+ enc_status = MEM_CALLOC(stardis->allocator, ecount, sizeof(*enc_status));
+ if(!enc_status) {
+ res = RES_MEM_ERR;
+ goto error;
+ }
+ ASSERT(stardis->undefined_medium_behind_boundary_id != SENC3D_UNSPECIFIED_MEDIUM);
+ FOR_EACH(e, 0, ecount) {
+ struct senc3d_enclosure_header header;
+ unsigned tid, med, enc_fst_med = SENC3D_UNSPECIFIED_MEDIUM;
+ int is_fst_med = 1, is_err_cs = 0;
+
+ enc_status[e] = NO_ENCLOSURE_ERROR;
+ ERR(senc3d_scene_get_enclosure(stardis->senc3d_scn, e, &enc));
+ ERR(senc3d_enclosure_get_header(enc, &header));
+
+ FOR_EACH(t, 0, header.unique_primitives_count) {
+ unsigned prop[SG3D_PROP_TYPES_COUNT__];
+ enum senc3d_side side;
+ size_t j;
+ ERR(senc3d_enclosure_get_triangle_id(enc, t, &tid, &side));
+ FOR_EACH(j, 0, darray_uint_size_get(&stardis->compute_surface.err_triangles))
+ {
+ unsigned prim
+ = darray_uint_cdata_get(&stardis->compute_surface.err_triangles)[j];
+ if(prim == tid) {
+ is_err_cs = 1;
+ break;
+ }
+ }
+ if(is_err_cs)
+ /* Don't flag an enclosure invalid because of a triangle that is
+ * considered not member of it */
+ continue;
+
+ ERR(sg3d_geometry_get_unique_triangle_properties(stardis->geometry.sg3d,
+ tid, prop));
+
+ if(prop[side] != SG3D_UNSPECIFIED_PROPERTY) {
+ ASSERT(prop[side] < darray_descriptions_size_get(&stardis->descriptions));
+ description_get_medium_id(descriptions + prop[side], &med);
+ } else {
+ /* If unspecified behind a boundary, use a specific ID to avoid to flag
+ * using different boundaries for a given enclosure as invalid */
+ int properties_conflict_status;
+ validate_properties(t, prop, stardis, &properties_conflict_status);
+ if(properties_conflict_status == NO_PROPERTY_CONFLICT)
+ med = stardis->undefined_medium_behind_boundary_id;
+ else {
+ enc_status[e] |= ENCLOSURE_WITH_UNDEF_MEDIUM;
+ continue; /* Don't flag N_MEDIA at the same time */
+ }
+ }
+ if(is_fst_med) {
+ is_fst_med = 0;
+ enc_fst_med = med;
+ } else {
+ if(enc_fst_med != med)
+ enc_status[e] |= ENCLOSURE_WITH_N_MEDIA;
+ }
+ }
+ /* The external (infinite) enclosure is always valid */
+ if(enc_status[e] != NO_ENCLOSURE_ERROR && !header.is_infinite)
+ invalid_enclosures_count++;
+ ERR(senc3d_enclosure_ref_put(enc));
+ }
+ if(invalid_enclosures_count) {
+ logger_print(stardis->logger, LOG_WARNING,
+ "Found %d invalid enclosure(s).\n", invalid_enclosures_count);
+ }
+ fprintf(stream, "FIELD EnclosuresData 2\n");
+ fprintf(stream, "Enclosures %d %d unsigned_char\n", ecount, tsz);
+ FOR_EACH(t, 0, tsz) {
+ unsigned encs[2], is_err_cs = 0;
+ size_t j;
+ FOR_EACH(j, 0, darray_uint_size_get(&stardis->compute_surface.err_triangles))
+ {
+ unsigned prim
+ = darray_uint_cdata_get(&stardis->compute_surface.err_triangles)[j];
+ if(prim == t) {
+ is_err_cs = 1;
+ break;
+ }
+ }
+ if(is_err_cs) {
+ /* Triangles in compute surface with error are considered member of no
+ * enclosure */
+ FOR_EACH(e, 1, ecount) fprintf(stream, "0 ");
+ fprintf(stream, "0\n");
+ continue;
+ }
+ ERR(senc3d_scene_get_triangle_enclosures(stardis->senc3d_scn, t, encs));
+ FOR_EACH(e, 0, ecount) {
+ unsigned c = (e == encs[SENC3D_FRONT] || e == encs[SENC3D_BACK])
+ ? (unsigned char)enc_status[e] : 0;
+ if(e == ecount - 1)
+ fprintf(stream, "%u\n", c);
+ else fprintf(stream, "%u ", c);
+ }
+ }
+
+#define ENC_NOT_MEMBER SENC3D_UNSPECIFIED_MEDIUM
+#define ENC_MEMBER_2_DISTINT_MEDIA (ENC_NOT_MEMBER - 1)
+#define ENC_MEMBER_NO_MEDIUM (ENC_NOT_MEMBER - 2)
+
+ fprintf(stream, "Enclosures_internal_media %d %d unsigned_int\n", ecount, tsz);
+ FOR_EACH(t, 0, tsz) {
+ unsigned descr[SG3D_PROP_TYPES_COUNT__];
+ unsigned encs[2];
+ unsigned is_err_cs = 0;
+ size_t j;
+ ERR(senc3d_scene_get_triangle_enclosures(stardis->senc3d_scn, t, encs));
+ ERR(sg3d_geometry_get_unique_triangle_properties(stardis->geometry.sg3d, t,
+ descr));
+
+ /* Special value for triangles in compute surface with error */
+ FOR_EACH(j, 0, darray_uint_size_get(&stardis->compute_surface.err_triangles))
+ {
+ unsigned prim
+ = darray_uint_cdata_get(&stardis->compute_surface.err_triangles)[j];
+ if(prim == t) {
+ is_err_cs = 1;
+ break;
+ }
+ }
+ if(is_err_cs) {
+ /* Triangles in compute surface with error are considered member of no
+ * enclosure */
+ FOR_EACH(e, 1, ecount) fprintf(stream, "%u ", ENC_NOT_MEMBER);
+ fprintf(stream, "%u\n", ENC_NOT_MEMBER);
+ continue;
+ }
+ FOR_EACH(e, 0, ecount) {
+ unsigned mid;
+ if(e == encs[SENC3D_FRONT] && e == encs[SENC3D_BACK]) {
+ /* Both sides of this triangle are in enclosure #e */
+ unsigned fmid, bmid;
+ if(descr[SG3D_FRONT] != SG3D_UNSPECIFIED_PROPERTY)
+ description_get_medium_id(descriptions + descr[SG3D_FRONT], &fmid);
+ else if(descr[SG3D_INTFACE] != SG3D_UNSPECIFIED_PROPERTY
+ && DESC_IS_BOUNDARY(descriptions[descr[SG3D_INTFACE]].type))
+ {
+ description_get_medium_id(descriptions + descr[SG3D_INTFACE], &fmid);
+ }
+ else fmid = ENC_MEMBER_NO_MEDIUM;
+ if(descr[SENC3D_BACK] != SG3D_UNSPECIFIED_PROPERTY)
+ description_get_medium_id(descriptions + descr[SENC3D_BACK], &bmid);
+ else if(descr[SG3D_INTFACE] != SG3D_UNSPECIFIED_PROPERTY
+ && DESC_IS_BOUNDARY(descriptions[descr[SG3D_INTFACE]].type))
+ {
+ description_get_medium_id(descriptions + descr[SG3D_INTFACE], &bmid);
+ }
+ else bmid = ENC_MEMBER_NO_MEDIUM;
+ mid = (fmid == bmid) ? fmid : ENC_MEMBER_2_DISTINT_MEDIA;
+ }
+ else if(e == encs[SENC3D_FRONT]) {
+ /* Member of enclosure #e (front side only) */
+ if(descr[SG3D_FRONT] != SG3D_UNSPECIFIED_PROPERTY)
+ description_get_medium_id(descriptions + descr[SG3D_FRONT], &mid);
+ else if(descr[SG3D_INTFACE] != SG3D_UNSPECIFIED_PROPERTY
+ && DESC_IS_BOUNDARY(descriptions[descr[SG3D_INTFACE]].type))
+ {
+ description_get_medium_id(descriptions + descr[SG3D_INTFACE], &mid);
+ }
+ else mid = ENC_MEMBER_NO_MEDIUM;
+ }
+ else if(e == encs[SENC3D_BACK]) {
+ /* Member of enclosure #e (back side only) */
+ if(descr[SENC3D_BACK] != SG3D_UNSPECIFIED_PROPERTY)
+ description_get_medium_id(descriptions + descr[SENC3D_BACK], &mid);
+ else if(descr[SG3D_INTFACE] != SG3D_UNSPECIFIED_PROPERTY
+ && DESC_IS_BOUNDARY(descriptions[descr[SG3D_INTFACE]].type))
+ {
+ description_get_medium_id(descriptions + descr[SG3D_INTFACE], &mid);
+ }
+ else mid = ENC_MEMBER_NO_MEDIUM;
+ } else {
+ /* Not member of enclosure #e */
+ mid = ENC_NOT_MEMBER;
+ }
+ if(e == ecount - 1)
+ fprintf(stream, "%u\n", mid);
+ else fprintf(stream, "%u ", mid);
+ }
+ }
+
+#undef ENC_NOT_MEMBER
+#undef ENC_ERR_COMPUTE_SURFACE
+#undef ENC_MEMBER_2_DISTINT_MEDIA
+#undef ENC_MEMBER_NO_MEDIUM
+
+exit:
+ MEM_RM(stardis->allocator, trgs);
+ MEM_RM(stardis->allocator, enc_status);
+ return res;
+error:
+ goto exit;
+}
+
+res_T
+print_single_MC_result
+ (struct sdis_estimator* estimator,
+ struct stardis* stardis,
+ FILE* stream)
+{
+ res_T res = RES_OK;
+ struct sdis_mc result;
+ size_t nfailures_;
+ unsigned long nfailures, nsamples;
+
+ ASSERT(estimator && stardis && stream);
+
+ /* Fetch the estimation data */
+ ERR(sdis_estimator_get_temperature(estimator, &result));
+ ERR(sdis_estimator_get_failure_count(estimator, &nfailures_));
+ ASSERT(nfailures_ <= ULONG_MAX && stardis->samples <= ULONG_MAX);
+ nfailures = (unsigned long)nfailures_;
+ nsamples = (unsigned long)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;
+ }
+
+ /* Print the results */
+ switch (stardis->mode & COMPUTE_MODES) {
+ case MODE_PROBE_COMPUTE:
+ if(stardis->mode & MODE_EXTENDED_RESULTS) {
+ if(stardis->time_range[0] == stardis->time_range[1])
+ fprintf(stream, "Temperature at [%g, %g, %g] at t=%g = %g +/- %g\n",
+ SPLIT3(stardis->probe), stardis->time_range[0],
+ result.E, /* Expected value */
+ result.SE); /* Standard error */
+ else
+ fprintf(stream, "Temperature at [%g, %g, %g] with t in [%g %g] = %g +/- %g\n",
+ SPLIT3(stardis->probe), SPLIT2(stardis->time_range),
+ result.E, /* Expected value */
+ result.SE); /* Standard error */
+ }
+ 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 +/- %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 +/- %g\n",
+ SPLIT3(stardis->probe), SPLIT2(stardis->time_range),
+ result.E, /* Expected value */
+ result.SE); /* Standard error */
+ }
+ 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])
+ fprintf(stream, "Temperature in medium '%s' at t=%g = %g +/- %g\n",
+ str_cget(&stardis->solve_name), stardis->time_range[0],
+ result.E, /* Expected value */
+ result.SE); /* Standard error */
+ else
+ fprintf(stream, "Temperature in medium '%s' with t in [%g %g] = %g +/- %g\n",
+ str_cget(&stardis->solve_name), SPLIT2(stardis->time_range),
+ result.E, /* Expected value */
+ result.SE); /* Standard error */
+ }
+ else fprintf(stream, "%g %g %lu %lu\n",
+ result.E, result.SE, nfailures, nsamples);
+ break;
+ case MODE_BOUNDARY_COMPUTE:
+ if(stardis->mode & MODE_EXTENDED_RESULTS) {
+ if(stardis->time_range[0] == stardis->time_range[1])
+ fprintf(stream, "Temperature at boundary '%s' at t=%g = %g +/- %g\n",
+ str_cget(&stardis->solve_name), stardis->time_range[0],
+ result.E, /* Expected value */
+ result.SE); /* Standard error */
+ else
+ fprintf(stream, "Temperature at boundary '%s' with t in [%g %g] = %g +/- %g\n",
+ str_cget(&stardis->solve_name), SPLIT2(stardis->time_range),
+ result.E, /* Expected value */
+ result.SE); /* Standard error */
+ }
+ else fprintf(stream, "%g %g %lu %lu\n",
+ result.E, result.SE, nfailures, nsamples);
+ break;
+ case MODE_FLUX_BOUNDARY_COMPUTE: {
+ enum sdis_estimator_type type;
+ ERR(sdis_estimator_get_type(estimator, &type));
+ ASSERT(type == SDIS_ESTIMATOR_FLUX);
+
+ if(stardis->mode & MODE_EXTENDED_RESULTS) {
+ if(stardis->time_range[0] == stardis->time_range[1])
+ fprintf(stream, "Temperature at boundary '%s' at t=%g = %g +/- %g\n",
+ str_cget(&stardis->solve_name), stardis->time_range[0],
+ result.E, /* Expected value */
+ result.SE); /* Standard error */
+ else
+ fprintf(stream, "Temperature at boundary '%s' with t in [%g %g] = %g +/- %g\n",
+ str_cget(&stardis->solve_name), SPLIT2(stardis->time_range),
+ result.E, /* Expected value */
+ result.SE); /* Standard error */
+ ERR(sdis_estimator_get_convective_flux(estimator, &result));
+ if(stardis->time_range[0] == stardis->time_range[1])
+ fprintf(stream, "Convective flux at boundary '%s' at t=%g = %g +/- %g\n",
+ str_cget(&stardis->solve_name), stardis->time_range[0],
+ result.E, /* Expected value */
+ result.SE); /* Standard error */
+ else
+ fprintf(stream, "Convective flux at boundary '%s' with t in [%g %g] = %g +/- %g\n",
+ str_cget(&stardis->solve_name), SPLIT2(stardis->time_range),
+ result.E, /* Expected value */
+ result.SE); /* Standard error */
+ ERR(sdis_estimator_get_radiative_flux(estimator, &result));
+ if(stardis->time_range[0] == stardis->time_range[1])
+ fprintf(stream, "Radiative flux at boundary '%s' at t=%g = %g +/- %g\n",
+ str_cget(&stardis->solve_name), stardis->time_range[0],
+ result.E, /* Expected value */
+ result.SE); /* Standard error */
+ else
+ fprintf(stream, "Radiative flux at boundary '%s' with t in [%g %g] = %g +/- %g\n",
+ str_cget(&stardis->solve_name), SPLIT2(stardis->time_range),
+ result.E, /* Expected value */
+ result.SE); /* Standard error */
+ ERR(sdis_estimator_get_imposed_flux(estimator, &result));
+ if(stardis->time_range[0] == stardis->time_range[1])
+ fprintf(stream, "Imposed flux at boundary '%s' at t=%g = %g +/- %g\n",
+ str_cget(&stardis->solve_name), stardis->time_range[0],
+ result.E, /* Expected value */
+ result.SE); /* Standard error */
+ else
+ fprintf(stream, "Imposed flux at boundary '%s' with t in [%g %g] = %g +/- %g\n",
+ str_cget(&stardis->solve_name), SPLIT2(stardis->time_range),
+ result.E, /* Expected value */
+ result.SE); /* Standard error */
+ ERR(sdis_estimator_get_total_flux(estimator, &result));
+ if(stardis->time_range[0] == stardis->time_range[1])
+ fprintf(stream, "Total flux Flux at boundary '%s' at t=%g = %g +/- %g\n",
+ str_cget(&stardis->solve_name), stardis->time_range[0],
+ result.E, /* Expected value */
+ result.SE); /* Standard error */
+ else
+ fprintf(stream, "Total flux Flux at boundary '%s' with t in [%g %g] = %g +/- %g\n",
+ str_cget(&stardis->solve_name), SPLIT2(stardis->time_range),
+ result.E, /* Expected value */
+ result.SE); /* Standard error */
+ } else {
+ fprintf(stream, "%g %g ", result.E, result.SE);
+ ERR(sdis_estimator_get_convective_flux(estimator, &result));
+ fprintf(stream, "%g %g ", result.E, result.SE);
+ ERR(sdis_estimator_get_radiative_flux(estimator, &result));
+ fprintf(stream, "%g %g ", result.E, result.SE);
+ ERR(sdis_estimator_get_imposed_flux(estimator, &result));
+ fprintf(stream, "%g %g ", result.E, result.SE);
+ ERR(sdis_estimator_get_total_flux(estimator, &result));
+ fprintf(stream, "%g %g ", result.E, result.SE);
+ fprintf(stream, "%lu %lu\n", nfailures, nsamples);
+ }
+ break;
+ }
+ default: FATAL("Invalid mode.");
+ }
+ if(stardis->mode & MODE_EXTENDED_RESULTS)
+ fprintf(stream, "#failures: %lu/%lu\n", nfailures, nsamples);
+ if(nfailures)
+ logger_print(stardis->logger, LOG_ERROR,
+ "#failures: %lu/%lu\n", nfailures, nsamples);
+
+end:
+ return res;
+error:
+ goto end;
+}
+
+void
+dump_map
+ (const struct stardis* stardis,
+ const struct darray_estimators* estimators,
+ FILE* stream)
+{
+ unsigned i, vcount, tcount, last_v = 0;
+ const size_t* idx;
+ size_t sz;
+ unsigned szp;
+ struct sdis_estimator* const* est;
+
+ ASSERT(stardis && estimators && stream);
+
+ est = darray_estimators_cdata_get(estimators);
+ idx = darray_size_t_cdata_get(&stardis->compute_surface.primitives);
+ sz = darray_size_t_size_get(&stardis->compute_surface.primitives);
+ ASSERT(sz <= UINT_MAX);
+ szp = (unsigned)sz;
+ SG3D(geometry_get_unique_vertices_count(stardis->geometry.sg3d, &vcount));
+ SG3D(geometry_get_unique_triangles_count(stardis->geometry.sg3d, &tcount));
+
+ /* Find last used vertex */
+ for(i = 0; i < szp; ++i) {
+ unsigned t;
+ unsigned indices[3];
+ ASSERT(idx[i] <= UINT_MAX);
+ t = (unsigned)idx[i];
+ SG3D(geometry_get_unique_triangle_vertices(stardis->geometry.sg3d, t,
+ indices));
+ last_v = MMAX(MMAX(last_v, indices[0]), MMAX(indices[1], indices[2]));
+ }
+
+ /* Dump vertices up to last_v, even unused ones, to avoid reindexing */
+ fprintf(stream, "# vtk DataFile Version 2.0\n");
+ fprintf(stream, "Temperature Map\n");
+ fprintf(stream, "ASCII\n");
+ fprintf(stream, "DATASET POLYDATA\n");
+ fprintf(stream, "POINTS %u float\n\n", last_v + 1);
+ for(i = 0; i <= last_v; ++i) {
+ double coord[3];
+ SG3D(geometry_get_unique_vertex(stardis->geometry.sg3d, i, coord));
+ fprintf(stream, "%f %f %f\n", SPLIT3(coord));
+ }
+ /* Dump only primitives in boundary */
+ fprintf(stream, "\nPOLYGONS %u %u\n", szp, 4 * szp);
+ for(i = 0; i < szp; ++i) {
+ unsigned t;
+ unsigned indices[3];
+ ASSERT(idx[i] <= UINT_MAX);
+ t = (unsigned)idx[i];
+ SG3D(geometry_get_unique_triangle_vertices(stardis->geometry.sg3d, t,
+ indices));
+ fprintf(stream, "3 %u %u %u\n", SPLIT3(indices));
+ }
+ fprintf(stream, "\nCELL_DATA %u\n", szp);
+ fprintf(stream, "SCALARS temperature_estimate float 1\n");
+ fprintf(stream, "LOOKUP_TABLE default\n");
+ for(i = 0; i < szp; ++i) {
+ struct sdis_mc T;
+ SDIS(estimator_get_temperature(est[i], &T));
+ fprintf(stream, "%f\n", T.E);
+ }
+ fprintf(stream, "SCALARS temperature_std_dev float 1\n");
+ fprintf(stream, "LOOKUP_TABLE default\n");
+ for(i = 0; i < szp; ++i) {
+ struct sdis_mc T;
+ SDIS(estimator_get_temperature(est[i], &T));
+ fprintf(stream, "%f\n", T.SE);
+ }
+ fprintf(stream, "SCALARS failures_count unsigned_long_long 1\n");
+ fprintf(stream, "LOOKUP_TABLE default\n");
+ for(i = 0; i < szp; ++i) {
+ size_t nfails;
+ SDIS(estimator_get_failure_count(est[i], &nfails));
+ ASSERT(nfails <= UINT_MAX);
+ fprintf(stream, "%u\n", (unsigned)nfails);
+ }
+ fprintf(stream, "SCALARS computation_time_estimate float 1\n");
+ fprintf(stream, "LOOKUP_TABLE default\n");
+ for(i = 0; i < szp; ++i) {
+ struct sdis_mc time;
+ SDIS(estimator_get_realisation_time(est[i], &time));
+ fprintf(stream, "%f\n", time.E);
+ }
+ fprintf(stream, "SCALARS computation_time_std_dev float 1\n");
+ fprintf(stream, "LOOKUP_TABLE default\n");
+ for(i = 0; i < szp; ++i) {
+ struct sdis_mc time;
+ SDIS(estimator_get_realisation_time(est[i], &time));
+ fprintf(stream, "%f\n", time.SE);
+ }
+}
+
+res_T
+dump_compute_region_at_the_end_of_vtk
+ (struct stardis* stardis,
+ FILE* stream)
+{
+ res_T res = RES_OK;
+ unsigned char* v = NULL;
+ unsigned tsz, i;
+ size_t j, psz;
+ ASSERT(stardis && stream);
+ psz = darray_size_t_size_get(&stardis->compute_surface.primitives);
+ ASSERT(psz == darray_sides_size_get(&stardis->compute_surface.sides));
+
+ ERR(sg3d_geometry_get_unique_triangles_count(stardis->geometry.sg3d, &tsz));
+ /* For triangles not in compute region v==0 */
+ v = MEM_CALLOC(stardis->allocator, tsz, sizeof(*v));
+ if(!v) {
+ res = RES_MEM_ERR;
+ goto error;
+ }
+
+ if(stardis->mode & SURFACE_COMPUTE_MODES) {
+ /* For triangles in compute surface, v==1 if FRONT or v==2 for BACK */
+ FOR_EACH(j, 0, psz) {
+ size_t prim
+ = darray_size_t_cdata_get(&stardis->compute_surface.primitives)[j];
+ enum sdis_side side
+ = darray_sides_cdata_get(&stardis->compute_surface.sides)[j];
+ ASSERT(prim <= tsz);
+ v[(unsigned)prim] =
+ (unsigned char)(v[(unsigned)prim] | (side == SDIS_FRONT ? 1 : 2));
+ }
+
+ /* For triangles in compute surface with error v==MAX */
+ FOR_EACH(j, 0, darray_uint_size_get(&stardis->compute_surface.err_triangles))
+ {
+ unsigned prim
+ = darray_uint_cdata_get(&stardis->compute_surface.err_triangles)[j];
+ ASSERT(prim <= tsz);
+ v[(unsigned)prim] = UCHAR_MAX;
+ }
+ } else {
+ unsigned descr[SG3D_PROP_TYPES_COUNT__];
+ struct sdis_medium* medium;
+ const struct description* descriptions;
+ unsigned medium_id;
+ ASSERT(stardis->mode & MODE_MEDIUM_COMPUTE);
+ medium = find_medium_by_name(stardis, &stardis->solve_name, &medium_id);
+ ASSERT(medium != NULL); (void)medium;
+ descriptions = darray_descriptions_cdata_get(&stardis->descriptions);
+ FOR_EACH(i, 0, tsz) {
+ unsigned f_mid, b_mid;
+ /* Get the description IDs for this triangle */
+ ERR(sg3d_geometry_get_unique_triangle_properties(stardis->geometry.sg3d,
+ i, descr));
+ /* For triangles in compute volume,
+ * v==1 if FRONT, v==2 for BACK */
+ if(descr[SG3D_FRONT] == SG3D_UNSPECIFIED_PROPERTY)
+ f_mid = UINT_MAX;
+ else description_get_medium_id(descriptions + descr[SG3D_FRONT], &f_mid);
+ if(descr[SG3D_BACK] == SG3D_UNSPECIFIED_PROPERTY)
+ b_mid = UINT_MAX;
+ else description_get_medium_id(descriptions + descr[SG3D_BACK], &b_mid);
+ if(f_mid == medium_id && b_mid == medium_id)
+ ; /* Keep v==0, not really a boundary */
+ else if(f_mid == medium_id)
+ v[i] = 1;
+ else if(b_mid == medium_id)
+ v[i] = 2;
+ }
+ }
+
+ fprintf(stream, "SCALARS Compute_region unsigned_int 1\n");
+ fprintf(stream, "LOOKUP_TABLE default\n");
+ FOR_EACH(i, 0, tsz)
+ fprintf(stream, "%u\n", v[i] == UCHAR_MAX ? UINT_MAX : v[i]);
+
+exit:
+ MEM_RM(stardis->allocator, v);
+ return res;
+error:
+ goto exit;
+}
+
+res_T
+dump_model_as_c_chunks
+ (struct stardis* stardis,
+ FILE* stream)
+{
+ res_T res = RES_OK;
+ const char* prefix;
+ unsigned n, vcount, tcount;
+
+ ASSERT(stardis && stream);
+
+ prefix = str_cget(&stardis->chunks_prefix);
+ ERR(sg3d_geometry_get_unique_vertices_count(stardis->geometry.sg3d, &vcount));
+ ERR(sg3d_geometry_get_unique_triangles_count(stardis->geometry.sg3d, &tcount));
+
+ fprintf(stream, "#define %s_UNSPECIFIED_PROPERTY %u\n\n",
+ prefix, SG3D_UNSPECIFIED_PROPERTY);
+
+ fprintf(stream, "static const unsigned\n");
+ fprintf(stream, "%s_vertices_count = %u;\n\n", prefix, vcount);
+
+ fprintf(stream, "static const unsigned\n");
+ fprintf(stream, "%s_triangles_count = %u;\n\n", prefix, tcount);
+
+ fprintf(stream, "static const double\n");
+ fprintf(stream, "%s_vertices[%u][3] = {\n", prefix, vcount);
+ for(n = 0; n < vcount; n++) {
+ double vertex[3];
+ ERR(sg3d_geometry_get_unique_vertex(stardis->geometry.sg3d, n,
+ vertex));
+ fprintf(stream, " { %g, %g, %g }%c\n",
+ SPLIT3(vertex), (n == vcount - 1 ? ' ' : ','));
+ }
+ fprintf(stream, "};\n\n");
+
+ fprintf(stream, "static const unsigned\n");
+ fprintf(stream, "%s_triangles[%u][3] = {\n", prefix, tcount);
+ for(n = 0; n < tcount; n++) {
+ unsigned triangle[3];
+ ERR(sg3d_geometry_get_unique_triangle_vertices(stardis->geometry.sg3d, n,
+ triangle));
+ fprintf(stream, " { %u, %u, %u }%c\n",
+ SPLIT3(triangle), (n == tcount - 1 ? ' ' : ','));
+ }
+ fprintf(stream, "};\n\n");
+
+ fprintf(stream, "static const unsigned\n");
+ fprintf(stream, "%s_properties[%u][3] = {\n", prefix, tcount);
+ for(n = 0; n < tcount; n++) {
+ unsigned properties[SG3D_PROP_TYPES_COUNT__];
+ ERR(sg3d_geometry_get_unique_triangle_properties(stardis->geometry.sg3d, n,
+ properties));
+ if(properties[0] == SG3D_UNSPECIFIED_PROPERTY)
+ fprintf(stream, " { %s_UNSPECIFIED_PROPERTY, ", prefix);
+ else fprintf(stream, " { %u, ", properties[0]);
+ if(properties[1] == SG3D_UNSPECIFIED_PROPERTY)
+ fprintf(stream, "%s_UNSPECIFIED_PROPERTY, ", prefix);
+ else fprintf(stream, "%u, ", properties[1]);
+ if(properties[2] == SG3D_UNSPECIFIED_PROPERTY)
+ fprintf(stream, "%s_UNSPECIFIED_PROPERTY }", prefix);
+ else fprintf(stream, "%u }", properties[2]);
+ if(n == tcount - 1) fprintf(stream, "\n"); else fprintf(stream, ",\n");
+ }
+ fprintf(stream, "};\n\n");
+
+exit:
+ return res;
+error:
+ goto exit;
+}
diff --git a/src/stardis-output.h b/src/stardis-output.h
@@ -0,0 +1,110 @@
+/* Copyright (C) 2018-2020 |Meso|Star> (contact@meso-star.com)
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+#ifndef SDIS_OUTPUT_H
+#define SDIS_OUTPUT_H
+
+#include <rsys/rsys.h>
+#include <stdio.h>
+
+struct sdis_green_path;
+struct sdis_heat_path;
+struct sdis_estimator_buffer;
+struct sdis_green_function;
+struct counts;
+struct description;
+struct mem_allocator;
+struct sdis_estimator;
+struct stardis;
+struct geometry;
+struct vertex;
+struct darray_estimators;
+
+struct dump_path_context {
+ unsigned long rank;
+ struct stardis* stardis;
+};
+
+extern res_T
+dump_path
+ (const struct sdis_heat_path* path,
+ void* context);
+
+extern res_T
+print_sample
+ (struct sdis_green_path* path,
+ void* ctx);
+
+extern res_T
+dump_vtk_image
+ (const struct sdis_estimator_buffer* buf,
+ FILE* stream);
+
+extern res_T
+dump_ht_image
+ (const struct sdis_estimator_buffer* buf,
+ FILE* stream);
+
+extern res_T
+dump_green_ascii
+ (struct sdis_green_function* green,
+ const struct stardis* stardis,
+ FILE* stream);
+
+extern res_T
+dump_green_bin
+ (struct sdis_green_function* green,
+ const struct stardis* stardis,
+ FILE* stream);
+
+extern res_T
+dump_paths_end
+ (struct sdis_green_function* green,
+ const struct stardis* stardis,
+ FILE* stream);
+
+extern res_T
+dump_enclosure_related_stuff_at_the_end_of_vtk
+ (struct stardis* stardis,
+ FILE* stream);
+
+extern res_T
+print_single_MC_result
+ (struct sdis_estimator* estimator,
+ struct stardis* stardis,
+ FILE* stream);
+
+extern void
+dump_map
+ (const struct stardis* stardis,
+ const struct darray_estimators* estimators,
+ FILE* stream);
+
+extern res_T
+dump_boundaries_at_the_end_of_vtk
+ (const struct stardis* stardis,
+ FILE* stream);
+
+extern res_T
+dump_compute_region_at_the_end_of_vtk
+ (struct stardis* stardis,
+ FILE* stream);
+
+extern res_T
+dump_model_as_c_chunks
+ (struct stardis* stardis,
+ FILE* stream);
+
+#endif
diff --git a/src/stardis-parsing.c b/src/stardis-parsing.c
@@ -0,0 +1,1820 @@
+/* Copyright (C) 2018-2020 |Meso|Star> (contact@meso-star.com)
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+#define _POSIX_C_SOURCE 200809L /* strdup */
+#include "stardis-parsing.h"
+#include "stardis-app.h"
+#include "stardis-default.h"
+#include "stardis-version.h"
+
+#include <rsys/cstr.h>
+#include <rsys/double2.h>
+#include <rsys/double3.h>
+#include <sdis_version.h>
+#include <rsys/logger.h>
+
+#include <getopt.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <ctype.h>
+#include <string.h>
+
+/*******************************************************************************
+ * Local Functions
+ ******************************************************************************/
+
+#ifdef COMPILER_GCC
+static char*
+_strupr
+ (char* s)
+{
+ char* ptr;
+ for(ptr = s; *ptr; ++ptr) {
+ int tmp = toupper(*ptr);
+ ASSERT(tmp == (char)tmp);
+ *ptr = (char)tmp;
+ }
+ return s;
+}
+#endif
+
+static char**
+split_line
+ (char* a_str,
+ const char a_delim)
+{
+ char** result = 0;
+ size_t chunks_count;
+ char* tmp = a_str;
+ char delim[2];
+ char* tok_ctx = NULL;
+
+ ASSERT(a_str);
+
+ delim[0] = a_delim;
+ delim[1] = 0;
+
+ /* if a_str starts with initial useless delimiters remove them */
+ while(*a_str == a_delim) a_str++;
+
+ /* if a_str ends with final useless delimiters remove them */
+ tmp = a_str + strlen(a_str) - 1;
+ while(*tmp == a_delim && tmp >= a_str) { *tmp = '\0'; tmp--; }
+
+ if(tmp >= a_str) chunks_count = 1;
+ else return NULL;
+
+ tmp = a_str;
+ while(*tmp) {
+ int delim_found = 0;
+ while(*tmp == a_delim) { delim_found = 1; tmp++; }
+ if(delim_found) chunks_count++;
+ tmp++;
+ }
+
+ /* Add space for terminating null string so caller
+ knows where the list of returned strings ends. */
+ result = malloc(sizeof(char*) * (1 + chunks_count));
+ if(result) {
+ size_t idx = 0;
+ char* token = strtok_r(a_str, delim, &tok_ctx);
+
+ while(token) {
+ ASSERT(idx <= chunks_count);
+#ifdef COMPILER_CL
+ *(result + idx++) = _strdup(token);
+#else
+ *(result + idx++) = strdup(token);
+#endif
+ token = strtok_r(NULL, delim, &tok_ctx);
+ }
+ ASSERT(idx == chunks_count);
+ *(result + idx) = 0;
+ }
+ return result;
+}
+
+void
+print_version
+ (FILE* stream)
+{
+ ASSERT(stream);
+ fprintf(stream,
+ "Stardis version %i.%i.%i built on stardis solver version %i.%i.%i\n",
+ STARDIS_APP_VERSION_MAJOR, STARDIS_APP_VERSION_MINOR, STARDIS_APP_VERSION_PATCH,
+ Stardis_VERSION_MAJOR, Stardis_VERSION_MINOR, Stardis_VERSION_PATCH);
+}
+
+void
+add_geom_ctx_indices
+ (const unsigned itri,
+ unsigned ids[3],
+ void* context)
+{
+ const struct add_geom_ctx* ctx = context;
+ const unsigned* trg;
+ int i;
+ ASSERT(ids && ctx);
+ ASSERT(itri < ctx->stl_desc.triangles_count);
+ trg = ctx->stl_desc.indices + 3 * itri;
+ for(i = 0; i < 3; i++) ids[i] = trg[i];
+}
+
+void
+add_geom_ctx_properties
+ (const unsigned itri,
+ unsigned prop[3],
+ void* context)
+{
+ const struct add_geom_ctx* ctx = context;
+ int i;
+ ASSERT(prop && ctx); (void)itri;
+ ASSERT(itri < ctx->stl_desc.triangles_count);
+ /* Same media for the whole add_geometry set of triangles */
+ for(i = 0; i < SG3D_PROP_TYPES_COUNT__; i++) prop[i] = ctx->properties[i];
+}
+
+void
+add_geom_ctx_position
+ (const unsigned ivert,
+ double pos[3],
+ void* context)
+{
+ const struct add_geom_ctx* ctx = context;
+ const float* v;
+ ASSERT(pos && ctx);
+ ASSERT(ivert < ctx->stl_desc.vertices_count);
+ v = ctx->stl_desc.vertices + 3 * ivert;
+ d3_set_f3(pos, v);
+}
+
+static res_T
+add_geom_keep_degenerated
+ (const unsigned itri,
+ void* context,
+ int* abort)
+{
+ const struct add_geom_ctx* ctx = context;
+ struct darray_uint* degenerated;
+
+ ASSERT(abort && ctx && ctx->custom); (void)abort;
+ ASSERT(itri < ctx->stl_desc.triangles_count);
+ degenerated = ctx->custom;
+ return darray_uint_push_back(degenerated, &itri);
+}
+
+static res_T
+read_sides_and_files
+ (struct stardis* stardis,
+ const int descr_is_intface, /* if 1, don't read side */
+ const unsigned description_id,
+ char** tok_ctx)
+{
+ char* tk = NULL;
+ int file_count = 0;
+ struct sstl* sstl = NULL;
+ struct add_geom_ctx add_geom_ctx;
+ unsigned current_merge_errors;
+ struct sg3d_geometry_add_callbacks callbacks = SG3D_ADD_CALLBACKS_NULL__;
+ struct darray_uint degenerated;
+ struct str str;
+ res_T res = RES_OK;
+
+ ASSERT(stardis && tok_ctx);
+
+ darray_uint_init(stardis->allocator, °enerated);
+ str_init(stardis->allocator, &str);
+ callbacks.get_indices = add_geom_ctx_indices;
+ callbacks.get_properties = add_geom_ctx_properties;
+ callbacks.get_position = add_geom_ctx_position;
+ callbacks.degenerated_triangle = add_geom_keep_degenerated;
+ add_geom_ctx.custom = °enerated;
+
+ ERR(sg3d_geometry_get_unique_triangles_with_merge_conflict_count(
+ stardis->geometry.sg3d, ¤t_merge_errors));
+
+ /* At least one side+name, no side without name */
+ ERR(sstl_create(stardis->logger, stardis->allocator, 1, &sstl));
+ for(;;) {
+ unsigned merge_errors;
+ if(descr_is_intface) {
+ add_geom_ctx.properties[SG3D_FRONT] = SG3D_UNSPECIFIED_PROPERTY;
+ add_geom_ctx.properties[SG3D_BACK] = SG3D_UNSPECIFIED_PROPERTY;
+ add_geom_ctx.properties[SG3D_INTFACE] = description_id;
+ } else {
+ tk = strtok_r(NULL, " \t", tok_ctx);
+ if(!tk) {
+ if(file_count == 0) {
+ /* At least 1 side */
+ logger_print(stardis->logger, LOG_ERROR,
+ "Invalid data (missing token 'side')\n");
+ res = RES_BAD_ARG;
+ goto error;
+ }
+ else break;
+ }
+ _strupr(tk);
+ add_geom_ctx.properties[SG3D_INTFACE] = SG3D_UNSPECIFIED_PROPERTY;
+ if(0 == strcmp(tk, "FRONT")) {
+ add_geom_ctx.properties[SG3D_FRONT] = description_id;
+ add_geom_ctx.properties[SG3D_BACK] = SG3D_UNSPECIFIED_PROPERTY;
+ }
+ else if(0 == strcmp(tk, "BACK")) {
+ add_geom_ctx.properties[SG3D_FRONT] = SG3D_UNSPECIFIED_PROPERTY;
+ add_geom_ctx.properties[SG3D_BACK] = description_id;
+ }
+ else if(0 == strcmp(tk, "BOTH")) {
+ add_geom_ctx.properties[SG3D_FRONT] = description_id;
+ add_geom_ctx.properties[SG3D_BACK] = description_id;
+ }
+ else {
+ logger_print(stardis->logger, LOG_ERROR,
+ "Invalid side specifier: %s\n", tk);
+ res = RES_BAD_ARG;
+ goto error;
+ }
+ }
+ tk = strtok_r(NULL, " \t", tok_ctx);
+ if(!tk) {
+ if(!descr_is_intface /* Has read a side */
+ || !file_count) /* Need at least 1 file */
+ {
+ logger_print(stardis->logger, LOG_ERROR,
+ "Invalid data (missing token 'file name')\n");
+ res = RES_BAD_ARG;
+ goto error;
+ }
+ else break;
+ }
+ file_count++;
+ res = sstl_load(sstl, tk);
+ if(res != RES_OK) {
+ logger_print(stardis->logger, LOG_ERROR,
+ "Cannot read STL file: '%s'\n", tk);
+ goto error;
+ }
+ ERR(sstl_get_desc(sstl, &add_geom_ctx.stl_desc));
+ ASSERT(add_geom_ctx.stl_desc.vertices_count <= UINT_MAX
+ && add_geom_ctx.stl_desc.triangles_count <= UINT_MAX);
+
+ res = sg3d_geometry_add(
+ stardis->geometry.sg3d,
+ (unsigned)add_geom_ctx.stl_desc.vertices_count,
+ (unsigned)add_geom_ctx.stl_desc.triangles_count,
+ &callbacks,
+ &add_geom_ctx);
+ if(darray_uint_size_get(°enerated)) {
+ size_t c, n;
+ const unsigned* ids = darray_uint_cdata_get(°enerated);
+ c = darray_uint_size_get(°enerated);
+ ASSERT(c <= ULONG_MAX);
+ logger_print(stardis->logger, LOG_WARNING,
+ "File '%s' included %lu degenerated triangles (removed)\n",
+ tk, (unsigned long)c);
+ ERR(str_printf(&str, "Degenerated triangles IDs: %u", ids[0]));
+ FOR_EACH(n, 1, c) { STR_APPEND_PRINTF(&str, ", %u", ARG1( ids[n] ) ); }
+ logger_print(stardis->logger, LOG_OUTPUT, "%s\n", str_cget(&str));
+ darray_uint_clear(°enerated);
+ }
+
+ if(res != RES_OK) {
+ logger_print(stardis->logger, LOG_ERROR,
+ "Cannot add file content: '%s'\n", tk);
+ goto error;
+ }
+ /* Check conflicts */
+ ERR(sg3d_geometry_get_unique_triangles_with_merge_conflict_count(
+ stardis->geometry.sg3d, &merge_errors));
+ if(current_merge_errors != merge_errors) {
+ int is_for_compute =
+ (stardis->mode & COMPUTE_MODES) && !(stardis->mode & MODE_DUMP_VTK);
+ logger_print(stardis->logger, (is_for_compute ? LOG_ERROR : LOG_WARNING),
+ "Merge conflicts found reading file '%s' (%u triangles).\n",
+ tk, merge_errors - current_merge_errors);
+ if(is_for_compute) {
+ res = RES_BAD_ARG;
+ goto error;
+ }
+ }
+ current_merge_errors = merge_errors;
+ }
+
+end:
+ darray_uint_release(°enerated);
+ str_release(&str);
+ if(sstl) SSTL(ref_put(sstl));
+ return res;
+error:
+ goto end;
+}
+
+/*******************************************************************************
+ * Public Functions
+ ******************************************************************************/
+
+res_T
+init_args
+ (struct logger* logger,
+ struct mem_allocator* allocator,
+ struct args** out_args)
+{
+ res_T res = RES_OK;
+ struct args* args = NULL;
+ ASSERT(logger && allocator && out_args);
+
+ args = calloc(sizeof(struct args), 1);
+ if(!args) {
+ res = RES_MEM_ERR;
+ goto error;
+ }
+
+ args->logger = logger;
+ args->allocator = allocator;
+ darray_str_init(allocator, &args->model_files);
+ /* Set default values */
+ args->samples = STARDIS_DEFAULT_SAMPLES_COUNT;
+ args->nthreads = SDIS_NTHREADS_DEFAULT;
+ d2(args->pos_and_time+3, STARDIS_DEFAULT_COMPUTE_TIME);
+ args->ambient_temp = STARDIS_DEFAULT_AMBIENT_TEMP;
+ args->ref_temp = STARDIS_DEFAULT_REFERENCE_TEMP;
+ args->verbose = STARDIS_DEFAULT_VERBOSE_LEVEL;
+
+end:
+ *out_args = args;
+ return res;
+error:
+ if(args) release_args(args);
+ args = NULL;
+ goto end;
+}
+
+void
+release_args(struct args* args)
+{
+ ASSERT(args);
+ darray_str_release(&args->model_files);
+ free(args);
+}
+
+char
+mode_option
+ (const int m)
+{
+ int found = 0;
+ char res = '?';
+ if(m & MODE_DUMP_C_CHUNKS) { found++; res = 'c'; }
+ if(m & MODE_DUMP_VTK) { found++; res = 'd'; }
+ if(m & MODE_DUMP_PATHS) { found++; res = 'D'; }
+ if(m & MODE_EXTENDED_RESULTS) { found++; res = 'e'; }
+ if(m & MODE_FLUX_BOUNDARY_COMPUTE) { found++; res = 'F'; }
+ 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_MEDIUM_COMPUTE) { found++; res = 'm'; }
+ if(m & MODE_PROBE_COMPUTE) { found++; res = 'p'; }
+ if(m & MODE_PROBE_COMPUTE_ON_INTERFACE) { found++; res = 'P'; }
+ if(m & MODE_IR_COMPUTE) { found++; res = 'R'; }
+ if(m & MODE_BOUNDARY_COMPUTE) { found++; res = 's'; }
+ if(m & MODE_MAP_COMPUTE) { found++; res = 'S'; }
+ if(m & MODE_VERBOSITY) { found++; res = 'V'; }
+ if(m & MODE_DUMP_VERSION) { found++; res = 'v'; }
+ ASSERT(found == 1);
+ return res;
+}
+
+void
+print_multiple_modes
+ (char* buf,
+ const size_t sz,
+ const int modes,
+ const int dont) /* Modes in dont are not printed */
+{
+ int b = 0, fst = 1;
+ int m = UNDEF_MODE;
+ size_t left = sz;
+ ASSERT(buf);
+ do {
+ m = BIT(b++);
+ if(m & dont) continue;
+ if(m & modes) {
+ size_t n =
+ (size_t)snprintf(buf, left, (fst ? "-%c" : ", -%c"), mode_option(m));
+ if(n >= left) FATAL("Buffer is too small.");
+ left -= n;
+ buf += n;
+ fst = 0;
+ }
+ } while(m < modes);
+}
+
+void
+short_help
+ (FILE* stream,
+ const char* prog)
+{
+ const char* name;
+ ASSERT(stream && prog);
+
+#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 -a AMBIENT_TEMP\n");
+ fprintf(stream, " Set the ambient radiative temperature.\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\n");
+ fprintf(stream, " Dump the geometry to stdout in VTK format along with various properties.\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 -r REFERENCE_TEMP\n");
+ fprintf(stream, " Set the temperature used for the linearization of the 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");
+}
+
+/* Workaround for a gcc warning when GET_OPTIONAL_TIME_RANGE used with Rank=0 */
+FINLINE int is_less(size_t a, size_t b) { return a < b; }
+
+/* Get a time range from a coma-separated list of doubles
+ * The first Rank values are mandatory, followed by an optional time range
+ * that can be a single time */
+#define GET_OPTIONAL_TIME_RANGE(Src, Rank, Dst, Logger, OptionString, Option) \
+ res = cstr_to_list_double((Src), ',', (Dst), &len, (Rank)+2); \
+ if(res != RES_OK \
+ || is_less(len, (Rank)) \
+ || (len == (Rank)+1 && (Dst)[(Rank)] < 0) \
+ || (len == (Rank)+2 && ((Dst)[0] < 0 || (Dst)[(Rank)] > (Dst)[(Rank)+1])) \
+ || len > (Rank)+2) \
+ { \
+ if(res == RES_OK) res = RES_BAD_ARG; \
+ logger_print((Logger), LOG_ERROR, \
+ "Invalid argument for option "OptionString": %s\n", \
+ (Option), (Src)); \
+ goto error; \
+ } else { \
+ if(len == (Rank)+1) (Dst)[(Rank)+1] = (Dst)[(Rank)];\
+ }
+
+ /* Get a string followed by an optional time range */
+#define GET_STR_AND_OPTIONAL_TIME_RANGE(Str, Time) \
+ ptr = strchr(optarg, ','); /* First ',' */ \
+ if(ptr) { /* Time range provided */ \
+ GET_OPTIONAL_TIME_RANGE(ptr+1, 0, (Time), args->logger, "-%c", opt); \
+ *ptr = '\0'; \
+ } \
+ (Str) = optarg;
+
+/* Get a position followed by an optional time range */
+#define GET_POS_AND_OPTIONAL_TIME_RANGE(Dst) \
+ GET_OPTIONAL_TIME_RANGE(optarg, 3, (Dst), args->logger, "-%c", opt);
+
+res_T
+parse_args
+ (const int argc,
+ char** argv,
+ struct args* args)
+{
+ int opt = 0, n_used = 0;
+ size_t len = 0;
+ const char option_list[] = "a:c:dD:eF:gG:hm:M:n:p:P:r:R:s:S:t:vV:";
+ char buf[128];
+ res_T res = RES_OK;
+
+ ASSERT(argv && args);
+
+ opterr = 0; /* No default error messages */
+ while((opt = getopt(argc, argv, option_list)) != -1) {
+ switch (opt) {
+
+ case '?': /* Unreconised option */
+ {
+ char* ptr = strchr(option_list, optopt);
+ res = RES_BAD_ARG;
+ if(ptr && ptr[1] == ':') {
+ logger_print(args->logger, LOG_ERROR,
+ "Missing argument for option -%c\n",
+ optopt);
+ } else {
+ logger_print(args->logger, LOG_ERROR, "Invalid option -%c\n", optopt);
+ }
+ goto error;
+ }
+
+ case 'a':
+ res = cstr_to_double(optarg, &args->ambient_temp);
+ if(res != RES_OK
+ || args->ambient_temp < 0)
+ {
+ if(res == RES_OK) res = RES_BAD_ARG;
+ logger_print(args->logger, LOG_ERROR,
+ "Invalid argument for option -%c: %s\n",
+ opt, optarg);
+ goto error;
+ }
+ break;
+
+ case 'c':
+ if(args->mode & USE_STDOUT_MODES) {
+ res = RES_BAD_ARG;
+ print_multiple_modes(buf, sizeof(buf), USE_STDOUT_MODES, MODE_DUMP_C_CHUNKS);
+ logger_print(args->logger, LOG_ERROR,
+ "Option -%c cannot be used in conjunction with other dump options (%s).\n",
+ (char)opt, buf);
+ goto error;
+ }
+ args->chunks_prefix = optarg;
+ args->mode |= MODE_DUMP_C_CHUNKS;
+ break;
+
+ case 'd':
+ if(args->mode & USE_STDOUT_MODES) {
+ res = RES_BAD_ARG;
+ print_multiple_modes(buf, sizeof(buf), USE_STDOUT_MODES, MODE_DUMP_VTK);
+ logger_print(args->logger, LOG_ERROR,
+ "Option -%c cannot be used in conjunction with other dump options (%s).\n",
+ (char)opt, buf);
+ goto error;
+ }
+ args->mode |= MODE_DUMP_VTK;
+ break;
+
+ case 'D': {
+ char* ptr = strrchr(optarg, ',');
+ if(!ptr || ptr != strchr(optarg, ','))
+ res = RES_BAD_ARG; /* Single ',' expected */
+ else {
+ args->paths_filename = ptr + 1;
+ *ptr = '\0';
+ }
+ if(res == RES_OK) {
+ if(0 == strcmp(optarg, "all")) {
+ args->dump_paths = DUMP_ALL;
+ }
+ else if(0 == strcmp(optarg, "error")) {
+ args->dump_paths = DUMP_ERROR;
+ }
+ else if(0 == strcmp(optarg, "success")) {
+ args->dump_paths = DUMP_SUCCESS;
+ }
+ }
+ if(res != RES_OK) {
+ res = RES_BAD_ARG;
+ logger_print(args->logger, LOG_ERROR,
+ "Invalid argument for option -%c: %s\n",
+ opt, optarg);
+ goto error;
+ }
+ args->mode |= MODE_DUMP_PATHS;
+ break;
+ }
+
+ case 'e':
+ args->mode |= MODE_EXTENDED_RESULTS;
+ break;
+
+ /*case 'F': see 's' */
+
+ case 'g':
+ if(args->mode & MODE_BIN_GREEN) {
+ res = RES_BAD_ARG;
+ logger_print(args->logger, LOG_ERROR,
+ "Options -%c and -%c are exclusive.\n",
+ (char)opt, mode_option(MODE_BIN_GREEN));
+ goto error;
+ }
+ args->mode |= MODE_GREEN;
+ break;
+
+ case 'G': {
+ char* ptr = strrchr(optarg, ',');
+ if(ptr && ptr != strchr(optarg, ','))
+ res = RES_BAD_ARG; /* Expecting 1 or 0 ',' */
+ if(args->mode & (MODE_BIN_GREEN | MODE_GREEN)) {
+ res = RES_BAD_ARG;
+ if(args->mode & MODE_BIN_GREEN)
+ logger_print(args->logger, LOG_ERROR,
+ "Option -%c cannot be used twice.\n",
+ (char)opt);
+ else
+ logger_print(args->logger, LOG_ERROR,
+ "Options -%c and -%c are exclusive.\n",
+ (char)opt, mode_option(MODE_GREEN));
+ goto error;
+ }
+ args->mode |= MODE_BIN_GREEN;
+ if(ptr) {
+ args->end_paths_filename = ptr + 1;
+ *ptr = '\0';
+ }
+ args->bin_green_filename = optarg;
+ break;
+ }
+
+ case 'h':
+ if(args->mode & USE_STDOUT_MODES) {
+ res = RES_BAD_ARG;
+ print_multiple_modes(buf, sizeof(buf), USE_STDOUT_MODES, MODE_DUMP_HELP);
+ logger_print(args->logger, LOG_ERROR,
+ "Option -%c cannot be used in conjunction with other dump options (%s).\n",
+ (char)opt, buf);
+ goto error;
+ }
+ args->mode |= MODE_DUMP_HELP;
+ break;
+
+ case 'm': {
+ char* ptr;
+ 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_MEDIUM_COMPUTE;
+ GET_STR_AND_OPTIONAL_TIME_RANGE(args->medium_name, args->pos_and_time + 3);
+ break;
+ }
+
+ case 'M': {
+ struct str name;
+ str_init(args->allocator, &name);
+ ERR(str_set(&name, optarg));
+ ERR(darray_str_push_back(&args->model_files, &name));
+ str_release(&name);
+ break;
+ }
+ case 'n': {
+ unsigned long n;
+ res = cstr_to_ulong(optarg, &n);
+ if(res != RES_OK
+ || n == 0)
+ {
+ if(res == RES_OK) res = RES_BAD_ARG;
+ logger_print(args->logger, LOG_ERROR,
+ "Invalid argument for option -%c: %s\n",
+ opt, optarg);
+ goto error;
+ }
+ args->samples = n;
+ n_used = 1;
+ break;
+ }
+
+ case 'p':
+ 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;
+ GET_POS_AND_OPTIONAL_TIME_RANGE(args->pos_and_time);
+ break;
+
+ case 'P':
+ 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;
+ GET_POS_AND_OPTIONAL_TIME_RANGE(args->pos_and_time);
+ break;
+
+ case 'r':
+ res = cstr_to_double(optarg, &args->ref_temp);
+ if(res != RES_OK
+ || args->ref_temp < 0)
+ {
+ if(res == RES_OK) res = RES_BAD_ARG;
+ logger_print(args->logger, LOG_ERROR,
+ "Invalid argument for option -%c: %s\n",
+ opt, optarg);
+ goto error;
+ }
+ break;
+
+ case 'R':
+ 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_IR_COMPUTE;
+ args->camera = optarg;
+ break;
+
+ case 's':
+ case 'S':
+ case 'F': {
+ char *ptr;
+ 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;
+ }
+ switch (opt) {
+ case 's':
+ args->mode |= MODE_BOUNDARY_COMPUTE;
+ break;
+ case 'S':
+ args->mode |= MODE_MAP_COMPUTE;
+ break;
+ case 'F':
+ args->mode |= MODE_FLUX_BOUNDARY_COMPUTE;
+ break;
+ }
+ GET_STR_AND_OPTIONAL_TIME_RANGE(args->solve_filename, args->pos_and_time + 3);
+ break;
+ }
+
+ case 't':
+ res = cstr_to_uint(optarg, &args->nthreads);
+ if(res != RES_OK
+ || args->nthreads <= 0)
+ {
+ if(res == RES_OK) res = RES_BAD_ARG;
+ logger_print(args->logger, LOG_ERROR,
+ "Invalid argument for option -%c: %s\n",
+ opt, optarg);
+ goto error;
+ }
+ break;
+
+ case 'v':
+ if(args->mode & USE_STDOUT_MODES) {
+ res = RES_BAD_ARG;
+ print_multiple_modes(buf, sizeof(buf), USE_STDOUT_MODES, MODE_DUMP_VERSION);
+ logger_print(args->logger, LOG_ERROR,
+ "Option -%c cannot be used in conjunction with other dump options (%s).\n",
+ (char)opt, buf);
+ goto error;
+ }
+ args->mode |= MODE_DUMP_VERSION;
+ break;
+
+ case 'V':
+ res = cstr_to_int(optarg, &args->verbose);
+ if(res != RES_OK
+ || args->verbose < 0
+ || args->verbose > 3)
+ {
+ if(res == RES_OK) res = RES_BAD_ARG;
+ logger_print(args->logger, LOG_ERROR,
+ "Invalid argument for option -%c: %s\n",
+ opt, optarg);
+ goto error;
+ }
+ break;
+ }
+ }
+
+ if(argc > optind) {
+ int i;
+ for(i = optind; i < argc; i++) {
+ logger_print(args->logger, LOG_ERROR, "Unexpected argument: %s.\n", argv[i]);
+ }
+ res = RES_BAD_ARG;
+ goto error;
+ }
+
+ if(!darray_str_size_get(&args->model_files)
+ && !(args->mode & SHORT_EXIT_MODES)) {
+ logger_print(args->logger, LOG_ERROR,
+ "Missing mandatory argument: -M <model_file_name>\n");
+ res = RES_BAD_ARG;
+ goto error;
+ }
+
+ if(args->mode == UNDEF_MODE) {
+ print_multiple_modes(buf, sizeof(buf), EXCLUSIVE_MODES | USE_STDOUT_MODES, 0);
+ logger_print(args->logger, LOG_WARNING,
+ "Nothing to do.\nOne of the following options should be used: %s\n",
+ buf);
+ res = RES_BAD_ARG;
+ goto error;
+ }
+
+ if(args->mode & (MODE_BIN_GREEN | MODE_GREEN)
+ && !(args->mode & GREEN_COMPATIBLE_MODES))
+ {
+ print_multiple_modes(buf, sizeof(buf), GREEN_COMPATIBLE_MODES, 0);
+ logger_print(args->logger, LOG_ERROR,
+ "Option -%c can only be used in conjunction with: %s\n",
+ mode_option(args->mode & (MODE_BIN_GREEN | MODE_GREEN)), buf);
+ res = RES_BAD_ARG;
+ goto error;
+ }
+
+ if(args->mode & MODE_IR_COMPUTE && n_used) {
+ logger_print(args->logger, LOG_ERROR,
+ "The -n option has no effect in rendering mode;"
+ " use rendering's SPP suboption instead.\n");
+ res = RES_BAD_ARG;
+ goto error;
+ }
+
+ if(args->mode & MODE_DUMP_PATHS) {
+ if(!(args->mode & COMPUTE_MODES)) {
+ res = RES_BAD_ARG;
+ print_multiple_modes(buf, sizeof(buf), COMPUTE_MODES, 0);
+ logger_print(args->logger, LOG_ERROR,
+ "Option -%c can only be used in conjunction with an option"
+ " that samples heat paths (%s).\n",
+ mode_option(MODE_DUMP_PATHS), buf);
+ goto error;
+ }
+ if(args->mode & (MODE_BIN_GREEN | MODE_GREEN)) {
+ res = RES_BAD_ARG;
+ logger_print(args->logger, LOG_ERROR,
+ "Option -%c cannot be used in conjunction with -%c nor -%c.\n",
+ mode_option(MODE_DUMP_PATHS), mode_option(MODE_GREEN)
+ , mode_option(MODE_BIN_GREEN));
+ goto error;
+ }
+ }
+
+ if(args->mode & MODE_EXTENDED_RESULTS) {
+ if(!(args->mode & EXT_COMPATIBLE_MODES)) {
+ res = RES_BAD_ARG;
+ print_multiple_modes(buf, sizeof(buf), EXT_COMPATIBLE_MODES, 0);
+ logger_print(args->logger, LOG_ERROR,
+ "Option -%c can only be used in conjunction with an option"
+ " that computes a single Monte-Carlo (%s).\n",
+ mode_option(MODE_EXTENDED_RESULTS), buf);
+ goto error;
+ }
+ if(args->mode & (MODE_BIN_GREEN | MODE_GREEN)) {
+ res = RES_BAD_ARG;
+ logger_print(args->logger, LOG_ERROR,
+ "Option -%c cannot be used in conjunction with -%c nor -%c.\n",
+ mode_option(MODE_EXTENDED_RESULTS), mode_option(MODE_GREEN)
+ , mode_option(MODE_BIN_GREEN));
+ goto error;
+ }
+ }
+
+end:
+ return res;
+error:
+ logger_print(args->logger, LOG_ERROR, "Use option -h to print help.\n");
+ goto end;
+}
+
+res_T
+parse_camera
+ (struct logger* logger,
+ char* cam_param,
+ struct stardis* stardis)
+{
+ char** line = NULL;
+ char** opt = NULL;
+ struct camera* cam;
+ res_T res = RES_OK;
+
+ ASSERT(cam_param && stardis);
+ cam = &stardis->camera;
+ line = split_line(cam_param, ':');
+
+ if(line) {
+ struct str keep;
+ int i = 0;
+ str_init(stardis->allocator, &keep);
+ for(i = 0; *(line + i); i++) {
+ size_t len = 0;
+ str_set(&keep, line[i]);
+ opt = split_line(line[i], '=');
+ if(!opt[0] || ! opt[1] || opt[2]) {
+ if(res == RES_OK) res = RES_BAD_ARG;
+ logger_print((logger), LOG_ERROR,
+ "Invalid option syntax: %s\n", str_cget(&keep));
+ goto error;
+ }
+ str_set(&keep, opt[0]);
+ _strupr(opt[0]);
+ if(strcmp(opt[0], "T") == 0) {
+ GET_OPTIONAL_TIME_RANGE(opt[1], 0, cam->time_range, logger, "%s",
+ str_cget(&keep));
+ }
+ else if(strcmp(opt[0], "FMT") == 0) {
+ _strupr(opt[1]);
+ if(strcmp(opt[1], "VTK") == 0)
+ cam->fmt = STARDIS_RENDERING_OUTPUT_FILE_FMT_VTK;
+ else if(strcmp(opt[1], "HT") == 0)
+ cam->fmt = STARDIS_RENDERING_OUTPUT_FILE_FMT_HT;
+ else {
+ logger_print(logger, LOG_ERROR,
+ "Unexpected value for rendering option %s: %s.\n",
+ opt[0], opt[1]);
+ res = RES_BAD_ARG;
+ goto error;
+ }
+ }
+ else if(strcmp(opt[0], "FOV") == 0) {
+ ERR(cstr_to_double(opt[1], &cam->fov));
+ }
+ else if(strcmp(opt[0], "UP") == 0) {
+ ERR(cstr_to_list_double(opt[1], ',', cam->up, &len, 3));
+ }
+ else if(strcmp(opt[0], "TGT") == 0) {
+ ERR(cstr_to_list_double(opt[1], ',', cam->tgt, &len, 3));
+ cam->auto_look_at = 0;
+ }
+ else if(strcmp(opt[0], "POS") == 0) {
+ ERR(cstr_to_list_double(opt[1], ',', cam->pos, &len, 3));
+ cam->auto_look_at = 0;
+ }
+ else if(strcmp(opt[0], "IMG") == 0) {
+ unsigned img_sz[2];
+ ERR(cstr_to_list_uint(opt[1], 'x', img_sz, &len, 2));
+ cam->img_width = img_sz[0];
+ cam->img_height = img_sz[1];
+ }
+ else if(strcmp(opt[0], "SPP") == 0) {
+ ERR(cstr_to_uint(opt[1], &cam->spp));
+ } else {
+ logger_print(logger, LOG_ERROR,
+ "Unexpected option for rendering mode: %s.\n",
+ opt[0]);
+ res = RES_BAD_ARG;
+ goto error;
+ }
+ }
+ str_release(&keep);
+ }
+
+end:
+#define FREE_AARRAY(ARRAY) if(ARRAY) {\
+ int i = 0; \
+ for(i=0; *(ARRAY+i);i++){\
+ free(ARRAY[i]);\
+ }\
+ free(ARRAY);\
+}
+ FREE_AARRAY(line)
+ FREE_AARRAY(opt)
+#undef FREE_AARRAY
+
+ return res;
+error:
+ logger_print(logger, LOG_ERROR, "Error parsing camera options.\n");
+ logger_print(logger, LOG_ERROR, "Use the -h option to get help.\n");
+ goto end;
+}
+
+#undef GET_STR_AND_OPTIONAL_TIME_RANGE
+#undef GET_POS_AND_OPTIONAL_TIME_RANGE
+#undef GET_OPTIONAL_TIME_RANGE
+
+static struct description*
+find_description_by_name
+ (struct stardis* stardis,
+ const struct str* name,
+ size_t* out_id)
+{
+ size_t i;
+ ASSERT(stardis && name);
+
+ FOR_EACH(i, 0, darray_descriptions_size_get(&stardis->descriptions)) {
+ struct description* desc
+ = darray_descriptions_data_get(&stardis->descriptions) + i;
+ if(str_eq(name, get_description_name(desc))) {
+ if(out_id) *out_id = i;
+ return desc;
+ }
+ }
+ return NULL;
+}
+
+/* H_BOUNDARY_FOR_SOLID Name emissivity specular_fraction hc T_env STL_filenames
+ * H_BOUNDARY_FOR_FLUID Name emissivity specular_fraction hc T_env STL_filenames */
+static res_T
+process_h
+ (struct stardis* stardis,
+ struct dummies* dummies,
+ const enum description_type type,
+ char** tok_ctx)
+{
+ char* tk = NULL;
+ struct description* desc;
+ size_t sz;
+ res_T res = RES_OK;
+
+ ASSERT(stardis && tok_ctx);
+
+ stardis->counts.hbound_count++;
+
+ sz = darray_descriptions_size_get(&stardis->descriptions);
+ ERR(darray_descriptions_resize(&stardis->descriptions, sz+1));
+ desc = darray_descriptions_data_get(&stardis->descriptions) + sz;
+ init_h(stardis->allocator, &desc->d.h_boundary);
+
+ desc->type = type;
+
+ CHK_TOK(strtok_r(NULL, " \t", tok_ctx), "h boundary name");
+ ERR(str_set(&desc->d.h_boundary.name, tk));
+ if(find_description_by_name(stardis, &desc->d.h_boundary.name, NULL)
+ != desc)
+ {
+ logger_print(stardis->logger, LOG_ERROR,
+ "Name already used: %s\n", tk);
+ if(res == RES_OK) res = RES_BAD_ARG;
+ goto end;
+ }
+
+ CHK_TOK(strtok_r(NULL, " \t", tok_ctx), "emissivity");
+ res = cstr_to_double(tk, &desc->d.h_boundary.emissivity);
+ if(res != RES_OK
+ || desc->d.h_boundary.emissivity < 0
+ || desc->d.h_boundary.emissivity > 1)
+ {
+ logger_print(stardis->logger, LOG_ERROR, "Invalid emissivity: %s\n", tk);
+ if(res == RES_OK) res = RES_BAD_ARG;
+ goto end;
+ }
+ CHK_TOK(strtok_r(NULL, " \t", tok_ctx), "specular fraction");
+ res = cstr_to_double(tk, &desc->d.h_boundary.specular_fraction);
+ if(res != RES_OK
+ || desc->d.h_boundary.specular_fraction < 0
+ || desc->d.h_boundary.specular_fraction > 1)
+ {
+ logger_print(stardis->logger, LOG_ERROR,
+ "Invalid specular fraction: %s\n", tk);
+ if(res == RES_OK) res = RES_BAD_ARG;
+ goto end;
+ }
+ CHK_TOK(strtok_r(NULL, " \t", tok_ctx), "hc");
+ res = cstr_to_double(tk, &desc->d.h_boundary.hc);
+ if(res != RES_OK
+ || desc->d.h_boundary.hc < 0)
+ {
+ logger_print(stardis->logger, LOG_ERROR, "Invalid hc: %s\n", tk);
+ if(res == RES_OK) res = RES_BAD_ARG;
+ goto end;
+ }
+ CHK_TOK(strtok_r(NULL, " \t", tok_ctx), "temperature");
+ res = cstr_to_double(tk, &desc->d.h_boundary.imposed_temperature);
+ if(res != RES_OK
+ || desc->d.h_boundary.imposed_temperature < 0)
+ {
+ logger_print(stardis->logger, LOG_ERROR, "Invalid temperature: %s\n", tk);
+ if(res == RES_OK) res = RES_BAD_ARG;
+ goto end;
+ }
+
+ if(type == DESC_BOUND_H_FOR_FLUID)
+ desc->d.h_boundary.mat_id = get_dummy_solid_id(stardis, dummies);
+ else {
+ struct fluid fluid_props;
+ init_fluid(stardis->allocator, &fluid_props);
+ fluid_props.fluid_id = allocate_stardis_medium_id(stardis);
+ desc->d.h_boundary.mat_id = fluid_props.fluid_id;
+ ASSERT(sz <= UINT_MAX);
+ fluid_props.desc_id = (unsigned)sz;
+ fluid_props.imposed_temperature
+ = desc->d.h_boundary.imposed_temperature;
+ fluid_props.is_outside = 1;
+ fluid_props.is_green = stardis->mode & (MODE_BIN_GREEN | MODE_GREEN);
+ ERR(create_solver_fluid(stardis, &fluid_props));
+ logger_print(stardis->logger, LOG_OUTPUT,
+ "External fluid created: T=%g (it is medium %u)\n",
+ fluid_props.imposed_temperature,
+ fluid_props.fluid_id);
+ }
+
+ ASSERT(sz <= UINT_MAX);
+ ERR(read_sides_and_files(stardis, 1, (unsigned)sz, tok_ctx));
+
+end:
+ return res;
+error:
+ goto end;
+}
+
+/* T_BOUNDARY_FOR_SOLID Name T STL_filenames
+ * T_BOUNDARY_FOR_FLUID Name T emissivity specular_fraction hc STL_filenames */
+static res_T
+process_t
+ (struct stardis* stardis,
+ struct dummies* dummies,
+ const enum description_type type,
+ char** tok_ctx)
+{
+ char* tk = NULL;
+ struct description* desc;
+ size_t sz;
+ res_T res = RES_OK;
+
+ ASSERT(stardis && tok_ctx);
+
+ stardis->counts.tbound_count++;
+
+ sz = darray_descriptions_size_get(&stardis->descriptions);
+ ERR(darray_descriptions_resize(&stardis->descriptions, sz + 1));
+ desc = darray_descriptions_data_get(&stardis->descriptions) + sz;
+ init_t(stardis->allocator, &desc->d.t_boundary);
+
+ desc->type = type;
+ desc->d.t_boundary.mat_id = (type == DESC_BOUND_T_FOR_FLUID)
+ ? get_dummy_solid_id(stardis, dummies) : get_dummy_fluid_id(stardis, dummies);
+
+ CHK_TOK(strtok_r(NULL, " \t", tok_ctx), "temperature boundary name");
+ ERR(str_set(&desc->d.t_boundary.name, tk));
+ if(find_description_by_name(stardis, &desc->d.t_boundary.name, NULL)
+ != desc)
+ {
+ logger_print(stardis->logger, LOG_ERROR,
+ "Name already used: %s\n", tk);
+ if(res == RES_OK) res = RES_BAD_ARG;
+ goto end;
+ }
+
+ CHK_TOK(strtok_r(NULL, " \t", tok_ctx), "temperature");
+ res = cstr_to_double(tk, &desc->d.t_boundary.imposed_temperature);
+ if(res != RES_OK
+ || desc->d.t_boundary.imposed_temperature < 0)
+ {
+ logger_print(stardis->logger, LOG_ERROR, "Invalid temperature: %s\n", tk);
+ if(res == RES_OK) res = RES_BAD_ARG;
+ goto end;
+ }
+ if(type == DESC_BOUND_T_FOR_FLUID) {
+ CHK_TOK(strtok_r(NULL, " \t", tok_ctx), "emissivity");
+ res = cstr_to_double(tk, &desc->d.t_boundary.emissivity);
+ if(res != RES_OK
+ || desc->d.t_boundary.emissivity < 0
+ || desc->d.t_boundary.emissivity > 1)
+ {
+ logger_print(stardis->logger, LOG_ERROR, "Invalid emissivity: %s\n", tk);
+ if(res == RES_OK) res = RES_BAD_ARG;
+ goto end;
+ }
+ CHK_TOK(strtok_r(NULL, " \t", tok_ctx), "specular fraction");
+ res = cstr_to_double(tk, &desc->d.t_boundary.specular_fraction);
+ if(res != RES_OK
+ || desc->d.t_boundary.specular_fraction < 0
+ || desc->d.t_boundary.specular_fraction > 1)
+ {
+ logger_print(stardis->logger, LOG_ERROR,
+ "Invalid specular fraction: %s\n", tk);
+ if(res == RES_OK) res = RES_BAD_ARG;
+ goto end;
+ }
+ CHK_TOK(strtok_r(NULL, " \t", tok_ctx), "hc");
+ res = cstr_to_double(tk, &desc->d.t_boundary.hc);
+ if(res != RES_OK
+ || desc->d.t_boundary.hc < 0)
+ {
+ logger_print(stardis->logger, LOG_ERROR, "Invalid hc: %s\n", tk);
+ if(res == RES_OK) res = RES_BAD_ARG;
+ goto end;
+ }
+ }
+
+ ASSERT(sz <= UINT_MAX);
+ ERR(read_sides_and_files(stardis, 1, (unsigned)sz, tok_ctx));
+
+end:
+ return res;
+error:
+ goto end;
+}
+
+/* F_BOUNDARY_FOR_SOLID Name F STL_filenames */
+static res_T
+process_flx
+ (struct stardis* stardis,
+ struct dummies* dummies,
+ char** tok_ctx)
+{
+ char* tk = NULL;
+ struct description* desc;
+ size_t sz;
+ res_T res = RES_OK;
+
+ ASSERT(stardis && tok_ctx);
+
+ stardis->counts.fbound_count++;
+
+ sz = darray_descriptions_size_get(&stardis->descriptions);
+ ERR(darray_descriptions_resize(&stardis->descriptions, sz + 1));
+ desc = darray_descriptions_data_get(&stardis->descriptions) + sz;
+ init_f(stardis->allocator, &desc->d.f_boundary);
+
+ desc->type = DESC_BOUND_F_FOR_SOLID;
+ desc->d.f_boundary.mat_id = get_dummy_fluid_id(stardis, dummies);
+
+ CHK_TOK(strtok_r(NULL, " \t", tok_ctx), "flux boundary name");
+ ERR(str_set(&desc->d.f_boundary.name, tk));
+ if(find_description_by_name(stardis, &desc->d.f_boundary.name, NULL)
+ != desc)
+ {
+ logger_print(stardis->logger, LOG_ERROR,
+ "Name already used: %s\n", tk);
+ if(res == RES_OK) res = RES_BAD_ARG;
+ goto end;
+ }
+
+ CHK_TOK(strtok_r(NULL, " \t", tok_ctx), "flux");
+ res = cstr_to_double(tk, &desc->d.f_boundary.imposed_flux);
+ if(res != RES_OK
+ || desc->d.f_boundary.imposed_flux == SDIS_FLUX_NONE) {
+ /* Flux can be < 0 but not undefined */
+ if(res == RES_OK) res = RES_BAD_ARG;
+ logger_print(stardis->logger, LOG_ERROR, "Invalid flux: %s\n", tk);
+ goto end;
+ }
+
+ ASSERT(sz <= UINT_MAX);
+ ERR(read_sides_and_files(stardis, 1, (unsigned)sz, tok_ctx));
+
+end:
+ return res;
+error:
+ goto end;
+}
+
+/* SOLID_FLUID_CONNECTION Name emissivity specular_fraction hc STL_filenames */
+static res_T
+process_sfc
+ (struct stardis* stardis,
+ char** tok_ctx)
+{
+ char* tk = NULL;
+ struct description* desc;
+ size_t sz;
+ res_T res = RES_OK;
+
+ ASSERT(stardis && tok_ctx);
+
+ stardis->counts.sfconnect_count++;
+
+ sz = darray_descriptions_size_get(&stardis->descriptions);
+ ERR(darray_descriptions_resize(&stardis->descriptions, sz + 1));
+ desc = darray_descriptions_data_get(&stardis->descriptions) + sz;
+ init_sf(stardis->allocator, &desc->d.sf_connect);
+
+ /* Use a medium ID even if there is no medium here
+ * As other cases use media IDs as unique IDs for read_sides_and_files calls
+ * we continue the trend to ensure connection ID is OK */
+ desc->type = DESC_SOLID_FLUID_CONNECT;
+ desc->d.sf_connect.connection_id = allocate_stardis_medium_id(stardis);
+
+ CHK_TOK(strtok_r(NULL, " \t", tok_ctx), "solid fluid connection name");
+ ERR(str_set(&desc->d.sf_connect.name, tk));
+ if(find_description_by_name(stardis, &desc->d.sf_connect.name, NULL)
+ != desc)
+ {
+ logger_print(stardis->logger, LOG_ERROR,
+ "Name already used: %s\n", tk);
+ if(res == RES_OK) res = RES_BAD_ARG;
+ goto end;
+ }
+
+ CHK_TOK(strtok_r(NULL, " \t", tok_ctx), "emissivity");
+ res = cstr_to_double(tk, &desc->d.sf_connect.emissivity);
+ if(res != RES_OK
+ || desc->d.sf_connect.emissivity < 0
+ || desc->d.h_boundary.emissivity > 1)
+ {
+ logger_print(stardis->logger, LOG_ERROR, "Invalid emissivity: %s\n", tk);
+ if(res == RES_OK) res = RES_BAD_ARG;
+ goto end;
+ }
+ CHK_TOK(strtok_r(NULL, " \t", tok_ctx), "specular fraction");
+ res = cstr_to_double(tk, &desc->d.sf_connect.specular_fraction);
+ if(res != RES_OK
+ || desc->d.sf_connect.specular_fraction < 0
+ || desc->d.sf_connect.specular_fraction > 1)
+ {
+ logger_print(stardis->logger, LOG_ERROR,
+ "Invalid specular fraction: %s\n", tk);
+ if(res == RES_OK) res = RES_BAD_ARG;
+ goto end;
+ }
+ CHK_TOK(strtok_r(NULL, " \t", tok_ctx), "hc");
+ res = cstr_to_double(tk, &desc->d.sf_connect.hc);
+ if(res != RES_OK
+ || desc->d.sf_connect.hc < 0)
+ {
+ logger_print(stardis->logger, LOG_ERROR, "Invalid hc: %s\n", tk);
+ if(res == RES_OK) res = RES_BAD_ARG;
+ goto end;
+ }
+
+ ASSERT(sz <= UINT_MAX);
+ ERR(read_sides_and_files(stardis, 1, (unsigned)sz, tok_ctx));
+
+end:
+ return res;
+error:
+ goto end;
+}
+
+static res_T
+read_imposed_temperature
+ (struct stardis* stardis,
+ double* imposed_temperature,
+ char** tok_ctx)
+{
+ char* tk = NULL;
+ struct str keep;
+ res_T res = RES_OK;
+ ASSERT(stardis && imposed_temperature && tok_ctx);
+
+ str_init(stardis->allocator, &keep);
+ CHK_TOK(strtok_r(NULL, " \t", tok_ctx), "imposed temperature");
+ ERR(str_set(&keep, tk));
+ if(RES_OK == cstr_to_double(tk, imposed_temperature)) {
+ /* Was a number */
+ if(*imposed_temperature < 0) {
+ res = RES_BAD_ARG;
+ goto error;
+ }
+ } else {
+ /* Could be 'unknown' */
+ _strupr(tk);
+ if(0 == strcmp(tk, "UNKNOWN")) {
+ *imposed_temperature = UNKNOWN_MEDIUM_TEMPERATURE;
+ } else {
+ res = RES_BAD_ARG;
+ goto error;
+ }
+ }
+end:
+ str_release(&keep);
+ return res;
+error:
+ logger_print(stardis->logger, LOG_ERROR, "Invalid imposed temperature: %s\n",
+ str_cget(&keep));
+ goto end;
+}
+
+static res_T
+read_delta
+ (struct stardis* stardis,
+ double* delta,
+ char** tok_ctx)
+{
+ char* tk = NULL;
+ struct str keep;
+ res_T res = RES_OK;
+ ASSERT(stardis && delta && tok_ctx);
+
+ str_init(stardis->allocator, &keep);
+ CHK_TOK(strtok_r(NULL, " \t", tok_ctx), "delta");
+ ERR(str_set(&keep, tk));
+ if(RES_OK == cstr_to_double(tk, delta)) {
+ /* Was a number */
+ if(*delta <= 0) {
+ res = RES_BAD_ARG;
+ goto error;
+ }
+ } else {
+ /* Could be 'auto' */
+ _strupr(tk);
+ if(0 == strcmp(tk, "AUTO")) {
+ /* Set to DELTA_AUTO until actual value is substituted */
+ *delta = DELTA_AUTO;
+ } else {
+ res = RES_BAD_ARG;
+ goto error;
+ }
+ }
+end:
+ str_release(&keep);
+ return res;
+error:
+ logger_print(stardis->logger, LOG_ERROR, "Invalid delta: %s\n",
+ str_cget(&keep));
+ goto end;
+}
+
+/* SOLID Name lambda rho cp delta Tinit Timposed volumic_power STL_filenames */
+static res_T
+process_solid
+ (struct stardis* stardis,
+ char** tok_ctx)
+{
+ char* tk = NULL;
+ struct description* desc;
+ size_t sz;
+ res_T res = RES_OK;
+
+ ASSERT(stardis && tok_ctx);
+
+ stardis->counts.smed_count++;
+
+ sz = darray_descriptions_size_get(&stardis->descriptions);
+ ERR(darray_descriptions_resize(&stardis->descriptions, sz + 1));
+ desc = darray_descriptions_data_get(&stardis->descriptions) + sz;
+ init_solid(stardis->allocator, &desc->d.solid);
+
+ desc->type = DESC_MAT_SOLID;
+ desc->d.solid.solid_id = allocate_stardis_medium_id(stardis);
+ desc->d.solid.is_green = stardis->mode & (MODE_BIN_GREEN | MODE_GREEN);
+ desc->d.solid.is_outside = 0;
+ ASSERT(sz <= UINT_MAX);
+ desc->d.solid.desc_id = (unsigned)sz;
+
+ CHK_TOK(strtok_r(NULL, " \t", tok_ctx), "solid name");
+ ERR(str_set(&desc->d.solid.name, tk));
+ if(find_description_by_name(stardis, &desc->d.solid.name, NULL)
+ != desc)
+ {
+ logger_print(stardis->logger, LOG_ERROR,
+ "Name already used: %s\n", tk);
+ if(res == RES_OK) res = RES_BAD_ARG;
+ goto end;
+ }
+
+ CHK_TOK(strtok_r(NULL, " \t", tok_ctx), "lambda");
+ res = cstr_to_double(tk, &desc->d.solid.lambda);
+ if(res != RES_OK
+ || desc->d.solid.lambda <= 0)
+ {
+ logger_print(stardis->logger, LOG_ERROR, "Invalid lambda: %s\n", tk);
+ if(res == RES_OK) res = RES_BAD_ARG;
+ goto end;
+ }
+ CHK_TOK(strtok_r(NULL, " \t", tok_ctx), "rho");
+ res = cstr_to_double(tk, &desc->d.solid.rho);
+ if(res != RES_OK
+ || desc->d.solid.rho <= 0)
+ {
+ logger_print(stardis->logger, LOG_ERROR, "Invalid rho: %s\n", tk);
+ if(res == RES_OK) res = RES_BAD_ARG;
+ goto end;
+ }
+ CHK_TOK(strtok_r(NULL, " \t", tok_ctx), "cp");
+ res = cstr_to_double(tk, &desc->d.solid.cp);
+ if(res != RES_OK
+ || desc->d.solid.cp <= 0)
+ {
+ logger_print(stardis->logger, LOG_ERROR, "Invalid cp: %s\n", tk);
+ if(res == RES_OK) res = RES_BAD_ARG;
+ goto end;
+ }
+ ERR(read_delta(stardis, &desc->d.solid.delta, tok_ctx));
+ CHK_TOK(strtok_r(NULL, " \t", tok_ctx), "Tinit");
+ res = cstr_to_double(tk, &desc->d.solid.tinit);
+ if(res != RES_OK
+ || desc->d.solid.tinit < 0)
+ {
+ logger_print(stardis->logger, LOG_ERROR, "Invalid Tinit: %s\n", tk);
+ if(res == RES_OK) res = RES_BAD_ARG;
+ goto end;
+ }
+ ERR(read_imposed_temperature(stardis, &desc->d.solid.imposed_temperature,
+ tok_ctx));
+ if(desc->d.solid.imposed_temperature >= 0
+ && desc->d.solid.imposed_temperature != desc->d.solid.tinit)
+ {
+ logger_print(stardis->logger, LOG_ERROR,
+ "Imposed temperature, if defined, must match initial temperature "
+ "(initial: %g; imposed: %g)\n",
+ desc->d.solid.tinit, desc->d.solid.imposed_temperature); res = RES_BAD_ARG;
+ goto end;
+ }
+ CHK_TOK(strtok_r(NULL, " \t", tok_ctx), "volumic power");
+ res = cstr_to_double(tk, &desc->d.solid.vpower);
+ if(res != RES_OK) {
+ /* VPower can be < 0 */
+ logger_print(stardis->logger, LOG_ERROR, "Invalid volumic power: %s\n", tk);
+ goto end;
+ }
+
+ /* Actual solid creation is defered until geometry is read to allow
+ * enclosure shape VS delta analysis (and auto delta computation) */
+
+ ASSERT(sz <= UINT_MAX);
+ ERR(read_sides_and_files(stardis, 0, (unsigned)sz, tok_ctx));
+
+end:
+ return res;
+error:
+ goto end;
+}
+
+/* FLUID Name rho cp Tinit Timposed STL_filenames */
+static res_T
+process_fluid
+ (struct stardis* stardis,
+ char** tok_ctx)
+{
+ char* tk = NULL;
+ struct description* desc;
+ size_t sz;
+ res_T res = RES_OK;
+
+ ASSERT(stardis && tok_ctx);
+
+ stardis->counts.fmed_count++;
+
+ sz = darray_descriptions_size_get(&stardis->descriptions);
+ ERR(darray_descriptions_resize(&stardis->descriptions, sz + 1));
+ desc = darray_descriptions_data_get(&stardis->descriptions) + sz;
+ init_fluid(stardis->allocator, &desc->d.fluid);
+
+ desc->type = DESC_MAT_FLUID;
+ desc->d.fluid.fluid_id = allocate_stardis_medium_id(stardis);
+ desc->d.fluid.is_outside = 0;
+ desc->d.fluid.is_green = stardis->mode & (MODE_BIN_GREEN | MODE_GREEN);
+ ASSERT(sz <= UINT_MAX);
+ desc->d.fluid.desc_id = (unsigned)sz;
+
+ CHK_TOK(strtok_r(NULL, " \t", tok_ctx), "fluid name");
+ ERR(str_set(&desc->d.fluid.name, tk));
+ if(find_description_by_name(stardis, &desc->d.fluid.name, NULL)
+ != desc)
+ {
+ logger_print(stardis->logger, LOG_ERROR,
+ "Name already used: %s\n", tk);
+ if(res == RES_OK) res = RES_BAD_ARG;
+ goto end;
+ }
+
+ CHK_TOK(strtok_r(NULL, " \t", tok_ctx), "rho");
+ res = cstr_to_double(tk, &desc->d.fluid.rho);
+ if(res != RES_OK
+ || desc->d.fluid.rho <= 0)
+ {
+ logger_print(stardis->logger, LOG_ERROR, "Invalid rho: %s\n", tk);
+ if(res == RES_OK) res = RES_BAD_ARG;
+ goto end;
+ }
+ CHK_TOK(strtok_r(NULL, " \t", tok_ctx), "cp");
+ res = cstr_to_double(tk, &desc->d.fluid.cp);
+ if(res != RES_OK
+ || desc->d.fluid.cp <= 0)
+ {
+ logger_print(stardis->logger, LOG_ERROR, "Invalid cp: %s\n", tk);
+ if(res == RES_OK) res = RES_BAD_ARG;
+ goto end;
+ }
+ CHK_TOK(strtok_r(NULL, " \t", tok_ctx), "Tinit");
+ res = cstr_to_double(tk, &desc->d.fluid.tinit);
+ if(res != RES_OK
+ || desc->d.fluid.tinit < 0)
+ {
+ logger_print(stardis->logger, LOG_ERROR, "Invalid Tinit: %s\n", tk);
+ if(res == RES_OK) res = RES_BAD_ARG;
+ goto end;
+ }
+
+ ERR(read_imposed_temperature(stardis, &desc->d.fluid.imposed_temperature,
+ tok_ctx));
+ if(desc->d.fluid.imposed_temperature >= 0
+ && desc->d.fluid.imposed_temperature != desc->d.fluid.tinit)
+ {
+ logger_print(stardis->logger, LOG_ERROR,
+ "Imposed temperature, if defined, must match initial temperature "
+ "(initial: %g; imposed: %g)\n",
+ desc->d.fluid.tinit, desc->d.fluid.imposed_temperature); res = RES_BAD_ARG;
+ goto end;
+ }
+
+ ERR(create_solver_fluid(stardis, &desc->d.fluid));
+
+ ASSERT(sz <= UINT_MAX);
+ ERR(read_sides_and_files(stardis, 0, (unsigned)sz, tok_ctx));
+
+end:
+ return res;
+error:
+ goto end;
+}
+
+/* SCALE scale_factor */
+static res_T
+process_scale
+ (struct stardis* stardis,
+ char** tok_ctx)
+{
+ char* tk = NULL;
+ res_T res = RES_OK;
+
+ ASSERT(stardis && tok_ctx);
+
+ if(stardis->scale_factor > 0) {
+ logger_print(stardis->logger, LOG_ERROR,
+ "SCALE cannot be specified twice\n");
+ res = RES_BAD_ARG;
+ goto end;
+ }
+ CHK_TOK(strtok_r(NULL, " \t", tok_ctx), "scale factor");
+ res = cstr_to_double(tk, &stardis->scale_factor);
+ if(res != RES_OK
+ || stardis->scale_factor <= 0)
+ {
+ logger_print(stardis->logger, LOG_ERROR,
+ "Invalid scale factor: %s\n", tk);
+ if(res == RES_OK) res = RES_BAD_ARG;
+ goto end;
+ }
+
+end:
+ return res;
+error:
+ goto end;
+}
+
+/* Read medium or boundary line; should be one of:
+ * SOLID Name lambda rho cp delta Tinit Timposed volumic_power STL_filenames
+ * FLUID Name rho cp Tinit Timposed STL_filenames
+ * H_BOUNDARY_FOR_SOLID Name emissivity specular_fraction hc T_env STL_filenames
+ * H_BOUNDARY_FOR_FLUID Name emissivity specular_fraction hc T_env STL_filenames
+ * T_BOUNDARY_FOR_SOLID Name T STL_filenames
+ * T_BOUNDARY_FOR_FLUID Name T hc STL_filenames
+ * F_BOUNDARY_FOR_SOLID Name F STL_filenames
+ * SOLID_FLUID_CONNECTION Name emissivity specular_fraction hc STL_filenames
+ * SCALE scale_factor
+ *
+ * STL_filenames = { { FRONT | BACK | BOTH } STL_filename }+
+ */
+res_T
+process_model_line
+ (const char* file_name,
+ char* line,
+ struct stardis* stardis,
+ struct dummies* dummies)
+{
+ res_T res = RES_OK;
+ struct str keep;
+ char* tk = NULL, * tok_ctx = NULL;
+
+ ASSERT(file_name && line && stardis);
+
+ str_init(stardis->allocator, &keep);
+ ERR(str_set(&keep, line));
+ CHK_TOK(strtok_r(line, " \t", &tok_ctx), "model line type");
+ _strupr(tk);
+
+ if(0 == strcmp(tk, "H_BOUNDARY_FOR_SOLID"))
+ ERR(process_h(stardis, dummies, DESC_BOUND_H_FOR_SOLID, &tok_ctx));
+ else if(0 == strcmp(tk, "H_BOUNDARY_FOR_FLUID"))
+ ERR(process_h(stardis, dummies, DESC_BOUND_H_FOR_FLUID, &tok_ctx));
+ else if(0 == strcmp(tk, "T_BOUNDARY_FOR_SOLID"))
+ ERR(process_t(stardis, dummies, DESC_BOUND_T_FOR_SOLID, &tok_ctx));
+ else if(0 == strcmp(tk, "T_BOUNDARY_FOR_FLUID"))
+ ERR(process_t(stardis, dummies, DESC_BOUND_T_FOR_FLUID, &tok_ctx));
+ else if(0 == strcmp(tk, "F_BOUNDARY_FOR_SOLID"))
+ ERR(process_flx(stardis, dummies, &tok_ctx));
+ else if(0 == strcmp(tk, "SOLID_FLUID_CONNECTION"))
+ ERR(process_sfc(stardis, &tok_ctx));
+ else if(0 == strcmp(tk, "SOLID"))
+ ERR(process_solid(stardis, &tok_ctx));
+ else if(0 == strcmp(tk, "FLUID"))
+ ERR(process_fluid(stardis, &tok_ctx));
+ else if(0 == strcmp(tk, "SCALE"))
+ ERR(process_scale(stardis, &tok_ctx));
+ else {
+ logger_print(stardis->logger, LOG_ERROR,
+ "Unknown description type: %s\n", tk);
+ res = RES_BAD_ARG;
+ goto error;
+ }
+
+end:
+ str_release(&keep);
+ return res;
+error:
+ logger_print(stardis->logger, LOG_ERROR,
+ "Invalid description line in model file '%s':\n", file_name);
+ logger_print(stardis->logger, LOG_ERROR, "%s\n", str_cget(&keep));
+ goto end;
+}
+
+unsigned
+get_dummy_solid_id
+ (struct stardis* stardis,
+ struct dummies* dummies)
+{
+ struct solid dummy;
+ if(dummies->dummy_solid)
+ return dummies->dummy_solid_id;
+ dummies->dummy_solid_id = allocate_stardis_medium_id(stardis);
+ init_solid(stardis->allocator, &dummy);
+ dummy.solid_id = dummies->dummy_solid_id;
+ dummy.is_outside = 1;
+ dummy.is_green = stardis->mode & (MODE_BIN_GREEN | MODE_GREEN);
+ create_solver_solid(stardis, &dummy);
+ dummies->dummy_solid
+ = darray_media_ptr_data_get(&stardis->media)[dummies->dummy_solid_id];
+ logger_print(stardis->logger, LOG_OUTPUT,
+ "Dummy solid created: (it is medium %u)\n",
+ dummies->dummy_solid_id);
+ return dummies->dummy_solid_id;
+}
+
+unsigned
+get_dummy_fluid_id
+ (struct stardis* stardis,
+ struct dummies* dummies)
+{
+ struct fluid dummy;
+ if(dummies->dummy_fluid)
+ return dummies->dummy_fluid_id;
+ dummies->dummy_fluid_id = allocate_stardis_medium_id(stardis);
+ init_fluid(stardis->allocator, &dummy);
+ dummy.fluid_id = dummies->dummy_fluid_id;
+ dummy.is_outside = 1;
+ dummy.is_green = stardis->mode & (MODE_BIN_GREEN | MODE_GREEN);
+ create_solver_fluid(stardis, &dummy);
+ dummies->dummy_fluid
+ = darray_media_ptr_data_get(&stardis->media)[dummies->dummy_fluid_id];
+ logger_print(stardis->logger, LOG_OUTPUT,
+ "Dummy fluid created: (it is medium %u)\n",
+ dummies->dummy_fluid_id);
+ return dummies->dummy_fluid_id;
+}
diff --git a/src/stardis-parsing.h b/src/stardis-parsing.h
@@ -0,0 +1,203 @@
+/* Copyright (C) 2018-2020 |Meso|Star> (contact@meso-star.com)
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+#ifndef STARDIS_PARSING_H
+#define STARDIS_PARSING_H
+
+#include <sdis.h>
+
+#include <rsys/rsys.h>
+#include <rsys/dynamic_array_str.h>
+
+#include <star/sstl.h>
+
+struct camera;
+struct logger;
+struct mem_allocator;
+struct stardis;
+struct dummies;
+
+/* Utility macros */
+#define CHK_TOK(x, Name) if((tk = (x)) == NULL) {\
+ logger_print(stardis->logger, LOG_ERROR,\
+ "Invalid data (missing token '" Name "')\n");\
+ res = RES_BAD_ARG;\
+ goto error;\
+ } (void)0
+
+#ifdef COMPILER_CL
+#define strtok_r strtok_s
+#endif
+
+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_VTK = 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_VTK | MODE_DUMP_HELP | MODE_DUMP_VERSION
+ | MODE_IR_COMPUTE | MODE_GREEN
+};
+
+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* paths_filename;
+ char* chunks_prefix;
+ size_t samples;
+ unsigned nthreads;
+ double pos_and_time[5];
+ enum stardis_mode mode;
+ double ambient_temp, ref_temp;
+ char* camera;
+ enum dump_path_type dump_paths;
+ int verbose;
+};
+
+/* Same ctx used for both media and interface add (some unused parts) */
+struct add_geom_ctx {
+ struct sstl_desc stl_desc;
+ unsigned properties[3];
+ void* custom;
+};
+
+/* Possible callbacks for sg3d_geometry_add calls
+ * when void* context is a struct add_geom_ctx */
+extern LOCAL_SYM void
+add_geom_ctx_indices
+ (const unsigned itri,
+ unsigned ids[3],
+ void* context);
+
+extern LOCAL_SYM void
+add_geom_ctx_properties
+ (const unsigned itri,
+ unsigned prop[3],
+ void* context);
+
+extern LOCAL_SYM void
+add_geom_ctx_position
+ (const unsigned ivert,
+ double pos[3],
+ void* context);
+
+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 char
+mode_option
+ (const int m);
+
+extern void
+print_multiple_modes
+ (char* buf,
+ const size_t sz,
+ const int modes,
+ const int dont);
+
+extern void
+print_version
+ (FILE* stream);
+
+extern void
+short_help
+ (FILE* stream,
+ const char* prog);
+
+extern res_T
+parse_args
+ (const int argc,
+ char** argv,
+ struct args* args);
+
+extern res_T
+parse_camera
+ (struct logger* logger,
+ char* cam_param,
+ struct stardis* stardis);
+
+extern LOCAL_SYM res_T
+process_model_line
+ (const char* file_name,
+ char* line,
+ struct stardis* stardis,
+ struct dummies* dummies);
+
+extern LOCAL_SYM unsigned
+get_dummy_solid_id
+ (struct stardis* stardis,
+ struct dummies* dummies);
+
+extern LOCAL_SYM unsigned
+get_dummy_fluid_id
+ (struct stardis* stardis,
+ struct dummies* dummies);
+
+#endif /*ARGS_H*/
diff --git a/src/stardis-solid.c b/src/stardis-solid.c
@@ -0,0 +1,221 @@
+/* Copyright (C) 2018-2020 |Meso|Star> (contact@meso-star.com)
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+#include "stardis-solid.h"
+#include "stardis-compute.h"
+#include "stardis-app.h"
+
+#include <sdis.h>
+
+#include <limits.h>
+
+/*******************************************************************************
+ * Local Functions
+ ******************************************************************************/
+
+static double
+solid_get_calorific_capacity
+ (const struct sdis_rwalk_vertex* vtx,
+ struct sdis_data* data)
+{
+ const struct solid* solid_props = sdis_data_cget(data);
+ (void)vtx;
+ return solid_props->cp;
+}
+
+static double
+solid_get_thermal_conductivity
+ (const struct sdis_rwalk_vertex* vtx,
+ struct sdis_data* data)
+{
+ const struct solid* solid_props = sdis_data_cget(data);
+ (void)vtx;
+ return solid_props->lambda;
+}
+
+static double
+solid_get_volumic_mass
+ (const struct sdis_rwalk_vertex* vtx,
+ struct sdis_data* data)
+{
+ const struct solid* solid_props = sdis_data_cget(data);
+ (void)vtx;
+ return solid_props->rho;
+}
+
+static double
+solid_get_delta
+ (const struct sdis_rwalk_vertex* vtx,
+ struct sdis_data* data)
+{
+ const struct solid* solid_props = sdis_data_cget(data);
+ (void)vtx;
+ return solid_props->delta;
+}
+
+#if Stardis_VERSION_MINOR == 3
+static double
+solid_get_delta_boundary
+ (const struct sdis_rwalk_vertex* vtx,
+ struct sdis_data* data)
+{
+ const struct solid* solid_props = sdis_data_cget(data);
+ return solid_props->delta;
+}
+#endif
+
+static double
+solid_get_temperature
+ (const struct sdis_rwalk_vertex* vtx,
+ struct sdis_data* data)
+{
+ const struct solid* solid_props = sdis_data_cget(data);
+ if(solid_props->imposed_temperature >= 0)
+ /* If there is an imposed temp, it is imposed regardless of time */
+ return solid_props->imposed_temperature;
+ if(vtx->time <= solid_props->t0) {
+ /* If time is <= t0: use tinit */
+ if(solid_props->tinit < 0) {
+ if(str_is_empty(&solid_props->name)) {
+ FATAL("solid_get_temperature: getting undefined Tinit\n");
+ } else {
+ VFATAL("solid_get_temperature: getting undefined Tinit (solid '%s')\n",
+ ARG1(str_cget(&solid_props->name)));
+ }
+ }
+ return solid_props->tinit;
+ }
+ return -1; /* Unknown temperature */
+}
+
+static double
+solid_get_power
+ (const struct sdis_rwalk_vertex* vtx,
+ struct sdis_data* data)
+{
+ const struct solid* solid_props = sdis_data_cget(data);
+ (void)vtx;
+ return solid_props->vpower;
+}
+
+/*******************************************************************************
+ * Public Functions
+ ******************************************************************************/
+
+res_T
+create_solver_solid
+ (struct stardis* stardis,
+ const struct solid* solid_props)
+{
+ res_T res = RES_OK;
+ struct sdis_solid_shader solid_shader = SDIS_SOLID_SHADER_NULL;
+ struct sdis_data* data = NULL;
+ struct solid* props;
+ /* Could be less restrictive if green output included positions/dates */
+
+ ASSERT(stardis && solid_props);
+ solid_shader.calorific_capacity = solid_get_calorific_capacity;
+ solid_shader.thermal_conductivity = solid_get_thermal_conductivity;
+ solid_shader.volumic_mass = solid_get_volumic_mass;
+ solid_shader.delta_solid = solid_get_delta;
+#if Stardis_VERSION_MINOR == 3
+ solid_shader.delta_boundary = solid_get_delta_boundary;
+#endif
+ solid_shader.temperature = solid_get_temperature;
+ ERR(sdis_data_create(stardis->dev, sizeof(struct solid), ALIGNOF(struct solid),
+ NULL, &data));
+
+ props = sdis_data_get(data); /* Fetch the allocated memory space */
+ init_solid(stardis->allocator, props);
+ cp_solid(props, solid_props);
+ if(solid_props->vpower != 0) solid_shader.volumic_power = solid_get_power;
+ if(solid_props->solid_id >= darray_media_ptr_size_get(&stardis->media)) {
+ ERR(darray_media_ptr_resize(&stardis->media, solid_props->solid_id + 1));
+ }
+ ASSERT(darray_media_ptr_data_get(&stardis->media)[solid_props->solid_id] == NULL);
+ ERR(sdis_solid_create(stardis->dev, &solid_shader, data,
+ darray_media_ptr_data_get(&stardis->media) + solid_props->solid_id));
+
+end:
+ if(data) SDIS(data_ref_put(data));
+ return res;
+error:
+ goto end;
+}
+
+void
+init_solid(struct mem_allocator* allocator, struct solid* dst)
+{
+ str_init(allocator, &dst->name);
+ dst->lambda = 1;
+ dst->rho = 1;
+ dst->cp = 1;
+ dst->delta = 1;
+ dst->tinit = -1;
+ dst->imposed_temperature = -1;
+ dst->vpower = 0;
+ dst->t0 = 0;
+ dst->is_outside = 0;
+ dst->is_green = 0;
+ dst->desc_id = UINT_MAX;
+ dst->solid_id = UINT_MAX;
+}
+
+void
+release_solid(struct solid* solid)
+{
+ str_release(&solid->name);
+}
+
+res_T
+str_print_solid(struct str* str, const struct solid* s)
+{
+ res_T res = RES_OK;
+ ASSERT(str && s);
+ STR_APPEND_PRINTF(str, "Solid '%s': lambda=%g rho=%g cp=%g delta=%g",
+ ARG5( str_cget(&s->name), s->lambda, s->rho, s->cp, s->delta ) );
+ if(s->vpower != 0) {
+ STR_APPEND_PRINTF(str, " VPower=%g", ARG1( s->vpower ) );
+ }
+ if(s->tinit >= 0) {
+ STR_APPEND_PRINTF(str, " Tinit=%g", ARG1( s->tinit ) );
+ }
+ if(s->imposed_temperature >= 0) {
+ STR_APPEND_PRINTF(str, " Temp=%g", ARG1( s->imposed_temperature ) );
+ }
+ STR_APPEND_PRINTF(str, " (it is medium %u)", ARG1( s->solid_id ) );
+end:
+ return res;
+error:
+ goto end;
+}
+
+res_T
+cp_solid(struct solid* dst, const struct solid* src)
+{
+ dst->lambda = src->lambda;
+ dst->rho = src->rho;
+ dst->cp = src->cp;
+ dst->delta = src->delta;
+ dst->tinit = src->tinit;
+ dst->imposed_temperature = src->imposed_temperature;
+ dst->vpower = src->vpower;
+ dst->t0 = src->t0;
+ dst->is_outside = src->is_outside;
+ dst->is_green = src->is_green;
+ dst->desc_id = src->desc_id;
+ dst->solid_id = src->solid_id;
+ return str_copy(&dst->name, &src->name);
+}
diff --git a/src/stardis-solid.h b/src/stardis-solid.h
@@ -0,0 +1,60 @@
+/* Copyright (C) 2018-2020 |Meso|Star> (contact@meso-star.com)
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+#ifndef SDIS_SOLID_H
+#define SDIS_SOLID_H
+
+#include <rsys/rsys.h>
+#include <rsys/str.h>
+
+struct stardis;
+
+/*******************************************************************************
+ * Solid data
+ ******************************************************************************/
+struct solid {
+ struct str name;
+ double lambda; /* Conductivity */
+ double rho; /* Volumic mass */
+ double cp; /* Calorific capacity */
+ double delta; /* Numerical parameter */
+ double tinit; /* Initial temperature */
+ double imposed_temperature; /* allow to impose a T; -1 if unset */
+ double vpower;
+ double t0; /* End time of tinit */
+ int is_outside; /* the solid is used for a boundary */
+ int is_green; /* green computation (nothing to do with solid itself) */
+ unsigned desc_id; /* id of the boundary; meaningful if is_outside */
+ unsigned solid_id;
+};
+
+LOCAL_SYM void
+init_solid(struct mem_allocator* allocator, struct solid* dst);
+
+LOCAL_SYM void
+release_solid(struct solid* solid);
+
+LOCAL_SYM res_T
+str_print_solid(struct str* str, const struct solid* s);
+
+LOCAL_SYM res_T
+cp_solid(struct solid* dst, const struct solid* src);
+
+LOCAL_SYM res_T
+create_solver_solid
+ (struct stardis* stardis,
+ const struct solid* solid_props);
+
+#endif
diff --git a/src/stardis-version.h.in b/src/stardis-version.h.in
@@ -0,0 +1,24 @@
+/* Copyright (C) 2018-2020 |Meso|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/>. */
+
+#ifndef STARDIS_APP_VERSION_H
+#define STARDIS_APP_VERSION_H
+
+#define STARDIS_APP_VERSION_MAJOR @SDIS_VERSION_MAJOR@
+#define STARDIS_APP_VERSION_MINOR @SDIS_VERSION_MINOR@
+#define STARDIS_APP_VERSION_PATCH @SDIS_VERSION_PATCH@
+
+#endif /* STARDIS_APP_VERSION_H */
+
diff --git a/tinyexpr/tinyexpr.c b/tinyexpr/tinyexpr.c
@@ -1,890 +0,0 @@
-/*
- * TINYEXPR - Tiny recursive descent parser and evaluation engine in C
- *
- * Copyright (c) 2015-2018 Lewis Van Winkle
- *
- * http://CodePlea.com
- *
- * This software is provided 'as-is', without any express or implied
- * warranty. In no event will the authors be held liable for any damages
- * arising from the use of this software.
- *
- * Permission is granted to anyone to use this software for any purpose,
- * including commercial applications, and to alter it and redistribute it
- * freely, subject to the following restrictions:
- *
- * 1. The origin of this software must not be misrepresented; you must not
- * claim that you wrote the original software. If you use this software
- * in a product, an acknowledgement in the product documentation would be
- * appreciated but is not required.
- * 2. Altered source versions must be plainly marked as such, and must not be
- * misrepresented as being the original software.
- * 3. This notice may not be removed or altered from any source distribution.
- */
-
-/* COMPILE TIME OPTIONS */
-
-/* Exponentiation associativity:
-For a^b^c = (a^b)^c and -a^b = (-a)^b do nothing.
-For a^b^c = a^(b^c) and -a^b = -(a^b) uncomment the next line.*/
-/* #define TE_POW_FROM_RIGHT */
-
-/* Logarithms
-For log = base 10 log do nothing
-For log = natural log uncomment the next line. */
-/* #define TE_NAT_LOG */
-
-#include "tinyexpr.h"
-#include <stdlib.h>
-#include <math.h>
-#include <string.h>
-#include <stdio.h>
-#include <limits.h>
-#include <assert.h>
-
-#ifndef M_E
-#define M_E 2.71828182845904523536 // e
-#endif
-
-#ifndef M_PI
-#define M_PI 3.14159265358979323846 // pi
-#endif
-
-#ifndef NAN
-#define NAN (0.0/0.0)
-#endif
-
-#ifndef INFINITY
-#define INFINITY (1.0/0.0)
-#endif
-
-
-typedef double (*te_fun2)(double, double);
-
-enum {
-
-#ifdef TE_WITHOUT_FUNCTION_0
- TE_FUNCTION0 = 8,
-#endif
-#ifdef TE_WITHOUT_CLOSURES
- TE_CLOSURE7 = 23,
-#endif
-
- TOK_NULL = TE_CLOSURE7+1, TOK_ERROR, TOK_END, TOK_SEP,
- TOK_OPEN, TOK_CLOSE, TOK_NUMBER, TOK_VARIABLE, TOK_OFFSET, TOK_INFIX,
-
- TE_CONDITION = 256
-};
-
-typedef struct state {
- const char *start;
- const char *next;
- int type;
- union value v;
- void *context;
-
- const te_variable *lookup;
- int lookup_len;
-} state;
-
-
-#define TYPE_MASK(TYPE) ((TYPE)&0x0000003F)
-
-#define IS_PURE(TYPE) (((TYPE) & TE_FLAG_PURE) != 0)
-#define IS_FUNCTION(TYPE) (((TYPE) & TE_FUNCTION0) != 0)
-#ifdef TE_WITHOUT_CLOSURES
-#define ARITY(TYPE) ( ((TYPE) & TE_FUNCTION0) ? ((TYPE) & 0x00000007) : 0 )
-#else
-#define IS_CLOSURE(TYPE) (((TYPE) & TE_CLOSURE0) != 0)
-#define ARITY(TYPE) ( ((TYPE) & (TE_FUNCTION0 | TE_CLOSURE0)) ? ((TYPE) & 0x00000007) : 0 )
-#endif
-#define IS_CONDITION(TYPE) (((TYPE) & TE_CONDITION) != 0)
-#define NEW_EXPR(type, ...) new_expr((type), (const te_expr*[]){__VA_ARGS__})
-
-static te_expr *new_expr(const int type, const te_expr *parameters[]) {
- const size_t arity = ARITY(type);
- const size_t psize = sizeof(void*) * arity;
- const size_t size = (sizeof(te_expr) - sizeof(void*)) + psize
-#ifndef TE_WITHOUT_CLOSURES
- + (IS_CLOSURE(type) ? sizeof(void*) : 0)
-#endif
- ;
- te_expr *ret = malloc(size);
- memset(ret, 0, size);
- if (arity && parameters) {
- memcpy(ret->parameters, parameters, psize);
- }
- ret->type = type;
- ret->v.bound = 0;
- return ret;
-}
-
-static te_expr *new_expr1(const int type, te_expr *p1) {
- const size_t size = sizeof(te_expr)
-#ifndef TE_WITHOUT_CLOSURES
- + (IS_CLOSURE(type) ? sizeof(void*) : 0)
-#endif
- ;
- assert(p1 && ARITY(type) == 1);
- te_expr *ret = malloc(size);
- ret->type = type;
- ret->v.bound = 0;
- ret->parameters[0] = p1;
- return ret;
-}
-
-te_expr* te_duplicate(te_expr* n) {
- const size_t size = sizeof(te_expr)
-#ifndef TE_WITHOUT_CLOSURES
- + (IS_CLOSURE(n->type) ? sizeof(void*) : 0);
-#endif
- ;
- te_expr* nn;
- assert(n);
- nn = malloc(size);
- memcpy(nn, n, size);
- return nn;
-}
-
-static te_expr *new_expr2(const int type, te_expr *p1, te_expr *p2) {
- const size_t size = sizeof(te_expr) + sizeof(void*)
-#ifndef TE_WITHOUT_CLOSURES
- + (IS_CLOSURE(type) ? sizeof(void*) : 0)
-#endif
- ;
- assert(p1 && p2 && ARITY(type) == 2);
- te_expr *ret = malloc(size);
- ret->type = type;
- ret->v.bound = 0;
- ret->parameters[0] = p1;
- ret->parameters[1] = p2;
- return ret;
-}
-
-static void te_free_parameters(te_expr *n) {
- int i;
- if (!n) return;
- for (i = 0; i < ARITY(n->type); i++)te_free(n->parameters[i]);
-}
-
-
-void te_free(te_expr *n) {
- if (!n) return;
- te_free_parameters(n);
- free(n);
-}
-
-static double fac(double a) {/* simplest version of fac */
- if (a < 0.0)
- return NAN;
- if (a > UINT_MAX)
- return INFINITY;
- unsigned int ua = (unsigned int)(a);
- unsigned long int result = 1, i;
- for (i = 1; i <= ua; i++) {
- if (i > ULONG_MAX / result)
- return INFINITY;
- result *= i;
- }
- return (double)result;
-}
-static double ncr(double n, double r) {
- if (n < 0.0 || r < 0.0 || n < r) return NAN;
- if (n > UINT_MAX || r > UINT_MAX) return INFINITY;
- unsigned long int un = (unsigned int)(n), ur = (unsigned int)(r), i;
- unsigned long int result = 1;
- if (ur > un / 2) ur = un - ur;
- for (i = 1; i <= ur; i++) {
- if (result > ULONG_MAX / (un - ur + i))
- return INFINITY;
- result *= un - ur + i;
- result /= i;
- }
- return (double)result;
-}
-static double npr(double n, double r) {return ncr(n, r) * fac(r);}
-
-/* Workaround for a VC 2017 problem */
-static double ceil_(double x) { return ceil(x); }
-static double floor_(double x) { return floor(x); }
-
-static const te_variable functions[] = {
- /* must be in alphabetical order */
- {"abs", {.f1=fabs}, TE_FUNCTION1 | TE_FLAG_PURE, 0},
- {"acos", {.f1=acos}, TE_FUNCTION1 | TE_FLAG_PURE, 0},
- {"asin", {.f1=asin}, TE_FUNCTION1 | TE_FLAG_PURE, 0},
- {"atan", {.f1=atan}, TE_FUNCTION1 | TE_FLAG_PURE, 0},
- {"atan2", {.f2=atan2}, TE_FUNCTION2 | TE_FLAG_PURE, 0},
- {"ceil", {.f1=ceil_}, TE_FUNCTION1 | TE_FLAG_PURE, 0},
- {"cos", {.f1=cos}, TE_FUNCTION1 | TE_FLAG_PURE, 0},
- {"cosh", {.f1=cosh}, TE_FUNCTION1 | TE_FLAG_PURE, 0},
- {"e", {.value = M_E}, TE_CONSTANT, 0},
- {"exp", {.f1=exp}, TE_FUNCTION1 | TE_FLAG_PURE, 0},
- {"fac", {.f1=fac}, TE_FUNCTION1 | TE_FLAG_PURE, 0},
- {"floor", {.f1=floor_}, TE_FUNCTION1 | TE_FLAG_PURE, 0},
- {"if", {.f3 = NULL}, /* Specific treatment, no associated C function */
- TE_FUNCTION3 | TE_CONDITION | TE_FLAG_PURE, 0},
- {"ln", {.f1=log}, TE_FUNCTION1 | TE_FLAG_PURE, 0},
-#ifdef TE_NAT_LOG
- {"log", {.f1=log}, TE_FUNCTION1 | TE_FLAG_PURE, 0},
-#else
- {"log", {.f1=log10}, TE_FUNCTION1 | TE_FLAG_PURE, 0},
-#endif
- {"log10", {.f1=log10}, TE_FUNCTION1 | TE_FLAG_PURE, 0},
- {"ncr", {.f2=ncr}, TE_FUNCTION2 | TE_FLAG_PURE, 0},
- {"npr", {.f2=npr}, TE_FUNCTION2 | TE_FLAG_PURE, 0},
- {"pi", {.value=M_PI}, TE_CONSTANT, 0},
- {"pow", {.f2=pow}, TE_FUNCTION2 | TE_FLAG_PURE, 0},
- {"sin", {.f1=sin}, TE_FUNCTION1 | TE_FLAG_PURE, 0},
- {"sinh", {.f1=sinh}, TE_FUNCTION1 | TE_FLAG_PURE, 0},
- {"sqrt", {.f1=sqrt}, TE_FUNCTION1 | TE_FLAG_PURE, 0},
- {"tan", {.f1=tan}, TE_FUNCTION1 | TE_FLAG_PURE, 0},
- {"tanh", {.f1=tanh}, TE_FUNCTION1 | TE_FLAG_PURE, 0},
- {0, {0}, 0, 0}
-};
-
-static const te_variable *find_builtin(const char *name, size_t len) {
- int imin = 0;
- int imax = sizeof(functions) / sizeof(te_variable) - 2;
-
- /*Binary search.*/
- while (imax >= imin) {
- const int i = (imin + ((imax-imin)/2));
- int c = strncmp(name, functions[i].name, len);
- if (!c) c = '\0' - functions[i].name[len];
- if (c == 0) {
- return functions + i;
- } else if (c > 0) {
- imin = i + 1;
- } else {
- imax = i - 1;
- }
- }
-
- return 0;
-}
-
-static const te_variable *find_lookup(const state *s, const char *name, size_t len) {
- int iters;
- const te_variable *var;
- if (!s->lookup) return 0;
-
- for (var = s->lookup, iters = s->lookup_len; iters; ++var, --iters) {
- if (strncmp(name, var->name, len) == 0 && var->name[len] == '\0') {
- return var;
- }
- }
- return 0;
-}
-
-
-
-static double add(double a, double b) {return a + b;}
-static double sub(double a, double b) {return a - b;}
-static double mul(double a, double b) {return a * b;}
-static double divide(double a, double b) {return a / b;}
-static double negate(double a) {return -a;}
-static double comma(double a, double b) {(void)a; return b;}
-static double is_gt(double a, double b) { return a > b ? 1 : 0; }
-static double is_ge(double a, double b) { return a >= b ? 1 : 0; }
-static double is_lt(double a, double b) { return a < b ? 1 : 0; }
-static double is_le(double a, double b) { return a <= b ? 1 : 0; }
-static double is_eq(double a, double b) { return a == b ? 1 : 0; }
-static double is_neq(double a, double b) { return a != b ? 1 : 0; }
-
-static int next_if(state *s, const char c) {
- int r = *s->next && s->next[0] == c;
- if (r) s->next++;
- return r;
-}
-
-static void next_token(state *s) {
- s->type = TOK_NULL;
-
- do {
-
- if (!*s->next){
- s->type = TOK_END;
- return;
- }
-
- /* Try reading a number. */
- if ((s->next[0] >= '0' && s->next[0] <= '9') || s->next[0] == '.') {
- s->v.value = strtod(s->next, (char**)&s->next);
- s->type = TOK_NUMBER;
- } else {
- /* Look for a variable or builtin function call. */
- if (s->next[0] >= 'a' && s->next[0] <= 'z') {
- const char *start;
- start = s->next;
- while ((s->next[0] >= 'a' && s->next[0] <= 'z') || (s->next[0] >= '0' && s->next[0] <= '9') || (s->next[0] == '_')) s->next++;
-
- const te_variable *var = find_lookup(s, start, (size_t)(s->next - start));
- if (!var) var = find_builtin(start, (size_t)(s->next - start));
-
- if (!var) {
- s->type = TOK_ERROR;
- } else {
- switch(TYPE_MASK(var->type))
- {
- case TE_VARIABLE:
- s->type = TOK_VARIABLE;
- s->v.bound = var->v.bound;
- break;
-
- case TE_OFFSET:
- s->type = TOK_OFFSET;
- s->v.offset = var->v.offset;
- break;
-
- case TE_CONSTANT:
- s->type = TE_CONSTANT;
- s->v.value = var->v.value;
- break;
-
-#ifndef TE_WITHOUT_CLOSURES
- case TE_CLOSURE0: case TE_CLOSURE1: case TE_CLOSURE2: case TE_CLOSURE3:
- case TE_CLOSURE4: case TE_CLOSURE5: case TE_CLOSURE6: case TE_CLOSURE7:
- s->context = var->context;
-#endif
-#ifndef TE_WITHOUT_FUNCTION_0
- /* fall through */
- case TE_FUNCTION0:
-#endif
- /* fall through */
- case TE_FUNCTION1: case TE_FUNCTION2: case TE_FUNCTION3:
-#if TE_MAX_FUNCTION_ARITY >= 4
- /* fall through */
- case TE_FUNCTION4:
-#endif
-#if TE_MAX_FUNCTION_ARITY >= 5
- /* fall through */
- case TE_FUNCTION5:
-#endif
-#if TE_MAX_FUNCTION_ARITY >= 6
- /* fall through */
- case TE_FUNCTION6:
-#endif
-#if TE_MAX_FUNCTION_ARITY == 7
- /* fall through */
- case TE_FUNCTION7:
-#endif
- s->type = var->type;
- s->v.any = var->v.any;
- break;
- }
- }
-
- } else {
- /* Look for an operator or special character. */
- switch (s->next++[0]) {
- case '+': s->type = TOK_INFIX; s->v.f2 = add; break;
- case '-': s->type = TOK_INFIX; s->v.f2 = sub; break;
- case '*': s->type = TOK_INFIX; s->v.f2 = mul; break;
- case '/': s->type = TOK_INFIX; s->v.f2 = divide; break;
- case '^': s->type = TOK_INFIX; s->v.f2 = pow; break;
- case '%': s->type = TOK_INFIX; s->v.f2 = fmod; break;
- case '>': s->type = TOK_INFIX;
- s->v.f2 = next_if(s, '=') ? is_ge : is_gt; break;
- case '<': s->type = TOK_INFIX;
- s->v.f2 = next_if(s, '=') ? is_le : is_lt; break;
- case '=': s->type = TOK_INFIX;
- /* The only valid char after = is = */
- if (next_if(s, '=')) s->v.f2 = is_eq; else s->type = TOK_ERROR;
- break;
- case '!': s->type = TOK_INFIX;
- /* The only valid char after ! is = */
- if (next_if(s, '=')) s->v.f2 = is_neq; else s->type = TOK_ERROR;
- break;
- case '(': s->type = TOK_OPEN; break;
- case ')': s->type = TOK_CLOSE; break;
- case ',': s->type = TOK_SEP; break;
- case ' ': case '\t': case '\n': case '\r': break;
- default: s->type = TOK_ERROR; break;
- }
- }
- }
- } while (s->type == TOK_NULL);
-}
-
-
-static te_expr *list(state *s);
-static te_expr *eql(state *s);
-static te_expr *power(state *s);
-
-static te_expr *base(state *s) {
- /* <base> = <constant> | <variable> | <function-0> {"(" ")"} | <function-1> <power> | <function-X> "(" <expr> {"," <expr>} ")" | "(" <list> ")" */
- te_expr *ret;
- int arity;
-
- switch (TYPE_MASK(s->type)) {
- case TOK_NUMBER:
- ret = new_expr(TE_CONSTANT, 0);
- ret->v.value = s->v.value;
- next_token(s);
- break;
-
- case TOK_VARIABLE:
- ret = new_expr(TE_VARIABLE, 0);
- ret->v.bound = s->v.bound;
- next_token(s);
- break;
-
- case TOK_OFFSET:
- ret = new_expr(TE_OFFSET, 0);
- ret->v.offset = s->v.offset;
- next_token(s);
- break;
-
- case TE_CONSTANT:
- ret = new_expr(TE_CONSTANT, 0);
- ret->v.value = s->v.value;
- next_token(s);
- break;
-
-#if ! defined(TE_WITHOUT_FUNCTION_0) || ! defined(TE_WITHOUT_CLOSURES)
-#ifndef TE_WITHOUT_FUNCTION_0
- case TE_FUNCTION0:
-#endif
-#ifndef TE_WITHOUT_CLOSURES
- case TE_CLOSURE0:
-#endif
- ret = new_expr(s->type, 0);
- ret->v.any = s->v.any;
-#ifndef TE_WITHOUT_CLOSURES
- if (IS_CLOSURE(s->type)) ret->parameters[0] = s->context;
-#endif
- next_token(s);
- if (s->type == TOK_OPEN) {
- next_token(s);
- if (s->type != TOK_CLOSE) {
- s->type = TOK_ERROR;
- } else {
- next_token(s);
- }
- }
- break;
-#endif
-
- case TE_FUNCTION1:
-#ifndef TE_WITHOUT_CLOSURES
- case TE_CLOSURE1:
-#endif
- ret = new_expr(s->type, 0);
- ret->v.any = s->v.any;
-#ifndef TE_WITHOUT_CLOSURES
- if (IS_CLOSURE(s->type)) ret->parameters[1] = s->context;
-#endif
- next_token(s);
- ret->parameters[0] = power(s);
- break;
-
- case TE_FUNCTION2: case TE_FUNCTION3:
-#if TE_MAX_FUNCTION_ARITY >= 4
- case TE_FUNCTION4:
-#endif
-#if TE_MAX_FUNCTION_ARITY >= 5
- case TE_FUNCTION5:
-#endif
-#if TE_MAX_FUNCTION_ARITY >= 6
- case TE_FUNCTION6:
-#endif
-#if TE_MAX_FUNCTION_ARITY == 7
- case TE_FUNCTION7:
-#endif
-#ifndef TE_WITHOUT_CLOSURES
- case TE_CLOSURE2: case TE_CLOSURE3: case TE_CLOSURE4:
- case TE_CLOSURE5: case TE_CLOSURE6: case TE_CLOSURE7:
-#endif
- arity = ARITY(s->type);
-
- ret = new_expr(s->type, 0);
- ret->v.any = s->v.any;
-#ifndef TE_WITHOUT_CLOSURES
- if (IS_CLOSURE(s->type)) ret->parameters[arity] = s->context;
-#endif
- next_token(s);
-
- if (s->type != TOK_OPEN) {
- s->type = TOK_ERROR;
- } else {
- int i;
- for(i = 0; i < arity; i++) {
- next_token(s);
- ret->parameters[i] = eql(s);
- if(s->type != TOK_SEP) {
- break;
- }
- }
- if(s->type != TOK_CLOSE || i != arity - 1) {
- s->type = TOK_ERROR;
- } else {
- next_token(s);
- }
- }
-
- break;
-
- case TOK_OPEN:
- next_token(s);
- ret = list(s);
- if (s->type != TOK_CLOSE) {
- s->type = TOK_ERROR;
- } else {
- next_token(s);
- }
- break;
-
- default:
- ret = new_expr(0, 0);
- s->type = TOK_ERROR;
- ret->v.value = NAN;
- break;
- }
-
- return ret;
-}
-
-
-static te_expr *power(state *s) {
- /* <power> = {("-" | "+")} <base> */
- int sign = 1;
- while (s->type == TOK_INFIX && (s->v.f2 == add || s->v.f2 == sub)) {
- if (s->v.f2 == sub) sign = -sign;
- next_token(s);
- }
-
- te_expr *ret;
-
- if (sign == 1) {
- ret = base(s);
- } else {
- ret = new_expr1(TE_FUNCTION1 | TE_FLAG_PURE, base(s));
- ret->v.f1 = negate;
- }
-
- return ret;
-}
-
-#ifdef TE_POW_FROM_RIGHT
-static te_expr *factor(state *s) {
- /* <factor> = <power> {"^" <power>} */
- te_expr *ret = power(s);
-
- int neg = 0;
- te_expr *insertion = 0;
-
- if (ret->type == (TE_FUNCTION1 | TE_FLAG_PURE) && ret->v.f1 == negate) {
- te_expr *se = ret->parameters[0];
- free(ret);
- ret = se;
- neg = 1;
- }
-
- while (s->type == TOK_INFIX && (s->v.f2 == pow)) {
- te_fun2 t = s->v.f2;
- next_token(s);
-
- if (insertion) {
- /* Make exponentiation go right-to-left. */
- te_expr *insert = new_expr2(TE_FUNCTION2 | TE_FLAG_PURE, insertion->parameters[1], power(s));
- insert->v.f2 = t;
- insertion->parameters[1] = insert;
- insertion = insert;
- } else {
- ret = new_expr2(TE_FUNCTION2 | TE_FLAG_PURE, ret, power(s));
- ret->v.f2 = t;
- insertion = ret;
- }
- }
-
- if (neg) {
- ret = new_expr1(TE_FUNCTION1 | TE_FLAG_PURE, ret);
- ret->v.f1 = negate;
- }
-
- return ret;
-}
-#else
-static te_expr *factor(state *s) {
- /* <factor> = <power> {"^" <power>} */
- te_expr *ret = power(s);
-
- while (s->type == TOK_INFIX && (s->v.f2 == pow)) {
- te_fun2 t = s->v.f2;
- next_token(s);
- ret = new_expr2(TE_FUNCTION2 | TE_FLAG_PURE, ret, power(s));
- ret->v.f2 = t;
- }
-
- return ret;
-}
-#endif
-
-
-
-static te_expr *term(state *s) {
- /* <term> = <factor> {("*" | "/" | "%") <factor>} */
- te_expr *ret = factor(s);
-
- while (s->type == TOK_INFIX && (s->v.f2 == mul || s->v.f2 == divide || s->v.f2 == fmod)) {
- te_fun2 t = s->v.f2;
- next_token(s);
- ret = new_expr2(TE_FUNCTION2 | TE_FLAG_PURE, ret, factor(s));
- ret->v.f2 = t;
- }
-
- return ret;
-}
-
-
-static te_expr *expr(state *s) {
- /* <expr> = <term> {("+" | "-") <term>} */
- te_expr *ret = term(s);
-
- while (s->type == TOK_INFIX && (s->v.f2 == add || s->v.f2 == sub)) {
- te_fun2 t = s->v.f2;
- next_token(s);
- ret = new_expr2(TE_FUNCTION2 | TE_FLAG_PURE, ret, term(s));
- ret->v.f2 = t;
- }
-
- return ret;
-}
-
-
-static te_expr *cmp(state *s) {
- /* <cmp> = <expr> {(">" | "<" | ">=" | "<=") <expr>} */
- te_expr *ret = expr(s);
-
- while (s->type == TOK_INFIX
- && (s->v.f2 == is_lt || s->v.f2 == is_le || s->v.f2 == is_gt || s->v.f2 == is_ge)) {
- te_fun2 t = s->v.f2;
- next_token(s);
- ret = new_expr2(TE_FUNCTION2 | TE_FLAG_PURE, ret, expr(s));
- ret->v.f2 = t;
- }
-
- return ret;
-}
-
-
-static te_expr *eql(state *s) {
- /* <eql> = <cmp> {("==" | "!=") <cmp>} */
- te_expr *ret = cmp(s);
-
- while (s->type == TOK_INFIX && (s->v.f2 == is_eq || s->v.f2 == is_neq)) {
- te_fun2 t = s->v.f2;
- next_token(s);
- ret = new_expr2(TE_FUNCTION2 | TE_FLAG_PURE, ret, cmp(s));
- ret->v.f2 = t;
- }
-
- return ret;
-}
-
-
-static te_expr *list(state *s) {
- /* <list> = <eql> {"," <eql>} */
- te_expr *ret = eql(s);
-
- while (s->type == TOK_SEP) {
- next_token(s);
- ret = new_expr2(TE_FUNCTION2 | TE_FLAG_PURE, ret, eql(s));
- ret->v.f2 = comma;
- }
-
- return ret;
-}
-
-
-#define M(e) te_eval(n->parameters[e], base_addr)
-
-
-double te_eval(const te_expr *n, const void* base_addr) {
- if (!n) return NAN;
-
- switch(TYPE_MASK(n->type)) {
- case TE_CONSTANT: return n->v.value;
- case TE_VARIABLE: return *n->v.bound;
- case TE_OFFSET: assert(base_addr);
- return *(double*)(((char*)base_addr)+n->v.offset);
-
-#ifndef TE_WITHOUT_FUNCTION_0
- case TE_FUNCTION0: return n->v.f0();
-#endif
- case TE_FUNCTION1: return n->v.f1(M(0));
- case TE_FUNCTION2: return n->v.f2(M(0), M(1));
- case TE_FUNCTION3:
- if (IS_CONDITION(n->type)) return M(0) ? M(1) : M(2);
- else return n->v.f3(M(0), M(1), M(2));
-#if TE_MAX_FUNCTION_ARITY >= 4
- case TE_FUNCTION4: return n->v.f4(M(0), M(1), M(2), M(3));
-#endif
-#if TE_MAX_FUNCTION_ARITY >= 5
- case TE_FUNCTION5: return n->v.f5(M(0), M(1), M(2), M(3), M(4));
-#endif
-#if TE_MAX_FUNCTION_ARITY >= 6
- case TE_FUNCTION6: return n->v.f6(M(0), M(1), M(2), M(3), M(4), M(5));
-#endif
-#if TE_MAX_FUNCTION_ARITY == 7
- case TE_FUNCTION7: return n->v.f7(M(0), M(1), M(2), M(3), M(4), M(5), M(6));
-#endif
-
-#ifndef TE_WITHOUT_CLOSURES
- case TE_CLOSURE0: return n->v.cl0(n->parameters[0]);
- case TE_CLOSURE1: return n->v.cl1(n->parameters[1], M(0));
- case TE_CLOSURE2: return n->v.cl2(n->parameters[2], M(0), M(1));
- case TE_CLOSURE3: return n->v.cl3(n->parameters[3], M(0), M(1), M(2));
- case TE_CLOSURE4: return n->v.cl4(n->parameters[4], M(0), M(1), M(2), M(3));
- case TE_CLOSURE5: return n->v.cl5(n->parameters[5], M(0), M(1), M(2), M(3), M(4));
- case TE_CLOSURE6: return n->v.cl6(n->parameters[6], M(0), M(1), M(2), M(3), M(4), M(5));
- case TE_CLOSURE7: return n->v.cl7(n->parameters[7], M(0), M(1), M(2), M(3), M(4), M(5), M(6));
-#endif
-
- default: return NAN;
- }
-
-}
-
-#undef M
-
-static int expr_equal(const te_expr* e1, const te_expr* e2) {
- int i;
- if (e1->type != e2->type) return 0;
- if (e1->v.any != e2->v.any) return 0;
- for (i = 0; i < ARITY(e1->type); i++) {
- if(!expr_equal(e1->parameters[i], e2->parameters[i])) return 0;
- }
- return 1;
-}
-
-static void optimize(te_expr *n) {
- /* Only optimize out conditions and functions flagged as pure. */
- if (IS_CONDITION(n->type)) {
- te_expr* cond = n->parameters[0];
- assert(IS_FUNCTION(n->type) && ARITY(n->type) == 3);
- optimize(cond);
- if (cond->type == TE_CONSTANT) {
- te_expr* keep = (cond->v.value) ? n->parameters[1] : n->parameters[2];
- /* Can keep either param[1] or param[2] */
- optimize(keep);
- n->type = keep->type;
- n->v.any = keep->v.any;
- te_free_parameters(n);
- }
- else { /* c ? x : x is x */
- te_expr* if_branch = n->parameters[1];
- te_expr* else_branch = n->parameters[2];
- optimize(if_branch);
- optimize(else_branch);
- if (expr_equal(if_branch, else_branch)) {
- n->type = if_branch->type;
- n->v.any = if_branch->v.any;
- te_free_parameters(n);
- }
- }
- }
- else if (IS_PURE(n->type)) {
- const int arity = ARITY(n->type);
- int known = 1;
- int i;
- assert(IS_FUNCTION(n->type));
- for (i = 0; i < arity; ++i) {
- optimize(n->parameters[i]);
- if (((te_expr*)(n->parameters[i]))->type != TE_CONSTANT) {
- known = 0;
- }
- }
- if (known) {
- const double value = te_eval(n, NULL);
- te_free_parameters(n);
- n->type = TE_CONSTANT;
- n->v.value = value;
- }
- }
-}
-
-
-te_expr *te_compile(const char *expression, const te_variable *variables, int var_count, int *error) {
- state s;
- s.start = s.next = expression;
- s.lookup = variables;
- s.lookup_len = var_count;
-
- next_token(&s);
- te_expr *root = list(&s);
-
- if (s.type != TOK_END) {
- te_free(root);
- if (error) {
- *error = (int)(s.next - s.start);
- if (*error == 0) *error = 1;
- }
- return 0;
- } else {
- optimize(root);
- if (error) *error = 0;
- return root;
- }
-}
-
-
-double te_interp(const char *expression, int *error) {
- te_expr *n = te_compile(expression, 0, 0, error);
- double ret;
- if (n) {
- ret = te_eval(n, NULL);
- te_free(n);
- } else {
- ret = NAN;
- }
- return ret;
-}
-
-static void pn (const te_expr *n, int depth) {
- int i, arity;
- printf("%*s", depth, "");
-
- switch(TYPE_MASK(n->type)) {
- case TE_CONSTANT: printf("%f\n", n->v.value); break;
- case TE_VARIABLE: printf("bound %p\n", (void*) n->v.bound); break;
- case TE_OFFSET: printf("offset %zu\n", n->v.offset); break;
-
-#ifndef TE_WITHOUT_FUNCTION_0
- case TE_FUNCTION0:
-#endif
- case TE_FUNCTION1: case TE_FUNCTION2: case TE_FUNCTION3:
-#if TE_MAX_FUNCTION_ARITY >= 4
- case TE_FUNCTION4:
-#endif
-#if TE_MAX_FUNCTION_ARITY >= 5
- case TE_FUNCTION5:
-#endif
-#if TE_MAX_FUNCTION_ARITY >= 6
- case TE_FUNCTION6:
-#endif
-#if TE_MAX_FUNCTION_ARITY == 7
- case TE_FUNCTION7:
-#endif
-#ifndef TE_WITHOUT_CLOSURES
- case TE_CLOSURE0: case TE_CLOSURE1: case TE_CLOSURE2: case TE_CLOSURE3:
- case TE_CLOSURE4: case TE_CLOSURE5: case TE_CLOSURE6: case TE_CLOSURE7:
-#endif
- arity = ARITY(n->type);
- printf("f%d", arity);
- for(i = 0; i < arity; i++) {
- printf(" %p", n->parameters[i]);
- }
- printf("\n");
- for(i = 0; i < arity; i++) {
- pn(n->parameters[i], depth + 1);
- }
- break;
- }
-}
-
-
-void te_print(const te_expr *n) {
- pn(n, 0);
-}
diff --git a/tinyexpr/tinyexpr.h b/tinyexpr/tinyexpr.h
@@ -1,197 +0,0 @@
-/*
- * TINYEXPR - Tiny recursive descent parser and evaluation engine in C
- *
- * Copyright (c) 2015-2018 Lewis Van Winkle
- *
- * http://CodePlea.com
- *
- * This software is provided 'as-is', without any express or implied
- * warranty. In no event will the authors be held liable for any damages
- * arising from the use of this software.
- *
- * Permission is granted to anyone to use this software for any purpose,
- * including commercial applications, and to alter it and redistribute it
- * freely, subject to the following restrictions:
- *
- * 1. The origin of this software must not be misrepresented; you must not
- * claim that you wrote the original software. If you use this software
- * in a product, an acknowledgement in the product documentation would be
- * appreciated but is not required.
- * 2. Altered source versions must be plainly marked as such, and must not be
- * misrepresented as being the original software.
- * 3. This notice may not be removed or altered from any source distribution.
- */
-
-#ifndef __TINYEXPR_H__
-#define __TINYEXPR_H__
-
-#include <stddef.h>
-
-/* Helper macro to be used when defining a te_variable */
-#define TE_DEF_VARIABLE(Name, Var) {(Name), {.var=&(Var)}, TE_VARIABLE, NULL}
-#define TE_DEF_OFFSET(Name, Offset) {(Name), {.offset=(Offset)}, TE_OFFSET, NULL}
-#define TE_DEF_CONSTANT(Name, Value) {(Name), {.value=(Value)}, TE_CONSTANT, NULL}
-#define TE_DEF_FUNCTION(Name, Fun, Arity) {(Name), {.f##Arity=(Fun)}, TE_FUNCTION##Arity, NULL}
-#ifndef TE_WITHOUT_CLOSURES
-#define TE_DEF_CLOSURE(Name, Closure, Arity, Ctx) {(Name), {.cl##Arity=(Closure)}, TE_CLOSURE##Arity, (Ctx)}
-#endif
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#ifdef TE_MAX_FUNCTION_ARITY
-#if !(TE_MAX_FUNCTION_ARITY >= 3 && TE_MAX_FUNCTION_ARITY <= 7)
-#error Valid range for TE_MAX_FUNCTION_ARITY is [3 7]
-#endif
-#else
-#define TE_MAX_FUNCTION_ARITY 7
-#endif
-
-
-#ifndef TE_WITHOUT_FUNCTION_0
-#define FUN_TYPE_0 \
- double(*f0)(void);
-#else
-#define FUN_TYPE_0
-#endif
-#define FUN_TYPES_1_3 \
- void *any;\
- double(*f1)(double);\
- double(*f2)(double, double);\
- double(*f3)(double, double, double);
-#if TE_MAX_FUNCTION_ARITY >= 4
-#define FUN_TYPE_4 \
- double(*f4)(double, double, double, double);
-#else
-#define FUN_TYPE_4
-#endif
-#if TE_MAX_FUNCTION_ARITY >= 5
-#define FUN_TYPE_5 \
- double(*f5)(double, double, double, double, double);
-#else
-#define FUN_TYPE_5
-#endif
-#if TE_MAX_FUNCTION_ARITY >= 6
-#define FUN_TYPE_6 \
- double(*f6)(double, double, double, double, double, double);
-#else
-#define FUN_TYPE_6
-#endif
-#if TE_MAX_FUNCTION_ARITY == 7
-#define FUN_TYPE_7 \
- double(*f7)(double, double, double, double, double, double, double);
-#else
-#define FUN_TYPE_7
-#endif
-
-#ifndef TE_WITHOUT_CLOSURES
-#define CLOSURE_TYPES \
- double(*cl0)(void*);\
- double(*cl1)(void*, double);\
- double(*cl2)(void*, double, double);\
- double(*cl3)(void*, double, double, double);\
- double(*cl4)(void*, double, double, double, double);\
- double(*cl5)(void*, double, double, double, double, double);\
- double(*cl6)(void*, double, double, double, double, double, double);\
- double(*cl7)(void*, double, double, double, double, double, double, double);
-#else
-#define CLOSURE_TYPES
-#endif
-
-union fun {
- FUN_TYPE_0
- FUN_TYPES_1_3
- FUN_TYPE_4
- FUN_TYPE_5
- FUN_TYPE_6
- FUN_TYPE_7
- CLOSURE_TYPES
-};
-
-union value {
- FUN_TYPE_0
- FUN_TYPES_1_3
- FUN_TYPE_4
- FUN_TYPE_5
- FUN_TYPE_6
- FUN_TYPE_7
- CLOSURE_TYPES
- double value;
- const double *var;
- size_t offset;
- const double *bound;
-};
-
-typedef struct te_expr {
- int type;
- union value v;
- void *parameters[1];
-} te_expr;
-
-
-enum {
- TE_VARIABLE = 0,
- TE_OFFSET = 1,
- TE_CONSTANT = 2,
-
-#ifndef TE_WITHOUT_FUNCTION_0
- TE_FUNCTION0 = 8,
-#endif
- TE_FUNCTION1 = 9, TE_FUNCTION2, TE_FUNCTION3,
-#if TE_MAX_FUNCTION_ARITY >= 4
- TE_FUNCTION4,
-#endif
-#if TE_MAX_FUNCTION_ARITY >= 5
- TE_FUNCTION5,
-#endif
-#if TE_MAX_FUNCTION_ARITY >= 6
- TE_FUNCTION6,
-#endif
-#if TE_MAX_FUNCTION_ARITY == 7
- TE_FUNCTION7,
-#endif
-#ifndef TE_WITHOUT_CLOSURES
- TE_CLOSURE0 = 16, TE_CLOSURE1, TE_CLOSURE2, TE_CLOSURE3,
- TE_CLOSURE4, TE_CLOSURE5, TE_CLOSURE6, TE_CLOSURE7,
-#endif
- TE_FLAG_PURE = 64
-};
-
-typedef struct te_variable {
- const char *name;
- const union value v;
- int type;
- /* context could be member only if TE_WITHOUT_CLOSURES is undefined
- * we don't take the opportunity as it would add too much complexity */
- void *context;
-} te_variable;
-
-
-
-/* Parses the input expression, evaluates it, and frees it. */
-/* Returns NaN on error. */
-double te_interp(const char *expression, int *error);
-
-/* Parses the input expression and binds variables. */
-/* Returns NULL on error. */
-te_expr *te_compile(const char *expression, const te_variable *variables, int var_count, int *error);
-
-/* Evaluates the expression. */
-double te_eval(const te_expr *n, const void* base_addr);
-
-/* Prints debugging information on the syntax tree. */
-void te_print(const te_expr *n);
-
-/* Frees the expression. */
-/* This is safe to call on NULL pointers. */
-void te_free(te_expr *n);
-
-/* Duplicates a te_expr */
-te_expr* te_duplicate(te_expr* n);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /*__TINYEXPR_H__*/