commit 3a4f5a242ec26c8db11447ef3551ec0bae661921
parent 018caeab084f4d5b8622cd6bfa106a28d3eb3940
Author: Vincent Forest <vincent.forest@meso-star.com>
Date: Wed, 1 Oct 2025 12:00:02 +0200
Make test_rnatm (renamed rnatm) a standalone utility.
It installs with the library, and a manual page replaces its detailed
built-in help to conform to the usage of any UNIX tool.
This tool can thus be used to help verify the data used to describe an
atmosphere for htrdr planets. As a side effect, it could also be used to
pre-construct its acceleration structures.
Diffstat:
8 files changed, 770 insertions(+), 527 deletions(-)
diff --git a/.gitignore b/.gitignore
@@ -4,8 +4,7 @@
*.[aod]
*.so
*~
-test*
-!test*.[ch]
+rnatm
.config
.test
tags
diff --git a/Makefile b/Makefile
@@ -30,7 +30,7 @@ LIBNAME_SHARED = librnatm.so
LIBNAME = $(LIBNAME_$(LIB_TYPE))
default: library
-all: default tests
+all: default util
################################################################################
# Library building
@@ -93,7 +93,33 @@ librnatm.o: $(OBJ)
$(CC) $(CFLAGS_LIB) -c $< -o $@
################################################################################
-# Installation
+# Tests
+################################################################################
+UTIL_SRC = src/rnatm_main.c
+UTIL_OBJ = $(UTIL_SRC:.c=.o)
+UTIL_DEP = $(UTIL_SRC:.c=.d)
+
+PKG_CONFIG_LOCAL = PKG_CONFIG_PATH="./:$${PKG_CONFIG_PATH}" $(PKG_CONFIG)
+INCS_UTIL = $$($(PKG_CONFIG_LOCAL) $(PCFLAGS) --cflags rnatm-local rsys)
+LIBS_UTIL = $$($(PKG_CONFIG_LOCAL) $(PCFLAGS) --libs rnatm-local rsys)
+
+CFLAGS_UTIL = $(CFLAGS_EXE) $(INCS_UTIL)
+LDFLAGS_UTIL = $(LDFLAGS_EXE) $(LIBS_UTIL)
+
+util: library $(UTIL_DEP)
+ @$(MAKE) -fMakefile -f src/rnatm_main.d rnatm
+
+$(UTIL_DEP): config.mk rnatm-local.pc
+ @$(CC) $(CFLAGS_UTIL) -MM -MT "$(@:.d=.o) $@" $(@:.d=.c) -MF $@
+
+$(UTIL_OBJ): config.mk rnatm-local.pc
+ $(CC) $(CFLAGS_UTIL) -c $(@:.o=.c) -o $@
+
+rnatm: src/rnatm_main.o config.mk rnatm-local.pc $(LIBNAME)
+ $(CC) $(CFLAGS_UTIL) -o $@ src/rnatm_main.o $(LDFLAGS_UTIL)
+
+################################################################################
+# Miscellaneous
################################################################################
pkg:
sed -e 's#@PREFIX@#$(PREFIX)#g'\
@@ -127,65 +153,39 @@ rnatm-local.pc: rnatm.pc.in
-e 's#@SVX_VERSION@#$(SVX_VERSION)#g'\
rnatm.pc.in > $@
-install: library pkg
+install: library util pkg
install() { mode="$$1"; prefix="$$2"; shift 2; \
mkdir -p "$${prefix}"; \
cp "$$@" "$${prefix}"; \
chmod "$${mode}" "$${prefix}/$${@##*/}"; \
}; \
+ install 755 "$(DESTDIR)$(BINPREFIX)" rnatm; \
install 755 "$(DESTDIR)$(LIBPREFIX)" $(LIBNAME); \
install 644 "$(DESTDIR)$(LIBPREFIX)/pkgconfig" rnatm.pc; \
install 644 "$(DESTDIR)$(INCPREFIX)/rad-net" src/rnatm.h; \
- install 644 "$(DESTDIR)$(MANPREFIX)/man5" rngt.5; \
- install 644 "$(DESTDIR)$(MANPREFIX)/man5" rnpfi.5; \
+ install 644 "$(DESTDIR)$(MANPREFIX)/man1" doc/rnatm.1; \
+ install 644 "$(DESTDIR)$(MANPREFIX)/man5" doc/rngt.5; \
+ install 644 "$(DESTDIR)$(MANPREFIX)/man5" doc/rnpfi.5; \
install 644 "$(DESTDIR)$(PREFIX)/share/doc/rnatm" COPYING; \
install 644 "$(DESTDIR)$(PREFIX)/share/doc/rnatm" README.md
uninstall:
+ rm -f "$(DESTDIR)$(BINPREFIX)/rnatm"
rm -f "$(DESTDIR)$(LIBPREFIX)/$(LIBNAME)"
rm -f "$(DESTDIR)$(LIBPREFIX)/pkgconfig/rnatm.pc"
rm -f "$(DESTDIR)$(INCPREFIX)/rad-net/rnatm.h"
+ rm -f "$(DESTDIR)$(MANPREFIX)/man1/rnatm.1"
rm -f "$(DESTDIR)$(MANPREFIX)/man5/rngt.5"
rm -f "$(DESTDIR)$(MANPREFIX)/man5/rnpfi.5"
rm -f "$(DESTDIR)$(PREFIX)/share/doc/rnatm/COPYING"
rm -f "$(DESTDIR)$(PREFIX)/share/doc/rnatm/README.md"
-################################################################################
-# Miscellaneous targets
-################################################################################
-clean: clean_test
+clean:
rm -f $(DEP) $(OBJ) $(LIBNAME)
+ rm -f $(UTIL_DEP) $(UTIL_OBJ) rnatm
rm -f .config librnatm.o rnatm.pc rnatm-local.pc
lint:
- mandoc -Tlint -Wall rngt.5 || [ $$? -le 1 ]
- mandoc -Tlint -Wall rnpfi.5 || [ $$? -le 1 ]
-
-################################################################################
-# Tests
-################################################################################
-TEST_SRC = src/test_rnatm.c
-TEST_OBJ = $(TEST_SRC:.c=.o)
-TEST_DEP = $(TEST_SRC:.c=.d)
-
-PKG_CONFIG_LOCAL = PKG_CONFIG_PATH="./:$${PKG_CONFIG_PATH}" $(PKG_CONFIG)
-INCS_TEST = $$($(PKG_CONFIG_LOCAL) $(PCFLAGS) --cflags rnatm-local rsys)
-LIBS_TEST = $$($(PKG_CONFIG_LOCAL) $(PCFLAGS) --libs rnatm-local rsys)
-
-CFLAGS_TEST = $(CFLAGS_EXE) $(INCS_TEST)
-LDFLAGS_TEST = $(LDFLAGS_EXE) $(LIBS_TEST)
-
-tests: library $(TEST_DEP) src/test_rnatm.d
- @$(MAKE) -fMakefile -f src/test_rnatm.d test_rnatm
-
-clean_test:
- rm -f test_rnatm src/test_rnatm.d src/test_rnatm.o
-
-$(TEST_DEP): config.mk rnatm-local.pc
- @$(CC) $(CFLAGS_TEST) -MM -MT "$(@:.d=.o) $@" $(@:.d=.c) -MF $@
-
-$(TEST_OBJ): config.mk rnatm-local.pc
- $(CC) $(CFLAGS_TEST) -c $(@:.o=.c) -o $@
-
-test_rnatm: src/test_rnatm.o config.mk rnatm-local.pc $(LIBNAME)
- $(CC) $(CFLAGS_TEST) -o $@ src/$@.o $(LDFLAGS_TEST)
+ mandoc -Tlint -Wall doc/rnatm.1 || [ $$? -le 1 ]
+ mandoc -Tlint -Wall doc/rngt.5 || [ $$? -le 1 ]
+ mandoc -Tlint -Wall doc/rnpfi.5 || [ $$? -le 1 ]
diff --git a/config.mk b/config.mk
@@ -1,6 +1,7 @@
VERSION = 0.1.0
PREFIX = /usr/local
+BINPREFIX = $(PREFIX)/bin
LIBPREFIX = $(PREFIX)/lib
INCPREFIX = $(PREFIX)/include
MANPREFIX = $(PREFIX)/share/man
diff --git a/doc/rnatm.1 b/doc/rnatm.1
@@ -0,0 +1,304 @@
+.\" Copyright (C) 2022, 2023 Centre National de la Recherche Scientifique
+.\" Copyright (C) 2022, 2023 Institut Pierre-Simon Laplace
+.\" Copyright (C) 2022, 2023 Institut de Physique du Globe de Paris
+.\" Copyright (C) 2022, 2023 |Méso|Star>(contact@meso-star.com)
+.\" Copyright (C) 2022, 2023 Observatoire de Paris
+.\" Copyright (C) 2022, 2023 Université de Reims Champagne-Ardenne
+.\" Copyright (C) 2022, 2023 Université de Versaille Saint-Quentin
+.\" Copyright (C) 2022, 2023 Université Paul Sabatier
+.\"
+.\" 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/>.
+.Dd October 1, 2025
+.Dt RNATM 1
+.Os
+.\""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.Sh NAME
+.Nm rnatm
+.Nd check atmospheric data and structures built to manage them
+.\""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.Sh SYNOPSIS
+.Nm
+.Op Fl hNv
+.Op Fl a Ar aerosol_opt Ns Op : Ns Ar aerosol_opt No ...
+.Op Fl c
+.Op Fl d Ar octrees
+.Op Fl i Ar storage
+.Op Fl n Ar name
+.Op Fl o Ar storage
+.Op Fl s Ar nu0 , Ns Ar nu1
+.Op Fl T Ar optical_thickness
+.Op Fl t Ar thread_count
+.Op Fl V Ar definition
+.Fl g Ar gas_opt Ns Op : Ns Ar gas_opt No ...
+.\""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.Sh DESCRIPTION
+.Nm
+helps to check and diagnose errors in input data as submitted to the RaD-net
+atmospheric library.
+It also makes it easy to check the internal workings of the library, such as the
+construction of structures used to accelerate ray tracing in the heterogeneous
+semi-transparent environment described by the input data.
+.Pp
+In addition to regular verification of the input data format, additional tests
+can be performed
+.Pq option Fl c
+to further validate the data, at the cost of longer execution time.
+For example, enabling this option allows to verify the validity of aerosol
+phase function indices with respect to the mesh to which they are associated and
+the list of loaded phase functions.
+.Pp
+The options are as follows:
+.Bl -tag -width Ds
+.\""""""""""""""""""""""""""""""""""""""
+.It Fl a Ar aerosol
+Define an aerosol.
+Use this option once per aerosol, and duplicate it as many times as
+necessary.
+.Pp
+The aerosol options are as follows:
+.Bl -tag -width Ds
+.It Cm mesh= Ns Ar volume_mesh
+Aerosol tetrahedral mesh saved in
+.Xr smsh 5
+format.
+.It Cm name= Ns Ar string
+Name assigned to the aerosol.
+.It Cm radprop= Ns Ar radiative_properties
+Radiatve properties of the aerosol saved in
+.Xr sars 5
+format.
+Radiative properties are defined per volumetric mesh node.
+This file and the tetrahedral mesh
+.Pq option Cm mesh
+must therefore be consistent with each other, i.e. the nodes must be
+listed in the same order.
+.It Cm phasefn= Ns Ar phase_functions_list
+List in
+.Xr rnsl 5
+format of phase functions to be loaded.
+Each phase function is saved in
+.Xr rnsf 5
+format.
+The correspondence between these phase functions and the nodes of the
+volumetric mesh is defined in another file
+.Pq option Cm phaseids .
+.It Cm phaseids= Ns Ar per_node_phase_function
+Path to the
+.Xr rnpfi 5
+file that stores the index of the phase function to be used per
+volumetric mesh node.
+The list of phase function is defined in another file
+.Pq option Cm phasefn .
+Note that this file and the tetrahedral mesh
+.Pq option Cm mesh
+must be consistent with each other, i.e. the nodes must be
+listed in the same order.
+.El
+.\""""""""""""""""""""""""""""""""""""""
+.It Fl c
+Thorough data validation.
+.\""""""""""""""""""""""""""""""""""""""
+.It Fl d Ar octrees
+Write the builded acceleration structures (i.e., the octrees) to file according
+to the VTK file format.
+They are written to standard ouput if the file is a dash
+.Pq - .
+To split the resulting file
+into
+.Ar n
+VTK files, each storing an octree, one can use the csplit command.
+For example with
+.Ar n
+= 4:
+.Bd -literal -offset Ds
+csplit -f octree -k file %^#\ vtk% /^#\ vtk/ {2};
+.Ed
+.\""""""""""""""""""""""""""""""""""""""
+.It Fl g Ar gas_opt Ns Op : Ns Ar gas_opt No ...
+Gas mixture.
+.Pp
+The gas options are as follows:
+.Bl -tag -width Ds
+.It Cm mesh= Ns Ar volumetric_mesh
+Gas tetrahedral mesh saved in
+.Xr smsh 5
+format.
+.It Cm ck= Ns Ar correlated_k
+Correlated K fof the gas saved in
+.Xr sck 5
+format.
+The correlated K are defined per volumetric mesh node.
+This file and the tetrahedral mesh
+.Pq option Cm mesh
+must therefore be consistent with each other, i.e. the nodes must be
+listed in the same order.
+.It Cm temp= Ns Ar temperature
+Gas temperatures saved in
+.Xr rngt 5
+format.
+The temperature is defined per volumetric mesh node.
+This file and the tetrahedral mesh
+.Pq option Cm mesh
+must therefore be consistent with each other, i.e. the nodes must be
+listed in the same order.
+.El
+.\""""""""""""""""""""""""""""""""""""""
+.It Fl h
+Display short help and exit.
+.\""""""""""""""""""""""""""""""""""""""
+.It Fl i Ar storage
+Acceleration structures are not built from scratch, but loaded from the
+.Ar storage
+file.
+.\""""""""""""""""""""""""""""""""""""""
+.It Fl N
+Precalculate tetrahedron normals.
+This speeds up execution performance for applications that search for the
+tetrahedron to which a position belongs.
+In return, the memory space used to store normals increases the memory
+footprint.
+.\""""""""""""""""""""""""""""""""""""""
+.It Fl n Ar name
+Atmosphere name.
+Default is
+.Dq atmosphere .
+.\""""""""""""""""""""""""""""""""""""""
+.It Fl o Ar storage
+Offload acceleration structures to the
+.Ar storage
+file.
+.\""""""""""""""""""""""""""""""""""""""
+.It Fl s Ar nu0 , Ns Ar nu1
+Spectral range to consider
+.Pq in nanometers .
+Default is visible spectrum, i.e., [380, 780] nm.
+.\""""""""""""""""""""""""""""""""""""""
+.It Fl T Ar optical_thickness
+Optical thickness criteria for the construction of acceleration structures.
+Default is 1.
+.\""""""""""""""""""""""""""""""""""""""
+.It Fl t Ar thread_count
+Advice on the number of threads to use to build acceleration structures.
+Default assumes as many threads as processor cores.
+.\""""""""""""""""""""""""""""""""""""""
+.It Fl V Ar definition
+Advice on the definition of the acceleration structures along the 3 axis.
+Default is 512.
+.\""""""""""""""""""""""""""""""""""""""
+.It Fl v
+Make
+.Nm
+Verbose.
+.El
+.\""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.Sh EXIT STATUS
+.Ex -std
+.\""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.Sh EXAMPLES
+A
+.Nm
+command line can be lengthy due to the options required to describe the
+atmopshere.
+For editing purposes, the following command line spans multiple lines using the
+backslash character
+.Pq \e .
+While there's nothing original about this practice, we'd like to
+emphasize the importance of spaces or their absence before the backslash
+character, particularly for options defining aerosols
+.Pq option Fl a :
+their argument must be a single character string with no spaces other
+than those that may be required for file names.
+.Bd -literal -offset Ds
+rnatm -v -c \\
+ -g mesh=gas.smsh:ck=gas.sck:temp=gas.rngt \\
+ -a name=clouds\\
+:mesh=clouds_tetrahedra.smsh\\
+:radprop=clouds_properties.sars\\
+:phasefn=clouds_phase_functions.rnsf\\
+:phaseids=clouds_phase_function_ids.rnpfi \\
+ -a name=haze\\
+:mesh=haze_tetrahedra.smsh\\
+:radprop=haze_properties.sars\\
+:phasefn=haze_phase_functions.rnsf\\
+:phaseids=haze_phase_function_ids.rnpfi \\
+ -N \\
+ -T 10 \\
+ -V 1024
+ -o storage.bin
+.Ed
+.Pp
+The above command line runs
+.Nm
+in a verbose way
+.Pq option Fl v
+for a thorough verification of the input data
+.Pq option Fl c .
+The gas of the planetary atmosphere
+.Pq option Fl g
+is described by the tetrahedral mesh recorded in the
+.Pa gas.smsh
+file, while its spectral data and temperature are given by the files
+.Pa gas.sck
+and
+.Pa gas.rngt ,
+respectively.
+.Pp
+Two aerosols complete the planetary atmosphere
+.Pq option Fl a :
+one for
+.Ar clouds
+and one for
+.Ar haze .
+Their respective meshes are stored in the
+.Pa clouds_tetrahedra.smsh No and Pa haze_tetrahedra.smsh
+files while their radiative properties are given by the
+.Pa clouds_properties.sars No and Pa haze_properties.sars
+files.
+Finally, their phase functions are described by a set of 2 files: the
+.Pa clouds_phase_functions.rnsf No and Pa haze_phase_functions.rnsf
+files which list the aerosol phase functions,
+and the
+.Pa clouds_phase_function_ids.rnpfi No and Pa haze_phase_function_ids.rnpfi
+files which reference them by volumetric mesh node.
+.Pp
+The normals of the tetrahedral meshes of the gas and aerosols are
+precalculated
+once and for all
+.Pq option Fl N .
+The definition of acceleration structures
+cannot exceed
+.Ar 1024^3
+.Pq option Fl V
+and its voxels can be merged until their optical thickness
+is greater than
+.Ar 10
+.Pq option Fl T .
+These structures are finally stored in
+.Pa storage.bin
+.Pq option Fl o .
+.\""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.Sh SEE ALSO
+.Xr htrdr-planets 1 ,
+.Xr rnpfi 5 ,
+.Xr rnsf 5 ,
+.Xr rnsl 5 ,
+.Xr sars 5 ,
+.Xr sck 5 ,
+.Xr smsh 5
+.\""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.Sh HISTORY
+.Nm
+has been developed as part of
+.Ql ANR-21-CE49-0020
+RaD-net project.
diff --git a/rngt.5 b/doc/rngt.5
diff --git a/rnpfi.5 b/doc/rnpfi.5
diff --git a/src/rnatm_main.c b/src/rnatm_main.c
@@ -0,0 +1,424 @@
+/* Copyright (C) 2022, 2023 Centre National de la Recherche Scientifique
+ * Copyright (C) 2022, 2023 Institut Pierre-Simon Laplace
+ * Copyright (C) 2022, 2023 Institut de Physique du Globe de Paris
+ * Copyright (C) 2022, 2023 |Méso|Star> (contact@meso-star.com)
+ * Copyright (C) 2022, 2023 Observatoire de Paris
+ * Copyright (C) 2022, 2023 Université de Reims Champagne-Ardenne
+ * Copyright (C) 2022, 2023 Université de Versaille Saint-Quentin
+ * Copyright (C) 2022, 2023 Université Paul Sabatier
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+#define _POSIX_C_SOURCE 200809L /* strdup, strtok_r */
+
+#include "rnatm.h"
+
+#include <rsys/cstr.h>
+#include <rsys/mem_allocator.h>
+#include <rsys/rsys.h>
+#include <rsys/stretchy_array.h>
+
+#include <getopt.h>
+#include <string.h>
+
+struct args {
+ struct rnatm_create_args rnatm;
+ const char* vtk_filename;
+ int check;
+ int quit;
+};
+#define ARGS_DEFAULT__ { RNATM_CREATE_ARGS_DEFAULT__, NULL, 0, 0 }
+static const struct args ARGS_DEFAULT = ARGS_DEFAULT__;
+
+/*******************************************************************************
+ * Helper functions
+ ******************************************************************************/
+static void
+usage(FILE* stream)
+{
+ ASSERT(stream);
+ fprintf(stream,
+"usage: rnatm [-hNv] [-a aerosol_opt[:aerosol_opt ...]] [-c] [-d octrees]\n"
+" [-i storage] [-n name] [-o storage] [-s nu0,nu1]\n"
+" [-T optical_thickness] [-t thread_count] [-V definition]\n"
+" -g gas_opt[:gas_opt ...]\n");
+}
+
+static res_T
+parse_gas_parameters(const char* str, void* ptr)
+{
+ enum { MESH, CK, TEMP } iparam;
+ char buf[BUFSIZ];
+ struct args* args = ptr;
+ char* key;
+ char* val;
+ char* tk_ctx;
+ res_T res = RES_OK;
+ ASSERT(args && str);
+
+ if(strlen(str) >= sizeof(buf) -1/*NULL char*/) {
+ fprintf(stderr, "Could not duplicate the gas parameter `%s'\n", str);
+ res = RES_MEM_ERR;
+ goto error;
+ }
+ strncpy(buf, str, sizeof(buf));
+
+ key = strtok_r(buf, "=", &tk_ctx);
+ val = strtok_r(NULL, "", &tk_ctx);
+
+ if(!strcmp(key, "mesh")) iparam = MESH;
+ else if(!strcmp(key, "ck")) iparam = CK;
+ else if(!strcmp(key, "temp")) iparam = TEMP;
+ else {
+ fprintf(stderr, "Invalid gas parameter `%s'\n", key);
+ res = RES_BAD_ARG;
+ goto error;
+ }
+
+ if(!val) {
+ fprintf(stderr, "Invalid null value for gas parameter `%s'\n", key);
+ res = RES_BAD_ARG;
+ goto error;
+ }
+
+ switch(iparam) {
+ case MESH:
+ args->rnatm.gas.smsh_filename = strdup(val);
+ if(!args->rnatm.gas.smsh_filename) res = RES_MEM_ERR;
+ break;
+ case CK:
+ args->rnatm.gas.sck_filename = strdup(val);
+ if(!args->rnatm.gas.sck_filename) res = RES_MEM_ERR;
+ break;
+ case TEMP:
+ args->rnatm.gas.temperatures_filename = strdup(val);
+ if(!args->rnatm.gas.temperatures_filename) res = RES_MEM_ERR;
+ break;
+ default: FATAL("Unreachable code\n"); break;
+ }
+ if(res != RES_OK) {
+ fprintf(stderr, "Unable to parse the gas parameter `%s' -- %s\n",
+ str, res_to_cstr(res));
+ goto error;
+ }
+
+exit:
+ return res;
+error:
+ goto exit;
+}
+
+static res_T
+parse_aerosol_parameters(const char* str, void* ptr)
+{
+ enum { MESH, NAME, RADPROP, PHASEFN, PHASEIDS } iparam;
+ struct rnatm_aerosol_args* aerosol = NULL;
+ char buf[BUFSIZ];
+ struct args* args = ptr;
+ char* key;
+ char* val;
+ char* tk_ctx;
+ res_T res = RES_OK;
+ ASSERT(args && str);
+
+ if(strlen(str) >= sizeof(buf) -1/*NULL char*/) {
+ fprintf(stderr, "Could not duplicate the aerosol parameter `%s'\n", str);
+ res = RES_MEM_ERR;
+ goto error;
+ }
+ strncpy(buf, str, sizeof(buf));
+
+ key = strtok_r(buf, "=", &tk_ctx);
+ val = strtok_r(NULL, "", &tk_ctx);
+
+ if(!strcmp(key, "mesh")) iparam = MESH;
+ else if(!strcmp(key, "name")) iparam = NAME;
+ else if(!strcmp(key, "radprop")) iparam = RADPROP;
+ else if(!strcmp(key, "phasefn")) iparam = PHASEFN;
+ else if(!strcmp(key, "phaseids")) iparam = PHASEIDS;
+ else {
+ fprintf(stderr, "Invalid aerosol parameter `%s'\n", key);
+ res = RES_BAD_ARG;
+ goto error;
+ }
+
+ if(!val) {
+ fprintf(stderr, "Invalid null value for aerosol parameter `%s'\n", key);
+ res = RES_BAD_ARG;
+ goto error;
+ }
+
+ ASSERT(args->rnatm.naerosols);
+ aerosol = args->rnatm.aerosols + (args->rnatm.naerosols - 1);
+
+ switch(iparam) {
+ case MESH:
+ aerosol->smsh_filename = strdup(val);
+ if(!aerosol->smsh_filename) res = RES_MEM_ERR;
+ break;
+ case NAME:
+ aerosol->name = strdup(val);
+ if(!aerosol->name) res = RES_MEM_ERR;
+ break;
+ case RADPROP:
+ aerosol->sars_filename = strdup(val);
+ if(!aerosol->sars_filename) res = RES_MEM_ERR;
+ break;
+ case PHASEFN:
+ aerosol->phase_fn_lst_filename = strdup(val);
+ if(!aerosol->phase_fn_lst_filename) res = RES_MEM_ERR;
+ break;
+ case PHASEIDS:
+ aerosol->phase_fn_ids_filename = strdup(val);
+ if(!aerosol->phase_fn_ids_filename) res = RES_MEM_ERR;
+ break;
+ default: FATAL("Unreachable code\n"); break;
+ }
+ if(res != RES_OK) {
+ fprintf(stderr, "Unable to parse the aerosol parameter `%s' -- %s\n",
+ str, res_to_cstr(res));
+ goto error;
+ }
+
+exit:
+ return res;
+error:
+ goto exit;
+}
+
+static res_T
+parse_spectral_range(struct args* args, char* str)
+{
+ size_t len = 0;
+ res_T res = RES_OK;
+ ASSERT(args && str);
+
+ res = cstr_to_list_double(str, ',', args->rnatm.spectral_range, &len, 2);
+ if(res == RES_OK && len != 2) res = RES_BAD_ARG;
+ if(res != RES_OK) goto error;
+
+ if(args->rnatm.spectral_range[0] < 0
+ || args->rnatm.spectral_range[1] < 0
+ || args->rnatm.spectral_range[0] > args->rnatm.spectral_range[1])
+ goto error;
+
+exit:
+ return res;
+error:
+ goto exit;
+}
+
+static void
+args_release(struct args* args)
+{
+ size_t i;
+ ASSERT(args);
+ if(args->rnatm.gas.smsh_filename) free(args->rnatm.gas.smsh_filename);
+ if(args->rnatm.gas.sck_filename) free(args->rnatm.gas.sck_filename);
+ if(args->rnatm.gas.temperatures_filename)
+ free(args->rnatm.gas.temperatures_filename);
+ if(args->rnatm.octrees_storage) CHK(fclose(args->rnatm.octrees_storage) == 0);
+
+ FOR_EACH(i, 0, args->rnatm.naerosols) {
+ struct rnatm_aerosol_args* aerosol = args->rnatm.aerosols + i;
+ if(aerosol->name) free(aerosol->name);
+ if(aerosol->smsh_filename) free(aerosol->smsh_filename);
+ if(aerosol->sars_filename) free(aerosol->sars_filename);
+ if(aerosol->phase_fn_ids_filename) free(aerosol->phase_fn_ids_filename);
+ if(aerosol->phase_fn_lst_filename) free(aerosol->phase_fn_lst_filename);
+ }
+ sa_release(args->rnatm.aerosols);
+ *args = ARGS_DEFAULT;
+}
+
+static res_T
+args_init(struct args* args, int argc, char** argv)
+{
+ const char* storage_filename = NULL;
+ size_t i = 0;
+ res_T res = RES_OK;
+ int opt;
+ ASSERT(args && argc && argv);
+
+ *args = ARGS_DEFAULT;
+
+ while((opt = getopt(argc, argv, "a:cd:g:hi:Nn:o:s:T:t:V:v")) != -1) {
+ switch(opt) {
+ case 'a':
+ (void)sa_add(args->rnatm.aerosols, 1);
+ args->rnatm.aerosols[args->rnatm.naerosols] = RNATM_AEROSOL_ARGS_NULL;
+ args->rnatm.naerosols += 1;
+ res = cstr_parse_list(optarg, ':', parse_aerosol_parameters, args);
+ break;
+ case 'c': args->check = 1; break;
+ case 'd': args->vtk_filename = optarg; break;
+ case 'g':
+ res = cstr_parse_list(optarg, ':', parse_gas_parameters, args);
+ break;
+ case 'h':
+ usage(stdout);
+ args_release(args);
+ args->quit = 1;
+ goto exit;
+ case 'N': args->rnatm.precompute_normals = 1; break;
+ case 'n': args->rnatm.name = optarg; break;
+ case 'o':
+ args->rnatm.load_octrees_from_storage = 0;
+ storage_filename = optarg;
+ break;
+ case 'i':
+ args->rnatm.load_octrees_from_storage = 1;
+ storage_filename = optarg;
+ break;
+ case 's':
+ res = parse_spectral_range(args, optarg);
+ break;
+ case 'T':
+ res = cstr_to_double(optarg, &args->rnatm.optical_thickness);
+ if(res != RES_OK && args->rnatm.optical_thickness<=0) res = RES_BAD_ARG;
+ break;
+ case 't':
+ res = cstr_to_uint(optarg, &args->rnatm.nthreads);
+ if(res == RES_OK && !args->rnatm.nthreads) res = RES_BAD_ARG;
+ break;
+ case 'V':
+ res = cstr_to_uint(optarg, &args->rnatm.grid_definition_hint);
+ if(res == RES_OK && !args->rnatm.grid_definition_hint) res = RES_BAD_ARG;
+ break;
+ case 'v': args->rnatm.verbose = 1; break;
+ default: res = RES_BAD_ARG; break;
+ }
+ if(res != RES_OK) {
+ if(optarg) {
+ fprintf(stderr, "%s: invalid option args `%s' -- `%c'\n",
+ argv[0], optarg, opt);
+ }
+ goto error;
+ }
+ }
+
+ if(storage_filename) {
+ const char* mode = args->rnatm.load_octrees_from_storage ? "r" : "w+";
+ args->rnatm.octrees_storage = fopen(storage_filename, mode);
+ if(!args->rnatm.octrees_storage) {
+ fprintf(stderr, "Unable to open octree storage file %s\n",
+ storage_filename);
+ res = RES_IO_ERR;
+ goto error;
+ }
+ }
+
+ /* Check the required options */
+ if(!args->rnatm.gas.smsh_filename
+ || !args->rnatm.gas.sck_filename
+ || !args->rnatm.gas.temperatures_filename) {
+ fprintf(stderr, "Incomplete gas definition -- option `-g'\n");
+ res = RES_BAD_ARG;
+ goto error;
+ }
+
+ FOR_EACH(i, 0, args->rnatm.naerosols) {
+ struct rnatm_aerosol_args* aerosol = args->rnatm.aerosols + i;
+
+ if(!aerosol->smsh_filename
+ || !aerosol->sars_filename
+ || !aerosol->phase_fn_ids_filename
+ || !aerosol->phase_fn_lst_filename) {
+ fprintf(stderr, "Incomplete %lu^th aerosol definition -- option `-a'\n",
+ (unsigned long)i);
+ res = RES_BAD_ARG;
+ goto error;
+ }
+ }
+
+exit:
+ return res;
+error:
+ usage(stderr);
+ args_release(args);
+ goto exit;
+}
+
+static res_T
+write_vtk_octrees(struct rnatm* atm, const char* filename)
+{
+ size_t octrees_range[2];
+ FILE* fp = NULL;
+ res_T res = RES_OK;
+ ASSERT(atm && filename);
+
+ if(!strcmp(filename, "-")) {
+ fp = stdout;
+ } else {
+ fp = fopen(filename, "w");
+ if(!fp) {
+ fprintf(stderr, "Could not open `%s' -- %s\n", filename, strerror(errno));
+ res = RES_IO_ERR;
+ goto error;
+ }
+ }
+
+ octrees_range[0] = 0;
+ octrees_range[1] = rnatm_get_spectral_items_count(atm) - 1;
+
+ res = rnatm_write_vtk_octrees(atm, octrees_range, fp);
+ if(res != RES_OK) goto error;
+
+exit:
+ if(fp != stdout) CHK(fclose(fp) == 0);
+ return res;
+error:
+ goto exit;
+}
+
+/*******************************************************************************
+ * Main function
+ ******************************************************************************/
+int
+main(int argc, char** argv)
+{
+ struct args args = ARGS_DEFAULT;
+ struct rnatm* atm = NULL;
+ res_T res = RES_OK;
+ int err = 0;
+
+ res = args_init(&args, argc, argv);
+ if(res != RES_OK) goto error;
+
+ res = rnatm_create(&args.rnatm, &atm);
+ if(res != RES_OK) goto error;
+
+ if(args.check) {
+ res = rnatm_validate(atm);
+ if(res != RES_OK) goto error;
+ }
+
+ if(args.vtk_filename) {
+ res = write_vtk_octrees(atm, args.vtk_filename);
+ if(res != RES_OK) goto error;
+ }
+
+exit:
+ args_release(&args);
+ if(atm) RNATM(ref_put(atm));
+ if(mem_allocated_size() != 0) {
+ fprintf(stderr, "Memory leaks: %lu bytes\n",
+ (unsigned long)mem_allocated_size());
+ err = -1;
+ }
+ return err;
+error:
+ err = -1;
+ goto exit;
+}
diff --git a/src/test_rnatm.c b/src/test_rnatm.c
@@ -1,485 +0,0 @@
-/* Copyright (C) 2022, 2023 Centre National de la Recherche Scientifique
- * Copyright (C) 2022, 2023 Institut Pierre-Simon Laplace
- * Copyright (C) 2022, 2023 Institut de Physique du Globe de Paris
- * Copyright (C) 2022, 2023 |Méso|Star> (contact@meso-star.com)
- * Copyright (C) 2022, 2023 Observatoire de Paris
- * Copyright (C) 2022, 2023 Université de Reims Champagne-Ardenne
- * Copyright (C) 2022, 2023 Université de Versaille Saint-Quentin
- * Copyright (C) 2022, 2023 Université Paul Sabatier
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>. */
-
-#define _POSIX_C_SOURCE 200809L /* strdup, strtok_r */
-
-#include "rnatm.h"
-
-#include <rsys/cstr.h>
-#include <rsys/mem_allocator.h>
-#include <rsys/rsys.h>
-#include <rsys/stretchy_array.h>
-
-#include <getopt.h>
-#include <string.h>
-
-struct args {
- struct rnatm_create_args rnatm;
- const char* vtk_filename;
- int check;
- int quit;
-};
-#define ARGS_DEFAULT__ { RNATM_CREATE_ARGS_DEFAULT__, NULL, 0, 0 }
-static const struct args ARGS_DEFAULT = ARGS_DEFAULT__;
-
-/*******************************************************************************
- * Helper functions
- ******************************************************************************/
-static void
-print_help(const char* cmd)
-{
- ASSERT(cmd);
- printf(
-"Usage: %s -g gas\n"
-"Test the Rad-Net ATMosphere library\n\n",
- cmd);
- printf(
-" -a aerosol atmospheric aerosol. Use this option as many times as\n"
-" there are aerosols to declare. An aerosol is defined\n"
-" by the following parameters, each parameter is\n"
-" separated from the previous one by a colon (:)\n\n");
- printf(
-" mesh=path aerosol mesh (smsh(5))\n"
-" name=string aerosol name\n"
-" radprop=path radiative properties (sars(5))\n"
-" phasefn=path list of phase functions (rnsl(5))\n"
-" phaseids=path phase function id by node (rnpfi(5))\n\n");
- printf(
-" -c check data\n");
- printf(
-" -d file write the builded octrees to file according to the VTK\n"
-" file format. The octrees are written to standard ouput\n"
-" if the file is a dash (-). To split the resulting file\n"
-" into n VTK files, each storing an octree, one can use\n"
-" the csplit command. For example with n = 4:\n\n");
- printf(
-" csplit -f octree -k file %%^#\\ vtk%% /^#\\ vtk/ {2}\n\n");
- printf(
-" -g gas atmospheric gas mixture. This mixture is defined by\n"
-" the following parameters, each parameter is separated\n"
-" from the previous one by a colon (:)\n\n");
- printf(
-" mesh=path gas mesh (smsh(5))\n"
-" ck=path correlated-K of the mixture (sck(5))\n"
-" temp=path temperatures (rngt(5))\n\n");
- printf(
-" -h display this help and exit\n");
- printf(
-" -i file octrees are loaded from file\n");
- printf(
-" -N precompute_normals the tetrahedra normals\n");
- printf(
-" -n atmosphere name. Default is `%s'\n",
- ARGS_DEFAULT.rnatm.name);
- printf(
-" -o file offload octrees to file\n");
- printf(
-" -s nu0,nu1 spectral range to consider (in nm).\n"
-" Default is visible spectrum, i.e [%g, %g] nm\n",
- ARGS_DEFAULT.rnatm.spectral_range[0],
- ARGS_DEFAULT.rnatm.spectral_range[1]);
- printf(
-" -T threshold optical thickness criteria for octree building.\n"
-" Default is %g\n",
- ARGS_DEFAULT.rnatm.optical_thickness);
- printf(
-" -t nthreads hint on the number of threads. Default assumes\n"
-" as many threads as CPU cores\n");
- printf(
-" -V definition advice on the definiton of the acceleration\n"
-" structure along the 3 axes. Default is %u\n",
- ARGS_DEFAULT.rnatm.grid_definition_hint);
- printf(
-" -v make the program verbose\n");
- printf("\n");
- printf(
-"This is free software released under the GNU GPL license, version 3 or\n"
-"later. You are free to change or redistribute it under certain\n"
-"conditions <http://gnu.org.licenses/gpl.html>\n");
-}
-
-static res_T
-parse_gas_parameters(const char* str, void* ptr)
-{
- enum { MESH, CK, TEMP } iparam;
- char buf[BUFSIZ];
- struct args* args = ptr;
- char* key;
- char* val;
- char* tk_ctx;
- res_T res = RES_OK;
- ASSERT(args && str);
-
- if(strlen(str) >= sizeof(buf) -1/*NULL char*/) {
- fprintf(stderr, "Could not duplicate the gas parameter `%s'\n", str);
- res = RES_MEM_ERR;
- goto error;
- }
- strncpy(buf, str, sizeof(buf));
-
- key = strtok_r(buf, "=", &tk_ctx);
- val = strtok_r(NULL, "", &tk_ctx);
-
- if(!strcmp(key, "mesh")) iparam = MESH;
- else if(!strcmp(key, "ck")) iparam = CK;
- else if(!strcmp(key, "temp")) iparam = TEMP;
- else {
- fprintf(stderr, "Invalid gas parameter `%s'\n", key);
- res = RES_BAD_ARG;
- goto error;
- }
-
- if(!val) {
- fprintf(stderr, "Invalid null value for gas parameter `%s'\n", key);
- res = RES_BAD_ARG;
- goto error;
- }
-
- switch(iparam) {
- case MESH:
- args->rnatm.gas.smsh_filename = strdup(val);
- if(!args->rnatm.gas.smsh_filename) res = RES_MEM_ERR;
- break;
- case CK:
- args->rnatm.gas.sck_filename = strdup(val);
- if(!args->rnatm.gas.sck_filename) res = RES_MEM_ERR;
- break;
- case TEMP:
- args->rnatm.gas.temperatures_filename = strdup(val);
- if(!args->rnatm.gas.temperatures_filename) res = RES_MEM_ERR;
- break;
- default: FATAL("Unreachable code\n"); break;
- }
- if(res != RES_OK) {
- fprintf(stderr, "Unable to parse the gas parameter `%s' -- %s\n",
- str, res_to_cstr(res));
- goto error;
- }
-
-exit:
- return res;
-error:
- goto exit;
-}
-
-static res_T
-parse_aerosol_parameters(const char* str, void* ptr)
-{
- enum { MESH, NAME, RADPROP, PHASEFN, PHASEIDS } iparam;
- struct rnatm_aerosol_args* aerosol = NULL;
- char buf[BUFSIZ];
- struct args* args = ptr;
- char* key;
- char* val;
- char* tk_ctx;
- res_T res = RES_OK;
- ASSERT(args && str);
-
- if(strlen(str) >= sizeof(buf) -1/*NULL char*/) {
- fprintf(stderr, "Could not duplicate the aerosol parameter `%s'\n", str);
- res = RES_MEM_ERR;
- goto error;
- }
- strncpy(buf, str, sizeof(buf));
-
- key = strtok_r(buf, "=", &tk_ctx);
- val = strtok_r(NULL, "", &tk_ctx);
-
- if(!strcmp(key, "mesh")) iparam = MESH;
- else if(!strcmp(key, "name")) iparam = NAME;
- else if(!strcmp(key, "radprop")) iparam = RADPROP;
- else if(!strcmp(key, "phasefn")) iparam = PHASEFN;
- else if(!strcmp(key, "phaseids")) iparam = PHASEIDS;
- else {
- fprintf(stderr, "Invalid aerosol parameter `%s'\n", key);
- res = RES_BAD_ARG;
- goto error;
- }
-
- if(!val) {
- fprintf(stderr, "Invalid null value for aerosol parameter `%s'\n", key);
- res = RES_BAD_ARG;
- goto error;
- }
-
- ASSERT(args->rnatm.naerosols);
- aerosol = args->rnatm.aerosols + (args->rnatm.naerosols - 1);
-
- switch(iparam) {
- case MESH:
- aerosol->smsh_filename = strdup(val);
- if(!aerosol->smsh_filename) res = RES_MEM_ERR;
- break;
- case NAME:
- aerosol->name = strdup(val);
- if(!aerosol->name) res = RES_MEM_ERR;
- break;
- case RADPROP:
- aerosol->sars_filename = strdup(val);
- if(!aerosol->sars_filename) res = RES_MEM_ERR;
- break;
- case PHASEFN:
- aerosol->phase_fn_lst_filename = strdup(val);
- if(!aerosol->phase_fn_lst_filename) res = RES_MEM_ERR;
- break;
- case PHASEIDS:
- aerosol->phase_fn_ids_filename = strdup(val);
- if(!aerosol->phase_fn_ids_filename) res = RES_MEM_ERR;
- break;
- default: FATAL("Unreachable code\n"); break;
- }
- if(res != RES_OK) {
- fprintf(stderr, "Unable to parse the aerosol parameter `%s' -- %s\n",
- str, res_to_cstr(res));
- goto error;
- }
-
-exit:
- return res;
-error:
- goto exit;
-}
-
-static res_T
-parse_spectral_range(struct args* args, char* str)
-{
- size_t len = 0;
- res_T res = RES_OK;
- ASSERT(args && str);
-
- res = cstr_to_list_double(str, ',', args->rnatm.spectral_range, &len, 2);
- if(res == RES_OK && len != 2) res = RES_BAD_ARG;
- if(res != RES_OK) goto error;
-
- if(args->rnatm.spectral_range[0] < 0
- || args->rnatm.spectral_range[1] < 0
- || args->rnatm.spectral_range[0] > args->rnatm.spectral_range[1])
- goto error;
-
-exit:
- return res;
-error:
- goto exit;
-}
-
-static void
-args_release(struct args* args)
-{
- size_t i;
- ASSERT(args);
- if(args->rnatm.gas.smsh_filename) free(args->rnatm.gas.smsh_filename);
- if(args->rnatm.gas.sck_filename) free(args->rnatm.gas.sck_filename);
- if(args->rnatm.gas.temperatures_filename)
- free(args->rnatm.gas.temperatures_filename);
- if(args->rnatm.octrees_storage) CHK(fclose(args->rnatm.octrees_storage) == 0);
-
- FOR_EACH(i, 0, args->rnatm.naerosols) {
- struct rnatm_aerosol_args* aerosol = args->rnatm.aerosols + i;
- if(aerosol->name) free(aerosol->name);
- if(aerosol->smsh_filename) free(aerosol->smsh_filename);
- if(aerosol->sars_filename) free(aerosol->sars_filename);
- if(aerosol->phase_fn_ids_filename) free(aerosol->phase_fn_ids_filename);
- if(aerosol->phase_fn_lst_filename) free(aerosol->phase_fn_lst_filename);
- }
- sa_release(args->rnatm.aerosols);
- *args = ARGS_DEFAULT;
-}
-
-static res_T
-args_init(struct args* args, int argc, char** argv)
-{
- const char* storage_filename = NULL;
- size_t i = 0;
- res_T res = RES_OK;
- int opt;
- ASSERT(args && argc && argv);
-
- *args = ARGS_DEFAULT;
-
- while((opt = getopt(argc, argv, "a:cd:g:hi:Nn:o:s:T:t:V:v")) != -1) {
- switch(opt) {
- case 'a':
- (void)sa_add(args->rnatm.aerosols, 1);
- args->rnatm.aerosols[args->rnatm.naerosols] = RNATM_AEROSOL_ARGS_NULL;
- args->rnatm.naerosols += 1;
- res = cstr_parse_list(optarg, ':', parse_aerosol_parameters, args);
- break;
- case 'c': args->check = 1; break;
- case 'd': args->vtk_filename = optarg; break;
- case 'g':
- res = cstr_parse_list(optarg, ':', parse_gas_parameters, args);
- break;
- case 'h':
- print_help(argv[0]);
- args_release(args);
- args->quit = 1;
- goto exit;
- case 'N': args->rnatm.precompute_normals = 1; break;
- case 'n': args->rnatm.name = optarg; break;
- case 'o':
- args->rnatm.load_octrees_from_storage = 0;
- storage_filename = optarg;
- break;
- case 'i':
- args->rnatm.load_octrees_from_storage = 1;
- storage_filename = optarg;
- break;
- case 's':
- res = parse_spectral_range(args, optarg);
- break;
- case 'T':
- res = cstr_to_double(optarg, &args->rnatm.optical_thickness);
- if(res != RES_OK && args->rnatm.optical_thickness<=0) res = RES_BAD_ARG;
- break;
- case 't':
- res = cstr_to_uint(optarg, &args->rnatm.nthreads);
- if(res == RES_OK && !args->rnatm.nthreads) res = RES_BAD_ARG;
- break;
- case 'V':
- res = cstr_to_uint(optarg, &args->rnatm.grid_definition_hint);
- if(res == RES_OK && !args->rnatm.grid_definition_hint) res = RES_BAD_ARG;
- break;
- case 'v': args->rnatm.verbose = 1; break;
- default: res = RES_BAD_ARG; break;
- }
- if(res != RES_OK) {
- if(optarg) {
- fprintf(stderr, "%s: invalid option args `%s' -- `%c'\n",
- argv[0], optarg, opt);
- }
- goto error;
- }
- }
-
- if(storage_filename) {
- const char* mode = args->rnatm.load_octrees_from_storage ? "r" : "w+";
- args->rnatm.octrees_storage = fopen(storage_filename, mode);
- if(!args->rnatm.octrees_storage) {
- fprintf(stderr, "Unable to open octree storage file %s\n",
- storage_filename);
- res = RES_IO_ERR;
- goto error;
- }
- }
-
- /* Check the required options */
- if(!args->rnatm.gas.smsh_filename
- || !args->rnatm.gas.sck_filename
- || !args->rnatm.gas.temperatures_filename) {
- fprintf(stderr, "Incomplete gas definition -- option `-g'\n");
- res = RES_BAD_ARG;
- goto error;
- }
-
- FOR_EACH(i, 0, args->rnatm.naerosols) {
- struct rnatm_aerosol_args* aerosol = args->rnatm.aerosols + i;
-
- if(!aerosol->smsh_filename
- || !aerosol->sars_filename
- || !aerosol->phase_fn_ids_filename
- || !aerosol->phase_fn_lst_filename) {
- fprintf(stderr, "Incomplete %lu^th aerosol definition -- option `-a'\n",
- (unsigned long)i);
- res = RES_BAD_ARG;
- goto error;
- }
- }
-
-exit:
- return res;
-error:
- args_release(args);
- goto exit;
-}
-
-static res_T
-write_vtk_octrees(struct rnatm* atm, const char* filename)
-{
- size_t octrees_range[2];
- FILE* fp = NULL;
- res_T res = RES_OK;
- ASSERT(atm && filename);
-
- if(!strcmp(filename, "-")) {
- fp = stdout;
- } else {
- fp = fopen(filename, "w");
- if(!fp) {
- fprintf(stderr, "Could not open `%s' -- %s\n", filename, strerror(errno));
- res = RES_IO_ERR;
- goto error;
- }
- }
-
- octrees_range[0] = 0;
- octrees_range[1] = rnatm_get_spectral_items_count(atm) - 1;
-
- res = rnatm_write_vtk_octrees(atm, octrees_range, fp);
- if(res != RES_OK) goto error;
-
-exit:
- if(fp != stdout) CHK(fclose(fp) == 0);
- return res;
-error:
- goto exit;
-}
-
-/*******************************************************************************
- * Main function
- ******************************************************************************/
-int
-main(int argc, char** argv)
-{
- struct args args = ARGS_DEFAULT;
- struct rnatm* atm = NULL;
- res_T res = RES_OK;
- int err = 0;
-
- res = args_init(&args, argc, argv);
- if(res != RES_OK) goto error;
-
- res = rnatm_create(&args.rnatm, &atm);
- if(res != RES_OK) goto error;
-
- if(args.check) {
- res = rnatm_validate(atm);
- if(res != RES_OK) goto error;
- }
-
- if(args.vtk_filename) {
- res = write_vtk_octrees(atm, args.vtk_filename);
- if(res != RES_OK) goto error;
- }
-
-exit:
- args_release(&args);
- if(atm) RNATM(ref_put(atm));
- if(mem_allocated_size() != 0) {
- fprintf(stderr, "Memory leaks: %lu bytes\n",
- (unsigned long)mem_allocated_size());
- err = -1;
- }
- return err;
-error:
- err = -1;
- goto exit;
-}