commit f2e468c6a3ca77c77de26bfeaca4ce8fa874eae3
parent c68eddff02ebac31c673556d3553aa95998667f4
Author: Christophe Coustet <christophe.coustet@meso-star.com>
Date: Sun, 29 Mar 2020 15:13:15 +0200
Add doc; fake at this time
Diffstat:
9 files changed, 2330 insertions(+), 33 deletions(-)
diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt
@@ -1,4 +1,4 @@
-# Copyright (C) 2016-2018 |Meso|Star>
+# Copyright (C) 2018-2020 |Meso|Star>
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
@@ -18,24 +18,63 @@ project(stardis-app C)
set(SDIS_SOURCE_DIR ${PROJECT_SOURCE_DIR}/../src)
+if(CMAKE_HOST_UNIX)
+ set(STARDIS_DOC "TROFF & HTML" CACHE STRING
+ "Type of documentation to generate and install.")
+else()
+ set(STARDIS_DOC "HTML" CACHE STRING
+ "Type of documentation to generate and install.")
+endif()
+
+set_property(CACHE STARDIS_DOC PROPERTY STRINGS
+ "HTML"
+ "TROFF"
+ "TROFF & HTML"
+ "NONE")
+
+###############################################################################
+# Generate files
+###############################################################################set(SOLSTICE_ARGS_DEFAULT_NREALISATIONS "10000")
+set(SOLSTICE_ARGS_DEFAULT_CAMERA_POS "0,0,0")
+set(SOLSTICE_ARGS_DEFAULT_CAMERA_TGT "0,0,-1")
+set(SOLSTICE_ARGS_DEFAULT_CAMERA_UP "0,1,0")
+set(SOLSTICE_ARGS_DEFAULT_CAMERA_FOV "70") # In degrees
+set(SOLSTICE_ARGS_DEFAULT_IMG_WIDTH "800")
+set(SOLSTICE_ARGS_DEFAULT_IMG_HEIGHT "600")
+set(SOLSTICE_ARGS_DEFAULT_IMG_SPP "1")
+
+configure_file(${SDIS_SOURCE_DIR}/../doc/stardis.1.txt.in
+ ${CMAKE_CURRENT_BINARY_DIR}/doc/stardis.1.txt @ONLY)
+
+set(VERSION_MAJOR 0)
+set(VERSION_MINOR 4)
+set(VERSION_PATCH 0)
+set(VERSION ${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_PATCH})
+
+configure_file(${SDIS_SOURCE_DIR}/stardis-version.h.in
+ ${CMAKE_CURRENT_BINARY_DIR}/stardis-version.h @ONLY)
+
###############################################################################
# Check dependencies
###############################################################################
find_package(RCMake 0.4 REQUIRED)
find_package(RSys 0.9 REQUIRED)
find_package(StarGeom3D 0.1 REQUIRED)
-find_package(StarEnc3D 0.3.1 REQUIRED)
-find_package(Stardis 0.7.1 REQUIRED)
+find_package(StarEnc3D 0.4.2 REQUIRED)
+find_package(Stardis 0.8.2 REQUIRED)
find_package(StarSTL 0.3 REQUIRED)
+if(MSVC)
+ find_package(MuslGetopt REQUIRED)
+endif()
include_directories(
${RSys_INCLUDE_DIR}
${StarGeom3D_INCLUDE_DIR}
${StarEnc3D_INCLUDE_DIR}
${Stardis_INCLUDE_DIR}
- ${StarSTL_INCLUDE_DIR})
+ ${StarSTL_INCLUDE_DIR}
+ ${CMAKE_CURRENT_BINARY_DIR})
if(MSVC)
- find_package(MuslGetopt REQUIRED)
include_directories(${MuslGetopt_INCLUDE_DIR})
endif()
@@ -46,13 +85,15 @@ include(rcmake_runtime)
rcmake_append_runtime_dirs(_runtime_dirs RSys Stardis StarGeom3D StarEnc3D StarSTL)
###############################################################################
-# Configure and define targets
+# Build subprojects
###############################################################################
-set(VERSION_MAJOR 0)
-set(VERSION_MINOR 4)
-set(VERSION_PATCH 0)
-set(VERSION ${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_PATCH})
+if(NOT STARDIS_DOC STREQUAL "NONE")
+ add_subdirectory(doc)
+endif()
+###############################################################################
+# Configure and define targets
+###############################################################################
set(SDIS_FILES_SRC
stardis-app.c
stardis-compute.c
@@ -70,7 +111,8 @@ set(SDIS_FILES_INC
stardis-intface.h
stardis-output.h
stardis-parsing.h
- stardis-solid.h)
+ stardis-solid.h
+ stardis-version.h.in)
set(SDIS_FILES_DOC COPYING README.md)
@@ -84,20 +126,24 @@ add_executable(sdis-app
${SDIS_FILES_INC})
if(CMAKE_COMPILER_IS_GNUCC)
+ set(MATH_LIB m)
+endif()
+if(MSVC)
+ set(GETOPT_LIB MuslGetopt)
+endif()
+
+if(CMAKE_COMPILER_IS_GNUCC)
set_target_properties(sdis-app PROPERTIES
- COMPILE_FLAGS "-std=c99 ${TE_DEFAULTS}"
+ COMPILE_FLAGS "-std=c99"
VERSION ${VERSION})
- target_link_libraries(sdis-app
- Stardis StarGeom3D StarEnc3D StarSTL RSys m)
elseif(MSVC)
set_target_properties(sdis-app PROPERTIES
- COMPILE_FLAGS "${TE_DEFAULTS}"
VERSION ${VERSION})
- target_link_libraries(sdis-app
- Stardis StarGeom3D StarEnc3D StarSTL RSys MuslGetopt)
endif()
-rcmake_copy_runtime_libraries(sdis-app)
+target_link_libraries(sdis-app
+ Stardis StarGeom3D StarEnc3D StarSTL RSys ${GETOPT_LIB} ${MATH_LIB})
+
###############################################################################
# Define output & install directories
@@ -106,4 +152,7 @@ install(TARGETS sdis-app
ARCHIVE DESTINATION bin
LIBRARY DESTINATION lib
RUNTIME DESTINATION bin)
+
install(FILES ${SDIS_FILES_DOC} DESTINATION share/doc/stardis-app)
+
+rcmake_copy_runtime_libraries(sdis-app)
+\ No newline at end of file
diff --git a/cmake/doc/CMakeLists.txt b/cmake/doc/CMakeLists.txt
@@ -0,0 +1,149 @@
+# Copyright (C) 2018-2020 |Meso|Star>
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+cmake_minimum_required(VERSION 3.0)
+
+string(REGEX MATCH ".*HTML.*" _html ${STARDIS_DOC})
+string(REGEX MATCH ".*ROFF.*" _roff ${STARDIS_DOC})
+
+set(STARDIS_DOC_DIR ${PROJECT_SOURCE_DIR}/../doc)
+
+################################################################################
+# Look for asciidoc and a2x programs
+################################################################################
+if(_html)
+ find_program(ASCIIDOC NAMES asciidoc asciidoc.py)
+ if(NOT ASCIIDOC)
+ unset(_html)
+ message(WARNING
+ "The `asciidoc' program is missing. "
+ "The stardis HTML documentation cannot be generated.")
+ endif()
+endif()
+
+if(_roff)
+ find_program(A2X NAMES a2x a2x.py)
+ if(NOT A2X)
+ unset(_roff)
+ message(WARNING
+ "The `a2x' program is missing. "
+ "The stardis man pages cannot be generated.")
+ endif()
+endif()
+
+################################################################################
+# Copy doc files
+################################################################################
+set(MAN_NAMES
+ stardis-input.5
+ stardis-output.5)
+
+if(_roff OR _html)
+ set(MAN_FILES)
+ foreach(_name IN LISTS MAN_NAMES)
+ set(_src ${STARDIS_DOC_DIR}/${_name}.txt)
+ set(_dst ${CMAKE_CURRENT_BINARY_DIR}/${_name}.txt)
+ add_custom_command(
+ OUTPUT ${_dst}
+ COMMAND ${CMAKE_COMMAND} -E copy ${_src} ${_dst}
+ DEPENDS ${_src}
+ COMMENT "Copy the asciidoc ${_src}"
+ VERBATIM)
+ list(APPEND MAN_FILES ${_dst})
+ endforeach()
+ add_custom_target(man-copy ALL DEPENDS ${MAN_FILES})
+endif()
+
+list(APPEND MAN_NAMES stardis.1)
+
+################################################################################
+# ROFF man pages
+################################################################################
+if(_roff)
+ set(A2X_OPTS -dmanpage -fmanpage)
+ set(MAN_FILES)
+ set(MAN5_FILES)
+ set(MAN1_FILES)
+ foreach(_name IN LISTS MAN_NAMES)
+ set(_man ${CMAKE_CURRENT_BINARY_DIR}/${_name})
+ set(_txt ${CMAKE_CURRENT_BINARY_DIR}/${_name}.txt)
+
+ add_custom_command(
+ OUTPUT ${_man}
+ COMMAND ${A2X} ${A2X_OPTS} ${_txt}
+ DEPENDS man-copy ${_txt}
+ WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
+ COMMENT "Build ROFF man page ${_man}"
+ VERBATIM)
+ list(APPEND MAN_FILES ${_man})
+
+ string(REGEX MATCH "^.*.5$" _man5 ${_man})
+ string(REGEX MATCH "^.*.1$" _man1 ${_man})
+ if(_man1)
+ list(APPEND MAN1_FILES ${_man1})
+ elseif(_man5)
+ list(APPEND MAN5_FILES ${_man5})
+ else()
+ message(FATAL_ERROR "Unexpected man type")
+ endif()
+ endforeach()
+ add_custom_target(man-roff ALL DEPENDS ${MAN_FILES})
+
+ install(FILES ${MAN1_FILES} DESTINATION share/man/man1)
+ install(FILES ${MAN5_FILES} DESTINATION share/man/man5)
+endif()
+
+################################################################################
+# HTML documentation
+################################################################################
+if(_html)
+ set(ASCIIDOC_OPTS
+ -bxhtml11
+ -dmanpage
+ --attribute themedir=${STARDIS_DOC_DIR}
+ --theme=stardis-man)
+
+ set(MAN_FILES)
+ set(MAN5_FILES)
+ set(MAN1_FILES)
+ foreach(_name IN LISTS MAN_NAMES)
+ set(_man ${CMAKE_CURRENT_BINARY_DIR}/${_name}.html)
+ set(_txt ${CMAKE_CURRENT_BINARY_DIR}/${_name}.txt)
+
+ add_custom_command(
+ OUTPUT ${_man}
+ COMMAND ${ASCIIDOC} ${ASCIIDOC_OPTS} ${_txt}
+ DEPENDS man-copy ${_txt} ${STARDIS_DOC_DIR}/stardis-man.css
+ WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
+ COMMENT "Build HTML man page ${_man}"
+ VERBATIM)
+ list(APPEND MAN_FILES ${_man})
+
+ string(REGEX MATCH "^.*.5.html$" _man5 ${_man})
+ string(REGEX MATCH "^.*.1.html$" _man1 ${_man})
+ if(_man1)
+ list(APPEND MAN1_FILES ${_man1})
+ elseif(_man5)
+ list(APPEND MAN5_FILES ${_man5})
+ else()
+ message(FATAL_ERROR "Unexpected man type")
+ endif()
+ endforeach()
+ add_custom_target(man-html ALL DEPENDS ${MAN_FILES})
+
+ install(FILES ${MAN1_FILES} DESTINATION share/man/man1)
+ install(FILES ${MAN5_FILES} DESTINATION share/man/man5)
+endif()
+
diff --git a/doc/stardis-input.5.txt b/doc/stardis-input.5.txt
@@ -0,0 +1,1179 @@
+// Copyright (C) 2016-2018 CNRS, 2018-2019 |Meso|Star>
+//
+// 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]
+ slope_error: <mtl-data>
+ [ microfacet: <normal-distrib> ] # Default is BECKMANN
+ [ <normal-map> ]
+
+<normal-distrib> ::= BECKMANN
+ | PILLBOX
+
+<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)
+ extinction: <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> | <gaussian> | <buie>
+
+<buie> ::= buie:
+ csr: REAL # in [1e-6, 0.849]
+
+<pillbox> ::= pillbox:
+ half_angle: REAL # in ]0, 90]
+
+<gaussian> ::= gaussian:
+ std_dev: REAL # in ]0, INF)
+
+----------------------------------------
+
+<atmosphere> ::= atmosphere:
+ extinction: <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 *half_angle* parameter is the sun's disk half-angle in degrees, that
+ is linked to the apparent size of the sun. A typical half_angle is 0.2664.
+
+*gaussian*::
+ The *gaussian* distribution defines a gaussian distribution of the solar
+ incoming direction. Its single *std_dev* parameter is the standard deviation
+ of the distribution in degrees. Values around 0.2 are typical.
+ As the gaussian distribution is not truncated, the resulting sun vector can
+ theoreticaly be oriented towards the sun, especially with a big, non-typical
+ *std_dev* value.
+
+*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 extinction coefficient in m^-1, that
+can either be a scalar if the *extinction* is constant over the spectrum, or
+can be spectrally described. The extinction 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 extinction 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, extinction: 0 }
+ medium_t: &glass { refractive_index: 1.5, extinction: 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 extinction 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 extinction 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 extinction
+is either 0 or the extinction 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 *slope_error* parameter is 0 or not,
+respectively. Glossy reflections are controlled by a microfacet BRDF. The
+microfacet normals are distributed with respect to the Beckmann or the Pillbox
+distribution according to the *normal-distrib* attribute.
++
+Let S the *slope_error* parameter in ]0, 1]. The Beckmann distribution is
+defined as:
++
+.......
+D(wh) = exp(-tan^2(a) / m^2) / (PI * m^2 * cos^4(a))
+.......
++
+with a = arccos(wh.N), and m = sqrt(2)*S while the pillbox distribution is
+defined as:
++
+.......
+ | 0; if |wh.N| >= S
+D(wh) = |
+ | 1 / (PI * (1 - cos^2(S))); if |wh.N| < S
+.......
+
+*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 extinction 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 extinction 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 extinction is either 0 or the extinction 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 ASCII
+ **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. In addition, the name string cannot
+contain dots, spaces or tabulations. 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 its
+ children 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. In addition, a name cannot contain
+dots, spaces or tabulations. 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
+ slope_error: 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 *half_angle* 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: {half_angle: 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, slope_error: 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, slope_error: 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 *extinction* 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
+ extinction: *air_kabs
+
+- medium: &glass_medium
+ refractive_index: *glass_ref_index
+ extinction: *glass_kabs
+
+# Sun & atmosphere
+- sun: {dni: 1, spectrum: *solar_spectrum}
+- atmosphere: {extinction: *air_kabs}
+
+# Materials
+- material: &specular {mirror: {reflectivity: 1, slope_error: 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}}
+
+# Primary 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/stardis-man.css b/doc/stardis-man.css
@@ -0,0 +1,96 @@
+/* Copyright (C) 2016-2018 CNRS
+ *
+ * This is free style sheet: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This CSS is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see http://www.gnu.org/licenses/. */
+
+body.manpage {
+ font-family:"Liberation Sans",sans-serif;
+ font-size:10pt;
+ text-align: justify;
+ max-width: 55em;
+ margin: 1em;
+ background: #ffffff
+}
+
+body.manpage .monospaced, .literalblock {
+ margin: 2em;
+ color: #636261
+}
+
+body.manpage em {
+ color: #660000
+}
+
+body.manpage div.verseblock > pre.content {
+ font-family: "Liberation Mono",monospace;
+}
+
+body.manpage h1 {
+ padding-bottom: 0.5em;
+}
+body.manpage h2 {
+ border-style: none;
+}
+body.manpage div.sectionbody {
+ margin-left: 3em;
+}
+
+body.manpage code {
+ font-family: "Liberation Mono",monospace;
+}
+
+body.manpage #footer { display: none; }
+
+body.manpage div#toctitle { display: none; }
+
+body.manpage div#toc {
+ display: block;
+ position:fixed;
+ top:0;
+ left:60em;
+ height:100%;
+ width: 100%;
+ padding:3em 0 0 0;
+ border-left:1px solid #dbdbdb;
+ background: #eeeeee
+}
+
+body.manpage a {
+ font-weight: bold;
+ color: #225588;
+}
+
+body.manpage div#toc a, div#toc a:link, div#toc a:visited {
+ margin:0;
+ padding-left: 2em;
+ color:#999999;
+ text-decoration:none;
+ font-weight: normal;
+}
+
+body.manpage div.toclevel1 {
+ line-height: 1.5em;
+}
+
+body.manpage div.toclevel2 {
+ margin-left: 2em;
+}
+
+body.manpage div#toc a:hover {
+ color:#666666;
+}
+
+@media print {
+ body.manpage div#toc { display: none; }
+}
+
diff --git a/doc/stardis-output.5.txt b/doc/stardis-output.5.txt
@@ -0,0 +1,541 @@
+// Copyright (C) 2016-2018 CNRS, 2018-2019 |Meso|Star>
+//
+// 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: <alpha> <beta> (<sun-vector>)"
+
+<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-flux>
+ <absorbed-flux>
+ <cos-factor>
+ <shadow-loss>
+ <missing-loss>
+ <materials-loss>
+ <atmospheric-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> ::= "<incoming-flux> <in-if-no-mat-loss>
+ <in-if-no-atm-loss> <in-mat-loss> <in-atm-loss>
+ <absorbed-flux> <abs-if-no-mat-loss>
+ <abs-if-no-atm-loss> <abs-mat-loss> <abs-atm-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> ::= "<incoming-flux> <in-if-no-mat-loss>
+ <in-if-no-atm-loss> <in-mat-loss> <in-atm-loss>
+ <absorbed-flux> <abs-if-no-mat-loss>
+ <abs-if-no-atm-loss> <abs-mat-loss> <abs-atm-loss>"
+
+-------------------------------------
+
+<receiver-maps> ::= VTK-RECEIVER-MAP
+ [ <receiver-maps> ... ]
+
+<geometry-data> ::= OBJ-FILE
+ [ ---
+ <geometry-data> ... ]
+
+-------------------------------------
+
+<area> ::= REAL # in ]0, INF)
+
+<real3> ::= REAL REAL REAL
+
+<alpha> ::= REAL # Degrees in [0, 360[
+<beta> ::= REAL # Degrees in [0, 90]
+<sun-vector> ::= <real3>
+
+<incoming-flux> ::= <estimate>
+<in-if-no-mat-loss> ::= <estimate>
+<in-if-no-atm-loss> ::= <estimate>
+<in-mat-loss> ::= <estimate>
+<in-atm-loss> ::= <estimate>
+<absorbed-flux> ::= <estimate>
+<abs-if-no-mat-loss> ::= <estimate>
+<abs-if-no-atm-loss> ::= <estimate>
+<abs-mat-loss> ::= <estimate>
+<abs-atm-loss> ::= <estimate>
+<cos-factor> ::= <estimate>
+<missing-loss> ::= <estimate>
+<materials-loss> ::= <estimate>
+<atmospheric-loss> ::= <estimate>
+<shadow-loss> ::= <estimate>
+<efficiency> ::= <estimate>
+
+<estimate> ::= <expected-value> <standard-error>
+<expected-value> ::= REAL
+<standard-error> ::= REAL # in [0, INF)
+
+<entity-identifier> # Defined in *solstice-input*(5)
+_______
+
+SIMULATION
+----------
+
+A *simulation-output* begins with two header lines. The first one reports the
+sun direction used in the simulation (two angles in degrees, plus the
+corresponding sun vector),
+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-flux*: maximum flux that all the primary geometries could
+ intercept if properly oriented and flat-shaped;
+- *absorbed-flux*: absorbed part of the flux reaching any receiver geometry.
+ At most equal to the potential flux;
+- *cos-factor*: cos of the angle between the sun direction and the normal of
+ the primary surfaces (average cos over all primary geometries);
+- *shadow-loss*: potential flux intercepted by another geometry before
+ reaching a primary geometry;
+- *missing-loss*: part of the flux that reaches a primary geometry, follows a
+ radiative path, but is not absorbed; this flux could have bounced on
+ geometries, including receivers, but without being absorbed;
+- *materials-loss*: total flux absorbed by non-receivers along radiative
+ paths; includes both surface and volume absorption;
+- *atmospheric-loss*: total flux extinction by the atmosphere along radiative
+ paths.
+
+This results can be used to check conservation of energy:
+
+potential-flux * cos-factor and (absorbed-flux + shadow-loss +
+missing-loss + materials-loss + atmospheric-loss)
+should be equal within their respective uncertainty ranges.
+
+Per receiver results
+~~~~~~~~~~~~~~~~~~~~
+
+Following global results, the output includes various per-receiver lines, one
+line per receiver, the exact number of lines being part of the headers. The
+per-receiver results are sorted according to the order of the receivers as
+defined in the submitted *solstice-receiver*(5) file. 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.
+
+- *incoming-flux*: flux that reaches the receiver side;
+- *in-if-no-mat-loss*: incoming-flux if absorption on non-receivers is not
+ taken into account;
+- *in-if-no-atm-loss*: incoming-flux if atmospheric extinction is not taken
+ into account;
+- *in-mat-loss*: in-if-no-mat-loss - incoming-flux;
+- *in-atm-loss*: in-if-no-atm-loss - incoming-flux;
+- *absorbed-flux*: flux absorbed by the receiver side;
+- *abs-if-no-mat-loss*: absorbed-flux if absorption by non-receivers is not
+ taken into account;
+- *abs-if-no-atm-loss*: absorbed-flux if atmospheric extinction is not taken
+ into account;
+- *abs-mat-loss*: abs-if-no-mat-loss - absorbed-flux;
+- *abs-atm-loss*: abs-if-no-atm-loss - absorbed-flux;
+- *efficiency*: fraction of the potential flux absorbed by this 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
+~~~~~~~~~~~~~~~~~~~
+
+Following 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*: cos of the angle between the sun direction and the normal of
+ the primary surface (average cos on the primary geometry);
+- *shadow-loss*: potential flux intercepted by another geometry before reaching
+ the primary geometry of interest.
+
+Per receiver and per primary results
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Following 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.
+
+- *incoming-flux*: flux that reaches the receiver side;
+- *in-if-no-mat-loss*: incoming-flux if absorption on non-receivers is not
+ taken into account;
+- *in-if-no-atm-loss*: incoming-flux if atmospheric extinction is not taken
+ into account;
+- *in-mat-loss*: in-if-no-mat-loss - incoming-flux;
+- *in-atm-loss*: in-if-no-atm-loss - incoming-flux;
+- *absorbed-flux*: flux absorbed by the receiver side;
+- *abs-if-no-mat-loss*: absorbed-flux if absorption by non-receivers is not
+ taken into account;
+- *abs-if-no-atm-loss*: absorbed-flux if atmospheric extinction is not taken
+ into account;
+- *abs-mat-loss*: abs-if-no-mat-loss - absorbed-flux;
+- *abs-atm-loss*: abs-if-no-atm-loss - absorbed-flux;
+
+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 estimate of its incoming flux density and/or absorbed flux
+density 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 incoming flux density and/or absorbed flux density. 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 flux densities, 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.
+
+The number of written per-triangle flux density estimates depends on the
+receiver's parameters: both front and back sides of the receiver can be active
+and each side can produce an estimate both for the incoming flux density and
+for the absorbed flux density. As a consequence, the output can include up to
+4 different estimates that are written in the order: incoming front, absorbed
+front, incoming back, absorbed back. 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> ::= <incoming-flux>
+ | <absorbed-flux>
+ | <incoming-flux> <absorbed-flux>
+
+<incoming-flux> ::= <flux-density-data>
+<absorbed-flux> ::= <flux-density-data>
+
+<flux-density-data> ::= SCALARS <side-and-flux-names> float 2
+ LOOKUP_TABLE default
+ <estimate>
+ [ <estimate> ... ]
+
+<side-and-flux-names> ::= Front_faces_Incoming_flux
+ | Front_faces_Absorbed_flux
+ | Back_faces_Incoming_flux
+ | Back_faces_Absorbed_flux
+
+<#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 type: the path is yellow if its first segment, i.e.
+the ray starting from the sun towards a primary geometry, is occluded by a non
+virtual object. If not occluded, the path can be blue or turquoise whether it
+reaches a receiver or not, respectively. Finally, the path can also be red if
+it was canceled due to a topologically incoherent impact (i.e. an impact on a
+surface not at the boundary of the medium in which the rays was propagating).
+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 5
+ <color-error>
+ <color-unused>
+ <color-success>
+ <color-missing>
+ <color-occluded>
+
+<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 # Red: for error paths
+ | 0.25 # Green: unused
+ | 0.5 # Blue: for success paths
+ | 0.75 # Turquoise: for missing paths
+ | 1.0 # Yellow: for occluded paths
+
+<color-error> ::= 1.0 0.0 0.0 1.0
+<color-unused> ::= 0.0 1.0 0.0 1.0
+<color-success> ::= 0.0 0.0 1.0 1.0
+<color-missing> ::= 0.0 1.0 1.0 1.0
+<color-occluded> ::= 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/stardis.1.txt.in b/doc/stardis.1.txt.in
@@ -0,0 +1,272 @@
+// Copyright (C) 2016-2018 CNRS, 2018-2019 |Meso|Star>
+//
+// 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,
+materials properties and atmospheric extinction. 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.
+
+Please note that any coordinate-related question in Solstice must be
+considered with the right-handed convention in mind.
+
+OPTIONS
+-------
+*-D* <__alpha__,__beta__[:...]>::
+ List of sun directions. A direction is defined by two angles in degrees. The
+ first one, here refered to as _alpha_, is an azimuthal angle in [0, 360[ and
+ the second one, here refered to as _beta_, is an elevation in [0, 90].
+ Each provided sun direction triggers a new computation whose results are
+ concatenated to the _output_ file.
++
+Following the right-handed convention, Solstice azimuthal rotation is
+counter-clockwise, with 0° on the X axis. Solstice elevation starts from 0° for
+directions in the XY plane, up to 90° at zenith. Thus -D0,0 -D90,0 -D180,0 and
+-D270,0 will produce solar vectors {-1,0,0} {0,-1,0} {+1,0,0} and {0,+1,0}
+respectively, while -D__alpha__,90 will produce {0,0,-1} regardless of _alpha_
+value.
+
+*-f*::
+ Force overwrite of the output files, i.e. the _output_ file and the file
+ where the state of the random number generator is saved (see the *-G*
+ option).
+
+*-G* <__sub-option__:...>::
+ Save and restore the state of the random number generator. This option can be
+ used to ensure the statistical independence between successive simulations
+ on the same system. For instance, one can run a new simulation and
+ initialising its random number generator with the final state of the
+ generator as defined by the previous run. Available sub options are:
+
+ **istate=**_input_rng_state_;;
+ Define the file from which the initial state of the random number generator
+ is read. If not defined, the random number generator is initialised with
+ its default seed.
+
+ **ostate=**_output_rng_state_;;
+ Define the file where the final state of the random number generator is
+ written. If not defined, this state is simply discarded.
+
+*-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 use as many threads as CPU
+ cores.
+
+*-v*::
+ Make solstice more verbose.
+
+*--version*::
+ Output version information and exit.
+
+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
+---------
+Copyright © 2016-2018 CNRS, 2018-2019 |Meso|Star>. License GPLv3+: GNU GPL
+version 3 or later <http://gnu.org/licenses/gpl.html>. This is free software.
+You are free to change and redistribute it. There is NO WARRANTY, to the extent
+permitted by law.
+
+SEE ALSO
+--------
+*csplit*(1),
+*feh*(1),
+*sed*(1),
+*solstice-input*(5),
+*solstice-output*(5),
+*solstice-receiver*(5)
diff --git a/src/stardis-parsing.c b/src/stardis-parsing.c
@@ -97,7 +97,7 @@ print_version
ASSERT(stream);
fprintf(stream,
"Stardis version %i.%i.%i built on stardis solver version %i.%i.%i\n",
- StardisApp_VERSION_MAJOR, StardisApp_VERSION_MINOR, StardisApp_VERSION_PATCH,
+ STARDIS_APP_VERSION_MAJOR, STARDIS_APP_VERSION_MINOR, STARDIS_APP_VERSION_PATCH,
Stardis_VERSION_MAJOR, Stardis_VERSION_MINOR, Stardis_VERSION_PATCH);
}
diff --git a/src/stardis-version.h b/src/stardis-version.h
@@ -1,14 +0,0 @@
-/* Copying and distribution of this file, with or without modification,
- * are permitted in any medium without royalty provided the copyright
- * notice and this notice are preserved. This file is offered as-is,
- * without any warranty. */
-
-#ifndef StardisApp_VERSION_H
-#define StardisApp_VERSION_H
-
-#define StardisApp_VERSION_MAJOR 0
-#define StardisApp_VERSION_MINOR 1
-#define StardisApp_VERSION_PATCH 0
-
-#endif /* StardisApp_VERSION_H */
-
diff --git a/src/stardis-version.h.in b/src/stardis-version.h.in
@@ -0,0 +1,24 @@
+/* Copyright (C) 2018-2020 |Meso|Star>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+#ifndef STARDIS_VERSION_H
+#define STARDIS_VERSION_H
+
+#define STARDIS_APP_VERSION_MAJOR @VERSION_MAJOR@
+#define STARDIS_APP_VERSION_MINOR @VERSION_MINOR@
+#define STARDIS_APP_VERSION_PATCH @VERSION_PATCH@
+
+#endif /* STARDIS_VERSION_H */
+