solstice

Compute collected power and efficiencies of a solar plant
git clone git://git.meso-star.com/solstice.git
Log | Files | Refs | README | LICENSE

commit 6b3109b669640ca102375c28014e7e362e72586d
parent ea201297e6a9cab0514f830139c2a43ee89afdd5
Author: Vincent Forest <vincent.forest@meso-star.com>
Date:   Fri,  2 Jun 2017 16:15:24 +0200

Merge branch 'release-0.2'

Diffstat:
MREADME.md | 71+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++----------
Mcmake/CMakeLists.txt | 43+++++++++++++++++++++++++++++++++++--------
Acmake/doc/CMakeLists.txt | 150+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mcmake/parser/CMakeLists.txt | 11++++++++++-
Ddoc/cli | 90-------------------------------------------------------------------------------
Ddoc/input | 341-------------------------------------------------------------------------------
Ddoc/output | 47-----------------------------------------------
Ddoc/receiver | 19-------------------
Adoc/solstice-input.5.txt | 1150+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Adoc/solstice-man.css | 87+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Adoc/solstice-output.5.txt | 488+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Adoc/solstice-receiver.5.txt | 114+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Adoc/solstice.1.txt.in | 241+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Msrc/parser/solparser.c | 96++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++---------
Msrc/parser/solparser.h | 57++++++++++++++++++++++++++++++++++++++++++---------------
Asrc/parser/solparser_atmosphere.c | 118+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/parser/solparser_atmosphere.h | 51+++++++++++++++++++++++++++++++++++++++++++++++++++
Msrc/parser/solparser_c.h | 117+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--------------
Msrc/parser/solparser_geometry.c | 230++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-------
Asrc/parser/solparser_image.c | 107+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/parser/solparser_image.h | 62++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Msrc/parser/solparser_material.c | 143+++++++++++++++++++------------------------------------------------------------
Msrc/parser/solparser_material.h | 59+++++++++++++++++++++++++++++++++++++++++++++++++----------
Asrc/parser/solparser_medium.c | 131+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/parser/solparser_medium.h | 30++++++++++++++++++++++++++++++
Asrc/parser/solparser_mtl_data.c | 56++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/parser/solparser_mtl_data.h | 35+++++++++++++++++++++++++++++++++++
Msrc/parser/solparser_pivot.c | 22+++-------------------
Msrc/parser/solparser_shape.h | 67+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Msrc/parser/solparser_spectrum.c | 76+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-----------
Msrc/parser/solparser_spectrum.h | 39+++++++++++++++++++++++++++++++++++++++
Msrc/parser/solparser_sun.c | 3+--
Msrc/parser/solparser_sun.h | 25++++++-------------------
Msrc/parser/test_solparser2.c | 22+++++++++++++++-------
Msrc/parser/test_solparser3.c | 35++++++++++++++++++++++++++++++++---
Msrc/parser/test_solparser4.c | 6++++--
Msrc/parser/test_solparser6.c | 34++++++++++++++++++++++++++++++++--
Msrc/parser/test_solparser7.c | 47++++++++++++++++++++++++++++++++++++++++-------
Msrc/parser/test_solparser8.c | 66++++++++++++++++++++++++++++++++++++++++++++----------------------
Asrc/parser/test_solparser_normal_map.c | 338+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/parser/test_solparser_spectrum.c | 355+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Msrc/parser/yaml/test_ko_0.yaml | 253+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++------
Msrc/parser/yaml/test_ok_0.yaml | 7++++++-
Msrc/parser/yaml/test_ok_2.yaml | 13+++++++++++++
Msrc/parser/yaml/test_ok_5.yaml | 12++++++------
Msrc/parser/yaml/test_ok_6.yaml | 26++++++++++++++++++++++++--
Msrc/parser/yaml/test_ok_7.yaml | 25+++++++++++++++++++------
Msrc/solstice.c | 52++++++++++++++++++++++++++++++++++++++++++++++++++--
Msrc/solstice.h | 21++++++++++++++++++++-
Msrc/solstice_args.c | 15++++++++-------
Msrc/solstice_args.h.in | 6+++---
Asrc/solstice_atmosphere.c | 63+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/solstice_atmosphere.h | 0
Msrc/solstice_c.h | 16++++++++++++++++
Msrc/solstice_draw.c | 46++++++++++++++++++++++++++++------------------
Msrc/solstice_dump.c | 2++
Msrc/solstice_entity.c | 30++++++++++++++++++++++++------
Msrc/solstice_material.c | 436++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-----------
Msrc/solstice_object.c | 86+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++----------
Msrc/solstice_solve.c | 220+++++++++++++++++++++++++++++++++++++++++++++++++------------------------------
Asrc/solstice_spectrum.c | 71+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Msrc/solstice_sun.c | 42+++++++++++++++++++++++++++++-------------
Asrc/solstice_sun_spectrum.c | 772+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/solstice_sun_spectrum.h | 33+++++++++++++++++++++++++++++++++
Msrc/test_solstice_args.c | 42+++++++++++++++++++++---------------------
Msrc/test_solstice_simulation.c | 423+++++++++++++++++++++++++++++++++++++++++++++++++------------------------------
Myaml/beam_down.ref | 52++++++++++++++++++++++++++++++++++++++++++++++------
Myaml/beam_down.yaml | 2+-
Myaml/test01.ref | 11+++++++++--
Myaml/test01.yaml | 4+---
Myaml/test02.ref | 13++++++++++---
Myaml/test02.yaml | 8++++----
Myaml/test03.ref | 11+++++++++--
Myaml/test03.yaml | 4+---
Myaml/test04.ref | 12++++++++++--
Myaml/test04.yaml | 4+---
Myaml/test05.ref | 11+++++++++--
Myaml/test05.yaml | 4+---
Ayaml/test06.ref | 12++++++++++++
Ayaml/test06.yaml | 60++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Ayaml/test06_receiver.yaml | 1+
Ayaml/test07.ref | 12++++++++++++
Ayaml/test07.yaml | 39+++++++++++++++++++++++++++++++++++++++
Ayaml/test07_receiver.yaml | 1+
Ayaml/test08.ref | 12++++++++++++
Ayaml/test08.yaml | 43+++++++++++++++++++++++++++++++++++++++++++
Ayaml/test08_receiver.yaml | 1+
87 files changed, 7064 insertions(+), 1244 deletions(-)

diff --git a/README.md b/README.md @@ -1,11 +1,37 @@ # Solstice -The purpose of this program is to estimate the solar flux in complex solar -facilities. It has been developed in the scope of the Solstice project, in +The purpose of this program is to compute the total power collected by a +concentrated solar plant, and to evaluate various efficiencies for each primary +reflector: it compute losses due to cosine effect, to shadowing and +masking, to orientation and surface irregularities, to reflectivity and to +atmospheric transmission. The efficiency for each one of these effects is +subsequently computed for each reflector, which provides insightful information +when looking for the optimal design of a concentrated solar plant. Note that +Solstice relies on Monte-Carlo method, which means that every result is +provided with its numerical accuracy. + +In addition of the aforementioned computations, Solstice can render an image of +the solar plant, either with a simple ray-caster or with a path-tracing +algorithm that correctly handles the materials of the scene. + +Solstice is designed to handle complex solar plants: any number of reflectors +can be specified (planes, conics, cylindro-parabolic, etc.) and positioned in +3D space, with a possibility for 1-axis and 2-axis auto-orientation with +respect to the sun direction. CAO geometries can be added to the solar plant +thanks to the support of the STereo Lithography file format. Multiple materials +can be used, as long as the relevant physical properties are provided (matte, +mirror, dielectric, etc.). Spectral effects are also taken into account: it is +possible to define the spectral distribution of any physical property, +including the input solar spectrum and the absorption of the atmosphere, at any +spectral resolution. + +Solstice has been developed in the scope of the Solstice project, in collaboration with the [Laboratory of Excellence Solstice](http://www.labex-solstice.fr) and the [PROMES](http://www.promes.cnrs.fr/index.php?page=home-en) laboratory of the National Center for Scientific Research ([CNRS](http://www.cnrs.fr/index.php)). +Refer to the Solstice man pages for more informations on the provided +functionalities. ## How to build @@ -16,20 +42,45 @@ It also depends on the [RSys](https://gitlab.com/vaplv/rsys/), [Solstice-Anim](https://gitlab.com/meso-star/solstice-anim/), [Solstice-Solver](https://gitlab.com/meso-star/solstice-solver/), -[Star-3DUT](https://gitlab.com/meso-star/star-3dut/) and, -[Star-SP](https://gitlab.com/meso-star/star-sp/) libraries. +[Star-3DUT](https://gitlab.com/meso-star/star-3dut/), +[Star-SP](https://gitlab.com/meso-star/star-sp/) and +[Star-STL](https://gitlab.com/meso-star/star-stm/) libraries. +The documentation is written with the +[AsciiDoc](http://www.methods.co.nz/asciidoc/) text format and relies on its +tool suite to generate HTML and/or ROFF man pages. If the AsciiDoc tools cannot +be find, the documentation will be not built. First ensure that CMake is installed on your system. Then install the RCMake -package as well as all the aforementioned prerequisites. Finally generate the +package as well as the aforementioned prerequisites. Finally generate the project from the `cmake/CMakeLists.txt` file by appending to the -`CMAKE_PREFIX_PATH` variable the install directories of its dependencies. +`CMAKE_PREFIX_PATH` variable the install directories of its dependencies. The +resulting project can be edited, built, tested and installed as any CMake +project. Refer to the [CMake](https://cmake.org/documentation) for further +informations on CMake. + +## Release notes + +### Version 0.2 + +- Add the support of an optional normal map to the materials. It defines + spatially varying normals in the tangent space of the surface. Currently, + only the quadric surfaces are parameterized: using a normal mapped material + on the other shapes will produce unforeseen behaviors. +- Add the support of spectral data to the materials: a material attribute can be + either a scalar or follow a spectral distribution. +- Add an optional atmospheric absorption after the first reflection of the light + path; the sun description includes the atmospheric effect before the first + reflector. +- Write the man pages of the Solstice command line and its associated file + formats. +- Add the verbose option `-v`. +- Update the output format of the simulation. ## Licenses Solstice is developed by [|Meso|Star>](http://www.meso-star.com) for the [National Center for Scientific Research](http://www.cnrs.fr/index.php) (CNRS). -It is a free software copyright (C) CNRS 2016-2017 and it is released under the -[OSI](http://opensource.org)-approved GPL v3+ license. You are welcome to -redistribute it under certain conditions; refer to the COPYING file for -details. +This is a free software copyright (C) CNRS 2016-2017 released under the GPL v3+ +license: GNU GPL version 3 or later. You are welcome to redistribute it under +certain conditions; refer to the COPYING file for details. diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt @@ -16,8 +16,23 @@ cmake_minimum_required(VERSION 2.8) project(solstice C) enable_testing() + option(NO_TEST "Do not build tests" OFF) +if(CMAKE_HOST_UNIX) + set(SOLSTICE_DOC "TROFF & HTML" CACHE STRING + "Type of documentation to generate and install.") +else() + set(SOLSTICE_DOC "HTML" CACHE STRING + "Type of documentation to generate and install.") +endif() + +set_property(CACHE SOLSTICE_DOC PROPERTY STRINGS + "HTML" + "TROFF" + "TROFF & HTML" + "NONE") + set(SOLSTICE_SOURCE_DIR ${PROJECT_SOURCE_DIR}/../src/) ################################################################################ @@ -30,10 +45,10 @@ find_package(LibYAML REQUIRED) find_package(RCMake 0.2.3 REQUIRED) find_package(RSys 0.4 REQUIRED) find_package(SolAnim 0.1 REQUIRED) -find_package(SolSolver 0.1.1 REQUIRED) -find_package(Star3DUT REQUIRED) +find_package(SolSolver 0.2 REQUIRED) +find_package(Star3DUT 0.2 REQUIRED) find_package(StarSP 0.4 REQUIRED) -find_package(StarSTL 0.3 REQUIRED) +find_package(StarSTL 0.3.1 REQUIRED) if(MSVC) find_package(MuslGetopt REQUIRED) @@ -57,6 +72,9 @@ include_directories( ################################################################################ # Build subprojects ################################################################################ +if(NOT SOLSTICE_DOC STREQUAL "NONE") + add_subdirectory(doc) +endif() add_subdirectory(parser) add_subdirectory(receivers) @@ -74,18 +92,21 @@ set(SOLSTICE_ARGS_DEFAULT_IMG_SPP "1") configure_file(${SOLSTICE_SOURCE_DIR}/solstice_args.h.in ${CMAKE_CURRENT_BINARY_DIR}/solstice_args.h @ONLY) +configure_file(${SOLSTICE_SOURCE_DIR}/../doc/solstice.1.txt.in + ${CMAKE_CURRENT_BINARY_DIR}/doc/solstice.1.txt @ONLY) ################################################################################ # Configure and define targets ################################################################################ set(VERSION_MAJOR 0) -set(VERSION_MINOR 1) -set(VERSION_PATCH 1) +set(VERSION_MINOR 2) +set(VERSION_PATCH 0) set(VERSION ${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_PATCH}) set(SOLSTICE_FILES_SRC solstice.c solstice_args.c + solstice_atmosphere.c solstice_draw.c solstice_dump.c solstice_entity.c @@ -93,11 +114,14 @@ set(SOLSTICE_FILES_SRC solstice_node.c solstice_object.c solstice_solve.c - solstice_sun.c) + solstice_spectrum.c + solstice_sun.c + solstice_sun_spectrum.c) set(SOLSTICE_FILES_INC solstice.h solstice_args.h.in - solstice_c.h) + solstice_c.h + solstice_sun_spectrum.h) set(SOLSTICE_FILES_DOC COPYING README.md) # Prepend each file in the `SOLSTICE_FILES_<SRC|INC>' list by `SOLSTICE_SOURCE_DIR' @@ -143,7 +167,7 @@ if(NOT NO_TEST) build_test(test_solstice_simulation) function(add_test_simulation _name) add_test(NAME test_solstice_simulation_${_name} - COMMAND test_solstice_simulation + COMMAND test_solstice_simulation $<TARGET_FILE:solstice> ${SOLSTICE_SOURCE_DIR}/../yaml/ ${_name}) @@ -155,6 +179,9 @@ if(NOT NO_TEST) add_test_simulation(test03) add_test_simulation(test04) add_test_simulation(test05) + add_test_simulation(test06) + add_test_simulation(test07) + add_test_simulation(test08) endif() diff --git a/cmake/doc/CMakeLists.txt b/cmake/doc/CMakeLists.txt @@ -0,0 +1,150 @@ +# Copyright (C) CNRS 2016-2017 +# +# 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 2.8) + +string(REGEX MATCH ".*HTML.*" _html ${SOLSTICE_DOC}) +string(REGEX MATCH ".*ROFF.*" _roff ${SOLSTICE_DOC}) + +set(SOLSTICE_DOC_DIR ${PROJECT_SOURCE_DIR}/../doc) + +################################################################################ +# Look for asciidoc and a2x programs +################################################################################ +if(_html) + find_program(ASCIIDOC asciidoc) + if(NOT ASCIIDOC) + unset(_html) + message(WARNING + "The `asciidoc' program is missing. " + "The solstice HTML documentation cannot be generated.") + endif() +endif() + +if(_roff) + find_program(A2X a2x) + if(NOT A2X) + unset(_roff) + message(WARNING + "The `a2x' program is missing. " + "The solstice man pages cannot be generated.") + endif() +endif() + +################################################################################ +# Copy doc files +################################################################################ +set(MAN_NAMES + solstice-input.5 + solstice-output.5 + solstice-receiver.5) + +if(_roff OR _html) + set(MAN_FILES) + foreach(_name IN LISTS MAN_NAMES) + set(_src ${SOLSTICE_DOC_DIR}/${_name}.txt) + set(_dst ${CMAKE_CURRENT_BINARY_DIR}/${_name}.txt) + add_custom_command( + OUTPUT ${_dst} + COMMAND ${CMAKE_COMMAND} -E copy ${_src} ${_dst} + DEPENDS ${_src} + COMMENT "Copy the asciidoc ${_src}" + VERBATIM) + list(APPEND MAN_FILES ${_dst}) + endforeach() + add_custom_target(man-copy ALL DEPENDS ${MAN_FILES}) +endif() + +list(APPEND MAN_NAMES solstice.1) + +################################################################################ +# ROFF man pages +################################################################################ +if(_roff) + set(A2X_OPTS -dmanpage -fmanpage) + set(MAN_FILES) + set(MAN5_FILES) + set(MAN1_FILES) + foreach(_name IN LISTS MAN_NAMES) + set(_man ${CMAKE_CURRENT_BINARY_DIR}/${_name}) + set(_txt ${CMAKE_CURRENT_BINARY_DIR}/${_name}.txt) + + add_custom_command( + OUTPUT ${_man} + COMMAND ${A2X} ${A2X_OPTS} ${_txt} + DEPENDS man-copy ${_txt} + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} + COMMENT "Build ROFF man page ${_man}" + VERBATIM) + list(APPEND MAN_FILES ${_man}) + + string(REGEX MATCH "^.*.5$" _man5 ${_man}) + string(REGEX MATCH "^.*.1$" _man1 ${_man}) + if(_man1) + list(APPEND MAN1_FILES ${_man1}) + elseif(_man5) + list(APPEND MAN5_FILES ${_man5}) + else() + message(FATAL_ERROR "Unexpected man type") + endif() + endforeach() + add_custom_target(man-roff ALL DEPENDS ${MAN_FILES}) + + install(FILES ${MAN1_FILES} DESTINATION share/man/man1) + install(FILES ${MAN5_FILES} DESTINATION share/man/man5) +endif() + +################################################################################ +# HTML documentation +################################################################################ +if(_html) + set(ASCIIDOC_OPTS + -bxhtml11 + -dmanpage + --attribute themedir=${SOLSTICE_DOC_DIR} + --theme=solstice-man) + + set(MAN_FILES) + set(MAN5_FILES) + set(MAN1_FILES) + foreach(_name IN LISTS MAN_NAMES) + set(_man ${CMAKE_CURRENT_BINARY_DIR}/${_name}.html) + set(_txt ${CMAKE_CURRENT_BINARY_DIR}/${_name}.txt) + + add_custom_command( + OUTPUT ${_man} + COMMAND ${ASCIIDOC} ${ASCIIDOC_OPTS} ${_txt} + DEPENDS man-copy ${_txt} ${SOLSTICE_DOC_DIR}/solstice-man.css + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} + COMMENT "Build HTML man page ${_man}" + VERBATIM) + list(APPEND MAN_FILES ${_man}) + + string(REGEX MATCH "^.*.5.html$" _man5 ${_man}) + string(REGEX MATCH "^.*.1.html$" _man1 ${_man}) + if(_man1) + list(APPEND MAN1_FILES ${_man1}) + elseif(_man5) + list(APPEND MAN5_FILES ${_man5}) + else() + message(FATAL_ERROR "Unexpected man type") + endif() + endforeach() + add_custom_target(man-html ALL DEPENDS ${MAN_FILES}) + + install(FILES ${MAN1_FILES} DESTINATION share/man/man1) + install(FILES ${MAN5_FILES} DESTINATION share/man/man5) +endif() + diff --git a/cmake/parser/CMakeLists.txt b/cmake/parser/CMakeLists.txt @@ -31,18 +31,26 @@ include_directories( ################################################################################ set(SOLPARSER_FILES_SRC solparser.c + solparser_atmosphere.c solparser_entity.c + solparser_image.c solparser_geometry.c solparser_material.c + solparser_medium.c + solparser_mtl_data.c solparser_pivot.c solparser_sun.c solparser_spectrum.c) set(SOLPARSER_FILES_INC solparser.h solparser_c.h + solparser_atmosphere.h solparser_entity.h solparser_geometry.h + solparser_image.h solparser_material.h + solparser_medium.h + solparser_mtl_data.h solparser_pivot.h solparser_shape.h solparser_sun.h @@ -103,8 +111,9 @@ if(NOT NO_TEST) new_test(test_solparser6) new_test(test_solparser7) new_test(test_solparser8) + new_test(test_solparser_normal_map) + new_test(test_solparser_spectrum) rcmake_copy_runtime_libraries(test_solparser) endif() - diff --git a/doc/cli b/doc/cli @@ -1,90 +0,0 @@ -solstice - -b # Output binary per receiver hits - -d <date-list>:<pos-on-earth> - -D <sun-dir-list> - -f # Force output overwrite - -h # Short help and exit - -g <dump> # Switch in dump geometry - -o OUTPUT # defaulting to stdout if not defined - -p <dump-radiative-path> # Switch in dump radiative paths mode - -q # don't print a message if no INPUT is submitted - -n INTEGER # Realisations count - -r <rendering> # Switch in rendering mode - -R FILE # receivers - -t INTEGER # Threads count - INPUT # Input scene in YAML - -solstice -r img=1280x720:pos=0,100,0:tgt=0,0,0:up=0,1,0:fov=70:spp=1 -solstice -g format=obj:split-group=1 - --d and -D are exclusive - -<date-list> ::= - <date> [ ... ] - -<date> ::= - year:month:day:minutes:seconds:timezone # <=> UNIX format - -<sun-dir-list> ::= - <sun-dir>:[ ... ] - -<sun-dir> ::= - REAL,REAL # azimuth:elevation - -<pos-on-earth> ::= - REAL:REAL:REAL # longititude:latitude:altitude - -<rendering> ::= - <rendering-option>[:<rendering-option> ... ] - -<rendering-option> ::= - <fov> | <img> | <position> | <render-mode> | <samples-per-pixel> | <target> | <up> - -<dump> ::= - format=<dump-format>[:split=<split-mode>] - -<dump-radiative-path> ::= - <dump-path-option>[:<dump-path-option> ... ] - -<dump-path-option> ::= - <sun-ray-len> | <inf-ray-len> | default - -<sun-ray-len> ::= - srlen=REAL - -<inf-ray-len> ::= # Length of the rays going to infinite - irlen=REAL - -<dump-format> ::= - obj - -<split-mode> ::= - geometry | object | none - -<fov> ::= - fov=<real3> - -<img> ::= - img=INTEGERxINTEGER - -<position> ::= - pos=<real3> - -<render-mode> ::= - rmode=<render-algorithm> - -<render-algorithm> ::= - draft | pt # path tracing - -<samples-per-pixel> ::= - spp=<INTEGER> - -<target> ::= - tgt=<real3> - -<up> ::= - up=<real3> - -<real3> ::= - REAL,REAL,REAL - diff --git a/doc/input b/doc/input @@ -1,341 +0,0 @@ -#-------------------------------------------------------------------------------- -# 1/ Example -#-------------------------------------------------------------------------------- -# Declare materials -- material: &lambertian - matte: - reflectivity: 1 -- material: &mirror - mirror: { reflectivity: 1, roughness: 0 } - -# Declare geometries -- geometry: &cylinders - - cylinder: { height: 5, radius: 0.5 } - material: *lambertian - transform: { rotation: [0, 90, 0] } - - cylinder: { height: 5, radius: 0.5 } - material: *lambertian - -- geometry: &parabol - - material: *mirror - parabol: - focal: 1 - clip: - - operation: SUB - vertices: [ [1, 2], [3, 4], [6, 7] ] - -# Create the solar factory -- sun: { dni: 1, spectrum: [{wavelength: 1, data: 1}] } -- entity: - name: "entity0" - primary: 0 - transform: { rotation: [0, 90, 0] } - anchors: - - name: "anchor0" - position: [1, 2, 3] - - name: "anchor2" - position: [3, 4, 5] - geometry: - - stl: { path: "house.stl" } - transform: { translation: [0, 1, 2] } - material: *lambertian - - cylinder: { height: 5, radius: 0.5 } - material: *mirror - -- template: &composition - name: "composition" - primary: 1 - transform: { translation: [1, 2, 3 ] } - geometry: - - cylinder: { height: 5, radius: 0.5 } - material: *mirror - children: - - name: "hop" - primary: 1 - transform: { translation: [1, 2, 3 ] } - geometry: *cylinders - - name: "hop2" - primary: 1 - geometry: *parabol - children: - - name: "child 1" - transform: { rotation: [0, 0, 0] } - x_pivot: - target: { position: [0, 0, 0] } -- entity: - name: "entity2" - transform: { translation: [4, 5, 6] } - children: [ *composition ] - -- entity: - name: "entity3" - transform: { translation: [7, 8, 9] } - children: [ *composition ] - -- entity: - name: "entity4" - transform: { translation: [10, 11, 12] } - children: [ *composition ] - -#-------------------------------------------------------------------------------- -# 2/ Grammar -#-------------------------------------------------------------------------------- -<solar-factory> ::= - <sun> - <items> - -<items> ::= - - <item> -[ - <item> ... ] - -<item> ::= - <geometry> - | <material> - | <entity> - | <template> - -#---------------------------------------- -<geometry> ::= - geometry: - - <object> -[ - <object> ... ] - -<object> ::= - <shape> - <material> -[ <transform> ] - -<x_pivot> ::= - x_pivot: -[ ref_point: <real3>. Default 0,0,0 ] - <target> - -<zx_pivot> ::= - zx_pivot: -[ spacing: REAL # in [0, INF). Default 0 ] -[ ref_point: <real3>. Default 0,0,0 ] - <target> - -<target> ::= - target: - anchor: <anchor-identifier> - | direction: <real3> - | position: <real3> - | <sun> - -#---------------------------------------- -<shape> ::= - <cuboid> - | <cylinder> - | <obj> - | <parabol> - | <parabolic-cylinder> - | <hyperbol> - | <plane> - | <sphere> - | <stl> - -<cuboid> ::= - cuboid: - size: <real3*+> - -<cylinder> ::= - cylinder: - height: REAL # in ]0, INF) - radius: REAL # in ]0, INF) -[ slices: INTEGER ] # in [4, 4096]. Default 16 - -<obj> ::= - obj: - path: PATH - -# x^2 + y^2 - 4*focal*z = 0 -<parabol> ::= - parabol: - focal: REAL # in ]0, INF) - clip: <polyclip-list> - # By default slices is automatically compute with respect to the parabol - # curvature -[ slices: INTEGER ] # in [4, 4096) - -<parabolic-cylinder> ::= - parabolic-cylinder: # y^2 - 4*focal*z = 0 - focal: REAL # in ]0, INF) - clip: <polyclip-list> - # By default slices is automatically compute with respect to the hyperbol - # curvature -[ slices: INTEGER ] # in [4, 4096) - -# (x^2 + y^2) / a^2 - (z + z0 - g/2)^2 / b^2 + 1 = 0 -# with g = img_focal + real_focal; f = real_focal / g; -# a^2 = g^2(f - f^2); b = g(f - 1/2); z0 = |b| + g/2 -<hyperbol> ::= - hyperbol: - focals: <hyperboloid_focals> - clip: <polyclip-list> - # By default slices is automatically compute with respect to the hyperbol - # curvature -[ slices: INTEGER ] # in [4, 4096) - -<hyperboloid_focals> ::= - real: REAL # in ]0, INF) - image: REAL # in ]0, INF) - -<plane> ::= - plane: - clip: <polyclip-list> -[ slices: INTEGER ] # in [1, 4096). Default 1 - -<sphere> ::= - sphere: - radius: REAL # in ]0, INF) -[ slices: INTEGER ] # in [4, 4096]. Default 16 - -<stl> ::= - stl: - path: PATH - -#---------------------------------------- -<polyclip-list> ::= - - <polyclip> -[ - <polyclip> ... ] - -<polyclip> ::= - operation: <AND|SUB> - vertices: <vertices-list> - -<vertices-list> ::= - - <real2> - - <real2> - - <real2> -[ - <real2> ... ] - -#---------------------------------------- -<material> ::= - <material-descriptor> | <double-sided-material> - -<double-sided-material> ::= - front: <material-descriptor> - back: <material-descriptor> - -<material-descriptor> ::= - <dielectric> | <matte> | <mirror> | thin-dielectric> | <virtual> - -<dielectric> ::= - dielectric: - medium_i: <dielectric-medium> - medium_t: <dielectric-medium> - -<matte> ::= - matte: - reflectivity: REAL # in [0, 1] - -<mirror> ::= - mirror: - reflectivity: REAL # in [0, 1] - roughness: REAL # in [0, 1] - -<virtual> ::= - virtual: EMPTY-STRING - -<thin-dielectric> ::= - thin_dielectric: - thickness: REAL # in [0, INF) - medium_i: <dielectric-medium> - medium_t: <dielectric-medium> - -<dielectric-medium> ::= - refractive_index: REAL # in ]0, INF) - absorptivity: REAL # in [0, INF) - -#---------------------------------------- -<entity> ::= - entity: - <entity-data> - -<template> ::= - template: - <entity-data> - -<entity-data> ::= - name: STRING # except "self" -[ <geometry-data> | <x_pivot> | <zx_pivot> ] -[ <anchors> ] -[ <transform> ] -[ <children> ] - -<geometry-data> ::= - primary: INTEGER # in [0, 1] - <geometry> - -<children> ::= - children: - - <entity-data> -[ - <entity-data> ... ] - -<anchors> ::= - anchors: - - <anchor-data> -[ - <anchor-data> ... ] - -<anchor-data> ::= - name: STRING - <position-description> - -<position-description> ::= - position: <real3> | hyperboloid_image_focals: <hyperboloid_focals> - -# "self" references the first level entity -<entity-identifier> ::= - <self|STRING>[.STRING ... ] - -<anchor-identifier> ::= - <entity-identifier>.STRING - -#---------------------------------------- -<sun> ::= - sun: - dni: REAL # Direct Normal Irradiance in ]0, INF) - <spectrum> -[ <radial-angular-distribution> ] - -<radial-angular-distribution> ::= - <pillbox> | <buie> - -<buie> ::= - buie: - csr: REAL # in [1e-6, 0.849] - -<pillbox> ::= - pillbox: - aperture: REAL # in ]0, 90] - -#---------------------------------------- -<transform> ::= - transform: - translation: <real3> - rotation: <real3> - -<real2> ::= - - REAL - - REAL - -<real3> ::= - - REAL - - REAL - - REAL - -<real3*+> ::= - - REAL # in ]0, inf) - - REAL # in ]0, inf) - - REAL # in ]0, inf) - -<spectrum> ::= - spectrum: - - <spectrum-data> -[ - <spectrum-data> ... ] - -<spectrum-data> ::= - wavelength: REAL # in [0, INF) - data: REAL # in [0, INF) - diff --git a/doc/output b/doc/output @@ -1,47 +0,0 @@ -<output> ::= - <count> -[ <mc-receiver> ... ] - <mc-shadow> - <mc-missing> -[ <receiver-hit> ... ] - -<count> ::= - INTEGER INTEGER # receivers-count experiments-count - -<mc-receiver> ::= - <receiver-name> <receiver-id> <integrated-irradiance> <reflectivity-loss> <absorptivity-loss> <cos-loss> <efficiency> - -<receiver-id> ::= - INTEGER - -<receiver-name> ::= - STRING - -<intregrated-irradiance> ::= - <mc-double-sided> - -<reflectivity-loss> ::= - <mc-double-sided> - -<absorptivity-loss> ::= - <mc-double-sided> - -<coss-loss> ::= - <mc-double-sided> - -<efficiency> ::= - <mc-double-sided> - -<mc-double-sided> ::= - <estimation> <estimation> # front-estimation back-estimation - -<mc-shadow> ::= - <estimation> - -<mc-missing> ::= - <estimation> - -<estimation> ::= - REAL REAL # Expected value and standard error - -<receiver-hit> ::= TODO diff --git a/doc/receiver b/doc/receiver @@ -1,19 +0,0 @@ -- { name: "entity.mirror", side: BACK } -- { name: "entity2.mirror0, side: FRONT } -- { name: "entity2.mirror1, side: FRONT_AND_BACK } - --------------------------------------------------------------------------------- -2/ Grammar --------------------------------------------------------------------------------- -<receivers> ::= - - <receiver> -[ - <receiver> ... ] - -<receiver> ::= - name: <entity-identifier> - side: <BACK|FRONT|FRONT_AND_BACK> -[ per_primitive: INTEGER ] # in [0, 1] - -<entity-identifier> - STRING[.STRING ... ] - diff --git a/doc/solstice-input.5.txt b/doc/solstice-input.5.txt @@ -0,0 +1,1150 @@ +// Copyright (C) CNRS 2016-2017 +// +// This is free documentation: 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 manual is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see <http://www.gnu.org/licenses/>. +:toc: + +solstice-input(5) +================= + +NAME +---- +solstice-input - solar plant description for solstice(1) + +DESCRIPTION +----------- +The *solstice-input* is the format used by the *solstice*(1) program to +represent a solar plant. It relies on the YAML 1.1 data serialization standard +[1]; assuming that the file is compatible with the *solstice-input* semantic, a +solar plant can be described by using the whole YAML 1.1 functionalities +including compact notation and data tagging. + +A solar plant is composed of a *sun*, an optional *atmosphere* and a collection +of *geometries*, i.e. *shapes* with their associated *material*. Beside the raw +description of the aforementioned data, the *solstice-input* format provides +the *entity* item to efficiently structure the geometries in the scene. An +entity is a node in a tree data structure where the position of each child +entity is relative to the position of its parent. An entity can either +encapsulate a *geometry* or a *pivot* that controls the dynamic positioning of +its child entities with respect to the pivot constraints and the sun direction +submitted to the *solstice*(1) program. + +GRAMMAR +------- + +[verse] +_______ +<solar-plant> ::= - <sun> + - <item> + [ - <item> ... ] + [ - <atmosphere> ] + +<item> ::= <entity> + | <geometry> + | <material> + | <medium> + | <spectrum> + | <template> + +------------------------------------- + +<geometry> ::= geometry: + - <object> + [ - <object> ... ] + +<object> ::= <shape> + <material> + [ <transform> ] + +<x_pivot> ::= x_pivot: + <target> + [ ref_point: <real3> ] # Default is [0,0,0] + +<zx_pivot> ::= zx_pivot: + <target> + [ spacing: REAL ] # in [0, INF). Default 0 + [ ref_point: <real3> ] # Default is [0,0,0] + +<target> ::= target: + anchor: <anchor-identifier> + | direction: <real3> + | position: <real3> + | <sun> + +------------------------------------- + +<shape> ::= <cuboid> + | <cylinder> + | <hemisphere> + | <hyperbol> + | <parabol> + | <parabolic-cylinder> + | <plane> + | <sphere> + | <stl> + +<cuboid> ::= cuboid: + size: <real3> # in ]0, INF]^3 + +<cylinder> ::= cylinder: + height: REAL # in ]0, INF) + radius: REAL # in ]0, INF) + [ slices: INTEGER ] # in [4, 4096]. Default is 16 + [ stacks: INTEGER ] # in [1, 4096]. Default is 1 + +<hemisphere> ::= hemisphere: + radius: REAL # in ]0, INF) + [ clip: <polyclip-list> ] + [ slices: INTEGER ] # in [4, 4096] + +<hyperbol> ::= hyperbol: + focals: <hyperboloid-focals> + clip: <polyclip-list> + [ slices: INTEGER ] # in [4, 4096] + +<parabol> ::= parabol: + focal: REAL # in ]0, INF) + clip: <polyclip-list> + [ slices: INTEGER ] # in [4, 4096] + +<parabolic-cylinder> ::= parabolic-cylinder: + focal: REAL # in ]0, INF) + clip: <polyclip-list> + [ slices: INTEGER ] # in [4, 4096] + +<plane> ::= plane: + clip: <polyclip-list> + [ slices: INTEGER ] # in [1, 4096]. Default is 1 + +<sphere> ::= sphere: + radius: REAL # in ]0, INF) + [ slices: INTEGER ] # in [4, 4096]. Default is 16 + [ stacks: INTEGER ] # in [2, 4096]. Default is slices/2 + +<stl> ::= stl: + path: PATH + +<hyperboloid-focals> ::= real: REAL # in ]0, INF) + image: REAL # in ]0, INF) + +---------------------------------------- + +<polyclip-list> ::= - <polyclip> + [ - <polyclip> ... ] + +<polyclip> ::= operation: <AND|SUB> + <contour-descriptor> + +<contour-descriptor> ::= <circle-descriptor> + | <vertices-descriptor> + +<vertices-descriptor> ::= vertices: <vertices-list> + +<circle-descriptor> ::= circle: + radius: REAL # in ]0, INF) + [ center: <real2> ] # Default is 0,0 + [ segments: INTEGER ] # in [3, 4096]. Default is 64 + +<vertices-list> ::= - <real2> + - <real2> + - <real2> + [ - <real2> ... ] + +---------------------------------------- + +<material> ::= material: + <material-descriptor> + | <double-sided-mtl> + +<double-sided-mtl> ::= front: <material-descriptor> + back: <material-descriptor> + +<material-descriptor> ::= <dielectric> + | <matte> + | <mirror> + | <thin-dielectric> + | <virtual> + +<dielectric> ::= dielectric: + medium_i: <medium-descriptor> + medium_t: <medium-descriptor> + [ <normal-map> ] + +<matte> ::= matte: + reflectivity: <mtl-data> # in [0, 1] + [ <normal-map> ] + +<mirror> ::= mirror: + reflectivity: <mtl-data> # in [0, 1] + roughness: <mtl-data> # in [0, 1] + [ <normal-map> ] + +<virtual> ::= virtual: EMPTY-STRING + +<thin-dielectric> ::= thin_dielectric: + thickness: REAL # in [0, INF) + medium_i: <medium-descriptor> + medium_t: <medium-descriptor> + [ <normal-map> ] + +<normal-map> ::= normal_map: + path: PATH + +---------------------------------------- + +<medium> ::= medium: <medium-descriptor> + +<medium-descriptor> ::= refractive_index: <mtl-data> # in ]0, INF) + absorption: <mtl-data> # in [0, INF) + +---------------------------------------- + +<entity> ::= entity: <entity-data> + +<template> ::= template: <entity-data> + +<entity-data> ::= name: STRING + [ <geometry-data> | <x_pivot> | <zx_pivot> ] + [ <anchors> ] + [ <transform> ] + [ <children> ] + +<geometry-data> ::= primary: INTEGER # in [0, 1] + <geometry> + +<children> ::= children: + - <entity-data> + [ - <entity-data> ... ] + +<anchors> ::= anchors: + - <anchor-data> + [ - <anchor-data> ... ] + +<anchor-data> ::= name: STRING + <position-descriptor> + +<position-descriptor> ::= position: <real3> + | hyperboloid_image_focals: <hyperboloid_focals> + +<entity-identifier> ::= <self|STRING>[.STRING ... ] + +<anchor-identifier> ::= <entity-identifier>.STRING + +---------------------------------------- + +<sun> ::= sun: + dni: REAL # Direct Normal Irradiance in ]0, INF) + [ <spectrum> ] # Default is the smarts295 spectrum + [ <sun-shape> ] + +<sun-shape> ::= <pillbox> | <buie> + +<buie> ::= buie: + csr: REAL # in [1e-6, 0.849] + +<pillbox> ::= pillbox: + aperture: REAL # in ]0, 90] + +---------------------------------------- + +<atmosphere> ::= atmosphere: + absorption: <mtl-data> # in [0, 1] + +---------------------------------------- + +<mtl-data> ::= REAL + | <spectrum-data-list> + +<transform> ::= transform: + translation: <real3> + rotation: <real3> + +<real2> ::= - REAL + - REAL + +<real3> ::= - REAL + - REAL + - REAL + +<spectrum> ::= spectrum: <spectrum-data-list> + +<spectrum-data-list> ::= - <spectrum-data> + [ - <spectrum-data> ... ] + +<spectrum-data> ::= wavelength: REAL # in [0, INF) + data: REAL # in [0, INF) +_______ + +SUN +--- + +The *sun* describes the source of the solar plant. Its direction is not defined +into the *solstice-input*(5) file but is provided by the *solstice*(1) command. +This allows to use the same unmodified *solstice-input*(5) file for several +simulations with different sun directions. + +The main *sun* property is its direct normal irradiance, or *dni* in W.m\^-2. +Its value is a scalar defining the direct irradiance received on a plane +perpendicular to the main sun direction. The optional *spectrum* parameter +describes the per wavelength distribution of the sun *dni*. Note that this +distribution is automatically normalized by *solstice*(1). If the *spectrum* +attribute is not defined, *solstice*(1) uses a default spectrum computed with +the SMARTS software [2] between 0.28 and 4 micro-meters. The total *dni* +(integrated over the spectral range) was set to 1000 W.m^-2. The standard +Mid-Latitude-Summer atmosphere was used with most of gases concentration set +as default (the CO2 concentration was assumed 400ppmv in the atmosphere +column). + +Even if an atmosphere is provided, the atmospheric effects from the top of the +atmosphere to ground level are not computed using the atmosphere description. +As a result, the sun description (*dni* and optional *spectrum*) is expected to +include all the atmospheric effects (sun irradiance available at ground +level). + +The *sun-shape* parameter controls the angular distribution of the sun light +intensity across the sun's disk. If not defined, the distribution is assumed to +be a dirac distribution (infinite directional source). The available sun +shapes are: + +*pillbox*:: + The *pillbox* distribution defines an uniform intensity over the sun's disk. + Its single *aperture* parameter is the sun's disk half-angle in degrees, that + is linked to the apparent size of the sun. A typical aperture is 0.2664. + +*buie*:: + The *buie* distribution, as first discribed in [3]. Its single *csr* + parameter is the ratio between the circumsolar irradiance and the sum of + the circumsolar and sun's disk irradiance. An analysis on typical *csr* + values can be found in [4]. + +ATMOSPHERE +---------- + +The *atmosphere*, when provided, describes the medium surrounding the +solar plant. Its only parameter is its absorption coefficient in m^-1, that +can either be a scalar if the *absorption* is constant over the spectrum, or +can be spectrally described. The absorption along light paths is only computed +after the first reflector, as sun description must include all the atmospheric +effects before the first reflector (see sun description for more details). + +If no atmosphere is provided, atmospheric absorption after the first reflector +is not taken into account. + +MATERIAL +-------- + +A *material* describes the properties of an interface. These properties can be +the same for the two sides of the interface or may be differentiated with a +*double-sided-mtl*. The material comportment is controlled by a +*material-descriptor* that specifies the physical properties of the interface +as well as its optional normal perturbation. Note that the physical properties +can be either scalars or spectral data. + +Material descriptors +~~~~~~~~~~~~~~~~~~~~ + +The available material descriptors are: + +*dielectric*:: +Interface between 2 dielectric media. Its *medium_i* parameter defines the +current medium, i.e. the medium the ray travels in, while *medium_t* +represents the opposite medium. Incoming rays are either specularly reflected +or refracted according to a Fresnel term computed with respect to the +refractive indices of the 2 media as: ++ +....... +Fr = 1/2 * (Rs^2 + Rp^2) +....... ++ +with Rs and Rp the reflectance for the light polarized with its electric +field perpendicular or parallel to the plane of incidence, respectively. ++ +....... +Rs = (n1 * |wi.N| - n2 * |wt.N|) / (n1 * |wi.N| + n2 * |wt.N|) +Rp = (n2 * |wi.N| - n1 * |wt.N|) / (n2 * |wi.N| + n1 * |wt.N|) +....... ++ +with n1 and n2 the indices of refraction of the incident and transmitted +media, and wi and wt the incident and transmitted direction. ++ +Be careful to ensure the media consistency in the *solstice-input*(5) file; a +ray travelling in a medium _A_ can only encounter a medium interface whose +*medium_i* attribute is _A_. Consequently, a *dielectric* material must be +defined as a double sided material whose front and back interfaces are +dielectrics with inverted media: ++ +....... +material: + front: + dielectric: + medium_i: &vacuum { refractive_index: 1, absorption: 0 } + medium_t: &glass { refractive_index: 1.5, absorption: 20 } + back: + dielectric: + medium_i: *glass + medium_t: *vacuum +....... ++ +If the media consistency is not ensured, *solstice*(1) will fail to run +simulations. Note that by default, the surrounding medium is assumed to be +the vacuum, i.e. its refractive index and its absorption are scalars whose +values are 1 and 0, respectively. If an atmosphere is defined, the refractive +index of the surrounding medium is still the scalar 1 but its absorption is +the one of the atmosphere. In other words, to reference the surrounding medium +in the *medium_i* or the *medium_t* attribute of a *dielectric* interface, one +has to define a medium whose refractive index is the scalar 1 and absorption +is either 0 or the absorption of the atmosphere if the latter is defined or +not, respectively. + +*matte*:: +Diffuse surface. Reflects the same intensity in all directions independently +of the incoming direction. + +*mirror*:: +Specular or glossy reflection whether the *roughness* parameter is 0 or not, +respectively. Glossy reflections are controlled by a microfacet BRDF with the +Beckmann normal distribution defined as: ++ +....... +D(wh) = exp(-tan^2(a) / m^2) / (PI * m^2 * cos^4(a)) +....... ++ +with a = arccos(wh.N) and m the *roughness* in ]0,1] of the interface. + +*thin-dielectric*:: +The interface is assumed to be a thin slab of a dielectric material. The +*medium_i* parameter defines the outside dielectric medium while *medium_t* +is the medium of the thin slab. Incoming rays are either specularly reflected +or transmitted (without deviation) according to a Fresnel term computed with +respect to the refractive indices of the 2 media as: ++ +....... +Fr = 1/2 * (Rs^2 + Rp^2) +....... ++ +with Rs and Rp the reflectance for the light polarized with its electric +field perpendicular or parallel to the plane of incidence, respectively. ++ +....... +Rs = (n1 * |wi.N| - n2 * |wt.N|) / (n1 * |wi.N| + n2 * |wt.N|) +Rp = (n2 * |wi.N| - n1 * |wt.N|) / (n2 * |wi.N| + n1 * |wt.N|) +....... ++ +with n1 and n2 the indices of refraction of the incident and transmitted +media, and wi and wt the incident and transmitted direction. Note that the +underlying scattering function correctly handles the multiple refraction +effects into the thin slab. ++ +Be careful to ensure the media consistency in the *solstice-input*(5) file; a +ray travelling in a medium _A_ can only encounter a medium interface whose +*medium_i* attribute is _A_. If the media consistency is not ensured, +*solstice*(1) will fail to run simulations. Note that by default, the +surrounding medium is assumed to be the vacuum, i.e. its refractive index and +its absorption are scalars whose values are 1 and 0, respectively. If an +atmosphere is defined, the refractive index of the surrounding medium is still +the scalar 1 but its absorption is the one of the atmosphere. In other words, +to reference the surrounding medium in the *medium_i* attribute of a +*thin-dielectric* interface, one has to define a medium whose refractive +index is the scalar 1 and absorption is either 0 or the absorption of the +atmosphere if the latter is defined. + +*virtual*:: +Fully transparent interface. + +Normal map +~~~~~~~~~~ + +All the material descriptors, excepted the *virtual*, provide an optional +*normal-map* attribute that defines a path toward a Portable PixMap image [5] +whose pixels store a normal expressed in the tangent space of the interface. By +default the unperturbed tangent space normal is {0,0,1}. The PPM image can +be encoded on 8 or 16-bits per component either in ASCII or binary. The +parameterization of this 2D image onto the shape surfaces depends on the type +of the shape. For the *hemisphere*, *hyperbol*, *parabol*, *plane* and +*parabolic-cylinder* shapes, the image is mapped in the {X,Y} plane. The other +shapes are not parameterized and consequently, applying a normal-mapped +material on these shapes leads to undefined behaviors. + +SHAPE +----- + +A *shape* describes a geometric model. It is defined in its local space, i.e. +in a coordinate system whose origin is proper to the shape. No space +transformation can be introduced through the declaration of a shape: it should +be transformed externally through an *object* and/or *entities*. +*solstice-input*(1) provides 2 types of shape: quadric and mesh. The former is +used to declare parametric surfaces, while the latter describes triangulated +surfaces. + +Quadric +~~~~~~~ + +A quadric shape is defined from a quadric equation and a set of 2D clipping +operations performed in their {X,Y} plane. By convention, the front side of the +quadric surface looks toward the positive Z axis. Internally, the clipped +quadric surface is discretized in a triangular mesh with respect to the +discretisation parameters of the quadric. This mesh is used by *solstice*(1) +as a "proxy" to speed up the access toward the quadric shape: the quadric +position and its associated normal are in fine computed from the quadric +equation. + +The quadric surface is parameterized in the {X,Y} plane. Its parameterization +domain is defined from the bounds of its clipped mesh in the {X,Y} plane: + + u = (x - lowerX) / (upperX-lowerX) + v = (y - lowerY) / (upperY-lowerY) + +with *u* and *v* the mapped 2D coordinates from a 3D position {*x*,*y*,*z*} +onto the quadric, and *lower*<**X**|**Y**> and *upper*<**X**|**Y**> the lower +and upper bounds of the clipped quadric along the X and Y axis. The available +quadrics are: + +*hemisphere*:: +Hemispheric shape defined along the Z axis whose minimum is positioned at +the origin. The *slices* parameter controls the number of divisions along +the Z axis. ++ +....... +x^2 + y^2 + (z-radius)^2 = radius^2 +....... + +*hyperbol*:: +Hyperbolic quadric defined along the Z axis whose minimum is positioned at +the origin. The *slices* parameter controls the discretisation of the +hyperbol. If not defined, it is automatically computed with respect to the +hyperbol curvature. ++ +....... +(x^2 + y^2) / a^2 - (z + z0 - g/2)^2 / b^2 + 1 = 0 + +a^2 = g^2(f - f^2) +b = g(f - 1/2) +z0 = |b| + g/2 +g = focals.real + focals.image +f = focals.real / g +....... + +*parabol*:: +Parabolic quadric defined along the Z axis whose minimum is positioned at the +origin. The *slices* parameter controls the discretisation of the parabol. If +not defined, it is automatically computed with respect to the parabol +curvature. ++ +....... +x^2 + y^2 - 4 * focal * z = 0 +....... + +*parabolic-cylinder*:: +Parabolic cylinder oriented along the Z axis whose main axis is along the X +axis and minimum is positioned at the origin. The *slices* parameter +controls the discretisation of the parabolic cylinder. If not defined, it is +automatically computed with respect to the parabolic cylinder curvature. ++ +....... +y^2 - 4 * focal * z = 0 +....... + +*plane*:: +Plane whose normal points along the positive Z axis. The *slices* attribute +controls the discretisation of the clipped plane. + +Clipping +~~~~~~~~ + +A clipping operation, or *polyclip*, is used to remove some parts of the +quadric surface. It is defined by a 2D *contour-descriptor* expressed in the +{X,Y} plane and a clipping *operation*. The *AND* and *SUB* clip operands, +remove the quadric surface that intersects or does not intersect the +*contour-descriptor*, respectively. The available *countour-descriptors* are: + +*circle-descriptor*:: +Circular contour whose size is defined by the *radius* parameter. Actually, +*solstice*(1) discretized the circular contour with respect to the *segments* +attribute that defines the overall number of segments used to approximate the +circle. + +*vertices-descriptor*:: +Polygonal contour described by a list of 2D vertices. The polygon edges are +defined by connecting each vertex to its previous one. To ensure that the +polygon is closed, an additional edge is automatically created between the +first and the last vertex. Note that *solstice*(1) assumes that the defined +polygon does not overlap itself, i.e. their non consecutive edges are not +intersecting. + +The *clip* parameter of the quadrics lists a set of the aforementioned 2D +*polyclips*. Each of these clipping operations is successively applied on the +remaining quadric surface, in the order on which they are declared. For +instance, the following example uses 5 clipping operations on a plane to build +a rectangle with a circular hole at each of its corner. The first *polyclip* +limits the infinite plane to a rectangle centered in 0 whose size in X and Y is +8 and 4, respectively. The 4 subsequent *polyclips* drill the +rectangle near of its corner with circles whose radius is 0.5: + +....... +plane: + clip: + - {operation: AND, vertices: [[-4,-2],[-4,2],[4,2],[4,-2]]} + - {operation: SUB, circle: {radius: 0.5, center: [-3,-1]}} + - {operation: SUB, circle: {radius: 0.5, center: [-3, 1]}} + - {operation: SUB, circle: {radius: 0.5, center: [ 3,-1]}} + - {operation: SUB, circle: {radius: 0.5, center: [ 3, 1]}} +....... + +Triangular mesh +~~~~~~~~~~~~~~~ + +Triangular meshes are generated by *solstice*(1) from a shape description or +loaded from a CAO file. Their normals are defined per triangle and are thus +discontinuous even for smooth shapes as spheres. The triangular meshes are not +parameterized, i.e. they do not provide a mapping from a 3D position onto its +surface to a 2D coordinates. Applying a normal-mapped material to a triangular +mesh will thus produce undefined behaviors. + +The available triangular meshes are: + +*cuboid*:: + Axis aligned cuboid centered in 0 whose corner positions and dimensions along + the 3 axis are defined by the *size* parameter. The front side of the cuboid + surface looks outside the cuboid. + +*cylinder*:: + Cylinder centered in 0 whose *height* is along the positive Z axis. The top + and the bottom of the cylinder is capped. The *stacks* and *slices* + parameters control the discretisation, i.e. the number of divisions, along or + around the Z axis, respectively. The front side of the cylinder surface looks + outside the cylinder. + +*sphere*:: + Triangulated sphere centered in 0. The *stacks* and *slices* parameters + control the discretisation, i.e. the number of divisions, along or around the + Z axis, respectively. The front side of the sphere surface looks outside the + sphere. + +*stl*:: + Path toward an external mesh file defined with respect to the **ST**ereo + **L**ithography file format. The front side of the loaded triangles is + defined with respect to their vertex ordering into the STL file: a triangle + is front facing when their vertices are clock wise ordered. + +ENTITY +------ + +An *entity* is used to declare and position shapes into the solar plant. +Actually, the entity is the only item that effectively spawns a *geometry* into +the solar plant: if a geometry is declared but not referenced by an entity, it +is ignored by *solstice*(1). An entity is a hierarchical data structure that +can have child entities whose transformation is relative to their parent. If +not defined, the *transform* parameter of an entity is assumed to be the +identity, i.e. its *rotation* and *translation* are nulls. + +Each entity has a *name* which must be unique per hierarchy level: 2 root +entities (i.e. entities without parent) cannot have the same name as well as +the children of a same parent entity. A child entity is identified into the +solar plant by successively concatenating, with the \'.' character, the name of +its ancestors with its own name. This naming convention is used in the +*solstice-receiver*(5) format to define the entities to track during the +*solstice*(1) computations. For instance, in the following example, the +*entity-identifier* of the child entity named *level2* is +*level0.level1.level2*: +....... +entity: + name: level0 + child: + - name: level1 + child: + - name: level2 +....... + +An entity encapsulates either a *geometry* or a *pivot*. The former is a +collection of *objects*, i.e. *shapes* with their associated *material* and an +optional *transformation*. The latter is used to control the dynamic +positioning of the child entities with respect to some constraints defined by +the pivot type, and the sun directions submitted by *solstice*(1). Each entity +can also have a list of *anchors*. An anchor is used to define a position +relative to the entity into which it is declared. + +For a geometric entity one has to define if the encapsulated geometry is a +*primary* geometry, i.e. a geometry directly lit by the sun and used to +concentrate the solar flux (e.g. a primary mirror). One can define all the +solar plant geometric entities as primaries but a well designed solar plant +with correctly tagged primary geometries will drastically improve the +convergence speed of the *solstice*(1) simulations. + +Template +~~~~~~~~ + +A *template* is a first level entity with no existence into the solar plant. It +is used to pre-declare an entity hierarchy that can then be instantiated +several times in the solar plant by referencing it through common entities with +YAML data tagging. In the following example, the templated entity *my-template* +is instantiated 3 times into the scene: +....... +- template: &my-template + name: bar + primary: 1 + geometry: ... +- entity: + name: foo0 + transform: {translation: [-10.5, 0, 0]} + children: [*my-template] +- entity: + name: foo1 + transform: {translation: [0, 0, 0]} + children: [*my-template] +- entity: + name: foo2 + transform: {translation: [10.5, 0, 0]} + children: [*my-template] +....... + +Pivot +~~~~~ + +A *pivot* is a special kind of node that can be used in the tree data +structure describing an entity to automatically point its child geometry +according to the sun position and to the pivot parameters. It is supposed (but +not mandatory) that the children of a pivot includes a reflector, that, +once pivoted, will reflect the sun light towards a *target*. You should +note that a pivot cannot be the child of another pivot. + +The most noticeable pivot parameter is its *target*. Four different types of +targets are available: + +*position*:: + Define the target as being an absolute point in world coordinates. + +*anchor*:: + Define the target as being a position relative to an entity (see the + *anchor* section). + +*sun*:: + Define the target as being the center of the sun. + +*direction*:: + The pivot reflects light in the given direction, specified in world + coordinates. + +Pivots can also have a *ref_point* optional parameter defining a 3D point in +the coordinate system the pivot children that will be used by the pointing algorithm. +If not provided, it is set to the origin. + +Two different flavours of *pivots* are available: *x_pivot* and *zx_pivot*, +each with its own set of parameters and behaviour. + +*x_pivot*:: + Pivot with a single rotation axis: the +X axis in its local coordinate + system. It has a *target* and can have a *ref_point*. Its pointing algorithm + considers an incoming ray of light from the center of the sun and rotates + its children so that a specular reflection at *ref_point* using +Z as + local normal will hit the target point of the pivot, or will have the + specified direction (depending of the kind of target). + +*zx_pivot*:: + Pivot with two rotation axis: the +Z axis in its local coordinate system, + then the +X axis in the coordinate system resulting of the Z rotation. + It has a *target* and can have a *ref_point* and a *spacing* that defines + the translation along the +Y axis after the first rotation. If not + defined, *spacing* is 0. The *zx_pivot* pointing algorithm considers an + incoming ray of light from the center of the sun and rotates the pivot's + children of the pivot so that a specular reflection at *ref_point* using + +Y as local normal will hit the target point of the pivot, or will have + the specified direction (depending of the kind of target). + +Anchor +~~~~~~ + +An *anchor* defines a relative position into the entity hierarchy. They are +particularly useful for pivots and hyperbolic shapes that may have to reference +a position relative to an entity whose transformations may also depends of its +ancestor. An anchor has a *name* that must be unique for the whole sets of per +entity anchors. An anchor is identified into the solar plant by concatenating, +with the \'.' character, its name to the *entity-identifier* of the entity into +which it is declared. For instance, in the following example, the +*anchor-identifier* of the anchor named *anchor0* is *level0.level1.anchor0*: +....... +entity: + name: level0 + child: + - name: level1 + anchor: + - {name: anchor0, position: [0, 0, 0]} + - {name: anchor1, position: [1, 2, 3]} +....... + +In some situations, the *anchor-identifier* cannot be fully determined. Let a +templated entity with a descendant referencing an anchor of one of its +ancestors. On its declaration, the template is still not instantiated through a +parent entity and consequently the name of the root entity is unknown. +Moreover, the name of the root entity cannot be fixed since it changes for each +instance of the template. To handle these cases, the *self* reserved keyword +allows to reference the unknown root entity of the currently declared +hierarchy. In the following example, the entities *entity0.level0.level1* and +*entity1.level0.level1* encapsulate a pivot that references the anchor +*anchor0* defined in their respective parent *entity0.level0* and +*entity1.level0*: +....... +- template: &my-template + name: level0 + anchor: [{name: anchor0, position: [1, 2, 3]}] + child: + - name: level1 + pivot: + x_pivot: + ref_point: {0, 0, 0} + target: {anchor: self.level0.anchor0} + +- entity: {name: entity0, child: [*my-template]} +- entity: {name: entity1, child: [*my-template]} +....... + +Transform +~~~~~~~~~ + +A *transform* is used to move an *object* or an *entity* in space. The +*rotation* parameter list 3 angles in degrees defining the rotation to perform +around the X, Y and Z axis. The *translation* attribute describes the offsets +to apply along the X, Y and Z axis. Let the local repair *p* of an object, *p* +is transformed in *p'* with respect to its associated *transform* as follow: + + p' = Rx * Ry * Rz * (T + p) + +with *T* the translation vector and *Rx*, *Ry* and *Rz* the rotation matrices +around the X, Y and Z axis defined as: + + | 1 0 0 | | cY 0 sY | | cZ -sZ 0 | + Rx = | 0 cX -sX |; Ry = | 0 1 0 |; Rz = | sZ cZ 0 | + | 0 sX cX | |-sY 0 cY | | 0 0 1 | + +where *c*<**X**|**Y**|**Z**> and *s*<**X**|**Y**|**Z**> are the cosine and the +sinus, respectively, of the rotation angles around the X, Y and Z axis. + +EXAMPLES +-------- + +Declare 2 entities and a point source sun. The first entity is a purely +specular square of size 10, whose center is at the origin. The second entity +is a purely transparent square used as a receiver of the solar flux. Its size +is 1 and its center is positioned at {0,0,2}: +....... +- sun: {dni: 1000} + +- entity: + name: reflector + primary: 1 + geometry: + - material: + mirror: + reflectivity: 1 + roughness: 0 + plane: + clip: + - operation: AND + vertices: + - [-5.0,-5.0] + - [-5.0, 5.0] + - [ 5.0, 5.0] + - [ 5.0,-5.0] + +- entity: + name: receiver + primary: 0 + transform: + translation: [0, 0, 2] + geometry: + - material: + virtual: # No attrib + plane: + clip: + - operation: AND + vertices: + - [-0.5,-0.5] + - [-0.5, 0.5] + - [ 0.5, 0.5] + - [ 0.5,-0.5] +....... + +Define a circular diffuse reflector surrounded by a virtual sphere and a +pillbox-shaped sun whose aperture is 0.1 degree. Use anchors and tags of the +YAML format to reference into the entities a pre-declared geometry. Rely on +the YAML compact notation to reduce the number of lines required to describe +the scene: +....... +- sun: {dni: 1000, pillbox: {aperture: 0.1}} + +- geometry: &small-circle + - material: {matte: {reflectivity: 1}} + plane: {clip: [{operation: AND, circle: {radius: 0.5}}]} + +- geometry: &big-sphere + - material: {?virtual} + sphere: {radius: 2, slices: 128} + +- entity: {name: reflector, primary: 1, geometry: *small-circle} +- entity: {name: receiver, primary: 0, geometry: *big-sphere} +....... + +Declare 2 parabolic reflectors from a *templated* parabola whose orientation is +controlled by a *zx_pivot*. This pivot ensures that the reflector points toward +the receiver, independently of its position, by targeting an *anchor* whose +position is defined relatively to the receiver: +....... +- sun: {dni: 1000} + +- entity: # Receiver + name: square_receiver + primary: 0 + transform: { rotation: [0,90,0], translation: [100,0,10] } + anchors: [{name: anchor0, position: [0,0,0]}] + geometry: + - material: {?virtual} + plane: + clip: + - operation: AND + vertices: [[-.5,-.5],[-.5,.5],[.5,.5],[.5,-.5]] + +- template: &self_oriented_parabol # Reflector + name: pivot + transform: {translation: [0, 0, 4], rotation: [0, 0, 90]} + zx_pivot: {target: {anchor: square_receiver.anchor0}} + children: + - name: parabol + transform: {rotation: [-90, 0, 0]} + primary: 1 + geometry: + - material: {mirror: {reflectivity: 1, roughness: 0}} + parabol: + focal: 100 + clip: + - operation: AND + vertices: [[-5,-5],[-5,5],[5,5],[5,-5]] + +# Instantiate the reflector template +- entity: + name: reflector1 + transform: {translation: [0,0,0]} + children: [*self_oriented_parabol] +- entity: + name: reflector2 + transform: {translation: [10,43.6,0]} + children: [*self_oriented_parabol] +....... + +Declare a solar furnace with 9 heliostats instantiated from the same +*template*. Their position is controlled by a *zx_pivot* to ensure that the +incoming sun rays are reflected toward the negative X axis. Reflected rays are +then concentrated by a parabola toward a purely absorptive receiver. The +heliostats and the parabola share the same material: the front faces are +purely specular while the back faces are diffuse: +....... +- sun: {dni: 1000} + +- material: &specular + front: {mirror: {reflectivity: 1, roughness: 0}} + back: {matte: {reflectivity: 1}} + +- template: &H # Template of an heliostat + name: heliostat + transform: {translation: [0,0,5.5]} + zx_pivot: {target: {direction: [-1,0,0]}} + children: + - name: reflector + transform: {rotation: [-90,0,0]} + primary: 1 + geometry: + - material: *specular + plane: + clip: [{operation: AND, vertices: [[-5,-5],[-5,5],[5,5],[5,-5]]}] + +- entity: # Receiver entity + name: receiver + primary: 0 + transform: {translation: [18,0,20], rotation: [0,90,0]} + geometry: + - material: {matte: {reflectivity: 0}} + plane: + clip: + - operation: AND + vertices: [[-.5,-.5],[-.5,.5],[.5,.5],[.5,-.5]] + +- entity: # Great parabola + name: parabola + primary: 0 + transform: {translation: [0,0,20], rotation: [0,90,90]} + geometry: + - material: *specular + parabol: + focal: 18 + clip: [{operation: AND, vertices: [[-30,-20],[-30,20],[30,20],[30,-20]]}] + +# Instantiate the heliostat template +- entity: {name: H1, children: [*H], transform: {translation: [40,-20, 0]}} +- entity: {name: H2, children: [*H], transform: {translation: [40, 0, 0]}} +- entity: {name: H3, children: [*H], transform: {translation: [40, 20, 0]}} +- entity: {name: H4, children: [*H], transform: {translation: [60,-20,10]}} +- entity: {name: H5, children: [*H], transform: {translation: [60, 0,10]}} +- entity: {name: H6, children: [*H], transform: {translation: [60, 20,10]}} +- entity: {name: H7, children: [*H], transform: {translation: [80,-20,20]}} +- entity: {name: H8, children: [*H], transform: {translation: [80, 0, 20]}} +- entity: {name: H9, children: [*H], transform: {translation: [80, 20,20]}} +....... + +This example illustrates the use of quadrics and refractive materials: in this +example, three partial *parabols* with various focal distances and positions +concentrate incoming radiation at a common focal position. But a *hyperbol* is +located between the parabols and their common focal position, which is also +one of the two focals of the hyperbol. Radiation is therefore redirected to +the second focal of the hyperbol, where the square target is located. Finally, +a *cuboid* using a glass material is located between the hyperbol and the +target. In this example, a small fraction of incoming power is absorbed by the +target. The rest is either missing the target, absorbed or refracted by the +glass. Furthermore, this example illustrates the use of a *spectrum* for +*refractive index* and *absorption* by various *media* (air and glass). +....... +# Spectra +- spectrum: &solar_spectrum + - {wavelength: 0.3, data: 1.0} + - {wavelength: 0.4, data: 2.0} + - {wavelength: 0.5, data: 0.5} + - {wavelength: 0.6, data: 3.5} + - {wavelength: 0.7, data: 1.5} + - {wavelength: 0.8, data: 0.8} + +- spectrum: &air_kabs + - {wavelength: 0.3, data: 1.0e-4} + - {wavelength: 0.4, data: 1.0e-5} + - {wavelength: 0.5, data: 2.0e-5} + - {wavelength: 0.6, data: 2.0e-4} + - {wavelength: 0.7, data: 3.0e-5} + - {wavelength: 0.8, data: 1.0e-4} + +- spectrum: &glass_kabs + - {wavelength: 0.3, data: 1.0e-2} + - {wavelength: 0.4, data: 1.0e-3} + - {wavelength: 0.5, data: 2.0e-3} + - {wavelength: 0.6, data: 2.0e-2} + - {wavelength: 0.7, data: 3.0e-3} + - {wavelength: 0.8, data: 1.0e-3} + +- spectrum: &glass_ref_index + - {wavelength: 0.30, data: 1.40} + - {wavelength: 0.40, data: 1.39} + - {wavelength: 0.50, data: 1.37} + - {wavelength: 0.60, data: 1.34} + - {wavelength: 0.70, data: 1.30} + - {wavelength: 0.80, data: 1.25} + +# Media +- medium: &air_medium + refractive_index: 1 + absorption: *air_kabs + +- medium: &glass_medium + refractive_index: *glass_ref_index + absorption: *glass_kabs + +# Sun & atmosphere +- sun: {dni: 1, spectrum: *solar_spectrum} +- atmosphere: {absorption: *air_kabs} + +# Materials +- material: &specular {mirror: {reflectivity: 1, roughness: 0}} +- material: &black {matte: {reflectivity: 0}} +- material: &glass + front: {dielectric: {medium_i: *air_medium, medium_t: *glass_medium}} + back: {dielectric: {medium_i: *glass_medium, medium_t: *air_medium}} + +# Pimary reflectors +- entity: + name: "primary_reflector1" + primary: 1 + transform: {translation: [0, 0, -2.0]} + geometry: + - material: *specular + parabol: + focal: 12 + clip: + - {operation: AND, circle: {radius: 10}} + - {operation: SUB, circle: {radius: 5}} + +- entity: + name: "primary_reflector2" + primary: 1 + transform: {translation: [0, 0, -4]} + geometry: + - material: *specular + parabol: + focal: 14 + clip: + - {operation: AND, circle: {radius: 15}} + - {operation: SUB, circle: {radius: 10}} + +- entity: + name: "primary_reflector3" + primary: 1 + transform: {translation: [0, 0, -6]} + geometry: + - material: *specular + parabol: + focal: 16 + clip: + - {operation: AND, circle: {radius: 20}} + - {operation: SUB, circle: {radius: 15}} + +# Secondary reflector +- entity: + name: "secondary_reflector" + primary: 0 + transform: {translation: [0, 0, 6]} + geometry: + - material: *specular + hyperbol: + focals: {real: 16.0, image: 4} + clip: [{operation: AND, circle: {radius: 5}}] + +# Glass box +- entity: + name: "glass_slide" + primary: 0 # The entity is not sampled as a primary reflector + geometry: + - material: *glass + cuboid: {size: [10,10,0.5]} + transform: {translation: [0, 0, 0.25]} + +# Receiver +- entity: + name: "square_receiver" + primary: 0 # The entity is not sampled as a primary reflector + transform: {translation: [0, 0, -10] } + geometry: + - material: *black + plane: + clip: + - operation: AND + vertices: [[-0.5,-0.5],[-0.5,0.5],[0.5,0.5],[0.5,-0.5]] +....... + + +NOTES +----- +1. YAML Ain't Markup Language - <http://yaml.org> +2. SMARTS, Simple Model of the Atmospheric Radiative Transfer of Sunshine - + <http://www.nrel.gov/rredc/smarts/> +3. D. Buie, A.G. Monger, C.J. Dey. "Sunshape distributions for + terrestrial solar simulations". Solar Energy, 2003, 74, pp. 113-122. +4. D. Buie, C.J. Dey, S. Bosi. "The effective size of the solar cone for + solar concentrating systems". Solar Energy, 2003, 74, pp. 417-427. +5. Portable PixMap - <http://netpbm.sourceforge.net/doc/ppm.html> + +SEE ALSO +-------- +*solstice*(1), *solstice-receiver*(5) diff --git a/doc/solstice-man.css b/doc/solstice-man.css @@ -0,0 +1,87 @@ +/* Copyright (C) CNRS 2016-2017 + * + * This is free style sheet: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This CSS is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see http://www.gnu.org/licenses/. */ + +body.manpage { + font-family:monospace; + font-size:2ex; + text-align: justify; + max-width: 55em; + margin: 1em; + background: #ffffff +} + +body.manpage .monospaced, .literalblock { + margin: 2em; + color: #636261 +} + +body.manpage em { + color: #660000 +} + +body.manpage div.verseblock > pre.content { + font-family: inherit; +} + +body.manpage h1 { + padding-bottom: 0.5em; +} +body.manpage h2 { + border-style: none; +} +body.manpage div.sectionbody { + margin-left: 3em; +} + +body.manpage #footer { display: none; } + +body.manpage div#toctitle { display: none; } + +body.manpage div#toc { + display.block ! important; + position:fixed; + top:0; + left:60em; + height:100%; + width: 100%; + padding:3em 0 0 0; + border-left:1px solid #dbdbdb; + background: #eeeeee +} + +body.manpage div#toc a, div#toc a:link, div#toc a:visited { + margin:0; + padding-left: 2em; + color:#999999; + text-decoration:none; +} + +body.manpage div.toclevel1 { + line-height: 1.5em; +} + +body.manpage div.toclevel2 { + margin-left: 2em; + +} + +body.manpage div#toc a:hover { + color:#666666; +} + +@media print { + body.manpage div#toc { display: none; } +} + diff --git a/doc/solstice-output.5.txt b/doc/solstice-output.5.txt @@ -0,0 +1,488 @@ +// Copyright (C) CNRS 2016-2017 +// +// This is free documentation: 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 manual is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see <http://www.gnu.org/licenses/>. +:toc: + +solstice-output(5) +================== + +NAME +---- +solstice-output - output format of solstice(1) results + +DESCRIPTION +----------- +The *solstice-output* describes the output format of the *solstice*(1) program. +All the data generated by a *solstice*(1) invocation are written in a single +file or on the standard output whether an _output_ file is defined through the +*-o* option or not, respectively. Note that submitting several sun directions +to *solstice*(1), through the *-D* option, will produce as many outputs as sun +directions. In other words, invoking *solstice*(1) with _N_ sun directions +looks like calling *solstice*(1) _N_ times and concatenating their associated +output. + +The type of the data that are generated depends on the mode in which +*solstice*(1) is invoked. By default, *solstice*(1) evaluates the power +collected by the submitted solar plant. When invoked with the *-g* option, +*solstice*(1) converts the solar plant geometries in a list of CAO files. The +*-p* option is used to track the sampled radiative paths while, finally, the +*-r* option allows to render an image of the solar facility. + +GRAMMAR +------- +The output values are mainly ASCII data formatted line by line. By convention, +in the following grammar the line data are listed between quote marks. The +grammar may use new lines for formatting constraints, but data are actually on +the same line while a closed quote mark is not defined. + +[verse] +_______ +<output> ::= <simulation-output> + | <dump-geometry-output> # -g option + | <dump-radiative-paths-output> # -p option + | <rendering-output> # -r option + +<simulation-output> ::= <sun-direction> + <counts> + <global> + [ <receivers-list> ] + [ <primaries-list> ] + [ <rcvXprims-list> ] + [ <receiver-maps> ] + [ <simulation-output> ... ] + +<dump-geometry-output> + ::= <sun-direction> + <geometry-data> + [ <dump-geometry-output> ... ] + +<dump-radiative-paths-output> + ::= <sun-direction> + VTK-RADIATIVE-PATHS + [ <dump-radiative-paths-output> ... ] + +<rendering-output> ::= <sun-direction> + PPM-FILE # ASCII PPM with 8-bits per component [1] + [ <rendering-output> ... ] + +------------------------------------- + +<sun-direction> ::= "#--- Sun direction: <azimuth> <elevation> (<real3>)" + +<counts> ::= "<#globals> <#receivers> <#primaries> + <#samples> <#failed>" + +<#globals> ::= 7 +<#receivers> ::= INTEGER # in [0, INF) +<#primaries> ::= INTEGER # in [0, INF) +<#samples> ::= INTEGER # in [0, INF) +<#failed> ::= INTEGER # in [0, INF) + +<global> ::= <potential-irradiance> + <absorbed-irradiance> + <cos-factor> + <shadow-loss> + <missing-loss> + <reflectivity-loss> + <absorptivity-loss> + +------------------------------------- + +<receivers-list> ::= <receiver> + [ <receiver> ... ] + +<receiver> ::= "<receiver-name> <receiver-id> <area> + <front> <back>" + +<receiver-name> ::= <entity-identifier> + +<receiver-id> ::= INTEGER + +<front> ::= <side> +<back> ::= <side> + +<side> ::= "<absorbed-irradiance> <irradiance> + <reflectivity-loss> <absorptivity-loss> + <efficiency>" + +------------------------------------- + +<primaries-list> ::= <primary> + [ <primary> ... ] + +<primary> ::= "<primary-name> <primary-id> <area> <#samples> + <cos-factor> <shadow-loss>" + +<primary-name> ::= <entity-identifier> + +<primary-id> ::= INTEGER + +------------------------------------- + +<rcvXprims-list> ::= <rcvXprim> + [ <rcvXprim> ... ] + +<rcvXprim> ::= "<receiver-id> <primary-id> + <rcvXprim-front> <rcvXprim-back>" + +<rcvXprim-front> ::= <rcvXprim-side> +<rcvXprim-back> ::= <rcvXprim-side> + +<rcvXprim-side> ::= "<absorbed-irradiance> <irradiance> + <reflectivity-loss> <absorptivity-loss>" + +------------------------------------- + +<receiver-maps> ::= VTK-RECEIVER-MAP + [ <receiver-maps> ... ] + +<geometry-data> ::= OBJ-FILE + [ --- + <geometry-data> ... ] + +------------------------------------- + +<area> ::= REAL # in ]0, INF) + +<real3> ::= REAL REAL REAL + +<azimuth> ::= REAL # Degrees in [0, 360[ +<elevation> ::= REAL # Degrees in [0, 90] + +<potential-irradiance>::= <estimate> +<absorbed-irradiance> ::= <estimate> +<absorptivity-loss> ::= <estimate> +<cos-factor> ::= <estimate> +<irradiance> ::= <estimate> +<missing-loss> ::= <estimate> +<reflectivity-loss> ::= <estimate> +<shadow-loss> ::= <estimate> + +<estimate> ::= <expected-value> <standard-error> +<expected-value> ::= REAL +<standard-error> ::= REAL # in [0, INF) + +<entity-identifier> # Defined in *solstice-input*(1) +_______ + +SIMULATION +---------- + +A *simulation-output* begins with two header lines. The first one reports the +sun direction used in the simulation (azimuth and elevation angles, in +degrees), and the second one lists the numbers of global, per receiver and per +primary results as well as the overall number of Monte-Carlo experiments used +by the simulation and the number of experiments that failed due to unforeseen +errors as numerical imprecisions. As soon as the number of failed experiments +reaches 1% of the required number of Monte-Carlo experiments, the code exits +with a "Error in integrating the solar flux" message, and the validity of +subsequent results is questionable: estimates are produced using the number of +Monte-Carlo experiments that have been successful, which is necessarily smaller +than the required number of experiments. + +Global results +~~~~~~~~~~~~~~ + +After the 2 header lines, the output includes various *global* result lines, +the exact number of lines being part of the headers. Currently this number is +7. Each global result is a pair of real numbers: the expected value and its +standard error. The global results are, in this order: + +- *potential-irradiance*: maximum irradiance that all the primary + geometries could intercept if properly oriented; +- *absorbed-irradiance*: absorbed part of the irradiance reaching any + receiver geometry. At most equal to potential irradiance; +- *cos-factor*: fraction of incoming irradiance not intercepted by the + primary geometries due to their orientation; +- *shadow-loss*: irradiance lost before reaching primary geometries due to the + shadow of another geometry; +- *missing-loss*: irradiance that reaches a primary geometry, but not + absorbed by a receiver; this irradiance could have been blocked along its + path, can have missed the receivers, or can have reach a receiver but + without being absorbed; +- *reflectivity-loss*: additional irradiance that could have been absorbed + by receivers if reflections had occurred on materials with reflectivity 1.0; +- *absorptivity-loss*: irradiance that could have been absorbed by + receivers if atmospheric absorption had not been taken into account. + +Per receiver results +~~~~~~~~~~~~~~~~~~~~ + +After the global results, the output includes various per-receiver lines, one +line per receiver, the exact number of lines being part of the headers. Each +line contains the following data: + +- *receiver-name*: name of the receiver, i.e. *entity-identifier* of the + entity in which the receiving geometry is defined (see the + *solstice-input*(5) format); +- *receiver-id*: unique integer identifying the receiver; +- *area*: area of the receiver; +- *front*: estimated results for the front side of the receiver; +- *back*: estimated results for the back side of the receiver. + +The estimates of the *front* and *back* sides are listed bellow. Note that +each of the following estimates is actually a pair of real numbers: the +expected value and its standard error. + +- *absorbed-irradiance*: irradiance absorbed by the receiver side; +- *irradiance*: irradiance that reaches the receiver side; +- *reflectivity-loss*: irradiance that could have been absorbed by the + receiver side if reflections had occurred on materials with reflectivity 1.0; +- *absorptivity-loss*: irradiance that could have been absorbed by the + receiver side if atmospheric absorption had not been taken into account; +- *efficiency*: fraction of incoming irradiance absorbed by the receiver side. + +Both *front* and *back* side estimates are output, even if the receiver has +only a single receiving side. In this case, the results of the non-receiving +side are meaningless (invalid -1 value). + +Per primary results +~~~~~~~~~~~~~~~~~~~ + +After the per-receiver results, the output includes various per-primary result +lines, one line per primary geometry, the exact number of lines being part of +the headers. Each line contains: + +- *primary-name*: name of the primary geometry, i.e. *entity-identifier* of + the entity in in which the primary geometry is defined (see the + *solstice-input*(5) format); +- *primary-id*: unique integer identifying the primary geometry; +- *area*: area of the primary geometry; +- *#sample*: number of Monte-Carlo experiments sampled on the primary + geometry; +- *cos-factor*: expected value and standard error of the fraction of incoming + irradiance not intercepted by the primary geometry due to its orientation; +- *shadow-loss*: expected value and standard error of the irradiance lost + before reaching the primary geometry due to the shadow of another geometry. + +Per receiver and per primary results +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +After the per-primary results, the output includes various result lines, each +describing the contribution of a primary geometry to a given receiver. The +total number of such lines is the number of receivers times the number of +primary geometries. Each line contains: + +- *receiver-id*: identifier of the involved receiver; +- *primary-id*: identifier of the involved primary geometry; +- *rcvXprim-front*: estimated results for the receiver front side; +- *rcvXprim-back*: estimated results for the receiver back side; + +The estimated values of *rcvXprim-front* and *rcvXprim-back* are listed +bellow. Each of these estimates is actually a pair of real numbers: the +expected value and its standard error. + +- *absorbed-irradiance*: irradiance absorbed by the receiver side coming + from the primary geometry; +- *irradiance*: irradiance reaching the receiver side coming from the primary + geometry; +- *reflectivity-loss*: irradiance that could have been absorbed by the + receiver side coming from the primary geometry if reflections had occurred + on materials with reflectivity 1.0; +- *absorptivity-loss*: irradiance that could have been absorbed by + the receiver side coming from the primary geometry if atmospheric + absorption had not been taken into account. + +Both front and back side estimates are output, even if the receiver has only a +single receiving side. In this case, the results of the non-receiving side are +meaningless (invalid -1 value). + +Receiver map +~~~~~~~~~~~~ + +A receiver defined in the submitted *solstice-receiver*(5) file, can have a +per-primitive irradiance estimate if its *per_primitive* flag is active. In +this case, *solstice*(1) generates a *receiver-map* that is actually an ASCII +VTK file [2] that stores the triangular mesh of the receiver and, for each +triangle, the estimate of its associated irradiance. The "definition" of the +receiver map is thus controlled by the discretisation of the receiver's shape, +as described in the *solstice-input*(5) file. Note that to obtain a good +estimate of the per-triangle irradiance, one have to ensure that the number +of per-triangle experiments is sufficient regarding the targeted accuracy. +Since only a small fraction of the overall sampled radiative paths reach a +given triangle, the total number of experiments required through the *-n* +option of *solstice*(1) should be increased significantly, as 1 or 2 order of +magnitude. + +If only the front or the back side of the receiver is active, then only one set +of per triangle irradiance estimate is written. If the *side* attribute of +the receiver is set to *FRONT_AND_BACK*, the irradiance estimate for the +front facing triangles are written before to the estimate of the back facing +ones. The following grammar gives a brief description of the formatting of a +*VTK-RECEIVER-MAP*. Please refer to the VTK format specification [2] for more +informations on the VTK file format. + +[verse] +_______ +VTK-RECEIVER-MAP ::= # vtk DataFile Version 2.0 + <receiver-name> + ASCII + DATASET POLYDATA + POINTS <#vertices> float + <map-vertices> + POLYGONS <#triangles> <#triangles*4> + <map-triangles> + CELL_DATA <#triangles> + <map-triangle-data> + +<map-vertices> ::= <real3> + [ <real3> ... ] # up to <#vertices> + +<map-triangles> ::= 3 <triangle-indices> + [ 3 <triangle-indices> ... ] # up to <#triangles> + +<map-triangle-data> ::= <map-front-data> + | <map-back-data> + | <map-front-data> <map-back-data> + +<map-front-data> ::= <map-side-data> +<map-back-data> ::= <map-side-data> + +<map-side-data> ::= CELL_DATA <#triangles> + SCALARS <side-name> float 2 + LOOKUP_TABLE default + <irradiance> + [ <irradiance> ... ] + +<map-side-name> ::= Front_faces | Back_faces + +<#triangles> ::= INTEGER +<#vertices> ::= INTEGER +<triangle-indices> ::= INTEGER INTEGER INTEGER +_______ + +DUMP GEOMETRY +------------- + +A *dump-geometry-output* is generated when *solstice*(1) is invoked with the +*-g* option. In this mode, for each submitted sun direction, *solstice*(1) +converts the geometry of the submitted *solstice-input*(5) file in triangular +meshes that are then written to the output with respect to the format provided +by the *format* parameter of the *-g* option. The only format currently +supported by *solstice*(1) is the Alias Wavefront OBJ [3] format. With no more +sub-option, *solstice*(1) will thus generate one OBJ file containing the whole +mesh of the solar plant. However, the *split* parameter of the *-g* option +allows to generate several OBJ files: one description is generated per +*geometry* or per *object*, as defined in the *solstice-input*(5) format, +whether the *split* sub-option is set to *geometry* or *object*. In this +situation, each OBJ description is followed by a line with 3 minus characters +in order to identify the end of the current OBJ. + +Independently of the *split* strategy, each *solstice-input*(1) geometry is an +OBJ group whose name is the *entity-identifier* of the entity in which it is +encapsulated. Finally, the *dump-geometry-output* uses the *usemtl* directive +of the OBJ format to associate to a mesh the name of its material type. The +following grammar succinctly describes the formatting of an *OBJ-FILE*. Please +refer to the OBJ format specification [3] for more informations on the OBJ file +format. + +[verse] +_______ +OBJ-FILE ::= g <entity-identifier> + <obj-mesh> + [ <obj-mesh> ... ] + +<obj-mesh> ::= usemtl <material-type> + <obj-vertices> + <obj-faces> + +<obj-vertices> ::= v <real3> + [ v <real3> ... ] + +<obj-indices> ::= f <triangle-indices> + [ f <triangle-indices> ... ] + +<material-type> ::= dielectric + | matte + | mirror + | thin_dielectric + | virtual +_______ + +DUMP RADIATIVE PATHS +-------------------- + +For each sun direction, the *dump-radiative-paths-output* lists the geometric +data of the radiative paths sampled during a simulation. Each path is colored +with respect to its trajectory: the path is blue or yellow whether it reaches +or not a receiver, respectively. A path can be red if its first segment, i.e. +the ray starting from the sun toward a primary geometry, is occluded by a non +virtual object. The following grammar describes the formatting of a +*VTK-RADIATIVE-PATHS* file. Refer to the VTK format specification [2] for more +informations on the VTK file format. + +[verse] +_______ +VTK-RADIATIVE-PATHS ::= # vtk DataFile Version 2.0 + Radiative paths + ASCII + DATASET POLYDATA + POINTS <#vertices> float + <paths-vertices> + LINES <#paths> <#paths+#vertices> + <paths-lists> + CELL_DATA <#paths> + SCALAR Radiative_path_type float 1 + LOOKUP_TABLE path_type + <paths-type> + LOOKUP_TABLE path_type 3 + <color-occlude> + <color-success> + <color-missing> + +<paths-vertices> ::= <real3> + [ <real3> ... ] # up to <#vertices> + +<paths-lists> ::= <radiative-path> + [ <radiative-path> ... ] # up to <#path> + +<radiative-path> ::= <#path-segments> <path-vertex-id> ... + +<paths-type> ::= <color-id> + [ <color-id> ... ] # up to <#paths> + +<color-id> ::= 0.0 # occlude + | 0.5 # success + | 1.0 # missing + +<color-occlude> ::= 1.0 0.0 0.0 1.0 +<color-success> ::= 0.0 0.0 1.0 1.0 +<color-missing> ::= 1.0 1.0 0.0 1.0 + +<#paths> ::= INTEGER +<#path-segments> ::= INTEGER +<path-vertex-id> ::= INTEGER +_______ + +RENDERING +--------- +When invoked with the *-r* option, *solstice*(1) generates an image of the +solar facility for each submitted sun direction. Each image is preceded by its +associated sun direction and is saved with respect to the ASCII PPM file +format [1]. The output images are actually greyscale images whose pixels store +the average normalized radiance that reaches them. + +NOTES +----- +1. Portable PixMap - <http://netpbm.sourceforge.net/doc/ppm.html> +2. VTK file format - + <http://www.vtk.org/wp-content/uploads/2015/04/file-formats.pdf> +3. OBJ file format - + <http://www.martinreddy.net/gfx/3d/OBJ.spec> + +SEE ALSO +-------- +*solstice*(1), +*solstice-input*(5), +*solstice-receiver*(5) diff --git a/doc/solstice-receiver.5.txt b/doc/solstice-receiver.5.txt @@ -0,0 +1,114 @@ +// Copyright (C) CNRS 2016-2017 +// +// This is free documentation: 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 manual is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see <http://www.gnu.org/licenses/>. +:toc: + +solstice-receiver(5) +==================== + +NAME +---- +solstice-receiver - declare the solar-plant receivers for solstice(1) + + +DESCRIPTION +----------- + +The *solstice-receiver* format is used by *solstice*(1) to declare which +geometric entities defined in a *solstice-input*(5) file are receivers. For +each receiver, *solstice*(1) computes its overall intercepted power, its +associated losses as well as its efficiency. Refer to the *solstice-output*(5) +format for informations on the per receiver data generated by *solstice*(1). +Declaring the receivers separately of the solar plant, allows to use the same +*solstice-input*(5) file for several simulations using different receivers. For +instance, one can define a specific *solstice-receiver* file that declares some +primary reflectors as receivers in order to track an unforeseen comportment +observed during a previous simulation. + +The *solstice-receiver* format uses the YAML 1.1 data serialization standard +[1]; assuming that the file is compatible with the *solstice-receiver* +semantic, the YAML compact notation can thus be used. + +A receiver is identified by its *name* that must be a valid *entity-identifier* +as defined in the *solstice-input*(5) format. This identifier must reference a +geometric entity and not a pivot or an empty entity. The side of the geometry +that is tracked is defined by the *side* attribute of the receiver. Note that +the front and the back side of a geometry can be both considered if the *side* +attribute is set to *FRONT_AND_BACK*. Refer to the *solstice-input*(5) +specification for informations on which side of the geometry is front facing or +back facing. Finally, if the optional *per_primitive* flag is set to *1*, +*solstice*(1) will estimate the irradiance for each triangle of the receiver +and use these data to generate a receiver map as described in +*solstice-output*(5). + +GRAMMAR +------- + +[verse] +_______ +<receivers-list> ::= - <receiver> + [ - <receiver> ... ] + +<receiver> ::= name: <entity-identifier> + side: <side-identifier> + [ per_primitive: INTEGER ] # in [0, 1] + +<side-identifier> ::= FRONT + | BACK + | FRONT_AND_BACK + +<entity-identifier> # Defined in *solstice-input*(1) +_______ + +EXAMPLES +-------- + +Define that the front and back side of the entity *small_square* are +receivers. For each side, enable the computation of per triangle irradiance. + +....... +- name: small_square + side: FRONT_AND_BACK + per_primitive: 1 +....... + +Declare that the front side of 3 reflectors are receivers. Use the YAML +compact notation to reduce the number of lines: + +...... +- {name: H1.heliostat.reflector, side: FRONT} +- {name: H4.heliostat.reflector, side: FRONT} +- {name: H7.heliostat.reflector, side: FRONT} +...... + +Declare that the back side of *receiver* is effectively a receiver and enable +the estimation of its associated irradiance map. Make a receiver from the front +side of the reflector named *LFR0.pivot.reflector*: + +....... +- {name: receiver, side: BACK, per_primitive: 1} +- {name: LFR0.pivot.reflector, side: FRONT} +....... + +NOTES +----- + +1. YAML Ain't Markup Language - <http://yaml.org> + +SEE ALSO +-------- +*solstice*(1), +*solstice-input*(5), +*solstice-output*(5) + diff --git a/doc/solstice.1.txt.in b/doc/solstice.1.txt.in @@ -0,0 +1,241 @@ +// Copyright (C) CNRS 2016-2017 +// +// This is free documentation: 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 manual is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see <http://www.gnu.org/licenses/>. +:toc: + +solstice(1) +=========== + +NAME +---- +solstice - compute the power collected by a concentrated solar plant + +SYNOPSIS +-------- +[verse] +*solstice* +*solstice* [_option_]... [_file_] +*solstice* *-g* <__sub-option__[:...]> [_option_]... [_file_] +*solstice* *-p* <__sub-option__[:...]> [_option_]... [_file_] +*solstice* *-r* <__sub-option__[:...]> [_option_]... [_file_] + +DESCRIPTION +----------- +*solstice* computes the total power collected by a concentrated solar plant, as +described in the *solstice-input*(5) _file_. If the _file_ argument is not +provided, the solar plant is read from standard input. To evaluate various +efficiencies for each primary reflector, it computes losses due to cosine +effect, shadowing and masking, orientation and surface irregularities, +reflectivity and atmospheric transmission. The efficiency for each one of these +effects is subsequently computed for each reflector. + +The entities on which computations must be performed are listed in the +*solstice-receiver*(5) file submitted through the *-R* option. The estimated +results follow the *solstice-output*(5) format and are written to the _output_ +file or to the standard output whether the *-o* _output_ option is defined or +not, respectively. Note that the *solstice* algorithm is based on the +Monte-Carlo method, which means that every result is provided with its +numerical accuracy. + +*solstice* is designed to efficiently handle complex solar facilities: several +reflectors can be specified (planes, conics, cylindro-parabolic, etc.) and +positioned in 3D space, with a possibility for 1-axis and 2-axis +auto-orientation. Multiple materials can be used, as long as the relevant +physical properties are provided. Spectral effects are also taken into account: +it is possible to define the spectral distribution of any physical property, +including the input solar spectrum and the transmissivity of the atmosphere, at +any spectral resolution. Refer to *solstice-input*(5) for more informations. + +In addition of the aforementioned computations, *solstice* provides three +other functionalities. The *-g* option can be used to convert the +*solstice-input*(5) geometries in CAO files. The *-p* option saves the sampled +radiative paths used by the estimates, allowing to visualise them externally +which may be a great help to identify a design issue. Finally, the *-r* option +is used to render an image of the submitted solar facility. Note that these +three options are mutually exclusives, and once defined, they replace the +default *solstice* behaviour. + +OPTIONS +------- +*-D* <__azimuth__,__elevation__[:...]>:: + List of sun directions. A direction is defined by its _azimuthal_ and + _elevation_ angles in degrees, with _azimuth_ in [0, 360[ and _elevation_ in + [0, 90]. Each sun direction triggers a new computation whose results are + concatenated to the _output_ file. + +*-f*:: + Force overwrite of the _output_ file. + +*-g* <__sub-option__:...>:: + Generate the shape of the geometry defined in the submitted _file_ and store + it in _output_. Available sub-options are: + + *format=obj*;; + Define the file format in which the meshes are stored. Currently, only the + Alias Wavefront OBJ file format is supported. + + *split=*<**geometry**|*object*|*none*>;; + Define how the output mesh is split in sub meshes. A sub mesh can be + generated for each *geometry* or for each *object* as defined in the + *solstice-input*(5) file format. The *none* option means that only one + mesh is generated for the whole solar facility. By default, the *split* + option is set to *none*. + +*-h*:: + List short help and exit. + +*-n* _experiments-count_:: + Number of Monte-Carlo experiments used to estimate the solar flux. By + default _experiments-count_ is set to @SOLSTICE_ARGS_DEFAULT_NREALISATIONS@. + +*-o* _output_:: + Write results to _output_ with respect to the *solstice-output*(5) format. If + not defined, write results to standard output. + +*-p* <__sub-option__:...>:: + Register the sampled radiative paths for each sun direction and write them to + _output_. Available sub-options are: + + *default*;; + Use default sub-options. + + **irlen=**_length_;; + Length of the radiative path segments going to the infinity. By default, it + is computed relatively to the scene size. + + **srlen=**_length_;; + Length of the radiative path segments coming from the sun. By default, it + is computed relatively to the scene size. + +*-q*:: + Do not print the helper message when no _file_ is submitted. + +*-R* _receivers_:: + *solstice-receiver*(5) file defining the scene receivers, i.e. the solar + plant entities for which *solstice* computes Monte-Carlo estimates. + +*-r* <__sub-option__:...>:: + Render an image of the scene through a pinhole camera, for each submitted + sun direction. Write the resulting images to _output_. Available sub-options + are: + + **fov=**_angle_;; + Horizontal field of view of the camera in [30, 120] degrees. By default + _angle_ is @SOLSTICE_ARGS_DEFAULT_CAMERA_FOV@ degrees. + + **img=**_width_**x**_height_;; + Definition of the rendered image in pixels. By default the image definition + is @SOLSTICE_ARGS_DEFAULT_IMG_WIDTH@x@SOLSTICE_ARGS_DEFAULT_IMG_HEIGHT@. + + **pos=**_x_**,**_y_**,**_z_;; + Position of the camera. By default it is set to + {@SOLSTICE_ARGS_DEFAULT_CAMERA_POS@} or it is automatically computed to + ensure that the whole scene is visible, whether *tgt* is set or not, + respectively. + + **rmode=**<**draft**|**pt**>;; + Rendering mode. In *draft* mode, images are computed by ray-casting; all + materials are lambertian, the sun is ignored and the only light source is + positioned at the camera position. In *pt* mode, the scene is rendered with + the un-biased path-tracing Monte-Carlo algorithm; the materials described + in the committed _file_ as well as the submitted sun directions are + correctly handled and an uniform skydome is added to simulate the diffuse + infinite lighting. By default *rmode* is set to *draft*. + + **spp=**_samples-count_;; + Number of samples per pixel. If *rmode* is *draft*, the samples position + into a pixel are the same for all pixels. With *rmode=pt* the pixel + samples are generated independently for each pixel. By default, use 1 + sample per pixel. + + **tgt=**_x_**,**_y_**,**_z_;; + Position targeted by the camera. By default, it is set to + {@SOLSTICE_ARGS_DEFAULT_CAMERA_TGT@} or it is automatically computed to + ensure that the whole scene is visible, whether *pos* is set or not, + respectively. + + **up=**_x_**,**_y_**,**_z_;; + Up vector of the camera. If *rmode* is *pt*, this vector also defines the + direction toward the top of the skydome. By default, *up* is set to + {@SOLSTICE_ARGS_DEFAULT_CAMERA_UP@}. + +*-t* _threads-count_:: + Hint on the number of threads to use. By default us as many threads as CPU + cores. + +*-v*:: + Make solstice more verbose. + +EXAMPLES +-------- + +Launch two simulations for sun directions whose azimuthal and elevation angles +are {*45*,*70*} and {*50*,*75*}. The solar facility is described in +*input.yaml* and the receivers on which the integrations must be performed are +declared in the *rcvs.yaml* file. *10000* experiments are used by the +Monte-Carlo estimates and the results are written to *output* even though this +file already exists: + + $ solstice -D45,70:50,75 -R rcvs.yaml -n 10000 -f -o output input.yaml + +Generate a mesh for each geometry described in *input.yaml*, and save them in +the *output* file with respect to the Alias Wavefront OBJ format. The meshes +are positioned according to their orientation constraints, with respect to the +sun direction whose azimuthal and elevation angles are {*30*,*60*}. Use the +*csplit*(1) Unix command to generate an Alias Wavefront OBJ file per geometry +stored in *output*. The name of the generated Alias Wavefront OBJ files are +*geom*<__NUM__>**.obj** with __NUM__ in [0, N-1] where N is the number of +geometries described in *input.yaml*. Refer to *solstice-output*(5) for +informations on the regular expression *^---$* used to split the output file: + + $ solstice -D30,60 -g format=obj:split=geometry -f -o output input.yaml + $ csplit -f geom -b %02d.obj -z --suppress-matched output /^---$/ {*} + +Trace 100 radiative paths into the solar plant described in *input.yaml*, with +respect to the sun direction whose azimuthal and elevations angles are *0* and +*90* degrees, respectively. Write the *solstice-output*(5) result to the +standard output and postprocess it with the *sed*(1) Unix command to remove the +first line that stores the sun direction from which the radiative paths come +from. The remaining data that list the radiative paths geometry are redirected +into the *paths.vtk* file: + + $ solstice -n 100 -D0,90 -R rcvs.yaml -p default input.yaml | sed '1d' > paths.vtk + +Use the path-tracing rendering algorithm to draw the solar plant +*solplant.yaml* with respect to the sun direction whose azimuthal and elevation +angles are *180* and *45* degrees, respectively. Use *64* samples per pixel to +estimate the per-pixel radiance and fix the up camera vector to {*0*,*0*,*1*}. +Write the *solstice-output*(5) result to standard output and use the *sed*(1) +Unix command to remove the first line which stores the sun direction used to +draw the image. Finally, visualise the rendered picture by redirecting the +remaining data to the *feh*(1) image viewer. + + $ solstice -D180,45 -r up=0,0,1:rmode=pt:spp=64 solplant.yaml | sed '1d' | feh - + +COPYRIGHT +--------- +*solstice* is copyright &copy; CNRS 2016-2017. License GPLv3+: GNU GPL version +3 or later <http://gnu.org/licenses/gpl.html>. This is a free software. You are +free to change and redistribute it. There is NO WARRANTY, to the extent +permitted by law. + +SEE ALSO +-------- +*csplit*(1), +*feh*(1), +*sed*(1), +*solstice-input*(5), +*solstice-output*(5), +*solstice-receivers*(5) + diff --git a/src/parser/solparser.c b/src/parser/solparser.c @@ -114,10 +114,12 @@ parse_item const yaml_node_t* item) { /* Temporary dummy variables */ - struct solparser_material_double_sided_id mtl2; struct solparser_entity_id entity; struct solparser_geometry_id geometry; + struct solparser_material_double_sided_id mtl2; + struct solparser_medium_id medium; struct solparser_sun* sun; + struct solparser_atmosphere* atmosphere; yaml_node_t* key; yaml_node_t* val; @@ -147,21 +149,24 @@ parse_item goto error; } + /* The parsing of the templates/spectra is deferred to their explicit use */ if(!strcmp((char*)key->data.scalar.value, "material")) { res = parse_material(parser, doc, val, &mtl2); + } else if(!strcmp((char*)key->data.scalar.value, "medium")) { + res = parse_medium(parser, doc, val, &medium); } else if(!strcmp((char*)key->data.scalar.value, "entity")) { res = parse_entity(parser, doc, val, &parser->str2entities, &entity); if(res == RES_OK) { res = flush_deferred_target_aliases(parser, item, entity); } - } else if(!strcmp((char*)key->data.scalar.value, "template")) { - /* The parsing of the template data is deferred to its explicit used in the - * definition of an entity. If the parsing of the template becomes a - * bottleneck, parse the data only once here and cache them for reuse. */ + } else if(!strcmp((char*)key->data.scalar.value, "template")) { /* Deferred */ } else if(!strcmp((char*)key->data.scalar.value, "geometry")) { res = parse_geometry(parser, doc, val, &geometry); } else if(!strcmp((char*)key->data.scalar.value, "sun")) { res = parse_sun(parser, doc, val, &sun); + } else if (!strcmp((char*)key->data.scalar.value, "atmosphere")) { + res = parse_atmosphere(parser, doc, val, &atmosphere); + } else if(!strcmp((char*)key->data.scalar.value, "spectrum")) { /* Deferred */ } else { log_err(parser, key, "unknown item `%s'.\n", key->data.scalar.value); res = RES_BAD_ARG; @@ -186,14 +191,18 @@ parser_clear(struct solparser* parser) /* Materials */ htable_yaml2sols_clear(&parser->yaml2mtls); + darray_image_clear(&parser->images); darray_material_clear(&parser->mtls); darray_material2_clear(&parser->mtls2); - darray_medium_clear(&parser->mediums); darray_dielectric_clear(&parser->dielectrics); darray_matte_clear(&parser->mattes); darray_mirror_clear(&parser->mirrors); darray_thin_dielectric_clear(&parser->thin_dielectrics); + /* Mediums */ + htable_yaml2sols_clear(&parser->yaml2mediums); + darray_medium_clear(&parser->mediums); + /* Deferred targeted anchors */ darray_tgtalias_clear(&parser->tgtaliases); @@ -205,6 +214,7 @@ parser_clear(struct solparser* parser) darray_paraboloid_clear(&parser->parabols); darray_paraboloid_clear(&parser->parabolic_cylinders); darray_hyperboloid_clear(&parser->hyperbols); + darray_hemisphere_clear(&parser->hemispheres); darray_plane_clear(&parser->planes); darray_sphere_clear(&parser->spheres); darray_impgeom_clear(&parser->stls); @@ -218,6 +228,10 @@ parser_clear(struct solparser* parser) solparser_sun_clear(&parser->sun); parser->sun_key = 0; + /* Atmosphere */ + solparser_atmosphere_clear(&parser->atmosphere); + parser->atmosphere_key = 0; + /* Entities */ htable_str2sols_clear(&parser->str2entities); darray_entity_clear(&parser->entities); @@ -226,6 +240,7 @@ parser_clear(struct solparser* parser) darray_anchor_clear(&parser->anchors); darray_x_pivot_clear(&parser->x_pivots); darray_zx_pivot_clear(&parser->zx_pivots); + darray_spectrum_clear(&parser->spectra); } static void @@ -240,14 +255,18 @@ parser_release(ref_T* ref) /* Materials */ htable_yaml2sols_release(&parser->yaml2mtls); + darray_image_release(&parser->images); darray_material_release(&parser->mtls); darray_material2_release(&parser->mtls2); - darray_medium_release(&parser->mediums); darray_dielectric_release(&parser->dielectrics); darray_matte_release(&parser->mattes); darray_mirror_release(&parser->mirrors); darray_thin_dielectric_release(&parser->thin_dielectrics); + /* Mediums */ + htable_yaml2sols_release(&parser->yaml2mediums); + darray_medium_release(&parser->mediums); + /* Deferred targeted anchors */ darray_tgtalias_release(&parser->tgtaliases); @@ -259,6 +278,7 @@ parser_release(ref_T* ref) darray_paraboloid_release(&parser->parabols); darray_paraboloid_release(&parser->parabolic_cylinders); darray_hyperboloid_release(&parser->hyperbols); + darray_hemisphere_release(&parser->hemispheres); darray_plane_release(&parser->planes); darray_sphere_release(&parser->spheres); darray_impgeom_release(&parser->stls); @@ -271,6 +291,9 @@ parser_release(ref_T* ref) /* Sun */ solparser_sun_release(&parser->sun); + /* Atmosphere */ + solparser_atmosphere_release(&parser->atmosphere); + /* Entities */ htable_str2sols_release(&parser->str2entities); darray_entity_release(&parser->entities); @@ -279,6 +302,7 @@ parser_release(ref_T* ref) darray_anchor_release(&parser->anchors); darray_x_pivot_release(&parser->x_pivots); darray_zx_pivot_release(&parser->zx_pivots); + darray_spectrum_release(&parser->spectra); MEM_RM(parser->allocator, parser); } @@ -383,7 +407,8 @@ parse_realX ASSERT(doc && realX && dst && dim > 0); if(realX->type != YAML_SEQUENCE_NODE) { - log_err(parser, realX, "expect a sequence of 3 reals.\n"); + log_err(parser, realX, "expect a sequence of %lu reals.\n", + (unsigned long)dim); res = RES_BAD_ARG; goto error; } @@ -568,14 +593,18 @@ solparser_create /* Materials */ htable_yaml2sols_init(mem_allocator, &parser->yaml2mtls); + darray_image_init(mem_allocator, &parser->images); darray_material_init(mem_allocator, &parser->mtls); darray_material2_init(mem_allocator, &parser->mtls2); - darray_medium_init(mem_allocator, &parser->mediums); darray_dielectric_init(mem_allocator, &parser->dielectrics); darray_matte_init(mem_allocator, &parser->mattes); darray_mirror_init(mem_allocator, &parser->mirrors); darray_thin_dielectric_init(mem_allocator, &parser->thin_dielectrics); + /* Mediums */ + htable_yaml2sols_init(mem_allocator, &parser->yaml2mediums); + darray_medium_init(mem_allocator, &parser->mediums); + /* Deferred targeted anchors */ darray_tgtalias_init(mem_allocator, &parser->tgtaliases); @@ -587,6 +616,7 @@ solparser_create darray_paraboloid_init(mem_allocator, &parser->parabols); darray_paraboloid_init(mem_allocator, &parser->parabolic_cylinders); darray_hyperboloid_init(mem_allocator, &parser->hyperbols); + darray_hemisphere_init(mem_allocator, &parser->hemispheres); darray_plane_init(mem_allocator, &parser->planes); darray_sphere_init(mem_allocator, &parser->spheres); darray_impgeom_init(mem_allocator, &parser->stls); @@ -599,14 +629,18 @@ solparser_create /* Sun */ solparser_sun_init(mem_allocator, &parser->sun); + /* Atmosphere */ + solparser_atmosphere_init(mem_allocator, &parser->atmosphere); + /* Entities */ htable_str2sols_init(mem_allocator, &parser->str2entities); darray_entity_init(mem_allocator, &parser->entities); - /* Anchors and pivot(2)s */ + /* Miscellaneous */ darray_anchor_init(mem_allocator, &parser->anchors); darray_x_pivot_init(mem_allocator, &parser->x_pivots); darray_zx_pivot_init(mem_allocator, &parser->zx_pivots); + darray_spectrum_init(mem_allocator, &parser->spectra); exit: *out_parser = parser; @@ -882,6 +916,15 @@ solparser_get_entity return darray_entity_cdata_get(&parser->entities) + entity.i; } +const struct solparser_image* +solparser_get_image + (const struct solparser* parser, + const struct solparser_image_id image) +{ + ASSERT(parser && image.i < darray_image_size_get(&parser->images)); + return darray_image_cdata_get(&parser->images) + image.i; +} + const struct solparser_geometry* solparser_get_geometry (const struct solparser* parser, @@ -1047,6 +1090,15 @@ solparser_get_shape_hyperbol return darray_hyperboloid_cdata_get(&parser->hyperbols) + hyperboloid.i; } +const struct solparser_shape_hemisphere* +solparser_get_shape_hemisphere + (const struct solparser* parser, + const struct solparser_shape_hemisphere_id hemisphere) +{ + ASSERT(parser && hemisphere.i < darray_hemisphere_size_get(&parser->hemispheres)); + return darray_hemisphere_cdata_get(&parser->hemispheres) + hemisphere.i; +} + const struct solparser_shape_plane* solparser_get_shape_plane (const struct solparser* parser, @@ -1074,6 +1126,22 @@ solparser_get_shape_stl return darray_impgeom_cdata_get(&parser->stls) + impgeom.i; } +const struct solparser_spectrum* +solparser_get_spectrum + (const struct solparser* parser, + const struct solparser_spectrum_id spectrum) +{ + ASSERT(parser && spectrum.i < darray_spectrum_size_get(&parser->spectra)); + return darray_spectrum_cdata_get(&parser->spectra) + spectrum.i; +} + +int +solparser_has_spectrum(const struct solparser* parser) +{ + ASSERT(parser); + return darray_spectrum_size_get(&parser->spectra) != 0; +} + const struct solparser_sun* solparser_get_sun(const struct solparser* parser) { @@ -1081,6 +1149,14 @@ solparser_get_sun(const struct solparser* parser) return &parser->sun; } +const struct solparser_atmosphere* +solparser_get_atmosphere(const struct solparser* parser) +{ + ASSERT(parser); + if(parser->atmosphere_key) return &parser->atmosphere; + else return NULL; +} + void solparser_entity_iterator_begin (struct solparser* parser, diff --git a/src/parser/solparser.h b/src/parser/solparser.h @@ -17,11 +17,15 @@ #define SOLPARSER_H #include "solparser_entity.h" +#include "solparser_spectrum.h" #include <rsys/rsys.h> +#include <stddef.h> struct mem_allocator; struct solparser; +#define SOLPARSER_ID_IS_VALID(Id) ((Id).i != SIZE_MAX) + struct solparser_entity_iterator { struct htable_str2sols_iterator it__; /* Internal data */ }; @@ -87,16 +91,16 @@ solparser_get_entity (const struct solparser* parser, const struct solparser_entity_id entity); +extern LOCAL_SYM const struct solparser_image* +solparser_get_image + (const struct solparser* parser, + const struct solparser_image_id image); + extern LOCAL_SYM const struct solparser_geometry* solparser_get_geometry (const struct solparser* parser, const struct solparser_geometry_id geom); -extern LOCAL_SYM const struct solparser_medium* -solparser_get_medium - (const struct solparser* parser, - const struct solparser_medium_id medium); - extern LOCAL_SYM const struct solparser_material* solparser_get_material (const struct solparser* parser, @@ -127,21 +131,16 @@ solparser_get_material_thin_dielectric (const struct solparser* parser, const struct solparser_material_thin_dielectric_id thin_dielectric); +extern LOCAL_SYM const struct solparser_medium* +solparser_get_medium + (const struct solparser* parser, + const struct solparser_medium_id medium); + extern LOCAL_SYM const struct solparser_object* solparser_get_object (const struct solparser* parser, const struct solparser_object_id obj); -extern LOCAL_SYM const struct solparser_x_pivot* -solparser_get_x_pivot - (const struct solparser* parser, - const struct solparser_pivot_id x_pivot); - -extern LOCAL_SYM const struct solparser_zx_pivot* -solparser_get_zx_pivot - (const struct solparser* parser, - const struct solparser_pivot_id zx_pivot); - extern LOCAL_SYM const struct solparser_shape* solparser_get_shape (const struct solparser* parser, @@ -177,6 +176,11 @@ solparser_get_shape_hyperbol (const struct solparser* parser, const struct solparser_shape_hyperboloid_id hyperboloid); +extern LOCAL_SYM const struct solparser_shape_hemisphere* +solparser_get_shape_hemisphere + (const struct solparser* parser, + const struct solparser_shape_hemisphere_id hemisphere); + extern LOCAL_SYM const struct solparser_shape_plane* solparser_get_shape_plane (const struct solparser* parser, @@ -196,6 +200,29 @@ extern LOCAL_SYM const struct solparser_sun* solparser_get_sun (const struct solparser* parser); +extern LOCAL_SYM const struct solparser_atmosphere* +solparser_get_atmosphere + (const struct solparser* parser); + +extern LOCAL_SYM const struct solparser_x_pivot* +solparser_get_x_pivot + (const struct solparser* parser, + const struct solparser_pivot_id x_pivot); + +extern LOCAL_SYM const struct solparser_zx_pivot* +solparser_get_zx_pivot + (const struct solparser* parser, + const struct solparser_pivot_id zx_pivot); + +extern LOCAL_SYM const struct solparser_spectrum* +solparser_get_spectrum + (const struct solparser* parser, + const struct solparser_spectrum_id spectrum); + +extern LOCAL_SYM int +solparser_has_spectrum + (const struct solparser* parser); + /******************************************************************************* * Entity interator ******************************************************************************/ diff --git a/src/parser/solparser_atmosphere.c b/src/parser/solparser_atmosphere.c @@ -0,0 +1,118 @@ +/* Copyright (C) CNRS 2016-2017 + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. */ + +#define _POSIX_C_SOURCE 200112L /* nextafter support */ + +#include "solparser_c.h" +#include <math.h> /* nextafter */ + +/******************************************************************************* + * Local function + ******************************************************************************/ +res_T +parse_atmosphere + (struct solparser* parser, + yaml_document_t* doc, + yaml_node_t* atm, + struct solparser_atmosphere** out_solatm) +{ + enum { ABSORPTION }; + struct solparser_atmosphere* solatm = NULL; + int mask = 0; /* Register the parsed attributes */ + intptr_t i, n; + res_T res = RES_OK; + ASSERT(doc && atm && out_solatm); + + if(atm == parser->atmosphere_key) { + solatm = &parser->atmosphere; + goto exit; + } else if(parser->atmosphere_key != 0) { + log_err(parser, atm, + "an atmosphere is already defined. Previous definition is here %lu:%lu.\n", + (unsigned long)parser->atmosphere_key->start_mark.line + 1, + (unsigned long)parser->atmosphere_key->start_mark.column + 1); + res = RES_BAD_ARG; + goto error; + } else { + solatm = &parser->atmosphere; + parser->atmosphere_key = atm; + } + + if(atm->type != YAML_MAPPING_NODE) { + log_err(parser, atm, "expect a mapping of atmosphere attributes.\n"); + res = RES_BAD_ARG; + goto error; + } + + n = atm->data.mapping.pairs.top - atm->data.mapping.pairs.start; + FOR_EACH(i, 0, n) { + yaml_node_t* key; + yaml_node_t* val; + + key = yaml_document_get_node(doc, atm->data.mapping.pairs.start[i].key); + val = yaml_document_get_node(doc, atm->data.mapping.pairs.start[i].value); + if(key->type != YAML_SCALAR_NODE) { + log_err(parser, key, "expect an atmosphere parameter.\n"); + res = RES_BAD_ARG; + goto error; + } + #define SETUP_MASK(Flag, Name) { \ + if(mask & BIT(Flag)) { \ + log_err(parser, key, \ + "the "Name" of the atmosphere is already defined.\n"); \ + res = RES_BAD_ARG; \ + goto error; \ + } \ + mask |= BIT(Flag); \ + } (void)0 + if(!strcmp((char*)key->data.scalar.value, "absorption")) { + SETUP_MASK(ABSORPTION, "absorption"); + res = parse_mtl_data + (parser, doc, val, 0, 1, &solatm->absorption); + } else { + log_err(parser, key, "unknown atmosphere parameter `%s'.\n", + key->data.scalar.value); + res = RES_BAD_ARG; + goto error; + } + if(res != RES_OK) { + log_node(parser, key); + goto error; + } + #undef SETUP_MASK + } + + #define CHECK_PARAM(Flag, Name) \ + if(!(mask & BIT(Flag))) { \ + log_err(parser, atm, "the "Name" of the atmosphere is missing.\n"); \ + res = RES_BAD_ARG; \ + goto error; \ + } (void)0 + CHECK_PARAM(ABSORPTION, "absorption"); + #undef CHECK_PARAM + +exit: + *out_solatm = solatm; + return res; +error: + if(solatm) { + solparser_atmosphere_clear(solatm); + solatm = NULL; + parser->atmosphere_key = 0; + } + solatm = NULL; + goto exit; +} + diff --git a/src/parser/solparser_atmosphere.h b/src/parser/solparser_atmosphere.h @@ -0,0 +1,51 @@ +/* Copyright (C) CNRS 2016-2017 + * + * 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 SOLPARSER_ATMOSPHERE_H +#define SOLPARSER_ATMOSPHERE_H + +#include "solparser_mtl_data.h" + +struct solparser_atmosphere { + struct solparser_mtl_data absorption; +}; + +static INLINE void +solparser_atmosphere_init + (struct mem_allocator* allocator, struct solparser_atmosphere* atmosphere) +{ + ASSERT(atmosphere); + (void)allocator, (void)atmosphere; + /* Do nothing */ +} + +static INLINE void +solparser_atmosphere_release(struct solparser_atmosphere* atmosphere) +{ + ASSERT(atmosphere); + (void)atmosphere; + /* Do nothing */ +} + +static INLINE void +solparser_atmosphere_clear(struct solparser_atmosphere* atmosphere) +{ + ASSERT(atmosphere); + (void)atmosphere; + /* Do nothing */ +} + +#endif /* SOLPARSER_ATMOSPHERE_H */ + diff --git a/src/parser/solparser_c.h b/src/parser/solparser_c.h @@ -17,10 +17,15 @@ #define SOLPARSER_C_H #include "solparser.h" +#include "solparser_atmosphere.h" #include "solparser_entity.h" +#include "solparser_image.h" #include "solparser_material.h" +#include "solparser_medium.h" +#include "solparser_mtl_data.h" #include "solparser_pivot.h" #include "solparser_shape.h" +#include "solparser_spectrum.h" #include "solparser_sun.h" #include <rsys/dynamic_array.h> @@ -48,21 +53,25 @@ struct target_alias { /* Declare the array of dielectric materials */ #define DARRAY_NAME dielectric #define DARRAY_DATA struct solparser_material_dielectric +#define DARRAY_FUNCTOR_INIT solparser_material_dielectric_init #include <rsys/dynamic_array.h> /* Declare the array of matte materials */ #define DARRAY_NAME matte #define DARRAY_DATA struct solparser_material_matte +#define DARRAY_FUNCTOR_INIT solparser_material_matte_init #include <rsys/dynamic_array.h> /* Declare the array of mirror materials */ #define DARRAY_NAME mirror #define DARRAY_DATA struct solparser_material_mirror +#define DARRAY_FUNCTOR_INIT solparser_material_mirror_init #include <rsys/dynamic_array.h> /* Declare the array of thin_dielectric materials */ #define DARRAY_NAME thin_dielectric #define DARRAY_DATA struct solparser_material_thin_dielectric +#define DARRAY_FUNCTOR_INIT solparser_material_thin_dielectric_init #include <rsys/dynamic_array.h> /* Declare the array of materials */ @@ -90,6 +99,15 @@ struct target_alias { #define DARRAY_DATA struct solparser_shape_cylinder #include <rsys/dynamic_array.h> +/* Declare the array of images */ +#define DARRAY_NAME image +#define DARRAY_DATA struct solparser_image +#define DARRAY_FUNCTOR_INIT solparser_image_init +#define DARRAY_FUNCTOR_RELEASE solparser_image_release +#define DARRAY_FUNCTOR_COPY solparser_image_copy +#define DARRAY_FUNCTOR_COPY_AND_RELEASE solparser_image_copy_and_release +#include <rsys/dynamic_array.h> + /* Declare the array of imported geometries */ #define DARRAY_NAME impgeom #define DARRAY_DATA struct solparser_shape_imported_geometry @@ -120,6 +138,16 @@ struct target_alias { solparser_shape_hyperboloid_copy_and_release #include <rsys/dynamic_array.h> +/* Declare the array of hemispheres */ +#define DARRAY_NAME hemisphere +#define DARRAY_DATA struct solparser_shape_hemisphere +#define DARRAY_FUNCTOR_INIT solparser_shape_hemisphere_init +#define DARRAY_FUNCTOR_RELEASE solparser_shape_hemisphere_release +#define DARRAY_FUNCTOR_COPY solparser_shape_hemisphere_copy +#define DARRAY_FUNCTOR_COPY_AND_RELEASE \ + solparser_shape_hemisphere_copy_and_release +#include <rsys/dynamic_array.h> + /* Declare the array of planes */ #define DARRAY_NAME plane #define DARRAY_DATA struct solparser_shape_plane @@ -178,6 +206,15 @@ struct target_alias { #define DARRAY_FUNCTOR_INIT solparser_zx_pivot_init #include <rsys/dynamic_array.h> +/* Declare the array of spectra */ +#define DARRAY_NAME spectrum +#define DARRAY_DATA struct solparser_spectrum +#define DARRAY_FUNCTOR_INIT solparser_spectrum_init +#define DARRAY_FUNCTOR_RELEASE solparser_spectrum_release +#define DARRAY_FUNCTOR_COPY solparser_spectrum_copy +#define DARRAY_FUNCTOR_COPY_AND_RELEASE solparser_spectrum_copy_and_release +#include <rsys/dynamic_array.h> + /* Declare the hash table that maps the address of a YAML node to the id of its * in memory representation. */ #define HTABLE_NAME yaml2sols @@ -190,16 +227,20 @@ struct solparser { struct str stream_name; int parser_is_init; - /* Materia data */ + /* Material */ struct htable_yaml2sols yaml2mtls; /* Cache of materials */ + struct darray_image images; struct darray_material mtls; struct darray_material2 mtls2; /* Double sided materials */ - struct darray_medium mediums; struct darray_dielectric dielectrics; struct darray_matte mattes; struct darray_mirror mirrors; struct darray_thin_dielectric thin_dielectrics; + /* Medium */ + struct htable_yaml2sols yaml2mediums; /* Cache of mediums */ + struct darray_medium mediums; + /* Use to deferred the setup of the anchor targeted by a pivot */ struct darray_tgtalias tgtaliases; @@ -211,6 +252,7 @@ struct solparser { struct darray_paraboloid parabols; struct darray_paraboloid parabolic_cylinders; struct darray_hyperboloid hyperbols; + struct darray_hemisphere hemispheres; struct darray_plane planes; struct darray_sphere spheres; struct darray_impgeom stls; @@ -224,6 +266,10 @@ struct solparser { const yaml_node_t* sun_key; /* yaml_node_t ptr used to spawn the sun */ struct solparser_sun sun; /* The loaded sun */ + /* Atmosphere. Note that at most one atmosphere is supported */ + const yaml_node_t* atmosphere_key; /* ptr of the atmosphere. Can be NULL */ + struct solparser_atmosphere atmosphere; /* The loaded atmosphere, if any */ + /* Entity */ struct htable_str2sols str2entities; struct darray_entity entities; @@ -232,6 +278,7 @@ struct solparser { struct darray_anchor anchors; struct darray_x_pivot x_pivots; struct darray_zx_pivot zx_pivots; + struct darray_spectrum spectra; ref_T ref; struct mem_allocator* allocator; @@ -328,13 +375,6 @@ parse_transform * Main parsing functions ******************************************************************************/ extern LOCAL_SYM res_T -parse_material - (struct solparser* parser, - yaml_document_t* doc, - yaml_node_t* mtl, - struct solparser_material_double_sided_id* out_imtl2); - -extern LOCAL_SYM res_T parse_entity (struct solparser* parser, yaml_document_t* doc, @@ -343,6 +383,13 @@ parse_entity struct solparser_entity_id* out_isolent); extern LOCAL_SYM res_T +parse_image + (struct solparser* parser, + yaml_document_t* doc, + const yaml_node_t* image, + struct solparser_image_id* out_img); + +extern LOCAL_SYM res_T parse_focals_description (struct solparser* parser, yaml_document_t* doc, @@ -357,33 +404,63 @@ parse_geometry struct solparser_geometry_id* out_isolgeom); extern LOCAL_SYM res_T -parse_x_pivot +parse_material (struct solparser* parser, yaml_document_t* doc, - const yaml_node_t* x_pivot, - struct solparser_pivot_id* out_isolpivot); + yaml_node_t* mtl, + struct solparser_material_double_sided_id* out_imtl2); extern LOCAL_SYM res_T -parse_zx_pivot +parse_medium (struct solparser* parser, yaml_document_t* doc, - const yaml_node_t* zx_pivot, - struct solparser_pivot_id* out_isolpivot); + yaml_node_t* medium, + struct solparser_medium_id* out_imedium); extern LOCAL_SYM res_T -parse_sun +parse_mtl_data (struct solparser* parser, yaml_document_t* doc, - const yaml_node_t* sun, - struct solparser_sun** out_solsun); + yaml_node_t* mtl_data, + const double lower_bound, + const double upper_bound, + struct solparser_mtl_data* data); extern LOCAL_SYM res_T parse_spectrum (struct solparser* parser, yaml_document_t* doc, + const yaml_node_t* spectrum, const double lower_bound, const double upper_bound, - const yaml_node_t* spectrum, - struct darray_spectrum_data* data); + struct solparser_spectrum_id* out_ispectrum); + +extern LOCAL_SYM res_T +parse_sun + (struct solparser* parser, + yaml_document_t* doc, + const yaml_node_t* sun, + struct solparser_sun** out_solsun); + +extern LOCAL_SYM res_T +parse_atmosphere + (struct solparser* parser, + yaml_document_t* doc, + yaml_node_t* atm, + struct solparser_atmosphere** out_solatm); + +extern LOCAL_SYM res_T +parse_x_pivot + (struct solparser* parser, + yaml_document_t* doc, + const yaml_node_t* x_pivot, + struct solparser_pivot_id* out_isolpivot); + +extern LOCAL_SYM res_T +parse_zx_pivot + (struct solparser* parser, + yaml_document_t* doc, + const yaml_node_t* zx_pivot, + struct solparser_pivot_id* out_isolpivot); #endif /* SOLPARSER_C_H */ diff --git a/src/parser/solparser_geometry.c b/src/parser/solparser_geometry.c @@ -16,6 +16,7 @@ #define _POSIX_C_SOURCE 200112L /* nextafter support */ #include "solparser_c.h" +#include <rsys/double2.h> #include <math.h> /* nextafter */ /******************************************************************************* @@ -100,13 +101,97 @@ error: } static res_T +parse_circle + (struct solparser* parser, + yaml_document_t* doc, + const yaml_node_t* circle, + struct solparser_circleclip* clip) +{ + enum { RADIUS, CENTER, SEGMENTS }; + intptr_t i, n; + int mask = 0; /* Register the parsed attributes */ + res_T res = RES_OK; + ASSERT(doc && circle && clip); + + if(circle->type != YAML_MAPPING_NODE) { + log_err(parser, circle, + "expect a mapping of clipping circles parameters.\n"); + res = RES_BAD_ARG; + goto error; + } + + n = circle->data.mapping.pairs.top - circle->data.mapping.pairs.start; + clip->segments = 64; /* default value */ + d2_splat(clip->center, 0); /* default value */ + FOR_EACH(i, 0, n) { + yaml_node_t* key; + yaml_node_t* val; + + key = yaml_document_get_node(doc, circle->data.mapping.pairs.start[i].key); + val = yaml_document_get_node(doc, circle->data.mapping.pairs.start[i].value); + if (key->type != YAML_SCALAR_NODE) { + log_err(parser, key, "expect a clipping circle parameter.\n"); + res = RES_BAD_ARG; + goto error; + } + + #define SETUP_MASK(Flag, Name) { \ + if(mask & BIT(Flag)) { \ + log_err(parser, key, \ + "the clipping circle parameter `"Name"' is already defined.\n"); \ + res = RES_BAD_ARG; \ + goto error; \ + } \ + mask |= BIT(Flag); \ + } (void)0 + if(!strcmp((char*)key->data.scalar.value, "radius")) { + SETUP_MASK(RADIUS, "radius"); + res = parse_real(parser, val, nextafter(0, 1), DBL_MAX, &clip->radius); + } + else if(!strcmp((char*)key->data.scalar.value, "center")) { + SETUP_MASK(CENTER, "center"); + res = parse_real2(parser, doc, val, -DBL_MAX, DBL_MAX, clip->center); + } + else if(!strcmp((char*)key->data.scalar.value, "segments")) { + SETUP_MASK(SEGMENTS, "segments"); + res = parse_integer(parser, val, 3, 4096, &clip->segments); + } else { + log_err(parser, key, "unknown clipping circle parameter `%s'.\n", + key->data.scalar.value); + res = RES_BAD_ARG; + goto error; + } + if(res != RES_OK) { + log_node(parser, key); + goto error; + } + #undef SETUP_MASK + } + + #define CHECK_PARAM(Flag, Name) \ + if(!(mask & BIT(Flag))) { \ + log_err(parser, circle, \ + "the clipping circle parameter `"Name"' is missing.\n"); \ + res = RES_BAD_ARG; \ + goto error; \ + } (void)0 + CHECK_PARAM(RADIUS, "radius"); + #undef CHECK_PARAM + +exit: + return res; +error: + goto exit; +} + +static res_T parse_polyclip (struct solparser* parser, yaml_document_t* doc, const yaml_node_t* polyclip, struct solparser_polyclip* clip) { - enum { OPERATION, VERTICES }; + enum { OPERATION, CONTOUR }; intptr_t i, n; int mask = 0; /* Register the parsed attributes */ res_T res = RES_OK; @@ -145,8 +230,14 @@ parse_polyclip SETUP_MASK(OPERATION, "operation"); res = parse_clip_op(parser, val, &clip->op); } else if(!strcmp((char*)key->data.scalar.value, "vertices")) { - SETUP_MASK(VERTICES, "vertices"); + SETUP_MASK(CONTOUR, "contour"); + clip->contour_type = SOLPARSER_CLIP_CONTOUR_POLY; res = parse_vertices(parser, doc, val, &clip->vertices); + } + else if(!strcmp((char*)key->data.scalar.value, "circle")) { + SETUP_MASK(CONTOUR, "contour"); + clip->contour_type = SOLPARSER_CLIP_CONTOUR_CIRCLE; + res = parse_circle(parser, doc, val, &clip->circle); } else { log_err(parser, key, "unknown clipping polygon parameter `%s'.\n", key->data.scalar.value); @@ -168,7 +259,7 @@ parse_polyclip goto error; \ } (void)0 CHECK_PARAM(OPERATION, "operation"); - CHECK_PARAM(VERTICES, "vertices"); + CHECK_PARAM(CONTOUR, "contour"); #undef CHECK_PARAM exit: @@ -305,7 +396,7 @@ parse_cylinder const yaml_node_t* cylinder, struct solparser_shape_cylinder_id* out_ishape) { - enum { HEIGHT, RADIUS, SLICES }; + enum { HEIGHT, RADIUS, SLICES, STACKS }; struct solparser_shape_cylinder* shape = NULL; size_t ishape = SIZE_MAX; intptr_t i, n; @@ -329,6 +420,8 @@ parse_cylinder shape = darray_cylinder_data_get(&parser->cylinders) + ishape; n = cylinder->data.mapping.pairs.top - cylinder->data.mapping.pairs.start; + shape->nslices = 16; /* default value */ + shape->nstacks = 1; /* default value */ FOR_EACH(i, 0, n) { yaml_node_t* key; yaml_node_t* val; @@ -358,6 +451,10 @@ parse_cylinder } else if(!strcmp((char*)key->data.scalar.value, "slices")) { SETUP_MASK(SLICES, "slices"); res = parse_integer(parser, val, 4, 4096, &shape->nslices); + } + else if(!strcmp((char*)key->data.scalar.value, "stacks")) { + SETUP_MASK(STACKS, "stacks"); + res = parse_integer(parser, val, 1, 4096, &shape->nstacks); } else { log_err(parser, key, "unknown cylinder parameter `%s'.\n", key->data.scalar.value); @@ -382,13 +479,6 @@ parse_cylinder CHECK_PARAM(RADIUS, "radius"); #undef CHECK_PARAM - #define DEFAULT_PARAM(Flag, Ptr, Value) \ - if(!(mask & BIT(Flag))) { \ - *(Ptr) = Value; \ - } (void)0 - DEFAULT_PARAM(SLICES, &shape->nslices, 16); - #undef DEFAULT_PARAM - exit: out_ishape->i = ishape; return res; @@ -692,6 +782,102 @@ error: } static res_T +parse_hemisphere + (struct solparser* parser, + yaml_document_t* doc, + const yaml_node_t* hemisphere, + struct solparser_shape_hemisphere_id* out_ishape) +{ + enum { CLIP, RADIUS, SLICES }; + struct solparser_shape_hemisphere* shape = NULL; + size_t ishape = SIZE_MAX; + intptr_t i, n; + int mask = 0; /* Register the parsed attributes */ + res_T res = RES_OK; + ASSERT(doc && hemisphere && out_ishape); + + if(hemisphere->type != YAML_MAPPING_NODE) { + log_err(parser, hemisphere, "expect a mapping of hemisphere parameters.\n"); + res = RES_BAD_ARG; + goto error; + } + + /* Allocate a hemispheric shape */ + ishape = darray_hemisphere_size_get(&parser->hemispheres); + res = darray_hemisphere_resize(&parser->hemispheres, ishape + 1); + if(res != RES_OK) { + log_err(parser, hemisphere, "could not allocate the hemisphere shape.\n"); + goto error; + } + shape = darray_hemisphere_data_get(&parser->hemispheres) + ishape; + + n = hemisphere->data.mapping.pairs.top - hemisphere->data.mapping.pairs.start; + FOR_EACH(i, 0, n) { + yaml_node_t* key; + yaml_node_t* val; + + key = yaml_document_get_node(doc, hemisphere->data.mapping.pairs.start[i].key); + val = yaml_document_get_node(doc, hemisphere->data.mapping.pairs.start[i].value); + if(key->type != YAML_SCALAR_NODE) { + log_err(parser, key, "expect hemisphere parameters.\n"); + res = RES_BAD_ARG; + goto error; + } + #define SETUP_MASK(Flag, Name) { \ + if(mask & BIT(Flag)) { \ + log_err(parser, key, \ + "the hemisphere parameter `"Name"' is already defined.\n"); \ + res = RES_BAD_ARG; \ + goto error; \ + } \ + mask |= BIT(Flag); \ + } (void)0 + if(!strcmp((char*)key->data.scalar.value, "clip")) { + SETUP_MASK(CLIP, "clip"); + res = parse_clip(parser, doc, val, &shape->polyclips); + } + else if(!strcmp((char*)key->data.scalar.value, "radius")) { + SETUP_MASK(RADIUS, "radius"); + res = parse_real(parser, val, nextafter(0, 1), DBL_MAX, &shape->radius); + } + else if(!strcmp((char*)key->data.scalar.value, "slices")) { + SETUP_MASK(SLICES, "slices"); + res = parse_integer(parser, val, 4, 4096, &shape->nslices); + } + else { + log_err(parser, key, "unknown hemisphere parameter `%s'.\n", + key->data.scalar.value); + res = RES_BAD_ARG; + goto error; + } + if (res != RES_OK) { + log_node(parser, key); + goto error; + } + #undef SETUP_MASK + } + #define CHECK_PARAM(Flag, Name) \ + if(!(mask & BIT(Flag))) { \ + log_err(parser, hemisphere, \ + "the hemisphere parameter `"Name"' is missing.\n"); \ + res = RES_BAD_ARG; \ + goto error; \ + } (void)0 + CHECK_PARAM(RADIUS, "radius"); + #undef CHECK_PARAM + +exit : + out_ishape->i = ishape; + return res; +error: + if(shape) { + darray_hemisphere_pop_back(&parser->hemispheres); + ishape = SIZE_MAX; + } + goto exit; +} + +static res_T parse_plane (struct solparser* parser, yaml_document_t* doc, @@ -722,6 +908,7 @@ parse_plane shape = darray_plane_data_get(&parser->planes) + ishape; n = plane->data.mapping.pairs.top - plane->data.mapping.pairs.start; + shape->nslices = 1; /* default value */ FOR_EACH(i, 0, n) { yaml_node_t* key; yaml_node_t* val; @@ -785,7 +972,7 @@ parse_sphere const yaml_node_t* sphere, struct solparser_shape_sphere_id* out_ishape) { - enum { RADIUS, SLICES }; + enum { RADIUS, SLICES, STACKS }; struct solparser_shape_sphere* shape = NULL; size_t ishape = SIZE_MAX; intptr_t i, n; @@ -809,6 +996,8 @@ parse_sphere shape = darray_sphere_data_get(&parser->spheres) + ishape; n = sphere->data.mapping.pairs.top - sphere->data.mapping.pairs.start; + shape->nslices = 16; /* default value */ + shape->nstacks = 8; /* initial default value */ FOR_EACH(i, 0, n) { yaml_node_t* key; yaml_node_t* val; @@ -835,6 +1024,11 @@ parse_sphere } else if(!strcmp((char*)key->data.scalar.value, "slices")) { SETUP_MASK(SLICES, "slices"); res = parse_integer(parser, val, 4, 4096, &shape->nslices); + if(!(mask & BIT(STACKS))) + shape->nstacks = shape->nslices / 2; /* if unset, new default value */ + } else if(!strcmp((char*)key->data.scalar.value, "stacks")) { + SETUP_MASK(STACKS, "stacks"); + res = parse_integer(parser, val, 2, 4096, &shape->nstacks); } else { log_err(parser, key, "unknown sphere parameter `%s'.\n", key->data.scalar.value); @@ -858,13 +1052,6 @@ parse_sphere CHECK_PARAM(RADIUS, "radius"); #undef CHECK_PARAM - #define DEFAULT_PARAM(Flag, Ptr, Value) \ - if(!(mask & BIT(Flag))) { \ - *(Ptr) = Value; \ - } (void)0 - DEFAULT_PARAM(SLICES, &shape->nslices, 16); - #undef DEFAULT_PARAM - exit: out_ishape->i = ishape; return res; @@ -975,6 +1162,11 @@ parse_object SETUP_MASK(SHAPE, "shape"); shape->type = SOLPARSER_SHAPE_HYPERBOL; res = parse_hyperboloid(parser, doc, val, &shape->data.hyperbol); + } + else if(!strcmp((char*)key->data.scalar.value, "hemisphere")) { + SETUP_MASK(SHAPE, "shape"); + shape->type = SOLPARSER_SHAPE_HEMISPHERE; + res = parse_hemisphere(parser, doc, val, &shape->data.hemisphere); } else if(!strcmp((char*)key->data.scalar.value, "plane")) { SETUP_MASK(SHAPE, "shape"); shape->type = SOLPARSER_SHAPE_PLANE; diff --git a/src/parser/solparser_image.c b/src/parser/solparser_image.c @@ -0,0 +1,107 @@ +/* Copyright (C) CNRS 2016-2017 + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. */ + +#include "solparser_c.h" + +/******************************************************************************* + * Local functions + ******************************************************************************/ +res_T +parse_image + (struct solparser* parser, + yaml_document_t* doc, + const yaml_node_t* img, + struct solparser_image_id* out_iimg) +{ + enum { PATH }; + struct solparser_image* solimg = NULL; + size_t isolimg = SIZE_MAX; + intptr_t i, n; + int mask = 0; /* Register the parsed attributes */ + res_T res = RES_OK; + ASSERT(parser && doc && img &&out_iimg); + + if(img->type != YAML_MAPPING_NODE) { + log_err(parser, img, "expect a mapping of image parameters.\n"); + res = RES_BAD_ARG; + goto error; + } + + /* Allocate an image */ + isolimg = darray_image_size_get(&parser->images); + res = darray_image_resize(&parser->images, isolimg + 1); + if(res != RES_OK) { + log_err(parser, img, "could not allocate the image.\n"); + goto error; + } + solimg = darray_image_data_get(&parser->images) + isolimg; + + n = img->data.mapping.pairs.top - img->data.mapping.pairs.start; + FOR_EACH(i, 0, n) { + yaml_node_t* key; + yaml_node_t* val; + + key = yaml_document_get_node(doc, img->data.mapping.pairs.start[i].key); + val = yaml_document_get_node(doc, img->data.mapping.pairs.start[i].value); + if(key->type != YAML_SCALAR_NODE) { + log_err(parser, key, "expect image parameters.\n"); + goto error; + } + #define SETUP_MASK(Flag, Name) { \ + if(mask & BIT(Flag)) { \ + log_err(parser, key, \ + "the image parameter `"Name"' is already defined.\n"); \ + res = RES_BAD_ARG; \ + goto error; \ + } \ + mask |= BIT(Flag); \ + } (void)0 + if(!strcmp((char*)key->data.scalar.value, "path")) { + SETUP_MASK(PATH, "path"); + res = parse_string(parser, val, &solimg->filename); + } else { + log_err(parser, key, "unknown image parameter `%s'.\n", + key->data.scalar.value); + res = RES_BAD_ARG; + goto error; + } + if(res != RES_OK) { + log_node(parser, key); + goto error; + } + #undef SETUP_MASK + } + + #define CHECK_PARAM(Flag, Name) \ + if(!(mask & BIT(Flag))) { \ + log_err(parser, img, \ + "the image parameter `"Name"' is missing.\n"); \ + res = RES_BAD_ARG; \ + goto error; \ + } (void)0 + CHECK_PARAM(PATH, "path"); + #undef CHECK_PARAM + +exit: + out_iimg->i = isolimg; + return res; +error: + if(solimg) { + darray_image_pop_back(&parser->images); + isolimg = SIZE_MAX; + } + goto exit; +} + diff --git a/src/parser/solparser_image.h b/src/parser/solparser_image.h @@ -0,0 +1,62 @@ +/* Copyright (C) CNRS 2016-2017 + * + * 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 SOLPARSER_IMAGE_H +#define SOLPARSER_IMAGE_H + +#include <rsys/str.h> + +struct solparser_image { + struct str filename; +}; + +struct solparser_image_id { size_t i; }; + +static INLINE void +solparser_image_init + (struct mem_allocator* allocator, + struct solparser_image* img) +{ + ASSERT(img); + str_init(allocator, &img->filename); +} + +static INLINE void +solparser_image_release(struct solparser_image* img) +{ + ASSERT(img); + str_release(&img->filename); +} + +static INLINE res_T +solparser_image_copy + (struct solparser_image* dst, + const struct solparser_image* src) +{ + ASSERT(dst && src); + return str_copy(&dst->filename, &src->filename); +} + +static INLINE res_T +solparser_image_copy_and_release + (struct solparser_image* dst, + struct solparser_image* src) +{ + ASSERT(dst && src); + return str_copy_and_release(&dst->filename, &src->filename); +} + +#endif /* SOLPARSER_IMAGE_H */ + diff --git a/src/parser/solparser_material.c b/src/parser/solparser_material.c @@ -22,105 +22,13 @@ * Helper functions ******************************************************************************/ static res_T -parse_medium - (struct solparser* parser, - yaml_document_t* doc, - const yaml_node_t* medium, - struct solparser_medium_id* out_imedium) -{ - enum { ABSORPTIVITY, REFRACTIVE_INDEX }; - struct solparser_medium* mdm = NULL; - size_t imedium = SIZE_MAX; - int mask = 0; /* Register the parsed attributes */ - intptr_t i, n; - res_T res = RES_OK; - ASSERT(doc && medium && out_imedium); - - if(medium->type != YAML_MAPPING_NODE) { - log_err(parser, medium, "expect a mapping of medium attributes.\n"); - res = RES_BAD_ARG; - goto error; - } - - /* Allocate the medium */ - imedium = darray_medium_size_get(&parser->mediums); - res = darray_medium_resize(&parser->mediums, imedium + 1); - if(res != RES_OK) { - log_err(parser, medium, "could not allocate the medium.\n"); - res = RES_BAD_ARG; - goto error; - } - mdm = darray_medium_data_get(&parser->mediums) + imedium; - - n = medium->data.mapping.pairs.top - medium->data.mapping.pairs.start; - FOR_EACH(i, 0, n) { - yaml_node_t* key; - yaml_node_t* val; - - key = yaml_document_get_node(doc, medium->data.mapping.pairs.start[i].key); - val = yaml_document_get_node(doc, medium->data.mapping.pairs.start[i].value); - if(key->type != YAML_SCALAR_NODE) { - log_err(parser, key, "expect a medium parameter.\n"); - res = RES_BAD_ARG; - goto error; - } - #define SETUP_MASK(Flag, Name) { \ - if(mask & BIT(Flag)) { \ - log_err(parser, key,"the "Name" of the medium is already defined.\n");\ - res = RES_BAD_ARG; \ - goto error; \ - } \ - mask |= BIT(Flag); \ - } (void)0 - if(!strcmp((char*)key->data.scalar.value, "absorptivity")) { - SETUP_MASK(ABSORPTIVITY, "absorptivity"); - res = parse_real(parser, val, 0, DBL_MAX, &mdm->absorptivity); - } else if(!strcmp((char*)key->data.scalar.value, "refractive_index")) { - SETUP_MASK(REFRACTIVE_INDEX, "refractive_index"); - res = parse_real - (parser, val, nextafter(0, 1), DBL_MAX, &mdm->refractive_index); - } else { - log_err(parser, key, "unknown medium parameter `%s'.\n", - key->data.scalar.value); - res = RES_BAD_ARG; - goto error; - } - if(res != RES_OK) { - log_node(parser, key); - goto error; - } - #undef SETUP_MASK - } - - #define CHECK_PARAM(Flag, Name) \ - if(!(mask & BIT(Flag))) { \ - log_err(parser, medium, "the "Name" of the medium is missing.\n"); \ - res = RES_BAD_ARG; \ - goto error; \ - } (void)0 - CHECK_PARAM(ABSORPTIVITY, "absorptivity"); - CHECK_PARAM(REFRACTIVE_INDEX, "refractive_index"); - #undef CHECK_PARAM - -exit: - out_imedium->i = imedium; - return res; -error: - if(imedium) { - darray_medium_pop_back(&parser->mediums); - imedium = SIZE_MAX; - } - goto exit; -} - -static res_T parse_material_dielectric (struct solparser* parser, yaml_document_t* doc, const yaml_node_t* dielec, struct solparser_material_dielectric_id* out_imtl) { - enum { MEDIUM_I, MEDIUM_T }; + enum { MEDIUM_I, MEDIUM_T, NORMAL_MAP }; struct solparser_material_dielectric* mtl = NULL; size_t imtl = SIZE_MAX; int mask = 0; /* Register the parsed attributes */ @@ -166,7 +74,10 @@ parse_material_dielectric } \ mask |= BIT(Flag); \ } (void)0 - if(!strcmp((char*)key->data.scalar.value, "medium_i")) { + if(!strcmp((char*)key->data.scalar.value, "normal_map")) { + SETUP_MASK(NORMAL_MAP, "normal_map"); + res = parse_image(parser, doc, val, &mtl->normal_map); + } else if(!strcmp((char*)key->data.scalar.value, "medium_i")) { SETUP_MASK(MEDIUM_I, "medium_i"); res = parse_medium(parser, doc, val, &mtl->medium_i); } else if(!strcmp((char*)key->data.scalar.value, "medium_t")) { @@ -214,7 +125,7 @@ parse_material_matte const yaml_node_t* matte, struct solparser_material_matte_id* out_imtl) { - enum { REFLECTIVITY }; + enum { NORMAL_MAP, REFLECTIVITY }; struct solparser_material_matte* mtl = NULL; size_t imtl = SIZE_MAX; intptr_t i, n; @@ -250,14 +161,21 @@ parse_material_matte goto error; } - if(!strcmp((char*)key->data.scalar.value, "reflectivity")) { - if(mask & BIT(REFLECTIVITY)) { - log_err(parser, key, "the matte reflectivity is already defined.\n"); - res = RES_BAD_ARG; - goto error; - } - mask |= BIT(REFLECTIVITY); - res = parse_real(parser, val, 0, 1, &mtl->reflectivity); + #define SETUP_MASK(Flag, Name) { \ + if(mask & BIT(Flag)) { \ + log_err(parser, key, \ + "the "Name" of the matte material is already defined.\n"); \ + res = RES_BAD_ARG; \ + goto error; \ + } \ + mask |= BIT(Flag); \ + } (void)0 + if(!strcmp((char*)key->data.scalar.value, "normal_map")) { + SETUP_MASK(NORMAL_MAP, "normal_map"); + res = parse_image(parser, doc, val, &mtl->normal_map); + } else if(!strcmp((char*)key->data.scalar.value, "reflectivity")) { + SETUP_MASK(REFLECTIVITY, "reflectivity"); + res = parse_mtl_data(parser, doc, val, 0, 1, &mtl->reflectivity); } else { log_err(parser, key, "unknown matte parameter `%s'.\n", key->data.scalar.value); @@ -268,6 +186,7 @@ parse_material_matte log_node(parser, key); goto error; } + #undef SETUP_MASK } if(!(mask & BIT(REFLECTIVITY))) { @@ -294,7 +213,7 @@ parse_material_mirror const yaml_node_t* mirror, struct solparser_material_mirror_id* out_imtl) { - enum { REFLECTIVITY, ROUGHNESS }; + enum { NORMAL_MAP, REFLECTIVITY, ROUGHNESS }; struct solparser_material_mirror* mtl = NULL; size_t imtl = SIZE_MAX; int mask = 0; /* Register the parsed attributes */ @@ -340,12 +259,15 @@ parse_material_mirror } \ mask |= BIT(Flag); \ } (void)0 - if(!strcmp((char*)key->data.scalar.value, "reflectivity")) { + if(!strcmp((char*)key->data.scalar.value, "normal_map")) { + SETUP_MASK(NORMAL_MAP, "normal_map"); + res = parse_image(parser, doc, val, &mtl->normal_map); + } else if(!strcmp((char*)key->data.scalar.value, "reflectivity")) { SETUP_MASK(REFLECTIVITY, "reflectivity"); - res = parse_real(parser, val, 0, 1, &mtl->reflectivity); + res = parse_mtl_data(parser, doc, val, 0, 1, &mtl->reflectivity); } else if(!strcmp((char*)key->data.scalar.value, "roughness")) { SETUP_MASK(ROUGHNESS, "roughness"); - res = parse_real(parser, val, 0, 1, &mtl->roughness); + res = parse_mtl_data(parser, doc, val, 0, 1, &mtl->roughness); } else { log_err(parser, key, "unknown mirror attribute `%s'.\n", key->data.scalar.value); @@ -387,7 +309,7 @@ parse_material_thin_dielectric yaml_node_t* thin, struct solparser_material_thin_dielectric_id* out_imtl) { - enum { MEDIUM_I, MEDIUM_T, THICKNESS }; + enum { MEDIUM_I, MEDIUM_T, NORMAL_MAP, THICKNESS }; struct solparser_material_thin_dielectric* mtl = NULL; size_t imtl = SIZE_MAX; int mask = 0; /* Register the parsed attributes */ @@ -434,7 +356,10 @@ parse_material_thin_dielectric } \ mask |= BIT(Flag); \ } (void)0 - if(!strcmp((char*)key->data.scalar.value, "medium_i")) { + if(!strcmp((char*)key->data.scalar.value, "normal_map")) { + SETUP_MASK(NORMAL_MAP, "normal_map"); + res = parse_image(parser, doc, val, &mtl->normal_map); + } else if(!strcmp((char*)key->data.scalar.value, "medium_i")) { SETUP_MASK(MEDIUM_I, "medium_i"); res = parse_medium(parser, doc, val, &mtl->medium_i); } else if(!strcmp((char*)key->data.scalar.value, "medium_t")) { diff --git a/src/parser/solparser_material.h b/src/parser/solparser_material.h @@ -16,6 +16,8 @@ #ifndef SOLPARSER_MATERIAL_H #define SOLPARSER_MATERIAL_H +#include "solparser_image.h" +#include "solparser_medium.h" #include <stddef.h> enum solparser_material_type { @@ -26,41 +28,78 @@ enum solparser_material_type { SOLPARSER_MATERIAL_VIRTUAL }; -struct solparser_medium { - double refractive_index; - double absorptivity; -}; - -struct solparser_medium_id { size_t i; }; - struct solparser_material_dielectric { struct solparser_medium_id medium_i; /* Medium the material "looks at" */ struct solparser_medium_id medium_t; /* Opposite medium */ + struct solparser_image_id normal_map; }; struct solparser_material_dielectric_id { size_t i; }; +static INLINE void +solparser_material_dielectric_init + (struct mem_allocator* allocator, + struct solparser_material_dielectric* dielectric) +{ + ASSERT(dielectric); + (void)allocator; + dielectric->normal_map.i = SIZE_MAX; +} + struct solparser_material_matte { - double reflectivity; /* In [0, 1] */ + struct solparser_mtl_data reflectivity; /* In [0, 1] */ + struct solparser_image_id normal_map; }; struct solparser_material_matte_id { size_t i; }; +static INLINE void +solparser_material_matte_init + (struct mem_allocator* allocator, + struct solparser_material_matte* matte) +{ + ASSERT(matte); + (void)allocator; + matte->normal_map.i = SIZE_MAX; +} + struct solparser_material_mirror { - double roughness; /* In [0, 1] */ - double reflectivity; /* In [0, 1] */ + struct solparser_mtl_data roughness; /* In [0, 1] */ + struct solparser_mtl_data reflectivity; /* In [0, 1] */ + struct solparser_image_id normal_map; }; struct solparser_material_mirror_id { size_t i; }; +static INLINE void +solparser_material_mirror_init + (struct mem_allocator* allocator, + struct solparser_material_mirror* mirror) +{ + ASSERT(mirror); + (void)allocator; + mirror->normal_map.i = SIZE_MAX; +} + struct solparser_material_thin_dielectric { struct solparser_medium_id medium_i; /* Outside medium */ struct solparser_medium_id medium_t; /* Medium of the slab */ + struct solparser_image_id normal_map; double thickness; }; struct solparser_material_thin_dielectric_id { size_t i; }; +static INLINE void +solparser_material_thin_dielectric_init + (struct mem_allocator* allocator, + struct solparser_material_thin_dielectric* thin) +{ + ASSERT(thin); + (void)allocator; + thin->normal_map.i = SIZE_MAX; +} + struct solparser_material { enum solparser_material_type type; union { diff --git a/src/parser/solparser_medium.c b/src/parser/solparser_medium.c @@ -0,0 +1,131 @@ +/* Copyright (C) CNRS 2016-2017 + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. */ + +#define _POSIX_C_SOURCE 200112L /* nextafter support */ + +#include "solparser_c.h" +#include <math.h> /* nextafter */ + +/******************************************************************************* + * Local function + ******************************************************************************/ +res_T +parse_medium + (struct solparser* parser, + yaml_document_t* doc, + yaml_node_t* medium, + struct solparser_medium_id* out_imedium) +{ + enum { ABSORPTION, REFRACTIVE_INDEX }; + struct solparser_medium* mdm = NULL; + size_t* pimedium = NULL; + size_t imedium = SIZE_MAX; + int mask = 0; /* Register the parsed attributes */ + intptr_t i, n; + res_T res = RES_OK; + ASSERT(doc && medium && out_imedium); + + if(medium->type != YAML_MAPPING_NODE) { + log_err(parser, medium, "expect a mapping of medium attributes.\n"); + res = RES_BAD_ARG; + goto error; + } + + /* Check whether or not the YAML medium alias an already created Solstice + * medium */ + pimedium = htable_yaml2sols_find(&parser->yaml2mediums, &medium); + if(pimedium) { + imedium = *pimedium; + goto exit; + } + + /* Allocate the medium */ + imedium = darray_medium_size_get(&parser->mediums); + res = darray_medium_resize(&parser->mediums, imedium + 1); + if(res != RES_OK) { + log_err(parser, medium, "could not allocate the medium.\n"); + res = RES_BAD_ARG; + goto error; + } + mdm = darray_medium_data_get(&parser->mediums) + imedium; + + n = medium->data.mapping.pairs.top - medium->data.mapping.pairs.start; + FOR_EACH(i, 0, n) { + yaml_node_t* key; + yaml_node_t* val; + + key = yaml_document_get_node(doc, medium->data.mapping.pairs.start[i].key); + val = yaml_document_get_node(doc, medium->data.mapping.pairs.start[i].value); + if(key->type != YAML_SCALAR_NODE) { + log_err(parser, key, "expect a medium parameter.\n"); + res = RES_BAD_ARG; + goto error; + } + #define SETUP_MASK(Flag, Name) { \ + if(mask & BIT(Flag)) { \ + log_err(parser, key,"the "Name" of the medium is already defined.\n");\ + res = RES_BAD_ARG; \ + goto error; \ + } \ + mask |= BIT(Flag); \ + } (void)0 + if(!strcmp((char*)key->data.scalar.value, "absorption")) { + SETUP_MASK(ABSORPTION, "absorption"); + res = parse_mtl_data(parser, doc, val, 0, DBL_MAX, &mdm->absorption); + } else if(!strcmp((char*)key->data.scalar.value, "refractive_index")) { + SETUP_MASK(REFRACTIVE_INDEX, "refractive_index"); + res = parse_mtl_data + (parser, doc, val, nextafter(0, 1), DBL_MAX, &mdm->refractive_index); + } else { + log_err(parser, key, "unknown medium parameter `%s'.\n", + key->data.scalar.value); + res = RES_BAD_ARG; + goto error; + } + if(res != RES_OK) { + log_node(parser, key); + goto error; + } + #undef SETUP_MASK + } + + #define CHECK_PARAM(Flag, Name) \ + if(!(mask & BIT(Flag))) { \ + log_err(parser, medium, "the "Name" of the medium is missing.\n"); \ + res = RES_BAD_ARG; \ + goto error; \ + } (void)0 + CHECK_PARAM(ABSORPTION, "absorption"); + CHECK_PARAM(REFRACTIVE_INDEX, "refractive_index"); + #undef CHECK_PARAM + + /* Cache the medium */ + res = htable_yaml2sols_set(&parser->yaml2mediums, &medium, &imedium); + if(res != RES_OK) { + log_err(parser, medium, "could not register the medium.\n"); + goto error; + } + +exit: + out_imedium->i = imedium; + return res; +error: + if(imedium) { + darray_medium_pop_back(&parser->mediums); + imedium = SIZE_MAX; + } + goto exit; +} + diff --git a/src/parser/solparser_medium.h b/src/parser/solparser_medium.h @@ -0,0 +1,30 @@ +/* Copyright (C) CNRS 2016-2017 + * + * 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 SOLPARSER_MEDIUM_H +#define SOLPARSER_MEDIUM_H + +#include "solparser_mtl_data.h" +#include <stddef.h> + +struct solparser_medium { + struct solparser_mtl_data refractive_index; + struct solparser_mtl_data absorption; +}; + +struct solparser_medium_id { size_t i; }; + +#endif /* SOLPARSER_MEDIUM_H */ + diff --git a/src/parser/solparser_mtl_data.c b/src/parser/solparser_mtl_data.c @@ -0,0 +1,56 @@ +/* Copyright (C) CNRS 2016-2017 + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. */ + +#include "solparser_c.h" + +/******************************************************************************* + * Local function + ******************************************************************************/ +res_T +parse_mtl_data + (struct solparser* parser, + yaml_document_t* doc, + yaml_node_t* mtl_data, + const double lower_bound, + const double upper_bound, + struct solparser_mtl_data* data) +{ + res_T res = RES_OK; + ASSERT(doc && mtl_data && data); + + if(mtl_data->type == YAML_SCALAR_NODE) { + data->type = SOLPARSER_MTL_DATA_REAL; + res = parse_real + (parser, mtl_data, lower_bound, upper_bound, &data->value.real); + } else if(mtl_data->type == YAML_SEQUENCE_NODE) { + data->type = SOLPARSER_MTL_DATA_SPECTRUM; + res = parse_spectrum + (parser, doc, mtl_data, lower_bound, upper_bound, &data->value.spectrum); + } else { + log_err(parser, mtl_data, "expect a real or a spectrum definition.\n"); + res = RES_BAD_ARG; + goto error; + } + if(res != RES_OK) { + log_node(parser, mtl_data); + goto error; + } + +exit: + return res; +error: + goto exit; +} + diff --git a/src/parser/solparser_mtl_data.h b/src/parser/solparser_mtl_data.h @@ -0,0 +1,35 @@ +/* Copyright (C) CNRS 2016-2017 + * + * 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 SOLPARSER_MTL_DATA_H +#define SOLPARSER_MTL_DATA_H + +#include "solparser_spectrum.h" + +enum solparser_mtl_data_type { + SOLPARSER_MTL_DATA_REAL, + SOLPARSER_MTL_DATA_SPECTRUM +}; + +struct solparser_mtl_data { + enum solparser_mtl_data_type type; + union { + double real; + struct solparser_spectrum_id spectrum; + } value; +}; + +#endif /* SOLPARSER_MTL_DATA_H */ + diff --git a/src/parser/solparser_pivot.c b/src/parser/solparser_pivot.c @@ -191,6 +191,7 @@ parse_x_pivot solxpivot = darray_x_pivot_data_get(&parser->x_pivots) + isolpivot; n = x_pivot->data.mapping.pairs.top - x_pivot->data.mapping.pairs.start; + d3_splat(solxpivot->ref_point, 0); /* default value */ FOR_EACH(i, 0, n) { yaml_node_t* key; yaml_node_t* val; @@ -240,15 +241,6 @@ parse_x_pivot CHECK_PARAM(TARGET, "target"); #undef CHECK_PARAM - #define DEFAULT_PARAM(Flag, Ptr, Value) \ - if(!(mask & BIT(Flag))) { \ - *(Ptr) = Value; \ - } (void)0 - DEFAULT_PARAM(REF_POINT, solxpivot->ref_point, 0); - DEFAULT_PARAM(REF_POINT, solxpivot->ref_point+1, 0); - DEFAULT_PARAM(REF_POINT, solxpivot->ref_point+2, 0); - #undef DEFAULT_PARAM - exit: out_isolpivot->i = isolpivot; return res; @@ -292,6 +284,8 @@ parse_zx_pivot solxzpivot = darray_zx_pivot_data_get(&parser->zx_pivots) + isolpivot; n = zx_pivot->data.mapping.pairs.top - zx_pivot->data.mapping.pairs.start; + solxzpivot->spacing = 0; /* default value */ + d3_splat(solxzpivot->ref_point, 0); /* default value */ FOR_EACH(i, 0, n) { yaml_node_t* key; yaml_node_t* val; @@ -348,16 +342,6 @@ parse_zx_pivot CHECK_PARAM(TARGET, "target"); #undef CHECK_PARAM - #define DEFAULT_PARAM(Flag, Ptr, Value) \ - if(!(mask & BIT(Flag))) { \ - *(Ptr) = Value; \ - } (void)0 - DEFAULT_PARAM(SPACING, &solxzpivot->spacing, 0); - DEFAULT_PARAM(REF_POINT, solxzpivot->ref_point, 0); - DEFAULT_PARAM(REF_POINT, solxzpivot->ref_point+1, 0); - DEFAULT_PARAM(REF_POINT, solxzpivot->ref_point+2, 0); - #undef DEFAULT_PARAM - exit: out_isolpivot->i = isolpivot; return res; diff --git a/src/parser/solparser_shape.h b/src/parser/solparser_shape.h @@ -26,6 +26,11 @@ enum solparser_clip_op { SOLPARSER_CLIP_OP_SUB }; +enum solparser_clip_contour_type { + SOLPARSER_CLIP_CONTOUR_CIRCLE, + SOLPARSER_CLIP_CONTOUR_POLY +}; + enum solparser_shape_type { SOLPARSER_SHAPE_CUBOID, SOLPARSER_SHAPE_CYLINDER, @@ -33,6 +38,7 @@ enum solparser_shape_type { SOLPARSER_SHAPE_PARABOL, SOLPARSER_SHAPE_PARABOLIC_CYLINDER, SOLPARSER_SHAPE_HYPERBOL, + SOLPARSER_SHAPE_HEMISPHERE, SOLPARSER_SHAPE_PLANE, SOLPARSER_SHAPE_SPHERE, SOLPARSER_SHAPE_STL /* Imported STereo Lithography */ @@ -41,9 +47,17 @@ enum solparser_shape_type { /******************************************************************************* * Clipping polygon ******************************************************************************/ +struct solparser_circleclip { + double radius; + double center[2]; + long segments; +}; + struct solparser_polyclip { enum solparser_clip_op op; + enum solparser_clip_contour_type contour_type; struct darray_double vertices; + struct solparser_circleclip circle; }; static INLINE void @@ -260,6 +274,55 @@ solparser_shape_hyperboloid_copy_and_release } /******************************************************************************* +* Hemisphere shape +******************************************************************************/ +struct solparser_shape_hemisphere { + double radius; + struct darray_polyclip polyclips; + long nslices; /* < 0 if not defined */ +}; + +static INLINE void +solparser_shape_hemisphere_init + (struct mem_allocator* allocator, + struct solparser_shape_hemisphere* hemisphere) +{ + ASSERT(hemisphere); + hemisphere->nslices = -1; + darray_polyclip_init(allocator, &hemisphere->polyclips); +} + +static INLINE void +solparser_shape_hemisphere_release + (struct solparser_shape_hemisphere* hemisphere) +{ + ASSERT(hemisphere); + darray_polyclip_release(&hemisphere->polyclips); +} + +static INLINE res_T +solparser_shape_hemisphere_copy + (struct solparser_shape_hemisphere* dst, + const struct solparser_shape_hemisphere* src) +{ + ASSERT(dst && src); + dst->radius = src->radius; + dst->nslices = src->nslices; + return darray_polyclip_copy(&dst->polyclips, &src->polyclips); +} + +static INLINE res_T +solparser_shape_hemisphere_copy_and_release + (struct solparser_shape_hemisphere* dst, + struct solparser_shape_hemisphere* src) +{ + ASSERT(dst && src); + dst->radius = src->radius; + dst->nslices = src->nslices; + return darray_polyclip_copy_and_release(&dst->polyclips, &src->polyclips); +} + +/******************************************************************************* * Plane shape ******************************************************************************/ struct solparser_shape_plane { @@ -315,11 +378,13 @@ struct solparser_shape_cylinder { double height; double radius; long nslices; + long nstacks; }; struct solparser_shape_sphere { double radius; long nslices; + long nstacks; }; struct solparser_shape_cuboid_id { size_t i; }; @@ -327,6 +392,7 @@ struct solparser_shape_cylinder_id { size_t i; }; struct solparser_shape_imported_geometry_id { size_t i; }; struct solparser_shape_paraboloid_id { size_t i; }; struct solparser_shape_hyperboloid_id { size_t i; }; +struct solparser_shape_hemisphere_id { size_t i; }; struct solparser_shape_plane_id { size_t i; }; struct solparser_shape_sphere_id { size_t i; }; @@ -339,6 +405,7 @@ struct solparser_shape { struct solparser_shape_paraboloid_id parabol; struct solparser_shape_paraboloid_id parabolic_cylinder; struct solparser_shape_hyperboloid_id hyperbol; + struct solparser_shape_hemisphere_id hemisphere; struct solparser_shape_plane_id plane; struct solparser_shape_sphere_id sphere; struct solparser_shape_imported_geometry_id stl; diff --git a/src/parser/solparser_spectrum.c b/src/parser/solparser_spectrum.c @@ -13,25 +13,39 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ +#define _POSIX_C_SOURCE 200112L /* nextafter support */ + #include "solparser_c.h" /******************************************************************************* * Helper functions ******************************************************************************/ +static int +cmp_spectrum_data(const void* op0, const void* op1) +{ + const struct solparser_spectrum_data* a = op0; + const struct solparser_spectrum_data* b = op1; + ASSERT(a && b); + if(a->wavelength < b->wavelength) return -1; + if(a->wavelength > b->wavelength) return 1; + return 0; +} + static res_T parse_spectrum_data (struct solparser* parser, yaml_document_t* doc, + const yaml_node_t* sdata, const double lower_bound, const double upper_bound, - const yaml_node_t* sdata, struct solparser_spectrum_data* spectrum_data) { enum { DATA, WAVELENGTH }; intptr_t i, n; int mask = 0; /* Register the parsed attributes */ res_T res = RES_OK; - ASSERT(doc && sdata && lower_bound < upper_bound && spectrum_data); + ASSERT(doc && sdata && spectrum_data); + ASSERT(lower_bound <= upper_bound); if(sdata->type != YAML_MAPPING_NODE) { log_err(parser, sdata, "expect the definition of a spectrum data.\n"); @@ -63,10 +77,12 @@ parse_spectrum_data } (void)0 if(!strcmp((char*)key->data.scalar.value, "data")) { SETUP_MASK(DATA, "data"); - res = parse_real(parser, val, lower_bound, upper_bound, &spectrum_data->data); + res = parse_real + (parser, val, lower_bound, upper_bound, &spectrum_data->data); } else if(!strcmp((char*)key->data.scalar.value, "wavelength")) { SETUP_MASK(WAVELENGTH, "wavelength"); - res = parse_real(parser, val, 0, DBL_MAX, &spectrum_data->wavelength); + res = parse_real(parser, val, nextafter(0, DBL_MAX), DBL_MAX, + &spectrum_data->wavelength); } else { log_err(parser, key, "unknown spectrum data parameter `%s'.\n", key->data.scalar.value); @@ -103,14 +119,17 @@ res_T parse_spectrum (struct solparser* parser, yaml_document_t* doc, + const yaml_node_t* spectrum, const double lower_bound, const double upper_bound, - const yaml_node_t* spectrum, - struct darray_spectrum_data* data) + struct solparser_spectrum_id* out_ispectrum) { + struct solparser_spectrum* spec = NULL; + size_t ispec = SIZE_MAX; intptr_t i, n; res_T res = RES_OK; - ASSERT(doc && spectrum && lower_bound < upper_bound && data); + ASSERT(doc && spectrum && out_ispectrum); + ASSERT(lower_bound <= upper_bound); if(spectrum->type != YAML_SEQUENCE_NODE) { log_err(parser, spectrum, "expect a list of spectrum data.\n"); @@ -118,8 +137,17 @@ parse_spectrum goto error; } + /* Allocate the spectrum */ + ispec = darray_spectrum_size_get(&parser->spectra); + res = darray_spectrum_resize(&parser->spectra, ispec + 1); + if(res != RES_OK) { + log_err(parser, spectrum, "could not allocate the spectrum.\n"); + goto error; + } + spec = darray_spectrum_data_get(&parser->spectra) + ispec; + n = spectrum->data.sequence.items.top - spectrum->data.sequence.items.start; - res = darray_spectrum_data_resize(data, (size_t)n); + res = darray_spectrum_data_resize(&spec->data, (size_t)n); if(res != RES_OK) { log_err(parser, spectrum, "could not allocate the list of spectrum data.\n"); goto error; @@ -130,16 +158,42 @@ parse_spectrum struct solparser_spectrum_data* spectrum_data; sdata = yaml_document_get_node(doc, spectrum->data.sequence.items.start[i]); - spectrum_data = darray_spectrum_data_data_get(data) + i; + spectrum_data = darray_spectrum_data_data_get(&spec->data) + i; res = parse_spectrum_data - (parser, doc, lower_bound, upper_bound, sdata, spectrum_data); + (parser, doc, sdata, lower_bound, upper_bound, spectrum_data); if(res != RES_OK) goto error; } + if(n == 1) goto exit; + + qsort + (darray_spectrum_data_data_get(&spec->data), + darray_spectrum_data_size_get(&spec->data), + sizeof(struct solparser_spectrum_data), + cmp_spectrum_data); + + FOR_EACH(i, 1, n) { + const struct solparser_spectrum_data* a; + const struct solparser_spectrum_data* b; + a = darray_spectrum_data_cdata_get(&spec->data) + i - 1; + b = darray_spectrum_data_cdata_get(&spec->data) + i; + ASSERT(cmp_spectrum_data(a, b) <= 0); + if(a->wavelength == b->wavelength) { + log_err(parser, spectrum, + "duplicated spectrum entry for the wavelength %g\n", a->wavelength); + res = RES_BAD_ARG; + goto error; + } + } + exit: + out_ispectrum->i = ispec; return res; error: - darray_spectrum_data_clear(data); + if(spec) { + darray_spectrum_pop_back(&parser->spectra); + ispec = SIZE_MAX; + } goto exit; } diff --git a/src/parser/solparser_spectrum.h b/src/parser/solparser_spectrum.h @@ -27,5 +27,44 @@ struct solparser_spectrum_data { #define DARRAY_DATA struct solparser_spectrum_data #include <rsys/dynamic_array.h> +struct solparser_spectrum { + struct darray_spectrum_data data; +}; + +struct solparser_spectrum_id { size_t i; }; + +static INLINE void +solparser_spectrum_init + (struct mem_allocator* allocator, struct solparser_spectrum* spectrum) +{ + ASSERT(spectrum); + darray_spectrum_data_init(allocator, &spectrum->data); +} + +static INLINE void +solparser_spectrum_release(struct solparser_spectrum* spectrum) +{ + ASSERT(spectrum); + darray_spectrum_data_release(&spectrum->data); +} + +static INLINE res_T +solparser_spectrum_copy + (struct solparser_spectrum* dst, + const struct solparser_spectrum* src) +{ + ASSERT(dst && src); + return darray_spectrum_data_copy(&dst->data, &src->data); +} + +static INLINE res_T +solparser_spectrum_copy_and_release + (struct solparser_spectrum* dst, + struct solparser_spectrum* src) +{ + ASSERT(dst && src); + return darray_spectrum_data_copy_and_release(&dst->data, &src->data); +} + #endif /* SOLPARSER_SPECTRUM_H */ diff --git a/src/parser/solparser_sun.c b/src/parser/solparser_sun.c @@ -222,7 +222,7 @@ parse_sun res = parse_pillbox(parser, doc, val, &solsun->radang_distrib.pillbox); } else if(!strcmp((char*)key->data.scalar.value, "spectrum")) { SETUP_MASK(SPECTRUM, "spectrum"); - res = parse_spectrum(parser, doc, 0, DBL_MAX, val, &solsun->spectrum); + res = parse_spectrum(parser, doc, val, 0, DBL_MAX, &solsun->spectrum); } else { log_err(parser, key, "unknown sun parameter `%s'.\n", key->data.scalar.value); @@ -243,7 +243,6 @@ parse_sun goto error; \ } (void)0 CHECK_PARAM(DNI, "dni"); - CHECK_PARAM(SPECTRUM, "spectrum"); #undef CHECK_PARAM exit: diff --git a/src/parser/solparser_sun.h b/src/parser/solparser_sun.h @@ -30,7 +30,7 @@ struct solparser_sun_pillbox { double aperture; }; struct solparser_sun { double dni; /* In ]0, INF) */ - struct darray_spectrum_data spectrum; + struct solparser_spectrum_id spectrum; enum solparser_sun_radang_distrib_type radang_distrib_type; union { struct solparser_sun_buie buie; @@ -42,38 +42,25 @@ static INLINE void solparser_sun_init(struct mem_allocator* allocator, struct solparser_sun* sun) { ASSERT(sun); + (void)allocator; sun->dni = 1.0; sun->radang_distrib_type = SOLPARSER_SUN_RADANG_DISTRIB_DIRECTIONAL; - darray_spectrum_data_init(allocator, &sun->spectrum); + sun->spectrum.i = SIZE_MAX; } static INLINE void solparser_sun_release(struct solparser_sun* sun) { ASSERT(sun); - darray_spectrum_data_release(&sun->spectrum); -} - -static INLINE res_T -solparser_sun_copy(struct solparser_sun* dst, const struct solparser_sun* src) -{ - ASSERT(dst && src); - return darray_spectrum_data_copy(&dst->spectrum, &src->spectrum); -} - -static INLINE res_T -solparser_sun_copy_and_release - (struct solparser_sun* dst, struct solparser_sun* src) -{ - ASSERT(dst && src); - return darray_spectrum_data_copy_and_release(&dst->spectrum, &src->spectrum); + (void)sun; + /* Do nothing */ } static INLINE void solparser_sun_clear(struct solparser_sun* sun) { ASSERT(sun); - darray_spectrum_data_clear(&sun->spectrum); + sun->spectrum.i = SIZE_MAX; } #endif /* SOLPARSER_SUN_H */ diff --git a/src/parser/test_solparser2.c b/src/parser/test_solparser2.c @@ -40,6 +40,7 @@ main(int argc, char** argv) const struct solparser_material_mirror* mirror; const struct solparser_shape_sphere* sphere; const struct solparser_sun* sun; + const struct solparser_spectrum* spectrum; size_t nmtls = 0; size_t ngeoms = 0; double tmp[3]; @@ -78,6 +79,8 @@ main(int argc, char** argv) fprintf(stream, "- sun:\n"); fprintf(stream, " dni: 1\n"); fprintf(stream, " spectrum: [ { wavelength: 1, data: 1} ]\n"); + fprintf(stream, "- atmosphere:\n"); + fprintf(stream, " absorption: 0\n"); rewind(stream); CHECK(solparser_setup(parser, NULL, stream), RES_OK); @@ -114,7 +117,7 @@ main(int argc, char** argv) entity_id = solparser_entity_iterator_get(&it); entity = solparser_get_entity(parser, entity_id); - + CHECK(strcmp("lvl 0", str_cget(&entity->name)), 0); CHECK(solparser_entity_get_children_count(entity), 2); CHECK(entity->type, SOLPARSER_ENTITY_GEOMETRY); @@ -136,7 +139,8 @@ main(int argc, char** argv) CHECK(mtl == mtls[0] || mtl == mtls[1], 1); CHECK(mtl->type, SOLPARSER_MATERIAL_MATTE); matte = solparser_get_material_matte(parser, mtl->data.matte); - CHECK(matte->reflectivity, 1); + CHECK(matte->reflectivity.type, SOLPARSER_MTL_DATA_REAL); + CHECK(matte->reflectivity.value.real, 1); entity_id = solparser_entity_get_child(entity, 0); entity1a = solparser_get_entity(parser, entity_id); @@ -164,8 +168,10 @@ main(int argc, char** argv) CHECK(mtl == mtls[0] || mtl == mtls[1], 1); CHECK(mtl->type, SOLPARSER_MATERIAL_MIRROR); mirror = solparser_get_material_mirror(parser, mtl->data.mirror); - CHECK(mirror->reflectivity, 0.9); - CHECK(mirror->roughness, 0.1); + CHECK(mirror->reflectivity.type, SOLPARSER_MTL_DATA_REAL); + CHECK(mirror->reflectivity.value.real, 0.9); + CHECK(mirror->roughness.type, SOLPARSER_MTL_DATA_REAL); + CHECK(mirror->roughness.value.real, 0.1); entity_id = solparser_entity_get_child(entity, 1); entity1b = solparser_get_entity(parser, entity_id); @@ -203,9 +209,11 @@ main(int argc, char** argv) NCHECK(sun, NULL); CHECK(sun->dni, 1.0); CHECK(sun->radang_distrib_type, SOLPARSER_SUN_RADANG_DISTRIB_DIRECTIONAL); - CHECK(darray_spectrum_data_size_get(&sun->spectrum), 1); - CHECK(darray_spectrum_data_cdata_get(&sun->spectrum)[0].wavelength, 1.0); - CHECK(darray_spectrum_data_cdata_get(&sun->spectrum)[0].data, 1.0); + CHECK(SOLPARSER_ID_IS_VALID(sun->spectrum), 1); + spectrum = solparser_get_spectrum(parser, sun->spectrum); + CHECK(darray_spectrum_data_size_get(&spectrum->data), 1); + CHECK(darray_spectrum_data_cdata_get(&spectrum->data)[0].wavelength, 1.0); + CHECK(darray_spectrum_data_cdata_get(&spectrum->data)[0].data, 1.0); CHECK(solparser_load(parser), RES_BAD_OP); solparser_ref_put(parser); diff --git a/src/parser/test_solparser3.c b/src/parser/test_solparser3.c @@ -32,9 +32,18 @@ static const char* input[] = { " - operation : AND\n", " vertices : [[1, 2],[3, 4],[6, 7]]\n", " material: *lambertian\n", + "- geometry: &hemisphere1\n", + " - hemisphere:\n", + " radius: 100\n", + " clip:\n", + " - operation : AND\n", + " circle: { radius: 4 }\n", + " material: *lambertian\n", "- sun: \n", " dni: 1\n", " spectrum: [{wavelength: 1, data: 1}]\n", + "- atmosphere:\n", + " absorption: [{wavelength: 1, data: 1}]\n", "- entity:\n", " name: entity0\n", " primary: 0\n", @@ -61,6 +70,9 @@ static const char* input[] = { " - name: entity0c\n", " primary: 0\n", " geometry: *hyperbol1\n", + " - name: entity0d\n", + " primary: 0\n", + " geometry: *hemisphere1\n", "- entity:\n", " name: entity1\n", " x_pivot:\n", @@ -95,7 +107,7 @@ check_entity0 struct solparser_anchor_id anchor_id; struct solparser_entity_id entity_id; struct solparser_object_id obj_id; - const struct solparser_entity *entity0a, *entity0b; + const struct solparser_entity *entity0a, *entity0b, *entity0c, *entity0d; const struct solparser_material_matte* matte; const struct solparser_material* mtl; const struct solparser_material_double_sided* mtl2; @@ -135,9 +147,10 @@ check_entity0 CHECK(mtl->type, SOLPARSER_MATERIAL_MATTE); matte = solparser_get_material_matte(parser, mtl->data.matte); - CHECK(matte->reflectivity, 0.5); + CHECK(matte->reflectivity.type, SOLPARSER_MTL_DATA_REAL); + CHECK(matte->reflectivity.value.real, 0.5); - CHECK(solparser_entity_get_children_count(entity0), 3); + CHECK(solparser_entity_get_children_count(entity0), 4); CHECK(solparser_entity_get_anchors_count(entity0), 3); anchor_id = solparser_entity_get_anchor(entity0, 0); @@ -186,6 +199,22 @@ check_entity0 entity0_entity0b_entity0b = solparser_get_anchor(parser, anchor_id); CHECK(strcmp(str_cget(&entity0_entity0b_entity0b->name), "entity0b"), 0); CHECK(d3_eq(entity0_entity0b_entity0b->position, d3(tmp, 7, 8, 9)), 1); + + entity_id = solparser_entity_get_child(entity0, 2); + entity0c = solparser_get_entity(parser, entity_id); + CHECK(strcmp(str_cget(&entity0c->name), "entity0c"), 0); + CHECK(entity0c->type, SOLPARSER_ENTITY_GEOMETRY); + NCHECK(entity0->data.geometry.i, entity0c->data.geometry.i); + CHECK(solparser_entity_get_anchors_count(entity0c), 0); + CHECK(solparser_entity_get_children_count(entity0c), 0); + + entity_id = solparser_entity_get_child(entity0, 3); + entity0d = solparser_get_entity(parser, entity_id); + CHECK(strcmp(str_cget(&entity0d->name), "entity0d"), 0); + CHECK(entity0d->type, SOLPARSER_ENTITY_GEOMETRY); + NCHECK(entity0->data.geometry.i, entity0d->data.geometry.i); + CHECK(solparser_entity_get_anchors_count(entity0d), 0); + CHECK(solparser_entity_get_children_count(entity0d), 0); } static void diff --git a/src/parser/test_solparser4.c b/src/parser/test_solparser4.c @@ -159,8 +159,10 @@ main(int argc, char** argv) mtl = solparser_get_material(parser, mtl2->front); CHECK(mtl->type, SOLPARSER_MATERIAL_MIRROR); mirror = solparser_get_material_mirror(parser, mtl->data.mirror); - CHECK(mirror->reflectivity, 0.2); - CHECK(mirror->roughness, 0.1); + CHECK(mirror->reflectivity.type, SOLPARSER_MTL_DATA_REAL); + CHECK(mirror->reflectivity.value.real, 0.2); + CHECK(mirror->roughness.type, SOLPARSER_MTL_DATA_REAL); + CHECK(mirror->roughness.value.real, 0.1); shape = solparser_get_shape(parser, obj->shape); CHECK(shape->type, SOLPARSER_SHAPE_CUBOID); diff --git a/src/parser/test_solparser6.c b/src/parser/test_solparser6.c @@ -35,6 +35,7 @@ main(int argc, char** argv) const struct solparser_shape_paraboloid* parabol; const struct solparser_shape_plane* plane; const struct solparser_shape_hyperboloid* hyperbol; + const struct solparser_shape_hemisphere* hemisphere; const struct solparser_polyclip* polyclip; double pos[2]; FILE* stream; @@ -70,7 +71,13 @@ main(int argc, char** argv) fprintf(stream, " - plane:\n"); fprintf(stream, " clip :\n"); fprintf(stream, " - operation : AND\n"); - fprintf(stream, " vertices : [[1, 2], [3, 4], [6, 7]]\n"); + fprintf(stream, " circle : { radius: 1, center: [-1, 1], segments: 8 }\n"); + fprintf(stream, " material: { ?virtual }\n"); + fprintf(stream, " - hemisphere:\n"); + fprintf(stream, " radius: 100\n"); + fprintf(stream, " clip :\n"); + fprintf(stream, " - operation : AND\n"); + fprintf(stream, " circle : { radius: 1 }\n"); fprintf(stream, " material: { ?virtual }\n"); rewind(stream); @@ -88,7 +95,7 @@ main(int argc, char** argv) CHECK(solparser_entity_get_children_count(entity), 0); CHECK(entity->type, SOLPARSER_ENTITY_GEOMETRY); geom = solparser_get_geometry(parser, entity->data.geometry); - CHECK(solparser_geometry_get_objects_count(geom), 4); + CHECK(solparser_geometry_get_objects_count(geom), 5); obj_id = solparser_geometry_get_object(geom, 0); obj = solparser_get_object(parser, obj_id); @@ -108,6 +115,7 @@ main(int argc, char** argv) CHECK(darray_polyclip_size_get(&parabol->polyclips), 1); polyclip = darray_polyclip_cdata_get(&parabol->polyclips); CHECK(polyclip->op, SOLPARSER_CLIP_OP_AND); + CHECK(polyclip->contour_type, SOLPARSER_CLIP_CONTOUR_POLY); CHECK(solparser_polyclip_get_vertices_count(polyclip), 3); solparser_polyclip_get_vertex(polyclip, 0, pos); CHECK(pos[0], 1); @@ -139,6 +147,28 @@ main(int argc, char** argv) CHECK(shape->type, SOLPARSER_SHAPE_PLANE); plane = solparser_get_shape_plane(parser, shape->data.plane); CHECK(plane->nslices, 1); /* Default value */ + CHECK(darray_polyclip_size_get(&plane->polyclips), 1); + polyclip = darray_polyclip_cdata_get(&plane->polyclips); + CHECK(polyclip->contour_type, SOLPARSER_CLIP_CONTOUR_CIRCLE); + CHECK(polyclip->circle.radius, 1); + CHECK(polyclip->circle.center[0], -1); + CHECK(polyclip->circle.center[1], 1); + CHECK(polyclip->circle.segments, 8); + + obj_id = solparser_geometry_get_object(geom, 4); + obj = solparser_get_object(parser, obj_id); + shape = solparser_get_shape(parser, obj->shape); + CHECK(shape->type, SOLPARSER_SHAPE_HEMISPHERE); + hemisphere = solparser_get_shape_hemisphere(parser, shape->data.hemisphere);; + CHECK(hemisphere->radius, 100); + CHECK(hemisphere->nslices, -1); /* Default value: auto */ + CHECK(darray_polyclip_size_get(&hemisphere->polyclips), 1); + polyclip = darray_polyclip_cdata_get(&hemisphere->polyclips); + CHECK(polyclip->contour_type, SOLPARSER_CLIP_CONTOUR_CIRCLE); + CHECK(polyclip->circle.radius, 1); + CHECK(polyclip->circle.center[0], 0); /* default value */ + CHECK(polyclip->circle.center[1], 0); /* default value */ + CHECK(polyclip->circle.segments, 64); /* Default value */ solparser_entity_iterator_next(&it); CHECK(solparser_entity_iterator_eq(&it, &end), 1); diff --git a/src/parser/test_solparser7.c b/src/parser/test_solparser7.c @@ -33,6 +33,7 @@ main(int argc, char** argv) const struct solparser_medium* medium; const struct solparser_object* obj; const struct solparser_shape* shape; + const struct solparser_spectrum* spectrum; FILE* stream; (void)argc, (void)argv; @@ -53,10 +54,18 @@ main(int argc, char** argv) fprintf(stream, " thickness: 0.123\n"); fprintf(stream, " medium_i: &outside\n"); fprintf(stream, " refractive_index: 1\n"); - fprintf(stream, " absorptivity: 0\n"); + fprintf(stream, " absorption: 0\n"); fprintf(stream, " medium_t: &inside\n"); - fprintf(stream, " refractive_index: 1.5\n"); - fprintf(stream, " absorptivity: 20\n"); + fprintf(stream, " refractive_index: \n"); + fprintf(stream, " - {wavelength: 1.2, data: 2.3}\n"); + fprintf(stream, " - {wavelength: 4.5, data: 6.7}\n"); + fprintf(stream, " - {wavelength: 0.5, data: 0.25}\n"); + fprintf(stream, " absorption:\n"); + fprintf(stream, " - {wavelength: 3, data: 3}\n"); + fprintf(stream, " - {wavelength: 1, data: 1}\n"); + fprintf(stream, " - {wavelength: 5, data: 5}\n"); + fprintf(stream, " - {wavelength: 4, data: 4}\n"); + fprintf(stream, " - {wavelength: 2, data: 2}\n"); rewind(stream); CHECK(solparser_setup(parser, NULL, stream), RES_OK); @@ -87,11 +96,35 @@ main(int argc, char** argv) CHECK(thin->thickness, 0.123); medium = solparser_get_medium(parser, thin->medium_i); - CHECK(medium->refractive_index, 1); - CHECK(medium->absorptivity, 0); + CHECK(medium->refractive_index.type, SOLPARSER_MTL_DATA_REAL); + CHECK(medium->refractive_index.value.real, 1); + CHECK(medium->absorption.type, SOLPARSER_MTL_DATA_REAL); + CHECK(medium->absorption.value.real, 0); medium = solparser_get_medium(parser, thin->medium_t); - CHECK(medium->refractive_index, 1.5); - CHECK(medium->absorptivity, 20); + + CHECK(medium->refractive_index.type, SOLPARSER_MTL_DATA_SPECTRUM); + spectrum = solparser_get_spectrum(parser, medium->refractive_index.value.spectrum); + CHECK(darray_spectrum_data_size_get(&spectrum->data), 3); + CHECK(darray_spectrum_data_cdata_get(&spectrum->data)[0].wavelength, 0.5); + CHECK(darray_spectrum_data_cdata_get(&spectrum->data)[1].wavelength, 1.2); + CHECK(darray_spectrum_data_cdata_get(&spectrum->data)[2].wavelength, 4.5); + CHECK(darray_spectrum_data_cdata_get(&spectrum->data)[0].data, 0.25); + CHECK(darray_spectrum_data_cdata_get(&spectrum->data)[1].data, 2.3); + CHECK(darray_spectrum_data_cdata_get(&spectrum->data)[2].data, 6.7); + + CHECK(medium->absorption.type, SOLPARSER_MTL_DATA_SPECTRUM); + spectrum = solparser_get_spectrum(parser, medium->absorption.value.spectrum); + CHECK(darray_spectrum_data_size_get(&spectrum->data), 5); + CHECK(darray_spectrum_data_cdata_get(&spectrum->data)[0].wavelength, 1); + CHECK(darray_spectrum_data_cdata_get(&spectrum->data)[1].wavelength, 2); + CHECK(darray_spectrum_data_cdata_get(&spectrum->data)[2].wavelength, 3); + CHECK(darray_spectrum_data_cdata_get(&spectrum->data)[3].wavelength, 4); + CHECK(darray_spectrum_data_cdata_get(&spectrum->data)[4].wavelength, 5); + CHECK(darray_spectrum_data_cdata_get(&spectrum->data)[0].data, 1); + CHECK(darray_spectrum_data_cdata_get(&spectrum->data)[1].data, 2); + CHECK(darray_spectrum_data_cdata_get(&spectrum->data)[2].data, 3); + CHECK(darray_spectrum_data_cdata_get(&spectrum->data)[3].data, 4); + CHECK(darray_spectrum_data_cdata_get(&spectrum->data)[4].data, 5); CHECK(solparser_load(parser), RES_BAD_OP); solparser_ref_put(parser); diff --git a/src/parser/test_solparser8.c b/src/parser/test_solparser8.c @@ -27,22 +27,34 @@ main(int argc, char** argv) struct solparser_object_id obj_id; const struct solparser_entity* entity; const struct solparser_geometry* geom; - const struct solparser_medium* medium; + const struct solparser_medium* vacuum; + const struct solparser_medium* glass; const struct solparser_material_double_sided* mtl2; const struct solparser_material* mtl; const struct solparser_material_dielectric* dielec; const struct solparser_object* obj; const struct solparser_shape* shape; + const struct solparser_spectrum* spectrum; FILE* stream; (void)argc, (void)argv; CHECK(mem_init_proxy_allocator(&allocator, &mem_default_allocator), RES_OK); - solparser_create(&allocator, &parser); + CHECK(solparser_create(&allocator, &parser), RES_OK); stream = tmpfile(); NCHECK(stream, NULL); fprintf(stream, "- sun: { dni: 1, spectrum: [{wavelength: 1, data: 1 }] }\n"); + fprintf(stream, "- medium: &vacuum {refractive_index: 1, absorption: 0}\n"); + fprintf(stream, "- medium: &glass \n"); + fprintf(stream, " refractive_index: 1.5\n"); + fprintf(stream, " absorption: \n"); + fprintf(stream, " - {wavelength: 1, data: 21}\n"); + fprintf(stream, " - {wavelength: 2, data: 22}\n"); + fprintf(stream, " - {wavelength: 3, data: 23}\n"); + fprintf(stream, " - {wavelength: 4, data: 24}\n"); + fprintf(stream, " - {wavelength: 5, data: 25}\n"); + fprintf(stream, " - {wavelength: 6, data: 26}\n"); fprintf(stream, "- entity:\n"); fprintf(stream, " name: test\n"); fprintf(stream, " primary: 0\n"); @@ -51,16 +63,12 @@ main(int argc, char** argv) fprintf(stream, " material:\n"); fprintf(stream, " front:\n"); fprintf(stream, " dielectric:\n"); - fprintf(stream, " medium_i: &outside\n"); - fprintf(stream, " refractive_index: 1\n"); - fprintf(stream, " absorptivity: 0\n"); - fprintf(stream, " medium_t: &inside\n"); - fprintf(stream, " refractive_index: 1.5\n"); - fprintf(stream, " absorptivity: 20\n"); + fprintf(stream, " medium_i: *vacuum\n"); + fprintf(stream, " medium_t: *glass\n"); fprintf(stream, " back:\n"); fprintf(stream, " dielectric:\n"); - fprintf(stream, " medium_i: *inside\n"); - fprintf(stream, " medium_t: *outside\n"); + fprintf(stream, " medium_i: *glass\n"); + fprintf(stream, " medium_t: *vacuum\n"); rewind(stream); CHECK(solparser_setup(parser, NULL, stream), RES_OK); @@ -88,22 +96,36 @@ main(int argc, char** argv) mtl = solparser_get_material(parser, mtl2->front); CHECK(mtl->type, SOLPARSER_MATERIAL_DIELECTRIC); dielec = solparser_get_material_dielectric(parser, mtl->data.dielectric); - medium = solparser_get_medium(parser, dielec->medium_i); - CHECK(medium->refractive_index, 1); - CHECK(medium->absorptivity, 0); - medium = solparser_get_medium(parser, dielec->medium_t); - CHECK(medium->refractive_index, 1.5); - CHECK(medium->absorptivity, 20); + vacuum = solparser_get_medium(parser, dielec->medium_i); + CHECK(vacuum->refractive_index.type, SOLPARSER_MTL_DATA_REAL); + CHECK(vacuum->refractive_index.value.real, 1); + CHECK(vacuum->absorption.type, SOLPARSER_MTL_DATA_REAL); + CHECK(vacuum->absorption.value.real, 0); + + glass = solparser_get_medium(parser, dielec->medium_t); + CHECK(glass->refractive_index.type, SOLPARSER_MTL_DATA_REAL); + CHECK(glass->refractive_index.value.real, 1.5); + CHECK(glass->absorption.type, SOLPARSER_MTL_DATA_SPECTRUM); + spectrum = solparser_get_spectrum(parser, glass->absorption.value.spectrum); + CHECK(darray_spectrum_data_size_get(&spectrum->data), 6); + CHECK(darray_spectrum_data_cdata_get(&spectrum->data)[0].wavelength, 1); + CHECK(darray_spectrum_data_cdata_get(&spectrum->data)[1].wavelength, 2); + CHECK(darray_spectrum_data_cdata_get(&spectrum->data)[2].wavelength, 3); + CHECK(darray_spectrum_data_cdata_get(&spectrum->data)[3].wavelength, 4); + CHECK(darray_spectrum_data_cdata_get(&spectrum->data)[4].wavelength, 5); + CHECK(darray_spectrum_data_cdata_get(&spectrum->data)[5].wavelength, 6); + CHECK(darray_spectrum_data_cdata_get(&spectrum->data)[0].data, 21); + CHECK(darray_spectrum_data_cdata_get(&spectrum->data)[1].data, 22); + CHECK(darray_spectrum_data_cdata_get(&spectrum->data)[2].data, 23); + CHECK(darray_spectrum_data_cdata_get(&spectrum->data)[3].data, 24); + CHECK(darray_spectrum_data_cdata_get(&spectrum->data)[4].data, 25); + CHECK(darray_spectrum_data_cdata_get(&spectrum->data)[5].data, 26); mtl = solparser_get_material(parser, mtl2->back); CHECK(mtl->type, SOLPARSER_MATERIAL_DIELECTRIC); dielec = solparser_get_material_dielectric(parser, mtl->data.dielectric); - medium = solparser_get_medium(parser, dielec->medium_i); - CHECK(medium->refractive_index, 1.5); - CHECK(medium->absorptivity, 20); - medium = solparser_get_medium(parser, dielec->medium_t); - CHECK(medium->refractive_index, 1); - CHECK(medium->absorptivity, 0); + CHECK(solparser_get_medium(parser, dielec->medium_i), glass); + CHECK(solparser_get_medium(parser, dielec->medium_t), vacuum); CHECK(solparser_load(parser), RES_BAD_OP); solparser_ref_put(parser); diff --git a/src/parser/test_solparser_normal_map.c b/src/parser/test_solparser_normal_map.c @@ -0,0 +1,338 @@ +/* Copyright (C) CNRS 2016-2017 + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. */ + +#include "solparser.h" +#include "test_solstice_utils.h" + +static void +test_dielectric(struct solparser* parser) +{ + struct solparser_entity_iterator it, end; + struct solparser_entity_id entity_id; + struct solparser_object_id obj_id; + const struct solparser_entity* entity; + const struct solparser_image* img; + const struct solparser_geometry* geom; + const struct solparser_material_double_sided* mtl2; + const struct solparser_material* mtl; + const struct solparser_material_dielectric* dielectric; + const struct solparser_object* obj; + const struct solparser_shape* shape; + FILE* stream; + + stream = tmpfile(); + NCHECK(stream, NULL); + + fprintf(stream, "- sun: {dni: 1, spectrum: [{wavelength: 1, data: 1} ]}\n"); + fprintf(stream, "\n"); + fprintf(stream, "- material: &glass\n"); + fprintf(stream, " front:\n"); + fprintf(stream, " dielectric:\n"); + fprintf(stream, " medium_i: &out {refractive_index: 1, absorption: 0}\n"); + fprintf(stream, " medium_t: &in {refractive_index: 1.5, absorption: 20}\n"); + fprintf(stream, " normal_map: {path: my_normal_map}\n"); + fprintf(stream, " back: {dielectric: {medium_i: *in, medium_t: *out}}\n"); + fprintf(stream, "\n"); + fprintf(stream, "- entity:\n"); + fprintf(stream, " name: foo\n"); + fprintf(stream, " primary: 1\n"); + fprintf(stream, " geometry:\n"); + fprintf(stream, " - cylinder: { radius: 2, height: 2 }\n"); + fprintf(stream, " material: *glass\n"); + rewind(stream); + + CHECK(solparser_setup(parser, NULL, stream), RES_OK); + CHECK(solparser_load(parser), RES_OK); + + solparser_entity_iterator_begin(parser, &it); + solparser_entity_iterator_end(parser, &end); + CHECK(solparser_entity_iterator_eq(&it, &end), 0); + + entity_id = solparser_entity_iterator_get(&it); + entity = solparser_get_entity(parser, entity_id); + + CHECK(strcmp("foo", str_cget(&entity->name)), 0); + CHECK(solparser_entity_get_children_count(entity), 0); + CHECK(entity->type, SOLPARSER_ENTITY_GEOMETRY); + CHECK(entity->primary, 1); + geom = solparser_get_geometry(parser, entity->data.geometry); + CHECK(solparser_geometry_get_objects_count(geom), 1); + obj_id = solparser_geometry_get_object(geom, 0); + obj = solparser_get_object(parser, obj_id); + shape = solparser_get_shape(parser, obj->shape); + CHECK(shape->type, SOLPARSER_SHAPE_CYLINDER); + mtl2 = solparser_get_material_double_sided(parser, obj->mtl2); + NCHECK(mtl2->front.i, mtl2->back.i); + + mtl = solparser_get_material(parser, mtl2->front); + CHECK(mtl->type, SOLPARSER_MATERIAL_DIELECTRIC); + dielectric = solparser_get_material_dielectric(parser, mtl->data.dielectric); + CHECK(SOLPARSER_ID_IS_VALID(dielectric->normal_map), 1); + img = solparser_get_image(parser, dielectric->normal_map); + CHECK(strcmp(str_cget(&img->filename), "my_normal_map"), 0); + + mtl = solparser_get_material(parser, mtl2->back); + CHECK(mtl->type, SOLPARSER_MATERIAL_DIELECTRIC); + dielectric = solparser_get_material_dielectric(parser, mtl->data.dielectric); + CHECK(SOLPARSER_ID_IS_VALID(dielectric->normal_map), 0); + + solparser_entity_iterator_next(&it); + CHECK(solparser_entity_iterator_eq(&it, &end), 1); + + CHECK(solparser_load(parser), RES_BAD_OP); + fclose(stream); +} + +static void +test_matte(struct solparser* parser) +{ + struct solparser_entity_iterator it, end; + struct solparser_entity_id entity_id; + struct solparser_object_id obj_id; + const struct solparser_entity* entity; + const struct solparser_image* img; + const struct solparser_geometry* geom; + const struct solparser_material_double_sided* mtl2; + const struct solparser_material* mtl; + const struct solparser_material_matte* matte; + const struct solparser_object* obj; + const struct solparser_shape* shape; + FILE* stream; + + stream = tmpfile(); + NCHECK(stream, NULL); + + fprintf(stream, "- sun: { dni: 1, spectrum: [{wavelength: 1, data: 1} ] }\n"); + fprintf(stream, "- entity:\n"); + fprintf(stream, " name: test\n"); + fprintf(stream, " primary: 0\n"); + fprintf(stream, " geometry:\n"); + fprintf(stream, " - sphere: { radius: 1 }\n"); + fprintf(stream, " material:\n"); + fprintf(stream, " matte:\n"); + fprintf(stream, " reflectivity: 0.123\n"); + fprintf(stream, " normal_map: { path: \"path to normal map\" }\n"); + rewind(stream); + + CHECK(solparser_setup(parser, NULL, stream), RES_OK); + CHECK(solparser_load(parser), RES_OK); + + solparser_entity_iterator_begin(parser, &it); + solparser_entity_iterator_end(parser, &end); + CHECK(solparser_entity_iterator_eq(&it, &end), 0); + + entity_id = solparser_entity_iterator_get(&it); + entity = solparser_get_entity(parser, entity_id); + + CHECK(strcmp("test", str_cget(&entity->name)), 0); + CHECK(solparser_entity_get_children_count(entity), 0); + CHECK(entity->primary, 0); + CHECK(entity->type, SOLPARSER_ENTITY_GEOMETRY); + geom = solparser_get_geometry(parser, entity->data.geometry); + CHECK(solparser_geometry_get_objects_count(geom), 1); + obj_id = solparser_geometry_get_object(geom, 0); + obj = solparser_get_object(parser, obj_id); + shape = solparser_get_shape(parser, obj->shape); + CHECK(shape->type, SOLPARSER_SHAPE_SPHERE); + mtl2 = solparser_get_material_double_sided(parser, obj->mtl2); + CHECK(mtl2->front.i, mtl2->back.i); + + mtl = solparser_get_material(parser, mtl2->front); + CHECK(mtl->type, SOLPARSER_MATERIAL_MATTE); + matte = solparser_get_material_matte(parser, mtl->data.matte); + CHECK(matte->reflectivity.type, SOLPARSER_MTL_DATA_REAL); + CHECK(matte->reflectivity.value.real, 0.123); + CHECK(SOLPARSER_ID_IS_VALID(matte->normal_map), 1); + img = solparser_get_image(parser, matte->normal_map); + CHECK(strcmp(str_cget(&img->filename), "path to normal map"), 0); + + solparser_entity_iterator_next(&it); + CHECK(solparser_entity_iterator_eq(&it, &end), 1); + + CHECK(solparser_load(parser), RES_BAD_OP); + fclose(stream); +} + +static void +test_mirror(struct solparser* parser) +{ + struct solparser_entity_iterator it, end; + struct solparser_entity_id entity_id; + struct solparser_object_id obj_id; + const struct solparser_entity* entity; + const struct solparser_image* img; + const struct solparser_geometry* geom; + const struct solparser_material_double_sided* mtl2; + const struct solparser_material* mtl; + const struct solparser_material_mirror* mirror; + const struct solparser_object* obj; + const struct solparser_shape* shape; + FILE* stream; + + stream = tmpfile(); + NCHECK(stream, NULL); + + fprintf(stream, "- sun: { dni: 1, spectrum: [{wavelength: 1, data: 1} ] }\n"); + fprintf(stream, "- entity: \n"); + fprintf(stream, " name: my entity\n"); + fprintf(stream, " primary: 0\n"); + fprintf(stream, " geometry: \n"); + fprintf(stream, " - cuboid: { size: [1, 1, 1] }\n"); + fprintf(stream, " material: \n"); + fprintf(stream, " mirror:\n"); + fprintf(stream, " reflectivity: 1\n"); + fprintf(stream, " roughness: 0.1\n"); + fprintf(stream, " normal_map: { path: Normal map } \n"); + rewind(stream); + + CHECK(solparser_setup(parser, NULL, stream), RES_OK); + CHECK(solparser_load(parser), RES_OK); + + solparser_entity_iterator_begin(parser, &it); + solparser_entity_iterator_end(parser, &end); + CHECK(solparser_entity_iterator_eq(&it, &end), 0); + + entity_id = solparser_entity_iterator_get(&it); + entity = solparser_get_entity(parser, entity_id); + + CHECK(strcmp("my entity", str_cget(&entity->name)), 0); + CHECK(solparser_entity_get_children_count(entity), 0); + CHECK(entity->primary, 0); + CHECK(entity->type, SOLPARSER_ENTITY_GEOMETRY); + geom = solparser_get_geometry(parser, entity->data.geometry); + CHECK(solparser_geometry_get_objects_count(geom), 1); + obj_id = solparser_geometry_get_object(geom, 0); + obj = solparser_get_object(parser, obj_id); + shape = solparser_get_shape(parser, obj->shape); + CHECK(shape->type, SOLPARSER_SHAPE_CUBOID); + mtl2 = solparser_get_material_double_sided(parser, obj->mtl2); + CHECK(mtl2->front.i, mtl2->back.i); + + mtl = solparser_get_material(parser, mtl2->front); + CHECK(mtl->type, SOLPARSER_MATERIAL_MIRROR); + mirror = solparser_get_material_mirror(parser, mtl->data.mirror); + CHECK(mirror->reflectivity.type, SOLPARSER_MTL_DATA_REAL); + CHECK(mirror->reflectivity.value.real, 1); + CHECK(mirror->roughness.type, SOLPARSER_MTL_DATA_REAL); + CHECK(mirror->roughness.value.real, 0.1); + CHECK(SOLPARSER_ID_IS_VALID(mirror->normal_map), 1); + img = solparser_get_image(parser, mirror->normal_map); + CHECK(strcmp(str_cget(&img->filename), "Normal map"), 0); + + solparser_entity_iterator_next(&it); + CHECK(solparser_entity_iterator_eq(&it, &end), 1); + + CHECK(solparser_load(parser), RES_BAD_OP); + fclose(stream); +} + +static void +test_thin_dielectric(struct solparser* parser) +{ + struct solparser_entity_iterator it, end; + struct solparser_entity_id entity_id; + struct solparser_object_id obj_id; + const struct solparser_entity* entity; + const struct solparser_image* img; + const struct solparser_geometry* geom; + const struct solparser_material_double_sided* mtl2; + const struct solparser_material* mtl; + const struct solparser_material_thin_dielectric* thin; + const struct solparser_object* obj; + const struct solparser_shape* shape; + FILE* stream; + + stream = tmpfile(); + NCHECK(stream, NULL); + fprintf(stream, "- sun: { dni: 1, spectrum: [{wavelength: 1, data: 1} ] }\n"); + fprintf(stream, "- entity:\n"); + fprintf(stream, " name: test\n"); + fprintf(stream, " primary: 0\n"); + fprintf(stream, " geometry:\n"); + fprintf(stream, " - sphere: { radius: 1 }\n"); + fprintf(stream, " material:\n"); + fprintf(stream, " thin_dielectric:\n"); + fprintf(stream, " thickness: 0.1\n"); + fprintf(stream, " medium_i:\n"); + fprintf(stream, " refractive_index: 1\n"); + fprintf(stream, " absorption: 0\n"); + fprintf(stream, " medium_t:\n"); + fprintf(stream, " refractive_index: 1.5\n"); + fprintf(stream, " absorption: 20\n"); + fprintf(stream, " normal_map: { path: Bump }\n"); + rewind(stream); + + CHECK(solparser_setup(parser, NULL, stream), RES_OK); + CHECK(solparser_load(parser), RES_OK); + + solparser_entity_iterator_begin(parser, &it); + solparser_entity_iterator_end(parser, &end); + CHECK(solparser_entity_iterator_eq(&it, &end), 0); + + entity_id = solparser_entity_iterator_get(&it); + entity = solparser_get_entity(parser, entity_id); + + CHECK(strcmp("test", str_cget(&entity->name)), 0); + CHECK(solparser_entity_get_children_count(entity), 0); + CHECK(entity->primary, 0); + CHECK(entity->type, SOLPARSER_ENTITY_GEOMETRY); + geom = solparser_get_geometry(parser, entity->data.geometry); + CHECK(solparser_geometry_get_objects_count(geom), 1); + obj_id = solparser_geometry_get_object(geom, 0); + obj = solparser_get_object(parser, obj_id); + shape = solparser_get_shape(parser, obj->shape); + CHECK(shape->type, SOLPARSER_SHAPE_SPHERE); + mtl2 = solparser_get_material_double_sided(parser, obj->mtl2); + CHECK(mtl2->front.i, mtl2->back.i); + + mtl = solparser_get_material(parser, mtl2->front); + CHECK(mtl->type, SOLPARSER_MATERIAL_THIN_DIELECTRIC); + thin = solparser_get_material_thin_dielectric(parser, mtl->data.thin_dielectric); + CHECK(thin->thickness, 0.1); + NCHECK(thin->medium_i.i, thin->medium_t.i); + CHECK(SOLPARSER_ID_IS_VALID(thin->normal_map), 1); + img = solparser_get_image(parser, thin->normal_map); + CHECK(strcmp(str_cget(&img->filename), "Bump"), 0); + + solparser_entity_iterator_next(&it); + CHECK(solparser_entity_iterator_eq(&it, &end), 1); + + CHECK(solparser_load(parser), RES_BAD_OP); + fclose(stream); +} + +int +main(int argc, char** argv) +{ + struct mem_allocator allocator; + struct solparser* parser; + (void)argc, (void)argv; + + CHECK(mem_init_proxy_allocator(&allocator, &mem_default_allocator), RES_OK); + CHECK(solparser_create(&allocator, &parser), RES_OK); + + test_dielectric(parser); + test_matte(parser); + test_mirror(parser); + test_thin_dielectric(parser); + + solparser_ref_put(parser); + + check_memory_allocator(&allocator); + mem_shutdown_proxy_allocator(&allocator); + CHECK(mem_allocated_size(), 0); + return 0; +} + diff --git a/src/parser/test_solparser_spectrum.c b/src/parser/test_solparser_spectrum.c @@ -0,0 +1,355 @@ +/* Copyright (C) CNRS 2016-2017 + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. */ + +#include "solparser.h" +#include "solparser_sun.h" +#include "test_solstice_utils.h" + +static void +test_sun(struct solparser* parser) +{ + const struct solparser_sun* sun; + const struct solparser_spectrum* spectrum; + FILE* stream; + size_t i; + + NCHECK(stream = tmpfile(), NULL); + + fprintf(stream, "- spectrum: &my_spectrum\n"); + fprintf(stream, " - { wavelength: 2, data: 2 }\n"); + fprintf(stream, " - { wavelength: 1, data: 1 }\n"); + fprintf(stream, " - { wavelength: 8, data: 8 }\n"); + fprintf(stream, " - { wavelength: 3, data: 3 }\n"); + fprintf(stream, " - { wavelength: 5, data: 5 }\n"); + fprintf(stream, " - { wavelength: 9, data: 9 }\n"); + fprintf(stream, " - { wavelength: 6, data: 6 }\n"); + fprintf(stream, " - { wavelength: 7, data: 7 }\n"); + fprintf(stream, " - { wavelength: 4, data: 4 }\n"); + fprintf(stream, "- sun:\n"); + fprintf(stream, " dni: 123.456\n"); + fprintf(stream, " spectrum: *my_spectrum\n"); + fprintf(stream, "- material: &matte { matte: { reflectivity: 1 } }\n"); + fprintf(stream, "- entity:\n"); + fprintf(stream, " name: foo bar\n"); + fprintf(stream, " primary: 0\n"); + fprintf(stream, " geometry: [{sphere: {radius: 1}, material: *matte}]\n"); + rewind(stream); + + CHECK(solparser_setup(parser, NULL, stream), RES_OK); + CHECK(solparser_load(parser), RES_OK); + + sun = solparser_get_sun(parser); + CHECK(sun->dni, 123.456); + CHECK(sun->radang_distrib_type, SOLPARSER_SUN_RADANG_DISTRIB_DIRECTIONAL); + CHECK(SOLPARSER_ID_IS_VALID(sun->spectrum), 1); + spectrum = solparser_get_spectrum(parser, sun->spectrum); + + CHECK(darray_spectrum_data_size_get(&spectrum->data), 9); + + FOR_EACH(i, 0, darray_spectrum_data_size_get(&spectrum->data)) { + CHECK(darray_spectrum_data_cdata_get(&spectrum->data)[i].wavelength, i+1); + CHECK(darray_spectrum_data_cdata_get(&spectrum->data)[i].wavelength, i+1); + } + + CHECK(solparser_load(parser), RES_BAD_OP); + fclose(stream); + + NCHECK(stream = tmpfile(), NULL); + fprintf(stream, "- sun: {dni: 1}\n"); + rewind(stream); + + CHECK(solparser_setup(parser, NULL, stream), RES_OK); + CHECK(solparser_load(parser), RES_OK); + + CHECK(SOLPARSER_ID_IS_VALID(sun->spectrum), 0); + + CHECK(solparser_load(parser), RES_BAD_OP); + fclose(stream); +} + +static void +test_matte(struct solparser* parser) +{ + struct solparser_material_iterator mtl_it, mtl_it_end; + const struct solparser_material* mtl; + const struct solparser_material_matte* matte; + const struct solparser_spectrum* spectrum; + FILE* stream; + + NCHECK(stream = tmpfile(), NULL); + + fprintf(stream, "- sun: { dni: 1 }\n"); + fprintf(stream, "- material:\n"); + fprintf(stream, " matte:\n"); + fprintf(stream, " reflectivity:\n"); + fprintf(stream, " - { wavelength: 3.4, data: 0.5 }\n"); + fprintf(stream, " - { wavelength: 1.2, data: 0.25 }\n"); + fprintf(stream, " - { wavelength: 6.7, data: 0.125 }\n"); + rewind(stream); + + CHECK(solparser_setup(parser, NULL, stream), RES_OK); + CHECK(solparser_load(parser), RES_OK); + + solparser_material_iterator_begin(parser, &mtl_it); + solparser_material_iterator_end(parser, &mtl_it_end); + CHECK(solparser_material_iterator_eq(&mtl_it, &mtl_it_end), 0); + + mtl = solparser_get_material(parser, solparser_material_iterator_get(&mtl_it)); + CHECK(mtl->type, SOLPARSER_MATERIAL_MATTE); + matte = solparser_get_material_matte(parser, mtl->data.matte); + CHECK(matte->reflectivity.type, SOLPARSER_MTL_DATA_SPECTRUM); + CHECK(SOLPARSER_ID_IS_VALID(matte->normal_map), 0); + spectrum = solparser_get_spectrum(parser, matte->reflectivity.value.spectrum); + CHECK(darray_spectrum_data_size_get(&spectrum->data), 3); + CHECK(darray_spectrum_data_cdata_get(&spectrum->data)[0].wavelength, 1.2); + CHECK(darray_spectrum_data_cdata_get(&spectrum->data)[1].wavelength, 3.4); + CHECK(darray_spectrum_data_cdata_get(&spectrum->data)[2].wavelength, 6.7); + CHECK(darray_spectrum_data_cdata_get(&spectrum->data)[0].data, 0.25); + CHECK(darray_spectrum_data_cdata_get(&spectrum->data)[1].data, 0.5); + CHECK(darray_spectrum_data_cdata_get(&spectrum->data)[2].data, 0.125); + + solparser_material_iterator_next(&mtl_it); + CHECK(solparser_material_iterator_eq(&mtl_it, &mtl_it_end), 1); + + CHECK(solparser_load(parser), RES_BAD_OP); + fclose(stream); +} + +static void +test_mirror(struct solparser* parser) +{ + struct solparser_material_iterator mtl_it, mtl_it_end; + const struct solparser_material* mtl; + const struct solparser_material_mirror* mirror; + const struct solparser_spectrum* spectrum; + FILE* stream; + + NCHECK(stream = tmpfile(), NULL); + + fprintf(stream, "- sun: { dni: 1 }\n"); + fprintf(stream, "- material:\n"); + fprintf(stream, " mirror:\n"); + fprintf(stream, " reflectivity:\n"); + fprintf(stream, " - { wavelength: 3.4, data: 0.5 }\n"); + fprintf(stream, " - { wavelength: 1.2, data: 0.25 }\n"); + fprintf(stream, " - { wavelength: 6.7, data: 0.125 }\n"); + fprintf(stream, " roughness:\n"); + fprintf(stream, " - { wavelength: 123, data: 0 }\n"); + fprintf(stream, " - { wavelength: 456, data: 1 }\n"); + rewind(stream); + + CHECK(solparser_setup(parser, NULL, stream), RES_OK); + CHECK(solparser_load(parser), RES_OK); + + solparser_material_iterator_begin(parser, &mtl_it); + solparser_material_iterator_end(parser, &mtl_it_end); + CHECK(solparser_material_iterator_eq(&mtl_it, &mtl_it_end), 0); + + mtl = solparser_get_material(parser, solparser_material_iterator_get(&mtl_it)); + CHECK(mtl->type, SOLPARSER_MATERIAL_MIRROR); + mirror = solparser_get_material_mirror(parser, mtl->data.mirror); + CHECK(mirror->reflectivity.type, SOLPARSER_MTL_DATA_SPECTRUM); + CHECK(mirror->roughness.type, SOLPARSER_MTL_DATA_SPECTRUM); + CHECK(SOLPARSER_ID_IS_VALID(mirror->normal_map), 0); + + spectrum = solparser_get_spectrum(parser, mirror->reflectivity.value.spectrum); + CHECK(darray_spectrum_data_size_get(&spectrum->data), 3); + CHECK(darray_spectrum_data_cdata_get(&spectrum->data)[0].wavelength, 1.2); + CHECK(darray_spectrum_data_cdata_get(&spectrum->data)[1].wavelength, 3.4); + CHECK(darray_spectrum_data_cdata_get(&spectrum->data)[2].wavelength, 6.7); + CHECK(darray_spectrum_data_cdata_get(&spectrum->data)[0].data, 0.25); + CHECK(darray_spectrum_data_cdata_get(&spectrum->data)[1].data, 0.5); + CHECK(darray_spectrum_data_cdata_get(&spectrum->data)[2].data, 0.125); + + spectrum = solparser_get_spectrum(parser, mirror->roughness.value.spectrum); + CHECK(darray_spectrum_data_size_get(&spectrum->data), 2); + CHECK(darray_spectrum_data_cdata_get(&spectrum->data)[0].wavelength, 123); + CHECK(darray_spectrum_data_cdata_get(&spectrum->data)[1].wavelength, 456); + CHECK(darray_spectrum_data_cdata_get(&spectrum->data)[0].data, 0); + CHECK(darray_spectrum_data_cdata_get(&spectrum->data)[1].data, 1); + + solparser_material_iterator_next(&mtl_it); + CHECK(solparser_material_iterator_eq(&mtl_it, &mtl_it_end), 1); + + CHECK(solparser_load(parser), RES_BAD_OP); + fclose(stream); +} + +static void +test_thin_dielectric(struct solparser* parser) +{ + struct solparser_material_iterator mtl_it, mtl_it_end; + const struct solparser_material* mtl; + const struct solparser_material_thin_dielectric* thin; + const struct solparser_medium* mdm; + const struct solparser_spectrum* spectrum; + FILE* stream; + + NCHECK(stream = tmpfile(), NULL); + + fprintf(stream, "- sun: { dni: 1 }\n"); + fprintf(stream, "- spectrum: &refractive_index\n"); + fprintf(stream, " - { wavelength: 123, data: 1.1 }\n"); + fprintf(stream, " - { wavelength: 456, data: 2.2 }\n"); + fprintf(stream, " - { wavelength: 789, data: 3.3 }\n"); + fprintf(stream, "- spectrum: &absorption\n"); + fprintf(stream, " - { wavelength: 0.456, data: 0.2 }\n"); + fprintf(stream, " - { wavelength: 0.123, data: 0.1 }\n"); + fprintf(stream, "- material:\n"); + fprintf(stream, " thin_dielectric:\n"); + fprintf(stream, " thickness: 1\n"); + fprintf(stream, " medium_i: { refractive_index: 1, absorption: 0 }\n"); + fprintf(stream, " medium_t: \n"); + fprintf(stream, " refractive_index: *refractive_index\n"); + fprintf(stream, " absorption: *absorption\n"); + rewind(stream); + + CHECK(solparser_setup(parser, NULL, stream), RES_OK); + CHECK(solparser_load(parser), RES_OK); + + solparser_material_iterator_begin(parser, &mtl_it); + solparser_material_iterator_end(parser, &mtl_it_end); + CHECK(solparser_material_iterator_eq(&mtl_it, &mtl_it_end), 0); + + mtl = solparser_get_material(parser, solparser_material_iterator_get(&mtl_it)); + CHECK(mtl->type, SOLPARSER_MATERIAL_THIN_DIELECTRIC); + thin = solparser_get_material_thin_dielectric(parser, mtl->data.thin_dielectric); + CHECK(thin->thickness, 1); + CHECK(SOLPARSER_ID_IS_VALID(thin->normal_map), 0); + + mdm = solparser_get_medium(parser, thin->medium_i); + CHECK(mdm->refractive_index.type, SOLPARSER_MTL_DATA_REAL); + CHECK(mdm->refractive_index.value.real, 1); + CHECK(mdm->absorption.type, SOLPARSER_MTL_DATA_REAL); + CHECK(mdm->absorption.value.real, 0); + + mdm = solparser_get_medium(parser, thin->medium_t); + CHECK(mdm->refractive_index.type, SOLPARSER_MTL_DATA_SPECTRUM); + spectrum = solparser_get_spectrum(parser, mdm->refractive_index.value.spectrum); + CHECK(darray_spectrum_data_size_get(&spectrum->data), 3); + CHECK(darray_spectrum_data_cdata_get(&spectrum->data)[0].wavelength, 123); + CHECK(darray_spectrum_data_cdata_get(&spectrum->data)[1].wavelength, 456); + CHECK(darray_spectrum_data_cdata_get(&spectrum->data)[2].wavelength, 789); + CHECK(darray_spectrum_data_cdata_get(&spectrum->data)[0].data, 1.1); + CHECK(darray_spectrum_data_cdata_get(&spectrum->data)[1].data, 2.2); + CHECK(darray_spectrum_data_cdata_get(&spectrum->data)[2].data, 3.3); + spectrum = solparser_get_spectrum(parser, mdm->absorption.value.spectrum); + CHECK(darray_spectrum_data_size_get(&spectrum->data), 2); + CHECK(darray_spectrum_data_cdata_get(&spectrum->data)[0].wavelength, 0.123); + CHECK(darray_spectrum_data_cdata_get(&spectrum->data)[1].wavelength, 0.456); + CHECK(darray_spectrum_data_cdata_get(&spectrum->data)[0].data, 0.1); + CHECK(darray_spectrum_data_cdata_get(&spectrum->data)[1].data, 0.2); + + solparser_material_iterator_next(&mtl_it); + CHECK(solparser_material_iterator_eq(&mtl_it, &mtl_it_end), 1); + + CHECK(solparser_load(parser), RES_BAD_OP); + fclose(stream); +} + +static void +test_dielectric(struct solparser* parser) +{ + struct solparser_material_iterator mtl_it, mtl_it_end; + const struct solparser_material* mtl; + const struct solparser_material_dielectric* dielec; + const struct solparser_medium* mdm; + const struct solparser_spectrum* spectrum; + FILE* stream; + + NCHECK(stream = tmpfile(), NULL); + + fprintf(stream, "- sun: { dni: 1 }\n"); + fprintf(stream, "- spectrum: &refractive_index\n"); + fprintf(stream, " - { wavelength: 123, data: 1.1 }\n"); + fprintf(stream, " - { wavelength: 456, data: 2.2 }\n"); + fprintf(stream, " - { wavelength: 789, data: 3.3 }\n"); + fprintf(stream, "- spectrum: &absorption\n"); + fprintf(stream, " - { wavelength: 0.456, data: 0.2 }\n"); + fprintf(stream, " - { wavelength: 0.123, data: 0.1 }\n"); + fprintf(stream, "- material:\n"); + fprintf(stream, " dielectric:\n"); + fprintf(stream, " medium_i: { refractive_index: 1, absorption: 0 }\n"); + fprintf(stream, " medium_t: \n"); + fprintf(stream, " refractive_index: *refractive_index\n"); + fprintf(stream, " absorption: *absorption\n"); + rewind(stream); + + CHECK(solparser_setup(parser, NULL, stream), RES_OK); + CHECK(solparser_load(parser), RES_OK); + + solparser_material_iterator_begin(parser, &mtl_it); + solparser_material_iterator_end(parser, &mtl_it_end); + CHECK(solparser_material_iterator_eq(&mtl_it, &mtl_it_end), 0); + + mtl = solparser_get_material(parser, solparser_material_iterator_get(&mtl_it)); + CHECK(mtl->type, SOLPARSER_MATERIAL_DIELECTRIC); + dielec = solparser_get_material_dielectric(parser, mtl->data.dielectric); + CHECK(SOLPARSER_ID_IS_VALID(dielec->normal_map), 0); + + mdm = solparser_get_medium(parser, dielec->medium_i); + CHECK(mdm->refractive_index.type, SOLPARSER_MTL_DATA_REAL); + CHECK(mdm->refractive_index.value.real, 1); + CHECK(mdm->absorption.type, SOLPARSER_MTL_DATA_REAL); + CHECK(mdm->absorption.value.real, 0); + + mdm = solparser_get_medium(parser, dielec->medium_t); + CHECK(mdm->refractive_index.type, SOLPARSER_MTL_DATA_SPECTRUM); + spectrum = solparser_get_spectrum(parser, mdm->refractive_index.value.spectrum); + CHECK(darray_spectrum_data_size_get(&spectrum->data), 3); + CHECK(darray_spectrum_data_cdata_get(&spectrum->data)[0].wavelength, 123); + CHECK(darray_spectrum_data_cdata_get(&spectrum->data)[1].wavelength, 456); + CHECK(darray_spectrum_data_cdata_get(&spectrum->data)[2].wavelength, 789); + CHECK(darray_spectrum_data_cdata_get(&spectrum->data)[0].data, 1.1); + CHECK(darray_spectrum_data_cdata_get(&spectrum->data)[1].data, 2.2); + CHECK(darray_spectrum_data_cdata_get(&spectrum->data)[2].data, 3.3); + spectrum = solparser_get_spectrum(parser, mdm->absorption.value.spectrum); + CHECK(darray_spectrum_data_size_get(&spectrum->data), 2); + CHECK(darray_spectrum_data_cdata_get(&spectrum->data)[0].wavelength, 0.123); + CHECK(darray_spectrum_data_cdata_get(&spectrum->data)[1].wavelength, 0.456); + CHECK(darray_spectrum_data_cdata_get(&spectrum->data)[0].data, 0.1); + CHECK(darray_spectrum_data_cdata_get(&spectrum->data)[1].data, 0.2); + + solparser_material_iterator_next(&mtl_it); + CHECK(solparser_material_iterator_eq(&mtl_it, &mtl_it_end), 1); + + CHECK(solparser_load(parser), RES_BAD_OP); + fclose(stream); +} + +int +main(int argc, char** argv) +{ + struct mem_allocator allocator; + struct solparser* parser; + (void)argc, (void)argv; + + CHECK(mem_init_proxy_allocator(&allocator, &mem_default_allocator), RES_OK); + CHECK(solparser_create(&allocator, &parser), RES_OK); + + test_sun(parser); + test_matte(parser); + test_mirror(parser); + test_thin_dielectric(parser); + test_dielectric(parser); + + solparser_ref_put(parser); + + check_memory_allocator(&allocator); + mem_shutdown_proxy_allocator(&allocator); + CHECK(mem_allocated_size(), 0); + return 0; +} + diff --git a/src/parser/yaml/test_ko_0.yaml b/src/parser/yaml/test_ko_0.yaml @@ -39,12 +39,18 @@ # data should be a number - sun: { spectrum: [{wavelength: 1, data: "dummy"}] } --- +# 0 invalid +- sun: { spectrum: [{wavelength: 0, data: 1}] } +--- # -1 invalid - sun: { spectrum: [{wavelength: -1, data: 1}] } --- # -1 invalid - sun: { spectrum: [{wavelength: 1, data: -1}] } --- +# invalid non-increasing wavelengths +- sun: { spectrum: [{wavelength: 1, data: 1}, {wavelength: 1, data: 2}] } +--- # # dni: REAL # Direct Normal Irradiance in ]0, INF) @@ -130,9 +136,6 @@ # <pillbox> | <buie> # -# missing spectrum -- sun: { dni: 1 } ---- # missing dni - sun: { spectrum: [{wavelength: 1, data: 1}] } --- @@ -201,6 +204,7 @@ # <matte> ::= # matte: # reflectivity: REAL # in [0, 1] +# [ normal_map: { path: PATH } ] # # missing matte parameters @@ -221,7 +225,25 @@ # 2x reflectivity - material: { matte: { reflectivity: 1, reflectivity: 1 } } --- - +# bad normal map +- material: + matte: { reflectivity: 1, normal_map: map } +--- +# bad normal map +- material: + matte: { reflectivity: 1, normal_map: { path: } } +--- +# Missing reflectivity +- material: + matte: { normal_map: { path: test } } +--- +# 2x normal map +- material: + matte: + reflectivity: 1 + normal_map: { path: test } + normal_map: { path: test2} +# # # <thin-dielectric> ::= # thin_dielectric: @@ -230,31 +252,31 @@ # medium_t: <dielectric-medium> # -# invalid absorptivity +# invalid absorption - material: thin_dielectric: thickness: 0 - medium_i: &m { refractive_index: 1, absorptivity: -1 } + medium_i: &m { refractive_index: 1, absorption: -1 } medium_t: *m --- # invalid thickness - material: thin_dielectric: thickness: -0.01 - medium_i: &m { refractive_index: 1, absorptivity: 0 } + medium_i: &m { refractive_index: 1, absorption: 0 } medium_t: *m --- # invalid refractive index - material: thin_dielectric: thickness: 0 - medium_i: &m { refractive_index: 0, absorptivity: 0 } + medium_i: &m { refractive_index: 0, absorption: 0 } medium_t: *m --- # missing thickness - material: thin_dielectric: - medium_i: &m { refractive_index: 1, absorptivity: 0 } + medium_i: &m { refractive_index: 1, absorption: 0 } medium_t: *m --- @@ -268,22 +290,22 @@ # invalid refractive_index - material: dielectric: - medium_i: &m { refractive_index: 0, absorptivity: 0 } + medium_i: &m { refractive_index: 0, absorption: 0 } medium_t: *m --- -# invalid absorptivity +# invalid absorption - material: dielectric: - medium_i: &m { refractive_index: 1, absorptivity: -1 } + medium_i: &m { refractive_index: 1, absorption: -1 } medium_t: *m --- # missing refractive_index - material: dielectric: - medium_i: &m { absorptivity: 0 } + medium_i: &m { absorption: 0 } medium_t: *m --- -# missing absorptivity +# missing absorption - material: dielectric: medium_i: &m { refractive_index: 1 } @@ -292,12 +314,12 @@ # missing medium_i - material: dielectric: - medium_t: { refractive_index: 1, absorptivity: 0 } + medium_t: { refractive_index: 1, absorption: 0 } --- # missing medium_t - material: dielectric: - medium_i: { refractive_index: 1, absorptivity: 0 } + medium_i: { refractive_index: 1, absorption: 0 } --- # @@ -372,7 +394,21 @@ # # <polyclip> ::= # operation: <AND|SUB> -# vertices: <vertices-list> +# <contour-descriptor> +# +# <contour-descriptor> ::= +# <vertices-descriptor> +# | <circle-descriptor> +# +# <vertices-descriptor> ::= +# vertices: <vertices-list> +# +# <circle-descriptor> ::= +# circle: +# radius: REAL # in ]0, INF) +# [ center: <real2>. Default 0,0 ] +# [ segments: INTEGER # in [3, 4096). Default 64 ] +# # # <vertices-list> ::= # - <real2> @@ -410,7 +446,7 @@ clip: - operation: dummy --- -# missing vertices parameter +# missing contour parameter - geometry: - plane: clip: @@ -449,6 +485,108 @@ - operation: AND vertices: [ [0, 1, 2], [3, 4], [6, 7] ] --- +# missing circle definition +- geometry: + - plane: + clip: + - circle: +--- +# missing radius value +- geometry: + - plane: + clip: + - circle: { radius: } +--- +# missing center description +- geometry: + - plane: + clip: + - circle: { center: } +--- +# invalid number "dummy" +- geometry: + - plane: + clip: + - operation: AND + circle: { radius: "dummy" } +--- +# invalid point "dummy" +- geometry: + - plane: + clip: + - operation: AND + circle: { center: "dummy" } +--- +# invalid point 1 +- geometry: + - plane: + clip: + - operation: AND + circle: { center: 1 } +--- +# invalid number "dummy" +- geometry: + - plane: + clip: + - operation: AND + circle: { segments: "dummy" } +--- +# 0 invalid +- geometry: + - plane: + clip: + - circle: { radius: 0 } +--- +# 2 invalid +- geometry: + - plane: + clip: + - circle: { segments: 2 } +--- +# missing radius +- geometry: + - plane: + clip: + - circle: { center: [4, -10] } +--- +# missing radius +- geometry: + - plane: + clip: + - circle: { segments: 10 } +--- +# 2x radius +- geometry: + - plane: + clip: + - circle: { radius: 1, radius: 1 } +--- +# 2x center +- geometry: + - plane: + clip: + - circle: { center: [4, -10], center: [4, -10] } +--- +# 2x segments +- geometry: + - plane: + clip: + - circle: { segments: 10, segments: 10 } +--- +# 2x contour +- geometry: + - plane: + clip: + - vertices: [ [1, 2], [3, 4], [6, 7] ] + circle: { radius: 1 } +--- +# 2x operation +- geometry: + - plane: + clip: + - operation: AND + operation: OR +--- # # <cuboid> ::= @@ -493,6 +631,7 @@ # height: REAL # in ]0, INF) # radius: REAL # in ]0, INF) # [ slices: INTEGER ] # in [4, 4096]. Default 16 +# [ stacks: INTEGER ] # in [1, 4096]. Default 1 # # missing cylinder definition @@ -522,6 +661,9 @@ # slices should be a number - geometry: [ { cylinder: { slices: "dummy" } } ] --- +# stacks +- geometry: [ { cylinder: { stacks: "dummy" } } ] +--- # -1 invalid - geometry: [ { cylinder: { radius: -1 } } ] --- @@ -543,15 +685,27 @@ # 2x slices - geometry: [ { cylinder: { slices: 10, slices: 10 } } ] --- +# stacks +- geometry: [ { cylinder: { stacks: 10, stacks: 10 } } ] +--- # 1 invalid - geometry: [ { cylinder: { height: 1, radius: 1, slices: 1 } } ] --- # 4097 invalid - geometry: [ { cylinder: { height: 1, radius: 1, slices: 4097 } } ] --- +# 0 invalid +- geometry: [ { cylinder: { height: 1, radius: 1, stacks: 0 } } ] +--- +# 4097 invalid +- geometry: [ { cylinder: { height: 1, radius: 1, stacks: 4097 } } ] +--- # 12.5 invalid - geometry: [ { cylinder: { height: 1, radius: 1, slices: 12.5 } } ] --- +# 12.5 invalid +- geometry: [ { cylinder: { height: 1, radius: 1, stacks: 12.5 } } ] +--- # # <obj> ::= @@ -862,6 +1016,9 @@ # slices should be a number - geometry: [ { sphere: { slices: "dummy" } } ] --- +# stacks should be a number +- geometry: [ { sphere: { stacks: "dummy" } } ] +--- # -1 invalid - geometry: [ { sphere: { radius: -1 } } ] --- @@ -874,12 +1031,21 @@ # 4097 invalid - geometry: [ { sphere: { radius: 1, slices: 4097 } } ] --- +# 0 invalid +- geometry: [ { sphere: { radius: 1, stacks: 0 } } ] +--- +# 4097 invalid +- geometry: [ { sphere: { radius: 1, stacks: 4097 } } ] +--- # 2x radius - geometry: [ { sphere: { radius: 1, radius: 1 } } ] --- # 2x slices - geometry: [ { sphere: { slices: 10, slices: 10 } } ] --- +# 2x stacks +- geometry: [ { sphere: { stacks: 10, stacks: 10 } } ] +--- # # <stl> ::= @@ -1729,9 +1895,49 @@ --- # +# <atmosphere> ::= +# atmosphere: +# absorption: <mtl-data> # in [0, 1] +# + +# missing atmosphere definition +- atmosphere: +--- +# unknown dummy parameter +- atmosphere: + dummy: 1 +--- +# missing absorption definition +- atmosphere: + absorption: +--- +# absorption should be a number +- atmosphere: + absorption: "dummy" +--- +# 2 invalid +- atmosphere: + absorption: 2 +--- +# 0 invalid +- atmosphere: + absorption: [{wavelength: 0, data: 1}] +--- +# 2 invalid +- atmosphere: + absorption: [{wavelength: 0, data: 2}] +--- +# 2x absorption +- atmosphere: + absorption: 0.1 + absorption: [{wavelength: 1, data: 1}] +--- + +# # <solar-factory> ::= # <sun> # <items> +# [ <atmosphere> ] # # <items> ::= # - <item> @@ -1754,4 +1960,13 @@ geometry: - cuboid: { size: [1, 2, 3] } material: { matte: { reflectivity: 1 } } - +--- +# 2x sun +- sun: { dni: 1000, spectrum: [{wavelength: 1, data: 1}] } +- sun: { dni: 1000, spectrum: [{wavelength: 1, data: 1}] } +--- +# 2x atmosphere +- atmosphere: + absorption: 0.1 +- atmosphere: + absorption: 0.1 diff --git a/src/parser/yaml/test_ok_0.yaml b/src/parser/yaml/test_ok_0.yaml @@ -50,8 +50,13 @@ - entity: { name: "hop", primary: 1, geometry: *cuboid } - sun: { dni: 1, spectrum: [{wavelength: 1, data: 1}] } --- +- spectrum: &sun_spectrum + - { wavelength: 1.1, data: 1.2 } + - { wavelength: 2.2, data: 2.3 } + - { wavelength: 3.3, data: 3.4 } + - { wavelength: 4.4, data: 4.4 } - material: &lambertian { matte: { reflectivity: 1 } } -- sun: { dni: 1, spectrum: [{wavelength: 1, data: 1}] } +- sun: { dni: 1, spectrum: *sun_spectrum } - entity: name: hop primary: 0 diff --git a/src/parser/yaml/test_ok_2.yaml b/src/parser/yaml/test_ok_2.yaml @@ -39,3 +39,16 @@ geometry: - material: { matte: { reflectivity: 1 } } stl: { path: "path/path/path" } +--- +- sun: { dni: 1, spectrum: [{wavelength: 1, data: 1}] } +- material: &lambertian + matte: + reflectivity: 0.123 + normal_map: { path: "path/to my normal map" } +- entity: + name: hop + primary: 1 + geometry: + - material: *lambertian + stl: { path: "path/path/path" } + diff --git a/src/parser/yaml/test_ok_5.yaml b/src/parser/yaml/test_ok_5.yaml @@ -3,8 +3,8 @@ - material: &thin_dielectric thin_dielectric: thickness: 1 - medium_i: { absorptivity: 0, refractive_index: 1.00027 } - medium_t: { absorptivity: 0.1, refractive_index: 1.5 } + medium_i: { absorption: 0, refractive_index: 1.00027 } + medium_t: { absorption: 0.1, refractive_index: 1.5 } - entity: name: "entity" @@ -18,8 +18,8 @@ - material: &thin_dielectric thin_dielectric: thickness: 0 - medium_i: { absorptivity: 0, refractive_index: 0.00027 } - medium_t: { absorptivity: 0.1, refractive_index: 1.5 } + medium_i: { absorption: 0, refractive_index: 0.00027 } + medium_t: { absorption: 0.1, refractive_index: 1.5 } - entity: name: "entity" @@ -38,6 +38,6 @@ material: thin_dielectric: thickness: 10 - medium_i: { absorptivity: 0, refractive_index: 1 } - medium_t: { absorptivity: 20, refractive_index: 1.5 } + medium_i: { absorption: 0, refractive_index: 1 } + medium_t: { absorption: 20, refractive_index: 1.5 } diff --git a/src/parser/yaml/test_ok_6.yaml b/src/parser/yaml/test_ok_6.yaml @@ -104,5 +104,27 @@ clip: - operation: AND vertices: [[-30.0, -20.0], [-30.0, 20.0], [30.0, 20.0], [30.0, -20.0]] - - +--- +- sun: { dni: 1, spectrum: [{wavelength: 1, data: 1}] } +- entity: + name: entity + primary: 1 + geometry: + - material: { mirror: { reflectivity: 0, roughness: 0.5 } } + hyperbol: + focals: { real: 1, image: 1 } + clip: + - operation: AND + circle: { radius: 1 } +--- +- sun: { dni: 1, spectrum: [{wavelength: 1, data: 1}] } +- entity: + name: entity + primary: 1 + geometry: + - material: { mirror: { reflectivity: 0, roughness: 0.5 } } + hyperbol: + focals: { real: 1, image: 1 } + clip: + - operation: AND + circle: { radius: 1, center: [1, 1], segments: 32 } diff --git a/src/parser/yaml/test_ok_7.yaml b/src/parser/yaml/test_ok_7.yaml @@ -2,8 +2,8 @@ - material: &dielectric dielectric: - medium_i: { absorptivity: 0, refractive_index: 1.00027 } - medium_t: { absorptivity: 0.1, refractive_index: 1.5 } + medium_i: { absorption: 0, refractive_index: 1.00027 } + medium_t: { absorption: 0.1, refractive_index: 1.5 } - entity: name: "entity" @@ -16,8 +16,8 @@ - material: &dielectric dielectric: - medium_i: { absorptivity: 0, refractive_index: 0.00027 } - medium_t: { absorptivity: 0.1, refractive_index: 1.5 } + medium_i: { absorption: 0, refractive_index: 0.00027 } + medium_t: { absorption: 0.1, refractive_index: 1.5 } - entity: name: "entity" @@ -35,6 +35,19 @@ - cylinder: { height: 1, radius: 1 } material: dielectric: - medium_i: { absorptivity: 0, refractive_index: 1 } - medium_t: { absorptivity: 20, refractive_index: 1.5 } + medium_i: { absorption: 0, refractive_index: 1 } + medium_t: { absorption: 20, refractive_index: 1.5 } + +--- +- sun: { dni: 1 } +- medium: &vacuum { refractive_index: 1, absorption: 0 } +- medium: &glass { refractive_index: 1.5, absorption: 20 } +- entity: + name: "entity" + primary: 0 + geometry: + - cylinder: { height: 1, radius: 1 } + material: + front: {dielectric: { medium_i: *vacuum, medium_t: *glass }} + back: {dielectric: {medium_i: *glass, medium_t: *vacuum}} diff --git a/src/solstice.c b/src/solstice.c @@ -48,6 +48,30 @@ * Helper functions ******************************************************************************/ static void +log_err(const char* msg, void* ctx) +{ + ASSERT(msg); + (void)ctx; +#ifdef OS_WINDOWS + fprintf(stderr, "error: %s", msg); +#else + fprintf(stderr, "\x1b[31merror:\x1b[0m %s", msg); +#endif +} + +static void +log_warn(const char* msg, void* ctx) +{ + ASSERT(msg); + (void)ctx; +#ifdef OS_WINDOWS + fprintf(stderr,"warning: %s", msg); +#else + fprintf(stderr, "\x1b[33mwarning:\x1b[0m %s", msg); +#endif +} + +static void clear_materials(struct htable_material* materials) { struct htable_material_iterator it, end; @@ -341,6 +365,7 @@ error: static res_T load_data(struct solstice* solstice, const struct solstice_args* args) { + struct solparser_entity_iterator it, end; FILE* file = stdin; const char* name = "stdin"; res_T res = RES_OK; @@ -370,6 +395,14 @@ load_data(struct solstice* solstice, const struct solstice_args* args) res = solparser_load(solstice->parser); if(res != RES_OK) goto error; + solparser_entity_iterator_begin(solstice->parser, &it); + solparser_entity_iterator_end(solstice->parser, &end); + if(solparser_entity_iterator_eq(&it, &end)) { + fprintf(stderr, "No entity is defined.\n"); + res = RES_BAD_ARG; + goto error; + } + exit: if(file && file != stdin) fclose(file); return res; @@ -536,6 +569,7 @@ solstice_init htable_object_init(allocator, &solstice->objects); htable_anchor_init(allocator, &solstice->anchors); htable_receiver_init(allocator, &solstice->receivers); + htable_primary_init(allocator, &solstice->primaries); darray_nodes_init(allocator, &solstice->roots); darray_nodes_init(allocator, &solstice->pivots); darray_double_init(allocator, &solstice->sun_dirs); @@ -543,7 +577,12 @@ solstice_init solstice->allocator = allocator ? allocator : &mem_default_allocator; - res = ssol_device_create(NULL, allocator, args->nthreads, 0, &solstice->ssol); + logger_init(solstice->allocator, &solstice->logger); + logger_set_stream(&solstice->logger, LOG_ERROR, log_err, NULL); + logger_set_stream(&solstice->logger, LOG_WARNING, log_warn, NULL); + + res = ssol_device_create(&solstice->logger, allocator, args->nthreads, + args->verbose, &solstice->ssol); if(res != RES_OK) { fprintf(stderr, "Could not create the Solstice Solver device.\n"); goto error; @@ -598,8 +637,13 @@ solstice_init goto error; } + res = solstice_create_atmosphere(solstice); + if(res != RES_OK) { + fprintf(stderr, "Could not setup the Solstice atmosphere.\n"); + goto error; + } + solstice->nexperiments = args->nexperiments; - solstice->output_hits = args->output_hits; solstice->dump_format = args->dump_format; solstice->dump_split_mode = args->dump_split_mode; solstice->dump_paths = args->dump_paths; @@ -615,6 +659,7 @@ solstice_init if(res != RES_OK) goto error; solstice->render_mode = args->render_mode; solstice->spp = args->img.spp; + d3_set(solstice->up, args->camera.up); } exit: @@ -635,6 +680,7 @@ solstice_release(struct solstice* solstice) if(solstice->ssol) SSOL(device_ref_put(solstice->ssol)); if(solstice->scene) SSOL(scene_ref_put(solstice->scene)); if(solstice->sun) SSOL(sun_ref_put(solstice->sun)); + if(solstice->atmosphere) SSOL(atmosphere_ref_put(solstice->atmosphere)); if(solstice->parser) solparser_ref_put(solstice->parser); if(solstice->camera) SSOL(camera_ref_put(solstice->camera)); if(solstice->framebuffer) SSOL(image_ref_put(solstice->framebuffer)); @@ -644,10 +690,12 @@ solstice_release(struct solstice* solstice) htable_object_release(&solstice->objects); htable_anchor_release(&solstice->anchors); htable_receiver_release(&solstice->receivers); + htable_primary_release(&solstice->primaries); darray_nodes_release(&solstice->roots); darray_nodes_release(&solstice->pivots); darray_double_release(&solstice->sun_dirs); darray_double_release(&solstice->sun_angles); + logger_release(&solstice->logger); } res_T diff --git a/src/solstice.h b/src/solstice.h @@ -22,6 +22,7 @@ #include <rsys/dynamic_array_double.h> #include <rsys/hash_table.h> +#include <rsys/logger.h> #include <rsys/mem_allocator.h> #include <rsys/str.h> @@ -38,6 +39,10 @@ struct solstice_receiver { int per_primitive; }; +struct solstice_primary { + struct solstice_node* node; +}; + #define DARRAY_NAME nodes #define DARRAY_DATA struct solstice_node* #include <rsys/dynamic_array.h> @@ -69,10 +74,22 @@ struct solstice_receiver { #define HTABLE_DATA struct solstice_receiver #include <rsys/hash_table.h> +#define HTABLE_NAME primary +#define HTABLE_KEY struct str +#define HTABLE_KEY_FUNCTOR_INIT str_init +#define HTABLE_KEY_FUNCTOR_RELEASE str_release +#define HTABLE_KEY_FUNCTOR_COPY str_copy +#define HTABLE_KEY_FUNCTOR_COPY_AND_RELEASE str_copy_and_release +#define HTABLE_KEY_FUNCTOR_EQ str_eq +#define HTABLE_KEY_FUNCTOR_HASH str_hash +#define HTABLE_DATA struct solstice_primary +#include <rsys/hash_table.h> + struct solstice { struct ssol_device* ssol; struct ssol_scene* scene; struct ssol_sun* sun; + struct ssol_atmosphere* atmosphere; struct solparser* parser; @@ -80,6 +97,7 @@ struct solstice { struct htable_object objects; struct htable_anchor anchors; struct htable_receiver receivers; + struct htable_primary primaries; struct darray_nodes roots; struct darray_nodes pivots; struct ssol_material* mtl_virtual; /* Shared virtual material */ @@ -88,6 +106,7 @@ struct solstice { struct ssol_camera* camera; struct ssol_image* framebuffer; enum solstice_args_render_mode render_mode; + double up[3]; unsigned spp; /* #Samples per pixel */ /* Dump geometry */ @@ -102,9 +121,9 @@ struct solstice { size_t nexperiments; /* # MC experiments */ FILE* output; /* Output stream */ - int output_hits; /* Output per receiver hits */ int dump_paths; + struct logger logger; struct mem_allocator* allocator; }; diff --git a/src/solstice_args.c b/src/solstice_args.c @@ -38,8 +38,9 @@ print_help(const char* program) { printf( "Usage: %s [OPTIONS] [FILE]\n" -"Integrate the solar flux in a complex solar facility described in FILE. If\n" -"not define, the solar facility is read from standard input.\n\n", +"Integrate the solar flux in a complex solar facility described in FILE. If not\n" +"define, the solar facility is read from standard input. Refer to solstice(1)\n" +"man page for more informations.\n\n", program); printf( " -D <dirs> list of sun directions.\n"); @@ -47,15 +48,13 @@ print_help(const char* program) " -f do not prompt before overwriting the output file submitted\n" " with the '-o' option.\n"); printf( -" -H output hit-on-receiver data (binary format).\n"); +" -g <dump> switch in dump geometry mode and configure it.\n"); printf( " -h display this help and exit.\n"); printf( " -n EXPERIMENTS number of Monte Carlo experiments. Default is %lu.\n", SOLSTICE_ARGS_DEFAULT.nexperiments); printf( -" -g <dump> switch in dump geometry mode and configure it.\n"); - printf( " -o OUTPUT write results to OUTPUT. If not defined, write results to\n" " standard output.\n"); printf( @@ -69,6 +68,8 @@ print_help(const char* program) printf( " -t THREADS hint on the number of threads to use. By default use as\n" " many threads as CPU cores.\n"); + printf( +" -v make the program more verbose.\n"); printf("\n"); printf( "Solstice (C) 2016-2017 CNRS. This is a free software released under the GNU GPL\n" @@ -492,13 +493,12 @@ solstice_args_init(struct solstice_args* args, const int argc, char** argv) *args = SOLSTICE_ARGS_DEFAULT; optind = 0; - while((opt = getopt(argc, argv, "D:fg:Hhn:o:p:qR:r:t:")) != -1) { + while((opt = getopt(argc, argv, "D:fg:hn:o:p:qR:r:t:v")) != -1) { switch(opt) { case 'D': /* Sun directions */ res = parse_sun_dir_list(optarg, args); break; case 'f': args->force_overwriting = 1; break; - case 'H': args->output_hits = 1; break; case 'h': /* Print short help and exit */ print_help(argv[0]); solstice_args_release(args); @@ -531,6 +531,7 @@ solstice_args_init(struct solstice_args* args, const int argc, char** argv) res = cstr_to_uint(optarg, &args->nthreads); if(res == RES_OK && !args->nthreads) res = RES_BAD_ARG; break; + case 'v': args->verbose = 1; break; default: res = RES_BAD_ARG; break; } if(res != RES_OK) { diff --git a/src/solstice_args.h.in b/src/solstice_args.h.in @@ -78,9 +78,9 @@ struct solstice_args { int force_overwriting; int dump_paths; /* Dump radiative paths */ int rendering; - int output_hits; /* Output the per receiver hits */ int quiet; int quit; /* Quit the application */ + int verbose; }; #define SOLSTICE_ARGS_NULL__ {0} @@ -121,9 +121,9 @@ static const struct solstice_args SOLSTICE_ARGS_NULL = SOLSTICE_ARGS_NULL__; 0, /* Force overwriting */ \ 0, /* Dump radiative paths */ \ 0, /* Rendering */ \ - 0, /* Output hits */ \ 0, /* Quiet */ \ - 0 /* Quit */ \ + 0, /* Quit */ \ + 0 /* Verbose */ \ } static const struct solstice_args SOLSTICE_ARGS_DEFAULT = SOLSTICE_ARGS_DEFAULT__; diff --git a/src/solstice_atmosphere.c b/src/solstice_atmosphere.c @@ -0,0 +1,63 @@ +/* Copyright (C) CNRS 2016-2017 +* +* This program is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program. If not, see <http://www.gnu.org/licenses/>. */ + +#include "solstice_c.h" +#include "parser/solparser.h" +#include "parser/solparser_atmosphere.h" + +#include <solstice/ssol.h> + +res_T +solstice_create_atmosphere(struct solstice* solstice) +{ + struct ssol_atmosphere* atm = NULL; + struct ssol_data absorption = SSOL_DATA_NULL; + const struct solparser_atmosphere* solparser_atm = NULL; + res_T res = RES_OK; + ASSERT(solstice); + + solparser_atm = solparser_get_atmosphere(solstice->parser); + if(!solparser_atm) return res; + + res = ssol_atmosphere_create(solstice->ssol, &atm); + if(res != RES_OK) goto error; + + res = mtl_to_ssol_data(solstice, &solparser_atm->absorption, &absorption); + if(res != RES_OK) goto error; + + res = ssol_atmosphere_set_absorption(atm, &absorption); + if(res != RES_OK) { + fprintf(stderr, "Could not set atmosphere absorbtion.\n"); + goto error; + } + + res = ssol_scene_attach_atmosphere(solstice->scene, atm); + if(res != RES_OK) { + fprintf(stderr, "Could not attach the atmosphere to the scene.\n"); + goto error; + } + +exit: + ssol_data_clear(&absorption); + solstice->atmosphere = atm; + return res; +error: + if(atm) { + SSOL(atmosphere_ref_put(atm)); + atm = NULL; + } + + goto exit; +} diff --git a/src/solstice_atmosphere.h b/src/solstice_atmosphere.h diff --git a/src/solstice_c.h b/src/solstice_c.h @@ -61,6 +61,10 @@ solstice_create_sun (struct solstice* solstice); extern LOCAL_SYM res_T +solstice_create_atmosphere + (struct solstice* solstice); + +extern LOCAL_SYM res_T solstice_setup_entities (struct solstice* solstice); @@ -70,6 +74,18 @@ solstice_update_entities const double sun_dir[3]); extern LOCAL_SYM res_T +solstice_create_ssol_spectrum + (struct solstice* solstice, + const struct solparser_spectrum_id spectrum_id, + struct ssol_spectrum** spectrum); + +extern LOCAL_SYM res_T +mtl_to_ssol_data + (struct solstice* solstice, + const struct solparser_mtl_data* mtl_data, + struct ssol_data* data); + +extern LOCAL_SYM res_T solstice_create_ssol_material (struct solstice* solstice, const struct solparser_material_id mtl_id, diff --git a/src/solstice_draw.c b/src/solstice_draw.c @@ -23,27 +23,32 @@ /******************************************************************************* * Helper function ******************************************************************************/ -/* Assume that the pixel format of the src is DOUBLE3 in gray scale while the - * pixel format of dst is UBYTE */ +/* Assume that the pixel format of the src is DOUBLE3 and dst is UBYTE3 */ static void -tone_map(const double* src, unsigned char* dst, const size_t count) +tone_map(const double* src, uint8_t* dst, const size_t count) { size_t i; ASSERT(src && dst && count); FOR_EACH(i, 0, count) { - double val; - val = pow(src[i*3/*#channels*/], 1/SCREEN_GAMMA);/* Gamma correction */ - val = CLAMP(val, 0, 1); - dst[i] = (unsigned char)((val * 255) + 0.5/*round*/); + double val[3]; + val[0] = pow(src[i*3/*#channels*/+0], 1/SCREEN_GAMMA);/* Gamma correction */ + val[1] = pow(src[i*3/*#channels*/+1], 1/SCREEN_GAMMA);/* Gamma correction */ + val[2] = pow(src[i*3/*#channels*/+2], 1/SCREEN_GAMMA);/* Gamma correction */ + val[0] = CLAMP(val[0], 0, 1); + val[1] = CLAMP(val[1], 0, 1); + val[2] = CLAMP(val[2], 0, 1); + dst[i*3/*#channels*/ + 0] = (uint8_t)((val[0]*255) + 0.5/*round*/); + dst[i*3/*#channels*/ + 1] = (uint8_t)((val[1]*255) + 0.5/*round*/); + dst[i*3/*#channels*/ + 2] = (uint8_t)((val[2]*255) + 0.5/*round*/); } } static void -tone_map_image(const struct ssol_image* img, unsigned char* dst) +tone_map_image(const struct ssol_image* img, uint8_t* dst) { struct ssol_image_layout layout; size_t irow = 0; - void* mem; + char* mem; ASSERT(img && dst); SSOL(image_get_layout(img, &layout)); @@ -52,7 +57,7 @@ tone_map_image(const struct ssol_image* img, unsigned char* dst) SSOL(image_map(img, &mem)); FOR_EACH(irow, 0, layout.height) { const void* src_row = ((char*)mem) + layout.offset + irow * layout.row_pitch; - unsigned char* dst_row = dst + irow * layout.width; + uint8_t* dst_row = dst + irow * layout.width * 3/*#channels*/; tone_map(src_row, dst_row, layout.width); } } @@ -64,13 +69,17 @@ res_T solstice_draw(struct solstice* solstice) { struct ssol_image_layout layout; - unsigned char* ubytes = NULL; + struct image img; + size_t pitch; res_T res = RES_OK; ASSERT(solstice); SSOL(image_get_layout(solstice->framebuffer, &layout)); - ubytes = MEM_ALLOC(solstice->allocator, layout.width*layout.height); - if(!ubytes) { + + pitch = layout.width * sizeof_image_format(IMAGE_RGB8); + image_init(solstice->allocator, &img); + res = image_setup(&img, layout.width, layout.height, pitch, IMAGE_RGB8, NULL); + if(res != RES_OK) { fprintf(stderr, "Could not allocate the 8-bits image buffer.\n"); res = RES_MEM_ERR; goto error; @@ -83,7 +92,8 @@ solstice_draw(struct solstice* solstice) break; case SOLSTICE_ARGS_RENDER_PATH_TRACING: res = ssol_draw_pt(solstice->scene, solstice->camera, layout.width, - layout.height, solstice->spp, ssol_image_write, solstice->framebuffer); + layout.height, solstice->spp, solstice->up, ssol_image_write, + solstice->framebuffer); break; default: FATAL("Unreachable code.\n"); } @@ -92,9 +102,9 @@ solstice_draw(struct solstice* solstice) goto error; } - tone_map_image(solstice->framebuffer, ubytes); - res = image_ppm_write_stream(solstice->output, (int)layout.width, - (int)layout.height, 1, ubytes); + tone_map_image(solstice->framebuffer, (uint8_t*)img.pixels); + + res = image_write_ppm_stream(&img, 0, solstice->output); if(res != RES_OK) { fprintf(stderr, "Could not write the rendered image to the output stream.\n"); @@ -102,7 +112,7 @@ solstice_draw(struct solstice* solstice) } exit: - if(ubytes) MEM_RM(solstice->allocator, ubytes); + image_release(&img); return res; error: goto exit; diff --git a/src/solstice_dump.c b/src/solstice_dump.c @@ -36,8 +36,10 @@ dump_instantiated_shaded_shape SSOL(material_get_type(sshape->mtl_front, &type)); switch(type) { + case SSOL_MATERIAL_DIELECTRIC: mtl = "dielectric"; break; case SSOL_MATERIAL_MATTE: mtl = "matte"; break; case SSOL_MATERIAL_MIRROR: mtl = "mirror"; break; + case SSOL_MATERIAL_THIN_DIELECTRIC: mtl = "thin_dielectric"; break; case SSOL_MATERIAL_VIRTUAL: mtl = "virtual"; break; default: FATAL("Unexpected Solstice Solver material type.\n"); break; } diff --git a/src/solstice_entity.c b/src/solstice_entity.c @@ -19,6 +19,8 @@ #include <solstice/ssol.h> #include <solstice/sanim.h> +#include <rsys/double33.h> + /******************************************************************************* * Helper function ******************************************************************************/ @@ -26,13 +28,19 @@ static res_T update_instance_transform (const struct sanim_node* n, const double transform[12], void* data) { + res_T res = RES_OK; struct solstice_node* node; - ASSERT(n && transform); + ASSERT(n && transform && data); (void)data; - node = CONTAINER_OF(n, struct solstice_node, anim); if(node->type != SOLSTICE_NODE_GEOMETRY) return RES_OK; - return ssol_instance_set_transform(node->instance, transform); + res = ssol_instance_set_transform(node->instance, transform); + if(res != RES_OK) goto error; + +exit: + return res; +error: + goto exit; } static res_T @@ -180,7 +188,7 @@ setup_tracking case SOLPARSER_TARGET_POSITION: tracking->policy = TRACKING_POINT; d3_set(tracking->data.point.target, target->data.position); - tracking->data.point.target_is_local = 0; /* TODO */ + tracking->data.point.target_is_local = 0; break; case SOLPARSER_TARGET_SUN: tracking->policy = TRACKING_SUN; @@ -328,6 +336,16 @@ create_node str_cget(&entity->name)); goto error; } + if (entity->primary) { + struct solstice_primary p; + p.node = node; + res = htable_primary_set(&solstice->primaries, name, &p); + if (res != RES_OK) { + fprintf(stderr, "Could not define the entity `%s' as primary.\n", + str_cget(&entity->name)); + goto error; + } + } } /* Setup the entity receiver flags */ @@ -448,7 +466,7 @@ solstice_setup_entities(struct solstice* solstice) /* Initialialised the world space position of the entity geometry */ res = sanim_node_visit_tree - (&root->anim, dummy_sun_dir, NULL, update_instance_transform); + (&root->anim, dummy_sun_dir, solstice, update_instance_transform); if(res != RES_OK) { fprintf(stderr, "Could not setup the transformation of the entity geometries.\n"); @@ -486,7 +504,7 @@ solstice_update_entities(struct solstice* solstice, const double sun_dir[3]) /* Initialialised the world space position of the entity geometry */ res = sanim_node_visit_tree - (&node->anim, sun_dir, NULL, update_instance_transform); + (&node->anim, sun_dir, solstice, update_instance_transform); if(res != RES_OK) { fprintf(stderr, "Could not update the transformation of the entity geometries.\n"); diff --git a/src/solstice_material.c b/src/solstice_material.c @@ -16,36 +16,87 @@ #include "solstice.h" #include "solstice_c.h" +#include <rsys/double33.h> +#include <rsys/image.h> #include <solstice/ssol.h> +struct dielectric_param { + struct ssol_image* normal_map; +}; + struct matte_param { - double reflectivity; + struct ssol_data reflectivity; + struct ssol_image* normal_map; }; struct mirror_param { - double reflectivity; - double roughness; + struct ssol_data reflectivity; + struct ssol_data roughness; + struct ssol_image* normal_map; +}; + +struct thin_dielectric_param { + struct ssol_image* normal_map; }; /******************************************************************************* * Helper functions ******************************************************************************/ static void +perturb_normal + (const struct ssol_surface_fragment* frag, + const struct ssol_image* normal_map, + double normal[3]) +{ + double basis[9]; + double N[3]; + ASSERT(frag && normal_map && normal); + + SSOL(image_sample(normal_map, SSOL_FILTER_LINEAR, SSOL_ADDRESS_CLAMP, + SSOL_ADDRESS_CLAMP, frag->uv, N)); + + d3_set(basis+0, frag->dPdu); + d3_set(basis+3, frag->dPdv); + d3_set(basis+6, frag->Ns); + d3_normalize(basis + 0, basis + 0); + d3_normalize(basis + 3, basis + 3); + + d3_subd(N, d3_muld(N, N, 2), 1); + d33_muld3(N, basis, N); + d3_normalize(normal, N); +} + +static void mtl_get_normal (struct ssol_device* dev, struct ssol_param_buffer* buf, const double wavelength, - const double P[3], - const double Ng[3], - const double Ns[3], - const double uv[2], - const double w[3], + const struct ssol_surface_fragment* frag, double* val) { - (void)dev, (void)buf, (void)wavelength, (void)P, (void)Ng, (void)uv, (void)w; - val[0] = Ns[0]; - val[1] = Ns[1]; - val[2] = Ns[2]; + (void)dev, (void)buf, (void)wavelength; + d3_set(val, frag->Ns); +} + +static void +dielectric_get_normal + (struct ssol_device* dev, + struct ssol_param_buffer* buf, + const double wavelength, + const struct ssol_surface_fragment* frag, + double* val) +{ + const struct dielectric_param* param = ssol_param_buffer_get(buf); + (void)dev, (void)buf, (void)wavelength; + perturb_normal(frag, param->normal_map, val); +} + +static void +dielectric_param_release(void* mem) +{ + struct dielectric_param* param = mem; + ASSERT(param); + if(param->normal_map) SSOL(image_ref_put(param->normal_map)); } static void @@ -53,16 +104,34 @@ matte_get_reflectivity (struct ssol_device* dev, struct ssol_param_buffer* buf, const double wavelength, - const double P[3], - const double Ng[3], - const double Ns[3], - const double uv[2], - const double w[3], + const struct ssol_surface_fragment* frag, + double* val) +{ + const struct matte_param* param = ssol_param_buffer_get(buf); + (void)dev, (void)wavelength, (void)frag; + *val = ssol_data_get_value(&param->reflectivity, wavelength); +} + +static void +matte_get_normal + (struct ssol_device* dev, + struct ssol_param_buffer* buf, + const double wavelength, + const struct ssol_surface_fragment* frag, double* val) { const struct matte_param* param = ssol_param_buffer_get(buf); - (void)dev, (void)wavelength, (void)P, (void)Ng, (void)Ns, (void)uv, (void)w; - *val = param->reflectivity; + (void)dev, (void)wavelength; + perturb_normal(frag, param->normal_map, val); +} + +static void +matte_param_release(void* mem) +{ + struct matte_param* param = mem; + ASSERT(param); + if(param->normal_map) SSOL(image_ref_put(param->normal_map)); + ssol_data_clear(&param->reflectivity); } static void @@ -70,16 +139,12 @@ mirror_get_reflectivity (struct ssol_device* dev, struct ssol_param_buffer* buf, const double wavelength, - const double P[3], - const double Ng[3], - const double Ns[3], - const double uv[2], - const double w[3], + const struct ssol_surface_fragment* frag, double* val) { const struct mirror_param* param = ssol_param_buffer_get(buf); - (void)dev, (void)wavelength, (void)P, (void)Ng, (void)Ns, (void)uv, (void)w; - *val = param->reflectivity; + (void)dev, (void)wavelength, (void)frag; + *val = ssol_data_get_value(&param->reflectivity, wavelength); } static void @@ -87,16 +152,125 @@ mirror_get_roughness (struct ssol_device* dev, struct ssol_param_buffer* buf, const double wavelength, - const double P[3], - const double Ng[3], - const double Ns[3], - const double uv[2], - const double w[3], + const struct ssol_surface_fragment* frag, double* val) { const struct mirror_param* param = ssol_param_buffer_get(buf); - (void)dev, (void)wavelength, (void)P, (void)Ng, (void)Ns, (void)uv, (void)w; - *val = param->roughness; + (void)dev, (void)wavelength, (void)frag; + *val = ssol_data_get_value(&param->roughness, wavelength); +} + +static void +mirror_get_normal + (struct ssol_device* dev, + struct ssol_param_buffer* buf, + const double wavelength, + const struct ssol_surface_fragment* frag, + double* val) +{ + const struct mirror_param* param = ssol_param_buffer_get(buf); + (void)dev, (void)wavelength; + perturb_normal(frag, param->normal_map, val); +} + +static void +mirror_param_release(void* mem) +{ + struct mirror_param* param = mem; + ASSERT(param); + if(param->normal_map) SSOL(image_ref_put(param->normal_map)); + ssol_data_clear(&param->reflectivity); + ssol_data_clear(&param->roughness); +} + +static void +thin_dielectric_get_normal + (struct ssol_device* dev, + struct ssol_param_buffer* buf, + const double wavelength, + const struct ssol_surface_fragment* frag, + double* val) +{ + const struct thin_dielectric_param* param = ssol_param_buffer_get(buf); + (void)dev, (void)buf, (void)wavelength; + perturb_normal(frag, param->normal_map, val); +} + +static void +thin_dielectric_param_release(void* mem) +{ + struct thin_dielectric_param* param = mem; + ASSERT(param); + if(param->normal_map) SSOL(image_ref_put(param->normal_map)); +} + +static res_T +load_image + (struct solstice* solstice, + const char* filename, + struct ssol_image** out_ssol_img) +{ + struct ssol_image* ssol_img = NULL; + struct ssol_image_layout layout; + struct image img; + char* mem; + size_t x, y; + res_T res = RES_OK; + ASSERT(solstice && filename && out_ssol_img); + + image_init(solstice->allocator, &img); + + res = image_read_ppm(&img, filename); + if(res != RES_OK) { + fprintf(stderr, "Could not load the PPM image `%s'.\n", filename); + goto error; + } + + res = ssol_image_create(solstice->ssol, &ssol_img); + if(res != RES_OK) { + fprintf(stderr, "Could not create the Solstice Solver image.\n"); + goto error; + } + + res = ssol_image_setup(ssol_img, img.width, img.height, SSOL_PIXEL_DOUBLE3); + if(res != RES_OK) { + fprintf(stderr, "Could not setup the Solstice Solver image.\n"); + goto error; + } + + SSOL(image_get_layout(ssol_img, &layout)); + SSOL(image_map(ssol_img, &mem)); + + FOR_EACH(y, 0, layout.height) { + char* dst_row = mem + layout.offset + y * layout.row_pitch; + const char* src_row = img.pixels + y * img.pitch; + + FOR_EACH(x, 0, layout.width) { + char* dst = dst_row + x*ssol_sizeof_pixel_format(layout.pixel_format); + const char* src = src_row + x*sizeof_image_format(img.format); + switch(img.format) { + case IMAGE_RGB8: + ((double*)dst)[0] = ((double)((uint8_t*)src)[0] + 0.5) / UINT8_MAX; + ((double*)dst)[1] = ((double)((uint8_t*)src)[1] + 0.5) / UINT8_MAX; + ((double*)dst)[2] = ((double)((uint8_t*)src)[2] + 0.5) / UINT8_MAX; + break; + case IMAGE_RGB16: + ((double*)dst)[0] = ((double)((uint16_t*)src)[0] + 0.5) / UINT16_MAX; + ((double*)dst)[1] = ((double)((uint16_t*)src)[1] + 0.5) / UINT16_MAX; + ((double*)dst)[2] = ((double)((uint16_t*)src)[2] + 0.5) / UINT16_MAX; + break; + default: FATAL("Unreachable code.\n"); break; + } + } + } + +exit: + image_release(&img); + *out_ssol_img = ssol_img; + return res; +error: + if(ssol_img) SSOL(image_ref_put(ssol_img)); + goto exit; } static res_T @@ -107,10 +281,12 @@ create_material_dielectric { const struct solparser_medium* medium_i; const struct solparser_medium* medium_t; - struct ssol_medium ssol_medium_i; - struct ssol_medium ssol_medium_t; + struct ssol_medium ssol_medium_i = SSOL_MEDIUM_VACUUM; + struct ssol_medium ssol_medium_t = SSOL_MEDIUM_VACUUM; struct ssol_dielectric_shader shader = SSOL_DIELECTRIC_SHADER_NULL; + struct ssol_image* img = NULL; struct ssol_material* mtl = NULL; + struct ssol_param_buffer* pbuf = NULL; res_T res = RES_OK; ASSERT(solstice && dielectric && out_mtl); @@ -123,18 +299,56 @@ create_material_dielectric medium_i = solparser_get_medium(solstice->parser, dielectric->medium_i); medium_t = solparser_get_medium(solstice->parser, dielectric->medium_t); - shader.normal = mtl_get_normal; - ssol_medium_i.refractive_index = medium_i->refractive_index; - ssol_medium_i.absorptivity = medium_i->absorptivity; - ssol_medium_t.refractive_index = medium_t->refractive_index; - ssol_medium_t.absorptivity = medium_t->absorptivity; + + if(!SOLPARSER_ID_IS_VALID(dielectric->normal_map)) { + shader.normal = mtl_get_normal; + } else { + const struct solparser_image* image; + struct dielectric_param* param = NULL; + + image = solparser_get_image(solstice->parser, dielectric->normal_map); + res = load_image(solstice, str_cget(&image->filename), &img); + if(res != RES_OK) goto error; + + res = ssol_param_buffer_create + (solstice->ssol, sizeof(struct dielectric_param), &pbuf); + if(res != RES_OK) { + fprintf(stderr, "Could not create the Solstice Solver parameter buffer.\n"); + goto error; + } + + param = ssol_param_buffer_allocate(pbuf, sizeof(struct dielectric_param), + ALIGNOF(struct dielectric_param), dielectric_param_release); + if(!param) { + fprintf(stderr, "Could not allocate the dielectric parameter.\n"); + res = RES_MEM_ERR; + goto error; + } + param->normal_map = img; + shader.normal = dielectric_get_normal; + SSOL(material_set_param_buffer(mtl, pbuf)); + } + + #define SET_SSOL_DATA(Medium, Name) { \ + res = mtl_to_ssol_data(solstice, &Medium->Name, &ssol_## Medium.Name); \ + if(res != RES_OK) goto error; \ + } (void)0 + SET_SSOL_DATA(medium_i, refractive_index); + SET_SSOL_DATA(medium_t, refractive_index); + SET_SSOL_DATA(medium_i, absorption); + SET_SSOL_DATA(medium_t, absorption); + #undef SET_SSOL_DATA SSOL(dielectric_setup(mtl, &shader, &ssol_medium_i, &ssol_medium_t)); exit: + ssol_medium_clear(&ssol_medium_i); + ssol_medium_clear(&ssol_medium_t); + if(pbuf) SSOL(param_buffer_ref_put(pbuf)); *out_mtl = mtl; return res; error: if(mtl) SSOL(material_ref_put(mtl)), mtl = NULL; + if(img) SSOL(image_ref_put(img)); goto exit; } @@ -145,6 +359,7 @@ create_material_matte struct ssol_material** out_mtl) { struct ssol_matte_shader shader = SSOL_MATTE_SHADER_NULL; + struct ssol_image* img = NULL; struct ssol_material* mtl = NULL; struct ssol_param_buffer* pbuf = NULL; struct matte_param* param; @@ -164,16 +379,29 @@ create_material_matte goto error; } - param = ssol_param_buffer_allocate - (pbuf, sizeof(struct matte_param), ALIGNOF(struct matte_param)); + param = ssol_param_buffer_allocate(pbuf, sizeof(struct matte_param), + ALIGNOF(struct matte_param), matte_param_release); if(!param) { fprintf(stderr, "Could not allocate the matte parameter.\n"); res = RES_MEM_ERR; goto error; } - param->reflectivity = matte->reflectivity; + memset(param, 0, sizeof(struct matte_param)); + + res = mtl_to_ssol_data(solstice, &matte->reflectivity, &param->reflectivity); + if(res != RES_OK) goto error; + + if(!SOLPARSER_ID_IS_VALID(matte->normal_map)) { + shader.normal = mtl_get_normal; + } else { + const struct solparser_image* image; + image = solparser_get_image(solstice->parser, matte->normal_map); + res = load_image(solstice, str_cget(&image->filename), &img); + if(res != RES_OK) goto error; + param->normal_map = img; + shader.normal = matte_get_normal; + } - shader.normal = mtl_get_normal; shader.reflectivity = matte_get_reflectivity; SSOL(matte_setup(mtl, &shader)); SSOL(material_set_param_buffer(mtl, pbuf)); @@ -184,6 +412,7 @@ exit: return res; error: if(mtl) SSOL(material_ref_put(mtl)), mtl = NULL; + if(img) SSOL(image_ref_put(img)); goto exit; } @@ -193,6 +422,7 @@ create_material_mirror const struct solparser_material_mirror* mirror, struct ssol_material** out_mtl) { + struct ssol_image* img = NULL; struct ssol_mirror_shader shader = SSOL_MIRROR_SHADER_NULL; struct ssol_material* mtl = NULL; struct ssol_param_buffer* pbuf = NULL; @@ -213,17 +443,31 @@ create_material_mirror goto error; } - param = ssol_param_buffer_allocate - (pbuf, sizeof(struct mirror_param), ALIGNOF(struct mirror_param)); + param = ssol_param_buffer_allocate(pbuf, sizeof(struct mirror_param), + ALIGNOF(struct mirror_param), mirror_param_release); if(!param) { fprintf(stderr, "Could not allocate the mirror parameters.\n"); res = RES_MEM_ERR; goto error; } - param->reflectivity = mirror->reflectivity; - param->roughness = mirror->roughness; + memset(param, 0, sizeof(struct mirror_param)); + + res = mtl_to_ssol_data(solstice, &mirror->reflectivity, &param->reflectivity); + if(res != RES_OK) goto error; + res = mtl_to_ssol_data(solstice, &mirror->roughness, &param->roughness); + if(res != RES_OK) goto error; + + if(!SOLPARSER_ID_IS_VALID(mirror->normal_map)) { + shader.normal = mtl_get_normal; + } else { + const struct solparser_image* image; + image = solparser_get_image(solstice->parser, mirror->normal_map); + res = load_image(solstice, str_cget(&image->filename), &img); + if(res != RES_OK) goto error; + param->normal_map = img; + shader.normal = mirror_get_normal; + } - shader.normal = mtl_get_normal; shader.reflectivity = mirror_get_reflectivity; shader.roughness = mirror_get_roughness; SSOL(mirror_setup(mtl, &shader)); @@ -235,6 +479,7 @@ exit: return res; error: if(mtl) SSOL(material_ref_put(mtl)), mtl = NULL; + if(img) SSOL(image_ref_put(img)); goto exit; } @@ -244,12 +489,14 @@ create_material_thin_dielectric const struct solparser_material_thin_dielectric* thin, struct ssol_material** out_mtl) { + struct ssol_image* img = NULL; struct ssol_thin_dielectric_shader shader = SSOL_THIN_DIELECTRIC_SHADER_NULL; - const struct solparser_medium* medium_i; - const struct solparser_medium* medium_t; - struct ssol_medium ssol_medium_i; - struct ssol_medium ssol_medium_t; + const struct solparser_medium* medium_i = NULL; + const struct solparser_medium* medium_t = NULL; + struct ssol_medium ssol_medium_i = SSOL_MEDIUM_VACUUM; + struct ssol_medium ssol_medium_t = SSOL_MEDIUM_VACUUM; struct ssol_material* mtl = NULL; + struct ssol_param_buffer* pbuf = NULL; res_T res = RES_OK; ASSERT(solstice && thin && out_mtl); @@ -260,29 +507,100 @@ create_material_thin_dielectric goto error; } - shader.normal = mtl_get_normal; medium_i = solparser_get_medium(solstice->parser, thin->medium_i); medium_t = solparser_get_medium(solstice->parser, thin->medium_t); - ssol_medium_i.refractive_index = medium_i->refractive_index; - ssol_medium_t.refractive_index = medium_t->refractive_index; - ssol_medium_i.absorptivity = medium_i->absorptivity; - ssol_medium_t.absorptivity = medium_t->absorptivity; + + if(!SOLPARSER_ID_IS_VALID(thin->normal_map)) { + shader.normal = mtl_get_normal; + } else { + const struct solparser_image* image; + struct dielectric_param* param = NULL; + + image = solparser_get_image(solstice->parser, thin->normal_map); + res = load_image(solstice, str_cget(&image->filename), &img); + if(res != RES_OK) goto error; + + res = ssol_param_buffer_create + (solstice->ssol, sizeof(struct thin_dielectric_param), &pbuf); + if(res != RES_OK) { + fprintf(stderr, "Could not create the Solsitce Solver parameter buffer.\n"); + goto error; + } + + param = ssol_param_buffer_allocate(pbuf, + sizeof(struct thin_dielectric_param), + ALIGNOF(struct thin_dielectric_param), + thin_dielectric_param_release); + if(!param) { + fprintf(stderr, "Could not allocate the thin dielectric parameter.\n"); + res = RES_MEM_ERR; + goto error; + } + param->normal_map = img; + shader.normal = thin_dielectric_get_normal; + SSOL(material_set_param_buffer(mtl, pbuf)); + } + + #define SET_SSOL_DATA(Medium, Name) { \ + res = mtl_to_ssol_data(solstice, &Medium->Name, &ssol_## Medium.Name); \ + if(res != RES_OK) goto error; \ + } (void)0 + SET_SSOL_DATA(medium_i, refractive_index); + SET_SSOL_DATA(medium_t, refractive_index); + SET_SSOL_DATA(medium_i, absorption); + SET_SSOL_DATA(medium_t, absorption); + #undef SET_SSOL_DATA SSOL(thin_dielectric_setup (mtl, &shader, &ssol_medium_i, &ssol_medium_t, thin->thickness)); exit: + ssol_medium_clear(&ssol_medium_i); + ssol_medium_clear(&ssol_medium_t); + if(pbuf) SSOL(param_buffer_ref_put(pbuf)); *out_mtl = mtl; return res; error: if(mtl) SSOL(material_ref_put(mtl)), mtl = NULL; + if(img) SSOL(image_ref_put(img)); goto exit; } - /******************************************************************************* * Local functions ******************************************************************************/ res_T +mtl_to_ssol_data + (struct solstice* solstice, + const struct solparser_mtl_data* mtl_data, + struct ssol_data* data) +{ + struct ssol_spectrum* spectrum = NULL; + res_T res = RES_OK; + ASSERT(mtl_data && data); + + ssol_data_clear(data); + switch(mtl_data->type) { + case SOLPARSER_MTL_DATA_REAL: + ssol_data_set_real(data, mtl_data->value.real); + break; + case SOLPARSER_MTL_DATA_SPECTRUM: + res = solstice_create_ssol_spectrum + (solstice, mtl_data->value.spectrum, &spectrum); + if(res != RES_OK) goto error; + ssol_data_set_spectrum(data, spectrum); + break; + default: FATAL("Unreachable code.\n"); break; + } + +exit: + if(spectrum) SSOL(spectrum_ref_put(spectrum)); + return res; +error: + ssol_data_clear(data); + goto exit; +} + +res_T solstice_create_ssol_material (struct solstice* solstice, const struct solparser_material_id mtl_id, diff --git a/src/solstice_object.c b/src/solstice_object.c @@ -99,7 +99,7 @@ get_carving_pos(const size_t ivert, double pos[2], void* ctx) } static INLINE enum ssol_clipping_op -solparser_clip_op_to_ssol_clipping_op(const enum solparser_clip_op op) +solparser_to_ssol_clip_op(const enum solparser_clip_op op) { switch(op) { case SOLPARSER_CLIP_OP_SUB: return SSOL_SUB; @@ -108,6 +108,16 @@ solparser_clip_op_to_ssol_clipping_op(const enum solparser_clip_op op) } } +static void +get_circular(const size_t ivert, double position[2], void* ctx) +{ + struct solparser_circleclip* data = (struct solparser_circleclip*)ctx; + const double a = (double)ivert * 2 * PI / (double)data->segments; + ASSERT(ivert < (size_t)data->segments); + position[0] = data->center[0] + data->radius * cos(a); + position[1] = data->center[1] + data->radius * sin(a); +} + static res_T create_ssol_shape_mesh (struct solstice* solstice, @@ -190,6 +200,7 @@ error: goto exit; } + static res_T create_cylinder (struct solstice* solstice, @@ -243,7 +254,7 @@ create_sphere sphere = solparser_get_shape_sphere(solstice->parser, sphere_id); ASSERT(sphere->nslices > 0 && sphere->nslices < UINT_MAX); res = s3dut_create_sphere(solstice->allocator, sphere->radius, - (unsigned)sphere->nslices, (unsigned)(sphere->nslices/2), &mesh); + (unsigned)sphere->nslices, (unsigned)(sphere->nslices / 2), &mesh); if(res != RES_OK) { fprintf(stderr, "Could not create the sphere 3D data.\n"); goto error; @@ -283,7 +294,7 @@ create_stl stl = solparser_get_shape_stl(solstice->parser, stl_id); ASSERT(str_cget(&stl->filename)); - res = sstl_create(NULL, solstice->allocator, 0, &tmp_stl); + res = sstl_create(NULL, solstice->allocator, 1, &tmp_stl); if(res != RES_OK) { fprintf(stderr, "Could not create a Solstice Solver STL shape.\n"); goto error; @@ -352,10 +363,21 @@ create_ssol_shape_punched_surface const struct solparser_polyclip* clip; clip = darray_polyclip_cdata_get(clips) + iclip; - carvings[iclip].get = get_carving_pos; - carvings[iclip].nb_vertices = solparser_polyclip_get_vertices_count(clip); - carvings[iclip].operation = solparser_clip_op_to_ssol_clipping_op(clip->op); - carvings[iclip].context = (void*)clip; + switch(clip->contour_type) { + case SOLPARSER_CLIP_CONTOUR_POLY: + carvings[iclip].get = get_carving_pos; + carvings[iclip].nb_vertices = solparser_polyclip_get_vertices_count(clip); + carvings[iclip].operation = solparser_to_ssol_clip_op(clip->op); + carvings[iclip].context = (void*)clip; + break; + case SOLPARSER_CLIP_CONTOUR_CIRCLE: + carvings[iclip].get = get_circular; + carvings[iclip].nb_vertices = (size_t)clip->circle.segments; + carvings[iclip].operation = solparser_to_ssol_clip_op(clip->op); + carvings[iclip].context = (void*)&clip->circle; + break; + default: FATAL("Unreachable code.\n"); + } } punched_surf.quadric = quadric; @@ -432,7 +454,6 @@ create_parabolic_cylinder return create_ssol_shape_punched_surface (solstice, &paraboloid->polyclips, &quadric, out_ssol_shape); - } static res_T @@ -458,7 +479,32 @@ create_hyperbol } return create_ssol_shape_punched_surface - (solstice, &hyperboloid->polyclips, &quadric, out_ssol_shape); + (solstice, &hyperboloid->polyclips, &quadric, out_ssol_shape); +} + +static res_T +create_hemisphere + (struct solstice* solstice, + const double transform[12], + const struct solparser_shape_hemisphere_id id, + struct ssol_shape** out_ssol_shape) +{ + const struct solparser_shape_hemisphere* hemisphere; + struct ssol_quadric quadric = SSOL_QUADRIC_DEFAULT; + ASSERT(solstice); + + hemisphere = solparser_get_shape_hemisphere(solstice->parser, id); + + quadric.type = SSOL_QUADRIC_HEMISPHERE; + quadric.data.hemisphere.radius = hemisphere->radius; + d33_set(quadric.transform, transform); + d3_set(quadric.transform + 9, transform + 9); + if(hemisphere->nslices > 0) { /* nslices is set */ + quadric.slices_count_hint = (size_t)hemisphere->nslices; + } + + return create_ssol_shape_punched_surface + (solstice, &hemisphere->polyclips, &quadric, out_ssol_shape); } static res_T @@ -500,11 +546,17 @@ create_shaded_shape res_T res = RES_OK; ASSERT(solstice && ssol_front && ssol_back && ssol_shape); + *ssol_front = NULL; + *ssol_back = NULL; + *ssol_shape = NULL; + obj = solparser_get_object(solstice->parser, obj_id); mtl2 = solparser_get_material_double_sided(solstice->parser, obj->mtl2); - solstice_create_ssol_material(solstice, mtl2->front, ssol_front); - solstice_create_ssol_material(solstice, mtl2->back, ssol_back); + res = solstice_create_ssol_material(solstice, mtl2->front, ssol_front); + if(res != RES_OK) goto error; + res = solstice_create_ssol_material(solstice, mtl2->back, ssol_back); + if(res != RES_OK) goto error; /* Define the shape transformation */ rotation[0] = MDEG2RAD(obj->rotation[0]); @@ -536,6 +588,10 @@ create_shaded_shape case SOLPARSER_SHAPE_HYPERBOL: res = create_hyperbol(solstice, transform, shape->data.hyperbol, ssol_shape); break; + case SOLPARSER_SHAPE_HEMISPHERE: + res = create_hemisphere + (solstice, transform, shape->data.hemisphere, ssol_shape); + break; case SOLPARSER_SHAPE_PLANE: res = create_plane(solstice, transform, shape->data.plane, ssol_shape); break; @@ -547,7 +603,15 @@ create_shaded_shape break; default: FATAL("Unreachable code.\n"); break; } + if(res != RES_OK) goto error; + +exit: return res; +error: + if(*ssol_front) SSOL(material_ref_put(*ssol_front)), *ssol_front = NULL; + if(*ssol_back) SSOL(material_ref_put(*ssol_back)), *ssol_back = NULL; + if(*ssol_shape) SSOL(shape_ref_put(*ssol_shape)), *ssol_shape = NULL; + goto exit; } /******************************************************************************* diff --git a/src/solstice_solve.c b/src/solstice_solve.c @@ -26,84 +26,171 @@ static void write_mc_global(struct solstice* solstice, struct ssol_estimator* estimator) { struct ssol_mc_global mc_global; - struct htable_receiver_iterator it, end; + struct htable_receiver_iterator r_it, r_end; + struct htable_primary_iterator p_it, p_end; const struct solparser_sun* solparser_sun = NULL; - size_t nexperiments; - double irradiance_factor; + size_t nexperiments, nfailed, nprimary; + double area, potential, irradiance_factor; ASSERT(solstice && estimator); - #define MC_RCV_NONE { \ - { -1, -1, -1 }, /* Integrated irradiance */ \ - { -1, -1, -1 }, /* Absorptivity loss */ \ - { -1, -1, -1 }, /* Reflectivity loss */ \ - { -1, -1, -1 }, /* Cos loss */ \ - 0, NULL, NULL \ - } - /* get global information */ SSOL(estimator_get_mc_global(estimator, &mc_global)); - SSOL(estimator_get_count(estimator, &nexperiments)); - SSOL(estimator_get_sampled_area(estimator, &irradiance_factor)); + SSOL(estimator_get_realisation_count(estimator, &nexperiments)); + SSOL(estimator_get_sampled_count(estimator, &nprimary)); + SSOL(estimator_get_failed_count(estimator, &nfailed)); + SSOL(estimator_get_sampled_area(estimator, &area)); solparser_sun = solparser_get_sun(solstice->parser); - irradiance_factor = 1.0 / (solparser_sun->dni * irradiance_factor); + potential = solparser_sun->dni * area; + irradiance_factor = 1 / potential; - fprintf(solstice->output, "%lu %lu\n", + /* Counts */ + fprintf(solstice->output, "%d %lu %lu %lu %lu\n", + 7, /* #global results count */ (unsigned long)htable_receiver_size_get(&solstice->receivers), - (unsigned long)nexperiments); - - htable_receiver_begin(&solstice->receivers, &it); - htable_receiver_end(&solstice->receivers, &end); - while(!htable_receiver_iterator_eq(&it, &end)) { - const struct str* name = htable_receiver_iterator_key_get(&it); - struct solstice_receiver* rcv = htable_receiver_iterator_data_get(&it); + (unsigned long)nprimary, + (unsigned long)nexperiments, + (unsigned long)nfailed); + + /* Global data */ + #define PRINT_MC_GLOBAL(Name) \ + fprintf(solstice->output, "%g %g\n", mc_global.Name.E, mc_global.Name.SE) + fprintf(solstice->output, "%g %g\n", potential, 0.); + PRINT_MC_GLOBAL(absorbed); + PRINT_MC_GLOBAL(cos_factor); + PRINT_MC_GLOBAL(shadowed); + PRINT_MC_GLOBAL(missing); + PRINT_MC_GLOBAL(reflectivity); + PRINT_MC_GLOBAL(atmosphere); + #undef PRINT_MC_GLOBAL + + /* Receivers' data */ + htable_receiver_begin(&solstice->receivers, &r_it); + htable_receiver_end(&solstice->receivers, &r_end); + while(!htable_receiver_iterator_eq(&r_it, &r_end)) { + const struct str* name = htable_receiver_iterator_key_get(&r_it); + struct solstice_receiver* rcv = htable_receiver_iterator_data_get(&r_it); struct ssol_instance* inst = rcv->node->instance; - struct ssol_mc_receiver front = MC_RCV_NONE; - struct ssol_mc_receiver back = MC_RCV_NONE; + struct ssol_mc_receiver front = MC_RCV_NONE__; + struct ssol_mc_receiver back = MC_RCV_NONE__; double f_eff_E = -1, f_eff_SE = -1; /* Front efficiency */ double b_eff_E = -1, b_eff_SE = -1; /* Back efficiency */ uint32_t id; - htable_receiver_iterator_next(&it); + htable_receiver_iterator_next(&r_it); switch(rcv->side) { case SRCVL_FRONT: SSOL(estimator_get_mc_receiver(estimator, inst, SSOL_FRONT, &front)); - f_eff_E = front.integrated_irradiance.E * irradiance_factor; - f_eff_SE = front.integrated_irradiance.SE * irradiance_factor; + f_eff_E = front.integrated_absorbed_irradiance.E * irradiance_factor; + f_eff_SE = front.integrated_absorbed_irradiance.SE * irradiance_factor; break; case SRCVL_BACK: SSOL(estimator_get_mc_receiver(estimator, inst, SSOL_BACK, &back)); - b_eff_E = back.integrated_irradiance.E * irradiance_factor; - b_eff_SE = back.integrated_irradiance.SE * irradiance_factor; + b_eff_E = back.integrated_absorbed_irradiance.E * irradiance_factor; + b_eff_SE = back.integrated_absorbed_irradiance.SE * irradiance_factor; break; case SRCVL_FRONT_AND_BACK: SSOL(estimator_get_mc_receiver(estimator, inst, SSOL_FRONT, &front)); SSOL(estimator_get_mc_receiver(estimator, inst, SSOL_BACK, &back)); - f_eff_E = front.integrated_irradiance.E * irradiance_factor; - f_eff_SE = front.integrated_irradiance.SE * irradiance_factor; - b_eff_E = back.integrated_irradiance.E * irradiance_factor; - b_eff_SE = back.integrated_irradiance.SE * irradiance_factor; + f_eff_E = front.integrated_absorbed_irradiance.E * irradiance_factor; + f_eff_SE = front.integrated_absorbed_irradiance.SE * irradiance_factor; + b_eff_E = back.integrated_absorbed_irradiance.E * irradiance_factor; + b_eff_SE = back.integrated_absorbed_irradiance.SE * irradiance_factor; break; default: FATAL("Unreachable code.\n"); break; } SSOL(instance_get_id(inst, &id)); + SSOL(instance_get_area(inst, &area)); fprintf(solstice->output, - "%s %u %g %g %g %g %g %g %g %g %g %g %g %g %g %g %g %g %g %g %g %g\n", - str_cget(name), (unsigned)id, + "%s %u %g " + "%g %g %g %g %g %g %g %g %g %g " + "%g %g %g %g %g %g %g %g %g %g\n", + str_cget(name), (unsigned)id, area, + front.integrated_absorbed_irradiance.E, front.integrated_absorbed_irradiance.SE, front.integrated_irradiance.E, front.integrated_irradiance.SE, - back.integrated_irradiance.E, back.integrated_irradiance.SE, front.reflectivity_loss.E, front.reflectivity_loss.SE, - back.reflectivity_loss.E, back.reflectivity_loss.SE, front.absorptivity_loss.E, front.absorptivity_loss.SE, + f_eff_E, f_eff_SE, + back.integrated_absorbed_irradiance.E, back.integrated_absorbed_irradiance.SE, + back.integrated_irradiance.E, back.integrated_irradiance.SE, + back.reflectivity_loss.E, back.reflectivity_loss.SE, back.absorptivity_loss.E, back.absorptivity_loss.SE, - front.cos_loss.E, front.cos_loss.SE, - back.cos_loss.E, back.cos_loss.SE, - f_eff_E, f_eff_SE, b_eff_E, b_eff_SE); + b_eff_E, b_eff_SE); + } + + /* Primary-instances' data */ + htable_primary_begin(&solstice->primaries, &p_it); + htable_primary_end(&solstice->primaries, &p_end); + while (!htable_primary_iterator_eq(&p_it, &p_end)) { + const struct str* name = htable_primary_iterator_key_get(&p_it); + struct solstice_primary* prim = htable_primary_iterator_data_get(&p_it); + struct ssol_mc_sampled sampled; + uint32_t id; + + htable_primary_iterator_next(&p_it); + SSOL(estimator_get_mc_sampled(estimator, prim->node->instance, &sampled)); + SSOL(instance_get_id(prim->node->instance, &id)); + SSOL(instance_get_area(prim->node->instance, &area)); + fprintf(solstice->output, + "%s %u %g %lu " + "%g %g %g %g\n", + str_cget(name), (unsigned) id, area, (unsigned long)sampled.nb_samples, + sampled.cos_factor.E, sampled.cos_factor.SE, + sampled.shadowed.E, sampled.shadowed.SE + ); } - fprintf(solstice->output, "%g %g\n", - mc_global.shadowed.E, mc_global.shadowed.SE); - fprintf(solstice->output, "%g %g\n", - mc_global.missing.E, mc_global.missing.SE); + /* ReceiverXprimarys' data */ + htable_receiver_begin(&solstice->receivers, &r_it); + htable_receiver_end(&solstice->receivers, &r_end); + while (!htable_receiver_iterator_eq(&r_it, &r_end)) { + struct solstice_receiver* rcv = htable_receiver_iterator_data_get(&r_it); + struct ssol_instance* rcv_inst = rcv->node->instance; + uint32_t rcv_id, prim_id; + + SSOL(instance_get_id(rcv_inst, &rcv_id)); + htable_primary_begin(&solstice->primaries, &p_it); + htable_primary_end(&solstice->primaries, &p_end); + while (!htable_primary_iterator_eq(&p_it, &p_end)) { + struct solstice_primary* prim = htable_primary_iterator_data_get(&p_it); + struct ssol_instance* prim_inst = prim->node->instance; + struct ssol_mc_receiver front = MC_RCV_NONE__; + struct ssol_mc_receiver back = MC_RCV_NONE__; + + SSOL(instance_get_id(prim_inst, &prim_id)); + switch (rcv->side) { + case SRCVL_FRONT: + SSOL(estimator_get_mc_sampled_x_receiver + (estimator, prim_inst, rcv_inst, SSOL_FRONT, &front)); + break; + case SRCVL_BACK: + SSOL(estimator_get_mc_sampled_x_receiver + (estimator, prim_inst, rcv_inst, SSOL_BACK, &back)); + break; + case SRCVL_FRONT_AND_BACK: + SSOL(estimator_get_mc_sampled_x_receiver + (estimator, prim_inst, rcv_inst, SSOL_FRONT, &front)); + SSOL(estimator_get_mc_sampled_x_receiver + (estimator, prim_inst, rcv_inst, SSOL_BACK, &back)); + break; + default: FATAL("Unreachable code.\n"); break; + } + fprintf(solstice->output, + "%u %u " + "%g %g %g %g %g %g %g %g " + "%g %g %g %g %g %g %g %g\n", + (unsigned) rcv_id, (unsigned) prim_id, + front.integrated_absorbed_irradiance.E, front.integrated_absorbed_irradiance.SE, + front.integrated_irradiance.E, front.integrated_irradiance.SE, + front.reflectivity_loss.E, front.reflectivity_loss.SE, + front.absorptivity_loss.E, front.absorptivity_loss.SE, + back.integrated_absorbed_irradiance.E, back.integrated_absorbed_irradiance.SE, + back.integrated_irradiance.E, back.integrated_irradiance.SE, + back.reflectivity_loss.E, back.reflectivity_loss.SE, + back.absorptivity_loss.E, back.absorptivity_loss.SE); + htable_primary_iterator_next(&p_it); + } + htable_receiver_iterator_next(&r_it); + } } static void @@ -304,7 +391,7 @@ dump_path_segments fprintf(solstice->output, "%lu", (unsigned long)nverts); FOR_EACH(i, 0, nverts) { - fprintf(solstice->output, " %lu", (unsigned long)i + offset); + fprintf(solstice->output, " %lu", (unsigned long)(i + offset)); } fprintf(solstice->output, "\n"); } @@ -314,7 +401,7 @@ write_paths(struct solstice* solstice, struct ssol_estimator* estimator) { struct ssol_path path; size_t ipath, npaths; - size_t nverts, nlines; + size_t nverts; size_t offset; ASSERT(solstice && estimator); @@ -332,7 +419,6 @@ write_paths(struct solstice* solstice, struct ssol_estimator* estimator) SSOL(estimator_get_tracked_path(estimator, ipath, &path)); SSOL(path_get_vertices_count(&path, &n)); nverts += n; - nlines += n - 1; } /* Write the positions of the tracked paths */ @@ -345,7 +431,7 @@ write_paths(struct solstice* solstice, struct ssol_estimator* estimator) /* Write the segment of the tracked paths */ offset = 0; fprintf(solstice->output, "LINES %lu %lu\n", - (unsigned long)npaths, (unsigned long)nverts + npaths); + (unsigned long)npaths, (unsigned long)(nverts + npaths)); FOR_EACH(ipath, 0, npaths) { size_t n; SSOL(estimator_get_tracked_path(estimator, ipath, &path)); @@ -381,11 +467,8 @@ write_paths(struct solstice* solstice, struct ssol_estimator* estimator) res_T solstice_solve(struct solstice* solstice) { - char buf[1024]; struct ssol_estimator* estimator = NULL; struct ssp_rng* rng = NULL; - FILE* bin_stream = NULL; - size_t sz; res_T res = RES_OK; ASSERT(solstice); @@ -395,21 +478,11 @@ solstice_solve(struct solstice* solstice) goto error; } - if(solstice->output_hits) { - bin_stream = tmpfile(); - if(!bin_stream) { - fprintf(stderr, "Could not create the temporary output binary stream.\n"); - res = RES_IO_ERR; - goto error; - } - } - res = ssol_solve(solstice->scene, rng, solstice->nexperiments, - solstice->dump_paths ? &solstice->path_tracker : NULL, bin_stream, - &estimator); + solstice->dump_paths ? &solstice->path_tracker : NULL, NULL, &estimator); if(res != RES_OK) { fprintf(stderr, "Error in integrating the solar flux.\n"); - goto error; + if(!estimator) goto error; } if(solstice->dump_paths) { @@ -417,30 +490,9 @@ solstice_solve(struct solstice* solstice) } else { write_mc_global(solstice, estimator); write_per_receiver_mc_primitive(solstice, estimator); - - if(solstice->output_hits) { - sz = (size_t)ftell(bin_stream); - rewind(bin_stream); - - while(sz) { - const size_t read_sz = MMIN(sz, sizeof(buf)); - if(fread(buf, 1, read_sz, bin_stream) != read_sz) { - fprintf(stderr, "Could not read the output binary stream.\n"); - res = RES_IO_ERR; - goto error; - } - if(fwrite(buf, 1, read_sz, solstice->output) != read_sz) { - fprintf(stderr, "Could not write the output binary stream.\n"); - res = RES_IO_ERR; - goto error; - } - sz -= read_sz; - } - } } exit: - if(bin_stream) fclose(bin_stream); if(estimator) SSOL(estimator_ref_put(estimator)); if(rng) SSP(rng_ref_put(rng)); return res; diff --git a/src/solstice_spectrum.c b/src/solstice_spectrum.c @@ -0,0 +1,71 @@ +/* Copyright (C) CNRS 2016-2017 + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. */ + +#include "solstice_c.h" + +/******************************************************************************* + * Helper function + ******************************************************************************/ +static void +get_wavelength(const size_t i, double* wlen, double* data, void* ctx) +{ + const struct solparser_spectrum_data* specdata = ctx; + ASSERT(wlen && data && ctx); + *wlen = specdata[i].wavelength; + *data = specdata[i].data; +} + +/******************************************************************************* + * Local functions + ******************************************************************************/ +res_T +solstice_create_ssol_spectrum + (struct solstice* solstice, + const struct solparser_spectrum_id spectrum_id, + struct ssol_spectrum** out_spectrum) +{ + struct ssol_spectrum* spectrum = NULL; + const struct solparser_spectrum_data* data; + const struct solparser_spectrum* spec; + size_t nwlens; + res_T res = RES_OK; + ASSERT(solstice && SOLPARSER_ID_IS_VALID(spectrum_id) && out_spectrum); + + res = ssol_spectrum_create(solstice->ssol, &spectrum); + if(res != RES_OK) { + fprintf(stderr, "Could not create the Solstice Solver spectrum.\n"); + goto error; + } + + spec = solparser_get_spectrum(solstice->parser, spectrum_id); + nwlens = darray_spectrum_data_size_get(&spec->data); + data = darray_spectrum_data_cdata_get(&spec->data); + res = ssol_spectrum_setup(spectrum, get_wavelength, nwlens, (void*)data); + if(res != RES_OK) { + fprintf(stderr, "Could not setup the Solstice Solver spectrum.\n"); + goto error; + } + +exit: + *out_spectrum = spectrum; + return res; +error: + if(spectrum) { + SSOL(spectrum_ref_put(spectrum)); + spectrum = NULL; + } + goto exit; +} + diff --git a/src/solstice_sun.c b/src/solstice_sun.c @@ -14,6 +14,7 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include "solstice_c.h" +#include "solstice_sun_spectrum.h" #include "parser/solparser.h" #include "parser/solparser_sun.h" @@ -125,23 +126,26 @@ error: static void get_wavelength(const size_t i, double* wlen, double* data, void* ctx) { - const struct solparser_spectrum_data* specdata = ctx; + const double* spectrum = ctx; ASSERT(wlen && data && ctx); - *wlen = specdata[i].wavelength; - *data = specdata[i].data; + *wlen = spectrum[i*2+0]; + *data = spectrum[i*2+1]; } static res_T -create_sun_spectrum +create_default_sun_spectrum (struct solstice* solstice, const struct solparser_sun* solparser_sun, struct ssol_spectrum** out_spectrum) { struct ssol_spectrum* spectrum = NULL; - const struct solparser_spectrum_data* data; - size_t nwlens; + const double* data; + size_t size; res_T res = RES_OK; - ASSERT(solstice && solparser_sun && out_spectrum); + + /* The solparser_sun may be used if the defautl spectrum is defined wrt the + * sun type */ + (void)solparser_sun; res = ssol_spectrum_create(solstice->ssol, &spectrum); if(res != RES_OK) { @@ -149,11 +153,17 @@ create_sun_spectrum goto error; } - nwlens = darray_spectrum_data_size_get(&solparser_sun->spectrum); - data = darray_spectrum_data_cdata_get(&solparser_sun->spectrum); - res = ssol_spectrum_setup(spectrum, get_wavelength, nwlens, (void*)data); + if(solparser_has_spectrum(solstice->parser)) { + data = solstice_sun_spectrum_smarts; + size = solstice_sun_spectrum_smarts_size; + } else { + data = solstice_sun_spectrum_dummy; + size = solstice_sun_spectrum_dummy_size; + } + + res = ssol_spectrum_setup(spectrum, get_wavelength, size, (void*)data); if(res != RES_OK) { - fprintf(stderr, "Could no setup the spectrum of the solver sun.\n"); + fprintf(stderr, "Coul not setup the default spectrum of the solver sun.\n"); goto error; } @@ -195,8 +205,14 @@ solstice_create_sun(struct solstice* solstice) } if(res != RES_OK) goto error; - res = create_sun_spectrum(solstice, solparser_sun, &spectrum); - if(res != RES_OK) goto error; + if(!SOLPARSER_ID_IS_VALID(solparser_sun->spectrum)) { + res = create_default_sun_spectrum(solstice, solparser_sun, &spectrum); + if(res != RES_OK) goto error; + } else { + res = solstice_create_ssol_spectrum + (solstice, solparser_sun->spectrum, &spectrum); + if(res != RES_OK) goto error; + } res = ssol_sun_set_spectrum(sun, spectrum); if(res != RES_OK) { diff --git a/src/solstice_sun_spectrum.c b/src/solstice_sun_spectrum.c @@ -0,0 +1,772 @@ +/* Copyright (C) CNRS 2016-2017 + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. */ + +#include "solstice_sun_spectrum.h" + +const double solstice_sun_spectrum_dummy[] = { 1, 1 }; +const size_t solstice_sun_spectrum_dummy_size = 1; + +const double solstice_sun_spectrum_smarts[] = { + 2.800000e-01, 1.755832e-22, + 2.850000e-01, 3.294496e-13, + 2.900000e-01, 9.825730e-07, + 2.950000e-01, 4.867814e-03, + 3.000000e-01, 5.930555e-01, + 3.050000e-01, 1.009141e+01, + 3.100000e-01, 3.418097e+01, + 3.150000e-01, 8.042174e+01, + 3.200000e-01, 1.269513e+02, + 3.250000e-01, 1.755832e+02, + 3.300000e-01, 2.802401e+02, + 3.350000e-01, 2.853227e+02, + 3.400000e-01, 3.165119e+02, + 3.450000e-01, 3.021880e+02, + 3.500000e-01, 3.613318e+02, + 3.550000e-01, 4.239411e+02, + 3.600000e-01, 4.052276e+02, + 3.650000e-01, 4.730351e+02, + 3.700000e-01, 5.417667e+02, + 3.750000e-01, 4.694541e+02, + 3.800000e-01, 5.618663e+02, + 3.850000e-01, 5.083828e+02, + 3.900000e-01, 6.487338e+02, + 3.950000e-01, 6.482718e+02, + 4.000000e-01, 9.550803e+02, + 4.050000e-01, 9.825730e+02, + 4.100000e-01, 9.814178e+02, + 4.150000e-01, 1.076949e+03, + 4.200000e-01, 1.098781e+03, + 4.250000e-01, 1.125350e+03, + 4.300000e-01, 8.677508e+02, + 4.350000e-01, 1.148568e+03, + 4.400000e-01, 1.220997e+03, + 4.450000e-01, 1.329581e+03, + 4.500000e-01, 1.492457e+03, + 4.550000e-01, 1.458958e+03, + 4.600000e-01, 1.491302e+03, + 4.650000e-01, 1.502854e+03, + 4.700000e-01, 1.461268e+03, + 4.750000e-01, 1.546750e+03, + 4.800000e-01, 1.581404e+03, + 4.850000e-01, 1.485527e+03, + 4.900000e-01, 1.568698e+03, + 4.950000e-01, 1.591801e+03, + 5.000000e-01, 1.539819e+03, + 5.050000e-01, 1.549060e+03, + 5.100000e-01, 1.569853e+03, + 5.150000e-01, 1.554836e+03, + 5.200000e-01, 1.516716e+03, + 5.250000e-01, 1.613748e+03, + 5.300000e-01, 1.609128e+03, + 5.350000e-01, 1.610283e+03, + 5.400000e-01, 1.515560e+03, + 5.450000e-01, 1.592956e+03, + 5.500000e-01, 1.595266e+03, + 5.550000e-01, 1.618369e+03, + 5.600000e-01, 1.557146e+03, + 5.650000e-01, 1.554836e+03, + 5.700000e-01, 1.515560e+03, + 5.750000e-01, 1.542129e+03, + 5.800000e-01, 1.561767e+03, + 5.850000e-01, 1.582559e+03, + 5.900000e-01, 1.363080e+03, + 5.950000e-01, 1.440476e+03, + 6.000000e-01, 1.523647e+03, + 6.050000e-01, 1.558301e+03, + 6.100000e-01, 1.539819e+03, + 6.150000e-01, 1.543284e+03, + 6.200000e-01, 1.555991e+03, + 6.250000e-01, 1.473975e+03, + 6.300000e-01, 1.460113e+03, + 6.350000e-01, 1.519026e+03, + 6.400000e-01, 1.524802e+03, + 6.450000e-01, 1.524802e+03, + 6.500000e-01, 1.461268e+03, + 6.550000e-01, 1.398890e+03, + 6.600000e-01, 1.465889e+03, + 6.650000e-01, 1.490147e+03, + 6.700000e-01, 1.493613e+03, + 6.750000e-01, 1.482061e+03, + 6.800000e-01, 1.473975e+03, + 6.850000e-01, 1.438165e+03, + 6.900000e-01, 1.227927e+03, + 6.950000e-01, 1.281064e+03, + 7.000000e-01, 1.282220e+03, + 7.050000e-01, 1.331891e+03, + 7.100000e-01, 1.342288e+03, + 7.150000e-01, 1.306478e+03, + 7.200000e-01, 8.671732e+02, + 7.250000e-01, 9.532321e+02, + 7.300000e-01, 1.061239e+03, + 7.350000e-01, 1.217531e+03, + 7.400000e-01, 1.253341e+03, + 7.450000e-01, 1.311098e+03, + 7.500000e-01, 1.303012e+03, + 7.550000e-01, 1.293771e+03, + 7.600000e-01, 2.831280e+02, + 7.650000e-01, 7.233567e+02, + 7.700000e-01, 1.226772e+03, + 7.750000e-01, 1.236014e+03, + 7.800000e-01, 1.237169e+03, + 7.850000e-01, 1.229083e+03, + 7.900000e-01, 1.118765e+03, + 7.950000e-01, 1.164394e+03, + 8.000000e-01, 1.134014e+03, + 8.050000e-01, 1.121307e+03, + 8.100000e-01, 1.091042e+03, + 8.150000e-01, 8.507700e+02, + 8.200000e-01, 8.317100e+02, + 8.250000e-01, 1.000362e+03, + 8.300000e-01, 9.195016e+02, + 8.350000e-01, 1.049456e+03, + 8.400000e-01, 1.061354e+03, + 8.450000e-01, 1.078220e+03, + 8.500000e-01, 1.017921e+03, + 8.550000e-01, 9.829195e+02, + 8.600000e-01, 1.063665e+03, + 8.650000e-01, 1.007640e+03, + 8.700000e-01, 1.043219e+03, + 8.750000e-01, 1.036288e+03, + 8.800000e-01, 1.023003e+03, + 8.850000e-01, 1.012145e+03, + 8.900000e-01, 1.000016e+03, + 8.950000e-01, 8.095311e+02, + 9.000000e-01, 7.268221e+02, + 9.050000e-01, 8.257032e+02, + 9.100000e-01, 5.527406e+02, + 9.150000e-01, 6.158120e+02, + 9.200000e-01, 7.346772e+02, + 9.250000e-01, 6.600543e+02, + 9.300000e-01, 3.049603e+02, + 9.350000e-01, 1.475130e+02, + 9.400000e-01, 3.614473e+02, + 9.450000e-01, 2.581767e+02, + 9.500000e-01, 6.159275e+01, + 9.550000e-01, 2.303375e+02, + 9.600000e-01, 3.137395e+02, + 9.650000e-01, 4.293703e+02, + 9.700000e-01, 5.969830e+02, + 9.750000e-01, 5.647542e+02, + 9.800000e-01, 5.682197e+02, + 9.850000e-01, 6.823488e+02, + 9.900000e-01, 7.674835e+02, + 9.950000e-01, 8.192344e+02, + 1, 8.012140e+02, + 1.005000e+00, 7.822695e+02, + 1.010000e+00, 7.758006e+02, + 1.015000e+00, 7.794971e+02, + 1.020000e+00, 7.657508e+02, + 1.025000e+00, 7.675990e+02, + 1.030000e+00, 7.572027e+02, + 1.035000e+00, 7.464597e+02, + 1.040000e+00, 7.380271e+02, + 1.045000e+00, 7.256670e+02, + 1.050000e+00, 7.190826e+02, + 1.055000e+00, 7.090328e+02, + 1.060000e+00, 6.904348e+02, + 1.065000e+00, 6.854677e+02, + 1.070000e+00, 6.587836e+02, + 1.075000e+00, 6.438822e+02, + 1.080000e+00, 6.396081e+02, + 1.085000e+00, 6.422650e+02, + 1.090000e+00, 5.934020e+02, + 1.095000e+00, 5.304462e+02, + 1.100000e+00, 4.647180e+02, + 1.105000e+00, 4.916330e+02, + 1.110000e+00, 4.297168e+02, + 1.115000e+00, 1.782401e+02, + 1.120000e+00, 6.423805e+01, + 1.125000e+00, 6.967882e+01, + 1.130000e+00, 2.260634e+01, + 1.135000e+00, 4.263669e+00, + 1.140000e+00, 1.699230e+02, + 1.145000e+00, 6.558958e+01, + 1.150000e+00, 6.521993e+01, + 1.155000e+00, 2.327633e+02, + 1.160000e+00, 2.165912e+02, + 1.165000e+00, 3.331461e+02, + 1.170000e+00, 4.473907e+02, + 1.175000e+00, 4.572095e+02, + 1.180000e+00, 4.366478e+02, + 1.185000e+00, 3.854745e+02, + 1.190000e+00, 4.808901e+02, + 1.195000e+00, 4.510872e+02, + 1.200000e+00, 4.587112e+02, + 1.205000e+00, 4.491234e+02, + 1.210000e+00, 4.704937e+02, + 1.215000e+00, 4.268290e+02, + 1.220000e+00, 4.885141e+02, + 1.225000e+00, 4.982174e+02, + 1.230000e+00, 4.974088e+02, + 1.235000e+00, 5.173929e+02, + 1.240000e+00, 5.160068e+02, + 1.245000e+00, 5.130034e+02, + 1.250000e+00, 5.102310e+02, + 1.255000e+00, 5.015674e+02, + 1.260000e+00, 4.792729e+02, + 1.265000e+00, 4.427701e+02, + 1.270000e+00, 4.321427e+02, + 1.275000e+00, 4.596353e+02, + 1.280000e+00, 4.599818e+02, + 1.285000e+00, 4.644869e+02, + 1.290000e+00, 4.539751e+02, + 1.295000e+00, 4.331823e+02, + 1.300000e+00, 3.504734e+02, + 1.305000e+00, 4.007225e+02, + 1.310000e+00, 2.752729e+02, + 1.315000e+00, 2.498596e+02, + 1.320000e+00, 2.327633e+02, + 1.325000e+00, 3.078482e+02, + 1.330000e+00, 1.720023e+02, + 1.335000e+00, 1.822831e+02, + 1.340000e+00, 1.253341e+02, + 1.345000e+00, 5.043397e+01, + 1.350000e+00, 1.852865e+00, + 1.355000e+00, 1.421993e-06, + 1.360000e+00, 4.201291e-07, + 1.365000e+00, 2.019207e-16, + 1.370000e+00, 8.799954e-09, + 1.375000e+00, 7.149241e-04, + 1.380000e+00, 2.424666e-04, + 1.385000e+00, 1.434700e-06, + 1.390000e+00, 1.954519e-03, + 1.395000e+00, 2.606025e-07, + 1.400000e+00, 3.272548e-12, + 1.405000e+00, 6.190464e-08, + 1.410000e+00, 5.661404e-03, + 1.415000e+00, 1.804349e-03, + 1.420000e+00, 7.145775e-01, + 1.425000e+00, 4.718799e+00, + 1.430000e+00, 2.378460e+01, + 1.435000e+00, 3.674541e+00, + 1.440000e+00, 1.269513e+01, + 1.445000e+00, 1.381563e+01, + 1.450000e+00, 7.487701e+00, + 1.455000e+00, 3.016104e+01, + 1.460000e+00, 4.723420e+01, + 1.465000e+00, 5.845073e+01, + 1.470000e+00, 1.375787e+01, + 1.475000e+00, 1.321495e+02, + 1.480000e+00, 2.521699e+01, + 1.485000e+00, 8.132276e+01, + 1.490000e+00, 1.404666e+02, + 1.495000e+00, 1.506319e+02, + 1.500000e+00, 2.457010e+02, + 1.505000e+00, 1.679592e+02, + 1.510000e+00, 2.838210e+02, + 1.515000e+00, 2.803556e+02, + 1.520000e+00, 2.709988e+02, + 1.525000e+00, 2.742333e+02, + 1.530000e+00, 2.812797e+02, + 1.535000e+00, 2.921381e+02, + 1.540000e+00, 3.012639e+02, + 1.545000e+00, 3.099275e+02, + 1.550000e+00, 3.042673e+02, + 1.555000e+00, 3.003397e+02, + 1.560000e+00, 3.006863e+02, + 1.565000e+00, 2.990691e+02, + 1.570000e+00, 2.735402e+02, + 1.575000e+00, 2.793159e+02, + 1.580000e+00, 2.746953e+02, + 1.585000e+00, 2.874020e+02, + 1.590000e+00, 2.694972e+02, + 1.595000e+00, 2.856693e+02, + 1.600000e+00, 2.646455e+02, + 1.605000e+00, 2.668403e+02, + 1.610000e+00, 2.498596e+02, + 1.615000e+00, 2.667248e+02, + 1.620000e+00, 2.664938e+02, + 1.625000e+00, 2.700747e+02, + 1.630000e+00, 2.686885e+02, + 1.635000e+00, 2.596784e+02, + 1.640000e+00, 2.400408e+02, + 1.645000e+00, 2.470872e+02, + 1.650000e+00, 2.502061e+02, + 1.655000e+00, 2.505526e+02, + 1.660000e+00, 2.503216e+02, + 1.665000e+00, 2.378460e+02, + 1.670000e+00, 2.482423e+02, + 1.675000e+00, 2.396942e+02, + 1.680000e+00, 2.306840e+02, + 1.685000e+00, 2.391166e+02, + 1.690000e+00, 2.287203e+02, + 1.695000e+00, 2.350736e+02, + 1.700000e+00, 2.195945e+02, + 1.705000e+00, 2.177463e+02, + 1.710000e+00, 2.065413e+02, + 1.715000e+00, 2.040000e+02, + 1.720000e+00, 2.040000e+02, + 1.725000e+00, 1.882899e+02, + 1.730000e+00, 1.879434e+02, + 1.735000e+00, 1.700385e+02, + 1.740000e+00, 1.747746e+02, + 1.745000e+00, 1.594111e+02, + 1.750000e+00, 1.725798e+02, + 1.755000e+00, 1.523647e+02, + 1.760000e+00, 1.639162e+02, + 1.765000e+00, 1.238324e+02, + 1.770000e+00, 1.276444e+02, + 1.775000e+00, 9.467632e+01, + 1.780000e+00, 7.652887e+01, + 1.785000e+00, 4.875900e+01, + 1.790000e+00, 6.226274e+01, + 1.795000e+00, 1.964915e+01, + 1.800000e+00, 1.596421e+01, + 1.805000e+00, 2.681110e+00, + 1.810000e+00, 1.351529e+00, + 1.815000e+00, 1.782401e-01, + 1.820000e+00, 2.100068e-02, + 1.825000e+00, 2.950260e-02, + 1.830000e+00, 5.069966e-06, + 1.835000e+00, 3.109671e-06, + 1.840000e+00, 1.126390e-08, + 1.845000e+00, 7.945141e-07, + 1.850000e+00, 2.736557e-07, + 1.855000e+00, 5.976761e-08, + 1.860000e+00, 3.084258e-05, + 1.865000e+00, 2.344960e-05, + 1.870000e+00, 4.700317e-13, + 1.875000e+00, 1.053730e-12, + 1.880000e+00, 3.766953e-04, + 1.885000e+00, 1.557146e-04, + 1.890000e+00, 8.908538e-04, + 1.895000e+00, 8.015605e-04, + 1.900000e+00, 3.690713e-07, + 1.905000e+00, 3.564802e-07, + 1.910000e+00, 3.483941e-05, + 1.915000e+00, 8.942038e-05, + 1.920000e+00, 3.726523e-03, + 1.925000e+00, 2.120861e-02, + 1.930000e+00, 1.522491e-02, + 1.935000e+00, 3.087723e-01, + 1.940000e+00, 3.988743e-01, + 1.945000e+00, 2.781608e+00, + 1.950000e+00, 6.680249e+00, + 1.955000e+00, 2.853227e+00, + 1.960000e+00, 1.102131e+01, + 1.965000e+00, 1.737350e+01, + 1.970000e+00, 3.748471e+01, + 1.975000e+00, 5.294065e+01, + 1.980000e+00, 6.599388e+01, + 1.985000e+00, 7.625164e+01, + 1.990000e+00, 7.612457e+01, + 1.995000e+00, 7.584733e+01, + 2, 3.413477e+01, + 2.005000e+00, 1.133320e+01, + 2.010000e+00, 3.980657e+01, + 2.015000e+00, 2.313771e+01, + 2.020000e+00, 4.245187e+01, + 2.025000e+00, 7.589354e+01, + 2.030000e+00, 8.488063e+01, + 2.035000e+00, 1.036519e+02, + 2.040000e+00, 9.467632e+01, + 2.045000e+00, 9.695198e+01, + 2.050000e+00, 7.200067e+01, + 2.055000e+00, 5.648697e+01, + 2.060000e+00, 7.166568e+01, + 2.065000e+00, 6.471166e+01, + 2.070000e+00, 6.833884e+01, + 2.075000e+00, 8.371392e+01, + 2.080000e+00, 9.408720e+01, + 2.085000e+00, 9.265481e+01, + 2.090000e+00, 9.914677e+01, + 2.095000e+00, 9.885798e+01, + 2.100000e+00, 9.155741e+01, + 2.105000e+00, 1.043450e+02, + 2.110000e+00, 9.829195e+01, + 2.115000e+00, 1.024158e+02, + 2.120000e+00, 9.531166e+01, + 2.125000e+00, 9.782989e+01, + 2.130000e+00, 9.974745e+01, + 2.135000e+00, 1.005561e+02, + 2.140000e+00, 1.021848e+02, + 2.145000e+00, 1.008102e+02, + 2.150000e+00, 9.193861e+01, + 2.155000e+00, 9.273567e+01, + 2.160000e+00, 9.260860e+01, + 2.165000e+00, 8.261653e+01, + 2.170000e+00, 9.129173e+01, + 2.175000e+00, 8.697146e+01, + 2.180000e+00, 9.136104e+01, + 2.185000e+00, 7.770713e+01, + 2.190000e+00, 8.627836e+01, + 2.195000e+00, 8.574699e+01, + 2.200000e+00, 7.709490e+01, + 2.205000e+00, 8.019071e+01, + 2.210000e+00, 8.848471e+01, + 2.215000e+00, 8.380634e+01, + 2.220000e+00, 8.744507e+01, + 2.225000e+00, 8.378323e+01, + 2.230000e+00, 8.583941e+01, + 2.235000e+00, 8.345979e+01, + 2.240000e+00, 8.287066e+01, + 2.245000e+00, 7.990192e+01, + 2.250000e+00, 8.172706e+01, + 2.255000e+00, 7.652887e+01, + 2.260000e+00, 7.598595e+01, + 2.265000e+00, 7.731438e+01, + 2.270000e+00, 7.353703e+01, + 2.275000e+00, 7.257825e+01, + 2.280000e+00, 7.551234e+01, + 2.285000e+00, 7.141155e+01, + 2.290000e+00, 7.159637e+01, + 2.295000e+00, 6.921676e+01, + 2.300000e+00, 6.564733e+01, + 2.305000e+00, 6.586681e+01, + 2.310000e+00, 6.974813e+01, + 2.315000e+00, 6.378754e+01, + 2.320000e+00, 5.589784e+01, + 2.325000e+00, 5.843918e+01, + 2.330000e+00, 6.036829e+01, + 2.335000e+00, 6.296738e+01, + 2.340000e+00, 4.414994e+01, + 2.345000e+00, 5.389943e+01, + 2.350000e+00, 4.024552e+01, + 2.355000e+00, 4.850487e+01, + 2.360000e+00, 5.193567e+01, + 2.365000e+00, 4.863193e+01, + 2.370000e+00, 2.624507e+01, + 2.375000e+00, 4.312185e+01, + 2.380000e+00, 3.800453e+01, + 2.385000e+00, 2.428131e+01, + 2.390000e+00, 3.251755e+01, + 2.395000e+00, 3.768108e+01, + 2.400000e+00, 4.099637e+01, + 2.405000e+00, 2.709988e+01, + 2.410000e+00, 2.648765e+01, + 2.415000e+00, 1.916399e+01, + 2.420000e+00, 1.944122e+01, + 2.425000e+00, 2.625662e+01, + 2.430000e+00, 3.942537e+01, + 2.435000e+00, 8.307859e+00, + 2.440000e+00, 3.668765e+01, + 2.445000e+00, 1.312254e+01, + 2.450000e+00, 6.917055e+00, + 2.455000e+00, 1.529422e+01, + 2.460000e+00, 2.475492e+01, + 2.465000e+00, 1.468199e+01, + 2.470000e+00, 7.535062e+00, + 2.475000e+00, 7.232412e+00, + 2.480000e+00, 2.036534e+00, + 2.485000e+00, 1.159773e+00, + 2.490000e+00, 4.409218e-01, + 2.495000e+00, 3.889400e-01, + 2.500000e+00, 1.192118e+00, + 2.505000e+00, 1.178256e-01, + 2.510000e+00, 2.302220e-01, + 2.515000e+00, 2.307995e-02, + 2.520000e+00, 5.186636e-03, + 2.525000e+00, 8.529648e-05, + 2.530000e+00, 5.429218e-08, + 2.535000e+00, 2.571370e-09, + 2.540000e+00, 1.254496e-08, + 2.545000e+00, 7.580113e-14, + 2.550000e+00, 1.089194e-20, + 2.555000e+00, 1.036288e-12, + 2.560000e+00, 6.137327e-14, + 2.565000e+00, 1.341132e-19, + 2.570000e+00, 4.495855e-27, + 2.575000e+00, 2.722695e-43, + 2.580000e+00, 8.278980e-35, + 2.585000e+00, 5.818505e-56, + 2.590000e+00, 1.185187e-50, + 2.595000e+00, 2.414269e-47, + 2.600000e+00, 8.499614e-46, + 2.605000e+00, 3.937916e-52, + 2.610000e+00, 4.453114e-55, + 2.615000e+00, 1.024505e-60, + 2.620000e+00, 6.394926e-43, + 2.625000e+00, 7.158482e-47, + 2.630000e+00, 6.029898e-76, + 2.635000e+00, 8.243170e-23, + 2.640000e+00, 1.977622e-25, + 2.645000e+00, 3.870917e-28, + 2.650000e+00, 5.282514e-31, + 2.655000e+00, 2.154360e-44, + 2.660000e+00, 7.691007e-38, + 2.665000e+00, 4.388426e-57, + 2.670000e+00, 6.902038e-97, + 2.675000e+00, 1.127314e-72, + 2.680000e+00, 7.614767e-78, + 2.685000e+00, 2.016897e-93, + 2.690000e+00, 4.231325e-45, + 2.695000e+00, 5.160068e-46, + 2.700000e+00, 3.717282e-70, + 2.705000e+00, 5.757282e-56, + 2.710000e+00, 8.303238e-47, + 2.715000e+00, 9.111845e-41, + 2.720000e+00, 9.901970e-73, + 2.725000e+00, 1.520181e-30, + 2.730000e+00, 1.561767e-30, + 2.735000e+00, 7.793816e-32, + 2.740000e+00, 3.076172e-38, + 2.745000e+00, 1.721178e-37, + 2.750000e+00, 5.867021e-42, + 2.755000e+00, 6.732231e-56, + 2.760000e+00, 1.425459e-56, + 2.765000e+00, 2.810487e-38, + 2.770000e+00, 6.439977e-34, + 2.775000e+00, 3.742695e-48, + 2.780000e+00, 3.463148e-41, + 2.785000e+00, 1.364235e-36, + 2.790000e+00, 8.396806e-22, + 2.795000e+00, 9.365979e-23, + 2.800000e+00, 1.356149e-14, + 2.805000e+00, 2.779298e-16, + 2.810000e+00, 4.397667e-12, + 2.815000e+00, 3.218256e-12, + 2.820000e+00, 7.425322e-14, + 2.825000e+00, 1.903692e-08, + 2.830000e+00, 3.691868e-06, + 2.835000e+00, 4.135447e-13, + 2.840000e+00, 6.424960e-08, + 2.845000e+00, 2.679955e-04, + 2.850000e+00, 4.470441e-07, + 2.855000e+00, 3.652593e-07, + 2.860000e+00, 2.067724e-04, + 2.865000e+00, 3.345323e-03, + 2.870000e+00, 1.248720e-05, + 2.875000e+00, 1.402356e-02, + 2.880000e+00, 8.862332e-03, + 2.885000e+00, 1.924485e-02, + 2.890000e+00, 7.473839e-03, + 2.895000e+00, 4.261359e-01, + 2.900000e+00, 9.198482e-02, + 2.905000e+00, 2.128947e-03, + 2.910000e+00, 6.100362e-01, + 2.915000e+00, 1.715402e-01, + 2.920000e+00, 6.144258e-01, + 2.925000e+00, 2.073499e-01, + 2.930000e+00, 1.656489e+00, + 2.935000e+00, 2.313771e+00, + 2.940000e+00, 2.400408e-01, + 2.945000e+00, 1.966070e-01, + 2.950000e+00, 1.638007e+00, + 2.955000e+00, 7.849263e-01, + 2.960000e+00, 1.492457e+00, + 2.965000e+00, 3.734609e+00, + 2.970000e+00, 4.676059e-02, + 2.975000e+00, 1.094623e-01, + 2.980000e+00, 2.450079e-01, + 2.985000e+00, 3.056534e+00, + 2.990000e+00, 6.057621e+00, + 2.995000e+00, 1.480906e+00, + 3, 3.981812e+00, + 3.005000e+00, 9.241222e-01, + 3.010000e+00, 3.634111e+00, + 3.015000e+00, 2.126636e+00, + 3.020000e+00, 4.987950e-02, + 3.025000e+00, 3.859366e+00, + 3.030000e+00, 2.861314e+00, + 3.035000e+00, 7.404530e-01, + 3.040000e+00, 5.771143e-01, + 3.045000e+00, 1.351529e+00, + 3.050000e+00, 1.505164e-01, + 3.055000e+00, 2.044620e-02, + 3.060000e+00, 3.115447e+00, + 3.065000e+00, 8.756058e-01, + 3.070000e+00, 3.492027e-01, + 3.075000e+00, 2.830124e+00, + 3.080000e+00, 1.386183e+00, + 3.085000e+00, 3.766953e-01, + 3.090000e+00, 5.635991e-01, + 3.095000e+00, 7.939365e-02, + 3.100000e+00, 1.830917e+00, + 3.105000e+00, 2.093137e-01, + 3.110000e+00, 8.597802e-02, + 3.115000e+00, 5.444235e-01, + 3.120000e+00, 5.816194e+00, + 3.125000e+00, 1.196738e+00, + 3.130000e+00, 3.370736e+00, + 3.135000e+00, 7.649422e+00, + 3.140000e+00, 1.336512e+00, + 3.145000e+00, 1.344598e+00, + 3.150000e+00, 3.883624e+00, + 3.155000e+00, 3.158188e+00, + 3.160000e+00, 6.340634e+00, + 3.165000e+00, 1.286840e+01, + 3.170000e+00, 9.983986e+00, + 3.175000e+00, 7.336376e+00, + 3.180000e+00, 8.348289e+00, + 3.185000e+00, 5.731868e+00, + 3.190000e+00, 2.194790e+00, + 3.195000e+00, 8.751438e-01, + 3.200000e+00, 4.146999e-02, + 3.205000e+00, 2.004190e-02, + 3.210000e+00, 9.394858e-03, + 3.215000e+00, 4.889762e-02, + 3.220000e+00, 4.417304e-01, + 3.225000e+00, 2.447769e-02, + 3.230000e+00, 5.661404e-02, + 3.235000e+00, 4.230170e+00, + 3.240000e+00, 1.881744e+00, + 3.245000e+00, 1.957984e-01, + 3.250000e+00, 1.468199e+00, + 3.255000e+00, 6.918210e+00, + 3.260000e+00, 5.117327e-01, + 3.265000e+00, 7.144620e-01, + 3.270000e+00, 3.461993e-01, + 3.275000e+00, 3.131619e+00, + 3.280000e+00, 1.364235e+00, + 3.285000e+00, 8.155379e+00, + 3.290000e+00, 6.398391e+00, + 3.295000e+00, 3.224031e-01, + 3.300000e+00, 6.914745e-01, + 3.305000e+00, 1.679592e+00, + 3.310000e+00, 2.510147e+00, + 3.315000e+00, 1.062972e-02, + 3.320000e+00, 8.433771e-03, + 3.325000e+00, 2.253703e+00, + 3.330000e+00, 3.401925e+00, + 3.335000e+00, 7.758006e+00, + 3.340000e+00, 1.736195e+00, + 3.345000e+00, 2.252548e+00, + 3.350000e+00, 6.016036e+00, + 3.355000e+00, 2.031914e+00, + 3.360000e+00, 3.474700e+00, + 3.365000e+00, 5.899365e+00, + 3.370000e+00, 2.852072e+00, + 3.375000e+00, 6.880090e+00, + 3.380000e+00, 4.453114e+00, + 3.385000e+00, 6.382219e+00, + 3.390000e+00, 1.068632e+01, + 3.395000e+00, 9.365979e+00, + 3.400000e+00, 1.320340e+01, + 3.405000e+00, 3.969105e+00, + 3.410000e+00, 5.988312e+00, + 3.415000e+00, 7.733748e+00, + 3.420000e+00, 1.455493e+01, + 3.425000e+00, 1.114838e+01, + 3.430000e+00, 1.007986e+01, + 3.435000e+00, 1.171325e+01, + 3.440000e+00, 8.677508e+00, + 3.445000e+00, 1.164394e+01, + 3.450000e+00, 1.297237e+01, + 3.455000e+00, 8.471891e+00, + 3.460000e+00, 1.351529e+01, + 3.465000e+00, 1.125581e+01, + 3.470000e+00, 1.354994e+01, + 3.475000e+00, 1.190963e+01, + 3.480000e+00, 1.279909e+01, + 3.485000e+00, 1.338822e+01, + 3.490000e+00, 1.101785e+01, + 3.495000e+00, 1.378097e+01, + 3.500000e+00, 1.314564e+01, + 3.505000e+00, 1.318029e+01, + 3.510000e+00, 1.311098e+01, + 3.515000e+00, 1.164394e+01, + 3.520000e+00, 1.328426e+01, + 3.525000e+00, 1.208290e+01, + 3.530000e+00, 1.186342e+01, + 3.535000e+00, 9.635130e+00, + 3.540000e+00, 9.058708e+00, + 3.545000e+00, 9.734473e+00, + 3.550000e+00, 1.095316e+01, + 3.555000e+00, 8.415288e+00, + 3.560000e+00, 1.149146e+01, + 3.565000e+00, 1.214066e+01, + 3.570000e+00, 7.699093e+00, + 3.575000e+00, 8.362151e+00, + 3.580000e+00, 1.120383e+01, + 3.585000e+00, 9.255084e+00, + 3.590000e+00, 9.442219e+00, + 3.595000e+00, 9.932004e+00, + 3.600000e+00, 1.093930e+01, + 3.605000e+00, 1.156308e+01, + 3.610000e+00, 9.555424e+00, + 3.615000e+00, 9.627044e+00, + 3.620000e+00, 1.319185e+01, + 3.625000e+00, 1.099243e+01, + 3.630000e+00, 1.045760e+01, + 3.635000e+00, 1.072906e+01, + 3.640000e+00, 1.296081e+01, + 3.645000e+00, 1.189807e+01, + 3.650000e+00, 1.092312e+01, + 3.655000e+00, 1.193273e+01, + 3.660000e+00, 1.182876e+01, + 3.665000e+00, 1.105135e+01, + 3.670000e+00, 7.242808e+00, + 3.675000e+00, 2.920226e+00, + 3.680000e+00, 7.257825e+00, + 3.685000e+00, 9.436443e+00, + 3.690000e+00, 1.000940e+01, + 3.695000e+00, 1.061470e+01, + 3.700000e+00, 1.223307e+01, + 3.705000e+00, 1.205980e+01, + 3.710000e+00, 9.839592e+00, + 3.715000e+00, 9.526545e+00, + 3.720000e+00, 1.134938e+01, + 3.725000e+00, 1.208290e+01, + 3.730000e+00, 9.712525e+00, + 3.735000e+00, 8.408357e+00, + 3.740000e+00, 9.006726e+00, + 3.745000e+00, 1.160929e+01, + 3.750000e+00, 9.896194e+00, + 3.755000e+00, 9.294360e+00, + 3.760000e+00, 8.864643e+00, + 3.765000e+00, 8.670577e+00, + 3.770000e+00, 9.617802e+00, + 3.775000e+00, 9.493046e+00, + 3.780000e+00, 1.045991e+01, + 3.785000e+00, 8.957055e+00, + 3.790000e+00, 7.537372e+00, + 3.795000e+00, 9.389082e+00, + 3.800000e+00, 1.133089e+01, + 3.805000e+00, 1.009604e+01, + 3.810000e+00, 8.170396e+00, + 3.815000e+00, 7.491166e+00, + 3.820000e+00, 1.101207e+01, + 3.825000e+00, 1.056734e+01, + 3.830000e+00, 1.079721e+01, + 3.835000e+00, 7.306342e+00, + 3.840000e+00, 9.927383e+00, + 3.845000e+00, 9.710215e+00, + 3.850000e+00, 9.877712e+00, + 3.855000e+00, 9.170758e+00, + 3.860000e+00, 8.479977e+00, + 3.865000e+00, 9.136104e+00, + 3.870000e+00, 8.273204e+00, + 3.875000e+00, 7.294790e+00, + 3.880000e+00, 7.233567e+00, + 3.885000e+00, 7.671370e+00, + 3.890000e+00, 7.663284e+00, + 3.895000e+00, 8.552751e+00, + 3.900000e+00, 8.527338e+00, + 3.905000e+00, 9.039071e+00, + 3.910000e+00, 8.155379e+00, + 3.915000e+00, 7.950917e+00, + 3.920000e+00, 7.851574e+00, + 3.925000e+00, 7.636715e+00, + 3.930000e+00, 8.031777e+00, + 3.935000e+00, 8.475356e+00, + 3.940000e+00, 8.463805e+00, + 3.945000e+00, 8.571234e+00, + 3.950000e+00, 8.652095e+00, + 3.955000e+00, 8.907383e+00, + 3.960000e+00, 8.891211e+00, + 3.965000e+00, 8.962831e+00, + 3.970000e+00, 8.746817e+00, + 3.975000e+00, 8.585096e+00, + 3.980000e+00, 8.561993e+00, + 3.985000e+00, 8.552751e+00, + 3.990000e+00, 8.494994e+00, + 3.995000e+00, 8.284756e+00, + 4, 8.193499e+00 +}; + +const size_t solstice_sun_spectrum_smarts_size = + sizeof(solstice_sun_spectrum_smarts) / sizeof(double[2]); + + diff --git a/src/solstice_sun_spectrum.h b/src/solstice_sun_spectrum.h @@ -0,0 +1,33 @@ +/* Copyright (C) CNRS 2016-2017 + * + * 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 SOLSTICE_SUN_SPECTRUM_H +#define SOLSTICE_SUN_SPECTRUM_H + +#include <rsys/rsys.h> + +/* + * Each built-in spectrum is a list of double2: [Wavelength in nano-meter, + * DNI]. Its associated size is the number of double[2] into the spectrum + */ + +extern LOCAL_SYM const double solstice_sun_spectrum_dummy[]; +extern LOCAL_SYM const size_t solstice_sun_spectrum_dummy_size; + +extern LOCAL_SYM const double solstice_sun_spectrum_smarts[]; +extern LOCAL_SYM const size_t solstice_sun_spectrum_smarts_size; + +#endif /* SOLSTICE_SUN_SPECTRUM_H */ + diff --git a/src/test_solstice_args.c b/src/test_solstice_args.c @@ -391,26 +391,6 @@ test_threads_count(void) } static void -test_output_hits(void) -{ - struct solstice_args args = SOLSTICE_ARGS_NULL; - char** cmd = NULL; - - cmd = cmd_create(0, "test", "-D", "0,90", NULL); - CHECK(solstice_args_init(&args, cmd_size(cmd), cmd), RES_OK); - CHECK(args.output_hits, SOLSTICE_ARGS_DEFAULT.output_hits); - CHECK(args.output_hits, 0); - solstice_args_release(&args); - cmd_delete(cmd); - - cmd = cmd_create(0, "test", "-D", "0,90", "-H", NULL); - CHECK(solstice_args_init(&args, cmd_size(cmd), cmd), RES_OK); - CHECK(args.output_hits, 1); - solstice_args_release(&args); - cmd_delete(cmd); -} - -static void test_output(void) { struct solstice_args args = SOLSTICE_ARGS_NULL; @@ -460,6 +440,26 @@ test_quiet(void) } static void +test_verbose(void) +{ + struct solstice_args args = SOLSTICE_ARGS_NULL; + char** cmd = NULL; + + cmd = cmd_create(0, "test", "-D", "0,90", NULL); + CHECK(solstice_args_init(&args, cmd_size(cmd), cmd), RES_OK); + CHECK(args.verbose, SOLSTICE_ARGS_DEFAULT.verbose); + CHECK(args.verbose, 0); + solstice_args_release(&args); + cmd_delete(cmd); + + cmd = cmd_create(0, "test", "-D", "0,90", "-v", NULL); + CHECK(solstice_args_init(&args, cmd_size(cmd), cmd), RES_OK); + CHECK(args.verbose, 1); + solstice_args_release(&args); + cmd_delete(cmd); +} + +static void test_receivers(void) { struct solstice_args args = SOLSTICE_ARGS_NULL; @@ -678,9 +678,9 @@ main(int argc, char** argv) test_sun_dirs(); test_realisations_count(); test_threads_count(); - test_output_hits(); test_output(); test_quiet(); + test_verbose(); test_receivers(); test_input(); test_dump(); diff --git a/src/test_solstice_simulation.c b/src/test_solstice_simulation.c @@ -17,6 +17,7 @@ #include <rsys/rsys.h> #include <rsys/math.h> +#include <rsys/double2.h> #include <math.h> #include <stdio.h> @@ -37,20 +38,52 @@ enum side { BACK }; -enum result_type { +enum global_result_type { + GLOBAL_POTENTIAL, + GLOBAL_ABSORBED, + GLOBAL_COS, + GLOBAL_SHADOW, + GLOBAL_MISSING, + GLOBAL_ATMOSPHERE, + GLOBAL_REFLECTIVITY, + GLOBAL_RESULTS_COUNT__ +}; + +enum receiver_result_type { + FIRST_RECEIVER_RESULT, + FRONT_INTEGRATED_ABSORBED_IRRADIANCE = FIRST_RECEIVER_RESULT, FRONT_INTEGRATED_IRRADIANCE, - BACK_INTEGRATED_IRRADIANCE, FRONT_REFLECTIVITY_LOSS, - BACK_REFLECTIVITY_LOSS, FRONT_ABSORPTIVITY_LOSS, - BACK_ABSORPTIVITY_LOSS, - FRONT_COS_LOSS, - BACK_COS_LOSS, FRONT_EFFICIENCY, + BACK_INTEGRATED_ABSORBED_IRRADIANCE, + BACK_INTEGRATED_IRRADIANCE, + BACK_REFLECTIVITY_LOSS, + BACK_ABSORPTIVITY_LOSS, BACK_EFFICIENCY, - MAX_RESULTS_COUNT__ + RECEIVER_RESULTS_COUNT__ +}; + +enum primary_result_type { + FIRST_PRIMARY_RESULT, + PRIMARY_SHADOW = FIRST_PRIMARY_RESULT, + PRIMARY_RESULTS_COUNT__ +}; + +struct counts { + unsigned long global, receiver, primary, realisation, failed; }; +static int +counts_ok(const struct counts* ref, const struct counts* c) +{ + CHECK(ref->global, GLOBAL_RESULTS_COUNT__); + CHECK(c->global, GLOBAL_RESULTS_COUNT__); + return ref->receiver == c->receiver + && ref->primary == c->primary + && ref->failed >= c->failed; +} + #define MAX_LINE_LEN 2048 static const char @@ -62,7 +95,7 @@ sundir_header [] = "#--- Sun direction:"; #ifdef COMPILER_CL /* mkstemp extracted from libc/sysdeps/posix/tempname.c. Copyright * (C) 1991-1999, 2000, 2001, 2006 Free Software Foundation, Inc. - * + * * The GNU C Library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either @@ -170,188 +203,258 @@ read_line(char* line, size_t max_line_len, FILE* stream) return 1; } -static void -get_dir_and_counts - (FILE* ref_file, +static int +get_angles_and_counts + (FILE* file, double angles[2], - unsigned long* recv_count, - unsigned long* realisation_count) + struct counts* counts) { char line[MAX_LINE_LEN]; - int n; + int r; - NCHECK(ref_file, NULL); + NCHECK(file, NULL); NCHECK(angles, NULL); - NCHECK(recv_count, NULL); - NCHECK(realisation_count, NULL); + NCHECK(counts, NULL); /* Get sun dir */ - CHECK(read_line(line, sizeof(line), ref_file), 1); + r = read_line(line, sizeof(line), file); + if (!r) { + CHECK(feof(file), 1); + return 0; + } CHECK(IS_NEW_BLOCK(line, sundir_header), 1); - n = sscanf(line+strlen(sundir_header), "%lg%lg", &angles[0], &angles[1]); - CHECK(n, 2); + CHECK( + sscanf(line+strlen(sundir_header), "%lg%lg", &angles[0], &angles[1]), + 2); + + /* Get counts */ + CHECK(read_line(line, sizeof(line), file), 1); + CHECK( + sscanf(line, + "%lu %lu %lu %lu %lu", + &counts->global, &counts->receiver, &counts->primary, + &counts->realisation, &counts->failed), + 5); + return 1; +} - /* Get #receivers and #realisations */ - CHECK(read_line(line, sizeof(line), ref_file), 1); - n = sscanf(line, "%lu%lu", recv_count, realisation_count); - CHECK(n, 2); +static void +read_global(FILE* file, double* E, double* SE) +{ + char line[MAX_LINE_LEN]; + CHECK(read_line(line, sizeof(line), file), 1); + CHECK( + sscanf(line, "%lg %lg", E, SE), + 2); } static void -read_recv(const char* line, char name[], double E[], double SE[]) +read_recv(FILE* file, char name[], double E[], double SE[]) { - int n; + char line[MAX_LINE_LEN]; - NCHECK(line, NULL); + NCHECK(file, NULL); NCHECK(name, NULL); NCHECK(E, NULL); NCHECK(SE, NULL); - n = sscanf(line, - "%s%*u%lg%lg%lg%lg%lg%lg%lg%lg%lg%lg%lg%lg%lg%lg%lg%lg%lg%lg%lg%lg", - name, - &E[FRONT_INTEGRATED_IRRADIANCE], &SE[FRONT_INTEGRATED_IRRADIANCE], - &E[BACK_INTEGRATED_IRRADIANCE], &SE[BACK_INTEGRATED_IRRADIANCE], - &E[FRONT_REFLECTIVITY_LOSS], &SE[FRONT_REFLECTIVITY_LOSS], - &E[BACK_REFLECTIVITY_LOSS], &SE[BACK_REFLECTIVITY_LOSS], - &E[FRONT_ABSORPTIVITY_LOSS], &SE[FRONT_ABSORPTIVITY_LOSS], - &E[BACK_ABSORPTIVITY_LOSS], &SE[BACK_ABSORPTIVITY_LOSS], - &E[FRONT_COS_LOSS], &SE[FRONT_COS_LOSS], - &E[BACK_COS_LOSS], &SE[BACK_COS_LOSS], - &E[FRONT_EFFICIENCY], &SE[FRONT_EFFICIENCY], - &E[BACK_EFFICIENCY], &SE[BACK_EFFICIENCY]); - - CHECK(n, 2*MAX_RESULTS_COUNT__+1); + CHECK(read_line(line, sizeof(line), file), 1); + CHECK( + sscanf(line, + "%s %*u %*g " + "%lg %lg %lg %lg %lg %lg %lg %lg %lg %lg " + "%lg %lg %lg %lg %lg %lg %lg %lg %lg %lg", + name, /* ID, area */ + &E[FRONT_INTEGRATED_ABSORBED_IRRADIANCE], + &SE[FRONT_INTEGRATED_ABSORBED_IRRADIANCE], + &E[FRONT_INTEGRATED_IRRADIANCE], &SE[FRONT_INTEGRATED_IRRADIANCE], + &E[FRONT_REFLECTIVITY_LOSS], &SE[FRONT_REFLECTIVITY_LOSS], + &E[FRONT_ABSORPTIVITY_LOSS], &SE[FRONT_ABSORPTIVITY_LOSS], + &E[FRONT_EFFICIENCY], &SE[FRONT_EFFICIENCY], + &E[BACK_INTEGRATED_ABSORBED_IRRADIANCE], + &SE[BACK_INTEGRATED_ABSORBED_IRRADIANCE], + &E[BACK_INTEGRATED_IRRADIANCE], &SE[BACK_INTEGRATED_IRRADIANCE], + &E[BACK_REFLECTIVITY_LOSS], &SE[BACK_REFLECTIVITY_LOSS], + &E[BACK_ABSORPTIVITY_LOSS], &SE[BACK_ABSORPTIVITY_LOSS], + &E[BACK_EFFICIENCY], &SE[BACK_EFFICIENCY]), + 2 * RECEIVER_RESULTS_COUNT__ + 1); } -#define POSITIVE_OR_M_ONE(x) ((x) == -1 || (x) >= 0) - -static FINLINE int -is_compatible_with - (const double ref_E, - const double ref_SE, - const double test_E, - const double test_SE) +static void +read_primary + (FILE* file, char name[], double* area, double* cos, double E[], double SE[]) { - double SE; - - CHECK(POSITIVE_OR_M_ONE(ref_E), 1); - CHECK(POSITIVE_OR_M_ONE(ref_SE), 1); - CHECK(POSITIVE_OR_M_ONE(test_E), 1); - CHECK(POSITIVE_OR_M_ONE(test_SE), 1); + char line[MAX_LINE_LEN]; - if(ref_E == -1) { - CHECK(ref_SE, -1); - return (test_E == -1 && test_SE == -1); - } + NCHECK(file, NULL); + NCHECK(area, NULL); + NCHECK(cos, NULL); + NCHECK(E, NULL); + NCHECK(SE, NULL); - NCHECK(ref_SE, -1); - SE = ref_SE > 0 ? 2 * ref_SE : (ref_E > 0 ? ref_E * 1e-6 : 1e-6); - return (fabs(ref_E - test_E) <= SE && test_SE <= SE); + CHECK(read_line(line, sizeof(line), file), 1); + CHECK( + sscanf(line, + "%s %*u " + "%lg %*u %lg " + "%lg %lg\n", + name, /* ID */ + area, /* count, */ cos, + &E[PRIMARY_SHADOW], &SE[PRIMARY_SHADOW]), + 2 * PRIMARY_RESULTS_COUNT__ + 3); } static void -check_1_reference - (FILE* tested_file, - const char* rcv_name, - const double* reference_E, - const double* reference_SE) +read_recvXprim + (FILE* file, + unsigned long* rcv_id, + unsigned long* prim_id, + double E[], + double SE[]) { - double a[2]; - unsigned long c1, c2; - int found = 0; - - NCHECK(tested_file, NULL); - NCHECK(rcv_name, NULL); - NCHECK(reference_E, NULL); - NCHECK(reference_SE, NULL); - - get_dir_and_counts(tested_file, a, &c1, &c2); /* Skip headers */ - - while(!feof(tested_file) && !found) { - char line[MAX_LINE_LEN]; - char tested_rcv_name[MAX_LINE_LEN]; - double tested_E[MAX_RESULTS_COUNT__], tested_SE[MAX_RESULTS_COUNT__]; - enum result_type r; - - CHECK(read_line(line, sizeof(line), tested_file), 1); + char line[MAX_LINE_LEN]; - read_recv(line, tested_rcv_name, tested_E, tested_SE); - if(strcmp(rcv_name, tested_rcv_name)) continue; + NCHECK(file, NULL); + NCHECK(rcv_id, NULL); + NCHECK(prim_id, NULL); + NCHECK(E, NULL); + NCHECK(SE, NULL); - FOR_EACH(r, FRONT_INTEGRATED_IRRADIANCE, MAX_RESULTS_COUNT__) { - CHECK(is_compatible_with - (reference_E[r], reference_SE[r], tested_E[r], tested_SE[r]), 1); - } - found = 1; - } - CHECK(found, 1); + CHECK(read_line(line, sizeof(line), file), 1); + CHECK( + sscanf(line, + "%lu %lu " + "%lg %lg %lg %lg %lg %lg %lg %lg " + "%lg %lg %lg %lg %lg %lg %lg %lg", + rcv_id, prim_id, + &E[FRONT_INTEGRATED_ABSORBED_IRRADIANCE], + &SE[FRONT_INTEGRATED_ABSORBED_IRRADIANCE], + &E[FRONT_INTEGRATED_IRRADIANCE], &SE[FRONT_INTEGRATED_IRRADIANCE], + &E[FRONT_REFLECTIVITY_LOSS], &SE[FRONT_REFLECTIVITY_LOSS], + &E[FRONT_ABSORPTIVITY_LOSS], &SE[FRONT_ABSORPTIVITY_LOSS], + &E[BACK_INTEGRATED_ABSORBED_IRRADIANCE], + &SE[BACK_INTEGRATED_ABSORBED_IRRADIANCE], + &E[BACK_INTEGRATED_IRRADIANCE], &SE[BACK_INTEGRATED_IRRADIANCE], + &E[BACK_REFLECTIVITY_LOSS], &SE[BACK_REFLECTIVITY_LOSS], + &E[BACK_ABSORPTIVITY_LOSS], &SE[BACK_ABSORPTIVITY_LOSS]), + 2 * (RECEIVER_RESULTS_COUNT__ - 2 /* efficiencies not read */) + 2); } static void -check_1_global - (FILE* tested_file, - const double reference_E, - const double reference_SE, - const unsigned rank) +compute_estimate_intersection + (double intersection[2], + const double scale, + const double E0, + const double SE0, + const double E1, + const double SE1) { - char line[MAX_LINE_LEN]; - double a[2]; - unsigned long recv_count, r2; - unsigned i; - int nb; - double tested_E, tested_SE; - - get_dir_and_counts(tested_file, a, &recv_count, &r2); - - /* Skip receivers */ - while(recv_count--) CHECK(read_line(line, sizeof(line), tested_file), 1); - - /* Read the rank th global data */ - FOR_EACH(i, 0, rank+1) CHECK(read_line(line, sizeof(line), tested_file), 1); + double interval0[2], interval1[2]; + CHECK(scale > 0, 1); + interval0[0] = E0 - scale*SE0; + interval0[1] = E0 + scale*SE0; + interval1[0] = E1 - scale*SE1; + interval1[1] = E1 + scale*SE1; + intersection[0] = MMAX(interval0[0], interval1[0]); + intersection[1] = MMIN(interval0[1], interval1[1]); +} - nb = sscanf(line, "%lg%lg", &tested_E, &tested_SE); - CHECK(nb, 2); - CHECK(is_compatible_with(reference_E, reference_SE, tested_E, tested_SE), 1); +static void +check_estimate + (double ref_E, + double ref_SE, + double test_E, + double test_SE) +{ + if(ref_E == -1) { + CHECK(ref_SE, -1); + CHECK(test_E, -1); + CHECK(test_SE, -1); + } else { + double interval[2]; + CHECK(ref_SE >= 0, 1); + CHECK(test_E >= 0, 1); + CHECK(test_SE >= 0, 1); + if(!ref_SE) ref_SE = ref_E / 1000.0; + if(!test_SE) test_SE = test_E / 1000.0; + compute_estimate_intersection(interval, 2, ref_E, ref_SE, test_E, test_SE); + CHECK(interval[0] <= interval[1], 1); + } } static void -check_references(FILE* ref_file, FILE* tested_file) +check_1_reference + (FILE* ref_file, + FILE* test_file, + const struct counts* counts) { - char line[MAX_LINE_LEN]; - unsigned nb_global = 0; - fpos_t pos; + unsigned n; NCHECK(ref_file, NULL); - NCHECK(tested_file, NULL); + NCHECK(test_file, NULL); + NCHECK(counts, NULL); - CHECK(fgetpos(ref_file, &pos), 0); - while(read_line(line, sizeof(line), ref_file)) { - double val, std; - int nb = 0; + /* both files' pointer are just past the new bloc header */ - if(IS_NEW_BLOCK(line, sundir_header)) { - /* Keep the header as a part of the following block */ - CHECK(fsetpos(ref_file, &pos), 0); - break; + for (n = 0; n < counts->global; n++) { + double reference_E, reference_SE, test_E, test_SE; + read_global(ref_file, &reference_E, &reference_SE); + read_global(test_file, &test_E, &test_SE); + check_estimate(reference_E, reference_SE, test_E, test_SE); + } + for (n = 0; n < counts->receiver; n++) { + char ref_rcv_name[MAX_LINE_LEN], test_rcv_name[MAX_LINE_LEN]; + double reference_E[RECEIVER_RESULTS_COUNT__]; + double reference_SE[RECEIVER_RESULTS_COUNT__]; + double test_E[RECEIVER_RESULTS_COUNT__]; + double test_SE[RECEIVER_RESULTS_COUNT__]; + enum receiver_result_type r; + + read_recv(ref_file, ref_rcv_name, reference_E, reference_SE); + read_recv(test_file, test_rcv_name, test_E, test_SE); + CHECK(strcmp(ref_rcv_name, test_rcv_name), 0); + FOR_EACH(r, FIRST_RECEIVER_RESULT, RECEIVER_RESULTS_COUNT__) { + check_estimate(reference_E[r], reference_SE[r], test_E[r], test_SE[r]); } - - nb = sscanf(line, "%lg%lg", &val, &std); - CHECK(nb == 0 || nb == 2, 1); - - rewind(tested_file); - if(nb != 0) { - check_1_global(tested_file, val, std, nb_global); - nb_global++; - } else { - char ref_name[MAX_LINE_LEN]; - double reference_E[MAX_RESULTS_COUNT__]; - double reference_SE[MAX_RESULTS_COUNT__]; - read_recv(line, ref_name, reference_E, reference_SE); - check_1_reference(tested_file, ref_name, reference_E, reference_SE); + } + for (n = 0; n < counts->primary; n++) { + char ref_prim_name[MAX_LINE_LEN], test_prim_name[MAX_LINE_LEN]; + double reference_E[PRIMARY_RESULTS_COUNT__]; + double reference_SE[PRIMARY_RESULTS_COUNT__]; + double test_E[PRIMARY_RESULTS_COUNT__]; + double test_SE[PRIMARY_RESULTS_COUNT__]; + double ref_area, ref_cos; + double test_area, test_cos; + enum primary_result_type r; + + read_primary(ref_file, ref_prim_name, &ref_area, &ref_cos, reference_E, reference_SE); + read_primary(test_file, test_prim_name, &test_area, &test_cos, test_E, test_SE); + check_estimate(ref_area, 0, test_area, 0); + check_estimate(ref_cos, 0, test_cos, 0); + CHECK(strcmp(ref_prim_name, test_prim_name), 0); + FOR_EACH(r, FIRST_RECEIVER_RESULT, PRIMARY_RESULTS_COUNT__) { + check_estimate(reference_E[r], reference_SE[r], test_E[r], test_SE[r]); + } + } + for (n = 0; n < counts->receiver * counts->primary; n++) { + double reference_E[RECEIVER_RESULTS_COUNT__]; + double reference_SE[RECEIVER_RESULTS_COUNT__]; + double test_E[RECEIVER_RESULTS_COUNT__]; + double test_SE[RECEIVER_RESULTS_COUNT__]; + unsigned long ref_rcv_id, ref_prim_id; + unsigned long test_rcv_id, test_prim_id; + + enum receiver_result_type r; + read_recvXprim(ref_file, &ref_rcv_id, &ref_prim_id, reference_E, reference_SE); + read_recvXprim(test_file, &test_rcv_id, &test_prim_id, test_E, test_SE); + /* we rely on the order of outputs */ + CHECK(ref_rcv_id, test_rcv_id); + CHECK(ref_prim_id, test_prim_id); + FOR_EACH(r, FIRST_RECEIVER_RESULT, RECEIVER_RESULTS_COUNT__) { + if (r == FRONT_EFFICIENCY || r == BACK_EFFICIENCY) + continue; /* not read */ + check_estimate(reference_E[r], reference_SE[r], test_E[r], test_SE[r]); } - - CHECK(fgetpos(ref_file, &pos), 0); } } @@ -373,7 +476,7 @@ do_check(const char* binary, const char* dir, const char* base_name) { char ref_file_name[128]; FILE* ref_file; - unsigned long c1, realisation_count; + struct counts ref_counts, test_counts; int n; int err; ASSERT(base_name); @@ -386,30 +489,34 @@ do_check(const char* binary, const char* dir, const char* base_name) while(!feof(ref_file)) { char cmd[512]; - char tested_file_name[128]; - double sun_angles[2]; - FILE* fp = NULL; + char test_file_name[128]; + double ref_sun_angles[2], test_sun_angles[2]; + FILE* test_file = NULL; int fd = -1; - get_dir_and_counts(ref_file, sun_angles, &c1, &realisation_count); + if (!get_angles_and_counts(ref_file, ref_sun_angles, &ref_counts)) + break; /* EOF */ - fd = create_tmp_file(tested_file_name, sizeof(tested_file_name)); - fp = fdopen(fd, "r"); - NCHECK(fp, NULL); + fd = create_tmp_file(test_file_name, sizeof(test_file_name)); + test_file = fdopen(fd, "r"); + NCHECK(test_file, NULL); n = snprintf(cmd, sizeof(cmd), "%s -o %s -f -D %g,%g -n %lu -R %s%s_receiver.yaml %s%s.yaml", - binary, tested_file_name, SPLIT2(sun_angles), realisation_count, + binary, test_file_name, SPLIT2(ref_sun_angles), ref_counts.realisation, dir, base_name, dir, base_name); CHECK((unsigned)n < sizeof(cmd), 1); err = system(cmd); CHECK(err, 0); - check_references(ref_file, fp); + get_angles_and_counts(test_file, test_sun_angles, &test_counts); + CHECK(d2_eq(ref_sun_angles, test_sun_angles), 1); + CHECK(counts_ok(&ref_counts, &test_counts), 1); + check_1_reference(ref_file, test_file, &ref_counts); - fclose(fp); - remove(tested_file_name); + fclose(test_file); + remove(test_file_name); } } diff --git a/yaml/beam_down.ref b/yaml/beam_down.ref @@ -1,12 +1,52 @@ #--- Sun direction: 90 90 (-3.7494e-33 -6.12323e-17 -1) -2 10000 -tower.secondary.hyperbol 10 465.484 0.0183212 0 0 0 0 0 0 0 0 0 0 34.5362 0.00509812 0 0 0.930888 3.66392e-05 0 0 -tower.receptor 14 465.484 0.0183212 -1 -1 0 0 -1 -1 0 0 -1 -1 34.5362 0.00509812 -1 -1 0.930888 3.66392e-05 -1 -1 +7 2 5 100000 0 +500.043 0 +465.46 0.0057839 +0.930834 1.15684e-05 0 0 0 0 +0 0 +0 0 +tower.secondary.hyperbol 10 421.957 0 0 465.46 0.0057839 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +tower.receptor 14 25 465.46 0.0057839 465.46 0.0057839 0 0 0 0 0.93084 1.15668e-05 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 +heliostat4.temp-heliostat150.pivot.reflector 6 100.009 19915 0 0 0 0 +heliostat5.temp-heliostat150.pivot.reflector 30 100.009 20068 0 0 0 0 +heliostat3.temp-heliostat150.pivot.reflector 22 100.009 19919 0 0 0 0 +heliostat2.temp-heliostat150.pivot.reflector 26 100.009 20054 0 0 0 0 +heliostat1.temp-heliostat150.pivot.reflector 34 100.009 20044 0 0 0 0 +10 6 0 0 92.7742 0.588324 0 0 0 0 0 0 0 0 0 0 0 0 +10 30 0 0 93.2842 0.588736 0 0 0 0 0 0 0 0 0 0 0 0 +10 22 0 0 92.8029 0.588432 0 0 0 0 0 0 0 0 0 0 0 0 +10 26 0 0 93.4242 0.589876 0 0 0 0 0 0 0 0 0 0 0 0 +10 34 0 0 93.1748 0.588486 0 0 0 0 0 0 0 0 0 0 0 0 +14 6 92.7742 0.588324 92.7742 0.588324 0 0 0 0 -1 -1 -1 -1 -1 -1 -1 -1 +14 30 93.2842 0.588736 93.2842 0.588736 0 0 0 0 -1 -1 -1 -1 -1 -1 -1 -1 +14 22 92.8029 0.588432 92.8029 0.588432 0 0 0 0 -1 -1 -1 -1 -1 -1 -1 -1 +14 26 93.4242 0.589876 93.4242 0.589876 0 0 0 0 -1 -1 -1 -1 -1 -1 -1 -1 +14 34 93.1748 0.588486 93.1748 0.588486 0 0 0 0 -1 -1 -1 -1 -1 -1 -1 -1 #--- Sun direction: 50 50 (-0.413176 -0.492404 -0.766044) -2 10000 -tower.secondary.hyperbol 10 400.227 0.111144 0 0 0 0 0 0 0 0 0 0 99.7686 0.107226 0 0 0.800384 0.000222269 0 0 -tower.receptor 14 136.561 1.90791 -1 -1 0 0 -1 -1 0 0 -1 -1 32.9896 0.464742 -1 -1 0.273098 0.0038155 -1 -1 +7 2 5 100000 0 +500.043 0 +135.852 0.602426 +0.800261 7.05527e-05 +0 0 +245.21 0.615008 0 0 0 0 +tower.secondary.hyperbol 10 421.957 0 0 400.167 0.0352796 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +tower.receptor 14 25 135.852 0.602426 135.852 0.602426 0 0 0 0 0.271681 0.00120475 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 +heliostat4.temp-heliostat150.pivot.reflector 6 100.009 20095 0 0 0 0 +heliostat5.temp-heliostat150.pivot.reflector 30 100.009 20027 0 0 0 0 +heliostat3.temp-heliostat150.pivot.reflector 22 100.009 19777 0 0 0 0 +heliostat2.temp-heliostat150.pivot.reflector 26 100.009 19976 0 0 0 0 +heliostat1.temp-heliostat150.pivot.reflector 34 100.009 20125 0 0 0 0 +10 6 0 0 78.903 0.497568 0 0 0 0 0 0 0 0 0 0 0 0 +10 30 0 0 77.0867 0.487147 0 0 0 0 0 0 0 0 0 0 0 0 +10 22 0 0 79.1052 0.503835 0 0 0 0 0 0 0 0 0 0 0 0 +10 26 0 0 81.4942 0.515816 0 0 0 0 0 0 0 0 0 0 0 0 +10 34 0 0 83.5784 0.526554 0 0 0 0 0 0 0 0 0 0 0 0 +14 6 22.1799 0.286704 22.1799 0.286704 0 0 0 0 -1 -1 -1 -1 -1 -1 -1 -1 +14 30 18.6614 0.26147 18.6614 0.26147 0 0 0 0 -1 -1 -1 -1 -1 -1 -1 -1 +14 22 25.3271 0.308097 25.3271 0.308097 0 0 0 0 -1 -1 -1 -1 -1 -1 -1 -1 +14 26 31.6777 0.345324 31.6777 0.345324 0 0 0 0 -1 -1 -1 -1 -1 -1 -1 -1 +14 34 38.0063 0.378737 38.0063 0.378737 0 0 0 0 -1 -1 -1 -1 -1 -1 -1 -1 diff --git a/yaml/beam_down.yaml b/yaml/beam_down.yaml @@ -7,7 +7,7 @@ # 0 0 # --- Sun direction: -3.7494e-33 -6.12323e-17 -1 -- sun: &sun { dni: 1, spectrum: [{wavelength: 1, data: 1}] } +- sun: &sun { dni: 1 } - material: &mirror { mirror: { reflectivity: 1, roughness: 0 } } - material: &black { matte: { reflectivity: 0 } } diff --git a/yaml/test01.ref b/yaml/test01.ref @@ -1,5 +1,12 @@ #--- Sun direction: 0 90 (-6.12323e-17 -0 -1) -1 10000 -square_receiver 2 -1 -1 1 0 -1 -1 0 0 -1 -1 0 0 -1 -1 0 0 -1 -1 1 0 +7 1 1 10000 0 +1 0 0 0 +1 0 0 0 +1 0 +0 0 +0 0 +square_receiver 2 100 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 0 0 1 0 0 0 0 0 0 0 +reflector 6 1 10000 0 0 0 0 +2 6 -1 -1 -1 -1 -1 -1 -1 -1 0 0 1 0 0 0 0 0 diff --git a/yaml/test01.yaml b/yaml/test01.yaml @@ -1,6 +1,4 @@ -- sun: &sun - dni: 1 - spectrum: [{wavelength: 1, data: 1}] +- sun: &sun { dni: 1 } - material: &specular front: diff --git a/yaml/test02.ref b/yaml/test02.ref @@ -1,5 +1,12 @@ #--- Sun direction: 0 90 (-6.12323e-17 -0 -1) -1 100000 -square_receiver 2 -1 -1 1 0.0313065 -1 -1 0 0 -1 -1 0 0 -1 -1 0 0 -1 -1 0.01003 0.000315109 +7 1 1 10000 0 +100 0 +0.96 0.0975082 +1 0 0 0 -99 0.0313065 +99.04 0.0975082 +0 0 +0 0 +square_receiver 2 1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 0.96 0.0975082 0.96 0.0975082 0 0 0 0 0.0096 0.000975082 +reflector 6 100 10000 0 0 0 0 +2 6 -1 -1 -1 -1 -1 -1 -1 -1 0.96 0.0975082 0.96 0.0975082 0 0 0 0 diff --git a/yaml/test02.yaml b/yaml/test02.yaml @@ -1,13 +1,13 @@ -- sun: &sun - dni: 1 - spectrum: [{wavelength: 1, data: 1}] +- sun: &sun { dni: 1 } - material: &specular mirror: { reflectivity: 1, roughness: 0 } - geometry: &small_square - - material: { virtual: } + - material: + front: { virtual: } + back: { matte: { reflectivity: 0 } } plane: clip: - operation: AND diff --git a/yaml/test03.ref b/yaml/test03.ref @@ -1,5 +1,12 @@ #--- Sun direction: 0 45 (-0.707107 -0 -0.707107) -1 10000 -square_receiver 2 -1 -1 0.707107 0 -1 -1 0 0 -1 -1 0 0 -1 -1 0.292893 0 -1 -1 0.707107 0 +7 1 1 10000 0 +1 0 0 0 +0.707107 0 0 0 +0.707107 0 +0 0 +0 0 +square_receiver 2 100 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 0 0 0.707107 0 0 0 0 0 0 0 +reflector 6 1 10000 0 0 0 0 +2 6 -1 -1 -1 -1 -1 -1 -1 -1 0 0 0.707107 0 0 0 0 0 diff --git a/yaml/test03.yaml b/yaml/test03.yaml @@ -1,6 +1,4 @@ -- sun: &sun - dni: 1 - spectrum: [{wavelength: 1, data: 1}] +- sun: &sun { dni: 1 } - material: &specular front: diff --git a/yaml/test04.ref b/yaml/test04.ref @@ -1,4 +1,12 @@ #--- Sun direction: 0 45 (-0.707107 -0 -0.707107) -1 10000 -square_receiver 2 0 0 0.707107 0 0 0 0 0 0 0 0 0 0 0 0.292893 0 0 0 0.707107 0 +7 1 1 10000 0 +1 0 0 0 +0.707107 0 +0 0 +0.707107 0 +0 0 +0 0 +square_receiver 2 100 0 0 0 0 0 0 0 0 0 0 0 0 0.707107 0 0 0 0 0 0 0 +reflector 6 1 10000 0 0 0 0 +2 6 0 0 0 0 0 0 0 0 0 0 0.707107 0 0 0 0 0 diff --git a/yaml/test04.yaml b/yaml/test04.yaml @@ -1,6 +1,4 @@ -- sun: &sun - dni: 1 - spectrum: [{wavelength: 1, data: 1}] +- sun: &sun { dni: 1 } - material: &specular front: diff --git a/yaml/test05.ref b/yaml/test05.ref @@ -1,5 +1,12 @@ #--- Sun direction: 0 90 (-6.12323e-17 -0 -1) -1 10000 -spherical_receiver 2 -1 -1 1 0 -1 -1 0 0 -1 -1 0 0 -1 -1 0 0 -1 -1 1 0 +7 1 1 10000 0 +1 0 0 0 +1 0 0 0 +1 0 +0 0 +0 0 +spherical_receiver 2 50.2403 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 0 0 1 0 0 0 0 0 0 0 +reflector 6 1 10000 0 0 0 0 +2 6 -1 -1 -1 -1 -1 -1 -1 -1 0 0 1 0 0 0 0 0 diff --git a/yaml/test05.yaml b/yaml/test05.yaml @@ -1,6 +1,4 @@ -- sun: &sun - dni: 1 - spectrum: [{wavelength: 1, data: 1}] +- sun: &sun { dni: 1 } - material: &lambertian front: diff --git a/yaml/test06.ref b/yaml/test06.ref @@ -0,0 +1,12 @@ +#--- Sun direction: 0 63 (-0.45399 -0 -0.891007) +7 1 1 10000 0 +111.97 0 +0 0 +0.896295 0.000571234 +0 0 +100 0 +0 0 +0 0 +reflector.ground.pivot.small_square 10 1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 0 0 100 0 0 0 0 0 0 0 +reflector.ground.pivot.parabol 6 111.97 10000 0 0 0 0 +10 6 -1 -1 -1 -1 -1 -1 -1 -1 0 0 100 0 0 0 0 0 diff --git a/yaml/test06.yaml b/yaml/test06.yaml @@ -0,0 +1,60 @@ +- sun: &sun { dni: 1 } + +- material: &lambertian + front: + matte: { reflectivity: 1 } + back: + matte: { reflectivity: 1 } + +- material: &specular + mirror: { reflectivity: 1, roughness: 0 } + + +- template: &self_oriented_parabol + name: "ground" + primary: 0 + geometry: + - material: *lambertian + plane: + clip: + - operation: AND + vertices: + - [-20.0, -20.0] + - [-20.0, 20.0] + - [ 20.0, 20.0] + - [ 20.0, -20.0] + children: + - name: "pivot" + transform: { translation: [0, 0, 4], rotation: [0, 0, 90] } + x_pivot: + target: { sun: *sun } + children: + - name: "parabol" + primary: 1 + geometry: + - material: *specular + parabol: + focal: 4 + clip: + - operation: AND + vertices: [[-5.0, -5.0], [-5.0, 5.0], [5.0, 5.0], [5.0, -5.0]] + - name: "small_square" + transform: { translation: [0, 0, 4] } + primary: 0 + geometry: + - material: { virtual: } + plane: + clip: + - operation: AND + vertices: + - [-0.50, -0.50] + - [-0.50, 0.50] + - [0.50, 0.50] + - [0.50, -0.50] + + +- entity: + name: "reflector" + transform: { rotation: [0, 0, 0], translation: [0, 0, 0] } + children: [ *self_oriented_parabol ] + diff --git a/yaml/test06_receiver.yaml b/yaml/test06_receiver.yaml @@ -0,0 +1 @@ +- { name: "reflector.ground.pivot.small_square", side: BACK } diff --git a/yaml/test07.ref b/yaml/test07.ref @@ -0,0 +1,12 @@ +#--- Sun direction: 0 90 (-6.12323e-17 -0 -1) +7 1 1 10000 0 +56.3503 0 +0 0 +0.666607 0.00232391 +0 0 +28.093 0 +0 0 +0 0 +square_receiver 2 100 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 0 0 28.093 0 0 0 0 0 0 0 +reflector 6 56.3503 10000 0 0 0 0 +2 6 -1 -1 -1 -1 -1 -1 -1 -1 0 0 28.093 0 0 0 0 0 diff --git a/yaml/test07.yaml b/yaml/test07.yaml @@ -0,0 +1,39 @@ +- sun: &sun { dni: 1 } + +- atmosphere: + absorption: [{wavelength: 1, data: 0},{wavelength: 10, data: 0}] + +- material: &specular + front: + mirror: { reflectivity: 1, roughness: 0 } + back: + mirror: { reflectivity: 1, roughness: 0 } + +- geometry: &hemisphere + - material: *specular + hemisphere: + radius: 3 + slices: 32 + +- geometry: &big_square + - material: { virtual: } + plane: + clip: + - operation: AND + vertices: + - [-5.00, -5.00] + - [-5.00, 5.00] + - [5.00, 5.00] + - [5.00, -5.00] + +- entity: + name: "reflector" + primary: 1 + transform: { rotation: [0, 0, 0], translation: [0, 0, 0] } + geometry: *hemisphere + +- entity: + name: "square_receiver" + primary: 0 + transform: { rotation: [0, 0, 0], translation: [0, 0, 4] } + geometry: *big_square diff --git a/yaml/test07_receiver.yaml b/yaml/test07_receiver.yaml @@ -0,0 +1 @@ +- { name: "square_receiver", side: BACK } diff --git a/yaml/test08.ref b/yaml/test08.ref @@ -0,0 +1,12 @@ +#--- Sun direction: 0 63 (-0.45399 -0 -0.891007) +7 1 1 10000 0 +85.5109 0 +0 0 +0.917875 0.000431307 +0 0 +78.4137 2.52319e-08 +0 0 +0 0 +reflector.pivot.small_square 6 1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 0 0 78.4137 2.52319e-08 0 0 0 0 0 0 +reflector.pivot.parabol 2 85.5109 10000 0 0 0 0 +6 2 -1 -1 -1 -1 -1 -1 -1 -1 0 0 78.4137 2.52319e-08 0 0 0 0 diff --git a/yaml/test08.yaml b/yaml/test08.yaml @@ -0,0 +1,43 @@ +- sun: &sun { dni: 1 } + +- atmosphere: + absorption: 0 + +- material: &lambertian + front: + matte: { reflectivity: 1 } + back: + matte: { reflectivity: 1 } + +- material: &specular + mirror: { reflectivity: 1, roughness: 0 } + +- template: &self_oriented_parabol + name: "pivot" + transform: { translation: [0, 0, 4], rotation: [0, 0, 90] } + x_pivot: + target: { sun: *sun } + children: + - name: "parabol" + primary: 1 + geometry: + - material: *specular + parabol: + focal: 4 + clip: + - operation: AND + circle: { radius: 5 } + - name: "small_square" + transform: { translation: [0, 0, 4] } + primary: 0 + geometry: + - material: { virtual: } + plane: + clip: + - operation: AND + vertices: [ [-0.50, -0.50], [-0.50, 0.50], [0.50, 0.50], [0.50, -0.50] ] + +- entity: + name: "reflector" + transform: { rotation: [0, 0, 0], translation: [0, 0, 0] } + children: [ *self_oriented_parabol ] diff --git a/yaml/test08_receiver.yaml b/yaml/test08_receiver.yaml @@ -0,0 +1 @@ +- { name: "reflector.pivot.small_square", side: BACK }