stardis

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

commit 7931abdb3a38702965db98487207b7d59f15be91
parent 806c14f4e28b2f73471c19e88d8b9fda4091d7d6
Author: Christophe Coustet <christophe.coustet@meso-star.com>
Date:   Mon, 14 Mar 2022 10:08:07 +0100

Merge branch 'release_0.8'

Diffstat:
MREADME.md | 17++++++++++++++++-
Mcmake/CMakeLists.txt | 55++++++++++++++++++++++++++++++++++++++++++++-----------
Acmake/stardis-green-types/CMakeLists.txt | 53+++++++++++++++++++++++++++++++++++++++++++++++++++++
Mdoc/stardis-input.5.txt | 32++++++++++++++++++++++----------
Mdoc/stardis-output.5.txt | 217++++++++++++++++++++++++++-----------------------------------------------------
Mdoc/stardis.1.txt.in | 65+++++++++++++++++++++++++++++++++++++++++++----------------------
Msrc/stardis-app.c | 157+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--------------
Msrc/stardis-app.h | 504++++++++++++++++++++++++++++++++++++++++++++-----------------------------------
Asrc/stardis-args.c | 986+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/stardis-args.h | 141+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Msrc/stardis-compute.c | 567+++++++++++++++++++++++++++++++++++++++++++------------------------------------
Msrc/stardis-compute.h | 2+-
Msrc/stardis-default.h.in | 5+++--
Msrc/stardis-fluid.c | 97++++++++++++++++++++++++++++++++++++++++++-------------------------------------
Msrc/stardis-fluid.h | 14+++++++-------
Asrc/stardis-green-types.h.in | 129+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Msrc/stardis-intface.c | 77++++++++++++++++++++++++++++++++++++++++++++++-------------------------------
Msrc/stardis-intface.h | 3++-
Msrc/stardis-main.c | 16++++++++++++++--
Msrc/stardis-output.c | 542+++++++++++++++++++++++++++++++++++++++++++++++++------------------------------
Msrc/stardis-output.h | 4++--
Msrc/stardis-parsing.c | 1355++++++++++++++++++-------------------------------------------------------------
Msrc/stardis-parsing.h | 139++++---------------------------------------------------------------------------
Msrc/stardis-solid.c | 121++++++++++++++++++++++++++++++++++++++++---------------------------------------
Msrc/stardis-solid.h | 16++++++++--------
Astardis-green-types/stardis-green-types-config-version.cmake.in | 22++++++++++++++++++++++
Astardis-green-types/stardis-green-types-config.cmake | 28++++++++++++++++++++++++++++
27 files changed, 3110 insertions(+), 2254 deletions(-)

diff --git a/README.md b/README.md @@ -22,7 +22,10 @@ It also depends on the [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. +parallelize its computations. It may depend on +[OpenMPI](https://www.open-mpi.org/) 2.0 if distributed memory parallelism +is enabled via the `ENABLE_MPI` variable of the CMake file. + First ensure that CMake and a C compiler are installed on your system. @@ -33,6 +36,18 @@ variable the install directories of its dependencies. ## Release notes +## Version 0.8 + +- Add a new option to support non-linear radiative transfer computations. +- Changes in input file's format to support non-linear radiative transfer by + adding reference temperatures on interfaces. +- Add optional support for MPI (must be enabled at compile time, default is OFF). +- Change random number generator type to use Threefry. +- Change the format of binary Green files. A new public header file is now + installed that describes all types involved in binary Green files. +- Fix a crash on an exit-on-error execution path. +- Fix parsing of command-line options. + ### Version 0.7.2 Fix the binary file format of the green function: the fileformat has been diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt @@ -1,4 +1,4 @@ -# Copyright (C) 2018-2021 |Meso|Star> (contact@meso-star.com) +# Copyright (C) 2018-2022 |Meso|Star> (contact@meso-star.com) # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -17,6 +17,12 @@ cmake_minimum_required(VERSION 3.0) project(stardis C) set(SDIS_SOURCE_DIR ${PROJECT_SOURCE_DIR}/../src) +set(SDIS_SGT_DIR ${PROJECT_SOURCE_DIR}/../stardis-green-types) + + +option(ENABLE_MPI + "Enable the support of distributed parallelism \ +using the Message Passing Interface specification." OFF) if(CMAKE_HOST_UNIX) set(STARDIS_DOC "TROFF" CACHE STRING @@ -35,8 +41,10 @@ set_property(CACHE STARDIS_DOC PROPERTY STRINGS ############################################################################### # Generate files ############################################################################### -set(STARDIS_ARGS_DEFAULT_AMBIENT_TEMP "300") +set(STARDIS_ARGS_DEFAULT_TRAD "300") +set(STARDIS_ARGS_DEFAULT_TRAD_REFERENCE "300") set(STARDIS_ARGS_DEFAULT_COMPUTE_TIME "INF") +set(STARDIS_ARGS_DEFAULT_PICARD_ORDER "1") set(STARDIS_ARGS_DEFAULT_RENDERING_FOV "70") # degrees set(STARDIS_ARGS_DEFAULT_RENDERING_IMG_HEIGHT "480") set(STARDIS_ARGS_DEFAULT_RENDERING_IMG_WIDTH "640") @@ -46,7 +54,6 @@ 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") @@ -55,8 +62,8 @@ 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 7) -set(SDIS_VERSION_PATCH 2) +set(SDIS_VERSION_MINOR 8) +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 @@ -65,20 +72,34 @@ configure_file(${SDIS_SOURCE_DIR}/stardis-default.h.in configure_file(${SDIS_SOURCE_DIR}/stardis-version.h.in ${CMAKE_CURRENT_BINARY_DIR}/stardis-version.h @ONLY) +set(STARDIS_GREEN_TYPES_VERSION "4") + +configure_file(${SDIS_SOURCE_DIR}/stardis-green-types.h.in + ${CMAKE_CURRENT_BINARY_DIR}/stardis-green-types/stardis-green-types.h @ONLY) + +configure_file(${SDIS_SGT_DIR}/stardis-green-types-config-version.cmake.in + ${CMAKE_CURRENT_BINARY_DIR}/stardis-green-types/stardis-green-types-config-version.cmake @ONLY) + ############################################################################### # Check dependencies ############################################################################### -find_package(RCMake 0.4.1 REQUIRED) +find_package(RCMake 0.4 REQUIRED) find_package(RSys 0.12 REQUIRED) find_package(StarGeom3D 0.1 REQUIRED) find_package(Star3D 0.8 REQUIRED) -find_package(StarEnc3D 0.5.3 REQUIRED) -find_package(Stardis 0.12 REQUIRED) -find_package(StarSTL 0.3.3 REQUIRED) -find_package(StarSP 0.12 REQUIRED) +find_package(StarEnc3D 0.5 REQUIRED) +find_package(Stardis 0.13 REQUIRED) +find_package(StarSTL 0.3 REQUIRED) +find_package(StarSP 0.13 REQUIRED) if(MSVC) find_package(MuslGetopt REQUIRED) endif() +if(ENABLE_MPI) + find_package(MPI 2 REQUIRED) + set(CMAKE_C_COMPILER ${MPI_C_COMPILER}) + include_directories(${MPI_INCLUDE_PATH}) +endif() + include_directories( ${RSys_INCLUDE_DIR} @@ -88,7 +109,8 @@ include_directories( ${Stardis_INCLUDE_DIR} ${StarSTL_INCLUDE_DIR} ${StarSP_INCLUDE_DIR} - ${CMAKE_CURRENT_BINARY_DIR}) + ${CMAKE_CURRENT_BINARY_DIR} + ${CMAKE_CURRENT_BINARY_DIR}/stardis-green-types) if(MSVC) include_directories(${MuslGetopt_INCLUDE_DIR}) endif() @@ -113,11 +135,14 @@ if(NOT STARDIS_DOC STREQUAL "NONE") add_subdirectory(doc) endif() +add_subdirectory(stardis-green-types) + ############################################################################### # Configure and define targets ############################################################################### set(SDIS_FILES_SRC stardis-app.c + stardis-args.c stardis-compute.c stardis-fluid.c stardis-intface.c @@ -128,9 +153,11 @@ set(SDIS_FILES_SRC set(SDIS_FILES_INC stardis-app.h + stardis-args.h stardis-compute.h stardis-default.h.in stardis-fluid.h + stardis-green-types.h.in stardis-intface.h stardis-output.h stardis-parsing.h @@ -160,6 +187,10 @@ set_target_properties(stardis target_link_libraries(stardis Stardis Star3D StarGeom3D StarEnc3D StarSTL StarSP RSys ${GETOPT_LIB} ${MATH_LIB}) +if(ENABLE_MPI) + set_target_properties(stardis PROPERTIES COMPILE_DEFINITIONS "STARDIS_ENABLE_MPI") +endif() + ############################################################################### # Define output & install directories ############################################################################### @@ -169,5 +200,7 @@ install(TARGETS stardis RUNTIME DESTINATION bin) install(FILES ${SDIS_FILES_DOC} DESTINATION share/doc/stardis) +install(FILES ${CMAKE_CURRENT_BINARY_DIR}/stardis-version.h + DESTINATION include/stardis) rcmake_copy_runtime_libraries(stardis) diff --git a/cmake/stardis-green-types/CMakeLists.txt b/cmake/stardis-green-types/CMakeLists.txt @@ -0,0 +1,53 @@ +# Copyright (C) 2018-2021 |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/>. + +cmake_minimum_required(VERSION 3.0) + +set(STARDIS_SGT_DIR ${PROJECT_SOURCE_DIR}/../stardis-green-types) + +################################################################################ +# Copy stardis-green-types CMake files +################################################################################ +set(SGT_NAMES + stardis-green-types-config) + +set(SGT_FILES) +foreach(_name IN LISTS SGT_NAMES) + set(_src ${STARDIS_SGT_DIR}/${_name}.cmake) + set(_dst ${CMAKE_CURRENT_BINARY_DIR}/${_name}.cmake) + add_custom_command( + OUTPUT ${_dst} + COMMAND ${CMAKE_COMMAND} -E copy ${_src} ${_dst} + DEPENDS ${_src} + COMMENT "Copy the CMake file ${_src}" + VERBATIM) + list(APPEND SGT_FILES ${_dst}) +endforeach() +add_custom_target(sgt-cmake ALL DEPENDS ${SGT_FILES}) + +################################################################################ +# Install stardis-green-types CMake Files +################################################################################ +list(APPEND SGT_FILES ${CMAKE_CURRENT_BINARY_DIR}/stardis-green-types-config-version.cmake) + +install(FILES ${SGT_FILES} + DESTINATION lib/cmake/stardis-green-types) + +################################################################################ +# Install stardis-green-types header Files +################################################################################ +install(FILES + ${CMAKE_CURRENT_BINARY_DIR}/stardis-green-types.h + DESTINATION include/stardis/) diff --git a/doc/stardis-input.5.txt b/doc/stardis-input.5.txt @@ -76,7 +76,6 @@ description. [verse] _______ <thermal-system> ::= <description-lines> - [ <scaling-factor> ] <description-lines> ::= <description-line> [ <description-lines> ] @@ -84,8 +83,8 @@ _______ <description-line> ::= [ <medium-frontier> ] [ <comment> ] | [ <medium-boundary> ] [ <comment> ] | [ <media-connection> ] [ <comment> ] - -<scaling-factor> ::= "SCALE" <scaling_factor> [ <comment> ] + | [ <scaling-factor> ] [ <comment> ] # at most once + | [ <radiative-temps> ] [ <comment > ] # at most once ------------------------------------- @@ -117,22 +116,26 @@ _______ <triangles> -<h-bound-for-solid> ::= "H_BOUNDARY_FOR_SOLID" <bound-name> <emissivity> \ +<h-bound-for-solid> ::= "H_BOUNDARY_FOR_SOLID" <bound-name> <Tref> <emissivity> \ <specular-fraction> <hc> <outside-temperature> \ <triangles> -<h-bound-for-fluid> ::= "H_BOUNDARY_FOR_FLUID" <bound-name> <emissivity> \ +<h-bound-for-fluid> ::= "H_BOUNDARY_FOR_FLUID" <bound-name> <Tref> <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> \ +<solid-fluid-connect> ::= "SOLID_FLUID_CONNECTION" <bound-name> <Tref> <emissivity> \ <specular-fraction> <hc> <triangles> <solid-solid-connect> ::= "SOLID_SOLID_CONNECTION" <bound-name> \ <contact-resistance> <triangles> +<scaling-factor> ::= "SCALE" <scaling_factor> [ <comment> ] + +<radiative-temps> ::= "TRAD" <radiative-temp> <radiative-temp-ref> + ------------------------------------- <medium-name> ::= STRING # no space allowed, must not be parsable as a @@ -163,6 +166,8 @@ _______ <bound-name> ::= STRING # no space allowed +<Tref> ::= REAL # in [0, inf) + <emissivity> ::= REAL # in [0, 1] <specular-fraction> ::= REAL # in [0, 1] @@ -175,6 +180,10 @@ _______ <triangles> ::= <file-name> [ <triangles> ] +<radiative-temp> ::= REAL # in [0, inf) + +<radiative-temp-ref> ::= REAL # in [0, inf) + ------------------------------------- <side-specifier> ::= "FRONT" | "BACK" | "BOTH" @@ -199,11 +208,12 @@ one or ore ASCII characters, including numbers and special characters like spacing* either escaped or not. Names are case-sensitive and two different description lines, either in the same description file or from different description files, cannot use the same name. Additionaly, medium and boundary -names cannot be parsable as a number, nor be one of the few keywords defined +names cannot be parsable as a number, nor be one of the keywords defined by the present grammar (AUTO, BACK, BOTH, FLUID, FRONT, F_BOUNDARY_FOR_SOLID, H_BOUNDARY_FOR_FLUID, H_BOUNDARY_FOR_SOLID, SCALE, SOLID, SOLID_FLUID_CONNECTION, T_BOUNDARY_FOR_FLUID, T_BOUNDARY_FOR_SOLID, UNKNOWN) or -their lowercase counterparts. +their lowercase counterparts. Finally, description names cannot be longer than +63 characters. EXAMPLES -------- @@ -212,10 +222,12 @@ 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. +external-temperature = 100°K, while the reference temperature for radiative +transfer linearization in the Picard algorithm is set to 300°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 +H_BOUNDARY_FOR_SOLID HdT 300 0 0 10 100 cube.stl ....... SEE ALSO diff --git a/doc/stardis-output.5.txt b/doc/stardis-output.5.txt @@ -210,7 +210,7 @@ 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. +ambient radiative temperature (Trad). The output in green mode is made of tables containing the different media and boundaries and their imposed temperature, flux and volumic power values, @@ -222,38 +222,40 @@ 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; +* Get the temperature of the ending boundary, medium or Trad; * 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. +Binary Green outputs are formated according to the various C types from the +*stardis-green.h* header file. The output begins with a header (of type struct +green_file_header) that includes counts, followed by descriptions (of type +struct green_description) and samples. 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] +<binary-green> ::= "GREEN_BIN_FILE:" # char[16] + <file_format_version> # unsigned #descriptions # unsigned #solids # unsigned #fluids # unsigned - #t-boundaries # unsigned #h-boundaries # unsigned - #flux-boundaries # unsigned + #t-boundaries # unsigned + #f-boundaries # unsigned #solid-fluid-connections # unsigned - names-pool-size # size of concatenated description names - # unsigned + #solid-solid-connections # unsigned #ok-samples # size_t #failed-samples # size_t - <descriptions> - <concatenated-names> # char[names-pool-size] - ambient-temperature # double - reference-temperature # double + Trad # double + Trad-reference # double time-range # double[2] + <descriptions> <samples> -<descriptions> ::= description # struct description +<descriptions> ::= description # struct green_description <descriptions> # #descriptions descriptions <samples> ::= <sample> @@ -261,111 +263,11 @@ _______ --------------------- -<sample> ::= <sample-header> # struct path_header - <ids> # unsigned[header.pcount + header.fcount] - <weights> # double[header.pcount + header.fcount] +<sample> ::= <sample-header> # struct green_sample_header + <ids> # unsigned[header.pw_count then header.fx_count] + <weights> # double[header.pw_count then header.fx_count] _______ -[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 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_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 @@ -390,13 +292,13 @@ _______ "# ID Name temperature" <t-bounds> "# H Boundaries" - "# ID Name emissivity specular_fraction hc T_env" + "# ID Name ref_temperature emissivity specular_fraction hc T_env" <h-bounds> "# F Boundaries" "# ID Name flux" <f-bounds> - "# Radiative Temperatures" - "# ID Rad_Temp Lin_Temp" + "# Radiative Temperature" + "# ID Rad_Temp" <rad-temps> "# Samples" "# end #power_terms #flux_terms power_term_1 ... \ @@ -425,7 +327,7 @@ _______ <f-bounds> ::= <f-bound> <f-bounds> # #f-bounds f-bound descriptions -<rad-temps> ::= <green-id> <rad-temp> <lin-temp> +<rad-temps> ::= <green-id> <Trad> <Trad-ref> <samples> ::= <sample> <samples> # #samples sample descriptions @@ -443,12 +345,11 @@ _______ <t-bound> ::= <green-id> <name> <temperature> -<h-bound> ::= <green-id> <name> <emissivity> <specular_fraction> \ - <hc> <temperature> +<h-bound> ::= <green-id> <name> <ref_temperature> <emissivity> \ + <specular_fraction> <hc> <temperature> <f-bound> ::= <green-id> <name> <flux> -<rad-temps> ::= <green-id> <ambient-temp> <lin-temp> <name> ::= STRING # no space allowed @@ -468,6 +369,8 @@ _______ <temperature> ::= REAL # in [0, INF) +<ref-temperature> ::= REAL # in [0, INF) + <emissivity> ::= REAL # in [0, 1] <specular-fraction> ::= REAL # in [0, 1] @@ -476,9 +379,9 @@ _______ <flux> ::= REAL # in (-INF, INF) -<ambient-temp> ::= REAL # in [0, INF) +<Trad> ::= REAL # in [0, INF) -<lin-temp> ::= REAL # in [0, INF) +<Trad-ref> ::= REAL # in [0, INF) <green-id> ::= INTEGER # in [0 #green-sources[ @@ -488,7 +391,7 @@ _______ <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 + | "R" # sample ends with Trad | "F" # sample ends in a fluid with known temperature | "S" # sample ends in a solid with known temperature @@ -540,11 +443,11 @@ _______ ------------------------------------- <end-name> ::= STRING # the name of the boundary at the end of the - # heat path, or AMBIENT for radiative ending + # heat path, or TRAD for radiative ending <end-id> ::= INTEGER # in [0 #boundaries] # order is the order in the description file, - # AMBIENT's id being #boundaries + # TRAD's id being #boundaries <x> ::= REAL @@ -900,7 +803,13 @@ 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. +not INF. Due to the branching nature of non-linear Monte-Carlo algorithms, +paths are made of strips. Whith a Picard order of 1, there is only a single +strip, with higher orders, the number of strips can be greater than 1. As a +result, the whole path is a tree: past the first strip, each strip can start +from any vertex of one of the previous strips. This tree, when displaying the +*Branch_id* field, starts with id 0, then increments each time a non-linearity +leads to the creation of a new strip (to fetch a temperature). [verse] _______ @@ -911,31 +820,41 @@ _______ "DATASET POLYDATA" "POINTS" #vertices "double" <path-vertices> - "LINES 1" #vertices+1 - <heat-path> + "LINES" #strips #vertices+#strips + <heat-strips> + "CELL_DATA" #strips + "SCALAR Path_Failure unsigned_char 1" + "LOOKUP_TABLE default" + <path-failures> "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> + <weights> + "SCALARS Branch_id int 1" + "LOOKUP_TABLE default" + <branch_ids> [ <vertices-time> ] # if not steady <path-vertices> ::= <real3> <path-vertices> # #vertices vertices -<heat-path> ::= #vertices "0" "1" ... #vertices-1 +<path-failures> ::= <path-failure> + <path-failures> # #strips failure statutes + +<heat-strips> ::= <heat-strip> + <heat-strips> # #strips strips <vertices-types> ::= <vertice-type> <vertices-types> # #vertices types -<weigths> ::= REAL - <weigths> # #vertices weigths +<weights> ::= <weight> + <weights> # #vertices weights + +<branch_ids> ::= <branch_id> + <branch_ids> # #vertices ids <vertices-time> ::= "SCALARS Time double 1" "LOOKUP_TABLE default" @@ -945,15 +864,23 @@ _______ <real3> ::= REAL REAL REAL -<durations> ::= REAL # in [0, INF) - <durations> # #vertices durations +<path-failure> ::= "0" # SUCCESS + | "1" # FAILURE + +<heat-strip> ::= #strip_vertices <vtx_idx 1> ... <vtx_idx #strip_vertices> <vertice-type> ::= "0" # CONDUCTION | "1" # CONVECTION | "2" # RADIATIVE -<path-type> ::= "0" # SUCCESS - | "1" # FAILURE +<weight> ::= REAL + +<branch-id> ::= INTEGER in [0 Picard_Order] + +<durations> ::= REAL # in [0, INF) + <durations> # #vertices durations + +<vtx_idx> ::= INTEGER # in [0 #vertices[ _______ diff --git a/doc/stardis.1.txt.in b/doc/stardis.1.txt.in @@ -29,12 +29,14 @@ SYNOPSIS *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, +*stardis* solves coupled thermal systems: conductive, convective and +radiative transfers are solved together. The physical model used for +conduction is the local unstationary heat conduction equation. +Convection fluxes are assumed to be linear with temperature, and radiation +is assumed to be integrated over the whole thermal spectral range, +therefore radiative heat fluxes are proportionnal to a difference of +temperatures to the power 4. *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. @@ -62,13 +64,28 @@ 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. -Everytime the linear assumption is relevant, this theoretical framework allows -to encompass all the heat transfer mechanisms (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. +Monte-Carlo algorithms associated with convective and conductive processes +consist in sampling heat paths: this can be seen as an extension of +Monte-Carlo algorithms that solve monochromatic radiative transfer. +The radiative transfer algorithm, based on the Picard method, is also based +on sampling radiative paths. However, since stardis solves the spectrally +integrated radiative transfer, the process can be recursive: secondary heat +paths (convective, conductive and radiative) may be necessary along the +sampling of an initial radiative path. + +The solution may not be sufficiently converged with a Picard order equal +to 1 in the presence of high temperature gradients. +Increasing the Picard order may be necessary in this case, until the +required convergence is reached. + +A main property of this approach is that the resulting algorithms do +not rely on a volumic mesh of the system: only the representation +of interfaces is necessary. + +*stardis* supports shared memory parallelism and relies on the Message +Passing Interface specification [4] to parallelise its computations in a +distributed memory environment; it can thus be run either directly or through +a MPI process launcher like *mpirun(1)*. [1] Delatorre et al., Monte Carlo advances and concentrated solar applications, Solar Energy, 2014 @@ -79,6 +96,8 @@ Mathematical Statistics, 1949. [3] Muller, Some continuous Monte-Carlo Methods for the Dirichlet Problem, Transactions of the American Mathematical Society, 1956. +[4] MPI specifications - https://www.mpi-forum.org/docs/ + MANDATORY OPTIONS ----------------- *-M* _file_:: @@ -186,10 +205,6 @@ EXCLUSIVE OPTIONS 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 @@ -242,10 +257,13 @@ different temperature, flux or volumic power values. 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@. +*-o* _Picard_order_:: + Determine the iteration level used with the Picard method to deal with + non-linear radiative transfer accross the model. + By default *Picard_order* is set to @STARDIS_ARGS_DEFAULT_PICARD_ORDER@. + Note that a Picard order greater than 1 is incompatible both with Green + computations and models including volumic power sources or non zero flux + at a boundary. *-t* _threads-count_:: Hint on the number of threads to use. By default use as many threads as CPU @@ -306,9 +324,11 @@ Compute 3 probe temperatures, ensuring statistical independence: $ stardis -M model.txt -p 1,2.5,0,50,5000 -xstate1 -Xstate2 $ stardis -M model.txt -p 1,3.5,0,50,5000 -xstate2 + +Use mpirun(1) to launch stardis on several hosts defined in the my_hosts file. Render the system as described in *scene.txt* with default settings: - $ stardis -M scene.txt -R : + $ mpirun --hostfile my_hosts 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 @@ -342,3 +362,4 @@ SEE ALSO *sgreen*(1), *htpp*(1) *htrdr-image*(5) +*mpirun(1)* diff --git a/src/stardis-app.c b/src/stardis-app.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2018-2021 |Meso|Star> (contact@meso-star.com) +/* Copyright (C) 2018-2022 |Meso|Star> (contact@meso-star.com) * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -13,6 +13,10 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ +#ifdef STARDIS_ENABLE_MPI +#define _POSIX_C_SOURCE 200112L +#endif + #include "stardis-app.h" #include "stardis-output.h" #include "stardis-compute.h" @@ -32,8 +36,12 @@ #include <string.h> -static const struct dummies DUMMIES_NULL = DUMMIES_NULL__; +#ifdef STARDIS_ENABLE_MPI +#include <stdio.h> +#include <mpi.h> +#endif +static const struct dummies DUMMIES_NULL = DUMMIES_NULL__; static const struct counts COUNTS_NULL = COUNTS_NULL__; /******************************************************************************* @@ -42,8 +50,7 @@ static const struct counts COUNTS_NULL = COUNTS_NULL__; static res_T read_model (const struct darray_str* model_files, - struct stardis* stardis, - struct dummies* dummies) + struct stardis* stardis) { res_T res = RES_OK; const struct str* files = NULL; @@ -51,7 +58,7 @@ read_model FILE* f = NULL; struct txtrdr* txtrdr = NULL; - ASSERT(model_files && stardis && dummies); + ASSERT(model_files && stardis); files = darray_str_cdata_get(model_files); FOR_EACH(i, 0, darray_str_size_get(model_files)) { const char* name = str_cget(files + i); @@ -69,7 +76,7 @@ read_model ERR(txtrdr_read_line(txtrdr)); line = txtrdr_get_line(txtrdr); if(!line) break; - ERR(process_model_line(name, line, stardis, dummies)); + ERR(process_model_line(name, line, stardis)); } txtrdr_ref_put(txtrdr); txtrdr = NULL; @@ -80,6 +87,14 @@ read_model stardis->scale_factor = STARDIS_DEFAULT_SCALE_FACTOR; logger_print(stardis->logger, LOG_OUTPUT, "Scaling factor is %g\n", stardis->scale_factor); + logger_print(stardis->logger, LOG_OUTPUT, + "Trad is %g, Trad reference is %g\n", stardis->trad, stardis->trad_ref); + stardis->t_range[0] = MMIN(stardis->t_range[0], stardis->trad_ref); + stardis->t_range[1] = MMAX(stardis->t_range[1], stardis->trad_ref); + logger_print(stardis->logger, LOG_OUTPUT, + "System T range is [%g %g]\n", SPLIT2(stardis->t_range)); + logger_print(stardis->logger, LOG_OUTPUT, + "Picard order is %u\n", stardis->picard_order); ASSERT(!f && !txtrdr); exit: @@ -110,6 +125,7 @@ check_delta_and_create_solid double ratio, delta_range[2] = { DBL_MAX, -DBL_MAX }; const double acceptance_ratio = 3; struct senc3d_enclosure_header header; + struct solid* solid = description->d.solid; ASSERT(stardis && description && description->type == DESC_MAT_SOLID); @@ -118,7 +134,7 @@ check_delta_and_create_solid 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; + const unsigned desc_id = solid->desc_id; /* The enclosures where created using description ids */ ERR(senc3d_scene_get_enclosure_count_by_medium(stardis->senc3d_scn, @@ -153,31 +169,31 @@ check_delta_and_create_solid 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); + str_cget(&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]; + if(solid->delta == DELTA_AUTO) { + 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); + str_cget(&solid->name), solid->delta); } else { int too_small - = (delta_range[0] > description->d.solid.delta * acceptance_ratio); + = (delta_range[0] > solid->delta * acceptance_ratio); int too_big - = (delta_range[0] * acceptance_ratio < description->d.solid.delta); + = (delta_range[0] * acceptance_ratio < 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]); + str_cget(&solid->name), (too_big ? "big" : "small"), + solid->delta, delta_range[0]); } } } } } - ERR(create_solver_solid(stardis, &description->d.solid)); + ERR(create_solver_solid(stardis, solid)); end: if(enc) SENC3D(enclosure_ref_put(enc)); @@ -190,6 +206,58 @@ error: * Public Functions ******************************************************************************/ +#ifdef STARDIS_ENABLE_MPI +/* To be called after logger has been initialized + * and before stardis is initialized */ +res_T +init_mpi + (int* pargc, + char** pargv[], + void (*prt_err_fn)(const char* msg, void* ctx), + void (*prt_warn_fn)(const char* msg, void* ctx)) +{ + res_T res = RES_OK; + char buf[64]; + int mpi_provided; + + ASSERT(pargc && pargv && prt_err_fn && prt_warn_fn); + + if(MPI_Init_thread(pargc, pargv, MPI_THREAD_MULTIPLE, &mpi_provided) + != MPI_SUCCESS) + { + prt_err_fn("Cannot init MPI\n", NULL); + res = RES_BAD_ARG; + goto error; + } + else if(mpi_provided != MPI_THREAD_MULTIPLE) { + const char* lvl; + switch(mpi_provided) { + case MPI_THREAD_SINGLE: lvl = "MPI_THREAD_SINGLE"; break; + case MPI_THREAD_FUNNELED: lvl = "MPI_THREAD_FUNNELED"; break; + case MPI_THREAD_SERIALIZED: lvl = "MPI_THREAD_SERIALIZED"; break; + default: FATAL("Unreachable code.\n"); break; + } + snprintf(buf, sizeof(buf)-1, "MPI support restricted to %s\n", lvl); + prt_warn_fn(buf, NULL); + } + +end: + return res; +error: + goto end; +} + +void +finalize_mpi(void) +{ + int initialized; + + CHK(MPI_Initialized(&initialized) == MPI_SUCCESS); + if(initialized) + CHK(MPI_Finalize() == MPI_SUCCESS); +} +#endif + res_T stardis_init (const struct args* args, @@ -199,16 +267,17 @@ stardis_init { 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; + struct sdis_device_create_args dev_args; ASSERT(args && logger && allocator && stardis); str_init(allocator, &str); /* Init everithing that cannot fail */ + stardis->dummies = DUMMIES_NULL; stardis->logger = logger; stardis->allocator = allocator; htable_intface_init(stardis->allocator, &htable_interfaces); @@ -234,9 +303,13 @@ stardis_init stardis->compute_surface.area = 0; stardis->samples = args->samples; stardis->nthreads = args->nthreads; + stardis->picard_order = args->picard_order; stardis->scale_factor = -1; /* invalid value */ - stardis->ambient_temp = args->ambient_temp; - stardis->ref_temp = args->ref_temp; + stardis->trad = STARDIS_DEFAULT_TRAD; + stardis->trad_ref = STARDIS_DEFAULT_TRAD_REFERENCE; + stardis->trad_def = 0; + stardis->geometry_initialized = 0; + d2(stardis->t_range, INF, -INF); stardis->dump_paths = SDIS_HEAT_PATH_NONE; if(args->dump_paths & DUMP_ERROR) stardis->dump_paths |= SDIS_HEAT_PATH_FAILURE; @@ -251,11 +324,30 @@ stardis_init 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)); + dev_args.logger = stardis->logger; + dev_args.allocator = stardis->allocator; + dev_args.nthreads_hint = stardis->nthreads; + dev_args.verbosity = stardis->verbose; + +#ifdef STARDIS_ENABLE_MPI + logger_print(stardis->logger, LOG_OUTPUT, "MPI is enabled.\n"); + /* Open MPI accepts the C/C++ argc and argv arguments to main, + * but neither modifies, interprets, nor distributes them: use NULL */ + CHK(MPI_Initialized(&stardis->mpi_initialized) == MPI_SUCCESS); + if(stardis->mpi_initialized) + CHK(MPI_Comm_rank(MPI_COMM_WORLD, &stardis->mpi_rank) == MPI_SUCCESS); +#else + logger_print(stardis->logger, LOG_OUTPUT, "MPI is disabled.\n"); + stardis->mpi_initialized = 0; +#endif + + dev_args.use_mpi = stardis->mpi_initialized; + + ERR(sdis_device_create(&dev_args, &stardis->dev)); ERR(init_geometry(stardis->logger, stardis->allocator, stardis->verbose, &stardis->geometry)); + stardis->geometry_initialized = 1; if(args->mode & MODE_IR_COMPUTE) { ERR(parse_camera(stardis->logger, args->camera, stardis)); @@ -272,7 +364,7 @@ stardis_init 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)); + ERR(read_model(&args->model_files, stardis)); create_context.geometry = stardis->geometry.sg3d; create_context.app_interface_getter = geometry_get_interface; @@ -394,8 +486,9 @@ stardis_init 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.trad.temperature = stardis->trad; + scn_args.trad.reference = stardis->trad_ref; + d2_set(scn_args.t_range, stardis->t_range); scn_args.context = &create_context; res = sdis_scene_create(stardis->dev, &scn_args, &stardis->sdis_scn); if(res != RES_OK) { @@ -430,8 +523,13 @@ stardis_release str_release(&stardis->bin_green_filename); str_release(&stardis->end_paths_filename); str_release(&stardis->chunks_prefix); + FOR_EACH(i, 0, darray_descriptions_size_get(&stardis->descriptions)) { + struct description* d = darray_descriptions_data_get(&stardis->descriptions) +i; + release_description(d, stardis->allocator); + } darray_descriptions_release(&stardis->descriptions); - release_geometry(&stardis->geometry); + if(stardis->geometry_initialized) + 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); @@ -441,6 +539,12 @@ stardis_release } darray_media_ptr_release(&stardis->media); release_camera(&stardis->camera); + if(stardis->dummies.stardis_fluid) { + release_fluid(stardis->dummies.stardis_fluid, stardis->allocator); + } + if(stardis->dummies.stardis_solid) { + release_solid(stardis->dummies.stardis_solid, stardis->allocator); + } } res_T @@ -473,8 +577,7 @@ error: 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);\ + ASSERT(DESC_IS_MEDIUM(descs[properties[(Rank)]].type));\ if(descs[properties[(Rank)]].type == DESC_MAT_SOLID) solid_count++;\ else fluid_count++;\ }\ diff --git a/src/stardis-app.h b/src/stardis-app.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2018-2021 |Meso|Star> (contact@meso-star.com) +/* Copyright (C) 2018-2022 |Meso|Star> (contact@meso-star.com) * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -16,6 +16,7 @@ #ifndef STARDIS_APP_H #define STARDIS_APP_H +#include "stardis-args.h" #include "stardis-parsing.h" #include "stardis-default.h" #include "stardis-solid.h" @@ -37,6 +38,10 @@ #include <limits.h> #include <stdarg.h> +#ifdef STARDIS_ENABLE_MPI +#include <mpi/mpi.h> +#endif + /* Forward declarations */ struct logger; struct mem_allocator; @@ -125,12 +130,15 @@ enum description_type { struct dummies { struct sdis_medium* dummy_fluid; unsigned dummy_fluid_id; + struct fluid* stardis_fluid; struct sdis_medium* dummy_solid; unsigned dummy_solid_id; + struct solid* stardis_solid; }; #define DUMMIES_NULL__ {\ - NULL, UINT_MAX, NULL, UINT_MAX\ + NULL, UINT_MAX, NULL, NULL, UINT_MAX, NULL\ } +static const struct dummies DUMMIES_NULL; static FINLINE void init_media_ptr @@ -193,30 +201,80 @@ error: /******************************************************************************/ +struct fluid; +struct solid; +struct t_boundary; +struct f_boundary; +struct h_boundary; +struct solid_fluid_connect; +struct solid_solid_connect; + +struct description { + enum description_type type; + union { + struct fluid* fluid; + struct solid* solid; + struct t_boundary* t_boundary; + struct f_boundary* f_boundary; + struct h_boundary* h_boundary; + struct solid_fluid_connect* sf_connect; + struct solid_solid_connect* ss_connect; + } d; +}; + +/******************************************************************************/ + struct h_boundary { struct str name; + double ref_temperature; double emissivity; double specular_fraction; double hc; double imposed_temperature; unsigned mat_id; + struct fluid* possible_external_fluid; /* if H for solid */ }; -static FINLINE void -init_h(struct mem_allocator* allocator, struct h_boundary* dst) +static FINLINE res_T +init_h + (struct mem_allocator* allocator, + struct h_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; + res_T res = RES_OK; + int str_initialized = 0; + ASSERT(allocator && dst && *dst == NULL); + *dst = MEM_ALLOC(allocator, sizeof(struct h_boundary)); + if(! *dst) { + res = RES_MEM_ERR; + goto error; + } + str_init(allocator, &(*dst)->name); + (*dst)->ref_temperature = 0; + (*dst)->emissivity = 0; + (*dst)->specular_fraction = 0; + (*dst)->hc = 0; + (*dst)->imposed_temperature = -1; + (*dst)->mat_id = UINT_MAX; + (*dst)->possible_external_fluid = NULL; +end: + return res; +error: + if(str_initialized) str_release(&(*dst)->name); + if(*dst) MEM_RM(allocator, *dst); + goto end; } static FINLINE void -release_h_boundary(struct h_boundary* bound) +release_h_boundary + (struct h_boundary* bound, + struct mem_allocator* allocator) { + ASSERT(bound && allocator); str_release(&bound->name); + if(bound->possible_external_fluid) { + release_fluid(bound->possible_external_fluid, allocator); + } + MEM_RM(allocator, bound); } static res_T @@ -228,45 +286,55 @@ str_print_h_boundary 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 ) ); + "H boundary for %s '%s': ref_temperature=%g emissivity=%g specular_fraction=%g " + "hc=%g T=%g (using medium %u as external medium)", + ARG8( (type == DESC_BOUND_H_FOR_SOLID ? "solid" : "fluid"), str_cget(&b->name), + b->ref_temperature, b->emissivity, b->specular_fraction, b->hc, + b->imposed_temperature, b->mat_id ) ); end: return res; error: goto end; } -static FINLINE res_T -cp_h_boundary(struct h_boundary* dst, const struct h_boundary* src) -{ - 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 { struct str name; double imposed_temperature; unsigned mat_id; }; -static FINLINE void -init_t(struct mem_allocator* allocator, struct t_boundary* dst) +static FINLINE res_T +init_t + (struct mem_allocator* allocator, + struct t_boundary** dst) { - str_init(allocator, &dst->name); - dst->imposed_temperature = -1; - dst->mat_id = UINT_MAX; + res_T res = RES_OK; + int str_initialized = 0; + ASSERT(allocator && dst && *dst == NULL); + *dst = MEM_ALLOC(allocator, sizeof(struct t_boundary)); + if(! *dst) { + res = RES_MEM_ERR; + goto error; + } + str_init(allocator, &(*dst)->name); + (*dst)->imposed_temperature = -1; + (*dst)->mat_id = UINT_MAX; +end: + return res; +error: + if(str_initialized) str_release(&(*dst)->name); + if(*dst) MEM_RM(allocator, *dst); + goto end; } static FINLINE void -release_t_boundary(struct t_boundary* bound) +release_t_boundary + (struct t_boundary* bound, + struct mem_allocator* allocator) { + ASSERT(bound && allocator); str_release(&bound->name); + MEM_RM(allocator, bound); } static res_T @@ -287,32 +355,44 @@ error: goto end; } -static FINLINE res_T -cp_t_boundary(struct t_boundary* dst, const struct t_boundary* src) -{ - dst->imposed_temperature = src->imposed_temperature; - dst->mat_id = src->mat_id; - return str_copy(&dst->name, &src->name); -} - struct f_boundary { struct str name; double imposed_flux; unsigned mat_id; }; -static FINLINE void -init_f(struct mem_allocator* allocator, struct f_boundary* dst) +static FINLINE res_T +init_f + (struct mem_allocator* allocator, + struct f_boundary** dst) { - str_init(allocator, &dst->name); - dst->mat_id = UINT_MAX; - dst->imposed_flux = -1; + res_T res = RES_OK; + int str_initialized = 0; + ASSERT(allocator && dst && *dst == NULL); + *dst = MEM_ALLOC(allocator, sizeof(struct f_boundary)); + if(! *dst) { + res = RES_MEM_ERR; + goto error; + } + str_init(allocator, &(*dst)->name); + (*dst)->mat_id = UINT_MAX; + (*dst)->imposed_flux = -1; +end: + return res; +error: + if(str_initialized) str_release(&(*dst)->name); + if(*dst) MEM_RM(allocator, *dst); + goto end; } static FINLINE void -release_f_boundary(struct f_boundary* bound) +release_f_boundary + (struct f_boundary* bound, + struct mem_allocator* allocator) { + ASSERT(bound && allocator); str_release(&bound->name); + MEM_RM(allocator, bound); } static res_T @@ -331,16 +411,9 @@ 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 { struct str name; + double ref_temperature; double emissivity; double specular_fraction; double hc; @@ -348,19 +421,40 @@ struct solid_fluid_connect { }; static FINLINE void -release_sf_connect(struct solid_fluid_connect* connect) +release_sf_connect + (struct solid_fluid_connect* connect, + struct mem_allocator* allocator) { + ASSERT(connect && allocator); str_release(&connect->name); + MEM_RM(allocator, connect); } -static FINLINE void -init_sf(struct mem_allocator* allocator, struct solid_fluid_connect* dst) +static FINLINE res_T +init_sf + (struct mem_allocator* allocator, + struct solid_fluid_connect** dst) { - str_init(allocator, &dst->name); - dst->emissivity = 0; - dst->specular_fraction = 0; - dst->hc = 0; - dst->connection_id = UINT_MAX; + res_T res = RES_OK; + int str_initialized = 0; + ASSERT(allocator && dst && *dst == NULL); + *dst = MEM_ALLOC(allocator, sizeof(struct solid_fluid_connect)); + if(! *dst) { + res = RES_MEM_ERR; + goto error; + } + str_init(allocator, &(*dst)->name); + (*dst)->ref_temperature = 0; + (*dst)->emissivity = 0; + (*dst)->specular_fraction = 0; + (*dst)->hc = 0; + (*dst)->connection_id = UINT_MAX; +end: + return res; +error: + if(str_initialized) str_release(&(*dst)->name); + if(*dst) MEM_RM(allocator, *dst); + goto end; } static res_T @@ -370,33 +464,15 @@ str_print_sf_connect { 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 ) ); + STR_APPEND_PRINTF(str, "Solid-Fluid connection '%s': ", ARG1( str_cget(&c->name) ) ); + STR_APPEND_PRINTF(str, "ref_temperature=%g emissivity=%g, specular_fraction=%g hc=%g", + ARG4( c->ref_temperature, 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 solid_solid_connect { struct str name; double tcr; @@ -404,17 +480,37 @@ struct solid_solid_connect { }; static FINLINE void -release_ss_connect(struct solid_solid_connect* connect) +release_ss_connect + (struct solid_solid_connect* connect, + struct mem_allocator* allocator) { + ASSERT(connect && allocator); str_release(&connect->name); + MEM_RM(allocator, connect); } -static FINLINE void -init_ss(struct mem_allocator* allocator, struct solid_solid_connect* dst) +static FINLINE res_T +init_ss + (struct mem_allocator* allocator, + struct solid_solid_connect** dst) { - str_init(allocator, &dst->name); - dst->tcr = 0; - dst->connection_id = UINT_MAX; + res_T res = RES_OK; + int str_initialized = 0; + ASSERT(allocator && dst && *dst == NULL); + *dst = MEM_ALLOC(allocator, sizeof(struct solid_solid_connect)); + if(! *dst) { + res = RES_MEM_ERR; + goto error; + } + str_init(allocator, &(*dst)->name); + (*dst)->tcr = 0; + (*dst)->connection_id = UINT_MAX; +end: + return res; +error: + if(str_initialized) str_release(&(*dst)->name); + if(*dst) MEM_RM(allocator, *dst); + goto end; } static res_T @@ -424,8 +520,8 @@ str_print_ss_connect { res_T res = RES_OK; ASSERT(str && c); - STR_APPEND_PRINTF(str, "Solid-Solid connection '%s':", ARG1( str_cget(&c->name) ) ); - STR_APPEND_PRINTF(str, " contact resistance=%g", ARG1( c->tcr ) ); + STR_APPEND_PRINTF(str, "Solid-Solid connection '%s': ", ARG1( str_cget(&c->name) ) ); + STR_APPEND_PRINTF(str, "contact resistance=%g", ARG1( c->tcr ) ); end: return res; error: @@ -433,69 +529,45 @@ error: } static FINLINE res_T -cp_ss_connect - (struct solid_solid_connect* dst, const struct solid_solid_connect* src) -{ - dst->connection_id = src->connection_id; - dst->tcr = src->tcr; - return str_copy(&dst->name, &src->name); -} - -static FINLINE res_T -cp_release_ss_connect - (struct solid_solid_connect* dst, struct solid_solid_connect* src) -{ - return cp_ss_connect(dst, src); -} - - -struct description { - enum description_type type; - union { - struct fluid fluid; - struct solid solid; - struct t_boundary t_boundary; - struct f_boundary f_boundary; - struct h_boundary h_boundary; - struct solid_fluid_connect sf_connect; - struct solid_solid_connect ss_connect; - } d; -}; - -static FINLINE res_T -init_description(struct mem_allocator* alloc, struct description* desc) +init_description + (struct mem_allocator* alloc, + struct description* desc) { ASSERT(desc); (void)alloc; desc->type = DESCRIPTION_TYPE_COUNT__; + desc->d.fluid = NULL; return RES_OK; } static FINLINE void -release_description(struct description* desc) +release_description + (struct description* desc, + struct mem_allocator* allocator) { + ASSERT(desc && allocator); switch (desc->type) { case DESC_MAT_SOLID: - release_solid(&desc->d.solid); + release_solid(desc->d.solid, allocator); break; case DESC_MAT_FLUID: - release_fluid(&desc->d.fluid); + release_fluid(desc->d.fluid, allocator); break; case DESC_BOUND_H_FOR_SOLID: case DESC_BOUND_H_FOR_FLUID: - release_h_boundary(&desc->d.h_boundary); + release_h_boundary(desc->d.h_boundary, allocator); break; case DESC_BOUND_T_FOR_SOLID: - release_t_boundary(&desc->d.t_boundary); + release_t_boundary(desc->d.t_boundary, allocator); break; case DESC_BOUND_F_FOR_SOLID: - release_f_boundary(&desc->d.f_boundary); + release_f_boundary(desc->d.f_boundary, allocator); break; case DESC_SOLID_FLUID_CONNECT: - release_sf_connect(&desc->d.sf_connect); + release_sf_connect(desc->d.sf_connect, allocator); break; case DESC_SOLID_SOLID_CONNECT: - release_ss_connect(&desc->d.ss_connect); + release_ss_connect(desc->d.ss_connect, allocator); break; default: FATAL("error:" STR(__FILE__) ":" STR(__LINE__)": Invalid type.\n"); @@ -514,26 +586,26 @@ str_print_description ERR(str_printf(str, "Description %u: ", rank)); switch (desc->type) { case DESC_MAT_SOLID: - ERR(str_print_solid(str, &desc->d.solid)); + ERR(str_print_solid(str, desc->d.solid)); break; case DESC_MAT_FLUID: - ERR(str_print_fluid(str, &desc->d.fluid)); + ERR(str_print_fluid(str, desc->d.fluid)); break; case DESC_BOUND_T_FOR_SOLID: - ERR(str_print_t_boundary(str, &desc->d.t_boundary)); + ERR(str_print_t_boundary(str, desc->d.t_boundary)); break; case DESC_BOUND_H_FOR_SOLID: case DESC_BOUND_H_FOR_FLUID: - ERR(str_print_h_boundary(str, &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: - ERR(str_print_f_boundary(str, &desc->d.f_boundary)); + 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)); + ERR(str_print_sf_connect(str, desc->d.sf_connect)); break; case DESC_SOLID_SOLID_CONNECT: - ERR(str_print_ss_connect(str, &desc->d.ss_connect)); + ERR(str_print_ss_connect(str, desc->d.ss_connect)); break; default: FATAL("error:" STR(__FILE__) ":" STR(__LINE__)": Invalid type.\n"); @@ -551,92 +623,25 @@ get_description_name ASSERT(desc); switch (desc->type) { case DESC_MAT_SOLID: - return &desc->d.solid.name; + return &desc->d.solid->name; case DESC_MAT_FLUID: - return &desc->d.fluid.name; + return &desc->d.fluid->name; case DESC_BOUND_T_FOR_SOLID: - return &desc->d.t_boundary.name; + return &desc->d.t_boundary->name; case DESC_BOUND_H_FOR_SOLID: case DESC_BOUND_H_FOR_FLUID: - return &desc->d.h_boundary.name; + return &desc->d.h_boundary->name; case DESC_BOUND_F_FOR_SOLID: - return &desc->d.f_boundary.name; + return &desc->d.f_boundary->name; case DESC_SOLID_FLUID_CONNECT: - return &desc->d.sf_connect.name; + return &desc->d.sf_connect->name; case DESC_SOLID_SOLID_CONNECT: - return &desc->d.ss_connect.name; + return &desc->d.ss_connect->name; default: FATAL("error:" STR(__FILE__) ":" STR(__LINE__)": Invalid type.\n"); } } -static FINLINE res_T -cp_description - (struct description* dst, - const struct description* src) -{ - res_T res = RES_OK; - ASSERT(src && dst); - switch (src->type) { - case DESC_MAT_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: - 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: - 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: - 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: - 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: - 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; - case DESC_SOLID_SOLID_CONNECT: - if(dst->type == DESCRIPTION_TYPE_COUNT__) { - dst->type = src->type; - init_ss(src->d.ss_connect.name.allocator, &dst->d.ss_connect); - } - ERR(cp_ss_connect(&dst->d.ss_connect, &src->d.ss_connect)); - break; - default: - FATAL("error:" STR(__FILE__) ":" STR(__LINE__)": Invalid type.\n"); - } -end: - return res; -error: - goto end; -} - static FINLINE void description_get_medium_id (const struct description* desc, @@ -645,20 +650,20 @@ description_get_medium_id ASSERT(desc && id); switch (desc->type) { case DESC_MAT_SOLID: - *id = desc->d.solid.solid_id; + *id = desc->d.solid->solid_id; return; case DESC_MAT_FLUID: - *id = desc->d.fluid.fluid_id; + *id = desc->d.fluid->fluid_id; return; case DESC_BOUND_H_FOR_SOLID: case DESC_BOUND_H_FOR_FLUID: - *id = desc->d.h_boundary.mat_id; + *id = desc->d.h_boundary->mat_id; return; case DESC_BOUND_T_FOR_SOLID: - *id = desc->d.t_boundary.mat_id; + *id = desc->d.t_boundary->mat_id; return; case DESC_BOUND_F_FOR_SOLID: - *id = desc->d.f_boundary.mat_id; + *id = desc->d.f_boundary->mat_id; return; case DESC_SOLID_FLUID_CONNECT: /* No medium linked to SF */ case DESC_SOLID_SOLID_CONNECT: /* No medium linked to SS */ @@ -710,8 +715,20 @@ release_camera(struct camera* cam) { static INLINE void log_err_fn(const char* msg, void* ctx) { +#ifdef STARDIS_ENABLE_MPI + int initialized, rank = 0; +#endif + ASSERT(msg); (void)ctx; + +#ifdef STARDIS_ENABLE_MPI + CHK(MPI_Initialized(&initialized) == MPI_SUCCESS); + if(initialized) CHK(MPI_Comm_rank(MPI_COMM_WORLD, &rank) == MPI_SUCCESS); + /* Only master prints */ + if(rank != 0) return; +#endif + #ifdef OS_WINDOWS fprintf(stderr, "error: %s", msg); #else @@ -722,8 +739,20 @@ log_err_fn(const char* msg, void* ctx) static INLINE void log_warn_fn(const char* msg, void* ctx) { +#ifdef STARDIS_ENABLE_MPI + int initialized, rank = 0; +#endif + ASSERT(msg); (void)ctx; + +#ifdef STARDIS_ENABLE_MPI + CHK(MPI_Initialized(&initialized) == MPI_SUCCESS); + if(initialized) CHK(MPI_Comm_rank(MPI_COMM_WORLD, &rank) == MPI_SUCCESS); + /* Only master prints */ + if(rank != 0) return; +#endif + #ifdef OS_WINDOWS fprintf(stderr, "warning: %s", msg); #else @@ -734,8 +763,20 @@ log_warn_fn(const char* msg, void* ctx) static INLINE void log_prt_fn(const char* msg, void* ctx) { +#ifdef STARDIS_ENABLE_MPI + int initialized, rank = 0; +#endif + ASSERT(msg); (void)ctx; + +#ifdef STARDIS_ENABLE_MPI + CHK(MPI_Initialized(&initialized) == MPI_SUCCESS); + if(initialized) CHK(MPI_Comm_rank(MPI_COMM_WORLD, &rank) == MPI_SUCCESS); + /* Only master prints */ + if(rank != 0) return; +#endif + #ifdef OS_WINDOWS fprintf(stderr, "message: %s", msg); #else @@ -759,8 +800,6 @@ struct counts { #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 { @@ -771,6 +810,7 @@ struct compute_surface { }; struct stardis { + struct dummies dummies; /* dummy meterials for boundaries' outside */ struct geometry geometry; struct sdis_scene* sdis_scn; /* The solver scene */ struct darray_descriptions descriptions; /* Materials and boundaries */ @@ -793,18 +833,24 @@ struct stardis { struct str rndgen_state_in_filename; struct str rndgen_state_out_filename; struct str chunks_prefix; - int mode; - size_t samples; - unsigned nthreads; - double scale_factor; - double ambient_temp, ref_temp; struct mem_allocator* allocator; struct logger* logger; struct sdis_device* dev; + size_t samples; + double scale_factor; + double trad, trad_ref; + double t_range[2]; + int mode; + int trad_def; + unsigned nthreads; + unsigned picard_order; unsigned next_medium_id; unsigned undefined_medium_behind_boundary_id; int dump_paths; int verbose; + int geometry_initialized; + int mpi_initialized; + int mpi_rank; }; static INLINE unsigned @@ -814,6 +860,18 @@ allocate_stardis_medium_id(struct stardis* stardis) return stardis->next_medium_id++; } +#ifdef STARDIS_ENABLE_MPI +extern LOCAL_SYM res_T +init_mpi + (int* pargc, + char** pargv[], + void (*prt_err_fn)(const char* msg, void* ctx), + void (*prt_warn_fn)(const char* msg, void* ctx)); + +extern LOCAL_SYM void +finalize_mpi(void); +#endif + extern LOCAL_SYM res_T stardis_init (const struct args* args, diff --git a/src/stardis-args.c b/src/stardis-args.c @@ -0,0 +1,986 @@ +/* Copyright (C) 2018-2022 |Meso|Star> (contact@meso-star.com) + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. */ + +#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> + +#ifdef COMPILER_GCC +#include <strings.h> /* strcasecmp */ +#else +#define strcasecmp(s1, s2) _stricmp((s1), (s2)) +#endif + +#ifdef STARDIS_ENABLE_MPI +#include <mpi/mpi.h> +#endif + +/******************************************************************************* + * Local Functions + ******************************************************************************/ + +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; +} + +static 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; +} + +static 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); +} + +/******************************************************************************* + * Public Functions + ******************************************************************************/ + +void +print_version + (FILE* stream) +{ + ASSERT(stream); + fprintf(stream, + "Stardis version %i.%i.%i built on stardis solver version %i.%i.%i; MPI is " +#ifdef STARDIS_ENABLE_MPI + "enabled.\n", +#else + "disabled.\n", +#endif + STARDIS_APP_VERSION_MAJOR, STARDIS_APP_VERSION_MINOR, STARDIS_APP_VERSION_PATCH, + Stardis_VERSION_MAJOR, Stardis_VERSION_MINOR, Stardis_VERSION_PATCH); +} + +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 non-zero default values */ + args->samples = STARDIS_DEFAULT_SAMPLES_COUNT; + args->nthreads = SDIS_NTHREADS_DEFAULT; + args->picard_order = STARDIS_DEFAULT_PICARD_ORDER; + d2(args->pos_and_time+3, + STARDIS_DEFAULT_COMPUTE_TIME, STARDIS_DEFAULT_COMPUTE_TIME); + 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); +} + +void +short_help + (FILE* stream, + const char* prog) +{ + const char* name; +#ifdef STARDIS_ENABLE_MPI + int rank; +#endif + ASSERT(stream && prog); + +#ifdef STARDIS_ENABLE_MPI + CHK(MPI_Comm_rank(MPI_COMM_WORLD, &rank) == MPI_SUCCESS); + /* Only master prints */ + if(rank != 0) return; +#endif + +#ifdef COMPILER_GCC + name = strrchr(prog, '/'); +#else + name = strrchr(prog, '\\'); +#endif + + name = name ? name + 1 : prog; + fprintf(stream, + "Usage: %s [OPTIONS]\n" + "\nSolve coupled thermal systems under the linear assumption.\n" + "Refer to stardis(1) man page for more information.\n\n", + name); + print_version(stream); + + fprintf(stream, "\nMandatory options\n"); + fprintf(stream, "-----------------\n"); + + fprintf(stream, "\n -M <FILE>\n"); + fprintf(stream, " Read a text file that contains (partial) description of the model.\n"); + + fprintf(stream, "\nExclusive options\n"); + fprintf(stream, "-----------------\n"); + + fprintf(stream, "\n -F STL_FILE[,TIME-RANGE]\n"); + fprintf(stream, " Compute the mean flux on a given 2D region at a given time.\n"); + + fprintf(stream, "\n -m MEDIUM_NAME[,TIME-RANGE]\n"); + fprintf(stream, " Compute the mean temperature in a given medium at a given time.\n"); + + fprintf(stream, "\n -p X,Y,Z[,TIME-RANGE]\n"); + fprintf(stream, " Compute the temperature at the given probe.\n"); + + fprintf(stream, "\n -P X,Y,Z[,TIME-RANGE]\n"); + fprintf(stream, " Compute the temperature at the given probe on an interface.\n"); + + fprintf(stream, "\n -R [RENDERING_OPTIONS]\n"); + fprintf(stream, " Compute an infra-red image of the model.\n"); + + fprintf(stream, "\n -s STL_FILE[,TIME-RANGE]\n"); + fprintf(stream, " Compute the mean temperature on a given 2D region.\n"); + + fprintf(stream, "\n -S STL_FILE[,TIME-RANGE]\n"); + fprintf(stream, " Compute the by-triangle mean temperature on a given 2D region.\n"); + + fprintf(stream, "\nOther options\n"); + fprintf(stream, "-------------\n"); + + fprintf(stream, "\n -c NAMES_PREFIX\n"); + fprintf(stream, " Dump the geometry and property ids to stdout as C chunks.\n"); + + fprintf(stream, "\n -d\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 -o\n"); + fprintf(stream, " Set the order for the Picard linearization of radiative transfer.\n"); + + fprintf(stream, "\n -t NUM_OF_THREADS\n"); + fprintf(stream, " Hint on the number of threads.\n"); + + fprintf(stream, "\n -v\n"); + fprintf(stream, " Print version information and exit.\n"); + + fprintf(stream, "\n -V LEVEL\n"); + fprintf(stream, " Set the verbosity level.\n"); + + fprintf(stream, "\n -x <FILE>\n"); + fprintf(stream, " Use a random generator's state read from a file.\n"); + + fprintf(stream, "\n -X <FILE>\n"); + fprintf(stream, " Save the final random generator's state in a file.\n"); + + fprintf(stream, +"\nCopyright (C) 2018-2022 |Meso|Star> <contact@meso-star.com>.\n" +"stardis is free software released under the GNU GPL license, version 3 or later.\n" +"You are free to change or redistribute it under certain conditions\n" +"<http://gnu.org/licenses/gpl.html>.\n"); +} + +#define FREE_AARRAY(ARRAY) \ +if(ARRAY) {\ + int i__ = 0; \ + for(i__=0; *((ARRAY)+i__);i__++){\ + free((ARRAY)[i__]);\ + }\ + free(ARRAY);\ + (ARRAY) = NULL;\ +} + +/* Workaround for a gcc warning when GET_OPTIONAL_TIME_RANGE used with Rank=0 */ +static 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, FullSrc) \ + 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), (FullSrc)); \ + 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, optarg); \ + *ptr = '\0'; \ + } \ + (Str) = optarg; + +/* Get a position followed by an optional time range */ +#define GET_POS_AND_OPTIONAL_TIME_RANGE(Src, Dst, FullSrc) \ + GET_OPTIONAL_TIME_RANGE((Src), 3, (Dst), args->logger, "-%c", opt, (FullSrc)); + +res_T +parse_args + (const int argc, + char** argv, + struct args* args, + struct mem_allocator* allocator) +{ + int opt = 0, n_used = 0, o_used = 0; + size_t len = 0; + const char option_list[] = "c:dD:eF:gG:hm:M:n:o:p:P:R:s:S:t:vV:x:X:"; + char buf[128]; + struct str keep; + char** line = NULL; + res_T res = RES_OK; + + ASSERT(argv && args); + + str_init(allocator, &keep); + 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 '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 == strcasecmp(optarg, "all")) { + args->dump_paths = DUMP_ALL; + } + else if(0 == strcasecmp(optarg, "error")) { + args->dump_paths = DUMP_ERROR; + } + else if(0 == strcasecmp(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': { + long n; + res = cstr_to_long(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 = (unsigned long)n; + n_used = 1; + break; + } + + case 'o': { + int order; + res = cstr_to_int(optarg, &order); + if(res != RES_OK + || order <= 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->picard_order = (unsigned)order; + o_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(optarg, args->pos_and_time, optarg); + 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; + + ERR(str_set(&keep, optarg)); + line = split_line(optarg, ':'); + if(!line) { + res = RES_MEM_ERR; + str_release(&keep); + goto error; + } + + /* We expect 1 or 2 parts in line */ + if(!line[0] || (line[1] && line[2])) { + logger_print((args->logger), LOG_ERROR, + "Invalid argument for option ""-%c"": %s\n", + opt, str_cget(&keep)); + str_release(&keep); + res = RES_BAD_ARG; + goto error; + } + + /* First part is pos and optional time, optional second part is a + * medium name (OK if NULL) */ + GET_POS_AND_OPTIONAL_TIME_RANGE(line[0], args->pos_and_time, + str_cget(&keep)); + if(line[1]) + args->medium_name = optarg + strlen(line[0]) + 1; + + 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': { + int nt; + res = cstr_to_int(optarg, &nt); + if(res != RES_OK + || nt <= 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->nthreads = (unsigned)nt; + 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; + + case 'x': + if(!(args->mode & RANDOM_RW_MODES)) { + res = RES_BAD_ARG; + print_multiple_modes(buf, sizeof(buf), RANDOM_RW_MODES, 0); + logger_print(args->logger, LOG_ERROR, + "Option -%c can only be used in conjunction with one of the following options: %s.\n", + (char)opt, buf); + goto error; + } + args->rndgen_state_in_filename = optarg; + break; + + case 'X': + if(!(args->mode & RANDOM_RW_MODES)) { + res = RES_BAD_ARG; + print_multiple_modes(buf, sizeof(buf), RANDOM_RW_MODES, 0); + logger_print(args->logger, LOG_ERROR, + "Option -%c can only be used in conjunction with one of the following options: %s.\n", + (char)opt, buf); + goto error; + } + args->rndgen_state_out_filename = optarg; + 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_BIN_GREEN | MODE_GREEN) + && o_used && args->picard_order > 1) + { + logger_print(args->logger, LOG_ERROR, + "Option -%c cannot be used if Picard order is not 1 (here order is %u)\n", + mode_option(args->mode & (MODE_BIN_GREEN | MODE_GREEN)), + args->picard_order); + 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; + } + } + + if(args->rndgen_state_in_filename && !(args->mode & COMPUTE_MODES)) { + res = RES_BAD_ARG; + print_multiple_modes(buf, sizeof(buf), COMPUTE_MODES, 0); + logger_print(args->logger, LOG_ERROR, + "Option -x can only be used in conjunction with an option" + " that launch a MC computation (%s).\n", + buf); + goto error; + } + + if(args->rndgen_state_out_filename && !(args->mode & COMPUTE_MODES)) { + res = RES_BAD_ARG; + print_multiple_modes(buf, sizeof(buf), COMPUTE_MODES, 0); + logger_print(args->logger, LOG_ERROR, + "Option -X can only be used in conjunction with an option" + " that launch a MC computation (%s).\n", + buf); + goto error; + } + +end: + FREE_AARRAY(line); + str_release(&keep); + 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; + struct str keep; + int i = 0; + res_T res = RES_OK; + + ASSERT(cam_param && stardis); + cam = &stardis->camera; + line = split_line(cam_param, ':'); + if(!line) { + res = RES_MEM_ERR; + goto error; + } + + str_init(stardis->allocator, &keep); + for(i = 0; *(line + i); i++) { + size_t len = 0; + ERR(str_set(&keep, line[i])); + opt = split_line(line[i], '='); + if(!opt[0] || !opt[1] || opt[2]) { /* We expect 2 parts */ + if(res == RES_OK) res = RES_BAD_ARG; + logger_print((logger), LOG_ERROR, + "Invalid option syntax: %s\n", str_cget(&keep)); + goto error; + } + if(strcasecmp(opt[0], "T") == 0) { + GET_OPTIONAL_TIME_RANGE(opt[1], 0, cam->time_range, logger, "%s", opt[0], + str_cget(&keep)); + } + else if(strcasecmp(opt[0], "FILE") == 0) { + ERR(str_set(&cam->file_name, opt[1])); + } + else if(strcasecmp(opt[0], "FMT") == 0) { + if(strcasecmp(opt[1], "VTK") == 0) + cam->fmt = STARDIS_RENDERING_OUTPUT_FILE_FMT_VTK; + else if(strcasecmp(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(strcasecmp(opt[0], "FOV") == 0) { + res = cstr_to_double(opt[1], &cam->fov); + if(res != RES_OK + || cam->fov <= 0) + { + if(res == RES_OK) res = RES_BAD_ARG; + logger_print((logger), LOG_ERROR, + "Invalid %s option: %s\n", opt[0], opt[1]); + goto error; + } + } + else if(strcasecmp(opt[0], "UP") == 0) { + ERR(cstr_to_list_double(opt[1], ',', cam->up, &len, 3)); + } + else if(strcasecmp(opt[0], "TGT") == 0) { + ERR(cstr_to_list_double(opt[1], ',', cam->tgt, &len, 3)); + cam->auto_look_at = 0; + } + else if(strcasecmp(opt[0], "POS") == 0) { + ERR(cstr_to_list_double(opt[1], ',', cam->pos, &len, 3)); + cam->auto_look_at = 0; + } + else if(strcasecmp(opt[0], "IMG") == 0) { + unsigned img_sz[2]; + res = cstr_to_list_uint(opt[1], 'x', img_sz, &len, 2); + if(res != RES_OK + /* mimic cstr_to_list_int() possible behaviour; but it doesnt exist */ + || img_sz[0] == 0 || img_sz[0] > INT_MAX + || img_sz[1] == 0 || img_sz[1] > INT_MAX) + { + if(res == RES_OK) res = RES_BAD_ARG; + logger_print((logger), LOG_ERROR, + "Invalid %s option: %s\n", opt[0], opt[1]); + goto error; + } + cam->img_width = img_sz[0]; + cam->img_height = img_sz[1]; + } + else if(strcasecmp(opt[0], "SPP") == 0) { + int ssp; + res = cstr_to_int(opt[1], &ssp); + if(res != RES_OK + || ssp <= 0) + { + if(res == RES_OK) res = RES_BAD_ARG; + logger_print((logger), LOG_ERROR, + "Invalid %s option: %s\n", opt[0], opt[1]); + goto error; + } + cam->spp = (unsigned)ssp; + } else { + logger_print(logger, LOG_ERROR, + "Unexpected option for rendering mode: %s.\n", + opt[0]); + res = RES_BAD_ARG; + goto error; + } + FREE_AARRAY(opt); + } + +end: + FREE_AARRAY(line); + FREE_AARRAY(opt); +#undef FREE_AARRAY + + str_release(&keep); + 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 diff --git a/src/stardis-args.h b/src/stardis-args.h @@ -0,0 +1,141 @@ +/* Copyright (C) 2018-2022 |Meso|Star> (contact@meso-star.com) + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. */ + +#ifndef STARDIS_ARGS_H +#define STARDIS_ARGS_H + +#include <sdis.h> + +#include <rsys/rsys.h> +#include <rsys/dynamic_array_str.h> + +struct camera; +struct logger; +struct mem_allocator; +struct stardis; +struct dummies; + +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, + + RANDOM_RW_MODES + = MODE_PROBE_COMPUTE | MODE_PROBE_COMPUTE_ON_INTERFACE | MODE_MEDIUM_COMPUTE + | MODE_BOUNDARY_COMPUTE | MODE_FLUX_BOUNDARY_COMPUTE +}; + +STATIC_ASSERT(GREEN_COMPATIBLE_MODES == (COMPUTE_MODES & GREEN_COMPATIBLE_MODES), + Cannot_have_a_GREEN_COMPATIBLE_MODE_that_is_not_a_COMPUTE_MODE); + +enum dump_path_type { + DUMP_NONE = 0, + DUMP_SUCCESS = BIT(0), + DUMP_ERROR = BIT(1), + DUMP_ALL = DUMP_SUCCESS | DUMP_ERROR +}; + +struct args { + struct logger* logger; + struct mem_allocator* allocator; + struct darray_str model_files; + char* medium_name; + char* solve_filename; + char* bin_green_filename; + char* end_paths_filename; + char* paths_filename; + char* rndgen_state_in_filename; + char* rndgen_state_out_filename; + char* chunks_prefix; + char* camera; + size_t samples; + double pos_and_time[5]; + unsigned nthreads; + unsigned picard_order; + enum stardis_mode mode; + enum dump_path_type dump_paths; + int verbose; +}; + +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 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, + struct mem_allocator* allocator); + +extern res_T +parse_camera + (struct logger* logger, + char* cam_param, + struct stardis* stardis); + +#endif /* STRADIS_ARGS_H */ diff --git a/src/stardis-compute.c b/src/stardis-compute.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2018-2021 |Meso|Star> (contact@meso-star.com) +/* Copyright (C) 2018-2022 |Meso|Star> (contact@meso-star.com) * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -246,35 +246,35 @@ check_probe_conform_to_type "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); + struct solid* solid = filter_ctx.desc->d.solid; + ASSERT(solid->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) { + "Probe was in solid '%s'.\n", str_cget(&solid->name)); + if(filter_ctx.dist > 2 * solid->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); + filter_ctx.dist / solid->delta); res = RES_BAD_ARG; goto error; } - if(filter_ctx.dist > 0.5 * delta) { + if(filter_ctx.dist > 0.5 * solid->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); + "Consider using -p instead of -P.\n", + filter_ctx.dist / solid->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); + filter_ctx.dist / solid->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)); + "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); } @@ -329,34 +329,34 @@ check_probe_conform_to_type goto error; } logger_print(stardis->logger, LOG_OUTPUT, - "Probe is in solid '%s'.\n", str_cget(&filter_ctx.desc->d.solid.name)); + "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) { + struct solid* solid = filter_ctx.desc->d.solid; + if(filter_ctx.dist < 0.25 * solid->delta) { logger_print(stardis->logger, LOG_ERROR, "Probe is %g delta from closest boundary. Use -P instead of -p.\n", - filter_ctx.dist / delta); + filter_ctx.dist / solid->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) { + if(filter_ctx.dist < 0.5 * solid->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); + filter_ctx.dist / solid->delta); } else { logger_print(stardis->logger, LOG_OUTPUT, "Probe is %g delta from closest boundary.\n", - filter_ctx.dist / delta); + filter_ctx.dist / solid->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)); + str_cget(&filter_ctx.desc->d.fluid->name)); /* In fluid; TODO: check distance wrt local geometry (use 4V/S?) */ } } @@ -375,40 +375,47 @@ error: } #define READ_RANDOM_STATE(Name) \ - if(!str_is_empty(Name)) { \ - const char* name = str_cget(Name); \ - stream = fopen(name, "r"); \ - if(!stream) { \ - res = RES_IO_ERR; \ - logger_print(stardis->logger, LOG_ERROR, \ - "Could not open generator's state file ('%s').\n", \ - name); \ - goto error; \ + if(!stardis->mpi_initialized || stardis->mpi_rank == 0) { \ + if(str_is_empty(Name)) { \ + /* Force using threefry independently of the default RNG type */ \ + args.rng_type = SSP_RNG_THREEFRY; \ + } else { \ + const char* name = str_cget(Name); \ + stream = fopen(name, "r"); \ + if(!stream) { \ + res = RES_IO_ERR; \ + logger_print(stardis->logger, LOG_ERROR, \ + "Could not open generator's state file ('%s').\n", \ + name); \ + goto error; \ + } \ + ERR(ssp_rng_create(stardis->allocator, SSP_RNG_THREEFRY, &args.rng_state)); \ + res = read_random_generator_state(args.rng_state, stream); \ + if(res != RES_OK) { \ + logger_print(stardis->logger, LOG_ERROR, \ + "Could not read random generator's state ('%s').\n", \ + name); \ + goto error; \ + } \ + fclose(stream); stream = NULL; \ } \ - ERR(ssp_rng_create(stardis->allocator, SSP_RNG_MT19937_64, &args.rng_state)); \ - res = read_random_generator_state(args.rng_state, stream); \ - if(res != RES_OK) { \ - logger_print(stardis->logger, LOG_ERROR, \ - "Could not read random generator's state ('%s').\n", \ - name); \ - goto error; \ - } \ - fclose(stream); stream = NULL; \ } #define WRITE_RANDOM_STATE(Name) \ - if(!str_is_empty(Name)) { \ - const char* name = str_cget(Name); \ - stream = fopen(name, "wb"); \ - if(!stream) { \ - res = RES_IO_ERR; \ - logger_print(stardis->logger, LOG_ERROR, \ - "Could not write random generator's state ('%s').\n", \ - name); \ - goto error; \ + if(!stardis->mpi_initialized || stardis->mpi_rank == 0) { \ + if(!str_is_empty(Name)) { \ + const char* name = str_cget(Name); \ + stream = fopen(name, "wb"); \ + if(!stream) { \ + res = RES_IO_ERR; \ + logger_print(stardis->logger, LOG_ERROR, \ + "Could not write random generator's state ('%s').\n", \ + name); \ + goto error; \ + } \ + ERR(write_random_generator_state(estimator, stream)); \ + fclose(stream); stream = NULL; \ } \ - ERR(write_random_generator_state(estimator, stream)); \ - fclose(stream); stream = NULL; \ } static res_T @@ -436,50 +443,59 @@ compute_probe(struct stardis* stardis, struct time* start) READ_RANDOM_STATE(&stardis->rndgen_state_in_filename); if(stardis->mode & (MODE_BIN_GREEN | MODE_GREEN)) { - time_current(&compute_start); - ERR(sdis_solve_probe_green_function(stardis->sdis_scn, &args, &green)); - time_current(&compute_end); - if(stardis->mode & MODE_BIN_GREEN) { - struct time output_end; - 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(stardis->mpi_initialized && stardis->mpi_rank != 0) { + ERR(sdis_solve_probe_green_function(stardis->sdis_scn, &args, &green)); + } else { + time_current(&compute_start); + ERR(sdis_solve_probe_green_function(stardis->sdis_scn, &args, &green)); + time_current(&compute_end); + if(stardis->mode & MODE_BIN_GREEN) { + struct time output_end; + 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_paths_end(green, stardis, stream)); + 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; + } + time_current(&output_end); + ERR(print_computation_time(NULL, stardis, + start, &compute_start, &compute_end, &output_end)); + } + if(stardis->mode & MODE_GREEN) { + ERR(dump_green_ascii(green, stardis, stdout)); } - time_current(&output_end); - ERR(print_computation_time(NULL, stardis, - start, &compute_start, &compute_end, &output_end)); - } - if(stardis->mode & MODE_GREEN) { - ERR(dump_green_ascii(green, stardis, stdout)); } } else { args.register_paths = stardis->dump_paths; - time_current(&compute_start); - ERR(sdis_solve_probe(stardis->sdis_scn, &args, &estimator)); - time_current(&compute_end); - ERR(print_computation_time(estimator, stardis, - start, &compute_start, &compute_end, NULL)); - ERR(print_single_MC_result(estimator, stardis, stdout)); - - /* Dump recorded paths according to user settings */ - dump_ctx.stardis = stardis; - dump_ctx.rank = 0; - ERR(sdis_estimator_for_each_path(estimator, dump_path, &dump_ctx)); + args.picard_order = stardis->picard_order; + if(stardis->mpi_initialized && stardis->mpi_rank != 0) { + ERR(sdis_solve_probe(stardis->sdis_scn, &args, &estimator)); + } else { + time_current(&compute_start); + ERR(sdis_solve_probe(stardis->sdis_scn, &args, &estimator)); + time_current(&compute_end); + ERR(print_computation_time(estimator, stardis, + start, &compute_start, &compute_end, NULL)); + ERR(print_single_MC_result(estimator, stardis, stdout)); + + /* Dump recorded paths according to user settings */ + dump_ctx.stardis = stardis; + dump_ctx.rank = 0; + ERR(sdis_estimator_for_each_path(estimator, dump_path, &dump_ctx)); + } } /* Output random state? */ @@ -532,7 +548,7 @@ compute_probe_on_interface(struct stardis* stardis, struct time* start) ASSERT(prop[SG3D_INTFACE] < dcount); intface_desc = descriptions + prop[SG3D_INTFACE]; if(intface_desc->type == DESC_SOLID_SOLID_CONNECT) - tcr = intface_desc->d.ss_connect.tcr; + tcr = intface_desc->d.ss_connect->tcr; } if(str_is_empty(&stardis->solve_name)) { @@ -544,7 +560,7 @@ compute_probe_on_interface(struct stardis* stardis, struct time* start) const struct description* d; ASSERT(prop[SG3D_FRONT] < dcount); d = descriptions + prop[SG3D_FRONT]; - ASSERT(d->type == DESC_MAT_SOLID || d->type == DESC_MAT_FLUID); + ASSERT(DESC_IS_MEDIUM(d->type)); medium_name = str_cget(get_description_name(d)); compute_side = SDIS_FRONT; compute_side_name = "FRONT"; @@ -553,7 +569,7 @@ compute_probe_on_interface(struct stardis* stardis, struct time* start) const struct description* d; ASSERT(prop[SG3D_BACK] < dcount); d = descriptions + prop[SG3D_BACK]; - ASSERT(d->type == DESC_MAT_SOLID || d->type == DESC_MAT_FLUID); + ASSERT(DESC_IS_MEDIUM(d->type)); medium_name = str_cget(get_description_name(d)); compute_side = SDIS_BACK; compute_side_name = "BACK"; @@ -573,12 +589,10 @@ compute_probe_on_interface(struct stardis* stardis, struct time* start) fd = descriptions + prop[SG3D_FRONT]; bd = descriptions + prop[SG3D_BACK]; - ASSERT(fd->type == DESC_MAT_SOLID || fd->type == DESC_MAT_FLUID); - fmat_id = (fd->type == DESC_MAT_SOLID) - ? fd->d.solid.solid_id : fd->d.fluid.fluid_id; - ASSERT(bd->type == DESC_MAT_SOLID || bd->type == DESC_MAT_FLUID); - bmat_id = (bd->type == DESC_MAT_SOLID) - ? bd->d.solid.solid_id : bd->d.fluid.fluid_id; + ASSERT(DESC_IS_MEDIUM(fd->type)); + ASSERT(DESC_IS_MEDIUM(bd->type)); + description_get_medium_id(fd, &fmat_id); + description_get_medium_id(bd, &bmat_id); if(med_id != fmat_id && med_id != bmat_id) { /* Not here */ logger_print(stardis->logger, LOG_ERROR, @@ -671,51 +685,61 @@ compute_probe_on_interface(struct stardis* stardis, struct time* start) READ_RANDOM_STATE(&stardis->rndgen_state_in_filename); if(stardis->mode & (MODE_BIN_GREEN | MODE_GREEN)) { - time_current(&compute_start); - ERR(sdis_solve_probe_boundary_green_function(stardis->sdis_scn, &args, - &green)); - time_current(&compute_end); - if(stardis->mode & MODE_BIN_GREEN) { - struct time output_end; - 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(stardis->mpi_initialized && stardis->mpi_rank != 0) { + ERR(sdis_solve_probe_boundary_green_function(stardis->sdis_scn, &args, + &green)); + } else { + time_current(&compute_start); + ERR(sdis_solve_probe_boundary_green_function(stardis->sdis_scn, &args, + &green)); + time_current(&compute_end); + if(stardis->mode & MODE_BIN_GREEN) { + struct time output_end; + 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_paths_end(green, stardis, stream)); + 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; + } + time_current(&output_end); + ERR(print_computation_time(NULL, stardis, + start, &compute_start, &compute_end, &output_end)); + } + if(stardis->mode & MODE_GREEN) { + ERR(dump_green_ascii(green, stardis, stdout)); } - time_current(&output_end); - ERR(print_computation_time(NULL, stardis, - start, &compute_start, &compute_end, &output_end)); - } - if(stardis->mode & MODE_GREEN) { - ERR(dump_green_ascii(green, stardis, stdout)); } } else { args.register_paths = stardis->dump_paths; - time_current(&compute_start); - ERR(sdis_solve_probe_boundary(stardis->sdis_scn, &args, &estimator)); - time_current(&compute_end); - ERR(print_computation_time(estimator, stardis, - start, &compute_start, &compute_end, NULL)); - ERR(print_single_MC_result(estimator, stardis, stdout)); + args.picard_order = stardis->picard_order; + if(stardis->mpi_initialized && stardis->mpi_rank != 0) { + ERR(sdis_solve_probe_boundary(stardis->sdis_scn, &args, &estimator)); + } else { + time_current(&compute_start); + ERR(sdis_solve_probe_boundary(stardis->sdis_scn, &args, &estimator)); + time_current(&compute_end); + ERR(print_computation_time(estimator, stardis, + start, &compute_start, &compute_end, NULL)); + ERR(print_single_MC_result(estimator, stardis, stdout)); - /* Dump recorded paths according to user settings */ - dump_ctx.stardis = stardis; - dump_ctx.rank = 0; - ERR(sdis_estimator_for_each_path(estimator, dump_path, &dump_ctx)); + /* Dump recorded paths according to user settings */ + dump_ctx.stardis = stardis; + dump_ctx.rank = 0; + ERR(sdis_estimator_for_each_path(estimator, dump_path, &dump_ctx)); + } } /* Output random state? */ @@ -849,48 +873,53 @@ compute_camera(struct stardis* stardis, struct time* start) args.cam = cam; d2_set(args.time_range, stardis->camera.time_range); - args.image_resolution[0] = width; - args.image_resolution[1] = height; + args.image_definition[0] = width; + args.image_definition[1] = height; args.spp = (size_t)stardis->camera.spp; args.register_paths = stardis->dump_paths; + args.picard_order = stardis->picard_order; /* Launch the simulation */ - time_current(&compute_start); - ERR(sdis_solve_camera(stardis->sdis_scn, &args, &buf)); - time_current(&compute_end); - - /* Write the image */ - if(str_is_empty(&stardis->camera.file_name)) - stream = stdout; - else { - stream = fopen(str_cget(&stardis->camera.file_name), "w"); - if(!stream) { - res = RES_IO_ERR; - goto error; + if(stardis->mpi_initialized && stardis->mpi_rank != 0) { + ERR(sdis_solve_camera(stardis->sdis_scn, &args, &buf)); + } else { + time_current(&compute_start); + ERR(sdis_solve_camera(stardis->sdis_scn, &args, &buf)); + time_current(&compute_end); + + /* Write the image */ + if(str_is_empty(&stardis->camera.file_name)) + stream = stdout; + else { + stream = fopen(str_cget(&stardis->camera.file_name), "w"); + if(!stream) { + res = RES_IO_ERR; + goto error; + } } - } - 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, stream)); - else ERR(dump_ht_image(buf, stream)); - if(!str_is_empty(&stardis->camera.file_name)) - fclose(stream); - - /* Dump recorded paths 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)); + 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, stream)); + else ERR(dump_ht_image(buf, stream)); + if(!str_is_empty(&stardis->camera.file_name)) + fclose(stream); + + /* Dump recorded paths 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)); + } } + time_current(&output_end); + ERR(print_computation_time(NULL, stardis, + start, &compute_start, &compute_end, NULL)); } - time_current(&output_end); - ERR(print_computation_time(NULL, stardis, - start, &compute_start, &compute_end, NULL)); end: if(cam) SDIS(camera_ref_put(cam)); @@ -932,49 +961,58 @@ compute_medium(struct stardis* stardis, struct time* start) READ_RANDOM_STATE(&stardis->rndgen_state_in_filename); if(stardis->mode & (MODE_BIN_GREEN | MODE_GREEN)) { - time_current(&compute_start); - ERR(sdis_solve_medium_green_function(stardis->sdis_scn, &args, &green)); - time_current(&compute_end); - if(stardis->mode & MODE_BIN_GREEN) { - struct time output_end; - 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(stardis->mpi_initialized && stardis->mpi_rank != 0) { + ERR(sdis_solve_medium_green_function(stardis->sdis_scn, &args, &green)); + } else { + time_current(&compute_start); + ERR(sdis_solve_medium_green_function(stardis->sdis_scn, &args, &green)); + time_current(&compute_end); + if(stardis->mode & MODE_BIN_GREEN) { + struct time output_end; + 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_paths_end(green, stardis, stream)); + 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; + } + time_current(&output_end); + ERR(print_computation_time(NULL, stardis, + start, &compute_start, &compute_end, &output_end)); + } + if(stardis->mode & MODE_GREEN) { + ERR(dump_green_ascii(green, stardis, stdout)); } - time_current(&output_end); - ERR(print_computation_time(NULL, stardis, - start, &compute_start, &compute_end, &output_end)); - } - if(stardis->mode & MODE_GREEN) { - ERR(dump_green_ascii(green, stardis, stdout)); } } else { args.register_paths = stardis->dump_paths; - time_current(&compute_start); - ERR(sdis_solve_medium(stardis->sdis_scn, &args, &estimator)); - time_current(&compute_end); - ERR(print_computation_time(estimator, stardis, - start, &compute_start, &compute_end, NULL)); - ERR(print_single_MC_result(estimator, stardis, stdout)); - /* Dump recorded paths according to user settings */ - dump_ctx.stardis = stardis; - dump_ctx.rank = 0; - ERR(sdis_estimator_for_each_path(estimator, dump_path, &dump_ctx)); + args.picard_order = stardis->picard_order; + if(stardis->mpi_initialized && stardis->mpi_rank != 0) { + ERR(sdis_solve_medium(stardis->sdis_scn, &args, &estimator)); + } else { + time_current(&compute_start); + ERR(sdis_solve_medium(stardis->sdis_scn, &args, &estimator)); + time_current(&compute_end); + ERR(print_computation_time(estimator, stardis, + start, &compute_start, &compute_end, NULL)); + ERR(print_single_MC_result(estimator, stardis, stdout)); + /* Dump recorded paths according to user settings */ + dump_ctx.stardis = stardis; + dump_ctx.rank = 0; + ERR(sdis_estimator_for_each_path(estimator, dump_path, &dump_ctx)); + } } /* Output random state? */ @@ -1063,49 +1101,58 @@ compute_boundary(struct stardis* stardis, struct time* start) READ_RANDOM_STATE(&stardis->rndgen_state_in_filename); if(stardis->mode & (MODE_BIN_GREEN | MODE_GREEN)) { - time_current(&compute_start); - ERR(sdis_solve_boundary_green_function(stardis->sdis_scn, &args, &green)); - time_current(&compute_end); - if(stardis->mode & MODE_BIN_GREEN) { - struct time output_end; - 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(stardis->mpi_initialized && stardis->mpi_rank != 0) { + ERR(sdis_solve_boundary_green_function(stardis->sdis_scn, &args, &green)); + } else { + time_current(&compute_start); + ERR(sdis_solve_boundary_green_function(stardis->sdis_scn, &args, &green)); + time_current(&compute_end); + if(stardis->mode & MODE_BIN_GREEN) { + struct time output_end; + 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_paths_end(green, stardis, stream)); + 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; + } + time_current(&output_end); + ERR(print_computation_time(NULL, stardis, + start, &compute_start, &compute_end, &output_end)); + } + if(stardis->mode & MODE_GREEN) { + ERR(dump_green_ascii(green, stardis, stdout)); } - time_current(&output_end); - ERR(print_computation_time(NULL, stardis, - start, &compute_start, &compute_end, &output_end)); - } - if(stardis->mode & MODE_GREEN) { - ERR(dump_green_ascii(green, stardis, stdout)); } } else { args.register_paths = stardis->dump_paths; - time_current(&compute_start); - ERR(sdis_solve_boundary(stardis->sdis_scn, &args, &estimator)); - time_current(&compute_end); - ERR(print_computation_time(estimator, stardis, - start, &compute_start, &compute_end, NULL)); - ERR(print_single_MC_result(estimator, stardis, stdout)); - /* Dump recorded paths according to user settings */ - dump_ctx.stardis = stardis; - dump_ctx.rank = 0; - ERR(sdis_estimator_for_each_path(estimator, dump_path, &dump_ctx)); + args.picard_order = stardis->picard_order; + if(stardis->mpi_initialized && stardis->mpi_rank != 0) { + ERR(sdis_solve_boundary(stardis->sdis_scn, &args, &estimator)); + } else { + time_current(&compute_start); + ERR(sdis_solve_boundary(stardis->sdis_scn, &args, &estimator)); + time_current(&compute_end); + ERR(print_computation_time(estimator, stardis, + start, &compute_start, &compute_end, NULL)); + ERR(print_single_MC_result(estimator, stardis, stdout)); + /* Dump recorded paths according to user settings */ + dump_ctx.stardis = stardis; + dump_ctx.rank = 0; + ERR(sdis_estimator_for_each_path(estimator, dump_path, &dump_ctx)); + } } /* Output random state? */ @@ -1140,22 +1187,27 @@ compute_flux_boundary(struct stardis* stardis, struct time* start) = darray_size_t_cdata_get(&stardis->compute_surface.primitives); args.nprimitives = darray_size_t_size_get(&stardis->compute_surface.primitives); + args.picard_order = stardis->picard_order; d2_set(args.time_range, stardis->time_range); /* Input random state? */ READ_RANDOM_STATE(&stardis->rndgen_state_in_filename); - time_current(&compute_start); - ERR(sdis_solve_boundary_flux(stardis->sdis_scn, &args, &estimator)); - time_current(&compute_end); - ERR(print_computation_time(estimator, stardis, - start, &compute_start, &compute_end, NULL)); - ERR(print_single_MC_result(estimator, stardis, stdout)); + if(stardis->mpi_initialized && stardis->mpi_rank != 0) { + ERR(sdis_solve_boundary_flux(stardis->sdis_scn, &args, &estimator)); + } else { + time_current(&compute_start); + ERR(sdis_solve_boundary_flux(stardis->sdis_scn, &args, &estimator)); + time_current(&compute_end); + ERR(print_computation_time(estimator, stardis, + start, &compute_start, &compute_end, NULL)); + ERR(print_single_MC_result(estimator, stardis, stdout)); - /* Dump recorded paths according to user settings */ - dump_ctx.stardis = stardis; - dump_ctx.rank = 0; - ERR(sdis_estimator_for_each_path(estimator, dump_path, &dump_ctx)); + /* Dump recorded paths according to user settings */ + dump_ctx.stardis = stardis; + dump_ctx.rank = 0; + ERR(sdis_estimator_for_each_path(estimator, dump_path, &dump_ctx)); + } /* Output random state? */ WRITE_RANDOM_STATE(&stardis->rndgen_state_out_filename); @@ -1201,11 +1253,14 @@ compute_map(struct stardis* stardis, struct time* start) = darray_size_t_size_get(&stardis->compute_surface.primitives); d2_set(args.time_range, stardis->time_range); args.register_paths = stardis->dump_paths; + args.picard_order = stardis->picard_order; ERR(sdis_solve_boundary(stardis->sdis_scn, &args, darray_estimators_data_get(&estimators) + p)); } - dump_map(stardis, &estimators, stdout); + if(stardis->mpi_initialized && stardis->mpi_rank != 0) { + ERR(dump_map(stardis, &estimators, stdout)); + } end: if(estimators_initialized) { @@ -1240,26 +1295,16 @@ find_medium_by_name 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; - } - } - 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; - } - } + unsigned id; + struct description* desc = + darray_descriptions_data_get(&stardis->descriptions) + i; + if(!str_eq(name, get_description_name(desc))) + continue; + description_get_medium_id(desc, &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; } diff --git a/src/stardis-compute.h b/src/stardis-compute.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2018-2021 |Meso|Star> (contact@meso-star.com) +/* Copyright (C) 2018-2022 |Meso|Star> (contact@meso-star.com) * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/src/stardis-default.h.in b/src/stardis-default.h.in @@ -17,8 +17,10 @@ #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_TRAD @STARDIS_ARGS_DEFAULT_TRAD@ +#define STARDIS_DEFAULT_TRAD_REFERENCE @STARDIS_ARGS_DEFAULT_TRAD_REFERENCE@ #define STARDIS_DEFAULT_COMPUTE_TIME @STARDIS_ARGS_DEFAULT_COMPUTE_TIME@ +#define STARDIS_DEFAULT_PICARD_ORDER @STARDIS_ARGS_DEFAULT_PICARD_ORDER@ #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@ @@ -28,7 +30,6 @@ #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@ diff --git a/src/stardis-fluid.c b/src/stardis-fluid.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2018-2021 |Meso|Star> (contact@meso-star.com) +/* Copyright (C) 2018-2022 |Meso|Star> (contact@meso-star.com) * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -19,6 +19,8 @@ #include <sdis.h> +#include <rsys/mem_allocator.h> + #include <limits.h> /******************************************************************************* @@ -30,9 +32,9 @@ fluid_get_calorific_capacity (const struct sdis_rwalk_vertex* vtx, struct sdis_data* data) { - const struct fluid* fluid_props = sdis_data_cget(data); + const struct fluid* const* fluid_props = sdis_data_cget(data); (void)vtx; - return fluid_props->cp; + return (*fluid_props)->cp; } static double @@ -40,9 +42,9 @@ fluid_get_volumic_mass (const struct sdis_rwalk_vertex* vtx, struct sdis_data* data) { - const struct fluid* fluid_props = sdis_data_cget(data); + const struct fluid* const* fluid_props = sdis_data_cget(data); (void)vtx; - return fluid_props->rho; + return (*fluid_props)->rho; } static double @@ -50,21 +52,21 @@ 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) + const struct fluid* const* 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) { + 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)) { + 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))); + ARG1(str_cget(&(*fluid_props)->name))); } } - return fluid_props->tinit; + return (*fluid_props)->tinit; } return -1; /* Unknown temperature */ } @@ -81,22 +83,21 @@ create_solver_fluid res_T res = RES_OK; struct sdis_fluid_shader fluid_shader = SDIS_FLUID_SHADER_NULL; struct sdis_data* data = NULL; - struct fluid* props; + const 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), + 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); + *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); + ASSERT(!darray_media_ptr_data_get(&stardis->media)[fluid_props->fluid_id]); ERR(sdis_fluid_create(stardis->dev, &fluid_shader, data, darray_media_ptr_data_get(&stardis->media) + fluid_props->fluid_id)); @@ -107,25 +108,44 @@ error: goto end; } -void -init_fluid(struct mem_allocator* allocator, struct fluid* dst) +res_T +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; + res_T res = RES_OK; + int str_initialized = 0; + ASSERT(allocator && dst && *dst == NULL); + *dst = MEM_ALLOC(allocator, sizeof(struct fluid)); + if(! *dst) { + res = RES_MEM_ERR; + goto error; + } + str_init(allocator, &(*dst)->name); + str_initialized = 1; + (*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; +end: + return res; +error: + if(str_initialized) str_release(&(*dst)->name); + if(*dst) MEM_RM(allocator, *dst); + goto end; } void -release_fluid(struct fluid* fluid) +release_fluid + (struct fluid* fluid, + struct mem_allocator* allocator) { + ASSERT(fluid && allocator); str_release(&fluid->name); + MEM_RM(allocator, fluid); } res_T @@ -147,18 +167,3 @@ end: 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 @@ -1,4 +1,4 @@ -/* Copyright (C) 2018-2021 |Meso|Star> (contact@meso-star.com) +/* Copyright (C) 2018-2022 |Meso|Star> (contact@meso-star.com) * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -22,6 +22,7 @@ #include <rsys/str.h> struct stardis; +struct mem_allocator; /******************************************************************************* * Fluid data @@ -44,16 +45,15 @@ 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 res_T +init_fluid(struct mem_allocator* allocator, struct fluid** dst); LOCAL_SYM void -release_fluid(struct fluid* fluid); +release_fluid + (struct fluid* desc, + struct mem_allocator* allocator); 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-green-types.h.in b/src/stardis-green-types.h.in @@ -0,0 +1,129 @@ +/* Copyright (C) 2018-2022 |Meso|Star> (contact@meso-star.com) + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. */ + +#ifndef SDIS_GREEN_H +#define SDIS_GREEN_H + +/* The number of the file format as presented thereafter */ +#define GREEN_FILE_FORMAT_VERSION @STARDIS_GREEN_TYPES_VERSION@ + +/* The max length for a description name */ +#define DESC_NAME_MAX_LEN 63 + +/* The string at the beginning of a binary Green file that identifies it */ +#define BIN_FILE_IDENT_STRING "GREEN_BIN_FILE:" + +/* The header of a binary Green file */ +struct green_file_header { + char green_string[sizeof(BIN_FILE_IDENT_STRING)]; + unsigned file_format_version; + unsigned description_count; + unsigned solid_count; + unsigned fluid_count; + unsigned hbound_count; + unsigned tbound_count; + unsigned fbound_count; + unsigned sfconnect_count; + unsigned ssconnect_count; + size_t ok_count; + size_t failed_count; + double ambient_radiative_temperature; + double ambient_radiative_temperature_reference; + double time_range[2]; +}; + +/* Different types of descriptions */ +enum green_description_type { + GREEN_MAT_SOLID, + GREEN_MAT_FLUID, + GREEN_BOUND_H, + GREEN_BOUND_T, + GREEN_BOUND_F, + GREEN_SOLID_FLUID_CONNECT, + GREEN_SOLID_SOLID_CONNECT +}; + +struct green_solid { + char name[DESC_NAME_MAX_LEN+1]; + double conductivity; + double volumic_mass; + double calorific_capacity; + double volumic_power; + double initial_temperature; + double imposed_temperature; +}; + +struct green_fluid { + char name[DESC_NAME_MAX_LEN+1]; + double volumic_mass; + double calorific_capacity; + double initial_temperature; + double imposed_temperature; +}; + +struct green_h_boundary { + char name[DESC_NAME_MAX_LEN+1]; + double reference_temperature; + double emissivity; + double specular_fraction; + double convection_coefficient; + double imposed_temperature; +}; + +struct green_t_boundary { + char name[DESC_NAME_MAX_LEN+1]; + double imposed_temperature; +}; + +struct green_f_boundary { + char name[DESC_NAME_MAX_LEN+1]; + double imposed_flux; +}; + +struct green_solid_fluid_connect { + char name[DESC_NAME_MAX_LEN+1]; + double reference_temperature; + double emissivity; + double specular_fraction; + double convection_coefficient; +}; + +struct green_solid_solid_connect { + char name[DESC_NAME_MAX_LEN+1]; + double thermal_contact_resistance; +}; + +struct green_description { + enum green_description_type type; + union { + struct green_fluid fluid; + struct green_solid solid; + struct green_t_boundary t_boundary; + struct green_f_boundary f_boundary; + struct green_h_boundary h_boundary; + struct green_solid_fluid_connect sf_connect; + struct green_solid_solid_connect ss_connect; + } d; +}; + +/* The header of a Green sample */ +struct green_sample_header { + unsigned pw_count; + unsigned fx_count; + unsigned sample_end_description_id; + int at_initial; +}; + +#endif diff --git a/src/stardis-intface.c b/src/stardis-intface.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2018-2021 |Meso|Star> (contact@meso-star.com) +/* Copyright (C) 2018-2022 |Meso|Star> (contact@meso-star.com) * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -56,6 +56,16 @@ interface_get_flux } static double +interface_get_ref_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->ref_temperature; +} + +static double interface_get_emissivity (const struct sdis_interface_fragment* frag, struct sdis_data* data) @@ -150,14 +160,14 @@ create_intface if(front_defined) { switch (descriptions[fd].type) { case DESC_MAT_SOLID: - id = descriptions[fd].d.solid.solid_id; + 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; + id = descriptions[fd].d.fluid->fluid_id; interface_props->front_medium_id = id; front_med = media[id]; fluid_side_shader = &interface_shader.front; @@ -169,14 +179,14 @@ create_intface if(back_defined) { switch (descriptions[bd].type) { case DESC_MAT_SOLID: - id = descriptions[bd].d.solid.solid_id; + 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; + 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 @@ -222,9 +232,9 @@ create_intface goto error; } type_checked = 1; - ASSERT(connect->d.h_boundary.imposed_temperature >= 0); + ASSERT(connect->d.h_boundary->imposed_temperature >= 0); interface_props->imposed_temperature - = connect->d.h_boundary.imposed_temperature; + = connect->d.h_boundary->imposed_temperature; ASSERT(fluid_side_shader); fluid_side_shader->temperature = interface_get_temperature; /* fall through */ @@ -234,7 +244,7 @@ create_intface { res = RES_BAD_ARG; goto error; } - ext_id = connect->d.h_boundary.mat_id; /* External material id */ + 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)); @@ -242,15 +252,17 @@ create_intface 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_upper_bound = connect->d.h_boundary->hc; + interface_props->hc = connect->d.h_boundary->hc; + interface_props->ref_temperature = connect->d.h_boundary->ref_temperature; + 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); + ASSERT(fluid_side_shader); + fluid_side_shader->reference_temperature = interface_get_ref_temperature; + if(connect->d.h_boundary->emissivity > 0) { fluid_side_shader->emissivity = interface_get_emissivity; fluid_side_shader->specular_fraction = interface_get_alpha; } @@ -260,7 +272,7 @@ create_intface res = RES_BAD_ARG; goto error; } - ext_id = connect->d.t_boundary.mat_id; /* External material id */ + 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]) == SDIS_FLUID); connection_count++; @@ -278,11 +290,12 @@ create_intface /* 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->reference_temperature = interface_get_ref_temperature; fluid_side_shader->emissivity = interface_get_emissivity; interface_props->emissivity = 1; - ASSERT(connect->d.t_boundary.imposed_temperature >= 0); + ASSERT(connect->d.t_boundary->imposed_temperature >= 0); interface_props->imposed_temperature - = connect->d.t_boundary.imposed_temperature; + = connect->d.t_boundary->imposed_temperature; break; case DESC_BOUND_F_FOR_SOLID: if(sdis_medium_get_type(def_medium) != SDIS_SOLID) { @@ -292,14 +305,14 @@ create_intface connection_count++; boundary_count++; if(front_defined) { - back_med = media[connect->d.f_boundary.mat_id]; + 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]; + 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; + 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 */ @@ -310,15 +323,17 @@ create_intface 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_upper_bound = connect->d.sf_connect->hc; + interface_props->hc = connect->d.sf_connect->hc; + interface_props->ref_temperature = connect->d.sf_connect->ref_temperature; + 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); + ASSERT(fluid_side_shader); + fluid_side_shader->reference_temperature = interface_get_ref_temperature; + if(connect->d.sf_connect->emissivity > 0) { fluid_side_shader->emissivity = interface_get_emissivity; fluid_side_shader->specular_fraction = interface_get_alpha; } @@ -332,8 +347,8 @@ create_intface ASSERT(front_defined && back_defined); connection_count++; solid_solid_connection_count++; - interface_props->tcr = connect->d.ss_connect.tcr; - if(connect->d.ss_connect.tcr > 0) { + interface_props->tcr = connect->d.ss_connect->tcr; + if(connect->d.ss_connect->tcr > 0) { interface_shader.thermal_contact_resistance = interface_get_tcr; } break; diff --git a/src/stardis-intface.h b/src/stardis-intface.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2018-2021 |Meso|Star> (contact@meso-star.com) +/* Copyright (C) 2018-2022 |Meso|Star> (contact@meso-star.com) * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -29,6 +29,7 @@ struct dummies; struct intface { /* fluid - solid */ double hc; + double ref_temperature; double emissivity; double alpha; /* solid - solid */ diff --git a/src/stardis-main.c b/src/stardis-main.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2018-2021 |Meso|Star> (contact@meso-star.com) +/* Copyright (C) 2018-2022 |Meso|Star> (contact@meso-star.com) * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -26,6 +26,10 @@ #include <stdlib.h> #include <stdio.h> +#ifdef STARDIS_ENABLE_MPI +#include <mpi.h> +#endif + int main (int argc, @@ -44,12 +48,16 @@ main time_current(&start); +#ifdef STARDIS_ENABLE_MPI + ERR(init_mpi(&argc, &argv, log_err_fn, log_warn_fn)); +#endif + 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 */ + /* Active loggin for args parsing */ 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); @@ -119,6 +127,10 @@ exit: } mem_shutdown_proxy_allocator(&allocator); } +#ifdef STARDIS_ENABLE_MPI + finalize_mpi(); +#endif + return err; error: if(mode & COMPUTE_MODES) diff --git a/src/stardis-output.c b/src/stardis-output.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2018-2021 |Meso|Star> (contact@meso-star.com) +/* Copyright (C) 2018-2022 |Meso|Star> (contact@meso-star.com) * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -20,6 +20,7 @@ #include "stardis-solid.h" #include "stardis-intface.h" #include "stardis-app.h" +#include "stardis-green-types.h" #include <sdis.h> @@ -67,6 +68,83 @@ enum enclosure_errors_t { ENCLOSURE_WITH_UNDEF_MEDIUM = BIT(2) }; + +static res_T +copy_desc_to_green_desc + (struct green_description* gdesc, + const struct darray_descriptions* descriptions, + const size_t idx) +{ + size_t sz; + const struct description* desc; + ASSERT(gdesc && descriptions); + sz = darray_descriptions_size_get(descriptions); + CHK(idx < sz); + desc = darray_descriptions_cdata_get(descriptions) + idx; + switch(desc->type) { + case DESC_MAT_SOLID: + gdesc->type = GREEN_MAT_SOLID; + strcpy(gdesc->d.solid.name, str_cget(&desc->d.solid->name)); + gdesc->d.solid.conductivity = desc->d.solid->lambda; + gdesc->d.solid.volumic_mass = desc->d.solid->rho; + gdesc->d.solid.calorific_capacity = desc->d.solid->cp; + gdesc->d.solid.volumic_power = desc->d.solid->vpower; + gdesc->d.solid.initial_temperature = desc->d.solid->tinit; + gdesc->d.solid.imposed_temperature = desc->d.solid->imposed_temperature; + break; + case DESC_MAT_FLUID: + gdesc->type = GREEN_MAT_FLUID; + strcpy(gdesc->d.fluid.name, str_cget(&desc->d.fluid->name)); + gdesc->d.fluid.volumic_mass = desc->d.fluid->rho; + gdesc->d.fluid.calorific_capacity = desc->d.fluid->cp; + gdesc->d.fluid.initial_temperature = desc->d.fluid->tinit; + gdesc->d.fluid.imposed_temperature = desc->d.fluid->imposed_temperature; + break; + case DESC_BOUND_H_FOR_FLUID: + case DESC_BOUND_H_FOR_SOLID: + gdesc->type = GREEN_BOUND_H; + strcpy(gdesc->d.h_boundary.name, str_cget(&desc->d.h_boundary->name)); + gdesc->d.h_boundary.reference_temperature + = desc->d.h_boundary->ref_temperature; + gdesc->d.h_boundary.emissivity = desc->d.h_boundary->emissivity; + gdesc->d.h_boundary.specular_fraction + = desc->d.h_boundary->specular_fraction; + gdesc->d.h_boundary.convection_coefficient = desc->d.h_boundary->hc; + gdesc->d.h_boundary.imposed_temperature + = desc->d.h_boundary->imposed_temperature; + break; + case DESC_BOUND_T_FOR_SOLID: + gdesc->type = GREEN_BOUND_T; + strcpy(gdesc->d.t_boundary.name, str_cget(&desc->d.t_boundary->name)); + gdesc->d.t_boundary.imposed_temperature + = desc->d.t_boundary->imposed_temperature; + break; + case DESC_BOUND_F_FOR_SOLID: + gdesc->type = GREEN_BOUND_F; + strcpy(gdesc->d.f_boundary.name, str_cget(&desc->d.f_boundary->name)); + gdesc->d.f_boundary.imposed_flux + = desc->d.f_boundary->imposed_flux; + break; + case DESC_SOLID_FLUID_CONNECT: + gdesc->type = GREEN_SOLID_FLUID_CONNECT; + strcpy(gdesc->d.sf_connect.name, str_cget(&desc->d.sf_connect->name)); + gdesc->d.sf_connect.reference_temperature + = desc->d.sf_connect->ref_temperature; + gdesc->d.sf_connect.emissivity = desc->d.sf_connect->emissivity; + gdesc->d.sf_connect.specular_fraction + = desc->d.sf_connect->specular_fraction; + gdesc->d.sf_connect.convection_coefficient = desc->d.sf_connect->hc; + break; + case DESC_SOLID_SOLID_CONNECT: + gdesc->type = GREEN_SOLID_SOLID_CONNECT; + strcpy(gdesc->d.ss_connect.name, str_cget(&desc->d.ss_connect->name)); + gdesc->d.ss_connect.thermal_contact_resistance = desc->d.ss_connect->tcr; + break; + default: return RES_BAD_ARG; + } + return RES_OK; +} + /******************************************************************************* * Local Functions ******************************************************************************/ @@ -91,6 +169,7 @@ merge_flux_terms data = sdis_interface_get_data(interf); d__ = sdis_data_get(data); desc_id = d__->desc_id; + CHK(desc_id < darray_descriptions_size_get(w_ctx->desc)); descs = darray_descriptions_cdata_get(w_ctx->desc); switch (descs[desc_id].type) { @@ -123,9 +202,11 @@ merge_power_terms struct sdis_data* data = NULL; enum sdis_medium_type type; struct w_ctx* w_ctx = ctx; + size_t sz; ASSERT(mdm && w_ctx); + sz = darray_descriptions_size_get(w_ctx->desc); data = sdis_medium_get_data(mdm); type = sdis_medium_get_type(mdm); @@ -135,9 +216,10 @@ merge_power_terms FATAL("Unexpected power term in fluid"); } case SDIS_SOLID: { - struct solid* d__ = sdis_data_get(data); + struct solid** psolid = sdis_data_get(data); double* w; - unsigned id = d__->desc_id; + unsigned id = (*psolid)->desc_id; + CHK(id < sz); w = htable_weigth_find(&w_ctx->pw, &id); if(w) *w += power_term; else ERR(htable_weigth_set(&w_ctx->pw, &id, &power_term)); @@ -165,8 +247,8 @@ dump_path 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; + size_t vcount_, scount_, offset, name_sz, istrip; + unsigned long scount, vcount; ASSERT(path && dump_ctx && dump_ctx->stardis @@ -189,67 +271,121 @@ dump_path res = RES_IO_ERR; goto error; } + + /* Get counts */ + ERR(sdis_heat_path_get_line_strips_count(path, &scount_)); + if(scount > ULONG_MAX) goto abort; + scount = (unsigned long)scount_; + vcount_ = 0; + FOR_EACH(istrip, 0, scount_) { + size_t n; + ERR(sdis_heat_path_line_strip_get_vertices_count(path, istrip, &n)); + vcount_+= n; + } + if(vcount > ULONG_MAX) goto abort; + vcount = (unsigned long)vcount_; /* 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; + FOR_EACH(istrip, 0, scount_) { + size_t ivert, nverts; + ERR(sdis_heat_path_line_strip_get_vertices_count(path, istrip, &nverts)); + FOR_EACH(ivert, 0, nverts) { + struct sdis_heat_vertex vtx; + ERR(sdis_heat_path_line_strip_get_vertex(path, istrip, ivert, &vtx)); + fprintf(stream, "%g %g %g\n", SPLIT3(vtx.P)); + } + } + /* Write the strips of the path */ + fprintf(stream, "LINES %lu %lu\n", scount, scount + vcount); + offset = 0; + FOR_EACH(istrip, 0, scount) { + size_t ivert, nverts; + ERR(sdis_heat_path_line_strip_get_vertices_count(path, istrip, &nverts)); + if(nverts > ULONG_MAX) goto abort; + fprintf(stream, "%lu", (unsigned long)nverts); + FOR_EACH(ivert, 0, nverts) { + if(ivert + offset > ULONG_MAX) goto abort; + fprintf(stream, " %lu", (unsigned long)(ivert + offset)); + } + fprintf(stream, "\n"); + offset += nverts; } + /* Write path status on strips */ + fprintf(stream, "CELL_DATA %lu\n", scount); + fprintf(stream, "SCALARS Path_Failure unsigned_char 1\n"); + fprintf(stream, "LOOKUP_TABLE default\n"); + FOR_EACH(istrip, 0, scount) { + 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); + FOR_EACH(istrip, 0, scount_) { + size_t ivert, nverts; + ERR(sdis_heat_path_line_strip_get_vertices_count(path, istrip, &nverts)); + FOR_EACH(ivert, 0, nverts) { + struct sdis_heat_vertex vtx; + ERR(sdis_heat_path_line_strip_get_vertex(path, istrip, ivert, &vtx)); + if((size_t)vtx.type > UCHAR_MAX) goto abort; + switch(vtx.type) { + case SDIS_HEAT_VERTEX_CONDUCTION: fprintf(stream, "%d\n", 0); break; + case SDIS_HEAT_VERTEX_CONVECTION: fprintf(stream, "%d\n", 1); break; + case SDIS_HEAT_VERTEX_RADIATIVE: fprintf(stream, "%d\n", 2); break; + default: FATAL("Unreachable code.\n"); break; + } + } } /* 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); + FOR_EACH(istrip, 0, scount_) { + size_t ivert, nverts; + ERR(sdis_heat_path_line_strip_get_vertices_count(path, istrip, &nverts)); + FOR_EACH(ivert, 0, nverts) { + struct sdis_heat_vertex vtx; + ERR(sdis_heat_path_line_strip_get_vertex(path, istrip, ivert, &vtx)); + fprintf(stream, "%g\n", vtx.weight); + } + } + /* Write the branch_id of the random walk vertices */ + fprintf(stream, "SCALARS Branch_id int 1\n"); + fprintf(stream, "LOOKUP_TABLE default\n"); + FOR_EACH(istrip, 0, scount_) { + size_t ivert, nverts; + ERR(sdis_heat_path_line_strip_get_vertices_count(path, istrip, &nverts)); + FOR_EACH(ivert, 0, nverts) { + struct sdis_heat_vertex vtx; + ERR(sdis_heat_path_line_strip_get_vertex(path, istrip, ivert, &vtx)); + fprintf(stream, "%d\n", vtx.branch_id); + } } - /* If computation time is not INF for every vertex, + /* If computation time is not INF, * 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"); + FOR_EACH(istrip, 0, scount_) { + size_t ivert, nverts; + ERR(sdis_heat_path_line_strip_get_vertices_count(path, istrip, &nverts)); + FOR_EACH(ivert, 0, nverts) { + struct sdis_heat_vertex vtx; + ERR(sdis_heat_path_line_strip_get_vertex(path, istrip, ivert, &vtx)); + if(istrip == 0 && ivert == 0) { + if(IS_INF(vtx.time)) break; + fprintf(stream, "SCALARS Time double 1\n"); + fprintf(stream, "LOOKUP_TABLE default\n"); + } + if(IS_INF(vtx.time)) goto abort; + fprintf(stream, "%g\n", vtx.time); } - ASSERT(!IS_INF(vtx.time)); - fprintf(stream, "%g\n", vtx.time); } end: @@ -258,6 +394,9 @@ end: return res; error: goto end; +abort: + res = RES_BAD_ARG; + goto error; } res_T @@ -273,7 +412,7 @@ dump_vtk_image ASSERT(buf && stream); ERR(sdis_estimator_buffer_get_definition(buf, def)); - ASSERT(def[0] != 0 && def[1] != 0 && def[0] * def[1] <= ULONG_MAX); + if(def[0] == 0 || def[1] == 0 || def[0] * def[1] > ULONG_MAX) goto abort; definition[0] = (unsigned long)def[0]; definition[1] = (unsigned long)def[1]; @@ -344,7 +483,7 @@ dump_vtk_image size_t nfails; ERR(sdis_estimator_buffer_at(buf, ix, iy, &estimator)); ERR(sdis_estimator_get_failure_count(estimator, &nfails)); - ASSERT(nfails <= ULONG_MAX); + if(nfails > ULONG_MAX) goto abort; fprintf(stream, "%lu\n", (unsigned long)nfails); } } @@ -354,6 +493,9 @@ end: return res; error: goto end; +abort: + res = RES_BAD_ARG; + goto error; } res_T @@ -368,7 +510,7 @@ dump_ht_image ASSERT(buf && stream); ERR(sdis_estimator_buffer_get_definition(buf, def)); - ASSERT(def[0] <= ULONG_MAX && def[1] <= ULONG_MAX); + if(def[0] > ULONG_MAX || def[1] > ULONG_MAX) goto abort; definition[0] = (unsigned long)def[0]; definition[1] = (unsigned long)def[1]; @@ -390,6 +532,9 @@ end: return res; error: goto end; +abort: + res = RES_BAD_ARG; + goto error; } #define FW(Ptr, Count) \ @@ -398,12 +543,6 @@ error: goto error; \ } -struct path_header { - unsigned id; - unsigned pcount, fcount; - char at_initial; -}; - static FINLINE double medium_get_t0 (struct sdis_medium* medium) @@ -433,18 +572,20 @@ dump_sample_end enum sdis_green_path_end_type end_type; FILE* stream; double elapsed; + size_t sz; + unsigned trad_id; CHK(path && ctx); stream = e_ctx->stream; ERR(sdis_green_path_get_elapsed_time(path, &elapsed)); ERR(sdis_green_path_get_end_type(path, &end_type)); + sz = darray_descriptions_size_get(e_ctx->desc); + if(sz > UINT_MAX) goto abort; + trad_id = (unsigned)sz; if(end_type == SDIS_GREEN_PATH_END_RADIATIVE) { - size_t ambient_id = darray_descriptions_size_get(e_ctx->desc); - ASSERT(ambient_id <= UINT_MAX); /* End, End ID, X, Y, Z, Elapsed time */ - fprintf(stream, "AMBIENT, %u, 0, 0, 0, %g\n", - (unsigned)ambient_id, elapsed); + fprintf(stream, "TRAD, %u, 0, 0, 0, %g\n", trad_id, elapsed); } else { struct sdis_point pt = SDIS_POINT_NULL; struct sdis_data* data = NULL; @@ -471,19 +612,17 @@ dump_sample_end 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 */ + /* Radiative output (Trad) */ + id = trad_id; } else if(type == SDIS_FLUID) { - struct fluid* d__ = sdis_data_get(data); - id = d__->desc_id; + struct fluid** pfluid = sdis_data_get(data); + id = (*pfluid)->desc_id; } else { - struct solid* d__ = sdis_data_get(data); + struct solid** psolid = sdis_data_get(data); ASSERT(type == SDIS_SOLID); - ASSERT(!d__->is_outside); /* FIXME: what if in external solid? */ - id = d__->desc_id; + ASSERT(!(*psolid)->is_outside); /* FIXME: what if in external solid? */ + id = (*psolid)->desc_id; } break; default: FATAL("Unreachable code.\n"); break; @@ -497,6 +636,9 @@ end: return res; error: goto end; +abort: + res = RES_BAD_ARG; + goto error; } static res_T @@ -506,23 +648,24 @@ dump_sample { res_T res = RES_OK; struct htable_weigth_iterator it, end; - struct path_header header; + struct green_sample_header header; struct w_ctx* w_ctx = ctx; enum sdis_green_path_end_type end_type; FILE* stream; unsigned* ids = NULL; double* weights = NULL; size_t sz, i; - + unsigned trad_id; CHK(path && ctx); stream = w_ctx->stream; ERR(sdis_green_path_get_end_type(path, &end_type)); + sz = darray_descriptions_size_get(w_ctx->desc); + if(sz > UINT_MAX) goto abort; + trad_id = (unsigned)sz; if(end_type == SDIS_GREEN_PATH_END_RADIATIVE) { - size_t ambient_id = darray_descriptions_size_get(w_ctx->desc); - ASSERT(ambient_id <= UINT_MAX); header.at_initial = 0; - header.id = (unsigned)ambient_id; + header.sample_end_description_id = trad_id; } else { struct sdis_point pt = SDIS_POINT_NULL; struct sdis_data* data = NULL; @@ -547,7 +690,7 @@ dump_sample 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.sample_end_description_id = desc_id; header.at_initial = 0; break; } @@ -557,19 +700,17 @@ dump_sample 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 */ + /* Radiative output (Trad) */ + header.sample_end_description_id = trad_id; } else if(type == SDIS_FLUID) { - struct fluid* d__ = sdis_data_get(data); - header.id = d__->desc_id; + struct fluid** pfluid = sdis_data_get(data); + header.sample_end_description_id = (*pfluid)->desc_id; } else { - struct solid* d__ = sdis_data_get(data); + struct solid** psolid = sdis_data_get(data); ASSERT(type == SDIS_SOLID); - ASSERT(!d__->is_outside); /* FIXME: what if in external solid? */ - header.id = d__->desc_id; + ASSERT(!(*psolid)->is_outside); /* FIXME: what if in external solid? */ + header.sample_end_description_id = (*psolid)->desc_id; } break; default: FATAL("Unreachable code.\n"); break; @@ -582,17 +723,17 @@ dump_sample 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; + if(sz > UINT_MAX) goto abort; + header.pw_count = (unsigned)sz; sz = htable_weigth_size_get(&w_ctx->flux); - ASSERT(sz <= UINT_MAX); - header.fcount = (unsigned)sz; + if(sz > UINT_MAX) goto abort; + header.fx_count = (unsigned)sz; /* Write path's header */ FW(&header, 1); /* Allocate buffers */ - sz = header.pcount + header.fcount; + sz = header.pw_count + header.fx_count; ids = MEM_CALLOC(w_ctx->alloc, sz, sizeof(*ids)); weights = MEM_CALLOC(w_ctx->alloc, sz, sizeof(*weights)); if(!ids || !weights) { @@ -607,24 +748,26 @@ dump_sample while(!htable_weigth_iterator_eq(&it, &end)) { double* w = htable_weigth_iterator_data_get(&it); unsigned* k = htable_weigth_iterator_key_get(&it); + CHK(*k <= trad_id); ids[i] = *k; weights[i] = *w; htable_weigth_iterator_next(&it); i++; } - CHK(i == header.pcount); + CHK(i == header.pw_count); 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); + CHK(*k <= trad_id); ids[i] = *k; weights[i] = *w; htable_weigth_iterator_next(&it); i++; } - CHK(i == header.pcount + header.fcount); + CHK(i == header.pw_count + header.fx_count); FW(ids, sz); FW(weights, sz); @@ -635,6 +778,9 @@ end: return res; error: goto end; +abort: + res = RES_BAD_ARG; + goto error; } res_T @@ -644,95 +790,52 @@ dump_green_bin FILE* stream) { res_T res = RES_OK; - size_t ok_count, failed_count; - size_t sz; + size_t sz, i; 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; - const char green_string[] = "GREEN_BIN_FILE:"; - const unsigned file_fmt_version = 3; /* The following type must be identical to its stardis-green counterpart! */ - struct bfile_green_counts { - unsigned desc_count, smed_count, fmed_count, tbound_count, hbound_count, - fbound_count, sfconnect_count, ssconnect_count, name_pool_sz; - size_t ok_count, failed_count; - } file_counts; + struct green_file_header header; 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)); + /* Init header */ + strcpy(header.green_string, BIN_FILE_IDENT_STRING); + header.file_format_version = GREEN_FILE_FORMAT_VERSION; + header.solid_count = stardis->counts.smed_count; + header.fluid_count = stardis->counts.fmed_count; + header.tbound_count = stardis->counts.tbound_count; + header.hbound_count = stardis->counts.hbound_count; + header.fbound_count = stardis->counts.fbound_count; + header.sfconnect_count = stardis->counts.sfconnect_count; + header.ssconnect_count = stardis->counts.ssconnect_count; + ERR(sdis_green_function_get_paths_count(green, &header.ok_count)); + ERR(sdis_green_function_get_invalid_paths_count(green, &header.failed_count)); sz = darray_descriptions_size_get(&stardis->descriptions); - ASSERT(sz <= UINT_MAX); - szd = (unsigned)sz; - ASSERT(szd == + if(sz > UINT_MAX) goto abort; + ASSERT(sz == (stardis->counts.smed_count + stardis->counts.fmed_count + stardis->counts.tbound_count + stardis->counts.hbound_count + stardis->counts.fbound_count + stardis->counts.sfconnect_count + stardis->counts.ssconnect_count)); - descs = darray_descriptions_cdata_get(&stardis->descriptions); + header.description_count = (unsigned)sz; + header.ambient_radiative_temperature = stardis->trad; + header.ambient_radiative_temperature_reference = stardis->trad_ref; + d2_set(header.time_range, stardis->time_range); - /* 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 and file format version */ - FW(green_string, sizeof(green_string)); - FW(&file_fmt_version, 1); - - /* Write counts */ - file_counts.desc_count = szd; - file_counts.smed_count = stardis->counts.smed_count; - file_counts.fmed_count = stardis->counts.fmed_count; - file_counts.tbound_count = stardis->counts.tbound_count; - file_counts.hbound_count = stardis->counts.hbound_count; - file_counts.fbound_count = stardis->counts.fbound_count; - file_counts.sfconnect_count = stardis->counts.sfconnect_count; - file_counts.ssconnect_count = stardis->counts.ssconnect_count; - file_counts.name_pool_sz = name_pool_sz; - file_counts.ok_count = ok_count; - file_counts.failed_count = failed_count; - FW(&file_counts, 1); + /* Write header */ + FW(&header, 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); + for(i = 0; i < sz; i++) { + struct green_description desc; + ERR(copy_desc_to_green_desc(&desc, &stardis->descriptions, i)); + FW(&desc, 1); + } w_ctx.alloc = stardis->allocator; w_ctx.desc = &stardis->descriptions; - htable_weigth_init(NULL, &w_ctx.pw); - htable_weigth_init(NULL, &w_ctx.flux); + htable_weigth_init(stardis->allocator, &w_ctx.pw); + htable_weigth_init(stardis->allocator, &w_ctx.flux); w_ctx.stream = stream; table_initialized = 1; @@ -740,12 +843,14 @@ dump_green_bin 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; +abort: + res = RES_BAD_ARG; + goto error; } res_T @@ -782,7 +887,7 @@ print_sample enum sdis_medium_type type; struct htable_weigth_iterator it, end; unsigned desc_id; - size_t pcount, fcount; + size_t pw_count, fx_count; struct w_ctx* w_ctx = ctx; const struct description* descs; CHK(path && ctx); @@ -792,7 +897,7 @@ print_sample /* 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 + * - end = end_type end_id; end_type = T | H | R | F | S * - power_term_i = power_type_i power_id_i factor_i * - flux_term_i = flux_id_i factor_i */ @@ -823,42 +928,42 @@ print_sample 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)*/ + /* Radiative output (Trad)*/ size_t sz = darray_descriptions_size_get(w_ctx->desc); - ASSERT(sz <= UINT_MAX); - fprintf(w_ctx->stream, "A\t%u", (unsigned)sz); + if(sz > UINT_MAX) goto abort; + fprintf(w_ctx->stream, "R\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) + struct fluid** pfluid = sdis_data_get(data); + desc_id = (*pfluid)->desc_id; + if((*pfluid)->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); + struct solid** psolid = sdis_data_get(data); ASSERT(type == SDIS_SOLID); - ASSERT(!d__->is_outside); /* FIXME: what if in external solid? */ - desc_id = d__->desc_id; + ASSERT(!(*psolid)->is_outside); /* FIXME: what if in external solid? */ + desc_id = (*psolid)->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)); + ERR(sdis_green_function_get_power_terms_count(path, &pw_count)); 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); + fx_count = htable_weigth_size_get(&w_ctx->flux); - ASSERT(pcount <= ULONG_MAX && fcount <= ULONG_MAX); + if(pw_count > ULONG_MAX || fx_count > ULONG_MAX) goto abort; fprintf(w_ctx->stream, "\t%lu\t%lu", - (unsigned long)pcount, (unsigned long)fcount); + (unsigned long)pw_count, (unsigned long)fx_count); htable_weigth_begin(&w_ctx->pw, &it); htable_weigth_end(&w_ctx->pw, &end); @@ -883,6 +988,9 @@ end: return res; error: goto end; +abort: + res = RES_BAD_ARG; + goto error; } res_T @@ -902,13 +1010,13 @@ dump_green_ascii ASSERT(green && stardis && stream); ERR(sdis_green_function_get_paths_count(green, &sz)); - ASSERT(sz <= UINT_MAX); + if(sz > UINT_MAX) goto abort; ok_count = (unsigned)sz; ERR(sdis_green_function_get_invalid_paths_count(green, &sz)); - ASSERT(sz <= UINT_MAX); + if(sz > UINT_MAX) goto abort; failed_count = (unsigned)sz; sz = darray_descriptions_size_get(&stardis->descriptions); - ASSERT(sz <= UINT_MAX); + if(sz > UINT_MAX) goto abort; szd = (unsigned)sz; descs = darray_descriptions_cdata_get(&stardis->descriptions); @@ -932,7 +1040,7 @@ dump_green_ascii const struct description* desc = descs + i; const struct solid* sl; if(desc->type != DESC_MAT_SOLID) continue; - sl = &desc->d.solid; + 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) { @@ -954,7 +1062,7 @@ dump_green_ascii const struct description* desc = descs + i; const struct fluid* fl; if(desc->type != DESC_MAT_FLUID) continue; - fl = &desc->d.fluid; + 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); @@ -982,23 +1090,23 @@ dump_green_ascii FOR_EACH(i, 0, szd) { const struct description* desc = descs + i; const struct t_boundary* bd; - bd = &desc->d.t_boundary; + 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"); + fprintf(stream, "# ID Name ref_temperature 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); + bd = desc->d.h_boundary; + fprintf(stream, "%u\t%s\t%g\t%g\t%g\t%g\t%g\n", + i, str_cget(&bd->name), bd->ref_temperature, bd->emissivity, + bd->specular_fraction, bd->hc, bd->imposed_temperature); } } if(stardis->counts.fbound_count) { @@ -1008,29 +1116,29 @@ dump_green_ascii 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; + bd = desc->d.f_boundary; fprintf(stream, "%u\t%s\t%g\n", i, str_cget(&bd->name), bd->imposed_flux); } } - /* Radiative Temperatures */ + /* Radiative Temperature */ fprintf(stream, "# Radiative Temperatures\n"); - fprintf(stream, "# ID Amb_Temp Lin_Temp\n"); + fprintf(stream, "# ID Trad Trad_Ref\n"); fprintf(stream, "%u\t%g\t%g\n", - szd, stardis->ambient_temp, stardis->ref_temp); + szd, stardis->trad, stardis->trad_ref); 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, "# end = end_type end_id; end_type = T | H | R | 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); + htable_weigth_init(stardis->allocator, &w_ctx.pw); + htable_weigth_init(stardis->allocator, &w_ctx.flux); w_ctx.stream = stream; table_initialized = 1; @@ -1044,6 +1152,9 @@ end: return res; error: goto end; +abort: + res = RES_BAD_ARG; + goto error; } res_T @@ -1347,6 +1458,9 @@ print_computation_time ASSERT(stardis && start && compute_start && compute_end); + /* Only master prints or reads estimators */ + ASSERT(!stardis->mpi_initialized || stardis->mpi_rank == 0); + time_sub(&tmp, compute_start, start); time_dump(&tmp, flag, NULL, buf, sizeof(buf)); logger_print(stardis->logger, LOG_OUTPUT, @@ -1387,10 +1501,13 @@ print_single_MC_result ASSERT(estimator && stardis && stream); + /* Only master prints or reads estimators */ + ASSERT(!stardis->mpi_initialized || stardis->mpi_rank == 0); + /* Fetch the estimation data */ ERR(sdis_estimator_get_temperature(estimator, &result)); ERR(sdis_estimator_get_failure_count(estimator, &nfailures_)); - ASSERT(nfailures_ <= ULONG_MAX && stardis->samples <= ULONG_MAX); + if(nfailures_ > ULONG_MAX || stardis->samples > ULONG_MAX) goto abort; nfailures = (unsigned long)nfailures_; nsamples = (unsigned long)stardis->samples; if(nfailures == nsamples) { @@ -1570,14 +1687,18 @@ end: return res; error: goto end; +abort: + res = RES_BAD_ARG; + goto error; } -void +res_T dump_map (const struct stardis* stardis, const struct darray_estimators* estimators, FILE* stream) { + res_T res = RES_OK; unsigned i, vcount, tcount, last_v = 0; const size_t* idx; size_t sz; @@ -1586,10 +1707,13 @@ dump_map ASSERT(stardis && estimators && stream); + /* Only master prints or reads estimators */ + ASSERT(!stardis->mpi_initialized || stardis->mpi_rank == 0); + 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); + if(sz > UINT_MAX) goto abort; szp = (unsigned)sz; SG3D(geometry_get_unique_vertices_count(stardis->geometry.sg3d, &vcount)); SG3D(geometry_get_unique_triangles_count(stardis->geometry.sg3d, &tcount)); @@ -1598,7 +1722,7 @@ dump_map for(i = 0; i < szp; ++i) { unsigned t; unsigned indices[3]; - ASSERT(idx[i] <= UINT_MAX); + if(idx[i] > UINT_MAX) goto abort; t = (unsigned)idx[i]; SG3D(geometry_get_unique_triangle_vertices(stardis->geometry.sg3d, t, indices)); @@ -1621,7 +1745,7 @@ dump_map for(i = 0; i < szp; ++i) { unsigned t; unsigned indices[3]; - ASSERT(idx[i] <= UINT_MAX); + if(idx[i] > UINT_MAX) goto abort; t = (unsigned)idx[i]; SG3D(geometry_get_unique_triangle_vertices(stardis->geometry.sg3d, t, indices)); @@ -1647,7 +1771,7 @@ dump_map for(i = 0; i < szp; ++i) { size_t nfails; SDIS(estimator_get_failure_count(est[i], &nfails)); - ASSERT(nfails <= UINT_MAX); + if(nfails > UINT_MAX) goto abort; fprintf(stream, "%u\n", (unsigned)nfails); } fprintf(stream, "SCALARS computation_time_estimate float 1\n"); @@ -1664,6 +1788,13 @@ dump_map SDIS(estimator_get_realisation_time(est[i], &time)); fprintf(stream, "%f\n", time.SE); } +end: + return res; +error: + goto end; +abort: + res = RES_BAD_ARG; + goto error; } res_T @@ -1676,6 +1807,10 @@ dump_compute_region_at_the_end_of_vtk unsigned tsz, i; size_t j, psz; ASSERT(stardis && stream); + + /* Only master prints or reads estimators */ + ASSERT(!stardis->mpi_initialized || stardis->mpi_rank == 0); + psz = darray_size_t_size_get(&stardis->compute_surface.primitives); ASSERT(psz == darray_sides_size_get(&stardis->compute_surface.sides)); @@ -1761,6 +1896,9 @@ dump_model_as_c_chunks ASSERT(stardis && stream); + /* Only master prints or reads estimators */ + ASSERT(!stardis->mpi_initialized || stardis->mpi_rank == 0); + 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)); diff --git a/src/stardis-output.h b/src/stardis-output.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2018-2021 |Meso|Star> (contact@meso-star.com) +/* Copyright (C) 2018-2022 |Meso|Star> (contact@meso-star.com) * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -97,7 +97,7 @@ print_single_MC_result struct stardis* stardis, FILE* stream); -extern void +extern res_T dump_map (const struct stardis* stardis, const struct darray_estimators* estimators, diff --git a/src/stardis-parsing.c b/src/stardis-parsing.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2018-2021 |Meso|Star> (contact@meso-star.com) +/* Copyright (C) 2018-2022 |Meso|Star> (contact@meso-star.com) * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -17,12 +17,11 @@ #include "stardis-parsing.h" #include "stardis-app.h" #include "stardis-default.h" -#include "stardis-version.h" +#include "stardis-green-types.h" #include <rsys/cstr.h> #include <rsys/double2.h> #include <rsys/double3.h> -#include <sdis_version.h> #include <rsys/logger.h> #include <getopt.h> @@ -34,79 +33,14 @@ #include <strings.h> /* strcasecmp */ #else #define strcasecmp(s1, s2) _stricmp((s1), (s2)) +#define strdup(tok) _strdup(tok) +#define strtok_r(str, delim, save) strtok_s((str), (delim), (save)) #endif /******************************************************************************* * Local Functions ******************************************************************************/ -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, @@ -313,834 +247,6 @@ error: * 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, 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"); - - fprintf(stream, "\n -x <FILE>\n"); - fprintf(stream, " Use a random generator's state read from a file.\n"); - - fprintf(stream, "\n -X <FILE>\n"); - fprintf(stream, " Save the final random generator's state in a file.\n"); - - fprintf(stream, -"\nCopyright (C) 2018-2021 |Meso|Star> <contact@meso-star.com>.\n" -"stardis is free software released under the GNU GPL license, version 3 or later.\n" -"You are free to change or redistribute it under certain conditions\n" -"<http://gnu.org/licenses/gpl.html>.\n"); - -} - -#define FREE_AARRAY(ARRAY) \ -if(ARRAY) {\ - int i__ = 0; \ - for(i__=0; *((ARRAY)+i__);i__++){\ - free((ARRAY)[i__]);\ - }\ - free(ARRAY);\ - (ARRAY) = NULL;\ -} - -/* Workaround for a gcc warning when GET_OPTIONAL_TIME_RANGE used with Rank=0 */ -static 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, FullSrc) \ - 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), (FullSrc)); \ - 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, optarg); \ - *ptr = '\0'; \ - } \ - (Str) = optarg; - -/* Get a position followed by an optional time range */ -#define GET_POS_AND_OPTIONAL_TIME_RANGE(Src, Dst, FullSrc) \ - GET_OPTIONAL_TIME_RANGE((Src), 3, (Dst), args->logger, "-%c", opt, (FullSrc)); - -res_T -parse_args - (const int argc, - char** argv, - struct args* args, - struct mem_allocator* allocator) -{ - 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:x:X:"; - char buf[128]; - struct str keep; - char** line = NULL; - res_T res = RES_OK; - - ASSERT(argv && args); - - str_init(allocator, &keep); - 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 == strcasecmp(optarg, "all")) { - args->dump_paths = DUMP_ALL; - } - else if(0 == strcasecmp(optarg, "error")) { - args->dump_paths = DUMP_ERROR; - } - else if(0 == strcasecmp(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(optarg, args->pos_and_time, optarg); - 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; - - ERR(str_set(&keep, optarg)); - line = split_line(optarg, ':'); - if(!line) { - res = RES_MEM_ERR; - str_release(&keep); - goto error; - } - - /* We expect 1 or 2 parts in line */ - if(!line[0] || (line[1] && line[2])) { - logger_print((args->logger), LOG_ERROR, - "Invalid argument for option ""-%c"": %s\n", - opt, str_cget(&keep)); - str_release(&keep); - res = RES_BAD_ARG; - goto error; - } - - /* First part is pos and optional time, optional second part is a - * medium name (OK if NULL) */ - GET_POS_AND_OPTIONAL_TIME_RANGE(line[0], args->pos_and_time, - str_cget(&keep)); - if(line[1]) - args->medium_name = optarg + strlen(line[0]) + 1; - - 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; - - case 'x': - if(!(args->mode & RANDOM_RW_MODES)) { - res = RES_BAD_ARG; - print_multiple_modes(buf, sizeof(buf), RANDOM_RW_MODES, 0); - logger_print(args->logger, LOG_ERROR, - "Option -%c can only be used in conjunction with one of the following options: %s.\n", - (char)opt, buf); - goto error; - } - args->rndgen_state_in_filename = optarg; - break; - - case 'X': - if(!(args->mode & RANDOM_RW_MODES)) { - res = RES_BAD_ARG; - print_multiple_modes(buf, sizeof(buf), RANDOM_RW_MODES, 0); - logger_print(args->logger, LOG_ERROR, - "Option -%c can only be used in conjunction with one of the following options: %s.\n", - (char)opt, buf); - goto error; - } - args->rndgen_state_out_filename = optarg; - 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; - } - } - - if(args->rndgen_state_in_filename && !(args->mode & COMPUTE_MODES)) { - res = RES_BAD_ARG; - print_multiple_modes(buf, sizeof(buf), COMPUTE_MODES, 0); - logger_print(args->logger, LOG_ERROR, - "Option -x can only be used in conjunction with an option" - " that launch a MC computation (%s).\n", - buf); - goto error; - } - - if(args->rndgen_state_out_filename && !(args->mode & COMPUTE_MODES)) { - res = RES_BAD_ARG; - print_multiple_modes(buf, sizeof(buf), COMPUTE_MODES, 0); - logger_print(args->logger, LOG_ERROR, - "Option -X can only be used in conjunction with an option" - " that launch a MC computation (%s).\n", - buf); - goto error; - } - -end: - FREE_AARRAY(line); - str_release(&keep); - 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; - struct str keep; - int i = 0; - res_T res = RES_OK; - - ASSERT(cam_param && stardis); - cam = &stardis->camera; - line = split_line(cam_param, ':'); - if(!line) { - res = RES_MEM_ERR; - goto error; - } - - str_init(stardis->allocator, &keep); - for(i = 0; *(line + i); i++) { - size_t len = 0; - ERR(str_set(&keep, line[i])); - opt = split_line(line[i], '='); - if(!opt[0] || !opt[1] || opt[2]) { /* We expect 2 parts */ - if(res == RES_OK) res = RES_BAD_ARG; - logger_print((logger), LOG_ERROR, - "Invalid option syntax: %s\n", str_cget(&keep)); - goto error; - } - if(strcasecmp(opt[0], "T") == 0) { - GET_OPTIONAL_TIME_RANGE(opt[1], 0, cam->time_range, logger, "%s", opt[0], - str_cget(&keep)); - } - else if(strcasecmp(opt[0], "FILE") == 0) { - ERR(str_set(&cam->file_name, opt[1])); - } - else if(strcasecmp(opt[0], "FMT") == 0) { - if(strcasecmp(opt[1], "VTK") == 0) - cam->fmt = STARDIS_RENDERING_OUTPUT_FILE_FMT_VTK; - else if(strcasecmp(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(strcasecmp(opt[0], "FOV") == 0) { - ERR(cstr_to_double(opt[1], &cam->fov)); - } - else if(strcasecmp(opt[0], "UP") == 0) { - ERR(cstr_to_list_double(opt[1], ',', cam->up, &len, 3)); - } - else if(strcasecmp(opt[0], "TGT") == 0) { - ERR(cstr_to_list_double(opt[1], ',', cam->tgt, &len, 3)); - cam->auto_look_at = 0; - } - else if(strcasecmp(opt[0], "POS") == 0) { - ERR(cstr_to_list_double(opt[1], ',', cam->pos, &len, 3)); - cam->auto_look_at = 0; - } - else if(strcasecmp(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(strcasecmp(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; - } - FREE_AARRAY(opt); - } - -end: - FREE_AARRAY(line); - FREE_AARRAY(opt); -#undef FREE_AARRAY - - str_release(&keep); - 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 res_T description_set_name (struct stardis* stardis, @@ -1152,7 +258,9 @@ description_set_name const char* keywords[] = { "AUTO", "BACK", "BOTH", "FLUID", "FRONT", "F_BOUNDARY_FOR_SOLID", "H_BOUNDARY_FOR_FLUID", "H_BOUNDARY_FOR_SOLID", "SCALE", "SOLID", - "SOLID_FLUID_CONNECTION", "T_BOUNDARY_FOR_SOLID", "UNKNOWN" }; + "SOLID_FLUID_CONNECTION", "SOLID_SOLID_CONNECTION", "TRAD", + "T_BOUNDARY_FOR_SOLID", "UNKNOWN" }; + const char* reason = NULL; int i; ASSERT(name && tk); @@ -1162,21 +270,31 @@ description_set_name if(RES_OK == cstr_to_double(tk, &foo)) { /* A number is not a sensible choice for a name! */ res = RES_BAD_ARG; + reason = "number"; goto error; } FOR_EACH(i, 0, sizeof(keywords) / sizeof(*keywords)) { if(0 == strcasecmp(tk, keywords[i])) { /* A keyword is not a sensible choice for a name! */ res = RES_BAD_ARG; + reason = "reserved keyword"; goto error; } } + if(str_len(name) > DESC_NAME_MAX_LEN) { + /* Due to Green export limitations, names are limited in length */ + res = RES_BAD_ARG; + reason = "too long"; + goto error; + } /* Name is OK */ end: return res; error: - logger_print(stardis->logger, LOG_ERROR, "Invalid name: %s\n", tk); + ASSERT(reason != NULL); + logger_print(stardis->logger, LOG_ERROR, "Invalid name (%s): %s\n", + reason, tk); goto end; } @@ -1184,34 +302,34 @@ static struct description* find_description_by_name (struct stardis* stardis, const struct str* name, - size_t* out_id) + const struct description* self) { size_t i; - ASSERT(stardis && name); + ASSERT(stardis && name && self); FOR_EACH(i, 0, darray_descriptions_size_get(&stardis->descriptions)) { struct description* desc = darray_descriptions_data_get(&stardis->descriptions) + i; + if(self == desc) continue; 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 */ +/* H_BOUNDARY_FOR_SOLID Name ref_temperature emissivity specular_fraction hc T_env STL_filenames + * H_BOUNDARY_FOR_FLUID Name ref_temperature 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; + struct h_boundary* h_boundary; res_T res = RES_OK; ASSERT(stardis && tok_ctx); @@ -1221,36 +339,45 @@ process_h 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); - + ERR(init_h(stardis->allocator, &desc->d.h_boundary)); + h_boundary = desc->d.h_boundary; desc->type = type; CHK_TOK(strtok_r(NULL, " \t", tok_ctx), "h boundary name"); - ERR(description_set_name(stardis, &desc->d.h_boundary.name, tk)); - if(find_description_by_name(stardis, &desc->d.h_boundary.name, NULL) - != desc) - { + ERR(description_set_name(stardis, &h_boundary->name, tk)); + if(find_description_by_name(stardis, &h_boundary->name, 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), "ref_temperature"); + res = cstr_to_double(tk, &h_boundary->ref_temperature); + if(res != RES_OK + || h_boundary->ref_temperature < 0) + { + logger_print(stardis->logger, LOG_ERROR, "Invalid reference temperature: %s\n", tk); + if(res == RES_OK) res = RES_BAD_ARG; + goto end; + } + stardis->t_range[0] = MMIN(stardis->t_range[0], h_boundary->ref_temperature); + stardis->t_range[1] = MMAX(stardis->t_range[1], h_boundary->ref_temperature); CHK_TOK(strtok_r(NULL, " \t", tok_ctx), "emissivity"); - res = cstr_to_double(tk, &desc->d.h_boundary.emissivity); + res = cstr_to_double(tk, &h_boundary->emissivity); if(res != RES_OK - || desc->d.h_boundary.emissivity < 0 - || desc->d.h_boundary.emissivity > 1) + || h_boundary->emissivity < 0 + || 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); + res = cstr_to_double(tk, &h_boundary->specular_fraction); if(res != RES_OK - || desc->d.h_boundary.specular_fraction < 0 - || desc->d.h_boundary.specular_fraction > 1) + || h_boundary->specular_fraction < 0 + || h_boundary->specular_fraction > 1) { logger_print(stardis->logger, LOG_ERROR, "Invalid specular fraction: %s\n", tk); @@ -1258,42 +385,45 @@ process_h goto end; } CHK_TOK(strtok_r(NULL, " \t", tok_ctx), "hc"); - res = cstr_to_double(tk, &desc->d.h_boundary.hc); + res = cstr_to_double(tk, &h_boundary->hc); if(res != RES_OK - || desc->d.h_boundary.hc < 0) + || 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); + res = cstr_to_double(tk, &h_boundary->imposed_temperature); if(res != RES_OK - || desc->d.h_boundary.imposed_temperature < 0) + || 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; } + stardis->t_range[0] = MMIN(stardis->t_range[0], h_boundary->imposed_temperature); + stardis->t_range[1] = MMAX(stardis->t_range[1], h_boundary->imposed_temperature); if(type == DESC_BOUND_H_FOR_FLUID) - desc->d.h_boundary.mat_id = get_dummy_solid_id(stardis, dummies); + ERR(get_dummy_solid_id(stardis, &h_boundary->mat_id)); 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; + struct fluid* fluid = NULL; + ERR(init_fluid(stardis->allocator, &fluid)); + fluid->fluid_id = allocate_stardis_medium_id(stardis); + h_boundary->mat_id = fluid->fluid_id; + h_boundary->possible_external_fluid = fluid; 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)); + fluid->desc_id = (unsigned)sz; + fluid->imposed_temperature + = h_boundary->imposed_temperature; + fluid->is_outside = 1; + fluid->is_green = stardis->mode & (MODE_BIN_GREEN | MODE_GREEN); + ERR(create_solver_fluid(stardis, fluid)); logger_print(stardis->logger, LOG_OUTPUT, "External fluid created: T=%g (it is medium %u)\n", - fluid_props.imposed_temperature, - fluid_props.fluid_id); + fluid->imposed_temperature, + fluid->fluid_id); } ASSERT(sz <= UINT_MAX); @@ -1309,12 +439,12 @@ error: static res_T process_t (struct stardis* stardis, - struct dummies* dummies, char** tok_ctx) { char* tk = NULL; struct description* desc; size_t sz; + struct t_boundary* t_boundary; res_T res = RES_OK; ASSERT(stardis && tok_ctx); @@ -1324,16 +454,15 @@ process_t 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); - + ERR(init_t(stardis->allocator, &desc->d.t_boundary)); + t_boundary = desc->d.t_boundary; desc->type = DESC_BOUND_T_FOR_SOLID; - desc->d.t_boundary.mat_id = get_dummy_fluid_id(stardis, dummies); + + ERR(get_dummy_fluid_id(stardis, &t_boundary->mat_id)); CHK_TOK(strtok_r(NULL, " \t", tok_ctx), "temperature boundary name"); - ERR(description_set_name(stardis, &desc->d.t_boundary.name, tk)); - if(find_description_by_name(stardis, &desc->d.t_boundary.name, NULL) - != desc) - { + ERR(description_set_name(stardis, &t_boundary->name, tk)); + if(find_description_by_name(stardis, &t_boundary->name, desc)) { logger_print(stardis->logger, LOG_ERROR, "Name already used: %s\n", tk); if(res == RES_OK) res = RES_BAD_ARG; @@ -1341,14 +470,16 @@ process_t } CHK_TOK(strtok_r(NULL, " \t", tok_ctx), "temperature"); - res = cstr_to_double(tk, &desc->d.t_boundary.imposed_temperature); + res = cstr_to_double(tk, &t_boundary->imposed_temperature); if(res != RES_OK - || desc->d.t_boundary.imposed_temperature < 0) + || 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; } + stardis->t_range[0] = MMIN(stardis->t_range[0], t_boundary->imposed_temperature); + stardis->t_range[1] = MMAX(stardis->t_range[1], t_boundary->imposed_temperature); ASSERT(sz <= UINT_MAX); ERR(read_sides_and_files(stardis, 1, (unsigned)sz, tok_ctx)); @@ -1363,12 +494,12 @@ error: static res_T process_flx (struct stardis* stardis, - struct dummies* dummies, char** tok_ctx) { char* tk = NULL; struct description* desc; size_t sz; + struct f_boundary* f_boundary; res_T res = RES_OK; ASSERT(stardis && tok_ctx); @@ -1378,16 +509,15 @@ process_flx 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); - + ERR(init_f(stardis->allocator, &desc->d.f_boundary)); + f_boundary = desc->d.f_boundary; desc->type = DESC_BOUND_F_FOR_SOLID; - desc->d.f_boundary.mat_id = get_dummy_fluid_id(stardis, dummies); + + ERR(get_dummy_fluid_id(stardis, &f_boundary->mat_id)); CHK_TOK(strtok_r(NULL, " \t", tok_ctx), "flux boundary name"); - ERR(description_set_name(stardis, &desc->d.f_boundary.name, tk)); - if(find_description_by_name(stardis, &desc->d.f_boundary.name, NULL) - != desc) - { + ERR(description_set_name(stardis, &f_boundary->name, tk)); + if(find_description_by_name(stardis, &f_boundary->name, desc)) { logger_print(stardis->logger, LOG_ERROR, "Name already used: %s\n", tk); if(res == RES_OK) res = RES_BAD_ARG; @@ -1395,14 +525,22 @@ process_flx } CHK_TOK(strtok_r(NULL, " \t", tok_ctx), "flux"); - res = cstr_to_double(tk, &desc->d.f_boundary.imposed_flux); + res = cstr_to_double(tk, &f_boundary->imposed_flux); if(res != RES_OK - || desc->d.f_boundary.imposed_flux == SDIS_FLUX_NONE) { + || 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; } + if(f_boundary->imposed_flux != 0 && stardis->picard_order > 1) { + logger_print(stardis->logger, LOG_ERROR, + "Cannot have a flux defined at a boundary (here %f) if Picard order " + "is not 1 (here order is %u)\n", + f_boundary->imposed_flux, stardis->picard_order); + res = RES_BAD_ARG; + goto end; + } ASSERT(sz <= UINT_MAX); ERR(read_sides_and_files(stardis, 1, (unsigned)sz, tok_ctx)); @@ -1413,7 +551,7 @@ error: goto end; } -/* SOLID_FLUID_CONNECTION Name emissivity specular_fraction hc STL_filenames */ +/* SOLID_FLUID_CONNECTION Name ref_temperature emissivity specular_fraction hc STL_filenames */ static res_T process_sfc (struct stardis* stardis, @@ -1422,6 +560,7 @@ process_sfc char* tk = NULL; struct description* desc; size_t sz; + struct solid_fluid_connect* sf_connect; res_T res = RES_OK; ASSERT(stardis && tok_ctx); @@ -1431,40 +570,50 @@ process_sfc 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); + ERR(init_sf(stardis->allocator, &desc->d.sf_connect)); + sf_connect = desc->d.sf_connect; + desc->type = DESC_SOLID_FLUID_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); + sf_connect->connection_id = allocate_stardis_medium_id(stardis); CHK_TOK(strtok_r(NULL, " \t", tok_ctx), "solid fluid connection name"); - ERR(description_set_name(stardis, &desc->d.sf_connect.name, tk)); - if(find_description_by_name(stardis, &desc->d.sf_connect.name, NULL) - != desc) - { + ERR(description_set_name(stardis, &sf_connect->name, tk)); + if(find_description_by_name(stardis, &sf_connect->name, 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), "ref_temperature"); + res = cstr_to_double(tk, &sf_connect->ref_temperature); + if(res != RES_OK + || sf_connect->ref_temperature < 0) + { + logger_print(stardis->logger, LOG_ERROR, "Invalid reference temperature: %s\n", tk); + if(res == RES_OK) res = RES_BAD_ARG; + goto end; + } + stardis->t_range[0] = MMIN(stardis->t_range[0], sf_connect->ref_temperature); + stardis->t_range[1] = MMAX(stardis->t_range[1], sf_connect->ref_temperature); CHK_TOK(strtok_r(NULL, " \t", tok_ctx), "emissivity"); - res = cstr_to_double(tk, &desc->d.sf_connect.emissivity); + res = cstr_to_double(tk, &sf_connect->emissivity); if(res != RES_OK - || desc->d.sf_connect.emissivity < 0 - || desc->d.h_boundary.emissivity > 1) + || sf_connect->emissivity < 0 + || sf_connect->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); + res = cstr_to_double(tk, &sf_connect->specular_fraction); if(res != RES_OK - || desc->d.sf_connect.specular_fraction < 0 - || desc->d.sf_connect.specular_fraction > 1) + || sf_connect->specular_fraction < 0 + || sf_connect->specular_fraction > 1) { logger_print(stardis->logger, LOG_ERROR, "Invalid specular fraction: %s\n", tk); @@ -1472,9 +621,9 @@ process_sfc goto end; } CHK_TOK(strtok_r(NULL, " \t", tok_ctx), "hc"); - res = cstr_to_double(tk, &desc->d.sf_connect.hc); + res = cstr_to_double(tk, &sf_connect->hc); if(res != RES_OK - || desc->d.sf_connect.hc < 0) + || sf_connect->hc < 0) { logger_print(stardis->logger, LOG_ERROR, "Invalid hc: %s\n", tk); if(res == RES_OK) res = RES_BAD_ARG; @@ -1499,6 +648,7 @@ process_ssc char* tk = NULL; struct description* desc; size_t sz; + struct solid_solid_connect* ss_connect; res_T res = RES_OK; ASSERT(stardis && tok_ctx); @@ -1508,19 +658,18 @@ process_ssc sz = darray_descriptions_size_get(&stardis->descriptions); ERR(darray_descriptions_resize(&stardis->descriptions, sz + 1)); desc = darray_descriptions_data_get(&stardis->descriptions) + sz; - init_ss(stardis->allocator, &desc->d.ss_connect); + ERR(init_ss(stardis->allocator, &desc->d.ss_connect)); + ss_connect = desc->d.ss_connect; + desc->type = DESC_SOLID_SOLID_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_SOLID_CONNECT; - desc->d.ss_connect.connection_id = allocate_stardis_medium_id(stardis); + ss_connect->connection_id = allocate_stardis_medium_id(stardis); CHK_TOK(strtok_r(NULL, " \t", tok_ctx), "solid solid connection name"); - ERR(description_set_name(stardis, &desc->d.ss_connect.name, tk)); - if(find_description_by_name(stardis, &desc->d.ss_connect.name, NULL) - != desc) - { + ERR(description_set_name(stardis, &ss_connect->name, tk)); + if(find_description_by_name(stardis, &ss_connect->name, desc)) { logger_print(stardis->logger, LOG_ERROR, "Name already used: %s\n", tk); if(res == RES_OK) res = RES_BAD_ARG; @@ -1528,19 +677,19 @@ process_ssc } CHK_TOK(strtok_r(NULL, " \t", tok_ctx), "contact resistance"); - res = cstr_to_double(tk, &desc->d.ss_connect.tcr); + res = cstr_to_double(tk, &ss_connect->tcr); if(res != RES_OK - || desc->d.ss_connect.tcr < 0) + || ss_connect->tcr < 0) { logger_print(stardis->logger, LOG_ERROR, "Invalid contact resistance: %s\n", tk); if(res == RES_OK) res = RES_BAD_ARG; goto end; } - else if(desc->d.ss_connect.tcr == 0) { + else if(ss_connect->tcr == 0) { logger_print(stardis->logger, LOG_WARNING, "Solid-solid connection %s: defining a contact resistance to 0 has " - "no effect\n", str_cget(&desc->d.ss_connect.name)); + "no effect\n", str_cget(&ss_connect->name)); } ASSERT(sz <= UINT_MAX); @@ -1638,6 +787,7 @@ process_solid char* tk = NULL; struct description* desc; size_t sz; + struct solid* solid; res_T res = RES_OK; ASSERT(stardis && tok_ctx); @@ -1647,20 +797,19 @@ process_solid 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); - + ERR(init_solid(stardis->allocator, &desc->d.solid)); + solid = 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; + + solid->solid_id = allocate_stardis_medium_id(stardis); + solid->is_green = stardis->mode & (MODE_BIN_GREEN | MODE_GREEN); + solid->is_outside = 0; ASSERT(sz <= UINT_MAX); - desc->d.solid.desc_id = (unsigned)sz; + solid->desc_id = (unsigned)sz; CHK_TOK(strtok_r(NULL, " \t", tok_ctx), "solid name"); - ERR(description_set_name(stardis, &desc->d.solid.name, tk)); - if(find_description_by_name(stardis, &desc->d.solid.name, NULL) - != desc) - { + ERR(description_set_name(stardis, &solid->name, tk)); + if(find_description_by_name(stardis, &solid->name, desc)) { logger_print(stardis->logger, LOG_ERROR, "Name already used: %s\n", tk); if(res == RES_OK) res = RES_BAD_ARG; @@ -1668,60 +817,74 @@ process_solid } CHK_TOK(strtok_r(NULL, " \t", tok_ctx), "lambda"); - res = cstr_to_double(tk, &desc->d.solid.lambda); + res = cstr_to_double(tk, &solid->lambda); if(res != RES_OK - || desc->d.solid.lambda <= 0) + || 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); + res = cstr_to_double(tk, &solid->rho); if(res != RES_OK - || desc->d.solid.rho <= 0) + || 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); + res = cstr_to_double(tk, &solid->cp); if(res != RES_OK - || desc->d.solid.cp <= 0) + || 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)); + ERR(read_delta(stardis, &solid->delta, tok_ctx)); CHK_TOK(strtok_r(NULL, " \t", tok_ctx), "Tinit"); - res = cstr_to_double(tk, &desc->d.solid.tinit); + res = cstr_to_double(tk, &solid->tinit); if(res != RES_OK - || desc->d.solid.tinit < 0) + || 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, + stardis->t_range[0] = MMIN(stardis->t_range[0], solid->tinit); + stardis->t_range[1] = MMAX(stardis->t_range[1], solid->tinit); + ERR(read_imposed_temperature(stardis, &solid->imposed_temperature, tok_ctx)); - if(desc->d.solid.imposed_temperature >= 0 - && desc->d.solid.imposed_temperature != desc->d.solid.tinit) + if(solid->imposed_temperature >= 0 + && solid->imposed_temperature != 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; + solid->tinit, solid->imposed_temperature); + res = RES_BAD_ARG; goto end; } + if(solid->imposed_temperature >= 0) + stardis->t_range[0] = MMIN(stardis->t_range[0], solid->imposed_temperature); + stardis->t_range[1] = MMAX(stardis->t_range[1], solid->imposed_temperature); CHK_TOK(strtok_r(NULL, " \t", tok_ctx), "volumic power"); - res = cstr_to_double(tk, &desc->d.solid.vpower); + res = cstr_to_double(tk, &solid->vpower); if(res != RES_OK) { /* VPower can be < 0 */ logger_print(stardis->logger, LOG_ERROR, "Invalid volumic power: %s\n", tk); goto end; } + if(solid->vpower != 0 && stardis->picard_order > 1) { + logger_print(stardis->logger, LOG_ERROR, + "Cannot have volumic power (here %f) if Picard order is not 1 " + "(here order is %u)\n", + solid->vpower, stardis->picard_order); + res = RES_BAD_ARG; + goto end; + } /* Actual solid creation is defered until geometry is read to allow * enclosure shape VS delta analysis (and auto delta computation) */ @@ -1744,6 +907,7 @@ process_fluid char* tk = NULL; struct description* desc; size_t sz; + struct fluid* fluid; res_T res = RES_OK; ASSERT(stardis && tok_ctx); @@ -1753,20 +917,19 @@ process_fluid 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); - + ERR(init_fluid(stardis->allocator, &desc->d.fluid)); + fluid = 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); + + fluid->fluid_id = allocate_stardis_medium_id(stardis); + fluid->is_outside = 0; + fluid->is_green = stardis->mode & (MODE_BIN_GREEN | MODE_GREEN); ASSERT(sz <= UINT_MAX); - desc->d.fluid.desc_id = (unsigned)sz; + fluid->desc_id = (unsigned)sz; CHK_TOK(strtok_r(NULL, " \t", tok_ctx), "fluid name"); - ERR(description_set_name(stardis, &desc->d.fluid.name, tk)); - if(find_description_by_name(stardis, &desc->d.fluid.name, NULL) - != desc) - { + ERR(description_set_name(stardis, &fluid->name, tk)); + if(find_description_by_name(stardis, &fluid->name, desc)) { logger_print(stardis->logger, LOG_ERROR, "Name already used: %s\n", tk); if(res == RES_OK) res = RES_BAD_ARG; @@ -1774,46 +937,51 @@ process_fluid } CHK_TOK(strtok_r(NULL, " \t", tok_ctx), "rho"); - res = cstr_to_double(tk, &desc->d.fluid.rho); + res = cstr_to_double(tk, &fluid->rho); if(res != RES_OK - || desc->d.fluid.rho <= 0) + || 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); + res = cstr_to_double(tk, &fluid->cp); if(res != RES_OK - || desc->d.fluid.cp <= 0) + || 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); + res = cstr_to_double(tk, &fluid->tinit); if(res != RES_OK - || desc->d.fluid.tinit < 0) + || 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, + stardis->t_range[0] = MMIN(stardis->t_range[0], fluid->tinit); + stardis->t_range[1] = MMAX(stardis->t_range[1], fluid->tinit); + ERR(read_imposed_temperature(stardis, &fluid->imposed_temperature, tok_ctx)); - if(desc->d.fluid.imposed_temperature >= 0 - && desc->d.fluid.imposed_temperature != desc->d.fluid.tinit) + if(fluid->imposed_temperature >= 0 + && fluid->imposed_temperature != 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; + fluid->tinit, fluid->imposed_temperature); + res = RES_BAD_ARG; goto end; } + if(fluid->imposed_temperature >= 0) + stardis->t_range[0] = MMIN(stardis->t_range[0], fluid->imposed_temperature); + stardis->t_range[1] = MMAX(stardis->t_range[1], fluid->imposed_temperature); - ERR(create_solver_fluid(stardis, &desc->d.fluid)); + ERR(create_solver_fluid(stardis, fluid)); ASSERT(sz <= UINT_MAX); ERR(read_sides_and_files(stardis, 0, (unsigned)sz, tok_ctx)); @@ -1858,15 +1026,61 @@ error: goto end; } +/* TRAD Trad Trad_ref */ +static res_T +process_radiative + (struct stardis* stardis, + char** tok_ctx) +{ + char* tk = NULL; + res_T res = RES_OK; + + ASSERT(stardis && tok_ctx); + + if(stardis->trad_def) { + logger_print(stardis->logger, LOG_ERROR, + "TRAD cannot be specified twice\n"); + res = RES_BAD_ARG; + goto end; + } + CHK_TOK(strtok_r(NULL, " \t", tok_ctx), "Trad"); + res = cstr_to_double(tk, &stardis->trad); + if(res != RES_OK + || stardis->trad < 0) + { + logger_print(stardis->logger, LOG_ERROR, + "Invalid Trad: %s\n", tk); + if(res == RES_OK) res = RES_BAD_ARG; + goto end; + } + CHK_TOK(strtok_r(NULL, " \t", tok_ctx), "Trad reference"); + res = cstr_to_double(tk, &stardis->trad_ref); + if(res != RES_OK + || stardis->trad_ref < 0) + { + logger_print(stardis->logger, LOG_ERROR, + "Invalid Trad reference: %s\n", tk); + if(res == RES_OK) res = RES_BAD_ARG; + goto end; + } + stardis->trad_def = 1; + +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 + * H_BOUNDARY_FOR_SOLID Name ref_temperature emissivity specular_fraction hc T_env STL_filenames + * H_BOUNDARY_FOR_FLUID Name ref_temperature emissivity specular_fraction hc T_env STL_filenames * T_BOUNDARY_FOR_SOLID Name T STL_filenames * F_BOUNDARY_FOR_SOLID Name F STL_filenames - * SOLID_FLUID_CONNECTION Name emissivity specular_fraction hc STL_filenames + * SOLID_FLUID_CONNECTION Name ref_temperature emissivity specular_fraction hc STL_filenames * SCALE scale_factor + * TRAD Trad Trad_ref * * STL_filenames = { { FRONT | BACK | BOTH } STL_filename }+ */ @@ -1874,8 +1088,7 @@ res_T process_model_line (const char* file_name, char* line, - struct stardis* stardis, - struct dummies* dummies) + struct stardis* stardis) { res_T res = RES_OK; struct str keep; @@ -1888,13 +1101,13 @@ process_model_line CHK_TOK(strtok_r(line, " \t", &tok_ctx), "model line type"); if(0 == strcasecmp(tk, "H_BOUNDARY_FOR_SOLID")) - ERR(process_h(stardis, dummies, DESC_BOUND_H_FOR_SOLID, &tok_ctx)); + ERR(process_h(stardis, DESC_BOUND_H_FOR_SOLID, &tok_ctx)); else if(0 == strcasecmp(tk, "H_BOUNDARY_FOR_FLUID")) - ERR(process_h(stardis, dummies, DESC_BOUND_H_FOR_FLUID, &tok_ctx)); + ERR(process_h(stardis, DESC_BOUND_H_FOR_FLUID, &tok_ctx)); else if(0 == strcasecmp(tk, "T_BOUNDARY_FOR_SOLID")) - ERR(process_t(stardis, dummies, &tok_ctx)); + ERR(process_t(stardis, &tok_ctx)); else if(0 == strcasecmp(tk, "F_BOUNDARY_FOR_SOLID")) - ERR(process_flx(stardis, dummies, &tok_ctx)); + ERR(process_flx(stardis, &tok_ctx)); else if(0 == strcasecmp(tk, "SOLID_FLUID_CONNECTION")) ERR(process_sfc(stardis, &tok_ctx)); else if(0 == strcasecmp(tk, "SOLID_SOLID_CONNECTION")) @@ -1905,6 +1118,8 @@ process_model_line ERR(process_fluid(stardis, &tok_ctx)); else if(0 == strcasecmp(tk, "SCALE")) ERR(process_scale(stardis, &tok_ctx)); + else if(0 == strcasecmp(tk, "TRAD")) + ERR(process_radiative(stardis, &tok_ctx)); else { logger_print(stardis->logger, LOG_ERROR, "Unknown description type: %s\n", tk); @@ -1922,46 +1137,68 @@ error: goto end; } -unsigned +res_T get_dummy_solid_id (struct stardis* stardis, - struct dummies* dummies) + unsigned* id) { - struct solid dummy; - if(dummies->dummy_solid) - return dummies->dummy_solid_id; + res_T res = RES_OK; + struct solid* dummy = NULL; + struct dummies* dummies; + ASSERT(stardis && id); + dummies = &stardis->dummies; + if(dummies->dummy_solid) { + *id = dummies->dummy_solid_id; + goto end; + } + ERR(init_solid(stardis->allocator, &dummy)); + dummies->stardis_solid = dummy; 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); + 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; + *id = dummies->dummy_solid_id; +end: + return res; +error: + goto end; } -unsigned +res_T get_dummy_fluid_id (struct stardis* stardis, - struct dummies* dummies) + unsigned* id) { - struct fluid dummy; - if(dummies->dummy_fluid) - return dummies->dummy_fluid_id; + res_T res = RES_OK; + struct fluid* dummy = NULL; + struct dummies* dummies; + ASSERT(stardis && id); + dummies = &stardis->dummies; + if(dummies->dummy_fluid) { + *id = dummies->dummy_fluid_id; + goto end; + } + ERR(init_fluid(stardis->allocator, &dummy)); + dummies->stardis_fluid = dummy; 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); + 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; + *id = dummies->dummy_fluid_id; +end: + return res; +error: + goto end; } diff --git a/src/stardis-parsing.h b/src/stardis-parsing.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2018-2021 |Meso|Star> (contact@meso-star.com) +/* Copyright (C) 2018-2022 |Meso|Star> (contact@meso-star.com) * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -37,89 +37,6 @@ struct dummies; 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, - - RANDOM_RW_MODES - = MODE_PROBE_COMPUTE | MODE_PROBE_COMPUTE_ON_INTERFACE | MODE_MEDIUM_COMPUTE - | MODE_BOUNDARY_COMPUTE | MODE_FLUX_BOUNDARY_COMPUTE -}; - -STATIC_ASSERT(GREEN_COMPATIBLE_MODES == (COMPUTE_MODES & GREEN_COMPATIBLE_MODES), - Cannot_have_a_GREEN_COMPATIBLE_MODE_that_is_not_a_COMPUTE_MODE); - -enum dump_path_type { - DUMP_NONE = 0, - DUMP_SUCCESS = BIT(0), - DUMP_ERROR = BIT(1), - DUMP_ALL = DUMP_SUCCESS | DUMP_ERROR -}; - -struct args { - struct logger* logger; - struct mem_allocator* allocator; - struct darray_str model_files; - char* medium_name; - char* solve_filename; - char* bin_green_filename; - char* end_paths_filename; - char* paths_filename; - char* rndgen_state_in_filename; - char* rndgen_state_out_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; @@ -148,63 +65,19 @@ add_geom_ctx_position 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, - struct mem_allocator* allocator); - -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); + struct stardis* stardis); -extern LOCAL_SYM unsigned +extern LOCAL_SYM res_T get_dummy_solid_id (struct stardis* stardis, - struct dummies* dummies); + unsigned* id); -extern LOCAL_SYM unsigned +extern LOCAL_SYM res_T get_dummy_fluid_id (struct stardis* stardis, - struct dummies* dummies); + unsigned* id); #endif /*ARGS_H*/ diff --git a/src/stardis-solid.c b/src/stardis-solid.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2018-2021 |Meso|Star> (contact@meso-star.com) +/* Copyright (C) 2018-2022 |Meso|Star> (contact@meso-star.com) * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -19,6 +19,8 @@ #include <sdis.h> +#include <rsys/mem_allocator.h> + #include <limits.h> /******************************************************************************* @@ -30,9 +32,9 @@ solid_get_calorific_capacity (const struct sdis_rwalk_vertex* vtx, struct sdis_data* data) { - const struct solid* solid_props = sdis_data_cget(data); + const struct solid* const* solid_props = sdis_data_cget(data); (void)vtx; - return solid_props->cp; + return (*solid_props)->cp; } static double @@ -40,9 +42,9 @@ solid_get_thermal_conductivity (const struct sdis_rwalk_vertex* vtx, struct sdis_data* data) { - const struct solid* solid_props = sdis_data_cget(data); + const struct solid* const* solid_props = sdis_data_cget(data); (void)vtx; - return solid_props->lambda; + return (*solid_props)->lambda; } static double @@ -50,9 +52,9 @@ solid_get_volumic_mass (const struct sdis_rwalk_vertex* vtx, struct sdis_data* data) { - const struct solid* solid_props = sdis_data_cget(data); + const struct solid* const* solid_props = sdis_data_cget(data); (void)vtx; - return solid_props->rho; + return (*solid_props)->rho; } static double @@ -60,9 +62,9 @@ solid_get_delta (const struct sdis_rwalk_vertex* vtx, struct sdis_data* data) { - const struct solid* solid_props = sdis_data_cget(data); + const struct solid* const* solid_props = sdis_data_cget(data); (void)vtx; - return solid_props->delta; + return (*solid_props)->delta; } #if Stardis_VERSION_MINOR == 3 @@ -71,8 +73,8 @@ 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; + const struct solid* const* solid_props = sdis_data_cget(data); + return (*solid_props)->delta; } #endif @@ -81,21 +83,21 @@ 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) + const struct solid* const* 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) { + 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)) { + 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))); + ARG1(str_cget(&(*solid_props)->name))); } } - return solid_props->tinit; + return (*solid_props)->tinit; } return -1; /* Unknown temperature */ } @@ -105,9 +107,9 @@ solid_get_power (const struct sdis_rwalk_vertex* vtx, struct sdis_data* data) { - const struct solid* solid_props = sdis_data_cget(data); + const struct solid* const* solid_props = sdis_data_cget(data); (void)vtx; - return solid_props->vpower; + return (*solid_props)->vpower; } /******************************************************************************* @@ -122,14 +124,14 @@ create_solver_solid res_T res = RES_OK; struct sdis_solid_shader solid_shader = SDIS_SOLID_SHADER_NULL; struct sdis_data* data = NULL; - struct solid* props; + const 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; + solid_shader.delta = solid_get_delta; #if Stardis_VERSION_MINOR == 3 solid_shader.delta_boundary = solid_get_delta_boundary; #endif @@ -138,13 +140,12 @@ create_solver_solid NULL, &data)); props = sdis_data_get(data); /* Fetch the allocated memory space */ - init_solid(stardis->allocator, props); - cp_solid(props, solid_props); + *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); + ASSERT(!darray_media_ptr_data_get(&stardis->media)[solid_props->solid_id]); ERR(sdis_solid_create(stardis->dev, &solid_shader, data, darray_media_ptr_data_get(&stardis->media) + solid_props->solid_id)); @@ -155,28 +156,46 @@ error: goto end; } -void -init_solid(struct mem_allocator* allocator, struct solid* dst) +res_T +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; + res_T res = RES_OK; + int str_initialized = 0; + ASSERT(allocator && dst && *dst == NULL); + *dst = MEM_ALLOC(allocator, sizeof(struct solid)); + if(! *dst) { + res = RES_MEM_ERR; + goto error; + } + 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; +end: + return res; +error: + if(str_initialized) str_release(&(*dst)->name); + if(*dst) MEM_RM(allocator, *dst); + goto end; } void -release_solid(struct solid* solid) +release_solid + (struct solid* solid, + struct mem_allocator* allocator) { + ASSERT(solid && allocator); str_release(&solid->name); + MEM_RM(allocator, solid); } res_T @@ -201,21 +220,3 @@ end: 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 @@ -1,4 +1,4 @@ -/* Copyright (C) 2018-2021 |Meso|Star> (contact@meso-star.com) +/* Copyright (C) 2018-2022 |Meso|Star> (contact@meso-star.com) * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -20,6 +20,7 @@ #include <rsys/str.h> struct stardis; +struct mem_allocator; /******************************************************************************* * Solid data @@ -40,17 +41,16 @@ struct solid { unsigned solid_id; }; -LOCAL_SYM void -init_solid(struct mem_allocator* allocator, struct solid* dst); +LOCAL_SYM res_T +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); +release_solid + (struct solid* desc, + struct mem_allocator* allocator); LOCAL_SYM res_T -cp_solid(struct solid* dst, const struct solid* src); +str_print_solid(struct str* str, const struct solid* solid); LOCAL_SYM res_T create_solver_solid diff --git a/stardis-green-types/stardis-green-types-config-version.cmake.in b/stardis-green-types/stardis-green-types-config-version.cmake.in @@ -0,0 +1,22 @@ +# Copyright (C) 2018-2022 |Meso|Star> (contact@meso-star.com) +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + +SET(PACKAGE_VERSION @STARDIS_GREEN_TYPES_VERSION@) + +IF (${PACKAGE_FIND_VERSION_MAJOR} EQUAL @STARDIS_GREEN_TYPES_VERSION@) + SET(PACKAGE_VERSION_COMPATIBLE 1) +ELSE() + SET(PACKAGE_VERSION_UNSUITABLE 1) +ENDIF() diff --git a/stardis-green-types/stardis-green-types-config.cmake b/stardis-green-types/stardis-green-types-config.cmake @@ -0,0 +1,28 @@ +# Copyright (C) 2013-2017, 2021 Vincent Forest (vaplv@free.fr) +# +# 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.1) +include(SelectLibraryConfigurations) + +# Try to find stardis-green-types + +# Look for stardis-green-types header +find_path(SGT_INCLUDE_DIR stardis-green-types.h) + +# Check the package +include(FindPackageHandleStandardArgs) +FIND_PACKAGE_HANDLE_STANDARD_ARGS(stardis-green-types DEFAULT_MSG + SGT_INCLUDE_DIR) +