diff --git a/recipes/fpzip/all/conandata.yml b/recipes/fpzip/all/conandata.yml new file mode 100644 index 0000000000..ef306da4b0 --- /dev/null +++ b/recipes/fpzip/all/conandata.yml @@ -0,0 +1,4 @@ +sources: + "1.3.0": + url: "https://github.com/LLNL/fpzip/releases/download/1.3.0/fpzip-1.3.0.tar.gz" + sha256: "248df7d84259e3feaa4c4797956b2a77c3fcd734e8f8fdc51ce171dcf4f0136c" diff --git a/recipes/fpzip/all/conanfile.py b/recipes/fpzip/all/conanfile.py new file mode 100644 index 0000000000..2369b2e58e --- /dev/null +++ b/recipes/fpzip/all/conanfile.py @@ -0,0 +1,80 @@ +from conan import ConanFile +from conan.tools.files import apply_conandata_patches, export_conandata_patches, get, copy, rmdir +from conan.tools.cmake import CMake, CMakeDeps, CMakeToolchain, cmake_layout +import os + + +required_conan_version = ">=1.53.0" + +class FpzipConan(ConanFile): + name = "fpzip" + description = "Lossless compressor of multidimensional floating-point arrays" + license = "BSD-3-Clause" + url = "https://github.com/conan-io/conan-center-index" + homepage = "http://fpzip.llnl.gov/" + topics = ("compression", "lossless", "floating-point") + package_type = "library" + settings = "os", "arch", "compiler", "build_type" + options = { + "shared": [True, False], + "fPIC": [True, False], + "with_fp": ["fast", "safe", "emul", "int"], + } + default_options = { + "shared": False, + "fPIC": True, + "with_fp": "fast", + } + + def export_sources(self): + export_conandata_patches(self) + + def config_options(self): + if self.settings.os == "Windows": + del self.options.fPIC + + def configure(self): + if self.options.shared: + self.options.rm_safe("fPIC") + + def layout(self): + cmake_layout(self, src_folder="src") + + def source(self): + get(self, **self.conan_data["sources"][self.version], strip_root=True) + + @property + def _fp_name_table(self): + return { + "fast": "FPZIP_FP_FAST", + "safe": "FPZIP_FP_SAFE", + "emul": "FPZIP_FP_EMUL", + "int": "FPZIP_FP_INT", + } + + def generate(self): + tc = CMakeToolchain(self) + tc.variables["FPZIP_FP"] = self._fp_name_table.get(str(self.options.with_fp), "FP_ZIP_FAST") + tc.generate() + deps = CMakeDeps(self) + deps.generate() + + def build(self): + apply_conandata_patches(self) + cmake = CMake(self) + cmake.configure() + cmake.build() + + def package(self): + copy(self, pattern="LICENSE", dst=os.path.join(self.package_folder, "licenses"), src=self.source_folder) + cmake = CMake(self) + cmake.install() + rmdir(self, os.path.join(self.package_folder, "lib", "cmake")) + + def package_info(self): + self.cpp_info.libs = ["fpzip"] + self.cpp_info.defines.append("FPZIP_FP={}".format(self._fp_name_table.get(str(self.options.with_fp), "FP_ZIP_FAST"))) + if self.options.shared: + self.cpp_info.defines.append("FPZIP_SHARED_LIBS") + if self.settings.compiler in ["gcc", "clang", "apple-clang"]: + self.cpp_info.system_libs += ["stdc++"] diff --git a/recipes/fpzip/all/test_package/CMakeLists.txt b/recipes/fpzip/all/test_package/CMakeLists.txt new file mode 100644 index 0000000000..1476da8811 --- /dev/null +++ b/recipes/fpzip/all/test_package/CMakeLists.txt @@ -0,0 +1,7 @@ +cmake_minimum_required(VERSION 3.15) +project(test_package LANGUAGES C) + +find_package(fpzip REQUIRED CONFIG) + +add_executable(${PROJECT_NAME} test_package.c) +target_link_libraries(${PROJECT_NAME} PRIVATE fpzip::fpzip) diff --git a/recipes/fpzip/all/test_package/conanfile.py b/recipes/fpzip/all/test_package/conanfile.py new file mode 100644 index 0000000000..ef5d704216 --- /dev/null +++ b/recipes/fpzip/all/test_package/conanfile.py @@ -0,0 +1,26 @@ +from conan import ConanFile +from conan.tools.build import can_run +from conan.tools.cmake import cmake_layout, CMake +import os + + +class TestPackageConan(ConanFile): + settings = "os", "arch", "compiler", "build_type" + generators = "CMakeDeps", "CMakeToolchain", "VirtualRunEnv" + test_type = "explicit" + + def requirements(self): + self.requires(self.tested_reference_str) + + def layout(self): + cmake_layout(self) + + def build(self): + cmake = CMake(self) + cmake.configure() + cmake.build() + + def test(self): + if can_run(self): + bin_path = os.path.join(self.cpp.build.bindir, "test_package") + self.run(bin_path, env="conanrun") diff --git a/recipes/fpzip/all/test_package/test_package.c b/recipes/fpzip/all/test_package/test_package.c new file mode 100644 index 0000000000..8e359fe8da --- /dev/null +++ b/recipes/fpzip/all/test_package/test_package.c @@ -0,0 +1,142 @@ +#include +#include +#include +#include +#include + +#include "fpzip.h" + +static size_t +compress(FPZ* fpz, const void* data) +{ + size_t size; + /* write header */ + if (!fpzip_write_header(fpz)) { + fprintf(stderr, "cannot write header: %s\n", fpzip_errstr[fpzip_errno]); + return 0; + } + /* perform actual compression */ + size = fpzip_write(fpz, data); + if (!size) { + fprintf(stderr, "compression failed: %s\n", fpzip_errstr[fpzip_errno]); + return 0; + } + return size; +} + +static int +decompress(FPZ* fpz, void* data, size_t inbytes) +{ + /* read header */ + if (!fpzip_read_header(fpz)) { + fprintf(stderr, "cannot read header: %s\n", fpzip_errstr[fpzip_errno]); + return 0; + } + /* make sure array size stored in header matches expectations */ + if ((fpz->type == FPZIP_TYPE_FLOAT ? sizeof(float) : sizeof(double)) * fpz->nx * fpz->ny * fpz->nz * fpz->nf != inbytes) { + fprintf(stderr, "array size does not match dimensions from header\n"); + return 0; + } + /* perform actual decompression */ + if (!fpzip_read(fpz, data)) { + fprintf(stderr, "decompression failed: %s\n", fpzip_errstr[fpzip_errno]); + return 0; + } + return 1; +} + +static float +float_rand() +{ + static unsigned int seed = 1; + double val; + seed = 1103515245 * seed + 12345; + seed &= 0x7fffffffu; + val = ldexp((double)seed, -31); + val = 2 * val - 1; + val *= val * val; + val *= val * val; + return val; +} + +/* generate a trilinear field perturbed by random noise */ +float* +float_field(int nx, int ny, int nz, float offset) +{ + int n = nx * ny * nz; + float* field = malloc(n * sizeof(float)); + int i, x, y, z; + /* generate random field */ + *field = offset; + for (i = 1; i < n; i++) + field[i] = float_rand(); + /* integrate along x */ + for (z = 0; z < nz; z++) + for (y = 0; y < ny; y++) + for (x = 1; x < nx; x++) + field[x + nx * (y + ny * z)] += field[(x - 1) + nx * (y + ny * z)]; + /* integrate along y */ + for (z = 0; z < nz; z++) + for (y = 1; y < ny; y++) + for (x = 0; x < nx; x++) + field[x + nx * (y + ny * z)] += field[x + nx * ((y - 1) + ny * z)]; + /* integrate along z */ + for (z = 1; z < nz; z++) + for (y = 0; y < ny; y++) + for (x = 0; x < nx; x++) + field[x + nx * (y + ny * z)] += field[x + nx * (y + ny * (z - 1))]; + return field; +} + +static void +test_float_array(const float* field, int nx, int ny, int nz, int prec) +{ + int status; + unsigned int actual_checksum; + int dims = (nz == 1 ? ny == 1 ? 1 : 2 : 3); + size_t inbytes = nx * ny * nz * sizeof(float); + size_t bufbytes = 1024 + inbytes; + size_t outbytes = 0; + void* buffer = malloc(bufbytes); + float* copy = malloc(inbytes); + char name[0x100]; + + /* compress to memory */ + FPZ* fpz = fpzip_write_to_buffer(buffer, bufbytes); + fpz->type = FPZIP_TYPE_FLOAT; + fpz->prec = prec; + fpz->nx = nx; + fpz->ny = ny; + fpz->nz = nz; + fpz->nf = 1; + outbytes = compress(fpz, field); + status = (0 < outbytes && outbytes <= bufbytes); + fpzip_write_close(fpz); + sprintf(name, "test.float.%dd.prec%d.compress", dims, prec); + + /* decompress */ + fpz = fpzip_read_from_buffer(buffer); + status = decompress(fpz, copy, inbytes); + fpzip_read_close(fpz); + sprintf(name, "test.float.%dd.prec%d.decompress", dims, prec); + + free(copy); + free(buffer); +} + +static int +test_float(int nx, int ny, int nz) +{ + float* field = float_field(nx, ny, nz, 0); + int prec = 8; + test_float_array(field, nx * ny * nz, 1, 1, prec); + test_float_array(field, nx, ny * nz, 1, prec); + test_float_array(field, nx, ny, nz, prec); + free(field); +} + +int main(void) { + test_float(65, 64, 63); + + return 0; +} diff --git a/recipes/fpzip/config.yml b/recipes/fpzip/config.yml new file mode 100644 index 0000000000..426a0e4c79 --- /dev/null +++ b/recipes/fpzip/config.yml @@ -0,0 +1,3 @@ +versions: + "1.3.0": + folder: all