solstice-pp

Post-processing utilities for the solstice app
git clone git://git.meso-star.com/solstice-pp.git
Log | Files | Refs | README | LICENSE

commit 8d0faf6bb9b35af8e7d8db3b33ef2f07d551c770
parent c67fd6f865f9d91dcf12e042c5dfa9c1c53d4ea3
Author: Christophe Coustet <christophe.coustet@meso-star.com>
Date:   Mon,  7 Sep 2026 16:12:38 +0200

Merge branch 'release_0.5'

Diffstat:
MMakefile | 46++++++++++++++++++++++++++++++++++++++--------
MREADME.md | 60++++++++++++++++++++++++++++++++++++++----------------------
Mconfig.mk | 50+++++++++++++++++++++++++++++++++++++++++++++++---
Mcyl/Makefile | 9++++++---
Adoc/solmaps.1 | 111+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Adoc/solpaths.1 | 103+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Adoc/solpp.1 | 142+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Adoc/solppraw.1 | 96+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Dsolmaps.c | 75---------------------------------------------------------------------------
Dsolpaths.c | 49-------------------------------------------------
Dsolpp.c | 338-------------------------------------------------------------------------------
Dsolpp.h | 450-------------------------------------------------------------------------------
Dsolppraw.c | 165-------------------------------------------------------------------------------
Asrc/solmaps.c | 92+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/solpaths.c | 58++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/solpp.c | 352+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/solpp.h | 470+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/solppraw.c | 182+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mthemis/Makefile | 11+++++++----
Mthemis/themis.c | 1+
20 files changed, 1743 insertions(+), 1117 deletions(-)

diff --git a/Makefile b/Makefile @@ -17,26 +17,56 @@ include config.mk +PROG =\ + solmaps \ + solpp \ + solppraw \ + solpaths -SRC = solmaps.c solpp.c solppraw.c solpaths.c -PROG = $(SRC:.c=) +MAN = \ + doc/solmaps.1 \ + doc/solpp.1 \ + doc/solpaths.1 \ + doc/solppraw.1 PROJECTS = themis cyl default: $(PROG) -install: $(PROG) - mkdir -p $(DESTDIR)$(PREFIX)/bin - cp $(PROG) $(DESTDIR)$(PREFIX)/bin - for i in $(PROG); do chmod 755 "$(DESTDIR)$(PREFIX)/bin/$${i}"; done +install: $(PROG) $(MAN) + install() { mode="$$1"; prefix="$$2"; shift 2; \ + mkdir -p "$${prefix}"; \ + cp "$$@" "$${prefix}"; \ + chmod "$${mode}" "$${prefix}/$${@##*/}"; \ + }; \ + install 644 "$(DESTDIR)$(PREFIX)/share/doc/solstice-pp" COPYING; \ + install 644 "$(DESTDIR)$(PREFIX)/share/doc/solstice-pp" README.md; \ + for i in $(PROG); \ + do install 755 "$(DESTDIR)$(PREFIX)/bin" $${i}; done; \ + for i in $(MAN); \ + do install 644 "$(DESTDIR)$(PREFIX)/share/man/man1" $${i}; done; + +uninstall: + rm -f "$(DESTDIR)$(PREFIX)/share/doc/solstice-pp/COPYING" + rm -f "$(DESTDIR)$(PREFIX)/share/doc/solstice-pp/README.md" + for i in $(PROG); do rm -f "$(DESTDIR)$(PREFIX)/bin/$${i}"; done + for i in $(MAN); do rm -f "$(DESTDIR)$(PREFIX)/share/man/man1/$${i##*/}"; done .PHONY: clean clean: rm -rf $(PROG) for i in $(PROJECTS); do $(MAKE) -C "$${i}" clean; done -$(PROG): solpp.h - $(CC) -o $@ $(CFLAGS) $@.c +solmaps: src/solmaps.c + +solpp: src/solpp.c + +solppraw: src/solppraw.c + +solpaths: src/solpaths.c + +$(PROG): src/solpp.h config.mk + $(CC) -o $@ $(CFLAGS) src/$@.c run: $(PROJECTS) diff --git a/README.md b/README.md @@ -1,40 +1,43 @@ # Solstice Post-Process -Solstice resuts post-processing tools. -In addition, the code base contains programs that generate input files -for systems to be simulated by Solstice. - -The sources of the post-processing tools are located at the root of the -repository. -Each sub-directory contains the sources of the programs used to generate -the Solstice input files for a specific solar power plant. - -All these programs are written in standard C, with no external -dependencies. -They can therefore be compiled by any C compiler that supports the C99 -standard. -However, to simplify the compilation process on POSIX-compatible -systems, POSIX Makefiles are supplied. -These are used not only to build the programs, but also to run solstice -simulations on the generated input files and to post-process their -results. +Post-processing tools for Solstice outputs and associated tests. + +The sources of the post-processing tools are located in the src directory. +The `themis' test is dynamically generated by building and running a dedicated +code, whose source code is locates in the `themis' subdirectory. +The `cyl' test, that is simple, is run from provided input files. + +All this code is written in C99, with no external dependencies. +It can therefore be compiled by any C compiler that supports the C99 standard. +To simplify compiling on POSIX-compatible systems, POSIX Makefiles are provided. +They can be used not only to build the tools, but also to run solstice tests +and to post-process their results. ## Requirements - C compiler (C99) - POSIX make -- Solstice (optional for test cases) +- Solstice (to run the tests) + +## How to build -## Installation +These programs, as part of the Solstice app suite, can be built on any x86-64 +POSIX system. -Edit config.mk as needed, then run: +Note that you will most likely want to build the entire Solstice suite rather +than these programs alone. If so, a good starting point is the dedicated +[Solstice web page](https://www.meso-star.com/solstice/install.html). + +First ensure that the make utility and a C99 compiler are installed on your +system. Then, edit the config.mk file to meet your needs and build the project +by running: make clean install ## Quick start Two examples are provided in the `cyl` and `themis` directories. -Each contain a Makefile that automate a complete workflow, from scene +Each contain a Makefile that automates a complete workflow, from scene generation, to post-processings with the provided tools, passing to Solstice computation. @@ -44,6 +47,19 @@ To run the test cases : ## Release notes +### Version 0.5 + +- Cope with requirements of solstice 0.11, starting with new output format + items. + +- Fix solpp and solppraw crash when reading on stdin. + +- Add man pages. + +### Version 0.4 + +- Replace CMake with a POSIX Makefile. + ### Version 0.3.1 - Fix VTK files generated by `solpp`: data were written as double while diff --git a/config.mk b/config.mk @@ -13,8 +13,52 @@ # You should have received a copy of the GNU General Public License # along with this program. If not, see <http://www.gnu.org/licenses/>. -VERSION = 0.3.1 +VERSION_MAJOR = 0 +VERSION_MINOR = 5 +VERSION_PATCH = 0 +VERSION = $(VERSION_MAJOR).$(VERSION_MINOR).$(VERSION_PATCH) + PREFIX = /usr/local -CFLAGS = -O2 -std=c99 -pedantic -Wall -#CFLAGS = -g -std=c99 -pedantic -Wall +BUILD_TYPE = RELEASE +#BUILD_TYPE = DEBUG + +################################################################################ +# Tools +################################################################################ +AR = ar +CC = cc +LD = ld +OBJCOPY = objcopy +PKG_CONFIG = pkg-config +RANLIB = ranlib + +################################################################################ +# Compilation options +################################################################################ +WFLAGS =\ + -Wall\ + -Wcast-align\ + -Wconversion\ + -Wextra\ + -Wmissing-declarations\ + -Wmissing-prototypes\ + -Wshadow + +CFLAGS_HARDENED =\ + -D_FORTIFY_SOURCES=2\ + -fcf-protection=full\ + -fstack-clash-protection\ + -fstack-protector-strong + +CFLAGS_COMMON =\ + -std=c99\ + -pedantic\ + -fvisibility=hidden\ + -fstrict-aliasing\ + $(CFLAGS_HARDENED)\ + $(WFLAGS) + +CFLAGS_RELEASE = -O2 -DNDEBUG $(CFLAGS_COMMON) +CFLAGS_DEBUG = -g $(CFLAGS_COMMON) +CFLAGS = $(CFLAGS_$(BUILD_TYPE)) diff --git a/cyl/Makefile b/cyl/Makefile @@ -29,13 +29,16 @@ SIMUL = simul default: run simul: $(INPUT) - solstice -D$(SUN_DIRS) -n$(NEXPERIMENTS) -R$(RCV) -fo $(SIMUL) $(INPUT) - solstice -D$(SUN_DIRS) -g format=obj:split=geometry -fo $(GEOM) $(INPUT) + solstice $$(for d in $(SUN_DIRS); do echo -f "-D$${d} "; done) \ + -n$(NEXPERIMENTS) -R$(RCV) -fo $(SIMUL) $(INPUT) + solstice $$(for d in $(SUN_DIRS); do echo -f "-D$${d} "; done) \ + -g format=obj:split=geometry -fo $(GEOM) $(INPUT) ../solppraw $(SIMUL) ../solpp $(GEOM) $(SIMUL) paths: $(PROG) $(INPUT) - solstice -D$(SUN_DIRS) -q -n$(NPATHS) -R$(RCV) -p default $(INPUT) | ../solpaths + solstice $$(for d in $(SUN_DIRS); do echo -f "-D$${d} "; done) \ + -q -n$(NPATHS) -R$(RCV) -p default $(INPUT) | ../solpaths run: paths simul diff --git a/doc/solmaps.1 b/doc/solmaps.1 @@ -0,0 +1,111 @@ +.\" SPDX-License-Identifier: GPL-3.0-or-later +.\" Copyright (C) 2018-2026 |Méso|Star> (contact@meso-star.com) +.\" +.\" 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/>. +.Dd $Mdocdate$ +.Dt SOLMAPS 1 +.Os +.Sh NAME +.Nm solmaps +.Nd extract and save receiver flux maps from Solstice results +.Sh SYNOPSIS +.Nm +.Op Ar file +.Sh DESCRIPTION +.Nm +reads the results of a +.Xr solstice 1 +simulation from +.Ar file +or from standard input whether a filename is provided as an argument or not, +respectively. +It extracts the maps of incoming flux computed by +.Xr solstice 1 +for the receivers whose +.Cm per_primitive +flag is enabled. +Refer to +.Xr solstice-receiver 5 +for more information. +Each map is then saved in a separate +.Tn VTK +file that can be visualised and analysed in a data +visualisation tool such as +.Lk https://www.paraview.org ParaView . +.Pp +The naming scheme for the output files depends on the way the sun direction was +provided to +.Xr solstice 1 : +.Bl -dash +.It +using the +.Fl D Ar azimuth,elevation +flag: the output file is named after the following pattern: +.Bd -literal -offset indent +printf "%g-%g-%s.vtk" azimuth elevation receiver_name +.Ed +.It +using the +.Fl L Ar latitude,longitude +and +.Fl T Ar time +flags: the output file is named after the following pattern: +.Bd -literal -offset indent +printf "%g-%g-%s-%s.vtk" latitude longitude time receiver_name +.Ed +.El +.Sh EXIT STATUS +.Ex -std +.Sh EXAMPLES +Pipe +.Xr solstice 1 +with +.Nm +to extract the flux maps of the receivers for each provided sun direction: +.Bd -literal -offset indent +solstice -D45,70 -D50,75 -R rcvs.yaml input.yaml | solmaps +.Ed +.Pp +First, invoke +.Xr solstice 1 +to write the results to +.Pa output , +then run +.Nm +on this file to extract the flux maps of the receivers for the provided sun +direction: +.Bd -literal -offset indent +solstice -L3,40 -T"2026-08-15T17:20:00" -R rcvs.yaml -o output input.yaml +solmaps output +.Ed +.Sh SEE ALSO +.Xr solpaths 1 , +.Xr solpp 1 , +.Xr solppraw 1 , +.Xr solstice 1 , +.Xr solstice-output 5 , +.Xr solstice-receiver 5 +.Sh HISTORY +.Nm +was initially developed with funding from the +.Em SOLSTICE LabEx +.Pq Laboratory of Excellence , +in collaboration with the PROMES Laboratory of the +French National Centre for Scientific Research +.Pq CNRS . +Starting in 2026, a new development effort funded by Ademe is ongoing. +.Sh AUTHORS +.Nm +was written and is maintained by +.An |M\['e]so|Star> Aq Mt contact@meso-star.com . diff --git a/doc/solpaths.1 b/doc/solpaths.1 @@ -0,0 +1,103 @@ +.\" SPDX-License-Identifier: GPL-3.0-or-later +.\" Copyright (C) 2018-2026 |Méso|Star> (contact@meso-star.com) +.\" +.\" 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/>. +.Dd $Mdocdate$ +.Dt SOLPATHS 1 +.Os +.Sh NAME +.Nm solpaths +.Nd convert Solstice radiative paths to VTK files +.Sh SYNOPSIS +.Nm +.Op Ar file +.Sh DESCRIPTION +.Nm +reads the radiative paths dumped by +.Xr solstice 1 +when invoked with the +.Fl p +option, from +.Ar file +or from standard input whether a filename is provided as an argument or not, +respectively. +For each simulated sun direction, it generates a +.Tn VTK +file of the radiative paths, that can be visualised and analysed in a data +visualisation tool such as +.Lk https://www.paraview.org ParaView . +.Pp +The naming scheme for the output files depends on the way the sun direction was +provided to +.Xr solstice 1 : +.Bl -dash +.It +using the +.Fl D Ar azimuth,elevation +flag: the output file is named after the following pattern: +.Bd -literal -offset indent +printf "%g-%g-paths.vtk" azimuth elevation +.Ed +.It +using the +.Fl L Ar latitude,longitude +and +.Fl T Ar time +flags: the output file is named after the following pattern: +.Bd -literal -offset indent +printf "%g-%g-%s-paths.vtk" latitude longitude time +.Ed +.El +.Sh EXIT STATUS +.Ex -std +.Sh EXAMPLES +Pipe +.Xr solstice 1 +with +.Nm +to extract the radiative paths for each provided sun direction: +.Bd -literal -offset indent +solstice -n100 -D45,70 -D50,75 -R rcvs.yaml -p default input.yaml | solpaths +.Ed +.Pp +First, invoke +.Xr solstice 1 +to write the results to +.Pa output , +then run +.Nm +on this file to extract the radiative paths for the provided sun direction: +.Bd -literal -offset indent +solstice -L3,40 -T"2026-08-15T17:20:00" -R rcvs.yaml -p default -o output input.yaml +solpaths output +.Ed +.Sh SEE ALSO +.Xr solmaps 1 , +.Xr solpp 1 , +.Xr solppraw 1 , +.Xr solstice 1 , +.Xr solstice-output 5 +.Sh HISTORY +.Nm +was initially developed with funding from the +.Em SOLSTICE LabEx +.Pq Laboratory of Excellence , +in collaboration with the PROMES Laboratory of the +French National Centre for Scientific Research +.Pq CNRS . +Starting in 2026, a new development effort funded by Ademe is ongoing. +.Sh AUTHORS +.Nm +was written and is maintained by +.An |M\['e]so|Star> Aq Mt contact@meso-star.com . diff --git a/doc/solpp.1 b/doc/solpp.1 @@ -0,0 +1,142 @@ +.\" SPDX-License-Identifier: GPL-3.0-or-later +.\" Copyright (C) 2018-2026 |Méso|Star> (contact@meso-star.com) +.\" +.\" 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/>. +.Dd $Mdocdate$ +.Dt SOLPP 1 +.Os +.Sh NAME +.Nm solpp +.Nd post-process Solstice simulation results into VTK and OBJ files +.Sh SYNOPSIS +.Nm +.Ar geom +.Ar simul +.Sh DESCRIPTION +.Nm +takes two input files: +.Ar geom , +the geometry of a solar plant exported by +.Xr solstice 1 +when invoked with the +.Fl g +option, and +.Ar simul , +the results of a +.Xr solstice 1 +simulation. +For each simulated sun direction, +.Nm +writes up to three output files. +.Pp +The first output file is a +.Tn VTK +file that maps the simulation results to the meshes of the primary +geometries, i.e.\& the reflectors. +The mapped results include, for instance, the cosine factor of each +reflector or the amount of flux that reaches a receiver from them. +.Pp +The second output file is another +.Tn VTK +file that stores the geometry of the receivers together with their +simulation results, such as their incoming flux or their efficiency. +.Pp +The optional third output file is an +.Tn OBJ +file that stores the meshes of the miscellaneous geometries, i.e.\& the +geometries that are neither receivers nor primary geometries (if any). +.Pp +The resulting files can be visualised and analysed in a data +visualisation tool such as +.Lk https://www.paraview.org ParaView . +.Pp +Where +.Va end +stands for +.Pa primaries.vtk , +.Pa receivers.vtk , +or +.Pa miscellaneous.obj +for the 1st, 2nd, and optional 3rd output file respectively, the naming scheme +for the output files depends on the way the sun direction was provided to +.Xr solstice 1 : +.Bl -dash +.It +using the +.Fl D Ar azimuth,elevation +flag: the output file is named after the following pattern: +.Bd -literal -offset indent +printf "%g-%g-%s" azimuth elevation end +.Ed +.It +using the +.Fl L Ar latitude,longitude +and +.Fl T Ar time +flags: the output file is named after the following pattern: +.Bd -literal -offset indent +printf "%g-%g-%s-%s" latitude longitude time end +.Ed +.El +.Sh EXIT STATUS +.Ex -std +.Sh EXAMPLES +Invoke +.Xr solstice 1 +to simulate two sun directions on the solar plant described in +.Pa input.yaml . +Then invoke it again to export the geometry of the solar plant for the same sun +directions. +Finally, post-process both outputs with +.Nm : +.Bd -literal -offset indent +solstice -D45,70 -D50,75 -R rcvs.yaml -o simul input.yaml +solstice -D45,70 -D50,75 -g format=obj -o geom input.yaml +solpp geom simul +.Ed +.Pp +Invoke +.Xr solstice 1 +to simulate a sun direction defined by a location and a time on the solar plant +described in +.Pa input.yaml . +Then invoke it again to export the geometry of the solar plant for the same sun +direction. +Finally, post-process both outputs with +.Nm : +.Bd -literal -offset indent +solstice -L3,40 -T"2026-08-15T17:20:00" -R rcvs.yaml -o simul input.yaml +solstice -L3,40 -T"2026-08-15T17:20:00" -g format=obj -o geom input.yaml +solpp geom simul +.Ed +.Sh SEE ALSO +.Xr solmaps 1 , +.Xr solpaths 1 , +.Xr solppraw 1 , +.Xr solstice 1 , +.Xr solstice-output 5 , +.Xr solstice-receiver 5 +.Sh HISTORY +.Nm +was initially developed with funding from the +.Em SOLSTICE LabEx +.Pq Laboratory of Excellence , +in collaboration with the PROMES Laboratory of the +French National Centre for Scientific Research +.Pq CNRS . +Starting in 2026, a new development effort funded by Ademe is ongoing. +.Sh AUTHORS +.Nm +was written and is maintained by +.An |M\['e]so|Star> Aq Mt contact@meso-star.com . diff --git a/doc/solppraw.1 b/doc/solppraw.1 @@ -0,0 +1,96 @@ +.\" SPDX-License-Identifier: GPL-3.0-or-later +.\" Copyright (C) 2018-2026 |Méso|Star> (contact@meso-star.com) +.\" +.\" 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/>. +.Dd $Mdocdate$ +.Dt SOLPPRAW 1 +.Os +.Sh NAME +.Nm solppraw +.Nd format raw Solstice results into human readable text +.Sh SYNOPSIS +.Nm +.Op Ar file +.Sh DESCRIPTION +.Nm +reads the +.Xr solstice 1 +outputs from +.Ar file +or from standard input whether a filename is provided as an argument or not, +respectively. +For each simulated sun direction, it formats the raw results into a human +readable text file, simplifying the analysis of the results. +.Pp +The naming scheme for the output files depends on the way the sun direction was +provided to +.Xr solstice 1 : +.Bl -dash +.It +using the +.Fl D Ar azimuth,elevation +flag: the output file is named after the following pattern: +.Bd -literal -offset indent +printf "%g-%g-raw-results.txt" azimuth elevation +.Ed +.It +using the +.Fl L Ar latitude,longitude +and +.Fl T Ar time +flags: the output file is named after the following pattern: +.Bd -literal -offset indent +printf "%g-%g-%s-results.txt" latitude longitude time +.Ed +.El +.Sh EXIT STATUS +.Ex -std +.Sh EXAMPLES +Invoke +.Xr solstice 1 +to simulate two sun directions and pipe the results directly to +.Nm , +without any intermediary file: +.Bd -literal -offset indent +solstice -D45,70 -D50,75 -R rcvs.yaml input.yaml | solppraw +.Ed +.Pp +Alternatively, invoke +.Xr solstice 1 +to simulate a sun direction and write the results to the +.Pa output +file, then post-process it with solppraw: +.Bd -literal -offset indent +solstice -L3,40 -T"2026-08-15T17:20:00" -R rcvs.yaml -o output input.yaml +solppraw output +.Ed +.Sh SEE ALSO +.Xr solmaps 1 , +.Xr solpaths 1 , +.Xr solpp 1 , +.Xr solstice 1 , +.Xr solstice-output 5 +.Sh HISTORY +.Nm +was initially developed with funding from the +.Em SOLSTICE LabEx +.Pq Laboratory of Excellence , +in collaboration with the PROMES Laboratory of the +French National Centre for Scientific Research +.Pq CNRS . +Starting in 2026, a new development effort funded by Ademe is ongoing. +.Sh AUTHORS +.Nm +was written and is maintained by +.An |M\['e]so|Star> Aq Mt contact@meso-star.com . diff --git a/solmaps.c b/solmaps.c @@ -1,75 +0,0 @@ -/* Copyright (C) 2017, 2018, 2025 |Méso|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/>. */ - -#include "solpp.h" - -int -main(int argc, char** argv) -{ - char s[128]; - buf_char_T buf = BUF_NULL; - FILE* input = stdin; - char* line = NULL; - double azim = -1; - double elev = -1; - - if(argc > 1 && !(input = fopen(argv[1], "r"))) { - fprintf(stderr, "Could not open the file `%s'.\n", argv[1]); - return 1; - } - - line = read_line(&buf, input); - while(line) { - if(!strncmp(line, "#--- Sun direction:", 19)) { - /* Get the solar direction */ - CHK(sscanf(line+19, "%lf %lf (%*f %*f %*f)", &azim, &elev)==2); - line = read_line(&buf, input); - } else if(!strncmp(line, "# vtk", 5)) { - char* header = NULL; - char* rcv_name = NULL; - FILE* output; - - CHK(azim >= 0 && elev >= 0); - - CHK(header = strdup(line)); /* Duplicate the current line */ - CHK(line = read_line(&buf, input)); - CHK(rcv_name = strdup(line)); /* Duplicate the line of the receiver name */ - - /* Create the name of the destination file */ - CHK(snprintf(s, sizeof(s), "%g-%g-%s.vtk", azim, elev, rcv_name) < sizeof(s)); - printf("Writing `%s'\n", s); - CHK(output = fopen(s, "w")); - - /* Write the map data into `output' */ - fprintf(output, "%s\n", header); - fprintf(output, "%s\n", rcv_name); - while((line = read_line(&buf, input)) && line[0] != '#') { - fprintf(output, "%s\n", line); - } - - /* Clean up temporary variable and close the destination file */ - fclose(output); - free(header); - free(rcv_name); - } else { - line = read_line(&buf, input); - } - } - - BUF_RELEASE(buf); - if(input && input!=stdin) fclose(input); - return 0; -} - diff --git a/solpaths.c b/solpaths.c @@ -1,49 +0,0 @@ -/* Copyright (C) 2017, 2018, 2025 |Méso|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/>. */ - -#include "solpp.h" - -int -main(int argc, char** argv) -{ - char s[128]; - buf_char_T buf = BUF_NULL; - FILE* input = stdin; - FILE* output = NULL; - char* line = NULL; - double azim = 0; - double elev = 0; - - if(argc > 1 && !(input = fopen(argv[1], "r"))) { - fprintf(stderr, "Could not open the file `%s'.\n", argv[1]); - return 1; - } - while((line = read_line(&buf, input))) { - if(strncmp(line, "#--- Sun direction:", 19)) { - CHK(output != NULL); - fprintf(output, "%s\n", line); - } else { - CHK(sscanf(line+19, "%lf %lf (%*f %*f %*f)", &azim, &elev) == 2); - CHK(snprintf(s, sizeof(s), "%g-%g-paths.vtk", azim, elev) < sizeof(s)); - if(output) fclose(output); - printf("Writing `%s'\n", s); - CHK(output = fopen(s, "w")); - } - } - BUF_RELEASE(buf); - if(output) fclose(output); - if(input && input!=stdin) fclose(input); - return 0; -} diff --git a/solpp.c b/solpp.c @@ -1,338 +0,0 @@ -/* Copyright (C) 2017, 2018, 2025 |Méso|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/>. */ - -#include "solpp.h" - -struct mesh { - BUF(double) coords; - BUF(size_t) ids; - BUF(size_t) entities; - BUF(size_t) ncells; - size_t voffset; -}; -static const struct mesh MESH_NULL = {BUF_NULL, BUF_NULL, BUF_NULL, BUF_NULL, 0}; - -static inline void -mesh_release(struct mesh* msh) -{ - BUF_RELEASE(msh->coords); - BUF_RELEASE(msh->ids); - BUF_RELEASE(msh->entities); - BUF_RELEASE(msh->ncells); - memset(msh, 0, sizeof(struct mesh)); -} - -static inline void -mesh_write_vtk(FILE* output, struct mesh* msh) -{ - size_t i, n; - - fprintf(output, "# vtk DataFile Version 2.0\n"); - fprintf(output, "Test\n"); - fprintf(output, "ASCII\n"); - fprintf(output, "DATASET POLYDATA\n"); - - n = BUF_SZ(msh->coords)/3; - fprintf(output, "POINTS %zu double\n", n); - FOR_EACH(i, 0, n) { - fprintf(output, "%g %g %g\n", - BUF_AT(msh->coords, i*3+0), - BUF_AT(msh->coords, i*3+1), - BUF_AT(msh->coords, i*3+2)); - } - n = BUF_SZ(msh->ids)/3; - fprintf(output, "POLYGONS %zu %zu\n", n, n*4); - FOR_EACH(i, 0, n) { - fprintf(output, "3 %zu %zu %zu\n", - BUF_AT(msh->ids, i*3+0), - BUF_AT(msh->ids, i*3+1), - BUF_AT(msh->ids, i*3+2)); - } -} - -static inline void -mesh_write_obj(FILE* output, struct mesh* msh) -{ - size_t i, n; - - n = BUF_SZ(msh->coords)/3; - FOR_EACH(i, 0, n) { - fprintf(output, "v %g %g %g\n", - BUF_AT(msh->coords, i*3+0), - BUF_AT(msh->coords, i*3+1), - BUF_AT(msh->coords, i*3+2)); - } - - n = BUF_SZ(msh->ids)/3; - FOR_EACH(i, 0, n) { - fprintf(output, "f %zu %zu %zu\n", - BUF_AT(msh->ids, i*3+0) + 1, - BUF_AT(msh->ids, i*3+1) + 1, - BUF_AT(msh->ids, i*3+2) + 1); - } -} - -static inline void -mesh_write_prim_data_vtk - (FILE* output, const struct mesh* msh, struct simul* simul) -{ - struct prim* prim; - struct rcvXprim* rcvXprim; - size_t ircv; - size_t iprim; - size_t icell; - size_t n; - - n = BUF_SZ(msh->ids) / 3; - fprintf(output, "CELL_DATA %zu\n", n); - - fprintf(output, "FIELD PrimaryData %zu\n", 2 + BUF_SZ(simul->rcvs)*6); - fprintf(output, "cos_factor 2 %zu double\n", n); - FOR_EACH(iprim, 0, BUF_SZ(msh->entities)) { - CHK(prim = find_primary_by_id(simul, BUF_AT(msh->entities, iprim))); - FOR_EACH(icell, 0, BUF_AT(msh->ncells, iprim)) { - fprintf(output, "%g %g\n", prim->cos_factor.E, prim->cos_factor.SE); - } - } - - fprintf(output, "shadow_loss 2 %zu double\n", n); - FOR_EACH(iprim, 0, BUF_SZ(msh->entities)) { - CHK(prim = find_primary_by_id(simul, BUF_AT(msh->entities, iprim))); - FOR_EACH(icell, 0, BUF_AT(msh->ncells, iprim)) { - fprintf(output, "%g %g\n", prim->shadow_loss.E, prim->shadow_loss.SE); - } - } - - #define WRITE(Side, Name) { \ - fprintf(output, "%s_"STR(Side)"_"STR(Name)" 2 %zu double\n", rcv->name, n);\ - FOR_EACH(iprim, 0, BUF_SZ(msh->entities)) { \ - CHK(rcvXprim = find_rcvXprim(simul,rcv->id,BUF_AT(msh->entities,iprim)));\ - FOR_EACH(icell, 0, BUF_AT(msh->ncells, iprim)) { \ - fprintf(output, "%g %g\n", \ - rcvXprim->Name[Side].E, \ - rcvXprim->Name[Side].SE); \ - } \ - } \ - } (void)0 - FOR_EACH(ircv, 0, BUF_SZ(simul->rcvs)) { - const struct rcv* rcv = &BUF_AT(simul->rcvs, ircv); - WRITE(FRONT, in.flux); - WRITE(FRONT, in.flux_mat_loss); - WRITE(FRONT, in.flux_atm_loss); - WRITE(BACK, in.flux); - WRITE(BACK, in.flux_mat_loss); - WRITE(BACK, in.flux_atm_loss); - } - #undef WRITE -} - -static inline void -mesh_write_rcv_data_vtk - (FILE* output, const struct mesh* msh, struct simul* simul) -{ - struct rcv* rcv; - size_t ircv; - size_t icell; - size_t n; - - n = BUF_SZ(msh->ids)/3; - fprintf(output, "CELL_DATA %zu\n", n); - fprintf(output, "FIELD PrimaryData 12\n"); - - #define WRITE(Side, Name) { \ - fprintf(output, STR(Side)"_"STR(Name)" 2 %zu double\n", n); \ - FOR_EACH(ircv, 0, BUF_SZ(msh->entities)) { \ - CHK(rcv = find_receiver_by_id(simul, BUF_AT(msh->entities, ircv))); \ - FOR_EACH(icell, 0, BUF_AT(msh->ncells, ircv)) { \ - fprintf(output, "%g %g\n", rcv->Name[Side].E, rcv->Name[Side].SE); \ - } \ - } \ - } (void)0 - WRITE(FRONT, in.flux); - WRITE(FRONT, in.flux_mat_loss); - WRITE(FRONT, in.flux_atm_loss); - WRITE(FRONT, efficiency); - WRITE(BACK, in.flux); - WRITE(BACK, in.flux_mat_loss); - WRITE(BACK, in.flux_atm_loss); - WRITE(BACK, efficiency); - #undef WRITE - - #define WRITE_MAP(Flux, Side) { \ - fprintf(output, STR(Side)"_"STR(Flux)"_map 2 %zu double\n", n); \ - FOR_EACH(ircv, 0, BUF_SZ(msh->entities)) { \ - CHK(rcv = find_receiver_by_id(simul, BUF_AT(msh->entities, ircv))); \ - if(!BUF_SZ(rcv->map[Flux][Side])) { \ - FOR_EACH(icell, 0, BUF_AT(msh->ncells,ircv)) fprintf(output,"-1 -1\n");\ - } else { \ - FOR_EACH(icell, 0, BUF_AT(msh->ncells,ircv)) { \ - const struct mc* mc = &BUF_AT(rcv->map[Flux][Side], icell); \ - fprintf(output, "%g %g\n", mc->E, mc->SE); \ - } \ - } \ - } \ - } (void)0 - WRITE_MAP(INCOMING, FRONT); - WRITE_MAP(INCOMING, BACK); - WRITE_MAP(ABSORBED, FRONT); - WRITE_MAP(ABSORBED, BACK); - #undef WRITE_MAP -} - -int -main(int argc, char** argv) -{ - buf_char_T buf = BUF_NULL; - char* line = NULL; - - FILE* input; - FILE* geom; - FILE* output; - - if(argc < 3) { - fprintf(stderr, "Usage: %s solstice-geometry solstice-simulation\n", argv[0]); - return 1; - } - - CHK(geom = fopen(argv[1], "r")); - CHK(input = fopen(argv[2], "r")); - - CHK(read_line(&buf, geom)); /* Skip the sun direction of the geometry */ - while((line = read_line(&buf, input))) { - struct simul simul; - - const struct rcv* rcv = NULL; - const struct prim* prim = NULL; - - struct mesh msh_rcv = MESH_NULL; - struct mesh msh_prim = MESH_NULL; - struct mesh msh_misc = MESH_NULL; - - char filename[128]; - char prefix[64]; - size_t ntris_grp = 0, nverts_grp = 0; - size_t nverts_obj = 0, off_obj = 0, off_grp = 0; - - simul_init(&simul); - - CHK(!strncmp(line, "#--- Sun direction:", 19)); - CHK(sscanf(line+19, "%lf %lf (%*f %*f %*f)", &simul.azimuth, &simul.elevation)==2); - CHK(snprintf(prefix, sizeof(prefix), "%g-%g-", - simul.azimuth, simul.elevation) < sizeof(prefix)); - read_simulation(&simul, input); - - while((line = read_line(&buf, geom)) && strncmp(line, "#--- Sun", 8)) { - if(!strncmp(line, "g ", 2)) { - if(prim) { - BUF_PUSH(msh_prim.ncells, ntris_grp); - msh_prim.voffset += nverts_grp; - } - if(rcv) { - BUF_PUSH(msh_rcv.ncells, ntris_grp); - msh_rcv.voffset += nverts_grp; - } - if(!prim && !rcv) msh_misc.voffset += nverts_grp; - prim = find_primary(&simul, line+2); - rcv = find_receiver(&simul, line+2); - if(prim) BUF_PUSH(msh_prim.entities, prim->id); - if(rcv) BUF_PUSH(msh_rcv.entities, rcv->id); - ntris_grp = 0; - nverts_grp = 0; - off_grp = 0; - off_obj = nverts_obj; - - } else if(!strncmp(line, "v ", 2)) { - double pos[3]; - CHK(sscanf(line+2, "%lf %lf %lf", pos+0, pos+1, pos+2) == 3); - if(prim) { - BUF_PUSH(msh_prim.coords, pos[0]); - BUF_PUSH(msh_prim.coords, pos[1]); - BUF_PUSH(msh_prim.coords, pos[2]); - } - if(rcv) { - BUF_PUSH(msh_rcv.coords, pos[0]); - BUF_PUSH(msh_rcv.coords, pos[1]); - BUF_PUSH(msh_rcv.coords, pos[2]); - } - if(!prim && !rcv) { - BUF_PUSH(msh_misc.coords, pos[0]); - BUF_PUSH(msh_misc.coords, pos[1]); - BUF_PUSH(msh_misc.coords, pos[2]); - } - ++nverts_grp; - ++nverts_obj; - } else if(!strncmp(line, "f ", 2)) { - size_t tri[3]; - CHK(sscanf(line+2, "%zu %zu %zu", tri+0, tri+1, tri+2) == 3); - if(prim) { - BUF_PUSH(msh_prim.ids, tri[0]-1 + msh_prim.voffset + off_grp - off_obj); - BUF_PUSH(msh_prim.ids, tri[1]-1 + msh_prim.voffset + off_grp - off_obj); - BUF_PUSH(msh_prim.ids, tri[2]-1 + msh_prim.voffset + off_grp - off_obj); - } - if(rcv) { - BUF_PUSH(msh_rcv.ids, tri[0]-1 + msh_rcv.voffset + off_grp - off_obj); - BUF_PUSH(msh_rcv.ids, tri[1]-1 + msh_rcv.voffset + off_grp - off_obj); - BUF_PUSH(msh_rcv.ids, tri[2]-1 + msh_rcv.voffset + off_grp - off_obj); - } - if(!prim && !rcv) { - BUF_PUSH(msh_misc.ids, tri[0]-1 + msh_misc.voffset + off_grp - off_obj); - BUF_PUSH(msh_misc.ids, tri[1]-1 + msh_misc.voffset + off_grp - off_obj); - BUF_PUSH(msh_misc.ids, tri[2]-1 + msh_misc.voffset + off_grp - off_obj); - } - ++ntris_grp; - } else if(!strcmp(line, "---")) { - nverts_obj = 0; - off_obj = 0; - off_grp = nverts_grp; - } - } - if(prim) BUF_PUSH(msh_prim.ncells, ntris_grp); - if(rcv) BUF_PUSH(msh_rcv.ncells, ntris_grp); - - CHK(snprintf(filename, sizeof(filename), - "%sprimaries.vtk", prefix) < sizeof(prefix)); - printf("Writing `%s'\n", filename); - CHK(output = fopen(filename, "w")); - mesh_write_vtk(output, &msh_prim); - mesh_write_prim_data_vtk(output, &msh_prim, &simul); - fclose(output); - - CHK(snprintf(filename, sizeof(filename), - "%sreceivers.vtk", prefix) < sizeof(prefix)); - printf("Writing `%s'\n", filename); - CHK(output = fopen(filename, "w")); - mesh_write_vtk(output, &msh_rcv); - mesh_write_rcv_data_vtk(output, &msh_rcv, &simul); - fclose(output); - - CHK(snprintf(filename, sizeof(filename), - "%smiscellaneous.obj", prefix) < sizeof(prefix)); - printf("Writing `%s'\n", filename); - CHK(output = fopen(filename, "w")); - mesh_write_obj(output, &msh_misc); - fclose(output); - - mesh_release(&msh_prim); - mesh_release(&msh_rcv); - mesh_release(&msh_misc); - simul_release(&simul); - } - - fclose(geom); - fclose(input); - BUF_RELEASE(buf); - return 0; -} - diff --git a/solpp.h b/solpp.h @@ -1,450 +0,0 @@ -/* Copyright (C) 2017, 2018, 2025 |Méso|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/>. */ - -#define _POSIX_C_SOURCE 200809L /* Support of strdup */ -#include <string.h> -#include <stdio.h> -#include <stdlib.h> - -#ifndef SOLPP_H -#define SOLPP_H - -enum side { FRONT, BACK }; -enum flux_density { ABSORBED, INCOMING }; -struct mc { double E/* Expected value */, SE/* Standard Error */; }; - -/******************************************************************************* - * Helper macros - ******************************************************************************/ -#define STR__(X) #X -#define STR(X) STR__(X) - -#define FOR_EACH(Id, Start, End) for((Id)=(Start); (Id)<(End); ++(Id)) - -#define CHK(Cond) { \ - if(!(Cond)) { \ - fprintf(stderr, "error:%s:%d\n", __FILE__, __LINE__); \ - abort(); \ - } \ - } (void)0 - -/******************************************************************************* - * Dynamic buffer - ******************************************************************************/ -#define BUF(Type) struct { Type* mem; size_t ca; size_t sz; } -#define BUF_NULL {NULL, 0, 0} -#define BUF_RELEASE(B) free((B).mem) -#define BUF_RESERVE(B, Sz) { \ - if((Sz)>(B).ca) { \ - CHK((B).mem = realloc((B).mem, sizeof(*(B).mem)*((B).ca=(Sz)))); \ - } \ - }(void)0 -#define BUF_RESIZE(B, Sz) {BUF_RESERVE((B), Sz); (B).sz = Sz;} (void)0 -#define BUF_PUSH(B, E) { \ - if((B).sz >= (B).ca) BUF_RESERVE((B), ((B).ca?(B).ca*2:32)); \ - (B).mem[(B).sz++]=(E); \ -} (void)0 -#define BUF_SZ(B) (B).sz -#define BUF_MEM(B) (B).mem -#define BUF_AT(B, I) (B).mem[I] - -/******************************************************************************* - * Helper function - ******************************************************************************/ -typedef BUF(char) buf_char_T; - -static inline char* -read_line(buf_char_T* b, FILE* stream) -{ - char* c; - - if(!BUF_SZ(*b)) BUF_RESIZE(*b, 32); - if(!fgets(BUF_MEM(*b), (int)BUF_SZ(*b), stream)) return NULL; - - /* Ensure that the whole line is read */ - while(!strrchr(BUF_MEM(*b), '\n') && !feof(stream)) { - BUF_RESIZE(*b, BUF_SZ(*b)+32); - CHK(fgets - (BUF_MEM(*b) + strlen(BUF_MEM(*b)), - (int)(BUF_SZ(*b) - strlen(BUF_MEM(*b))), stream)); - } - - /* Remove the carriage return */ - if((c = strrchr(BUF_MEM(*b), '\n'))) *c = '\0'; - - return BUF_MEM(*b); -} - -/******************************************************************************* - * Per receiver double sided estimations - ******************************************************************************/ -struct flux { - struct mc flux[2]; - struct mc flux_no_mat_loss[2]; - struct mc flux_no_atm_loss[2]; - struct mc flux_mat_loss[2]; - struct mc flux_atm_loss[2]; -}; - -struct rcv { - struct flux in; - struct flux abs; - struct mc efficiency[2]; - BUF(struct mc) map[2][2]; /* Absorbed/Incoming, Front/Back */ - char* name; - size_t id; - double area; -}; - -static inline void rcv_init(struct rcv* r) {memset(r, 0, sizeof(*r));} -static inline void rcv_release(struct rcv* r) -{ - free(r->name); - BUF_RELEASE(r->map[ABSORBED][FRONT]); - BUF_RELEASE(r->map[ABSORBED][BACK]); - BUF_RELEASE(r->map[INCOMING][FRONT]); - BUF_RELEASE(r->map[INCOMING][BACK]); -} - -/******************************************************************************* - * Per primary estimations - ******************************************************************************/ -struct prim { - struct mc cos_factor; - struct mc shadow_loss; - char* name; - size_t id; - size_t nsamps; - double area; -}; -static inline void prim_init(struct prim* p) {memset(p, 0, sizeof(*p));} -static inline void prim_release(struct prim* p) {free(p->name);} - -/******************************************************************************* - * Per receiver X primary estimations - ******************************************************************************/ -struct rcvXprim { - struct flux in; - struct flux abs; - size_t rcv_id; - size_t prim_id; -}; -static inline void rcvXprim_init(struct rcvXprim* r) {memset(r, 0, sizeof(*r));} -static inline void rcvXprim_release(struct rcvXprim* r) { /*Do nothing*/ } - -/******************************************************************************* - * Overall estimations of a simulation - ******************************************************************************/ -struct simul { - struct mc potential_flux; - struct mc absorbed_flux; - struct mc cos_factor; - struct mc shadow_loss; - struct mc missing_loss; - struct mc materials_loss; - struct mc atmospheric_loss; - - BUF(struct rcv) rcvs; - BUF(struct prim) prims; - BUF(struct rcvXprim) rcvXprims; - - double azimuth; - double elevation; - size_t nsamps; -}; - -static inline void simul_init(struct simul* s) {memset(s, 0, sizeof(*s));} - -static inline void -simul_release(struct simul* s) -{ - size_t i; - FOR_EACH(i,0,BUF_SZ(s->rcvs)) rcv_release(&BUF_AT(s->rcvs, i)); - FOR_EACH(i,0,BUF_SZ(s->prims)) prim_release(&BUF_AT(s->prims, i)); - FOR_EACH(i,0,BUF_SZ(s->rcvXprims)) rcvXprim_release(&BUF_AT(s->rcvXprims, i)); - BUF_RELEASE(s->rcvs); - BUF_RELEASE(s->prims); - BUF_RELEASE(s->rcvXprims); -} - -/******************************************************************************* - * Look for entities - ******************************************************************************/ -static inline struct prim* -find_primary(struct simul* s, const char* name) -{ - size_t i; - FOR_EACH(i, 0, BUF_SZ(s->prims)) - if(!strcmp(BUF_AT(s->prims, i).name, name)) return &BUF_AT(s->prims, i); - return NULL; -} - -static inline struct prim* -find_primary_by_id(struct simul* s, const size_t id) -{ - size_t i; - FOR_EACH(i, 0, BUF_SZ(s->prims)) - if(BUF_AT(s->prims, i).id == id) return &BUF_AT(s->prims, i); - return NULL; -} - -static inline struct rcv* -find_receiver(struct simul* s, const char* name) -{ - size_t i; - FOR_EACH(i, 0, BUF_SZ(s->rcvs)) - if(!strcmp(BUF_AT(s->rcvs, i).name, name)) return &BUF_AT(s->rcvs, i); - return NULL; -} - -static inline struct rcv* -find_receiver_by_id(struct simul* s, const size_t id) -{ - size_t i; - FOR_EACH(i, 0, BUF_SZ(s->rcvs)) - if(BUF_AT(s->rcvs, i).id == id) return &BUF_AT(s->rcvs, i); - return NULL; -} - -static inline struct rcvXprim* -find_rcvXprim(struct simul* s, const size_t rcv_id, const size_t prim_id) -{ - size_t i; - FOR_EACH(i, 0, BUF_SZ(s->rcvXprims)) { - struct rcvXprim* rXp = &BUF_AT(s->rcvXprims, i); - if(rXp->rcv_id == rcv_id && rXp->prim_id == prim_id) return rXp; - } - return NULL; -} - -/******************************************************************************* - * Read simulation data from a solstice-output - ******************************************************************************/ -static inline void -read_receiver_map_side_data(struct rcv* rcv, const size_t n, FILE* input) -{ - buf_char_T buf = BUF_NULL; - char* line = NULL; - size_t i; - enum side side; - enum flux_density flux; - const char* str; - - CHK(line = read_line(&buf, input)); - str = line + 8; - if(!strncmp(str, "Front_faces", 11)) { side = FRONT; str += 12; } - else if(!strncmp(str, "Back_faces", 10)) { side = BACK; str += 11; } - else { fprintf(stderr, "Unexpected side name\n"); abort(); } - - if(!strncmp(str, "Incoming_flux", 13)) { flux = INCOMING; } - else if(!strncmp(str, "Absorbed_flux", 13)) { flux = ABSORBED; } - else { fprintf(stderr, "Unexpected flux name\n"); abort(); } - - CHK(read_line(&buf, input)); /* Discard "LOOKUP_TABLE default" line */ - - BUF_RESIZE(rcv->map[flux][side], n); - FOR_EACH(i, 0, n) { - struct mc* mc = &BUF_AT(rcv->map[flux][side], i); - CHK(line = read_line(&buf, input)); - CHK(sscanf(line, "%lf %lf", &mc->E, &mc->SE) == 2); - } - - BUF_RELEASE(buf); -} - -static inline void -read_receiver_map(struct simul* simul, FILE* input) -{ - struct rcv* rcv; - buf_char_T buf = BUF_NULL; - char* line = NULL; - size_t i, n; - long fp; - - CHK(line = read_line(&buf, input)); - CHK(rcv = find_receiver(simul, line)); - - /* Skip header */ - CHK(read_line(&buf, input)); - CHK(read_line(&buf, input)); - /* Skip vertices */ - CHK(line = read_line(&buf, input)); - CHK(sscanf(line, "POINTS %zu float", &n) == 1); - FOR_EACH(i, 0, n) CHK(read_line(&buf, input)); - /* Skip polygons */ - CHK(line = read_line(&buf, input)); - CHK(sscanf(line, "POLYGONS %zu %*u", &n) == 1); - FOR_EACH(i, 0, n) CHK(read_line(&buf, input)); - /* Read the map data of one side */ - CHK(line = read_line(&buf, input)); - CHK(sscanf(line, "CELL_DATA %zu", &n) == 1); - /* Read map data */ - do { - read_receiver_map_side_data(rcv, n, input); - fp = ftell(input); - line = read_line(&buf, input); - fseek(input, fp, SEEK_SET); - } while(line && !strncmp(line, "SCALARS", 7)); - - BUF_RELEASE(buf); -} - -static inline void -read_simulation(struct simul* simul, FILE* input) -{ - buf_char_T buf = BUF_NULL; - char* line = NULL; - char* tk = NULL; - size_t nrcvs, nprims; - size_t i; - - /* Counters */ - CHK(line = read_line(&buf, input)); - CHK(sscanf(line, "%*u %zu %zu %zu %*u", &nrcvs, &nprims, &simul->nsamps)==3); - - /* Global results */ - #define READ(Name) { \ - CHK(line = read_line(&buf, input)); \ - CHK(sscanf(line, "%lf %lf", &simul->Name.E, &simul->Name.SE) == 2); \ - } (void)0 - READ(potential_flux); - READ(absorbed_flux); - READ(cos_factor); - READ(shadow_loss); - READ(missing_loss); - READ(materials_loss); - READ(atmospheric_loss); - #undef READ - - /* Read per receiver results */ - BUF_RESIZE(simul->rcvs, nrcvs); - FOR_EACH(i, 0, nrcvs) { - struct rcv* rcv = &BUF_AT(simul->rcvs, i); - rcv_init(rcv); - - CHK(line = read_line(&buf, input)); - CHK(tk = strtok(line, " \t")); - CHK(rcv->name = strdup(tk)); - - CHK(tk = strtok(NULL, "")); - #define GET(Side, Name) &rcv->Name[Side].E, &rcv->Name[Side].SE - CHK(sscanf - (tk, - "%zu %lf " - "%lf %lf %lf %lf %lf %lf %lf %lf %lf %lf " - "%lf %lf %lf %lf %lf %lf %lf %lf %lf %lf " - "%lf %lf " - "%lf %lf %lf %lf %lf %lf %lf %lf %lf %lf " - "%lf %lf %lf %lf %lf %lf %lf %lf %lf %lf " - "%lf %lf", - &rcv->id, &rcv->area, - GET(FRONT, in.flux), - GET(FRONT, in.flux_no_mat_loss), - GET(FRONT, in.flux_no_atm_loss), - GET(FRONT, in.flux_mat_loss), - GET(FRONT, in.flux_atm_loss), - GET(FRONT, abs.flux), - GET(FRONT, abs.flux_no_mat_loss), - GET(FRONT, abs.flux_no_atm_loss), - GET(FRONT, abs.flux_mat_loss), - GET(FRONT, abs.flux_atm_loss), - GET(FRONT, efficiency), - GET(BACK, in.flux), - GET(BACK, in.flux_no_mat_loss), - GET(BACK, in.flux_no_atm_loss), - GET(BACK, in.flux_mat_loss), - GET(BACK, in.flux_atm_loss), - GET(BACK, abs.flux), - GET(BACK, abs.flux_no_mat_loss), - GET(BACK, abs.flux_no_atm_loss), - GET(BACK, abs.flux_mat_loss), - GET(BACK, abs.flux_atm_loss), - GET(BACK, efficiency)) == 46); - #undef GET - } - - /* Read per primary results */ - BUF_RESIZE(simul->prims, nprims); - FOR_EACH(i, 0, nprims) { - struct prim* prim = &BUF_AT(simul->prims, i); - prim_init(prim); - - CHK(line = read_line(&buf, input)); - CHK(tk = strtok(line, " \t")); - CHK(prim->name = strdup(tk)); - - CHK(tk = strtok(NULL, "")); - CHK(sscanf(tk, "%zu %lf %zu %lf %lf %lf %lf", - &prim->id, &prim->area, &prim->nsamps, - &prim->cos_factor.E, &prim->cos_factor.SE, - &prim->shadow_loss.E, &prim->shadow_loss.SE) == 7); - } - - /* Per receiverXprimary results */ - BUF_RESIZE(simul->rcvXprims, nprims*nrcvs); - FOR_EACH(i, 0, nprims*nrcvs) { - struct rcvXprim* rcvXprim = &BUF_AT(simul->rcvXprims, i); - rcvXprim_init(rcvXprim); - - CHK(line = read_line(&buf, input)); - #define GET(Side, Name) &rcvXprim->Name[Side].E, &rcvXprim->Name[Side].SE - CHK(sscanf - (line, - "%zu %zu " - "%lf %lf %lf %lf %lf %lf %lf %lf %lf %lf " - "%lf %lf %lf %lf %lf %lf %lf %lf %lf %lf " - "%lf %lf %lf %lf %lf %lf %lf %lf %lf %lf " - "%lf %lf %lf %lf %lf %lf %lf %lf %lf %lf", - &rcvXprim->rcv_id, &rcvXprim->prim_id, - GET(FRONT, in.flux), - GET(FRONT, in.flux_no_mat_loss), - GET(FRONT, in.flux_no_atm_loss), - GET(FRONT, in.flux_mat_loss), - GET(FRONT, in.flux_atm_loss), - GET(FRONT, abs.flux), - GET(FRONT, abs.flux_no_mat_loss), - GET(FRONT, abs.flux_no_atm_loss), - GET(FRONT, abs.flux_mat_loss), - GET(FRONT, abs.flux_atm_loss), - GET(BACK, in.flux), - GET(BACK, in.flux_no_mat_loss), - GET(BACK, in.flux_no_atm_loss), - GET(BACK, in.flux_mat_loss), - GET(BACK, in.flux_atm_loss), - GET(BACK, abs.flux), - GET(BACK, abs.flux_no_mat_loss), - GET(BACK, abs.flux_no_atm_loss), - GET(BACK, abs.flux_mat_loss), - GET(BACK, abs.flux_atm_loss)) == 42); - #undef GET - } - - /* Read receiver maps */ - for(;;) { - const long fp = ftell(input); - line = read_line(&buf, input); - - if(line && !strncmp(line, "# vtk", 5)) { - read_receiver_map(simul, input); - } else { - fseek(input, fp, SEEK_SET); - break; - } - } - BUF_RELEASE(buf); -} - -#endif /* SOLPP_H */ - diff --git a/solppraw.c b/solppraw.c @@ -1,165 +0,0 @@ -/* Copyright (C) 2017, 2018, 2025 |Méso|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/>. */ - -#include "solpp.h" - -static inline void -print_rcv_side(FILE* output, const enum side side, struct rcv* rcv) -{ - #define W(Name) rcv->Name[side].E, rcv->Name[side].SE - fprintf(output, " | [Incoming] "); - fprintf(output, " [Absorbed] \n"); - fprintf(output, " Flux | %16g +/- %-16g | %16g +/- %-16g\n", - W(in.flux), W(abs.flux)); - fprintf(output, " Material loss | %16g +/- %-16g | %16g +/- %-16g\n", - W(in.flux_mat_loss), W(abs.flux_mat_loss)); - fprintf(output, "Atmospheric loss | %16g +/- %-16g | %16g +/- %-16g\n", - W(in.flux_atm_loss), W(abs.flux_atm_loss)); - fprintf(output, "No Material loss | %16g +/- %-16g | %16g +/- %-16g\n", - W(in.flux_no_mat_loss), W(abs.flux_no_mat_loss)); - fprintf(output, " No Atmos. loss | %16g +/- %-16g | %16g +/- %-16g\n", - W(in.flux_no_atm_loss), W(abs.flux_no_atm_loss)); - fprintf(output, " |\n"); - fprintf(output, " Efficiency | %16g +/- %-16g\n", W(efficiency)); - #undef W -} - -static inline void -print_rcvXprim_side(FILE* output, const enum side side, struct rcvXprim* rXp) -{ - #define W(Name) rXp->Name[side].E, rXp->Name[side].SE - fprintf(output, " | [Incoming] "); - fprintf(output, " [Absorbed] \n"); - fprintf(output, " Flux | %16g +/- %-16g | %16g +/- %-16g\n", - W(in.flux), W(abs.flux)); - fprintf(output, " Material loss | %16g +/- %-16g | %16g +/- %-16g\n", - W(in.flux_mat_loss), W(abs.flux_mat_loss)); - fprintf(output, "Atmospheric loss | %16g +/- %-16g | %16g +/- %-16g\n", - W(in.flux_atm_loss), W(abs.flux_atm_loss)); - fprintf(output, "No Material loss | %16g +/- %-16g | %16g +/- %-16g\n", - W(in.flux_no_mat_loss), W(abs.flux_no_mat_loss)); - fprintf(output, " No Atmos. loss | %16g +/- %-16g | %16g +/- %-16g\n", - W(in.flux_no_atm_loss), W(abs.flux_no_atm_loss)); - #undef W -} - -static inline void -print_simulation(FILE* output, struct simul* simul) -{ - size_t i; - - /* Global results */ - #define W(Name) simul->Name.E, simul->Name.SE - fprintf(output, " Overall results (#Samples = %zu)\n", simul->nsamps); - fprintf(output, "------------------------------------------------------------"); - fprintf(output, "------------------------------\n"); - fprintf(output, " Potential flux | %16g +/- %-16g\n", W(potential_flux)); - fprintf(output, " Absorbed flux | %16g +/- %-16g\n", W(absorbed_flux)); - fprintf(output, " Cosine factor | %16g +/- %-16g\n", W(cos_factor)); - fprintf(output, " Shadow loss | %16g +/- %-16g\n", W(shadow_loss)); - fprintf(output, " Missing loss | %16g +/- %-16g\n", W(missing_loss)); - fprintf(output, " Materials loss | %16g +/- %-16g\n", W(materials_loss)); - fprintf(output, "Atmospheric loss | %16g +/- %-16g\n", W(atmospheric_loss)); - fprintf(output, "\n"); - #undef W - /* Per receivers results */ - FOR_EACH(i, 0, BUF_SZ(simul->rcvs)) { - struct rcv* rcv = &BUF_AT(simul->rcvs, i); - fprintf(output, " Receiver `%s' (Area = %g)\n", rcv->name, rcv->area); - if(rcv->in.flux[FRONT].E >= 0) { - fprintf(output, "-----------------------------------------------------[Front]"); - fprintf(output, "------------------------------\n"); - print_rcv_side(output, FRONT, rcv); - } - if(rcv->in.flux[BACK].E >= 0) { - fprintf(output, "------------------------------------------------------[Back]"); - fprintf(output, "------------------------------\n"); - print_rcv_side(output, BACK, rcv); - } - fprintf(output, "\n"); - } - /* Per primary results */ - FOR_EACH(i, 0, BUF_SZ(simul->prims)) { - struct prim* prim = &BUF_AT(simul->prims, i); - fprintf(output, " Primary `%s' (Area = %g; #Samples = %zu)\n", - prim->name, prim->area, prim->nsamps); - #define W(Name) prim->Name.E, prim->Name.SE - fprintf(output, "------------------------------------------------------------"); - fprintf(output, "------------------------------\n"); - fprintf(output, " Cosine factor | %16g +/- %-16g\n", W(cos_factor)); - fprintf(output, " Shadow loss | %16g +/- %-16g\n", W(shadow_loss)); - fprintf(output, "\n"); - #undef W - } - /* Per receiverXprimary results */ - FOR_EACH(i, 0, BUF_SZ(simul->rcvXprims)) { - struct rcvXprim* rXp = &BUF_AT(simul->rcvXprims, i); - struct rcv* rcv = find_receiver_by_id(simul, rXp->rcv_id); - struct prim* prim = find_primary_by_id(simul, rXp->prim_id); - fprintf(output, " Receiver `%s' X Primary `%s'\n", rcv->name, prim->name); - if(rXp->in.flux[FRONT].E >= 0) { - fprintf(output, "-----------------------------------------------------[Front]"); - fprintf(output, "------------------------------\n"); - print_rcvXprim_side(output, FRONT, rXp); - } - if(rXp->in.flux[BACK].E >= 0) { - fprintf(output, "------------------------------------------------------[Back]"); - fprintf(output, "------------------------------\n"); - print_rcvXprim_side(output, BACK, rXp); - } - fprintf(output, "\n"); - } -} - -int -main(int argc, char** argv) -{ - char s[128]; - buf_char_T buf = BUF_NULL; - FILE* input = stdin; - char* line = NULL; - - if(argc > 1 && !(input = fopen(argv[1], "r"))) { - fprintf(stderr, "Could not open the file `%s'.\n", argv[1]); - return 1; - } - while((line = read_line(&buf, input))) { - struct simul simul; - FILE* output = NULL; - - if(strncmp(line, "#--- Sun direction:", 19)) continue; - - simul_init(&simul); - - CHK(!strncmp(line, "#--- Sun direction:", 19)); - CHK(sscanf(line+19, "%lf %lf (%*f %*f %*f)", - &simul.azimuth, &simul.elevation)==2); - CHK(snprintf(s, sizeof(s), "%g-%g-raw-results.txt", - simul.azimuth, simul.elevation) < sizeof(s)); - read_simulation(&simul, input); - - printf("Writing `%s'\n", s); - CHK(output = fopen(s, "w")); - print_simulation(output, &simul); - fclose(output); - - simul_release(&simul); - } - - BUF_RELEASE(buf); - if(input && input != stdin) fclose(input); - return 0; -} - diff --git a/src/solmaps.c b/src/solmaps.c @@ -0,0 +1,92 @@ +/* Copyright (C) 2017, 2018, 2025 |Méso|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/>. */ + +#include "solpp.h" + +#include <string.h> + +int +main(int argc, char** argv) +{ + char s[128]; + buf_char_T buf = BUF_NULL; + FILE* input = stdin; + char* line = NULL; + double azim, elev, lat, lon; + int case_dir = 0; + char time[64]; + buf_char_T dont_read = BUF_NULL; + + if(argc > 1 && !(input = fopen(argv[1], "r"))) { + fprintf(stderr, "Could not open the file `%s'.\n", argv[1]); + return 1; + } + + line = read_line(&buf, input, &dont_read); + + while(line) { + if(!strncmp(line, "#--- Sun direction:", 19)) { + case_dir = 1; + /* Get the solar direction */ + CHK(sscanf(line+19, "%lf %lf (%*f %*f %*f)", &azim, &elev) == 2); + line = read_line(&buf, input, &dont_read); + } else if(!strncmp(line, "#--- Sun location and time:", 27)) { + /* Get the location and time */ + case_dir = 0; + memset(time, 0, sizeof(time)); + CHK(strlen(line+27) < sizeof(time)); + CHK(sscanf(line+27, "%lf %lf %s (%*f %*f %*f)", &lat, &lon, time) == 3); + line = read_line(&buf, input, &dont_read); + } else if(!strncmp(line, "# vtk", 5)) { + char* header = NULL; + char* rcv_name = NULL; + FILE* output; + + CHK(header = strdup(line)); /* Duplicate the current line */ + CHK(line = read_line(&buf, input, &dont_read)); + CHK(rcv_name = strdup(line)); /* Duplicate the line of the receiver name */ + + /* Create the name of the destination file */ + if(case_dir) { + CHK(snprintf(s, sizeof(s), "%g-%g-%s.vtk", azim, elev, rcv_name) + < (long)sizeof(s)); + } else { + CHK(snprintf(s, sizeof(s), "%g-%g-%s-%s.vtk", lat, lon, time, rcv_name) + < (long)sizeof(s)); + } + printf("Writing `%s'\n", s); + CHK(output = fopen(s, "w")); + + /* Write the map data into `output' */ + fprintf(output, "%s\n", header); + fprintf(output, "%s\n", rcv_name); + while((line = read_line(&buf, input, &dont_read)) && line[0] != '#') { + fprintf(output, "%s\n", line); + } + + /* Clean up temporary variable and close the destination file */ + fclose(output); + free(header); + free(rcv_name); + } else { + line = read_line(&buf, input, &dont_read); + } + } + + BUF_RELEASE(buf); + if(input && input!=stdin) fclose(input); + return 0; +} + diff --git a/src/solpaths.c b/src/solpaths.c @@ -0,0 +1,58 @@ +/* Copyright (C) 2017, 2018, 2025 |Méso|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/>. */ + +#include "solpp.h" + +int +main(int argc, char** argv) +{ + char s[128]; + buf_char_T buf = BUF_NULL; + FILE* input = stdin; + FILE* output = NULL; + char* line = NULL; + double azim, elev, lat, lon; + char time[64]; + + if(argc > 1 && !(input = fopen(argv[1], "r"))) { + fprintf(stderr, "Could not open the file `%s'.\n", argv[1]); + return 1; + } + while((line = read_line(&buf, input, NULL))) { + if(!strncmp(line, "#--- Sun direction:", 19)) { + CHK(sscanf(line+19, "%lf %lf (%*f %*f %*f)", &azim, &elev) == 2); + CHK(snprintf(s, sizeof(s), "%g-%g-paths.vtk", azim, elev) + < (long)sizeof(s)); + if(output) fclose(output); + printf("Writing `%s'\n", s); + CHK(output = fopen(s, "w")); + } else if(!strncmp(line, "#--- Sun location and time:", 27)) { + memset(time, 0, sizeof(time)); + CHK(sscanf(line+27, "%lf %lf %s (%*f %*f %*f)", &lat, &lon, time) == 3); + CHK(snprintf(s, sizeof(s), "%g-%g-%s-paths.vtk", lat, lon, time) + < (long)sizeof(s)); + if(output) fclose(output); + printf("Writing `%s'\n", s); + CHK(output = fopen(s, "w")); + } else { + CHK(output != NULL); + fprintf(output, "%s\n", line); + } + } + BUF_RELEASE(buf); + if(output) fclose(output); + if(input && input!=stdin) fclose(input); + return 0; +} diff --git a/src/solpp.c b/src/solpp.c @@ -0,0 +1,352 @@ +/* Copyright (C) 2017, 2018, 2025 |Méso|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/>. */ + +#include "solpp.h" + +struct mesh { + BUF(double) coords; + BUF(size_t) ids; + BUF(size_t) entities; + BUF(size_t) ncells; + size_t voffset; +}; +static const struct mesh MESH_NULL = {BUF_NULL, BUF_NULL, BUF_NULL, BUF_NULL, 0}; + +static inline void +mesh_release(struct mesh* msh) +{ + BUF_RELEASE(msh->coords); + BUF_RELEASE(msh->ids); + BUF_RELEASE(msh->entities); + BUF_RELEASE(msh->ncells); + memset(msh, 0, sizeof(struct mesh)); +} + +static inline void +mesh_write_vtk(FILE* output, struct mesh* msh) +{ + size_t i, n; + + fprintf(output, "# vtk DataFile Version 2.0\n"); + fprintf(output, "Test\n"); + fprintf(output, "ASCII\n"); + fprintf(output, "DATASET POLYDATA\n"); + + n = BUF_SZ(msh->coords)/3; + fprintf(output, "POINTS %zu double\n", n); + FOR_EACH(i, 0, n) { + fprintf(output, "%g %g %g\n", + BUF_AT(msh->coords, i*3+0), + BUF_AT(msh->coords, i*3+1), + BUF_AT(msh->coords, i*3+2)); + } + n = BUF_SZ(msh->ids)/3; + fprintf(output, "POLYGONS %zu %zu\n", n, n*4); + FOR_EACH(i, 0, n) { + fprintf(output, "3 %zu %zu %zu\n", + BUF_AT(msh->ids, i*3+0), + BUF_AT(msh->ids, i*3+1), + BUF_AT(msh->ids, i*3+2)); + } +} + +static inline void +mesh_write_obj(FILE* output, struct mesh* msh) +{ + size_t i, n; + + n = BUF_SZ(msh->coords)/3; + FOR_EACH(i, 0, n) { + fprintf(output, "v %g %g %g\n", + BUF_AT(msh->coords, i*3+0), + BUF_AT(msh->coords, i*3+1), + BUF_AT(msh->coords, i*3+2)); + } + + n = BUF_SZ(msh->ids)/3; + FOR_EACH(i, 0, n) { + fprintf(output, "f %zu %zu %zu\n", + BUF_AT(msh->ids, i*3+0) + 1, + BUF_AT(msh->ids, i*3+1) + 1, + BUF_AT(msh->ids, i*3+2) + 1); + } +} + +static inline void +mesh_write_prim_data_vtk + (FILE* output, const struct mesh* msh, struct simul* simul) +{ + struct prim* prim; + struct rcvXprim* rcvXprim; + size_t ircv; + size_t iprim; + size_t icell; + size_t n; + + n = BUF_SZ(msh->ids) / 3; + fprintf(output, "CELL_DATA %zu\n", n); + + fprintf(output, "FIELD PrimaryData %zu\n", 2 + BUF_SZ(simul->rcvs)*6); + fprintf(output, "cos_factor 2 %zu double\n", n); + FOR_EACH(iprim, 0, BUF_SZ(msh->entities)) { + CHK(prim = find_primary_by_id(simul, BUF_AT(msh->entities, iprim))); + FOR_EACH(icell, 0, BUF_AT(msh->ncells, iprim)) { + fprintf(output, "%g %g\n", prim->cos_factor.E, prim->cos_factor.SE); + } + } + + fprintf(output, "shadow_loss 2 %zu double\n", n); + FOR_EACH(iprim, 0, BUF_SZ(msh->entities)) { + CHK(prim = find_primary_by_id(simul, BUF_AT(msh->entities, iprim))); + FOR_EACH(icell, 0, BUF_AT(msh->ncells, iprim)) { + fprintf(output, "%g %g\n", prim->shadow_loss.E, prim->shadow_loss.SE); + } + } + + #define WRITE(Side, Name) { \ + fprintf(output, "%s_"STR(Side)"_"STR(Name)" 2 %zu double\n", rcv->name, n);\ + FOR_EACH(iprim, 0, BUF_SZ(msh->entities)) { \ + CHK(rcvXprim = find_rcvXprim(simul,rcv->id,BUF_AT(msh->entities,iprim)));\ + FOR_EACH(icell, 0, BUF_AT(msh->ncells, iprim)) { \ + fprintf(output, "%g %g\n", \ + rcvXprim->Name[Side].E, \ + rcvXprim->Name[Side].SE); \ + } \ + } \ + } (void)0 + FOR_EACH(ircv, 0, BUF_SZ(simul->rcvs)) { + const struct rcv* rcv = &BUF_AT(simul->rcvs, ircv); + WRITE(FRONT, in.flux); + WRITE(FRONT, in.flux_mat_loss); + WRITE(FRONT, in.flux_atm_loss); + WRITE(BACK, in.flux); + WRITE(BACK, in.flux_mat_loss); + WRITE(BACK, in.flux_atm_loss); + } + #undef WRITE +} + +static inline void +mesh_write_rcv_data_vtk + (FILE* output, const struct mesh* msh, struct simul* simul) +{ + struct rcv* rcv; + size_t ircv; + size_t icell; + size_t n; + + n = BUF_SZ(msh->ids)/3; + fprintf(output, "CELL_DATA %zu\n", n); + fprintf(output, "FIELD PrimaryData 12\n"); + + #define WRITE(Side, Name) { \ + fprintf(output, STR(Side)"_"STR(Name)" 2 %zu double\n", n); \ + FOR_EACH(ircv, 0, BUF_SZ(msh->entities)) { \ + CHK(rcv = find_receiver_by_id(simul, BUF_AT(msh->entities, ircv))); \ + FOR_EACH(icell, 0, BUF_AT(msh->ncells, ircv)) { \ + fprintf(output, "%g %g\n", rcv->Name[Side].E, rcv->Name[Side].SE); \ + } \ + } \ + } (void)0 + WRITE(FRONT, in.flux); + WRITE(FRONT, in.flux_mat_loss); + WRITE(FRONT, in.flux_atm_loss); + WRITE(FRONT, efficiency); + WRITE(BACK, in.flux); + WRITE(BACK, in.flux_mat_loss); + WRITE(BACK, in.flux_atm_loss); + WRITE(BACK, efficiency); + #undef WRITE + + #define WRITE_MAP(Flux, Side) { \ + fprintf(output, STR(Side)"_"STR(Flux)"_map 2 %zu double\n", n); \ + FOR_EACH(ircv, 0, BUF_SZ(msh->entities)) { \ + CHK(rcv = find_receiver_by_id(simul, BUF_AT(msh->entities, ircv))); \ + if(!BUF_SZ(rcv->map[Flux][Side])) { \ + FOR_EACH(icell, 0, BUF_AT(msh->ncells,ircv)) fprintf(output,"-1 -1\n");\ + } else { \ + FOR_EACH(icell, 0, BUF_AT(msh->ncells,ircv)) { \ + const struct mc* mc = &BUF_AT(rcv->map[Flux][Side], icell); \ + fprintf(output, "%g %g\n", mc->E, mc->SE); \ + } \ + } \ + } \ + } (void)0 + WRITE_MAP(INCOMING, FRONT); + WRITE_MAP(INCOMING, BACK); + WRITE_MAP(ABSORBED, FRONT); + WRITE_MAP(ABSORBED, BACK); + #undef WRITE_MAP +} + +int +main(int argc, char** argv) +{ + buf_char_T buf = BUF_NULL; + char* line = NULL; + buf_char_T dont_read_i = BUF_NULL; + buf_char_T dont_read_g = BUF_NULL; + FILE* input; + FILE* geom; + FILE* output; + + if(argc < 3) { + fprintf(stderr, "Usage: %s solstice-geometry solstice-simulation\n", argv[0]); + return 1; + } + + CHK(geom = fopen(argv[1], "r")); + CHK(input = fopen(argv[2], "r")); + + CHK(read_line(&buf, geom, &dont_read_g)); /* Skip the sun direction of the geometry */ + while((line = read_line(&buf, input, &dont_read_i))) { + struct simul simul; + + const struct rcv* rcv = NULL; + const struct prim* prim = NULL; + + struct mesh msh_rcv = MESH_NULL; + struct mesh msh_prim = MESH_NULL; + struct mesh msh_misc = MESH_NULL; + + char filename[128]; + char prefix[64]; + size_t ntris_grp = 0, nverts_grp = 0; + size_t nverts_obj = 0, off_obj = 0, off_grp = 0; + + simul_init(&simul); + + if(!strncmp(line, "#--- Sun direction:", 19)) { + CHK(sscanf(line+19, "%lf %lf (%*f %*f %*f)", + &simul.azimuth, &simul.elevation)==2); + CHK(snprintf(prefix, sizeof(prefix), "%g-%g-", + simul.azimuth, simul.elevation) + < (long)sizeof(prefix)); + } else if(!strncmp(line, "#--- Sun location and time:", 27)) { + memset(simul.time, 0, sizeof(simul.time)); + CHK(sscanf(line+27, "%lf %lf %s (%*f %*f %*f)", + &simul.latitude, &simul.longitude, simul.time) == 3); + CHK(snprintf(prefix, sizeof(prefix), "%g-%g-%s-", + simul.latitude, simul.longitude, simul.time) + < (long)sizeof(prefix)); + } + read_simulation(&simul, input, &dont_read_i); + + while((line = read_line(&buf, geom, &dont_read_g)) && strncmp(line, "#--- Sun", 8)) { + if(!strncmp(line, "g ", 2)) { + if(prim) { + BUF_PUSH(msh_prim.ncells, ntris_grp); + msh_prim.voffset += nverts_grp; + } + if(rcv) { + BUF_PUSH(msh_rcv.ncells, ntris_grp); + msh_rcv.voffset += nverts_grp; + } + if(!prim && !rcv) msh_misc.voffset += nverts_grp; + prim = find_primary(&simul, line+2); + rcv = find_receiver(&simul, line+2); + if(prim) { BUF_PUSH(msh_prim.entities, prim->id); } + if(rcv) { BUF_PUSH(msh_rcv.entities, rcv->id); } + ntris_grp = 0; + nverts_grp = 0; + off_grp = 0; + off_obj = nverts_obj; + + } else if(!strncmp(line, "v ", 2)) { + double pos[3]; + CHK(sscanf(line+2, "%lf %lf %lf", pos+0, pos+1, pos+2) == 3); + if(prim) { + BUF_PUSH(msh_prim.coords, pos[0]); + BUF_PUSH(msh_prim.coords, pos[1]); + BUF_PUSH(msh_prim.coords, pos[2]); + } + if(rcv) { + BUF_PUSH(msh_rcv.coords, pos[0]); + BUF_PUSH(msh_rcv.coords, pos[1]); + BUF_PUSH(msh_rcv.coords, pos[2]); + } + if(!prim && !rcv) { + BUF_PUSH(msh_misc.coords, pos[0]); + BUF_PUSH(msh_misc.coords, pos[1]); + BUF_PUSH(msh_misc.coords, pos[2]); + } + ++nverts_grp; + ++nverts_obj; + } else if(!strncmp(line, "f ", 2)) { + size_t tri[3]; + CHK(sscanf(line+2, "%zu %zu %zu", tri+0, tri+1, tri+2) == 3); + if(prim) { + BUF_PUSH(msh_prim.ids, tri[0]-1 + msh_prim.voffset + off_grp - off_obj); + BUF_PUSH(msh_prim.ids, tri[1]-1 + msh_prim.voffset + off_grp - off_obj); + BUF_PUSH(msh_prim.ids, tri[2]-1 + msh_prim.voffset + off_grp - off_obj); + } + if(rcv) { + BUF_PUSH(msh_rcv.ids, tri[0]-1 + msh_rcv.voffset + off_grp - off_obj); + BUF_PUSH(msh_rcv.ids, tri[1]-1 + msh_rcv.voffset + off_grp - off_obj); + BUF_PUSH(msh_rcv.ids, tri[2]-1 + msh_rcv.voffset + off_grp - off_obj); + } + if(!prim && !rcv) { + BUF_PUSH(msh_misc.ids, tri[0]-1 + msh_misc.voffset + off_grp - off_obj); + BUF_PUSH(msh_misc.ids, tri[1]-1 + msh_misc.voffset + off_grp - off_obj); + BUF_PUSH(msh_misc.ids, tri[2]-1 + msh_misc.voffset + off_grp - off_obj); + } + ++ntris_grp; + } else if(!strcmp(line, "---")) { + nverts_obj = 0; + off_obj = 0; + off_grp = nverts_grp; + } + } + if(prim) { BUF_PUSH(msh_prim.ncells, ntris_grp); } + if(rcv) { BUF_PUSH(msh_rcv.ncells, ntris_grp); } + + CHK(snprintf(filename, sizeof(filename), "%sprimaries.vtk", prefix) + < (long)sizeof(filename)); + printf("Writing `%s'\n", filename); + CHK(output = fopen(filename, "w")); + mesh_write_vtk(output, &msh_prim); + mesh_write_prim_data_vtk(output, &msh_prim, &simul); + fclose(output); + + CHK(snprintf(filename, sizeof(filename), "%sreceivers.vtk", prefix) + < (long)sizeof(filename)); + printf("Writing `%s'\n", filename); + CHK(output = fopen(filename, "w")); + mesh_write_vtk(output, &msh_rcv); + mesh_write_rcv_data_vtk(output, &msh_rcv, &simul); + fclose(output); + + CHK(snprintf(filename, sizeof(filename), "%smiscellaneous.obj", prefix) + < (long)sizeof(filename)); + if(BUF_SZ(msh_misc.coords) == 0) { + printf("No miscellanous geometry to write `%s'\n", filename); + } else { + printf("Writing `%s'\n", filename); + CHK(output = fopen(filename, "w")); + mesh_write_obj(output, &msh_misc); + fclose(output); + } + + mesh_release(&msh_prim); + mesh_release(&msh_rcv); + mesh_release(&msh_misc); + simul_release(&simul); + } + + fclose(geom); + fclose(input); + BUF_RELEASE(buf); + return 0; +} diff --git a/src/solpp.h b/src/solpp.h @@ -0,0 +1,470 @@ +/* Copyright (C) 2017, 2018, 2025 |Méso|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/>. */ + +#define _POSIX_C_SOURCE 200809L /* Support of strdup */ +#include <string.h> +#include <stdio.h> +#include <stdlib.h> + +#ifndef SOLPP_H +#define SOLPP_H + +enum side { FRONT, BACK }; +enum flux_density { ABSORBED, INCOMING }; +struct mc { double E/* Expected value */, SE/* Standard Error */; }; + +/******************************************************************************* + * Helper macros + ******************************************************************************/ +#define STR__(X) #X +#define STR(X) STR__(X) + +#define FOR_EACH(Id, Start, End) for((Id)=(Start); (Id)<(End); ++(Id)) + +#define CHK(Cond) { \ + if(!(Cond)) { \ + fprintf(stderr, "error:%s:%d\n", __FILE__, __LINE__); \ + abort(); \ + } \ + } (void)0 + +/******************************************************************************* + * Dynamic buffer + ******************************************************************************/ +#define BUF(Type) struct { Type* mem; size_t ca; size_t sz; } +#define BUF_NULL {NULL, 0, 0} +#define BUF_RELEASE(B) free((B).mem) +#define BUF_RESERVE(B, Sz) { \ + if((Sz)>(B).ca) { \ + CHK((B).mem = realloc((B).mem, sizeof(*(B).mem)*((B).ca=(Sz)))); \ + } \ + }(void)0 +#define BUF_RESIZE(B, Sz) {BUF_RESERVE((B), Sz); (B).sz = Sz;} (void)0 +#define BUF_PUSH(B, E) { \ + if((B).sz >= (B).ca) {BUF_RESERVE((B), ((B).ca?(B).ca*2:32));} \ + (B).mem[(B).sz++]=(E); \ +} (void)0 +#define BUF_SZ(B) (B).sz +#define BUF_MEM(B) (B).mem +#define BUF_AT(B, I) (B).mem[I] +#define BUF_MOVE(D, S) (D).mem=(S).mem,(S).mem=NULL, \ + (D).ca=(S).ca,(S).ca=0, \ + (D).sz=(S).sz,(S).sz=0 +#define BUF_SAVE(B, Data, Sz) (B).mem=realloc((B).mem, (Sz)), \ + memcpy((B).mem,(Data),sizeof(*(B).mem)*(Sz)), \ + (B).sz=(B).ca=(Sz), \ + (Data)=NULL + +/******************************************************************************* + * Helper function + ******************************************************************************/ +typedef BUF(char) buf_char_T; + +static inline char* +read_line(buf_char_T* b, FILE* stream, buf_char_T* dont_read) +{ + char* c; + + if(dont_read && BUF_MEM(*dont_read) != NULL) { + BUF_MOVE(*b, *dont_read); + return BUF_MEM(*b); + } + + if(!BUF_SZ(*b)) { BUF_RESIZE(*b, 32); } + if(!fgets(BUF_MEM(*b), (int)BUF_SZ(*b), stream)) return NULL; + + /* Ensure that the whole line is read */ + while(!strrchr(BUF_MEM(*b), '\n') && !feof(stream)) { + BUF_RESIZE(*b, BUF_SZ(*b)+32); + CHK(fgets + (BUF_MEM(*b) + strlen(BUF_MEM(*b)), + (int)(BUF_SZ(*b) - strlen(BUF_MEM(*b))), stream)); + } + + /* Remove the carriage return */ + if((c = strrchr(BUF_MEM(*b), '\n'))) *c = '\0'; + return BUF_MEM(*b); +} + +/******************************************************************************* + * Per receiver double sided estimations + ******************************************************************************/ +struct flux { + struct mc flux[2]; + struct mc flux_no_mat_loss[2]; + struct mc flux_no_atm_loss[2]; + struct mc flux_mat_loss[2]; + struct mc flux_atm_loss[2]; +}; + +struct rcv { + struct flux in; + struct flux abs; + struct mc efficiency[2]; + BUF(struct mc) map[2][2]; /* Absorbed/Incoming, Front/Back */ + char* name; + size_t id; + double area; +}; + +static inline void rcv_init(struct rcv* r) {memset(r, 0, sizeof(*r));} +static inline void rcv_release(struct rcv* r) +{ + free(r->name); + BUF_RELEASE(r->map[ABSORBED][FRONT]); + BUF_RELEASE(r->map[ABSORBED][BACK]); + BUF_RELEASE(r->map[INCOMING][FRONT]); + BUF_RELEASE(r->map[INCOMING][BACK]); +} + +/******************************************************************************* + * Per primary estimations + ******************************************************************************/ +struct prim { + struct mc cos_factor; + struct mc shadow_loss; + char* name; + size_t id; + size_t nsamps; + double area; +}; +static inline void prim_init(struct prim* p) {memset(p, 0, sizeof(*p));} +static inline void prim_release(struct prim* p) {free(p->name);} + +/******************************************************************************* + * Per receiver X primary estimations + ******************************************************************************/ +struct rcvXprim { + struct flux in; + struct flux abs; + size_t rcv_id; + size_t prim_id; +}; +static inline void rcvXprim_init(struct rcvXprim* r) {memset(r, 0, sizeof(*r));} +static inline void rcvXprim_release(struct rcvXprim* r) { (void)r; /*Do nothing*/ } + +/******************************************************************************* + * Overall estimations of a simulation + ******************************************************************************/ +struct simul { + struct mc potential_flux; + struct mc absorbed_flux; + struct mc cos_factor; + struct mc shadow_loss; + struct mc missing_loss; + struct mc materials_loss; + struct mc atmospheric_loss; + + BUF(struct rcv) rcvs; + BUF(struct prim) prims; + BUF(struct rcvXprim) rcvXprims; + + double azimuth; + double elevation; + double latitude; + double longitude; + char time[64]; + size_t nsamps; +}; + +static inline void simul_init(struct simul* s) {memset(s, 0, sizeof(*s));} + +static inline void +simul_release(struct simul* s) +{ + size_t i; + FOR_EACH(i,0,BUF_SZ(s->rcvs)) rcv_release(&BUF_AT(s->rcvs, i)); + FOR_EACH(i,0,BUF_SZ(s->prims)) prim_release(&BUF_AT(s->prims, i)); + FOR_EACH(i,0,BUF_SZ(s->rcvXprims)) rcvXprim_release(&BUF_AT(s->rcvXprims, i)); + BUF_RELEASE(s->rcvs); + BUF_RELEASE(s->prims); + BUF_RELEASE(s->rcvXprims); +} + +/******************************************************************************* + * Look for entities + ******************************************************************************/ +static inline struct prim* +find_primary(struct simul* s, const char* name) +{ + size_t i; + FOR_EACH(i, 0, BUF_SZ(s->prims)) + if(!strcmp(BUF_AT(s->prims, i).name, name)) return &BUF_AT(s->prims, i); + return NULL; +} + +static inline struct prim* +find_primary_by_id(struct simul* s, const size_t id) +{ + size_t i; + FOR_EACH(i, 0, BUF_SZ(s->prims)) + if(BUF_AT(s->prims, i).id == id) return &BUF_AT(s->prims, i); + return NULL; +} + +static inline struct rcv* +find_receiver(struct simul* s, const char* name) +{ + size_t i; + FOR_EACH(i, 0, BUF_SZ(s->rcvs)) + if(!strcmp(BUF_AT(s->rcvs, i).name, name)) return &BUF_AT(s->rcvs, i); + return NULL; +} + +static inline struct rcv* +find_receiver_by_id(struct simul* s, const size_t id) +{ + size_t i; + FOR_EACH(i, 0, BUF_SZ(s->rcvs)) + if(BUF_AT(s->rcvs, i).id == id) return &BUF_AT(s->rcvs, i); + return NULL; +} + +static inline struct rcvXprim* +find_rcvXprim(struct simul* s, const size_t rcv_id, const size_t prim_id) +{ + size_t i; + FOR_EACH(i, 0, BUF_SZ(s->rcvXprims)) { + struct rcvXprim* rXp = &BUF_AT(s->rcvXprims, i); + if(rXp->rcv_id == rcv_id && rXp->prim_id == prim_id) return rXp; + } + return NULL; +} + +/******************************************************************************* + * Read simulation data from a solstice-output + ******************************************************************************/ +static inline void +read_receiver_map_side_data + (struct rcv* rcv, + const size_t n, + FILE* input, + buf_char_T* dont_read) +{ + buf_char_T buf = BUF_NULL; + char* line = NULL; + size_t i; + enum side side; + enum flux_density flux; + const char* str; + + CHK(line = read_line(&buf, input, dont_read)); + + str = line + 8; + if(!strncmp(str, "Front_faces", 11)) { side = FRONT; str += 12; } + else if(!strncmp(str, "Back_faces", 10)) { side = BACK; str += 11; } + else { fprintf(stderr, "Unexpected side name: '%s'\n", str); abort(); } + + if(!strncmp(str, "Incoming_flux", 13)) { flux = INCOMING; } + else if(!strncmp(str, "Absorbed_flux", 13)) { flux = ABSORBED; } + else { fprintf(stderr, "Unexpected flux name: '%s'\n", str); abort(); } + + CHK(read_line(&buf, input, dont_read)); /* Discard "LOOKUP_TABLE default" line */ + + BUF_RESIZE(rcv->map[flux][side], n); + FOR_EACH(i, 0, n) { + struct mc* mc = &BUF_AT(rcv->map[flux][side], i); + CHK(line = read_line(&buf, input, dont_read)); + CHK(sscanf(line, "%lf %lf", &mc->E, &mc->SE) == 2); + } + + BUF_RELEASE(buf); +} + +static inline void +read_receiver_map(struct simul* simul, FILE* input, buf_char_T* dont_read) +{ + struct rcv* rcv; + buf_char_T buf = BUF_NULL; + char* line = NULL; + size_t i, n; + int exit_loop; + + CHK(line = read_line(&buf, input, dont_read)); + + CHK(rcv = find_receiver(simul, line)); + + /* Skip header */ + CHK(read_line(&buf, input, dont_read)); + CHK(read_line(&buf, input, dont_read)); + /* Skip vertices */ + CHK(line = read_line(&buf, input, dont_read)); + CHK(sscanf(line, "POINTS %zu float", &n) == 1); + FOR_EACH(i, 0, n) { CHK(read_line(&buf, input, dont_read)); } + /* Skip polygons */ + CHK(line = read_line(&buf, input, dont_read)); + CHK(sscanf(line, "POLYGONS %zu %*u", &n) == 1); + FOR_EACH(i, 0, n) { CHK(read_line(&buf, input, dont_read)); } + /* Read the map data of one side */ + CHK(line = read_line(&buf, input, dont_read)); + CHK(sscanf(line, "CELL_DATA %zu", &n) == 1); + /* Read map data */ + do { + read_receiver_map_side_data(rcv, n, input, dont_read); + line = read_line(&buf, input, dont_read); + exit_loop = (!line || strncmp(line, "SCALARS", 7)); + if(line) { BUF_SAVE(*dont_read, line, 1+strlen(line)); } + } while(!exit_loop); + + BUF_RELEASE(buf); +} + +static inline void +read_simulation(struct simul* simul, FILE* input, buf_char_T* dont_read) +{ + buf_char_T buf = BUF_NULL; + char* line = NULL; + char* tk = NULL; + size_t nrcvs, nprims; + size_t i; + + /* Counters */ + CHK(line = read_line(&buf, input, dont_read)); + CHK(sscanf(line, "%*u %zu %zu %zu %*u", &nrcvs, &nprims, &simul->nsamps)==3); + + /* Global results */ + #define READ(Name) { \ + CHK(line = read_line(&buf, input, dont_read)); \ + CHK(sscanf(line, "%lf %lf", &simul->Name.E, &simul->Name.SE) == 2); \ + } (void)0 + READ(potential_flux); + READ(absorbed_flux); + READ(cos_factor); + READ(shadow_loss); + READ(missing_loss); + READ(materials_loss); + READ(atmospheric_loss); + #undef READ + + /* Read per receiver results */ + BUF_RESIZE(simul->rcvs, nrcvs); + FOR_EACH(i, 0, nrcvs) { + struct rcv* rcv = &BUF_AT(simul->rcvs, i); + rcv_init(rcv); + + CHK(line = read_line(&buf, input, dont_read)); + CHK(tk = strtok(line, " \t")); + CHK(rcv->name = strdup(tk)); + + CHK(tk = strtok(NULL, "")); + #define GET(Side, Name) &rcv->Name[Side].E, &rcv->Name[Side].SE + CHK(sscanf + (tk, + "%zu %lf " + "%lf %lf %lf %lf %lf %lf %lf %lf %lf %lf " + "%lf %lf %lf %lf %lf %lf %lf %lf %lf %lf " + "%lf %lf " + "%lf %lf %lf %lf %lf %lf %lf %lf %lf %lf " + "%lf %lf %lf %lf %lf %lf %lf %lf %lf %lf " + "%lf %lf", + &rcv->id, &rcv->area, + GET(FRONT, in.flux), + GET(FRONT, in.flux_no_mat_loss), + GET(FRONT, in.flux_no_atm_loss), + GET(FRONT, in.flux_mat_loss), + GET(FRONT, in.flux_atm_loss), + GET(FRONT, abs.flux), + GET(FRONT, abs.flux_no_mat_loss), + GET(FRONT, abs.flux_no_atm_loss), + GET(FRONT, abs.flux_mat_loss), + GET(FRONT, abs.flux_atm_loss), + GET(FRONT, efficiency), + GET(BACK, in.flux), + GET(BACK, in.flux_no_mat_loss), + GET(BACK, in.flux_no_atm_loss), + GET(BACK, in.flux_mat_loss), + GET(BACK, in.flux_atm_loss), + GET(BACK, abs.flux), + GET(BACK, abs.flux_no_mat_loss), + GET(BACK, abs.flux_no_atm_loss), + GET(BACK, abs.flux_mat_loss), + GET(BACK, abs.flux_atm_loss), + GET(BACK, efficiency)) == 46); + #undef GET + } + + /* Read per primary results */ + BUF_RESIZE(simul->prims, nprims); + FOR_EACH(i, 0, nprims) { + struct prim* prim = &BUF_AT(simul->prims, i); + prim_init(prim); + + CHK(line = read_line(&buf, input, dont_read)); + CHK(tk = strtok(line, " \t")); + CHK(prim->name = strdup(tk)); + + CHK(tk = strtok(NULL, "")); + CHK(sscanf(tk, "%zu %lf %zu %lf %lf %lf %lf", + &prim->id, &prim->area, &prim->nsamps, + &prim->cos_factor.E, &prim->cos_factor.SE, + &prim->shadow_loss.E, &prim->shadow_loss.SE) == 7); + } + + /* Per receiverXprimary results */ + BUF_RESIZE(simul->rcvXprims, nprims*nrcvs); + FOR_EACH(i, 0, nprims*nrcvs) { + struct rcvXprim* rcvXprim = &BUF_AT(simul->rcvXprims, i); + rcvXprim_init(rcvXprim); + + CHK(line = read_line(&buf, input, dont_read)); + #define GET(Side, Name) &rcvXprim->Name[Side].E, &rcvXprim->Name[Side].SE + CHK(sscanf + (line, + "%zu %zu " + "%lf %lf %lf %lf %lf %lf %lf %lf %lf %lf " + "%lf %lf %lf %lf %lf %lf %lf %lf %lf %lf " + "%lf %lf %lf %lf %lf %lf %lf %lf %lf %lf " + "%lf %lf %lf %lf %lf %lf %lf %lf %lf %lf", + &rcvXprim->rcv_id, &rcvXprim->prim_id, + GET(FRONT, in.flux), + GET(FRONT, in.flux_no_mat_loss), + GET(FRONT, in.flux_no_atm_loss), + GET(FRONT, in.flux_mat_loss), + GET(FRONT, in.flux_atm_loss), + GET(FRONT, abs.flux), + GET(FRONT, abs.flux_no_mat_loss), + GET(FRONT, abs.flux_no_atm_loss), + GET(FRONT, abs.flux_mat_loss), + GET(FRONT, abs.flux_atm_loss), + GET(BACK, in.flux), + GET(BACK, in.flux_no_mat_loss), + GET(BACK, in.flux_no_atm_loss), + GET(BACK, in.flux_mat_loss), + GET(BACK, in.flux_atm_loss), + GET(BACK, abs.flux), + GET(BACK, abs.flux_no_mat_loss), + GET(BACK, abs.flux_no_atm_loss), + GET(BACK, abs.flux_mat_loss), + GET(BACK, abs.flux_atm_loss)) == 42); + #undef GET + } + + /* Read receiver maps */ + for(;;) { + line = read_line(&buf, input, dont_read); + + if(!line) break; + if(!strncmp(line, "# vtk", 5)) { + read_receiver_map(simul, input, dont_read); + } else { + BUF_SAVE(*dont_read, line, 1+strlen(line)); + break; + } + } + BUF_RELEASE(buf); +} + +#endif /* SOLPP_H */ + diff --git a/src/solppraw.c b/src/solppraw.c @@ -0,0 +1,182 @@ +/* Copyright (C) 2017, 2018, 2025 |Méso|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/>. */ + +#include "solpp.h" + +static inline void +print_rcv_side(FILE* output, const enum side side, struct rcv* rcv) +{ + #define W(Name) rcv->Name[side].E, rcv->Name[side].SE + fprintf(output, " | [Incoming] "); + fprintf(output, " [Absorbed] \n"); + fprintf(output, " Flux | %16g +/- %-16g | %16g +/- %-16g\n", + W(in.flux), W(abs.flux)); + fprintf(output, " Material loss | %16g +/- %-16g | %16g +/- %-16g\n", + W(in.flux_mat_loss), W(abs.flux_mat_loss)); + fprintf(output, "Atmospheric loss | %16g +/- %-16g | %16g +/- %-16g\n", + W(in.flux_atm_loss), W(abs.flux_atm_loss)); + fprintf(output, "No Material loss | %16g +/- %-16g | %16g +/- %-16g\n", + W(in.flux_no_mat_loss), W(abs.flux_no_mat_loss)); + fprintf(output, " No Atmos. loss | %16g +/- %-16g | %16g +/- %-16g\n", + W(in.flux_no_atm_loss), W(abs.flux_no_atm_loss)); + fprintf(output, " |\n"); + fprintf(output, " Efficiency | %16g +/- %-16g\n", W(efficiency)); + #undef W +} + +static inline void +print_rcvXprim_side(FILE* output, const enum side side, struct rcvXprim* rXp) +{ + #define W(Name) rXp->Name[side].E, rXp->Name[side].SE + fprintf(output, " | [Incoming] "); + fprintf(output, " [Absorbed] \n"); + fprintf(output, " Flux | %16g +/- %-16g | %16g +/- %-16g\n", + W(in.flux), W(abs.flux)); + fprintf(output, " Material loss | %16g +/- %-16g | %16g +/- %-16g\n", + W(in.flux_mat_loss), W(abs.flux_mat_loss)); + fprintf(output, "Atmospheric loss | %16g +/- %-16g | %16g +/- %-16g\n", + W(in.flux_atm_loss), W(abs.flux_atm_loss)); + fprintf(output, "No Material loss | %16g +/- %-16g | %16g +/- %-16g\n", + W(in.flux_no_mat_loss), W(abs.flux_no_mat_loss)); + fprintf(output, " No Atmos. loss | %16g +/- %-16g | %16g +/- %-16g\n", + W(in.flux_no_atm_loss), W(abs.flux_no_atm_loss)); + #undef W +} + +static inline void +print_simulation(FILE* output, struct simul* simul) +{ + size_t i; + + /* Global results */ + #define W(Name) simul->Name.E, simul->Name.SE + fprintf(output, " Overall results (#Samples = %zu)\n", simul->nsamps); + fprintf(output, "------------------------------------------------------------"); + fprintf(output, "------------------------------\n"); + fprintf(output, " Potential flux | %16g +/- %-16g\n", W(potential_flux)); + fprintf(output, " Absorbed flux | %16g +/- %-16g\n", W(absorbed_flux)); + fprintf(output, " Cosine factor | %16g +/- %-16g\n", W(cos_factor)); + fprintf(output, " Shadow loss | %16g +/- %-16g\n", W(shadow_loss)); + fprintf(output, " Missing loss | %16g +/- %-16g\n", W(missing_loss)); + fprintf(output, " Materials loss | %16g +/- %-16g\n", W(materials_loss)); + fprintf(output, "Atmospheric loss | %16g +/- %-16g\n", W(atmospheric_loss)); + fprintf(output, "\n"); + #undef W + /* Per receivers results */ + FOR_EACH(i, 0, BUF_SZ(simul->rcvs)) { + struct rcv* rcv = &BUF_AT(simul->rcvs, i); + fprintf(output, " Receiver `%s' (Area = %g)\n", rcv->name, rcv->area); + if(rcv->in.flux[FRONT].E >= 0) { + fprintf(output, "-----------------------------------------------------[Front]"); + fprintf(output, "------------------------------\n"); + print_rcv_side(output, FRONT, rcv); + } + if(rcv->in.flux[BACK].E >= 0) { + fprintf(output, "------------------------------------------------------[Back]"); + fprintf(output, "------------------------------\n"); + print_rcv_side(output, BACK, rcv); + } + fprintf(output, "\n"); + } + /* Per primary results */ + FOR_EACH(i, 0, BUF_SZ(simul->prims)) { + struct prim* prim = &BUF_AT(simul->prims, i); + fprintf(output, " Primary `%s' (Area = %g; #Samples = %zu)\n", + prim->name, prim->area, prim->nsamps); + #define W(Name) prim->Name.E, prim->Name.SE + fprintf(output, "------------------------------------------------------------"); + fprintf(output, "------------------------------\n"); + fprintf(output, " Cosine factor | %16g +/- %-16g\n", W(cos_factor)); + fprintf(output, " Shadow loss | %16g +/- %-16g\n", W(shadow_loss)); + fprintf(output, "\n"); + #undef W + } + /* Per receiverXprimary results */ + FOR_EACH(i, 0, BUF_SZ(simul->rcvXprims)) { + struct rcvXprim* rXp = &BUF_AT(simul->rcvXprims, i); + struct rcv* rcv = find_receiver_by_id(simul, rXp->rcv_id); + struct prim* prim = find_primary_by_id(simul, rXp->prim_id); + fprintf(output, " Receiver `%s' X Primary `%s'\n", rcv->name, prim->name); + if(rXp->in.flux[FRONT].E >= 0) { + fprintf(output, "-----------------------------------------------------[Front]"); + fprintf(output, "------------------------------\n"); + print_rcvXprim_side(output, FRONT, rXp); + } + if(rXp->in.flux[BACK].E >= 0) { + fprintf(output, "------------------------------------------------------[Back]"); + fprintf(output, "------------------------------\n"); + print_rcvXprim_side(output, BACK, rXp); + } + fprintf(output, "\n"); + } +} + +int +main(int argc, char** argv) +{ + char s[128]; + buf_char_T buf = BUF_NULL; + FILE* input = stdin; + char* line = NULL; + buf_char_T dont_read = BUF_NULL; + + if(argc > 1 && !(input = fopen(argv[1], "r"))) { + fprintf(stderr, "Could not open the file `%s'.\n", argv[1]); + return 1; + } + while((line = read_line(&buf, input, &dont_read))) { + struct simul simul; + FILE* output = NULL; + + if(!strncmp(line, "#--- Sun direction:", 19)) { + simul_init(&simul); + + CHK(sscanf(line+19, "%lf %lf (%*f %*f %*f)", + &simul.azimuth, &simul.elevation)==2); + CHK(snprintf(s, sizeof(s), "%g-%g-raw-results.txt", + simul.azimuth, simul.elevation) < (long)sizeof(s)); + read_simulation(&simul, input, &dont_read); + + printf("Writing `%s'\n", s); + CHK(output = fopen(s, "w")); + print_simulation(output, &simul); + fclose(output); + + simul_release(&simul); + } else if(!strncmp(line, "#--- Sun location and time:", 27)) { + + simul_init(&simul); + + memset(simul.time, 0, sizeof(simul.time)); + CHK(sscanf(line+27, "%lf %lf %s (%*f %*f %*f)", + &simul.latitude, &simul.longitude, simul.time) == 3); + CHK(snprintf(s, sizeof(s), "%g-%g-%s-", + simul.latitude, simul.longitude, simul.time) + < (long)sizeof(s)); + read_simulation(&simul, input, &dont_read); + + printf("Writing `%s'\n", s); + CHK(output = fopen(s, "w")); + print_simulation(output, &simul); + fclose(output); + + simul_release(&simul); + } + } + + BUF_RELEASE(buf); + if(input && input != stdin) fclose(input); + return 0; +} diff --git a/themis/Makefile b/themis/Makefile @@ -19,7 +19,7 @@ include ../config.mk NEXPERIMENTS = 1000000 NPATHS = 30 -SUN_DIRS = 270,30:160,40 +SUN_DIRS = 270,30 160,40 RCV = themis-rcv.yaml INPUT = themis.yaml @@ -29,13 +29,16 @@ SIMUL = simul default: run simul: $(INPUT) $(PROG) - solstice -D$(SUN_DIRS) -n$(NEXPERIMENTS) -R$(RCV) -fo $(SIMUL) $(INPUT) - solstice -D$(SUN_DIRS) -g format=obj:split=geometry -fo $(GEOM) $(INPUT) + solstice $$(for d in $(SUN_DIRS); do echo -f "-D$${d} "; done) \ + -n$(NEXPERIMENTS) -R$(RCV) -fo $(SIMUL) $(INPUT) + solstice $$(for d in $(SUN_DIRS); do echo -f "-D$${d} "; done) \ + -g format=obj:split=geometry -fo $(GEOM) $(INPUT) ../solppraw $(SIMUL) ../solpp $(GEOM) $(SIMUL) paths: $(PROG) $(INPUT) - solstice -D$(SUN_DIRS) -q -n$(NPATHS) -R$(RCV) -p default $(INPUT) | ../solpaths + solstice $$(for d in $(SUN_DIRS); do echo -f "-D$${d} "; done) \ + -q -n$(NPATHS) -R$(RCV) -p default $(INPUT) | ../solpaths run: paths simul diff --git a/themis/themis.c b/themis/themis.c @@ -1264,6 +1264,7 @@ main(int argc, char** argv) const double themis_target[3] = { 0, 6.2, 87.15};/* to compute slant range */ const double corr = 4. ;/* correction length due to offset of the stl */ size_t i; + (void)argc; (void)argv; /* Spectra */ print_section("Spectra");