commit aa8047462282f848c0f09be920dfe12378540966
parent 4721e560111b01f1088c3874007eab36f7c3e8bf
Author: Vincent Forest <vincent.forest@meso-star.com>
Date: Mon, 30 Oct 2023 12:12:11 +0100
Merge branch 'release_0.1'
Diffstat:
| M | .gitignore | | | 14 | +++++++------- |
| A | Makefile | | | 151 | ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
| M | README.md | | | 51 | +++++++++++++++++++++++++++++---------------------- |
| D | cmake/CMakeLists.txt | | | 119 | ------------------------------------------------------------------------------- |
| A | config.mk | | | 77 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
| D | doc/sck.5.scd | | | 110 | ------------------------------------------------------------------------------- |
| A | make.sh | | | 72 | ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
| A | sck.5 | | | 112 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
| A | sck.pc.in | | | 11 | +++++++++++ |
| M | src/sck.c | | | 571 | ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++------------- |
| M | src/sck.h | | | 41 | +++++++++++++++++++++++++++++++++++++---- |
| M | src/sck_c.h | | | 49 | ++++++++++++++++++++++++++++++++----------------- |
| M | src/test_sck_load.c | | | 110 | +++++++++++++++++++++++++++++++++++++++++++++++++------------------------------ |
13 files changed, 1077 insertions(+), 411 deletions(-)
diff --git a/.gitignore b/.gitignore
@@ -1,12 +1,12 @@
.gitignore
-CMakeCache.txt
-CMakeFiles
-Makefile
-tmp
[Bb]uild*
*.sw[po]
-*.[ao]
-*.orig
+*.[aod]
+*.so
*~
+test*
+!test*.[ch]
+.config
+.test
tags
-
+*.pc
diff --git a/Makefile b/Makefile
@@ -0,0 +1,151 @@
+# Copyright (C) 2022, 2023 |Méso|Star> (contact@meso-star.com)
+# Copyright (C) 2020, 2021 CNRS
+#
+# 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/>.
+
+.POSIX:
+.SUFFIXES: # Clean up default inference rules
+
+include config.mk
+
+LIBNAME_STATIC = libsck.a
+LIBNAME_SHARED = libsck.so
+LIBNAME = $(LIBNAME_$(LIB_TYPE))
+
+################################################################################
+# Library building
+################################################################################
+SRC = src/sck.c src/sck_log.c
+OBJ = $(SRC:.c=.o)
+DEP = $(SRC:.c=.d)
+
+build_library: .config $(DEP)
+ @$(MAKE) -fMakefile $$(for i in $(DEP); do echo -f $${i}; done) \
+ $$(if [ -n "$(LIBNAME)" ]; then \
+ echo "$(LIBNAME)"; \
+ else \
+ echo "$(LIBNAME_SHARED)"; \
+ fi)
+
+$(DEP) $(OBJ): config.mk
+
+$(LIBNAME_SHARED): $(OBJ)
+ $(CC) $(CFLAGS_SO) $(RSYS_CFLAGS) -o $@ $(OBJ) $(LDFLAGS_SO) $(RSYS_LIBS) -lm
+
+$(LIBNAME_STATIC): libsck.o
+ $(AR) -rc $@ $?
+ $(RANLIB) $@
+
+libsck.o: $(OBJ)
+ $(LD) -r $(OBJ) -o $@
+ $(OBJCOPY) $(OCPFLAGS) $@
+
+.config: config.mk
+ @if ! $(PKG_CONFIG) --atleast-version $(RSYS_VERSION) rsys; then \
+ echo "rsys $(RSYS_VERSION) not found" >&2; exit 1; fi
+ @echo "config done" > $@
+
+.SUFFIXES: .c .d .o
+.c.d:
+ @$(CC) $(CFLAGS_SO) $(RSYS_CFLAGS) -MM -MT "$(@:.d=.o) $@" $< -MF $@
+
+.c.o:
+ $(CC) $(CFLAGS_SO) $(RSYS_CFLAGS) -DSCK_SHARED_BUILD -c $< -o $@
+
+################################################################################
+# Installation
+################################################################################
+pkg:
+ sed -e 's#@PREFIX@#$(PREFIX)#g'\
+ -e 's#@VERSION@#$(VERSION)#g'\
+ -e 's#@RSYS_VERSION@#$(RSYS_VERSION)#g'\
+ sck.pc.in > sck.pc
+
+sck-local.pc: sck.pc.in
+ sed -e '1d'\
+ -e 's#^includedir=.*#includedir=./src/#'\
+ -e 's#^libdir=.*#libdir=./#'\
+ -e 's#@VERSION@#$(VERSION)#g'\
+ -e 's#@RSYS_VERSION@#$(RSYS_VERSION)#g'\
+ sck.pc.in > $@
+
+install: build_library pkg
+ @$(SHELL) make.sh install "$(DESTDIR)$(PREFIX)/lib" $(LIBNAME)
+ @$(SHELL) make.sh install "$(DESTDIR)$(PREFIX)/lib/pkgconfig" sck.pc
+ @$(SHELL) make.sh install "$(DESTDIR)$(PREFIX)/include/star" src/sck.h
+ @$(SHELL) make.sh install "$(DESTDIR)$(PREFIX)/share/doc/star-ck" COPYING README.md
+ @$(SHELL) make.sh install "$(DESTDIR)$(PREFIX)/share/man/man5" sck.5
+
+uninstall:
+ rm -f "$(DESTDIR)$(PREFIX)/lib/$(LIBNAME)"
+ rm -f "$(DESTDIR)$(PREFIX)/lib/pkgconfig/sck.pc"
+ rm -f "$(DESTDIR)$(PREFIX)/share/doc/star-ck/COPYING"
+ rm -f "$(DESTDIR)$(PREFIX)/share/doc/star-ck/README.md"
+ rm -f "$(DESTDIR)$(PREFIX)/include/star/sck.h"
+ rm -f "$(DESTDIR)$(PREFIX)/share/man/man5/sck.5"
+
+################################################################################
+# Miscellaneous targets
+################################################################################
+all: build_library build_tests
+
+clean: clean_test
+ rm -f $(OBJ) $(TEST_OBJ) $(LIBNAME)
+ rm -f .config .test libsck.o sck.pc sck-local.pc
+
+distclean: clean
+ rm -f $(DEP) $(TEST_DEP)
+
+lint:
+ shellcheck -o all make.sh
+ mandoc -Tlint -Wall sck.5 || [ $$? -le 1 ]
+
+################################################################################
+# Tests
+################################################################################
+TEST_SRC =\
+ src/test_sck.c\
+ src/test_sck_load.c
+TEST_OBJ = $(TEST_SRC:.c=.o)
+TEST_DEP = $(TEST_SRC:.c=.d)
+
+PKG_CONFIG_LOCAL = PKG_CONFIG_PATH="./:$${PKG_CONFIG_PATH}" $(PKG_CONFIG)
+SCK_CFLAGS = $$($(PKG_CONFIG_LOCAL) $(PCFLAGS) --cflags sck-local.pc)
+SCK_LIBS = $$($(PKG_CONFIG_LOCAL) $(PCFLAGS) --libs sck-local.pc)
+
+build_tests: build_library $(TEST_DEP) .test
+ @$(MAKE) -fMakefile -f.test $$(for i in $(TEST_DEP); do echo -f"$${i}"; done) test_bin
+
+test: build_tests
+ @$(SHELL) make.sh run_test $(TEST_SRC)
+
+.test: Makefile
+ @$(SHELL) make.sh config_test $(TEST_SRC) > $@
+
+clean_test:
+ $(SHELL) make.sh clean_test $(TEST_SRC)
+ rm -f test_file.sck
+
+$(TEST_DEP): config.mk sck-local.pc
+ @$(CC) $(CFLAGS_EXE) $(SCK_CFLAGS) $(RSYS_CFLAGS) \
+ -MM -MT "$(@:.d=.o) $@" $(@:.d=.c) -MF $@
+
+$(TEST_OBJ): config.mk sck-local.pc
+ $(CC) $(CFLAGS_EXE) $(SCK_CFLAGS) $(RSYS_CFLAGS) -c $(@:.o=.c) -o $@
+
+test_sck: config.mk sck-local.pc $(LIBNAME)
+ $(CC) $(CFLAGS_EXE) -o $@ src/$@.o $(LDFLAGS_EXE) $(SCK_LIBS) $(RSYS_LIBS)
+
+test_sck_load: config.mk sck-local.pc $(LIBNAME)
+ $(CC) $(CFLAGS_EXE) -o $@ src/$@.o $(LDFLAGS_EXE) $(SCK_LIBS) $(RSYS_LIBS) -lm
diff --git a/README.md b/README.md
@@ -1,32 +1,39 @@
# Star-CorrelatedK
-This C library loads the radiative properties of a gas mixture saved wrt the
-Star-CK file format.
+This C library loads the radiative properties of a gas mixture saved in
+sck file format. See `sck.5` for the format specification.
-## How to build
+## Requirements
-This library is compatible with 64-bits POSIX systems. It relies the
-[CMake](http://www.cmake.org) and the
-[RCMake](https://gitlab.com/vaplv/rcmake/) packages to build. It also depends
-on the [RSys](https://gitlab.com/vaplv/rsys/) library. It optionally depends on
-[scdoc](https://sr.ht/~sircmpwn/scdoc/) which, if available, is used to
-generate the man page of the Star-CK file format.
+- C compiler
+- POSIX make
+- pkg-config
+- [RSys](https://gitlab.com/vaplv/rsys)
+- [mandoc](https://mandoc.bsd.lv)
-First ensure that CMake is installed on your system. Then install the RCMake
-package as well as the aforementioned prerequisites. Finally generate the
-project from the `cmake/CMakeLists.txt` file by appending to the
-`CMAKE_PREFIX_PATH` variable the install directories of its dependencies. The
-resulting project can be edited, built, tested and installed as any CMake
-project. Refer to the [CMake documentation](https://cmake.org/documentation)
-for further informations on CMake.
+## Installation
-## Copyright notice
+Edit config.mk as needed, then run:
-Copyright (C) 2022, 2023 [|Méso|Star>](https://www.meso-star.com) (<contact@meso-star.com>).
-Copyright (C) 2020, 2021 Centre National de la Recherche Scientifique (CNRS).
+ make clean install
+
+## Release notes
+
+### Version 0.1
+
+- Write the man page directly in mdoc's roff macros, instead of using
+ the intermediate scdoc source.
+- Replace CMake by Makefile as build system.
+- Update compiler and linker flags to increase the security and
+ robustness of generated binaries.
+- Provide a pkg-config file to link the library as an external
+ dependency.
## License
-Star-CK is free software released under the GPL v3+ license: GNU GPL version 3
-or later. You are welcome to redistribute it under certain conditions; refer to
-the COPYING file for details.
+Copyright (C) 2022, 2023 |Méso|Star> (contact@meso-star.com)
+Copyright (C) 2020, 2021 Centre National de la Recherche Scientifique (CNRS)
+
+Star-CK is free software released under the GPL v3+ license: GNU GPL
+version 3 or later. You are welcome to redistribute it under certain
+conditions; refer to the COPYING file for details.
diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt
@@ -1,119 +0,0 @@
-# Copyright (C) 2022, 2023 |Méso|Star> (contact@meso-star.com)
-# Copyright (C) 2020, 2021 CNRS
-#
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
-
-cmake_minimum_required(VERSION 3.1)
-project(sck C)
-enable_testing()
-
-set(SCK_SOURCE_DIR ${PROJECT_SOURCE_DIR}/../src)
-option(NO_TEST "Do not build tests" OFF)
-
-################################################################################
-# Check dependencies
-################################################################################
-find_package(RCMake 0.4 REQUIRED)
-find_package(RSys 0.13 REQUIRED)
-
-set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${RCMAKE_SOURCE_DIR})
-include(rcmake)
-include(rcmake_runtime)
-
-include_directories(${RSys_INCLUDE_DIR})
-
-################################################################################
-# Configure and define targets
-################################################################################
-set(VERSION_MAJOR 0)
-set(VERSION_MINOR 0)
-set(VERSION_PATCH 0)
-set(VERSION ${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_PATCH})
-
-set(SCK_FILES_SRC
- sck.c
- sck_log.c)
-set(SCK_FILES_INC
- sck_c.h
- sck_log.h)
-set(SCK_FILES_INC_API
- sck.h)
-
-set(SCK_FILES_DOC COPYING README.md)
-
-# Prepend each file in the `SCK_FILES_<SRC|INC>' list by `SCK_SOURCE_DIR'
-rcmake_prepend_path(SCK_FILES_SRC ${SCK_SOURCE_DIR})
-rcmake_prepend_path(SCK_FILES_INC ${SCK_SOURCE_DIR})
-rcmake_prepend_path(SCK_FILES_INC_API ${SCK_SOURCE_DIR})
-rcmake_prepend_path(SCK_FILES_DOC ${PROJECT_SOURCE_DIR}/../)
-
-add_library(sck SHARED ${SCK_FILES_SRC} ${SCK_FILES_INC} ${SCK_FILES_INC_API})
-target_link_libraries(sck RSys)
-
-if(CMAKE_COMPILER_IS_GNUCC)
- target_link_libraries(sck m)
-endif()
-
-set_target_properties(sck PROPERTIES
- DEFINE_SYMBOL SCK_SHARED_BUILD
- VERSION ${VERSION}
- SOVERSION ${VERSION_MAJOR})
-
-rcmake_setup_devel(sck StarCK ${VERSION} star/sck_version.h)
-
-################################################################################
-# Add tests
-################################################################################
-if(NOT NO_TEST)
- function(new_test _name)
- add_executable(${_name} ${SCK_SOURCE_DIR}/${_name}.c)
- target_link_libraries(${_name} sck RSys ${ARGN})
- add_test(${_name} ${_name})
- endfunction()
-
- new_test(test_sck)
- new_test(test_sck_load)
-endif()
-
-################################################################################
-# Man page
-###############################################################################
-find_program(SCDOC NAMES scdoc)
-if(NOT SCDOC)
- message(WARNING
- "The `scdoc' program is missing. "
- "The Star-CK man page cannot be generated.")
-else()
- set(_src ${PROJECT_SOURCE_DIR}/../doc/sck.5.scd)
- add_custom_command(
- OUTPUT sck.5
- COMMAND ${SCDOC} < ${_src} > sck.5
- DEPENDS ${_src}
- WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
- COMMENT "Buid ROFF man page sck.5"
- VERBATIM)
- add_custom_target(man-roff ALL DEPENDS sck.5)
- install(FILES ${CMAKE_CURRENT_BINARY_DIR}/sck.5 DESTINATION share/man/man5)
-endif()
-
-################################################################################
-# Define output & install directories
-################################################################################
-install(TARGETS sck
- ARCHIVE DESTINATION bin
- LIBRARY DESTINATION lib
- RUNTIME DESTINATION bin)
-install(FILES ${SCK_FILES_INC_API} DESTINATION include/star)
-install(FILES ${SCK_FILES_DOC} DESTINATION share/doc/star-ck)
-
diff --git a/config.mk b/config.mk
@@ -0,0 +1,77 @@
+VERSION = 0.1.0
+PREFIX = /usr/local
+
+LIB_TYPE = SHARED
+#LIB_TYPE = STATIC
+
+BUILD_TYPE = RELEASE
+#BUILD_TYPE = DEBUG
+
+################################################################################
+# Tools
+################################################################################
+AR = ar
+CC = cc
+LD = ld
+OBJCOPY = objcopy
+PKG_CONFIG = pkg-config
+RANLIB = ranlib
+
+################################################################################
+# Dependencies
+################################################################################
+PCFLAGS_SHARED =
+PCFLAGS_STATIC = --static
+PCFLAGS = $(PCFLAGS_$(LIB_TYPE))
+
+RSYS_VERSION = 0.14
+RSYS_CFLAGS = $$($(PKG_CONFIG) $(PCFLAGS) --cflags rsys)
+RSYS_LIBS = $$($(PKG_CONFIG) $(PCFLAGS) --libs rsys)
+
+################################################################################
+# 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=c89\
+ -pedantic\
+ -fvisibility=hidden\
+ -fstrict-aliasing\
+ $(CFLAGS_HARDENED)\
+ $(WFLAGS)
+
+CFLAGS_DEBUG = -g $(CFLAGS_COMMON)
+CFLAGS_RELEASE = -O2 -DNDEBUG $(CFLAGS_COMMON)
+CFLAGS = $(CFLAGS_$(BUILD_TYPE))
+
+CFLAGS_SO = $(CFLAGS) -fPIC
+CFLAGS_EXE = $(CFLAGS) -fPIE
+
+################################################################################
+# Linker options
+################################################################################
+LDFLAGS_HARDENED = -Wl,-z,relro,-z,now
+LDFLAGS_DEBUG = $(LDFLAGS_HARDENED)
+LDFLAGS_RELEASE = -s $(LDFLAGS_HARDENED)
+LDFLAGS = $(LDFLAGS_$(BUILD_TYPE))
+
+LDFLAGS_SO = $(LDFLAGS) -shared -Wl,--no-undefined
+LDFLAGS_EXE = $(LDFLAGS) -pie
+
+OCPFLAGS_DEBUG = --localize-hidden
+OCPFLAGS_RELEASE = --localize-hidden --strip-unneeded
+OCPFLAGS = $(OCPFLAGS_$(BUILD_TYPE))
diff --git a/doc/sck.5.scd b/doc/sck.5.scd
@@ -1,110 +0,0 @@
-sck(5)
-
-; Copyright (C) 2022, 2023 |Méso|Star> (contact@meso-star.com)
-; Copyright (C) 2020, 2021 CNRS
-;
-; 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/>.
-
-# NAME
-
-sck - Star Correlated K file format
-
-# DESCRIPTION
-
-*sck* is a binary file format for storing the correlated K of a gas mixture.
-The volumetric mesh to which the CKs are attached is _not_ described there but
-must be defined in a separated file via, for example, the *smsh*(5) file
-format.
-
-An *sck* file begins by a header that describes the layout of the data. Next the
-spectral bands on which the CKs were evaluated are listed. Finally, the entire
-list of CKs are stored.
-
-A *sck* file begins with a header that describes the layout of the data. Then,
-the spectral bands on which the CKs have been evaluated are listed. Finally,
-the entire list of radiative coefficients is stored.
-
-The header consists of 3 64-bit integers. The first integer is a power of two
-(usually 4096) that defines the _pagesize_ in bytes on which the radiative
-coefficients are aligned. The remaining two integers store the number of bands
-and the number of nodes, that is, the number of radiative coefficients per band
-or per quadrature point, respectively, which is actually the number of nodes in
-the volumetric mesh to which these coefficients are attached.
-
-After the header comes the list of spectral bands sorted in ascending order
-relative to their interval. Each spectral band begins with 2 double-precision
-floating-point numbers that represent the lower and upper limits of the band in
-nanometers. Another 64-bit integer then gives the number of quadrature points in
-the band. Finally, the weights of the quadrature points are stored in a list of
-floating numbers with double precision.
-
-Fill bytes follow the list of spectral bands to ensure alignment of the first
-radiative coefficients on _pagesize_. Then, for each band, the diffusion
-coefficients are listed before the list of absorption coefficients for each
-quadrature point. Each list of radiative coefficients is followed by a
-_padding_, which is a list of bytes that provides memory alignment of the
-following data to _pagesize_. Bands and quadrature points are sorted according
-to the order in which they were previously declared.
-
-# BINARY FILE FORMAT
-
-Data are encoded with respect to the little endian bytes ordering, i.e. least
-significant bytes are stored first.
-
-```
-<sck> ::= <pagesize> <#bands> <#nodes>
- <bands>
- <padding>
- <rad-coefs>
-
-<pagesize> ::= UINT64
-<#bands> ::= UINT64
-<#nodes> ::= UINT64
-<padding> ::= [ BYTE ... ] #ensure alignment on <pagesize>
-
----
-
-<band-list> ::= <band> [ <band> ... ]
-<band> ::= <band-low> <band-upp> <#quad-pts> <quad-pt-list>
-
-<band-id> ::= UINT64
-<band-low> ::= DOUBLE # In nm (inclusive)
-<band-upp> ::= DOUBLE # In nm (exclusive)
-<#quad-pts> ::= UINT64
-
----
-
-<quad-pt-list> ::= <quad-weight> [ <quad-weight> ... ]
-<quad-weight> ::= DOUBLE
-
----
-
-<rad-coefs> ::= <per-band-k>
- [ <per-band-k> ... ]
-
-<per-band-k> ::= <ks-list>
- <per-quad-pt-ka>
-
-<per-quad-pt-ka> ::= <ka-list>
- [ <ka-list>... ]
-
-<ka-list> ::= <ka> [ <ka> ... ] <padding>
-<ks-list> ::= <ks> [ <ks> ... ] <padding>
-<ka> ::= FLOAT # in m^-1
-<ks> ::= FLOAT # in m^-1
-```
-
-# SEE ALSO
-
-*mmap*(2), *smsh*(5)
diff --git a/make.sh b/make.sh
@@ -0,0 +1,72 @@
+#!/bin/sh
+
+# Copyright (C) 2022, 2023 |Méso|Star> (contact@meso-star.com)
+# Copyright (C) 2020, 2021 CNRS
+#
+# 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/>.
+
+set -e
+
+config_test()
+{
+ for i in "$@"; do
+ test=$(basename "${i}" ".c")
+ test_list="${test_list} ${test}"
+ printf "%s: %s\n" "${test}" "src/${test}.o"
+ done
+ printf "test_bin: %s\n" "${test_list}"
+}
+
+run_test()
+{
+ for i in "$@"; do
+ test=$(basename "${i}" ".c")
+
+ printf "%s " "${test}"
+ if "./${test}" > /dev/null 2>&1; then
+ printf "\033[1;32mOK\033[m\n"
+ else
+ printf "\033[1;31mError\033[m\n"
+ fi
+ done 2> /dev/null
+}
+
+
+clean_test()
+{
+ for i in "$@"; do
+ rm -f "$(basename "${i}" ".c")"
+ done
+}
+
+install()
+{
+ prefix=$1
+ shift 1
+
+ mkdir -p "${prefix}"
+
+ for i in "$@"; do
+ dst="${prefix}/${i##*/}"
+
+ if cmp -s "${i}" "${dst}"; then
+ printf "Up to date %s\n" "${dst}"
+ else
+ printf "Installing %s\n" "${dst}"
+ cp "${i}" "${prefix}"
+ fi
+ done
+}
+
+"$@"
diff --git a/sck.5 b/sck.5
@@ -0,0 +1,112 @@
+.\" Copyright (C) 2022, 2023 |Méso|Star> (contact@meso-star.com)
+.\" Copyright (C) 2020, 2021 CNRS
+.\"
+.\" 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 July 28, 2023
+.Dt SCK 5
+.Os
+.Sh NAME
+.Nm sck
+.Nd Star Correlated K file format
+.Sh DESCRIPTION
+.Nm
+is a binary file format for storing the correlated K of a gas mixture.
+The volumetric mesh to which the CKs are attached is
+.Em not
+described there but must be defined in a separated file via, for example, the
+.Xr smsh 5
+file format.
+.Pp
+A
+.Nm
+file begins with a header that describes the layout of the data.
+Then, the spectral bands on which the CKs have been evaluated are listed.
+Finally, the entire list of radiative coefficients is stored.
+.Pp
+The header consists of 3 64-bit integers.
+The first integer is a power of two
+.Pq usually 4096
+that defines the
+.Va pagesize
+in bytes on which the radiative coefficients are aligned.
+The remaining two integers store the number of bands and the number of nodes,
+that is, the number of radiative coefficients per band or per quadrature point,
+respectively, which is actually the number of nodes in the volumetric mesh to
+which these coefficients are attached.
+.Pp
+After the header comes the list of spectral bands sorted in ascending order
+relative to their interval.
+Each spectral band begins with 2 double-precision floating-point numbers that
+represent the lower and upper limits of the band in nanometers.
+Another 64-bit integer then gives the number of quadrature points in the band.
+Finally, the weights of the quadrature points are stored in a list of floating
+numbers with double precision.
+.Pp
+Fill bytes follow the list of spectral bands to ensure alignment of the first
+radiative coefficients on
+.Va pagesize .
+Then, for each band, the diffusion coefficients are listed before the list of
+absorption coefficients for each quadrature point.
+Each list of radiative coefficients is followed by a
+.Va padding ,
+which is a list of bytes that provides memory alignment of the
+following data to
+.Va pagesize .
+Bands and quadrature points are sorted according to the order in which they
+were previously declared.
+.Pp
+Data are encoded with respect to the little endian bytes ordering, i.e. least
+significant bytes are stored first.
+.Pp
+The file format is as follows:
+.Bl -column (per-quad-pt-ka) (::=) ()
+.It Ao Va sck Ac Ta ::= Ta Ao Va pagesize Ac Ao Va #bands Ac Ao Va #nodes Ac
+.It Ta Ta Aq Va bands
+.It Ta Ta Aq Va padding
+.It Ta Ta Aq Va rad-coefs
+.It \ Ta Ta
+.It Ao Va pagesize Ac Ta ::= Ta Vt uint64_t
+.It Ao Va #bands Ac Ta ::= Ta Vt uint64_t
+.It Ao Va #nodes Ac Ta ::= Ta Vt uint64_t
+.It Ao Va padding Ac Ta ::= Ta Op Va int8_t ...
+# Ensure alignment on
+.Va pagesize
+.It \ Ta Ta
+.It Ao Va bands Ac Ta ::= Ta Ao Va band Ac Va ...
+.It Ao Va band Ac Ta ::= Ta
+.Aq Va band-low
+.Aq Va band-upp
+.Aq Va #quad-pts
+.Aq Va quad-pts
+.It Ao Va band-low Ac Ta ::= Ta Vt double
+# Inclusive bound in nm
+.It Ao Va band-upp Ac Ta ::= Ta Vt double
+# Exclusive bound in nm
+.It \ Ta Ta
+.It Ao Va #quad-pts Ac Ta ::= Ta Vt uint64_t
+.It Ao Va quad-pts Ac Ta ::= Ta Ao Va quad-weight Ac Va ...
+.It Ao Va quad-weight Ac Ta ::= Ta Vt double
+.It \ Ta Ta
+.It Ao Va rad-coefs Ac Ta ::= Ta Ao Va per-band-k Ac Va ...
+.It Ao Va per-band-k Ac Ta ::= Ta Ao Va ks-list Ac Ao Va per-quad-pt-ka Ac
+.It Ao Va per-quad-pt-ka Ac Ta ::= Ta Ao Va ka-list Ac Va ...
+.It Ao Va ka-list Ac Ta ::= Ta Ao Va ka Ac Va ... Ao Va padding Ac
+.It Ao Va ks-list Ac Ta ::= Ta Ao Va ks Ac Va ... Ao Va padding Ac
+.It Ao Va ka Ac Ta ::= Ta Vt float
+# In m^-1
+.It Ao Va ks Ac Ta ::= Ta Vt float
+# In m^-1
+.El
+.Sh SEE ALSO
+.Xr smsh 5
diff --git a/sck.pc.in b/sck.pc.in
@@ -0,0 +1,11 @@
+prefix=@PREFIX@
+includedir=${prefix}/include
+libdir=${prefix}/lib
+
+Requires: rsys >= @RSYS_VERSION@
+Name: Star-CK
+Description: Star Correlated K library
+Version: @VERSION@
+Libs: -L${libdir} -lsck
+Libs.private: -lm
+CFlags: -I${includedir}
diff --git a/src/sck.c b/src/sck.c
@@ -23,16 +23,29 @@
#include "sck_log.h"
#include <rsys/algorithm.h>
+#include <rsys/cstr.h>
#include <unistd.h> /* sysconf support */
#include <errno.h>
#include <string.h>
#include <sys/mman.h> /* mmap */
+#include <sys/stat.h> /* fstat */
/*******************************************************************************
* Helper functions
******************************************************************************/
+static INLINE int
+is_stdin(FILE* stream)
+{
+ struct stat stream_buf;
+ struct stat stdin_buf;
+ ASSERT(stream);
+ CHK(fstat(fileno(stream), &stream_buf) == 0);
+ CHK(fstat(STDIN_FILENO, &stdin_buf) == 0);
+ return stream_buf.st_dev == stdin_buf.st_dev;
+}
+
static INLINE res_T
check_sck_create_args(const struct sck_create_args* args)
{
@@ -40,6 +53,27 @@ check_sck_create_args(const struct sck_create_args* args)
return args ? RES_OK : RES_BAD_ARG;
}
+static INLINE res_T
+check_sck_load_args(const struct sck_load_args* args)
+{
+ if(!args || !args->path) return RES_BAD_ARG;
+ return RES_OK;
+}
+
+static INLINE res_T
+check_sck_load_stream_args
+ (struct sck* sck,
+ const struct sck_load_stream_args* args)
+{
+ if(!args || !args->stream || !args->name) return RES_BAD_ARG;
+ if(args->memory_mapping && is_stdin(args->stream)) {
+ log_err(sck, "%s: unable to use memory mapping on data loaded from stdin\n",
+ args->name);
+ return RES_BAD_ARG;
+ }
+ return RES_OK;
+}
+
static void
reset_sck(struct sck* sck)
{
@@ -47,6 +81,7 @@ reset_sck(struct sck* sck)
sck->pagesize = 0;
sck->nnodes = 0;
darray_band_purge(&sck->bands);
+ str_clear(&sck->name);
}
static INLINE int
@@ -62,17 +97,18 @@ read_quad_pt
(struct sck* sck,
struct quad_pt* quad_pt,
FILE* stream,
- const char* stream_name,
size_t iband,
size_t iquad_pt)
{
res_T res = RES_OK;
- ASSERT(sck && quad_pt && stream_name);
+ ASSERT(sck && quad_pt);
+
+ quad_pt->band = darray_band_data_get(&sck->bands) + iband;
if(fread(&quad_pt->weight, sizeof(quad_pt->weight), 1, stream) != 1) {
log_err(sck,
"%s: band %lu: quadrature point %lu: could not read the weight.\n",
- stream_name, iband, iquad_pt);
+ sck_get_name(sck), iband, iquad_pt);
res = RES_IO_ERR;
goto error;
}
@@ -80,7 +116,7 @@ read_quad_pt
if(quad_pt->weight < 0) {
log_err(sck,
"%s: band %lu: quadrature point %lu: invalid weight %g.\n",
- stream_name, iband, iquad_pt, quad_pt->weight);
+ sck_get_name(sck), iband, iquad_pt, quad_pt->weight);
res = RES_BAD_ARG;
goto error;
@@ -98,23 +134,23 @@ static res_T
read_band
(struct sck* sck,
struct band* band,
- FILE* stream,
- const char* stream_name)
+ FILE* stream)
{
double cumul;
size_t iquad_pt;
size_t iband;
uint64_t nquad_pts;
res_T res = RES_OK;
- ASSERT(sck && band && stream_name);
+ ASSERT(sck && band);
+ band->sck = sck;
iband = (size_t)(band - darray_band_cdata_get(&sck->bands));
/* Read band definition */
#define READ(Var, Name) { \
if(fread((Var), sizeof(*(Var)), 1, stream) != 1) { \
log_err(sck, "%s: band %lu: could not read the %s.\n", \
- stream_name, (unsigned long)iband, (Name)); \
+ sck_get_name(sck), (unsigned long)iband, (Name)); \
res = RES_IO_ERR; \
goto error; \
} \
@@ -128,14 +164,14 @@ read_band
if(band->low < 0 || band->low > band->upp) {
log_err(sck,
"%s: band %lu: invalid band range [%g, %g].\n",
- stream_name, (unsigned long)iband, band->low, band->upp);
+ sck_get_name(sck), (unsigned long)iband, band->low, band->upp);
res = RES_BAD_ARG;
goto error;
}
if(nquad_pts == 0) {
log_err(sck,
"%s: band %lu: invalid number fo quadrature points (#points=%lu).\n",
- stream_name, (unsigned long)iband, (unsigned long)nquad_pts);
+ sck_get_name(sck), (unsigned long)iband, (unsigned long)nquad_pts);
res = RES_BAD_ARG;
goto error;
}
@@ -146,7 +182,7 @@ read_band
log_err(sck,
"%s: band %lu: could not allocate the list of quadrature points "
"(#points=%lu).\n",
- stream_name, (unsigned long)iband, (unsigned long)nquad_pts);
+ sck_get_name(sck), (unsigned long)iband, (unsigned long)nquad_pts);
goto error;
}
@@ -156,7 +192,7 @@ read_band
log_err(sck,
"%s: band %lu: could not allocate the cumulative of quadrature points "
"(#points=%lu).\n",
- stream_name, (unsigned long)iband, (unsigned long)nquad_pts);
+ sck_get_name(sck), (unsigned long)iband, (unsigned long)nquad_pts);
goto error;
}
@@ -166,7 +202,7 @@ read_band
struct quad_pt* quad_pt = darray_quad_pt_data_get(&band->quad_pts)+iquad_pt;
/* Read current quadrature point */
- res = read_quad_pt(sck, quad_pt, stream, stream_name, iband, iquad_pt);
+ res = read_quad_pt(sck, quad_pt, stream, iband, iquad_pt);
if(res != RES_OK) goto error;
/* Compute the quadrature point cumulative */
@@ -178,7 +214,7 @@ read_band
if(!eq_eps(cumul, 1.0, 1.e-6)) {
log_warn(sck,
"%s: band %lu: the weights of the quadrature points are not normalised.\n",
- stream_name, (unsigned long)iband);
+ sck_get_name(sck), (unsigned long)iband);
/* Renormalize the cumulative */
FOR_EACH(iquad_pt, 0, nquad_pts) {
@@ -196,26 +232,281 @@ error:
}
static res_T
-load_stream(struct sck* sck, FILE* stream, const char* stream_name)
+map_data
+ (struct sck* sck,
+ const int fd, /* File descriptor */
+ const size_t filesz, /* Overall filesize */
+ const char* data_name,
+ const off_t offset, /* Offset of the data into file */
+ const size_t map_len,
+ void** out_map) /* Lenght of the data to map */
{
+ void* map = NULL;
+ res_T res = RES_OK;
+ ASSERT(sck && filesz && data_name && map_len && out_map);
+ ASSERT(IS_ALIGNED((size_t)offset, (size_t)sck->pagesize));
+
+ if((size_t)offset + map_len > filesz) {
+ log_err(sck, "%s: the %s to map exceed the file size\n",
+ sck_get_name(sck), data_name);
+ res = RES_IO_ERR;
+ goto error;
+ }
+
+ map = mmap(NULL, map_len, PROT_READ, MAP_PRIVATE|MAP_POPULATE, fd, offset);
+ if(map == MAP_FAILED) {
+ log_err(sck, "%s: could not map the %s -- %s\n",
+ sck_get_name(sck), data_name, strerror(errno));
+ res = RES_IO_ERR;
+ goto error;
+ }
+
+exit:
+ *out_map = map;
+ return res;
+error:
+ if(map == MAP_FAILED) map = NULL;
+ goto exit;
+}
+
+static res_T
+map_file(struct sck* sck, FILE* stream)
+{
+ size_t filesz;
size_t map_len;
size_t iband;
+ off_t offset;
+ res_T res = RES_OK;
+ ASSERT(sck && stream);
+
+ /* Compute the length in bytes of the k to map for each band/quadrature point */
+ map_len = ALIGN_SIZE(sck->nnodes * sizeof(float), sck->pagesize);
+
+ /* Compute the offset toward the 1st list of radiative coefficients */
+ offset = ftell(stream);
+ offset = (off_t)ALIGN_SIZE((uint64_t)offset, sck->pagesize);
+
+ /* Retrieve the overall filesize */
+ fseek(stream, 0, SEEK_END);
+ filesz = (size_t)ftell(stream);
+
+ FOR_EACH(iband, 0, darray_band_size_get(&sck->bands)) {
+ struct band* band = NULL;
+ size_t iquad_pt;
+
+ band = darray_band_data_get(&sck->bands) + iband;
+ band->map_len = map_len;
+
+ /* Mapping per band scattering coefficients */
+ res = map_data(sck, fileno(stream), filesz, "scattering coefficients",
+ offset, band->map_len, (void**)&band->ks_list);
+ if(res != RES_OK) {
+ log_err(sck,
+ "%s: data mapping error for band %lu\n",
+ sck_get_name(sck), (unsigned long)iband);
+ goto error;
+ }
+
+ offset = (off_t)((size_t)offset + map_len);
+
+ FOR_EACH(iquad_pt, 0, darray_quad_pt_size_get(&band->quad_pts)) {
+ struct quad_pt* quad_pt = NULL;
+
+ /* Mapping absorption coefficients per band and quadrature point */
+ quad_pt = darray_quad_pt_data_get(&band->quad_pts)+iquad_pt;
+ quad_pt->map_len = map_len;
+
+ res = map_data(sck, fileno(stream), filesz, "correlated Ka",
+ offset, quad_pt->map_len, (void**)&quad_pt->ka_list);
+ if(res != RES_OK) {
+ log_err(sck,
+ "%s: data mapping error for band %lu quadrature point %lu\n",
+ sck_get_name(sck), (unsigned long)iband, (unsigned long)iquad_pt);
+ goto error;
+ }
+
+ offset = (off_t)((size_t)offset + map_len);
+ }
+ }
+
+exit:
+ return res;
+error:
+ goto exit;
+}
+
+static res_T
+read_padding(FILE* stream, const size_t padding)
+{
+ char chunk[1024];
+ size_t remaining_nbytes = padding;
+
+ while(remaining_nbytes) {
+ const size_t nbytes = MMIN(sizeof(chunk), remaining_nbytes);
+ if(fread(chunk, 1, nbytes, stream) != nbytes) return RES_IO_ERR;
+ remaining_nbytes -= nbytes;
+ }
+ return RES_OK;
+}
+
+/* Return the size in bytes of the data layout and band descriptors */
+static size_t
+compute_sizeof_header(struct sck* sck)
+{
+ size_t sizeof_header = 0;
+ size_t iband = 0;
+ size_t nbands = 0;
+ ASSERT(sck);
+
+ sizeof_header =
+ sizeof(uint64_t) /* pagesize */
+ + sizeof(uint64_t) /* #bands */
+ + sizeof(uint64_t);/* #nodes */
+
+ nbands = darray_band_size_get(&sck->bands);
+ FOR_EACH(iband, 0, nbands) {
+ const struct band* band = darray_band_cdata_get(&sck->bands)+iband;
+ const size_t nquad_pts = darray_quad_pt_size_get(&band->quad_pts);
+ const size_t sizeof_band_desc =
+ sizeof(double) /* Lower bound */
+ + sizeof(double) /* Upper bound */
+ + sizeof(uint64_t) /* #quad_pts */
+ + sizeof(double) * nquad_pts; /* Weights */
+
+ sizeof_header += sizeof_band_desc;
+ }
+ return sizeof_header;
+}
+
+static res_T
+load_data
+ (struct sck* sck,
+ FILE* stream,
+ const char* data_name,
+ float** out_data)
+{
+ float* data = NULL;
+ res_T res = RES_OK;
+ ASSERT(sck && stream && data_name && out_data);
+
+ data = MEM_ALLOC(sck->allocator, sizeof(float)*sck->nnodes);
+ if(!data) {
+ res = RES_MEM_ERR;
+ log_err(sck, "%s: could not allocate the %s -- %s\n",
+ sck_get_name(sck), data_name, res_to_cstr(res));
+ goto error;
+ }
+
+ if(fread(data, sizeof(float), sck->nnodes, stream) != sck->nnodes) {
+ res = RES_IO_ERR;
+ log_err(sck, "%s: could not read the %s -- %s\n",
+ sck_get_name(sck), data_name, res_to_cstr(res));
+ goto error;
+ }
+
+exit:
+ *out_data = data;
+ return res;
+error:
+ if(data) { MEM_RM(sck->allocator, data); data = NULL; }
+ goto exit;
+}
+
+static res_T
+load_file(struct sck* sck, FILE* stream)
+{
+ size_t padding_bytes;
+ size_t sizeof_header;
+ size_t sizeof_k_list;
+ size_t iband;
+ size_t nbands;
+ res_T res = RES_OK;
+
+ sizeof_header = compute_sizeof_header(sck);
+ sizeof_k_list = sizeof(float)*sck->nnodes;
+
+ padding_bytes = ALIGN_SIZE(sizeof_header, sck->pagesize) - sizeof_header;
+ if((res = read_padding(stream, padding_bytes)) != RES_OK) goto error;
+
+ /* Calculate the padding between the lists of radiative coefficients. Note
+ * that this padding is the same between each list */
+ padding_bytes = ALIGN_SIZE(sizeof_k_list, sck->pagesize) - sizeof_k_list;
+
+ nbands = darray_band_size_get(&sck->bands);
+ FOR_EACH(iband, 0, nbands) {
+ struct band* band = NULL;
+ size_t iquad_pt = 0;
+
+ band = darray_band_data_get(&sck->bands) + iband;
+ ASSERT(!band->ks_list && band->sck == sck);
+
+ /* Loading per band scattering coefficients */
+ res = load_data(sck, stream, "scattering coefficients", &band->ks_list);
+ if(res != RES_OK) {
+ log_err(sck,
+ "%s: data loading error for band %lu\n",
+ sck_get_name(sck), (unsigned long)iband);
+ goto error;
+ }
+
+ if((res = read_padding(stream, padding_bytes)) != RES_OK) goto error;
+
+ FOR_EACH(iquad_pt, 0, darray_quad_pt_size_get(&band->quad_pts)) {
+ struct quad_pt* quad_pt = NULL;
+
+ quad_pt = darray_quad_pt_data_get(&band->quad_pts) + iquad_pt;
+
+ /* Loading absorption coefficients per band and quadrature point */
+ res = load_data(sck, stream, "correlated Ka", &quad_pt->ka_list);
+ if(res != RES_OK) {
+ log_err(sck,
+ "%s: data loading error for band %lu quadrature point %lu\n",
+ sck_get_name(sck), (unsigned long)iband, (unsigned long)iquad_pt);
+ goto error;
+ }
+
+ if((res = read_padding(stream, padding_bytes)) != RES_OK) goto error;
+ }
+ }
+
+exit:
+ return res;
+error:
+ goto exit;
+}
+
+static res_T
+load_stream(struct sck* sck, const struct sck_load_stream_args* args)
+{
+ size_t iband;
uint64_t nbands;
- off_t offset = 0;
res_T res = RES_OK;
- ASSERT(sck && stream && stream_name);
+ ASSERT(sck && check_sck_load_stream_args(sck, args) == RES_OK);
reset_sck(sck);
+ res = str_set(&sck->name, args->name);
+ if(res != RES_OK) {
+ log_err(sck, "%s: unable to duplicate path to loaded data or stream name\n",
+ args->name);
+ goto error;
+ }
+
/* Read file header */
+ if(fread(&sck->pagesize, sizeof(sck->pagesize), 1, args->stream) != 1) {
+ if(ferror(args->stream)) {
+ log_err(sck, "%s: could not read the pagesize.\n", sck_get_name(sck));
+ }
+ res = RES_IO_ERR;
+ goto error;
+ }
#define READ(Var, Name) { \
- if(fread((Var), sizeof(*(Var)), 1, stream) != 1) { \
- log_err(sck, "%s: could not read the %s.\n", stream_name, (Name)); \
+ if(fread((Var), sizeof(*(Var)), 1, args->stream) != 1) { \
+ log_err(sck, "%s: could not read the %s.\n", sck_get_name(sck), (Name)); \
res = RES_IO_ERR; \
goto error; \
} \
} (void)0
- READ(&sck->pagesize, "page size");
READ(&nbands, "number of bands");
READ(&sck->nnodes, "number of nodes");
#undef READ
@@ -225,21 +516,20 @@ load_stream(struct sck* sck, FILE* stream, const char* stream_name)
log_err(sck,
"%s: invalid page size %lu. The page size attribute must be aligned on "
"the page size of the operating system (%lu).\n",
- stream_name,
- (unsigned long)sck->pagesize,
- (unsigned long)sck->pagesize_os);
+ sck_get_name(sck), sck->pagesize, (unsigned long)sck->pagesize_os);
res = RES_BAD_ARG;
goto error;
}
+
if(!nbands) {
log_err(sck, "%s: invalid number of bands %lu.\n",
- stream_name, (unsigned long)nbands);
+ sck_get_name(sck), (unsigned long)nbands);
res = RES_BAD_ARG;
goto error;
}
if(!sck->nnodes) {
log_err(sck, "%s: invalid number of nodes %lu.\n",
- stream_name, (unsigned long)sck->nnodes);
+ sck_get_name(sck), (unsigned long)sck->nnodes);
res = RES_BAD_ARG;
goto error;
}
@@ -248,20 +538,20 @@ load_stream(struct sck* sck, FILE* stream, const char* stream_name)
res = darray_band_resize(&sck->bands, nbands);
if(res != RES_OK) {
log_err(sck, "%s: could not allocate the list of bands (#bands=%lu).\n",
- stream_name, (unsigned long)nbands);
+ sck_get_name(sck), (unsigned long)nbands);
goto error;
}
/* Read the band description */
FOR_EACH(iband, 0, nbands) {
struct band* band = darray_band_data_get(&sck->bands) + iband;
- res = read_band(sck, band, stream, stream_name);
+ res = read_band(sck, band, args->stream);
if(res != RES_OK) goto error;
if(iband > 0 && band[0].low < band[-1].upp) {
log_err(sck,
"%s: bands must be sorted in ascending order and must not "
"overlap (band %lu in [%g, %g[ nm; band %lu in [%g, %g[ nm).\n",
- stream_name,
+ sck_get_name(sck),
(unsigned long)(iband-1), band[-1].low, band[-1].upp,
(unsigned long)(iband), band[ 0].low, band[ 0].upp);
res = RES_BAD_ARG;
@@ -269,52 +559,12 @@ load_stream(struct sck* sck, FILE* stream, const char* stream_name)
}
}
- /* Compute the length in bytes of the k to map for each band/quadrature point */
- map_len = ALIGN_SIZE(sck->nnodes * sizeof(float), sck->pagesize);
-
- /* Compute the offset toward the 1st list of radiative coefficients */
- offset = ftell(stream);
- offset = (off_t)ALIGN_SIZE((uint64_t)offset, sck->pagesize);
-
- FOR_EACH(iband, 0, nbands) {
- struct band* band = NULL;
- size_t iquad_pt;
-
- /* Map the per band scattering coefficient */
- band = darray_band_data_get(&sck->bands) + iband;
- band->map_len = map_len;
- band->ks_list = mmap(NULL, band->map_len, PROT_READ,
- MAP_PRIVATE|MAP_POPULATE, fileno(stream), offset);
- if(band->ks_list == MAP_FAILED) {
- log_err(sck,
- "%s: band %lu: could not map the scattering coefficients -- %s.\n",
- stream_name, (unsigned long)iband, strerror(errno));
- res = RES_IO_ERR;
- goto error;
- }
- offset = (off_t)((size_t)offset + map_len);
-
- FOR_EACH(iquad_pt, 0, darray_quad_pt_size_get(&band->quad_pts)) {
- struct quad_pt* quad_pt = NULL;
-
- /* Map the per band absorption coefficient */
- quad_pt = darray_quad_pt_data_get(&band->quad_pts)+iquad_pt;
- quad_pt->map_len = map_len;
- quad_pt->ka_list = mmap(NULL, quad_pt->map_len, PROT_READ,
- MAP_PRIVATE|MAP_POPULATE, fileno(stream), offset);
- if(quad_pt->ka_list == MAP_FAILED) {
- log_err(sck,
- "%s: band %lu: quadrature point %lu: coult not map the correlated K "
- "-- %s.\n",
- stream_name,
- (unsigned long)iband,
- (unsigned long)iquad_pt,
- strerror(errno));
- res = RES_IO_ERR;
- goto error;
- }
- offset = (off_t)((size_t)offset + map_len);
- }
+ if(args->memory_mapping) {
+ res = map_file(sck, args->stream);
+ if(res != RES_OK) goto error;
+ } else {
+ res = load_file(sck, args->stream);
+ if(res != RES_OK) goto error;
}
exit:
@@ -383,6 +633,7 @@ release_sck(ref_T* ref)
sck = CONTAINER_OF(ref, struct sck, ref);
if(sck->logger == &sck->logger__) logger_release(&sck->logger__);
darray_band_release(&sck->bands);
+ str_release(&sck->name);
MEM_RM(sck->allocator, sck);
}
@@ -421,6 +672,7 @@ sck_create
sck->allocator = allocator;
sck->verbose = args->verbose;
sck->pagesize_os = (size_t)sysconf(_SC_PAGESIZE);
+ str_init(allocator, &sck->name);
darray_band_init(allocator, &sck->bands);
if(args->logger) {
sck->logger = args->logger;
@@ -456,24 +708,27 @@ sck_ref_put(struct sck* sck)
}
res_T
-sck_load(struct sck* sck, const char* path)
+sck_load(struct sck* sck, const struct sck_load_args* args)
{
+ struct sck_load_stream_args stream_args = SCK_LOAD_STREAM_ARGS_NULL;
FILE* file = NULL;
res_T res = RES_OK;
- if(!sck || !path) {
- res = RES_BAD_ARG;
- goto error;
- }
+ if(!sck) { res = RES_BAD_ARG; goto error; }
+ res = check_sck_load_args(args);
+ if(res != RES_OK) goto error;
- file = fopen(path, "r");
+ file = fopen(args->path, "r");
if(!file) {
- log_err(sck, "%s: error opening file `%s'.\n", FUNC_NAME, path);
+ log_err(sck, "%s: error opening file `%s'.\n", FUNC_NAME, args->path);
res = RES_IO_ERR;
goto error;
}
- res = load_stream(sck, file, path);
+ stream_args.stream = file;
+ stream_args.name = args->path;
+ stream_args.memory_mapping = args->memory_mapping;
+ res = load_stream(sck, &stream_args);
if(res != RES_OK) goto error;
exit:
@@ -484,13 +739,78 @@ error:
}
res_T
-sck_load_stream
- (struct sck* sck,
- FILE* stream,
- const char* stream_name)
+sck_load_stream(struct sck* sck, const struct sck_load_stream_args* args)
+{
+ res_T res = RES_OK;
+ if(!sck) return RES_BAD_ARG;
+ res = check_sck_load_stream_args(sck, args);
+ if(res != RES_OK) return res;
+ return load_stream(sck, args);
+}
+
+res_T
+sck_validate(const struct sck* sck)
{
- if(!sck || !stream) return RES_BAD_ARG;
- return load_stream(sck, stream, stream_name ? stream_name : "<stream>");
+ size_t iband;
+ if(!sck) return RES_BAD_ARG;
+
+ FOR_EACH(iband, 0, sck_get_bands_count(sck)) {
+ struct sck_band band = SCK_BAND_NULL;
+ size_t inode;
+ size_t iquad_pt;
+
+ SCK(get_band(sck, iband, &band));
+
+ /* Check band limits */
+ if(band.lower != band.lower /* NaN? */
+ || band.upper != band.upper) { /* NaN? */
+ log_err(sck, "%s: invalid limits for band %lu: [%g, %g[\n",
+ sck_get_name(sck), (unsigned long)iband, band.lower, band.upper);
+ return RES_BAD_ARG;
+ }
+
+ /* Check scattering coefficients */
+ FOR_EACH(inode, 0, sck_get_nodes_count(sck)) {
+ if(band.ks_list[inode] != band.ks_list[inode] /* NaN? */
+ || band.ks_list[inode] < 0) {
+ log_err(sck,
+ "%s: invalid scattering coefficient for band %lu at node %lu: %g\n",
+ sck_get_name(sck), (unsigned long)iband, (unsigned long) inode,
+ band.ks_list[inode]);
+ return RES_BAD_ARG;
+ }
+ }
+
+ FOR_EACH(iquad_pt, 0, band.quad_pts_count) {
+ struct sck_quad_pt quad_pt = SCK_QUAD_PT_NULL;
+
+ SCK(band_get_quad_pt(&band, iquad_pt, &quad_pt));
+
+ /* Check quadrature point weight */
+ if(quad_pt.weight != quad_pt.weight /* NaN? */
+ || quad_pt.weight <= 0) {
+ log_err(sck,
+ "%s: invalid weight for quadrature point %lu of band %lu: %g\n",
+ sck_get_name(sck), (unsigned long)iquad_pt, (unsigned long)iband,
+ quad_pt.weight);
+ return RES_BAD_ARG;
+ }
+
+ /* Check absorption coefficient */
+ FOR_EACH(inode, 0, sck_get_nodes_count(sck)) {
+ if(quad_pt.ka_list[inode] != quad_pt.ka_list[inode] /* NaN? */
+ || quad_pt.ka_list[inode] < 0) {
+ log_err(sck,
+ "%s: invalid absorption coefficient for quadrature point %lu "
+ "of band %lu at node %lu: %g\n",
+ sck_get_name(sck), (unsigned long)iquad_pt, (unsigned long)iband,
+ (unsigned long)inode, quad_pt.ka_list[inode]);
+ return RES_BAD_ARG;
+ }
+ }
+ }
+ }
+ return RES_OK;
}
size_t
@@ -770,6 +1090,13 @@ error:
goto exit;
}
+const char*
+sck_get_name(const struct sck* sck)
+{
+ ASSERT(sck);
+ return str_cget(&sck->name);
+}
+
/*******************************************************************************
* Local functions
******************************************************************************/
@@ -779,16 +1106,80 @@ band_release(struct band* band)
ASSERT(band);
darray_quad_pt_release(&band->quad_pts);
darray_double_release(&band->quad_pts_cumul);
- if(band->ks_list && band->ks_list != MAP_FAILED) {
+
+ if(!band->ks_list) return;
+
+ if(!band->map_len) {
+ MEM_RM(band->sck->allocator, band->ks_list);
+ } else if(band->ks_list != MAP_FAILED) {
munmap(band->ks_list, band->map_len);
}
}
+res_T
+band_copy(struct band* dst, const struct band* src)
+{
+ res_T res = RES_OK;
+ ASSERT(dst && src);
+
+ dst->sck = src->sck;
+ dst->low = src->low;
+ dst->upp = src->upp;
+
+ dst->map_len = src->map_len;
+ dst->ks_list = NULL;
+
+ if(src->map_len) {
+ /* The ks are mapped: copy the pointer */
+ dst->ks_list = src->ks_list;
+
+ } else if(src->ks_list != NULL) {
+ /* The ks are loaded: duplicate table contents */
+ const size_t memsz = sizeof(*dst->ks_list)*src->sck->nnodes;
+ dst->ks_list = MEM_ALLOC(dst->sck->allocator, memsz);
+ if(!dst->ks_list) return RES_MEM_ERR;
+ memcpy(dst->ks_list, src->ks_list, memsz);
+ }
+
+ res = darray_quad_pt_copy(&dst->quad_pts, &src->quad_pts);
+ if(res != RES_OK) return res;
+ res = darray_double_copy(&dst->quad_pts_cumul, &src->quad_pts_cumul);
+ if(res != RES_OK) return res;
+ return RES_OK;
+}
+
void
quad_pt_release(struct quad_pt* quad_pt)
{
ASSERT(quad_pt);
- if(quad_pt->ka_list && quad_pt->ka_list != MAP_FAILED) {
+ if(!quad_pt->ka_list) return;
+
+ if(!quad_pt->map_len) {
+ MEM_RM(quad_pt->band->sck->allocator, quad_pt->ka_list);
+ } else if(quad_pt->ka_list != MAP_FAILED) {
munmap(quad_pt->ka_list, quad_pt->map_len);
}
}
+
+res_T
+quad_pt_copy(struct quad_pt* dst, const struct quad_pt* src)
+{
+ ASSERT(dst && src);
+
+ dst->band = src->band;
+ dst->map_len = src->map_len;
+ dst->weight = src->weight;
+ dst->ka_list = NULL;
+ if(src->map_len) {
+ /* The ka are mapped: copy the pointer */
+ dst->ka_list = src->ka_list;
+
+ } else if(src->ka_list != NULL) {
+ /* The ka are loaded: duplicate table contents */
+ const size_t memsz = sizeof(*dst->ka_list)*src->band->sck->nnodes;
+ dst->ka_list = MEM_ALLOC(dst->band->sck->allocator, memsz);
+ if(!dst->ka_list) return RES_MEM_ERR;
+ memcpy(dst->ka_list, src->ka_list, memsz);
+ }
+ return RES_OK;
+}
diff --git a/src/sck.h b/src/sck.h
@@ -51,6 +51,24 @@ struct sck_create_args {
static const struct sck_create_args SCK_CREATE_ARGS_DEFAULT =
SCK_CREATE_ARGS_DEFAULT__;
+struct sck_load_args {
+ const char* path;
+ int memory_mapping; /* Use memory mapping instead of normal loading */
+};
+#define SCK_LOAD_ARGS_NULL__ {NULL, 0}
+static const struct sck_load_args SCK_LOAD_ARGS_NULL = SCK_LOAD_ARGS_NULL__;
+
+struct sck_load_stream_args {
+ FILE* stream;
+ const char* name; /* Stream name */
+ /* Use memory mapping instead of normal loading. Note that memory mapping
+ * cannot be used on some stream like stdin */
+ int memory_mapping;
+};
+#define SCK_LOAD_STREAM_ARGS_NULL__ {NULL, "stream", 0}
+static const struct sck_load_stream_args SCK_LOAD_STREAM_ARGS_NULL =
+ SCK_LOAD_STREAM_ARGS_NULL__;
+
struct sck_band {
double lower; /* Lower band wavelength in nm (inclusive) */
double upper; /* Upper band wavelength in nm (exclusive) */
@@ -98,13 +116,23 @@ sck_ref_put
SCK_API res_T
sck_load
(struct sck* sck,
- const char* path);
+ const struct sck_load_args* args);
SCK_API res_T
sck_load_stream
(struct sck* sck,
- FILE* stream,
- const char* stream_name); /* Can be NULL */
+ const struct sck_load_stream_args* args);
+
+/* Validates radiative coefficients. Data checks have already been carried out
+ * during loading, notably on spectral bands and quadrature points, but this
+ * function performs longer and more thorough tests. It reviews all scattering
+ * and absorption coefficients to check their validity, i.e. whether they are
+ * positive or zero. Note that checking radiative coefficients is not mandatory,
+ * in order to speed up the loading step and avoid loading/unloading them when
+ * using memory mapping. */
+SCK_API res_T
+sck_validate
+ (const struct sck* sck);
SCK_API size_t
sck_get_bands_count
@@ -158,7 +186,12 @@ sck_compute_hash
(const struct sck* sck,
hash256_T hash);
+/* Returns the path of the file or the name of the stream from which the data
+ * was loaded */
+SCK_API const char*
+sck_get_name
+ (const struct sck* sck);
+
END_DECLS
#endif /* SCK_H */
-
diff --git a/src/sck_c.h b/src/sck_c.h
@@ -20,10 +20,12 @@
#include <rsys/dynamic_array_double.h>
#include <rsys/logger.h>
#include <rsys/ref_count.h>
+#include <rsys/str.h>
struct mem_allocator;
struct quad_pt {
+ struct band* band; /* Band to which the quadrature point belongs */
float* ka_list; /* Per node ka */
size_t map_len;
double weight;
@@ -34,6 +36,7 @@ quad_pt_init(struct mem_allocator* allocator, struct quad_pt* quad)
{
ASSERT(quad);
(void)allocator;
+ quad->band = NULL;
quad->ka_list = NULL;
quad->map_len = 0;
quad->weight = 0;
@@ -43,15 +46,36 @@ extern LOCAL_SYM void
quad_pt_release
(struct quad_pt* quad);
+extern LOCAL_SYM res_T
+quad_pt_copy
+ (struct quad_pt* dst,
+ const struct quad_pt* src);
+
+static INLINE res_T
+quad_pt_copy_and_release(struct quad_pt* dst, struct quad_pt* src)
+{
+ ASSERT(dst && src);
+ dst->band = src->band;
+ dst->ka_list = src->ka_list;
+ dst->map_len = src->map_len;
+ dst->weight = src->weight;
+ return RES_OK;
+}
+
/* Define the dynamic array of quadrature points */
#define DARRAY_NAME quad_pt
#define DARRAY_DATA struct quad_pt
+#define DARRAY_FUNCTOR_INIT quad_pt_init
+#define DARRAY_FUNCTOR_RELEASE quad_pt_release
+#define DARRAY_FUNCTOR_COPY quad_pt_copy
+#define DARRAY_FUNCTOR_COPY_AND_RELEASE quad_pt_copy_and_release
#include <rsys/dynamic_array.h>
struct band {
+ struct sck* sck;
double low; /* Lower bound in nm (inclusive) */
double upp; /* Upper bound in nm (exclusive) */
- size_t map_len;
+ size_t map_len; /* 0 <=> band's data are not mapped, i.e. they are loaded */
float* ks_list; /* Per node ks */
struct darray_quad_pt quad_pts;
struct darray_double quad_pts_cumul;
@@ -61,6 +85,7 @@ static INLINE void
band_init(struct mem_allocator* allocator, struct band* band)
{
ASSERT(band);
+ band->sck = NULL;
band->low = DBL_MAX;
band->upp =-DBL_MAX;
band->map_len = 0;
@@ -73,22 +98,10 @@ extern LOCAL_SYM void
band_release
(struct band* band);
-static INLINE res_T
-band_copy(struct band* dst, const struct band* src)
-{
- res_T res = RES_OK;
- ASSERT(dst && src);
-
- dst->low = src->low;
- dst->upp = src->upp;
- dst->map_len = src->map_len;
- dst->ks_list = src->ks_list;
- res = darray_quad_pt_copy(&dst->quad_pts, &src->quad_pts);
- if(res != RES_OK) return res;
- res = darray_double_copy(&dst->quad_pts_cumul, &src->quad_pts_cumul);
- if(res != RES_OK) return res;
- return RES_OK;
-}
+extern LOCAL_SYM res_T
+band_copy
+ (struct band* dst,
+ const struct band* src);
static INLINE res_T
band_copy_and_release(struct band* dst, struct band* src)
@@ -96,6 +109,7 @@ band_copy_and_release(struct band* dst, struct band* src)
res_T res = RES_OK;
ASSERT(dst && src);
+ dst->sck = src->sck;
dst->low = src->low;
dst->upp = src->upp;
dst->map_len = src->map_len;
@@ -126,6 +140,7 @@ struct sck {
struct darray_band bands;
size_t pagesize_os;
+ struct str name; /* path/stream name */
struct mem_allocator* allocator;
struct logger* logger;
diff --git a/src/test_sck_load.c b/src/test_sck_load.c
@@ -21,6 +21,7 @@
#include <rsys/math.h>
#include <rsys/mem_allocator.h>
#include <math.h>
+#include <string.h>
static INLINE double
rand_canonic(void)
@@ -51,6 +52,9 @@ check_sck_load
CHK(nbands);
CHK(nnodes);
+ CHK(sck_validate(NULL) == RES_BAD_ARG);
+ CHK(sck_validate(sck) == RES_OK);
+
CHK(sck_get_bands_count(sck) == nbands);
CHK(sck_get_nodes_count(sck) == nnodes);
@@ -217,6 +221,8 @@ test_load(struct sck* sck)
hash256_T band_hash1;
hash256_T pt_hash0;
hash256_T pt_hash1;
+ struct sck_load_args args = SCK_LOAD_ARGS_NULL;
+ struct sck_load_stream_args stream_args = SCK_LOAD_STREAM_ARGS_NULL;
struct sck_band band;
FILE* fp = NULL;
@@ -229,9 +235,16 @@ test_load(struct sck* sck)
write_sck(fp, pagesize, nbands, nnodes);
rewind(fp);
- CHK(sck_load_stream(NULL, fp, filename) == RES_BAD_ARG);
- CHK(sck_load_stream(sck, NULL, filename) == RES_BAD_ARG);
- CHK(sck_load_stream(sck, fp, NULL) == RES_OK);
+ stream_args.stream = fp;
+ stream_args.name = filename;
+ CHK(sck_load_stream(NULL, &stream_args) == RES_BAD_ARG);
+ CHK(sck_load_stream(sck, NULL) == RES_BAD_ARG);
+ stream_args.stream = NULL;
+ CHK(sck_load_stream(sck, NULL) == RES_BAD_ARG);
+ stream_args.stream = fp;
+ CHK(sck_load_stream(sck, &stream_args) == RES_OK);
+
+ CHK(!strcmp(sck_get_name(sck), filename));
CHK(sck_compute_hash(sck, NULL) == RES_BAD_ARG);
CHK(sck_compute_hash(NULL, hash0) == RES_BAD_ARG);
@@ -254,12 +267,20 @@ test_load(struct sck* sck)
check_sck_load(sck, nbands, nnodes);
rewind(fp);
- CHK(sck_load_stream(sck, fp, filename) == RES_OK);
+ stream_args.name = NULL;
+ CHK(sck_load_stream(sck, &stream_args) == RES_BAD_ARG);
+ stream_args.name = SCK_LOAD_STREAM_ARGS_NULL.name;
+ stream_args.memory_mapping = 1;
+ CHK(sck_load_stream(sck, &stream_args) == RES_OK);
+ CHK(!strcmp(sck_get_name(sck), SCK_LOAD_STREAM_ARGS_NULL.name));
- CHK(sck_load(NULL, filename) == RES_BAD_ARG);
+ args.path = "nop";
+ CHK(sck_load(NULL, &args) == RES_BAD_ARG);
CHK(sck_load(sck, NULL) == RES_BAD_ARG);
- CHK(sck_load(sck, "nop") == RES_IO_ERR);
- CHK(sck_load(sck, filename) == RES_OK);
+ CHK(sck_load(sck, &args) == RES_IO_ERR);
+ args.path = filename;
+ CHK(sck_load(sck, &args) == RES_OK);
+ CHK(!strcmp(sck_get_name(sck), args.path));
check_sck_load(sck, nbands, nnodes);
CHK(sck_compute_hash(sck, hash1) == RES_OK);
@@ -269,7 +290,9 @@ test_load(struct sck* sck)
write_sck(fp, pagesize, nbands+1, nnodes);
rewind(fp);
- CHK(sck_load_stream(sck, fp, filename) == RES_OK);
+ stream_args.stream = fp;
+ stream_args.name = filename;
+ CHK(sck_load_stream(sck, &stream_args) == RES_OK);
CHK(sck_compute_hash(sck, hash1) == RES_OK);
CHK(!hash256_eq(hash0, hash1));
@@ -286,36 +309,42 @@ test_load(struct sck* sck)
static void
test_load_fail(struct sck* sck)
{
+ struct sck_load_stream_args stream_args = SCK_LOAD_STREAM_ARGS_NULL;
FILE* fp = NULL;
double low;
double upp;
+
/* The pagesize is less than the operating system page size*/
CHK(fp = tmpfile());
write_sck(fp, 2048, 1, 1);
rewind(fp);
- CHK(sck_load_stream(sck, fp, NULL) == RES_BAD_ARG);
+ stream_args.stream = fp;
+ CHK(sck_load_stream(sck, &stream_args) == RES_BAD_ARG);
CHK(fclose(fp) == 0);
/* The pagesize is not a power of two */
CHK(fp = tmpfile());
write_sck(fp, 4100, 1, 1);
rewind(fp);
- CHK(sck_load_stream(sck, fp, NULL) == RES_BAD_ARG);
+ stream_args.stream = fp;
+ CHK(sck_load_stream(sck, &stream_args) == RES_BAD_ARG);
CHK(fclose(fp) == 0);
/* Wrong #bands */
CHK(fp = tmpfile());
write_sck(fp, 4096, 0, 1);
rewind(fp);
- CHK(sck_load_stream(sck, fp, NULL) == RES_BAD_ARG);
+ stream_args.stream = fp;
+ CHK(sck_load_stream(sck, &stream_args) == RES_BAD_ARG);
CHK(fclose(fp) == 0);
/* Wrong #nodes */
CHK(fp = tmpfile());
write_sck(fp, 4096, 1, 0);
rewind(fp);
- CHK(sck_load_stream(sck, fp, NULL) == RES_BAD_ARG);
+ stream_args.stream = fp;
+ CHK(sck_load_stream(sck, &stream_args) == RES_BAD_ARG);
CHK(fclose(fp) == 0);
/* Wrong band boundaries */
@@ -327,7 +356,8 @@ test_load_fail(struct sck* sck)
CHK(fwrite(&low, sizeof(low), 1, fp) == 1);
CHK(fwrite(&upp, sizeof(upp), 1, fp) == 1);
rewind(fp);
- CHK(sck_load_stream(sck, fp, NULL) == RES_BAD_ARG);
+ stream_args.stream = fp;
+ CHK(sck_load_stream(sck, &stream_args) == RES_BAD_ARG);
CHK(fclose(fp) == 0);
/* Unsorted bands */
@@ -342,7 +372,8 @@ test_load_fail(struct sck* sck)
CHK(fwrite(&low, sizeof(low), 1, fp) == 1);
CHK(fwrite(&upp, sizeof(upp), 1, fp) == 1);
rewind(fp);
- CHK(sck_load_stream(sck, fp, NULL) == RES_BAD_ARG);
+ stream_args.stream = fp;
+ CHK(sck_load_stream(sck, &stream_args) == RES_BAD_ARG);
CHK(fclose(fp) == 0);
/* Bands overlap */
@@ -357,7 +388,8 @@ test_load_fail(struct sck* sck)
CHK(fwrite(&low, sizeof(low), 1, fp) == 1);
CHK(fwrite(&upp, sizeof(upp), 1, fp) == 1);
rewind(fp);
- CHK(sck_load_stream(sck, fp, NULL) == RES_BAD_ARG);
+ stream_args.stream = fp;
+ CHK(sck_load_stream(sck, &stream_args) == RES_BAD_ARG);
CHK(fclose(fp) == 0);
}
@@ -372,9 +404,22 @@ test_load_files(struct sck* sck, int argc, char** argv)
size_t nbands;
size_t iband;
- printf("Load %s\n", argv[1]);
-
- CHK(sck_load(sck, argv[i]) == RES_OK);
+ if(!strcmp(argv[i], "-")) {
+ struct sck_load_stream_args args = SCK_LOAD_STREAM_ARGS_NULL;
+ printf("Load from stdin\n");
+ args.stream = stdin;
+ args.name = "stdin";
+ args.memory_mapping = 1;
+ CHK(sck_load_stream(sck, &args) == RES_BAD_ARG);
+ args.memory_mapping = 0;
+ CHK(sck_load_stream(sck, &args) == RES_OK);
+ } else {
+ struct sck_load_args args = SCK_LOAD_ARGS_NULL;
+ printf("Load %s\n", argv[1]);
+ args.path = argv[i];
+ args.memory_mapping = 1;
+ CHK(sck_load(sck, &args) == RES_OK);
+ }
nbands = sck_get_bands_count(sck);
nnodes = sck_get_nodes_count(sck);
CHK(nbands);
@@ -382,37 +427,15 @@ test_load_files(struct sck* sck, int argc, char** argv)
FOR_EACH(iband, 0, nbands) {
struct sck_band band = SCK_BAND_NULL;
- size_t inode;
- size_t iqpt;
CHK(sck_get_band(sck, iband, &band) == RES_OK);
printf("band %lu in [%g, %g[ nm with %lu quadrature points\n",
(unsigned long)band.id,
band.lower, band.upper,
(unsigned long)band.quad_pts_count);
-
- CHK(band.lower == band.lower); /* !NaN */
- CHK(band.upper == band.upper); /* !NaN */
- CHK(band.lower < band.upper);
- CHK(band.quad_pts_count);
-
- FOR_EACH(inode, 0, nnodes) {
- CHK(band.ks_list[inode] == band.ks_list[inode]); /* !NaN */
- }
-
- FOR_EACH(iqpt, 0, band.quad_pts_count) {
- struct sck_quad_pt qpt;
-
- CHK(sck_band_get_quad_pt(&band, iqpt, &qpt) == RES_OK);
- CHK(qpt.weight == qpt.weight); /* !NaN */
- CHK(qpt.weight > 0);
-
- FOR_EACH(inode, 0, nnodes) {
- CHK(qpt.ka_list[inode] == qpt.ka_list[inode]); /* !NaN */
- }
- }
}
+ CHK(sck_validate(sck) == RES_OK);
CHK(sck_compute_hash(sck, hash) == RES_OK);
}
}
@@ -420,6 +443,7 @@ test_load_files(struct sck* sck, int argc, char** argv)
static void
test_find(struct sck* sck)
{
+ struct sck_load_stream_args stream_args = SCK_LOAD_STREAM_ARGS_NULL;
size_t ibands[2];
double range[2];
FILE* fp;
@@ -427,7 +451,9 @@ test_find(struct sck* sck)
CHK(fp = tmpfile());
write_sck(fp, 4096, 10, 1);
rewind(fp);
- CHK(sck_load_stream(sck, fp, NULL) == RES_OK);
+ stream_args.stream = fp;
+ stream_args.memory_mapping = 1;
+ CHK(sck_load_stream(sck, &stream_args) == RES_OK);
range[0] = 0;
range[1] = 10;