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:
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: ¶bol
- - 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 © 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(¶bol->polyclips), 1);
polyclip = darray_polyclip_cdata_get(¶bol->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(¶m->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(¶m->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(¶m->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(¶m->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(¶m->reflectivity);
+ ssol_data_clear(¶m->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, ¶m->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, ¶m->reflectivity);
+ if(res != RES_OK) goto error;
+ res = mtl_to_ssol_data(solstice, &mirror->roughness, ¶m->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, ¶boloid->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 }