From 1307dfca3b0b947b527987c84c89757024ed65e3 Mon Sep 17 00:00:00 2001 From: Willem Deconinck Date: Wed, 25 Oct 2023 21:56:00 +0200 Subject: [PATCH 01/25] Update install script --- tools/install.sh | 100 +++++++++++++++++++++-------------------------- 1 file changed, 45 insertions(+), 55 deletions(-) diff --git a/tools/install.sh b/tools/install.sh index 7a6392b9d..2f6b051e4 100755 --- a/tools/install.sh +++ b/tools/install.sh @@ -21,7 +21,7 @@ CMAKE_OPTIONS="" with_gridtools=false with_trans=false with_fftw=false -with_cgal=false +with_qhull=false with_deps=false WORK_DIR=$(pwd) BUILD_TYPE=RelWithDebInfo @@ -32,14 +32,14 @@ function print_help { echo "" echo "Usage:" echo "" - echo " install.sh [--with-deps] [--prefix ] [--build-type ] [--cmake ] \\" - echo " [--enable-gridtools] [--enable-trans] [--enable-fftw] [--enable-cgal] [--work-dir ] [--help]" + echo " install.sh [--with-deps] [--prefix ] [--build-type ] [--cmake ] [--parallel ] \\" + echo " [--enable-gridtools] [--enable-trans] [--enable-fftw] [--enable-qhull] [--work-dir ] [--help]" echo "" echo " " echo "" echo "Options:" echo "" - echo " --with-deps Install dependencies together with Atlas: fftw, cgal, ecbuild, eckit, fckit, fiat, ectrans" + echo " --with-deps Install dependencies together with Atlas: fftw, qhull, ecbuild, eckit, fckit, fiat, ectrans" echo " --prefix Install prefix for atlas (and its dependencies if requested with '--with-deps')" echo " --build-type Build type for atlas (and its dependencies if requested with '--with-deps')" echo " Possible values are ( Release | RelWithDebInfo | Debug )" @@ -48,8 +48,7 @@ function print_help { echo " --enable-gridtools Enable optional gridtools dependency (only has effect when '--with-deps' is also used)" echo " ! Requires Boost ! Specify Boost_ROOT environment variable to a fairly recent Boost installation" echo " --enable-fftw Enable optional fftw dependency required for spectral transforms" - echo " --enable-cgal Enable optional cgal required for meshing of unstructured grids" - echo " ! Requires Boost ! Specify Boost_ROOT environment variable to a fairly recent Boost installation" + echo " --enable-qhull Enable optional qhull required for meshing of unstructured grids" echo " --work-dir Working directory where sources and builds live" echo " --help Print this help" echo "" @@ -82,8 +81,8 @@ while [ $# != 0 ]; do "--enable-gridtools") with_gridtools=true; ;; - "--enable-cgal") - with_cgal=true; + "--enable-qhull") + with_qhull=true; ;; "--prefix") PREFIX="$2"; shift @@ -94,6 +93,9 @@ while [ $# != 0 ]; do "--work-dir") WORK_DIR="$2"; shift ;; + "--parallel") + export CMAKE_BUILD_PARALLEL_LEVEL="$2"; shift + ;; "--help") print_help; exit 0 @@ -114,7 +116,7 @@ SOURCES_DIR=${WORK_DIR}/sources BUILDS_DIR=${WORK_DIR}/builds export PATH=${PREFIX}/bin:${PATH} -export CMAKE_PREFIX_PATH=${PREFIX} +export CMAKE_PREFIX_PATH=${PREFIX}:${CMAKE_PREFIX_PATH} mkdir -p ${SOURCES_DIR} mkdir -p ${BUILDS_DIR} @@ -126,32 +128,23 @@ if ${with_deps}; then install-fftw.sh --prefix ${PREFIX} fi - ### Install CGAL (optional, off by default) - if ${with_cgal}; then - echo "Installing CGAL" - [[ -d ${SOURCES_DIR}/cgal ]] || git clone https://github.com/CGAL/cgal.git ${SOURCES_DIR}/cgal - cd ${SOURCES_DIR}/cgal - git checkout releases/CGAL-5.0 - mkdir -p ${BUILDS_DIR}/cgal && cd ${BUILDS_DIR}/cgal - cmake -DCMAKE_INSTALL_PREFIX=${PREFIX} \ - -DCMAKE_BUILD_TYPE=Release \ - -DBUILD_TESTING=OFF \ - ${SOURCES_DIR}/cgal - make -j8 install + ### Install qhull (optional, off by default) + if ${with_qhull}; then + install-qhull.sh --prefix ${PREFIX} fi ### Install ecbuild echo "Installing ecbuild" [[ -d ${SOURCES_DIR}/ecbuild ]] || git clone -b master https://github.com/ecmwf/ecbuild ${SOURCES_DIR}/ecbuild - mkdir -p ${BUILDS_DIR}/ecbuild && cd ${BUILDS_DIR}/ecbuild - cmake -DCMAKE_INSTALL_PREFIX=${PREFIX} -DENABLE_TESTS=OFF ${SOURCES_DIR}/ecbuild - make -j8 install + cmake -S ${SOURCES_DIR}/ecbuild -B ${BUILDS_DIR}/ecbuild -DCMAKE_INSTALL_PREFIX=${PREFIX} -DENABLE_TESTS=OFF + cmake --build ${BUILDS_DIR}/ecbuild + cmake --install ${BUILDS_DIR}/ecbuild ### Install eckit echo "Installing eckit" [[ -d ${SOURCES_DIR}/eckit ]] || git clone -b master https://github.com/ecmwf/eckit ${SOURCES_DIR}/eckit - mkdir -p ${BUILDS_DIR}/eckit && cd ${BUILDS_DIR}/eckit - cmake -DCMAKE_INSTALL_PREFIX=${PREFIX} \ + cmake -S ${SOURCES_DIR}/eckit -B ${BUILDS_DIR}/eckit \ + -DCMAKE_INSTALL_PREFIX=${PREFIX} \ -DCMAKE_BUILD_TYPE=${BUILD_TYPE} \ -DENABLE_TESTS=OFF \ -DENABLE_ECKIT_SQL=OFF \ @@ -167,42 +160,40 @@ if ${with_deps}; then -DENABLE_JEMALLOC=OFF \ -DENABLE_BZIP2=OFF \ -DCMAKE_DISABLE_FIND_PACKAGE_Doxygen=ON \ - ${CMAKE_OPTIONS} \ - ${SOURCES_DIR}/eckit - make -j8 install + ${CMAKE_OPTIONS} + cmake --build ${BUILDS_DIR}/eckit + cmake --install ${BUILDS_DIR}/eckit ### Install fckit echo "Installing fckit" [[ -d ${SOURCES_DIR}/fckit ]] || git clone -b master https://github.com/ecmwf/fckit ${SOURCES_DIR}/fckit - mkdir -p ${BUILDS_DIR}/fckit && cd ${BUILDS_DIR}/fckit - cmake -DCMAKE_INSTALL_PREFIX=${PREFIX} \ + cmake ${SOURCES_DIR}/fckit -B ${BUILDS_DIR}/fckit -DCMAKE_INSTALL_PREFIX=${PREFIX} \ -DCMAKE_BUILD_TYPE=${BUILD_TYPE} \ -DENABLE_TESTS=OFF \ - ${CMAKE_OPTIONS} \ - ${SOURCES_DIR}/fckit - make -j8 install + ${CMAKE_OPTIONS} + cmake --build ${BUILDS_DIR}/fckit + cmake --install ${BUILDS_DIR}/fckit ### Install fiat + ectrans (optional, off by default) if ${with_trans}; then echo "Installing fiat" [[ -d ${SOURCES_DIR}/fiat ]] || git clone -b master https://github.com/ecmwf-ifs/fiat ${SOURCES_DIR}/fiat - mkdir -p ${BUILDS_DIR}/fiat && cd ${BUILDS_DIR}/fiat - cmake -DCMAKE_INSTALL_PREFIX=${PREFIX} \ + cmake -S ${SOURCES_DIR}/fiat -B ${BUILDS_DIR}/fiat \ + -DCMAKE_INSTALL_PREFIX=${PREFIX} \ -DCMAKE_BUILD_TYPE=${BUILD_TYPE} \ -DENABLE_TESTS=OFF \ - ${CMAKE_OPTIONS} \ - ${SOURCES_DIR}/fiat - make -j8 install + ${CMAKE_OPTIONS} + cmake --build ${BUILDS_DIR}/fiat + cmake --install ${BUILDS_DIR}/fiat echo "Installing ectrans" [[ -d ${SOURCES_DIR}/ectrans ]] || git clone -b master https://github.com/ecmwf-ifs/ectrans ${SOURCES_DIR}/ectrans - mkdir -p ${BUILDS_DIR}/ectrans && cd ${BUILDS_DIR}/ectrans - cmake -DCMAKE_INSTALL_PREFIX=${PREFIX} \ + cmake -S ${SOURCES_DIR}/ectrans -B ${BUILDS_DIR}/ectrans -DCMAKE_INSTALL_PREFIX=${PREFIX} \ -DCMAKE_BUILD_TYPE=${BUILD_TYPE} \ -DENABLE_TESTS=OFF \ - ${CMAKE_OPTIONS} \ - ${SOURCES_DIR}/ectrans - make -j8 install + ${CMAKE_OPTIONS} + cmake --build ${BUILDS_DIR}/ectrans + cmake --install ${BUILDS_DIR}/ectrans fi @@ -212,15 +203,15 @@ if ${with_deps}; then # Note: known to work version: 80187f11 [[ -d ${SOURCES_DIR}/gridtools ]] || git clone -b master https://github.com/gridtools/gridtools ${SOURCES_DIR}/gridtools ( cd ${SOURCES_DIR}/gridtools && git checkout 80187f11 ) - mkdir -p ${BUILDS_DIR}/gridtools && cd ${BUILDS_DIR}/gridtools - cmake ${ECBUILD_MODULE_PATH} \ + cmake ${SOURCES_DIR}/gridtools -B ${BUILDS_DIR}/gridtools + ${ECBUILD_MODULE_PATH} \ -DCMAKE_INSTALL_PREFIX=${PREFIX} \ -DCMAKE_BUILD_TYPE=${BUILD_TYPE} \ -DBUILD_TESTING=OFF \ -DGT_ENABLE_OPENMP=OFF \ - ${CMAKE_OPTIONS} \ - ${SOURCES_DIR}/gridtools - make -j8 install + ${CMAKE_OPTIONS} + cmake --build ${BUILDS_DIR}/gridtools + cmake --install ${BUILDS_DIR}/gridtools ### Fix non-standard GridTools installation detection if [[ -f ${PREFIX}/lib/cmake/GridToolsConfig.cmake ]]; then export GridTools_DIR=${PREFIX}/lib/cmake # see GridTools issue (https://github.com/GridTools/gridtools/issues/1395) @@ -231,12 +222,11 @@ fi ### Install atlas echo "Installing atlas" -mkdir -p ${BUILDS_DIR}/atlas && cd ${BUILDS_DIR}/atlas -cmake ${ECBUILD_MODULE_PATH} \ +cmake -S ${SCRIPT_DIR}/.. -B ${BUILDS_DIR}/atlas \ -DCMAKE_INSTALL_PREFIX=${PREFIX} \ -DCMAKE_BUILD_TYPE=${BUILD_TYPE} \ -DENABLE_SANDBOX=ON \ - ${CMAKE_OPTIONS} \ - ${SCRIPT_DIR}/.. -make -j8 -make install + ${CMAKE_OPTIONS} +cmake --build ${BUILDS_DIR}/atlas +cmake --install ${BUILDS_DIR}/atlas + From 5ce300019389eebefb9bddb836bea87040a94034 Mon Sep 17 00:00:00 2001 From: Willem Deconinck Date: Fri, 27 Oct 2023 12:07:52 +0200 Subject: [PATCH 02/25] atlas_io: add [[maybe_unused]] attribute --- atlas_io/src/atlas_io/detail/Defaults.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/atlas_io/src/atlas_io/detail/Defaults.h b/atlas_io/src/atlas_io/detail/Defaults.h index c3691cf36..63a314d91 100644 --- a/atlas_io/src/atlas_io/detail/Defaults.h +++ b/atlas_io/src/atlas_io/detail/Defaults.h @@ -18,23 +18,23 @@ namespace atlas { namespace io { namespace defaults { -static std::string checksum_algorithm() { +[[maybe_unused]] static std::string checksum_algorithm() { static std::string checksum = eckit::Resource("atlas.io.checksum.algorithm;$ATLAS_IO_CHECKSUM", "xxh64"); return checksum; } -static bool checksum_read() { +[[maybe_unused]] static bool checksum_read() { static bool checksum = eckit::Resource("atlas.io.checksum.read;$ATLAS_IO_CHECKSUM_READ", true); return checksum; } -static bool checksum_write() { +[[maybe_unused]] static bool checksum_write() { static bool checksum = eckit::Resource("atlas.io.checksum.write;$ATLAS_IO_CHECKSUM_WRITE", true); return checksum; } -static const std::string& compression_algorithm() { +[[maybe_unused]] static const std::string& compression_algorithm() { static std::string compression = eckit::Resource("atlas.io.compression;$ATLAS_IO_COMPRESSION", "none"); return compression; } From 2986e42c7844df775422e2bddb5355a489eb472f Mon Sep 17 00:00:00 2001 From: Willem Deconinck Date: Mon, 6 Nov 2023 11:29:11 +0100 Subject: [PATCH 03/25] Enable support for ATLAS_PLUGIN_PATH when eckit version 1.24.4 is detected --- src/atlas/library/Library.cc | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/atlas/library/Library.cc b/src/atlas/library/Library.cc index 0ae5c565c..875ae8327 100644 --- a/src/atlas/library/Library.cc +++ b/src/atlas/library/Library.cc @@ -161,15 +161,13 @@ Library::Library(): trace_report_(getEnv("ATLAS_TRACE_REPORT", false)), atlas_io_trace_hook_(::atlas::io::TraceHookRegistry::invalidId()) { std::string ATLAS_PLUGIN_PATH = getEnv("ATLAS_PLUGIN_PATH"); -#if ATLAS_ECKIT_VERSION_AT_LEAST(1, 25, 0) || ATLAS_ECKIT_DEVELOP +#if ATLAS_ECKIT_VERSION_AT_LEAST(1, 24, 4) eckit::system::LibraryManager::addPluginSearchPath(ATLAS_PLUGIN_PATH); #else if (ATLAS_PLUGIN_PATH.size()) { std::cout << "WARNING: atlas::Library discovered environment variable ATLAS_PLUGIN_PATH. " << "Currently used version of eckit (" << eckit_version_str() << " [" << eckit_git_sha1() << "]) " - << "does not support adding plugin search paths. " - << "When using latest eckit develop branch, please rebuild Atlas with " - << "CMake argument -DENABLE_ECKIT_DEVELOP=ON\n" + << "Support started in eckit version 1.24.4 .\n" << "Alternatively, use combination of environment variables 'PLUGINS_MANIFEST_PATH' " << "and 'LD_LIBRARY_PATH (for UNIX) / DYLD_LIBRARY_PATH (for macOS)' (colon-separated lists)\n" << std::endl; } From c33e1817accde6b7380c0bd0a3d4e70802f9efe0 Mon Sep 17 00:00:00 2001 From: Willem Deconinck Date: Mon, 6 Nov 2023 12:13:32 +0100 Subject: [PATCH 04/25] Update install script, to be able to compile atlas-orca plugin --- tools/install.sh | 40 +++++++++++++++++++++++++++------------- 1 file changed, 27 insertions(+), 13 deletions(-) diff --git a/tools/install.sh b/tools/install.sh index 2f6b051e4..14973b121 100755 --- a/tools/install.sh +++ b/tools/install.sh @@ -19,10 +19,11 @@ export PATH=$SCRIPT_DIR:$PATH PREFIX=$(pwd)/install CMAKE_OPTIONS="" with_gridtools=false -with_trans=false +with_ectrans=false with_fftw=false with_qhull=false with_deps=false +with_atlas_orca=false WORK_DIR=$(pwd) BUILD_TYPE=RelWithDebInfo @@ -33,7 +34,8 @@ function print_help { echo "Usage:" echo "" echo " install.sh [--with-deps] [--prefix ] [--build-type ] [--cmake ] [--parallel ] \\" - echo " [--enable-gridtools] [--enable-trans] [--enable-fftw] [--enable-qhull] [--work-dir ] [--help]" + echo " [--with-atlas-orca] \\" + echo " [--enable-gridtools] [--enable-ectrans] [--enable-fftw] [--enable-qhull] [--work-dir ] [--help]" echo "" echo " " echo "" @@ -44,11 +46,12 @@ function print_help { echo " --build-type Build type for atlas (and its dependencies if requested with '--with-deps')" echo " Possible values are ( Release | RelWithDebInfo | Debug )" echo " --cmake Extra CMake Options to configure atlas and its dependencies" - echo " --enable-trans Enable optional trans dependency" + echo " --enable-ectrans Enable optional trans dependency" echo " --enable-gridtools Enable optional gridtools dependency (only has effect when '--with-deps' is also used)" echo " ! Requires Boost ! Specify Boost_ROOT environment variable to a fairly recent Boost installation" echo " --enable-fftw Enable optional fftw dependency required for spectral transforms" echo " --enable-qhull Enable optional qhull required for meshing of unstructured grids" + echo " --with-atlas-orca Enable optional atlas-orca plugin for ORCA grids" echo " --work-dir Working directory where sources and builds live" echo " --help Print this help" echo "" @@ -84,6 +87,9 @@ while [ $# != 0 ]; do "--enable-qhull") with_qhull=true; ;; + "--with-atlas-orca") + with_atlas_orca=true; + ;; "--prefix") PREFIX="$2"; shift ;; @@ -137,7 +143,7 @@ if ${with_deps}; then echo "Installing ecbuild" [[ -d ${SOURCES_DIR}/ecbuild ]] || git clone -b master https://github.com/ecmwf/ecbuild ${SOURCES_DIR}/ecbuild cmake -S ${SOURCES_DIR}/ecbuild -B ${BUILDS_DIR}/ecbuild -DCMAKE_INSTALL_PREFIX=${PREFIX} -DENABLE_TESTS=OFF - cmake --build ${BUILDS_DIR}/ecbuild + cmake --build ${BUILDS_DIR}/ecbuild cmake --install ${BUILDS_DIR}/ecbuild ### Install eckit @@ -156,12 +162,11 @@ if ${with_deps}; then -DENABLE_CUDA=OFF \ -DENABLE_AEC=OFF \ -DENABLE_XXHASH=OFF \ - -DENABLE_LZ4=OFF \ -DENABLE_JEMALLOC=OFF \ -DENABLE_BZIP2=OFF \ -DCMAKE_DISABLE_FIND_PACKAGE_Doxygen=ON \ ${CMAKE_OPTIONS} - cmake --build ${BUILDS_DIR}/eckit + cmake --build ${BUILDS_DIR}/eckit cmake --install ${BUILDS_DIR}/eckit ### Install fckit @@ -177,17 +182,17 @@ if ${with_deps}; then ### Install fiat + ectrans (optional, off by default) if ${with_trans}; then echo "Installing fiat" - [[ -d ${SOURCES_DIR}/fiat ]] || git clone -b master https://github.com/ecmwf-ifs/fiat ${SOURCES_DIR}/fiat + [[ -d ${SOURCES_DIR}/fiat ]] || git clone -b main https://github.com/ecmwf-ifs/fiat ${SOURCES_DIR}/fiat cmake -S ${SOURCES_DIR}/fiat -B ${BUILDS_DIR}/fiat \ -DCMAKE_INSTALL_PREFIX=${PREFIX} \ -DCMAKE_BUILD_TYPE=${BUILD_TYPE} \ -DENABLE_TESTS=OFF \ ${CMAKE_OPTIONS} - cmake --build ${BUILDS_DIR}/fiat + cmake --build ${BUILDS_DIR}/fiat cmake --install ${BUILDS_DIR}/fiat echo "Installing ectrans" - [[ -d ${SOURCES_DIR}/ectrans ]] || git clone -b master https://github.com/ecmwf-ifs/ectrans ${SOURCES_DIR}/ectrans + [[ -d ${SOURCES_DIR}/ectrans ]] || git clone -b main https://github.com/ecmwf-ifs/ectrans ${SOURCES_DIR}/ectrans cmake -S ${SOURCES_DIR}/ectrans -B ${BUILDS_DIR}/ectrans -DCMAKE_INSTALL_PREFIX=${PREFIX} \ -DCMAKE_BUILD_TYPE=${BUILD_TYPE} \ -DENABLE_TESTS=OFF \ @@ -203,14 +208,13 @@ if ${with_deps}; then # Note: known to work version: 80187f11 [[ -d ${SOURCES_DIR}/gridtools ]] || git clone -b master https://github.com/gridtools/gridtools ${SOURCES_DIR}/gridtools ( cd ${SOURCES_DIR}/gridtools && git checkout 80187f11 ) - cmake ${SOURCES_DIR}/gridtools -B ${BUILDS_DIR}/gridtools - ${ECBUILD_MODULE_PATH} \ + cmake -S ${SOURCES_DIR}/gridtools -B ${BUILDS_DIR}/gridtools \ -DCMAKE_INSTALL_PREFIX=${PREFIX} \ -DCMAKE_BUILD_TYPE=${BUILD_TYPE} \ -DBUILD_TESTING=OFF \ -DGT_ENABLE_OPENMP=OFF \ ${CMAKE_OPTIONS} - cmake --build ${BUILDS_DIR}/gridtools + cmake --build ${BUILDS_DIR}/gridtools cmake --install ${BUILDS_DIR}/gridtools ### Fix non-standard GridTools installation detection if [[ -f ${PREFIX}/lib/cmake/GridToolsConfig.cmake ]]; then @@ -227,6 +231,16 @@ cmake -S ${SCRIPT_DIR}/.. -B ${BUILDS_DIR}/atlas \ -DCMAKE_BUILD_TYPE=${BUILD_TYPE} \ -DENABLE_SANDBOX=ON \ ${CMAKE_OPTIONS} -cmake --build ${BUILDS_DIR}/atlas +cmake --build ${BUILDS_DIR}/atlas cmake --install ${BUILDS_DIR}/atlas +if ${with_atlas_orca}; then + echo "Installing atlas-orca" + [[ -d ${SOURCES_DIR}/atlas-orca ]] || git clone -b master https://github.com/ecmwf/atlas-orca ${SOURCES_DIR}/atlas-orca + cmake -S ${SOURCES_DIR}/atlas-orca -B ${BUILDS_DIR}/atlas-orca -DCMAKE_INSTALL_PREFIX=${PREFIX} \ + -DCMAKE_BUILD_TYPE=${BUILD_TYPE} \ + ${CMAKE_OPTIONS} + cmake --build ${BUILDS_DIR}/atlas-orca + cmake --install ${BUILDS_DIR}/atlas-orca +fi + From 62ab8751517a811a9a98ba2dbe21b80fa360fda9 Mon Sep 17 00:00:00 2001 From: Willem Deconinck Date: Fri, 3 Nov 2023 18:39:46 +0100 Subject: [PATCH 05/25] Remove duplicate test from atlas_io --- src/tests/io/CMakeLists.txt | 6 - src/tests/io/test_io_record.cc | 3 - src/tests/io/test_io_stream.cc | 211 --------------------------------- 3 files changed, 220 deletions(-) delete mode 100644 src/tests/io/test_io_stream.cc diff --git a/src/tests/io/CMakeLists.txt b/src/tests/io/CMakeLists.txt index 38b6633fa..3cfd7fa4e 100644 --- a/src/tests/io/CMakeLists.txt +++ b/src/tests/io/CMakeLists.txt @@ -13,12 +13,6 @@ ecbuild_add_test( TARGET atlas_test_io_encoding ENVIRONMENT ${ATLAS_TEST_ENVIRONMENT} ) -ecbuild_add_test( TARGET atlas_test_io_stream - SOURCES test_io_stream.cc - LIBS atlas - ENVIRONMENT ${ATLAS_TEST_ENVIRONMENT} -) - ecbuild_add_executable( TARGET atlas_test_io_record SOURCES test_io_record.cc LIBS atlas diff --git a/src/tests/io/test_io_record.cc b/src/tests/io/test_io_record.cc index 5b821eb41..852bb482e 100644 --- a/src/tests/io/test_io_record.cc +++ b/src/tests/io/test_io_record.cc @@ -21,9 +21,6 @@ #include "tests/AtlasTestEnvironment.h" -#include "atlas/io/atlas-io.h" - - namespace atlas { namespace test { diff --git a/src/tests/io/test_io_stream.cc b/src/tests/io/test_io_stream.cc deleted file mode 100644 index abb57e07a..000000000 --- a/src/tests/io/test_io_stream.cc +++ /dev/null @@ -1,211 +0,0 @@ -/* - * (C) Copyright 2013 ECMWF. - * - * This software is licensed under the terms of the Apache Licence Version 2.0 - * which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. - * In applying this licence, ECMWF does not waive the privileges and immunities - * granted to it by virtue of its status as an intergovernmental organisation - * nor does it submit to any jurisdiction. - */ - -#include "atlas_io/FileStream.h" -#include "atlas_io/Session.h" - -#include "eckit/io/FileHandle.h" -#include "eckit/io/PooledHandle.h" - -#include "tests/AtlasTestEnvironment.h" - - -namespace atlas { -namespace test { - -CASE("Stream interoperability with eckit::DataHandle") { - SECTION("own pointer") { - io::Stream s; - { - eckit::DataHandle* datahandle = new eckit::FileHandle("test_io_session.data"); - datahandle->openForWrite(0); - s = io::Stream{datahandle}; - } - s.datahandle().close(); - } - SECTION("shared pointer") { - io::Stream s; - { - std::shared_ptr datahandle = std::make_shared("test_io_session.data"); - datahandle->openForWrite(0); - s = io::Stream{datahandle}; - } - s.datahandle().close(); - } - SECTION("reference") { - io::Stream s; - eckit::FileHandle datahandle("test_io_session.data"); - datahandle.openForWrite(0); - s = io::Stream{datahandle}; - s.datahandle().close(); - } -} - -CASE("Test seek-for-write works when opening OutputFileStream for append") { - std::string s1("write \n"); - std::string s2("append \n"); - std::string s3("overwrite\n"); - { - ATLAS_TRACE("write"); - io::Stream f = io::OutputFileStream("append-test"); - f.write(s1.c_str(), s1.size()); - } - { - ATLAS_TRACE("append"); - io::Stream f = io::OutputFileStream("append-test", io::Mode::append); - auto offset = f.position(); - f.write(s2.c_str(), s2.size()); - - // Rewind to beginning of append - f.seek(offset); - f.write(s3.c_str(), s3.size()); - } - { - ATLAS_TRACE("read"); - io::Stream f = io::InputFileStream("append-test"); - std::string expected = s1 + s3; - std::string read(expected.size(), ' '); - f.read(const_cast(read.data()), read.size()); - EXPECT_EQ(read, expected); - } -} - - -CASE("Opening same file in same scope") { - // Opening same file within same scope will avoid opening it multiple times, good for perfmance - - // write a file - { - io::OutputFileStream out("test_io_session.data"); - out.write("line1\n", 6); - out.write("line2\n", 6); - out.write("line3\n", 6); - } - - std::string l1(5, ' '), l2(5, ' '), l3(5, ' '); - - io::Stream f1 = io::InputFileStream{"test_io_session.data"}; - f1.seek(0 * 6); - f1.read(const_cast(l1.data()), 5); - - io::Stream f2 = io::InputFileStream{"test_io_session.data"}; - f2.seek(1 * 6); - f2.read(const_cast(l2.data()), 5); - - io::Stream f3 = io::InputFileStream{"test_io_session.data"}; - f3.seek(2 * 6); - f3.read(const_cast(l3.data()), 5); - - EXPECT_EQ(l1, "line1"); - EXPECT_EQ(l2, "line2"); - EXPECT_EQ(l3, "line3"); - - auto& pooled_handle = dynamic_cast(f1.datahandle()); - EXPECT_EQ(pooled_handle.nbOpens(), 1); - EXPECT_EQ(pooled_handle.nbSeeks(), 3); - EXPECT_EQ(pooled_handle.nbReads(), 3); -} - -CASE("Opening same file in parallel scopes") { - // Files are opened and closed within each scope, bad for performance - - // write a file - { - io::OutputFileStream out("test_io_session.data"); - out.write("line1\n", 6); - out.write("line2\n", 6); - out.write("line3\n", 6); - } - - std::string l1(5, ' '), l2(5, ' '), l3(5, ' '); - - { - io::Stream f1 = io::InputFileStream{"test_io_session.data"}; - f1.seek(0 * 6); - f1.read(const_cast(l1.data()), 5); - auto& pooled_handle = dynamic_cast(f1.datahandle()); - EXPECT_EQ(pooled_handle.nbOpens(), 1); - EXPECT_EQ(pooled_handle.nbSeeks(), 1); - EXPECT_EQ(pooled_handle.nbReads(), 1); - } - { - io::Stream f2 = io::InputFileStream{"test_io_session.data"}; - f2.seek(1 * 6); - f2.read(const_cast(l2.data()), 5); - auto& pooled_handle = dynamic_cast(f2.datahandle()); - EXPECT_EQ(pooled_handle.nbOpens(), 1); - EXPECT_EQ(pooled_handle.nbSeeks(), 1); - EXPECT_EQ(pooled_handle.nbReads(), 1); - } - { - io::Stream f3 = io::InputFileStream{"test_io_session.data"}; - f3.seek(2 * 6); - f3.read(const_cast(l3.data()), 5); - auto& pooled_handle = dynamic_cast(f3.datahandle()); - EXPECT_EQ(pooled_handle.nbOpens(), 1); - EXPECT_EQ(pooled_handle.nbSeeks(), 1); - EXPECT_EQ(pooled_handle.nbReads(), 1); - } -} - -CASE("Opening same file in parallel scopes with Session") { - // Declaring this in an outer scope will keep storage of InputFileStream - // within nested scopes, so that files will not be opened/closed repeatedly - - io::Session session; - - // write a file - { - io::OutputFileStream out("test_io_session.data"); - out.write("line1\n", 6); - out.write("line2\n", 6); - out.write("line3\n", 6); - } - - - std::string l1(5, ' '), l2(5, ' '), l3(5, ' '); - - { - io::Stream f1 = io::InputFileStream{"test_io_session.data"}; - f1.seek(0 * 6); - f1.read(const_cast(l1.data()), 5); - auto& pooled_handle = dynamic_cast(f1.datahandle()); - EXPECT_EQ(pooled_handle.nbOpens(), 1); - EXPECT_EQ(pooled_handle.nbSeeks(), 1); - EXPECT_EQ(pooled_handle.nbReads(), 1); - } - { - io::Stream f2 = io::InputFileStream{"test_io_session.data"}; - f2.seek(1 * 6); - f2.read(const_cast(l2.data()), 5); - auto& pooled_handle = dynamic_cast(f2.datahandle()); - EXPECT_EQ(pooled_handle.nbOpens(), 1); - EXPECT_EQ(pooled_handle.nbSeeks(), 2); - EXPECT_EQ(pooled_handle.nbReads(), 2); - } - { - io::Stream f3 = io::InputFileStream{"test_io_session.data"}; - f3.seek(2 * 6); - f3.read(const_cast(l3.data()), 5); - auto& pooled_handle = dynamic_cast(f3.datahandle()); - EXPECT_EQ(pooled_handle.nbOpens(), 1); - EXPECT_EQ(pooled_handle.nbSeeks(), 3); - EXPECT_EQ(pooled_handle.nbReads(), 3); - } -} - - -} // namespace test -} // namespace atlas - - -int main(int argc, char** argv) { - return atlas::test::run(argc, argv); -} From 5ea733a88fd6bb57f73cb2fa588404f5dd260b04 Mon Sep 17 00:00:00 2001 From: Willem Deconinck Date: Mon, 6 Nov 2023 12:01:49 +0100 Subject: [PATCH 06/25] Reduce header dependency on atlas_io to prepare for eckit_codec adaptor library --- src/atlas/io/ArrayAdaptor.cc | 6 ------ src/atlas/io/ArrayAdaptor.h | 8 +------- src/atlas/io/VectorAdaptor.h | 4 +--- 3 files changed, 2 insertions(+), 16 deletions(-) diff --git a/src/atlas/io/ArrayAdaptor.cc b/src/atlas/io/ArrayAdaptor.cc index c8aafbe80..a8493e4d7 100644 --- a/src/atlas/io/ArrayAdaptor.cc +++ b/src/atlas/io/ArrayAdaptor.cc @@ -14,12 +14,6 @@ #include #include "atlas/array/Array.h" -#include "atlas_io/Data.h" -#include "atlas_io/Exceptions.h" -#include "atlas_io/Metadata.h" -#include "atlas_io/atlas_compat.h" -#include "atlas_io/detail/Assert.h" -#include "atlas_io/types/array/ArrayReference.h" namespace atlas { namespace array { diff --git a/src/atlas/io/ArrayAdaptor.h b/src/atlas/io/ArrayAdaptor.h index 6a786cbfe..aa330186f 100644 --- a/src/atlas/io/ArrayAdaptor.h +++ b/src/atlas/io/ArrayAdaptor.h @@ -10,13 +10,7 @@ #pragma once -namespace atlas { -namespace io { -class Metadata; -class Data; -class ArrayReference; -} // namespace io -} // namespace atlas +#include "atlas-io.h" namespace atlas { namespace array { diff --git a/src/atlas/io/VectorAdaptor.h b/src/atlas/io/VectorAdaptor.h index 633a1798d..89900ff9b 100644 --- a/src/atlas/io/VectorAdaptor.h +++ b/src/atlas/io/VectorAdaptor.h @@ -12,9 +12,7 @@ #include "atlas/util/vector.h" -#include "atlas_io/Data.h" -#include "atlas_io/Metadata.h" -#include "atlas_io/types/array/ArrayReference.h" +#include "atlas-io.h" namespace atlas { From f0d91143266d5dd0b627c7a70a6d2075881d5d10 Mon Sep 17 00:00:00 2001 From: Willem Deconinck Date: Wed, 8 Nov 2023 17:27:03 +0100 Subject: [PATCH 07/25] Add atlas_TriangularMeshBuilder with Fortran interface for serial meshes --- src/atlas/CMakeLists.txt | 2 + src/atlas/mesh/MeshBuilder.cc | 54 ++++++- src/atlas/mesh/MeshBuilder.h | 40 +++++- src/atlas/mesh/detail/MeshBuilderIntf.cc | 49 +++++++ src/atlas/mesh/detail/MeshBuilderIntf.h | 33 +++++ src/atlas_f/CMakeLists.txt | 4 + src/atlas_f/atlas_module.F90 | 2 + src/atlas_f/mesh/atlas_MeshBuilder_module.F90 | 120 ++++++++++++++++ src/tests/mesh/CMakeLists.txt | 14 ++ .../fctest_mesh_triangular_mesh_builder.F90 | 132 ++++++++++++++++++ .../mesh/test_mesh_triangular_mesh_builder.cc | 73 ++++++++++ 11 files changed, 519 insertions(+), 4 deletions(-) create mode 100644 src/atlas/mesh/detail/MeshBuilderIntf.cc create mode 100644 src/atlas/mesh/detail/MeshBuilderIntf.h create mode 100644 src/atlas_f/mesh/atlas_MeshBuilder_module.F90 create mode 100644 src/tests/mesh/fctest_mesh_triangular_mesh_builder.F90 create mode 100644 src/tests/mesh/test_mesh_triangular_mesh_builder.cc diff --git a/src/atlas/CMakeLists.txt b/src/atlas/CMakeLists.txt index 2b92a933b..3655519be 100644 --- a/src/atlas/CMakeLists.txt +++ b/src/atlas/CMakeLists.txt @@ -364,6 +364,8 @@ mesh/detail/MeshImpl.cc mesh/detail/MeshImpl.h mesh/detail/MeshIntf.cc mesh/detail/MeshIntf.h +mesh/detail/MeshBuilderIntf.cc +mesh/detail/MeshBuilderIntf.h mesh/detail/PartitionGraph.cc mesh/detail/PartitionGraph.h mesh/detail/AccumulateFacets.h diff --git a/src/atlas/mesh/MeshBuilder.cc b/src/atlas/mesh/MeshBuilder.cc index 32020d997..40155399f 100644 --- a/src/atlas/mesh/MeshBuilder.cc +++ b/src/atlas/mesh/MeshBuilder.cc @@ -160,6 +160,33 @@ Mesh MeshBuilder::operator()(size_t nb_nodes, const double lons[], const double const gidx_t tri_global_indices[], size_t nb_quads, const gidx_t quad_boundary_nodes[], const gidx_t quad_global_indices[], const eckit::Configuration& config) const { + return this->operator()( + nb_nodes, global_indices, + lons, lats, 1, 1, + lons, lats, 1, 1, + ghosts, partitions, remote_indices, remote_index_base, + nb_tris, tri_global_indices, tri_boundary_nodes, + nb_quads, quad_global_indices, quad_boundary_nodes, + config + ); +} + +Mesh MeshBuilder::operator()(size_t nb_nodes, const gidx_t global_indices[], + const double x[], const double y[], size_t xstride, size_t ystride, + const double lon[], const double lat[], size_t lonstride, size_t latstride, + const int ghosts[], const int partitions[], const idx_t remote_index[], const idx_t remote_index_base, + size_t nb_triags, const gidx_t triag_global_index[], const gidx_t triag_nodes_global[], + size_t nb_quads, const gidx_t quad_global_index[], const gidx_t quad_nodes_global[], + const eckit::Configuration& config) const { + auto* lons = lon; + auto* lats = lat; + auto* remote_indices = remote_index; + auto nb_tris = nb_triags; + auto* tri_boundary_nodes = triag_nodes_global; + auto* tri_global_indices = triag_global_index; + auto* quad_boundary_nodes = quad_nodes_global; + auto* quad_global_indices = quad_global_index; + // Get MPI comm from config name or fall back to atlas default comm auto mpi_comm_name = [](const auto& config) { return config.getString("mpi_comm", atlas::mpi::comm().name()); @@ -199,9 +226,8 @@ Mesh MeshBuilder::operator()(size_t nb_nodes, const double lons[], const double auto halo = array::make_view(mesh.nodes().halo()); for (size_t i = 0; i < nb_nodes; ++i) { - xy(i, size_t(XX)) = lons[i]; - xy(i, size_t(YY)) = lats[i]; - // Identity projection, therefore (lon,lat) = (x,y) + xy(i, size_t(XX)) = x[i]; + xy(i, size_t(YY)) = y[i]; lonlat(i, size_t(LON)) = lons[i]; lonlat(i, size_t(LAT)) = lats[i]; ghost(i) = ghosts[i]; @@ -274,5 +300,27 @@ Mesh MeshBuilder::operator()(size_t nb_nodes, const double lons[], const double //---------------------------------------------------------------------------------------------------------------------- +Mesh TriangularMeshBuilder::operator()(size_t nb_nodes, const gidx_t nodes_global_index[], const double x[], const double y[], const double lon[], const double lat[], + size_t nb_triags, const gidx_t triangle_global_index[], const gidx_t triangle_nodes_global_index[]) const { + std::vector ghost(nb_nodes,0); + std::vector partition(nb_nodes,0); + std::vector remote_index(nb_nodes); + idx_t remote_index_base = 0; + std::iota(remote_index.begin(), remote_index.end(), remote_index_base); + + size_t nb_quads = 0; + std::vector quad_nodes_global_index; + std::vector quad_global_index; + + return meshbuilder_( + nb_nodes, nodes_global_index, + x, y, 1, 1, lon, lat, 1, 1, + ghost.data(), partition.data(), remote_index.data(), remote_index_base, + nb_triags, triangle_global_index, triangle_nodes_global_index, + nb_quads, quad_global_index.data(), quad_nodes_global_index.data()); +} + +//---------------------------------------------------------------------------------------------------------------------- + } // namespace mesh } // namespace atlas diff --git a/src/atlas/mesh/MeshBuilder.h b/src/atlas/mesh/MeshBuilder.h index b7ab42547..d5c1b2304 100644 --- a/src/atlas/mesh/MeshBuilder.h +++ b/src/atlas/mesh/MeshBuilder.h @@ -35,7 +35,7 @@ namespace mesh { * * The Mesh's Grid can be initialized via the call operator's optional config argument. */ -class MeshBuilder { +class MeshBuilder : public eckit::Owned { public: MeshBuilder(const eckit::Configuration& = util::NoConfig()) {} @@ -69,6 +69,15 @@ class MeshBuilder { const gidx_t quad_global_indices[], const eckit::Configuration& config = util::NoConfig()) const; + Mesh operator()(size_t nb_nodes, const gidx_t global_index[], + const double x[], const double y[], size_t xstride, size_t ystride, + const double lon[], const double lat[], size_t lonstride, size_t latstride, + const int ghost[], const int partition[], const idx_t remote_index[], const idx_t remote_index_base, + size_t nb_triags, const gidx_t triag_global_index[], const gidx_t triag_nodes_global[], + size_t nb_quads, const gidx_t quad_global_index[], const gidx_t quad_nodes_global[], + const eckit::Configuration& config = util::NoConfig()) const; + + /** * \brief C++-interface to construct a Mesh from external connectivity data * @@ -86,5 +95,34 @@ class MeshBuilder { //----------------------------------------------------------------------------- + +class TriangularMeshBuilder { +public: + TriangularMeshBuilder(const eckit::Configuration& config = util::NoConfig()) : + meshbuilder_(config) {} + + /** + * \brief C-interface to construct a Triangular Mesh from external connectivity data + * + * The inputs x, y, lons, lats, ghost, global_index, remote_index, and partition are vectors of + * size nb_nodes, ranging over the nodes locally owned by (or in the ghost nodes of) the MPI + * task. The global index is a uniform labeling of the nodes across all MPI tasks; the remote + * index is a remote_index_base-based vector index for the node on its owning task. + * + * The triangle connectivities (boundary_nodes and global_index) are vectors ranging over the + * cells owned by the MPI task. Each cell is defined by a list of nodes defining its boundary; + * note that each boundary node must be locally known (whether as an owned of ghost node on the + * MPI task), in other words, must be an element of the node global_indices. The boundary nodes + * are ordered node-varies-fastest, element-varies-slowest order. The cell global index is, + * here also, a uniform labeling over the of the cells across all MPI tasks. + */ + Mesh operator()(size_t nb_nodes, const gidx_t node_global_index[], const double x[], const double y[], const double lon[], const double lat[], + size_t nb_triags, const gidx_t triangle_global_index[], const gidx_t triangle_nodes_global_index[]) const; +private: + MeshBuilder meshbuilder_; +}; + +//----------------------------------------------------------------------------- + } // namespace mesh } // namespace atlas diff --git a/src/atlas/mesh/detail/MeshBuilderIntf.cc b/src/atlas/mesh/detail/MeshBuilderIntf.cc new file mode 100644 index 000000000..3d04fa75b --- /dev/null +++ b/src/atlas/mesh/detail/MeshBuilderIntf.cc @@ -0,0 +1,49 @@ +/* + * (C) Copyright 2023 ECMWF. + * + * This software is licensed under the terms of the Apache Licence Version 2.0 + * which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. + * In applying this licence, ECMWF does not waive the privileges and immunities + * granted to it by virtue of its status as an intergovernmental organisation + * nor does it submit to any jurisdiction. + */ + +#include "atlas/mesh/detail/MeshBuilderIntf.h" +#include "atlas/runtime/Exception.h" + +namespace atlas { +namespace mesh { + +//---------------------------------------------------------------------------------------------------------------------- +// C wrapper interfaces to C++ routines + +TriangularMeshBuilder* atlas__TriangularMeshBuilder__new() { + return new TriangularMeshBuilder(); +} + +void atlas__TriangularMeshBuilder__delete(TriangularMeshBuilder* This) { + ATLAS_ASSERT(This != nullptr, "Cannot access uninitialisd atlas_TriangularMeshBuilder"); + delete This; +} + +Mesh::Implementation* atlas__TriangularMeshBuilder__operator(TriangularMeshBuilder* This, + size_t nb_nodes, const gidx_t node_global_index[], const double x[], const double y[], const double lon[], const double lat[], + size_t nb_triags, const gidx_t triangle_global_index[], const gidx_t triangle_nodes_global_index[]) { + + ATLAS_ASSERT(This != nullptr, "Cannot access uninitialisd atlas_TriangularMeshBuilder"); + + Mesh::Implementation* m; + { + Mesh mesh = This->operator()(nb_nodes, node_global_index, x, y, lon, lat, + nb_triags, triangle_global_index, triangle_nodes_global_index); + mesh.get()->attach(); + m = mesh.get(); + } + m->detach(); + return m; +} + +//---------------------------------------------------------------------------------------------------------------------- + +} // namespace mesh +} // namespace atlas diff --git a/src/atlas/mesh/detail/MeshBuilderIntf.h b/src/atlas/mesh/detail/MeshBuilderIntf.h new file mode 100644 index 000000000..4b5d5eb11 --- /dev/null +++ b/src/atlas/mesh/detail/MeshBuilderIntf.h @@ -0,0 +1,33 @@ +/* + * (C) Copyright 2023 ECMWF. + * + * This software is licensed under the terms of the Apache Licence Version 2.0 + * which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. + * In applying this licence, ECMWF does not waive the privileges and immunities + * granted to it by virtue of its status as an intergovernmental organisation + * nor does it submit to any jurisdiction. + */ + +#pragma once + +#include "atlas/mesh/MeshBuilder.h" + +//---------------------------------------------------------------------------------------------------------------------- + +namespace atlas { +namespace mesh { + +// C wrapper interfaces to C++ routines +extern "C" { +TriangularMeshBuilder* atlas__TriangularMeshBuilder__new(); +void atlas__TriangularMeshBuilder__delete(TriangularMeshBuilder* This); + +Mesh::Implementation* atlas__TriangularMeshBuilder__operator(TriangularMeshBuilder* This, + size_t nb_nodes, const gidx_t node_global_index[], const double x[], const double y[], const double lon[], const double lat[], + size_t nb_triags, const gidx_t triangle_global_index[], const gidx_t triangle_nodes_global_index[]); +} + +//---------------------------------------------------------------------------------------------------------------------- + +} // namespace mesh +} // namespace atlas diff --git a/src/atlas_f/CMakeLists.txt b/src/atlas_f/CMakeLists.txt index f01da0392..7075be1bb 100644 --- a/src/atlas_f/CMakeLists.txt +++ b/src/atlas_f/CMakeLists.txt @@ -83,6 +83,9 @@ generate_fortran_bindings(FORTRAN_BINDINGS ../atlas/domain/detail/Domain.h generate_fortran_bindings(FORTRAN_BINDINGS ../atlas/mesh/detail/MeshIntf.h MODULE atlas_mesh_c_binding OUTPUT atlas_mesh_c_binding.f90 ) +generate_fortran_bindings(FORTRAN_BINDINGS ../atlas/mesh/detail/MeshBuilderIntf.h + MODULE atlas_meshbuilder_c_binding + OUTPUT atlas_meshbuilder_c_binding.f90 ) generate_fortran_bindings(FORTRAN_BINDINGS ../atlas/mesh/Nodes.h) generate_fortran_bindings(FORTRAN_BINDINGS ../atlas/mesh/Connectivity.h) generate_fortran_bindings(FORTRAN_BINDINGS ../atlas/mesh/HybridElements.h) @@ -219,6 +222,7 @@ ecbuild_add_library( TARGET atlas_f grid/atlas_GridDistribution_module.F90 grid/atlas_Vertical_module.F90 grid/atlas_Partitioner_module.F90 + mesh/atlas_MeshBuilder_module.F90 mesh/atlas_MeshGenerator_module.F90 mesh/atlas_Mesh_module.F90 mesh/atlas_mesh_Nodes_module.F90 diff --git a/src/atlas_f/atlas_module.F90 b/src/atlas_f/atlas_module.F90 index 4e184c8a6..d82553e86 100644 --- a/src/atlas_f/atlas_module.F90 +++ b/src/atlas_f/atlas_module.F90 @@ -129,6 +129,8 @@ module atlas_module use atlas_Nabla_module, only: & & atlas_Nabla #endif +use atlas_meshbuilder_module, only : & + & atlas_TriangularMeshBuilder use atlas_mesh_actions_module, only: & & atlas_build_parallel_fields, & & atlas_build_nodes_parallel_fields, & diff --git a/src/atlas_f/mesh/atlas_MeshBuilder_module.F90 b/src/atlas_f/mesh/atlas_MeshBuilder_module.F90 new file mode 100644 index 000000000..5b1fce4dd --- /dev/null +++ b/src/atlas_f/mesh/atlas_MeshBuilder_module.F90 @@ -0,0 +1,120 @@ +! (C) Copyright 2023 ECMWF. +! +! This software is licensed under the terms of the Apache Licence Version 2.0 +! which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. +! In applying this licence, ECMWF does not waive the privileges and immunities +! granted to it by virtue of its status as an intergovernmental organisation nor +! does it submit to any jurisdiction. + +#include "atlas/atlas_f.h" + +module atlas_MeshBuilder_module + + +use fckit_owned_object_module, only: fckit_owned_object + +implicit none + +private :: fckit_owned_object + +public :: atlas_TriangularMeshBuilder + +private + +!-----------------------------! +! atlas_TriangularMeshBuilder ! +!-----------------------------! + +!------------------------------------------------------------------------------ +TYPE, extends(fckit_owned_object) :: atlas_TriangularMeshBuilder +contains + procedure, public :: build => atlas_TriangularMeshBuilder__build + +#if FCKIT_FINAL_NOT_INHERITING + final :: atlas_TriangularMeshBuilder__final_auto +#endif + +END TYPE atlas_TriangularMeshBuilder + +interface atlas_TriangularMeshBuilder + module procedure atlas_TriangularMeshBuilder__cptr + module procedure atlas_TriangularMeshBuilder__config +end interface + +!------------------------------------------------------------------------------ + + +!======================================================== +contains +!======================================================== + + +function atlas_TriangularMeshBuilder__cptr(cptr) result(this) + use, intrinsic :: iso_c_binding, only: c_ptr + type(atlas_TriangularMeshBuilder) :: this + type(c_ptr), intent(in) :: cptr + call this%reset_c_ptr( cptr ) + call this%return() +end function + +function atlas_TriangularMeshBuilder__config(config) result(this) + use fckit_c_interop_module, only: c_str + use atlas_MeshBuilder_c_binding + use atlas_Config_module, only: atlas_Config + type(atlas_TriangularMeshBuilder) :: this + type(atlas_Config), intent(in), optional :: config + call this%reset_c_ptr( atlas__TriangularMeshBuilder__new() ) + call this%return() +end function + + +! Mesh operator()(size_t nb_nodes, const gidx_t node_global_index[], const double x[], const double y[], const double lon[], const double lat[], +! size_t nb_triags, const gidx_t triangle_global_index[], const gidx_t triangle_nodes_global_index[]) const; + +function atlas_TriangularMeshBuilder__build(this, & + nb_nodes, node_global_index, x, y, lon, lat, & + nb_triags, triag_global_index, triag_nodes) result(mesh) + use, intrinsic :: iso_c_binding, only: c_double, c_size_t + use atlas_MeshBuilder_c_binding + use atlas_Mesh_module, only: atlas_Mesh + use atlas_kinds_module, only : ATLAS_KIND_GIDX + use fckit_array_module, only : array_strides, array_view1d + + type(atlas_Mesh) :: mesh + class(atlas_TriangularMeshBuilder), intent(in) :: this + integer, intent(in) :: nb_nodes + integer(ATLAS_KIND_GIDX), intent(in) :: node_global_index(:) + real(c_double), contiguous, intent(in) :: x(:), y(:), lon(:), lat(:) + integer, intent(in) :: nb_triags + integer(ATLAS_KIND_GIDX), intent(in) :: triag_global_index(nb_triags) + integer(ATLAS_KIND_GIDX), intent(in) :: triag_nodes(3,nb_triags) + + integer(ATLAS_KIND_GIDX), pointer :: triag_nodes_1d(:) + triag_nodes_1d => array_view1d( triag_nodes, int(0,ATLAS_KIND_GIDX) ) + + call mesh%reset_c_ptr() ! Somehow needed with PGI/16.7 and build-type "bit" + mesh = atlas_Mesh( atlas__TriangularMeshBuilder__operator(this%CPTR_PGIBUG_A, & + & int(nb_nodes,c_size_t), node_global_index, x, y, lon, lat, & + & int(nb_triags,c_size_t), triag_global_index, triag_nodes_1d) ) + call mesh%return() +end function + + +!------------------------------------------------------------------------------- + +#if FCKIT_FINAL_NOT_INHERITING +ATLAS_FINAL subroutine atlas_TriangularMeshBuilder__final_auto(this) + type(atlas_TriangularMeshBuilder), intent(inout) :: this +#if FCKIT_FINAL_DEBUGGING + write(0,*) "atlas_MeshBuilder__final_auto" +#endif +#if FCKIT_FINAL_NOT_PROPAGATING + call this%final() +#endif + FCKIT_SUPPRESS_UNUSED( this ) +end subroutine +#endif + +! ---------------------------------------------------------------------------------------- + +end module atlas_MeshBuilder_module diff --git a/src/tests/mesh/CMakeLists.txt b/src/tests/mesh/CMakeLists.txt index c901de5bc..f9d7825e3 100644 --- a/src/tests/mesh/CMakeLists.txt +++ b/src/tests/mesh/CMakeLists.txt @@ -24,6 +24,14 @@ if( HAVE_FCTEST ) ENVIRONMENT ${ATLAS_TEST_ENVIRONMENT} ) + add_fctest( TARGET atlas_fctest_mesh_triangular_mesh_builder + LINKER_LANGUAGE Fortran + CONDITION ON + SOURCES fctest_mesh_triangular_mesh_builder.F90 + LIBS atlas_f + ENVIRONMENT ${ATLAS_TEST_ENVIRONMENT} + ) + add_fctest( TARGET atlas_fctest_connectivity LINKER_LANGUAGE Fortran SOURCES fctest_connectivity.F90 @@ -135,6 +143,12 @@ ecbuild_add_test( TARGET atlas_test_mesh_builder_parallel ENVIRONMENT ${ATLAS_TEST_ENVIRONMENT} ) +ecbuild_add_test( TARGET atlas_test_mesh_triangular_mesh_builder + SOURCES test_mesh_triangular_mesh_builder.cc + LIBS atlas + ENVIRONMENT ${ATLAS_TEST_ENVIRONMENT} +) + ecbuild_add_executable( TARGET atlas_test_mesh_reorder SOURCES test_mesh_reorder.cc LIBS atlas diff --git a/src/tests/mesh/fctest_mesh_triangular_mesh_builder.F90 b/src/tests/mesh/fctest_mesh_triangular_mesh_builder.F90 new file mode 100644 index 000000000..efbca2f6a --- /dev/null +++ b/src/tests/mesh/fctest_mesh_triangular_mesh_builder.F90 @@ -0,0 +1,132 @@ +! (C) Copyright 2013 ECMWF. +! This software is licensed under the terms of the Apache Licence Version 2.0 +! which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. +! In applying this licence, ECMWF does not waive the privileges and immunities +! granted to it by virtue of its status as an intergovernmental organisation nor +! does it submit to any jurisdiction. + +! This File contains Unit Tests for testing the +! C++ / Fortran Interfaces to the Mesh Datastructure +! @author Willem Deconinck + +#include "fckit/fctest.h" + +! ----------------------------------------------------------------------------- + +TESTSUITE(fctest_atlas_TriangularMeshBuilder) + +! ----------------------------------------------------------------------------- + +TESTSUITE_INIT + use atlas_module + call atlas_library%initialise() +END_TESTSUITE_INIT + +! ----------------------------------------------------------------------------- + +TESTSUITE_FINALIZE + use atlas_module + call atlas_library%finalise() +END_TESTSUITE_FINALIZE + +! ----------------------------------------------------------------------------- + +TEST( test_mesbuilder ) + use, intrinsic :: iso_c_binding + use atlas_module + implicit none + type(atlas_Mesh) :: mesh + + integer :: nb_nodes + integer :: nb_triags + integer(ATLAS_KIND_GIDX), allocatable :: node_global_index(:) + integer(ATLAS_KIND_GIDX), allocatable :: triag_global_index(:) + integer(ATLAS_KIND_GIDX), allocatable :: triag_nodes_global_index(:,:) + real(c_double), allocatable :: x(:), y(:), lon(:), lat(:) + + ! small mesh + ! + ! 1 ---- 5 ------- 6 + ! | 3 / 4 \ 1 / 2 | + ! 2 ------ 3 ----- 4 + ! + nb_nodes = 6 + nb_triags = 4 + + allocate(node_global_index(nb_nodes)) + allocate(x(nb_nodes)) + allocate(y(nb_nodes)) + allocate(lon(nb_nodes)) + allocate(lat(nb_nodes)) + allocate(triag_global_index(nb_triags)) + allocate(triag_nodes_global_index(3,nb_triags)) + + node_global_index = [1, 2, 3, 4, 5, 6] + lon = [0.0, 0.0, 10.0, 15.0, 5.0, 15.0] + lat = [5.0, 0.0, 0.0, 0.0, 5.0, 5.0] + x = lon / 10._c_double + y = lat / 10._c_double + + triag_global_index = [1, 2, 3, 4] + triag_nodes_global_index = reshape([3,6,5 , 3,4,6, 2,5,1, 2,3,5], shape(triag_nodes_global_index)) + + + ! Manually build mesh + BLOCK + type(atlas_TriangularMeshBuilder) :: meshbuilder + meshbuilder = atlas_TriangularMeshBuilder() + mesh = meshbuilder%build(nb_nodes, node_global_index, x, y, lon, lat, & + nb_triags, triag_global_index, triag_nodes_global_index) + call meshbuilder%final() + END BLOCK + + ! Mesh should created now. Verify some fields + BLOCK + type(atlas_mesh_Nodes) :: nodes + real(c_double), pointer :: xy(:,:) + real(c_double), pointer :: lonlat(:,:) + integer(ATLAS_KIND_GIDX), pointer :: global_index(:) + + type(atlas_Field) :: field_xy + type(atlas_Field) :: field_lonlat + type(atlas_Field) :: field_global_index + + integer :: jnode + integer :: nb_nodes + nodes = mesh%nodes() + nb_nodes = nodes%size() + FCTEST_CHECK_EQUAL( nb_nodes, 6 ) + field_xy = nodes%xy() + field_lonlat = nodes%lonlat() + field_global_index = nodes%global_index() + call field_xy%data(xy) + call field_lonlat%data(lonlat) + call field_global_index%data(global_index) + do jnode=1,nb_nodes + FCTEST_CHECK_EQUAL( xy(:,jnode), ([x(jnode), y(jnode)])) + FCTEST_CHECK_EQUAL( lonlat(:,jnode), ([lon(jnode), lat(jnode)])) + FCTEST_CHECK_EQUAL( global_index(jnode), jnode) + enddo + call field_xy%final() + call field_lonlat%final() + call field_global_index%final() + call nodes%final() + END BLOCK + + ! Output mesh + BLOCK + type(atlas_Output) :: gmsh + gmsh = atlas_output_Gmsh("out.msh",coordinates="lonlat") + call gmsh%write(mesh) + call gmsh%final() + END BLOCK + + + call mesh%final() + +END_TEST + +! ----------------------------------------------------------------------------- + +END_TESTSUITE + diff --git a/src/tests/mesh/test_mesh_triangular_mesh_builder.cc b/src/tests/mesh/test_mesh_triangular_mesh_builder.cc new file mode 100644 index 000000000..27ed21a50 --- /dev/null +++ b/src/tests/mesh/test_mesh_triangular_mesh_builder.cc @@ -0,0 +1,73 @@ +/* + * (C) Copyright 2023 UCAR. + * + * This software is licensed under the terms of the Apache Licence Version 2.0 + * which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. + */ + +#include +#include +#include + +#include "atlas/array/MakeView.h" +#include "atlas/grid.h" +#include "atlas/mesh/Elements.h" +#include "atlas/mesh/HybridElements.h" +#include "atlas/mesh/Mesh.h" +#include "atlas/mesh/MeshBuilder.h" +#include "atlas/mesh/Nodes.h" +#include "atlas/util/Config.h" +#include "atlas/output/Gmsh.h" + +#include "tests/AtlasTestEnvironment.h" + +using namespace atlas::mesh; + +//#include "atlas/output/Gmsh.h" +//using namespace atlas::output; + +namespace atlas { +namespace test { + +//----------------------------------------------------------------------------- + +CASE("test_tiny_mesh") { + // small regional grid whose cell-centers are connected as (global nodes and cells): + // + // 1 ---- 5 ----- 6 + // | 3 / 4 | 1 /2 | + // 2 ----- 3 ---- 4 + // + size_t nb_nodes = 6; + std::vector lon{{0.0, 0.0, 10.0, 15.0, 5.0, 15.0}}; + std::vector lat{{5.0, 0.0, 0.0, 0.0, 5.0, 5.0}}; + std::vector x(nb_nodes); + std::vector y(nb_nodes); + for (size_t j=0; j global_index(6); + std::iota(global_index.begin(), global_index.end(), 1); // 1-based numbering + + // triangles + size_t nb_triags = 4; + std::vector> triag_nodes_global = {{{3, 6, 5}}, {{3, 4, 6}}, {{2, 5, 1}}, {{2, 3, 5}}}; + std::vector triag_global_index = {1, 2, 3, 4}; + + const TriangularMeshBuilder mesh_builder{}; + const Mesh mesh = mesh_builder(nb_nodes, global_index.data(), x.data(), y.data(), lon.data(), lat.data(), + nb_triags, triag_global_index.data(), triag_nodes_global.data()->data()); + + output::Gmsh gmsh("out.msh", util::Config("coordinates", "xy")); + gmsh.write(mesh); +} + +//----------------------------------------------------------------------------- + +} // namespace test +} // namespace atlas + +int main(int argc, char** argv) { + return atlas::test::run(argc, argv); +} From 72e18464630deb9acc8a499b0ff135171a88aa28 Mon Sep 17 00:00:00 2001 From: Slavko Brdar Date: Thu, 9 Nov 2023 16:32:37 +0100 Subject: [PATCH 08/25] Add Fortran interface for Redistribution (#160) --- src/atlas/CMakeLists.txt | 2 + .../detail/RedistributionInterface.cc | 66 +++++++++ .../detail/RedistributionInterface.h | 52 +++++++ src/atlas_f/CMakeLists.txt | 4 + .../atlas_Redistribution_module.F90 | 136 ++++++++++++++++++ src/tests/redistribution/CMakeLists.txt | 11 ++ .../redistribution/fctest_redistribution.F90 | 132 +++++++++++++++++ 7 files changed, 403 insertions(+) create mode 100644 src/atlas/redistribution/detail/RedistributionInterface.cc create mode 100644 src/atlas/redistribution/detail/RedistributionInterface.h create mode 100644 src/atlas_f/redistribution/atlas_Redistribution_module.F90 create mode 100644 src/tests/redistribution/fctest_redistribution.F90 diff --git a/src/atlas/CMakeLists.txt b/src/atlas/CMakeLists.txt index 3655519be..6e0d3d01b 100644 --- a/src/atlas/CMakeLists.txt +++ b/src/atlas/CMakeLists.txt @@ -693,6 +693,8 @@ linalg/dense/MatrixMultiply_EckitLinalg.cc list (APPEND atlas_redistribution_srcs redistribution/Redistribution.h redistribution/Redistribution.cc +redistribution/detail/RedistributionInterface.h +redistribution/detail/RedistributionInterface.cc redistribution/detail/RedistributionImpl.h redistribution/detail/RedistributionImpl.cc redistribution/detail/RedistributionImplFactory.h diff --git a/src/atlas/redistribution/detail/RedistributionInterface.cc b/src/atlas/redistribution/detail/RedistributionInterface.cc new file mode 100644 index 000000000..6f461967f --- /dev/null +++ b/src/atlas/redistribution/detail/RedistributionInterface.cc @@ -0,0 +1,66 @@ +/* + * (C) Copyright 2013 ECMWF. + * + * This software is licensed under the terms of the Apache Licence Version 2.0 + * which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. + * In applying this licence, ECMWF does not waive the privileges and immunities + * granted to it by virtue of its status as an intergovernmental organisation + * nor does it submit to any jurisdiction. + */ + +#include + +#include "RedistributionInterface.h" + +#include "RedistributeGeneric.h" +#include "RedistributionImpl.h" + +#include "atlas/functionspace/FunctionSpace.h" +#include "atlas/redistribution/detail/RedistributionImplFactory.h" + +namespace atlas { +namespace redistribution { + +// ---------------------------------------------------------------------------- +// Fortran interfaces +// ---------------------------------------------------------------------------- + +extern "C" { + +detail::RedistributionImpl* atlas__Redistribution__new__config( + const functionspace::FunctionSpaceImpl* fspace1, const functionspace::FunctionSpaceImpl* fspace2, + const eckit::Configuration* config) { + ATLAS_ASSERT(config != nullptr); + std::string type = detail::RedistributeGeneric::static_type(); + config->get("type", type); + auto redist = redistribution::detail::RedistributionImplFactory::build(type); + FunctionSpace fs1(fspace1); + FunctionSpace fs2(fspace2); + redist->setup(fs1, fs2); + return redist; +} + +void atlas__Redistribution__execute( + const detail::RedistributionImpl* This, const field::FieldImpl* field_1, field::FieldImpl* field_2) { + Field f1(field_1); + Field f2(field_2); + This->execute(f1, f2); +} + +const functionspace::FunctionSpaceImpl* atlas__Redistribution__source( + const detail::RedistributionImpl* This) { + return This->source().get(); +} + +const functionspace::FunctionSpaceImpl* atlas__Redistribution__target( + const detail::RedistributionImpl* This) { + return This->target().get(); +} + +} + + +// ---------------------------------------------------------------------------- + +} // namespace redistribution +} // namespace atlas diff --git a/src/atlas/redistribution/detail/RedistributionInterface.h b/src/atlas/redistribution/detail/RedistributionInterface.h new file mode 100644 index 000000000..2d6cb3bd8 --- /dev/null +++ b/src/atlas/redistribution/detail/RedistributionInterface.h @@ -0,0 +1,52 @@ +/* + * (C) Copyright 2013 ECMWF. + * + * This software is licensed under the terms of the Apache Licence Version 2.0 + * which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. + * In applying this licence, ECMWF does not waive the privileges and immunities + * granted to it by virtue of its status as an intergovernmental organisation + * nor does it submit to any jurisdiction. + */ +#pragma once + +namespace eckit { +class Configuration; +} + +namespace atlas { +namespace functionspace { +class FunctionSpaceImpl; +} +namespace field { +class FieldImpl; +} +} // namespace atlas + +namespace atlas { +namespace redistribution { +namespace detail { +class RedistributionImpl; + +// ------------------------------------------------------------------- +// C wrapper interfaces to C++ routines +extern "C" { + +RedistributionImpl* atlas__Redistribution__new__config( + const functionspace::FunctionSpaceImpl* fspace1, const functionspace::FunctionSpaceImpl* fspace2, + const eckit::Configuration* config); + +void atlas__Redistribution__execute( + const RedistributionImpl* This, const field::FieldImpl* field_1, field::FieldImpl* field_2); + +const functionspace::FunctionSpaceImpl* atlas__Redistribution__source( + const RedistributionImpl* This); + +const functionspace::FunctionSpaceImpl* atlas__Redistribution__target( + const RedistributionImpl* This); + +} + + +} // namespace detail +} // namespace redistribution +} // namespace atlas diff --git a/src/atlas_f/CMakeLists.txt b/src/atlas_f/CMakeLists.txt index 7075be1bb..a59e7f9c2 100644 --- a/src/atlas_f/CMakeLists.txt +++ b/src/atlas_f/CMakeLists.txt @@ -130,6 +130,9 @@ generate_fortran_bindings(FORTRAN_BINDINGS ../atlas/functionspace/EdgeColumns.h generate_fortran_bindings(FORTRAN_BINDINGS ../atlas/functionspace/detail/PointCloudInterface.h MODULE atlas_functionspace_PointCloud_c_binding OUTPUT functionspace_PointCloud_c_binding.f90) +generate_fortran_bindings(FORTRAN_BINDINGS ../atlas/redistribution/detail/RedistributionInterface.h + MODULE atlas_redistribution_c_binding + OUTPUT redistribution_c_binding.f90) if( atlas_HAVE_ATLAS_NUMERICS ) generate_fortran_bindings(FORTRAN_BINDINGS ../atlas/numerics/Nabla.h) @@ -237,6 +240,7 @@ ecbuild_add_library( TARGET atlas_f parallel/atlas_Checksum_module.fypp parallel/atlas_HaloExchange_module.fypp projection/atlas_Projection_module.F90 + redistribution/atlas_Redistribution_module.F90 internals/atlas_read_file.h internals/atlas_read_file.cc internals/Library.h diff --git a/src/atlas_f/redistribution/atlas_Redistribution_module.F90 b/src/atlas_f/redistribution/atlas_Redistribution_module.F90 new file mode 100644 index 000000000..1461e4c76 --- /dev/null +++ b/src/atlas_f/redistribution/atlas_Redistribution_module.F90 @@ -0,0 +1,136 @@ +! (C) Copyright 2013 ECMWF. +! +! This software is licensed under the terms of the Apache Licence Version 2.0 +! which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. +! In applying this licence, ECMWF does not waive the privileges and immunities +! granted to it by virtue of its status as an intergovernmental organisation nor +! does it submit to any jurisdiction. + +#include "atlas/atlas_f.h" + +module atlas_Redistribution_module + +use, intrinsic :: iso_c_binding, only : c_ptr +use atlas_config_module, only : atlas_Config +use atlas_functionspace_module, only : atlas_FunctionSpace +use fckit_owned_object_module, only: fckit_owned_object + +implicit none + +public :: atlas_Redistribution + +private + +!------------------------------------------------------------------------------ +TYPE, extends(fckit_owned_object) :: atlas_Redistribution + +! Purpose : +! ------- +! *atlas_Redistribution* : Object passed from atlas to inspect redistribution + +! Methods : +! ------- + +! Author : +! ------ +! October-2023 Slavko Brdar *ECMWF* +! August-2015 Willem Deconinck *ECMWF* + +!------------------------------------------------------------------------------ +contains + + procedure, public :: execute => atlas_Redistribution__execute + procedure, public :: source => atlas_Redistribution__source + procedure, public :: target => atlas_Redistribution__target + +#if FCKIT_FINAL_NOT_INHERITING + final :: atlas_Redistribution__final_auto +#endif +END TYPE atlas_Redistribution + +!------------------------------------------------------------------------------ + +interface atlas_Redistribution + module procedure ctor_cptr + module procedure ctor_create +end interface + +private :: c_ptr +private :: fckit_owned_object + +!======================================================== +contains +!======================================================== +! ----------------------------------------------------------------------------- +! Redistribution routines + +function empty_config() result(config) + type(atlas_Config) :: config + config = atlas_Config() + call config%return() +end function + +function ctor_cptr( cptr ) result(this) + use atlas_redistribution_c_binding + type(atlas_Redistribution) :: this + type(c_ptr), intent(in) :: cptr + call this%reset_c_ptr( cptr ) + call this%return() +end function + +function ctor_create(fspace1, fspace2, redist_name) result(this) + use atlas_redistribution_c_binding + class(atlas_FunctionSpace), intent(in) :: fspace1, fspace2 + character(len=*), intent(in), optional :: redist_name + type(atlas_Redistribution) :: this + type(atlas_Config) :: config + config = empty_config() + if (present(redist_name)) call config%set("type", redist_name) + call this%reset_c_ptr( atlas__Redistribution__new__config(fspace1%CPTR_PGIBUG_A, fspace2%CPTR_PGIBUG_A, config%CPTR_PGIBUG_B) ) + call config%final() + call this%return() +end function + +subroutine atlas_Redistribution__execute(this, field_1, field_2) + use atlas_redistribution_c_binding + use atlas_Field_module + class(atlas_Redistribution), intent(in) :: this + class(atlas_Field), intent(in) :: field_1 + class(atlas_Field), intent(inout) :: field_2 + call atlas__Redistribution__execute(this%CPTR_PGIBUG_A, field_1%CPTR_PGIBUG_A, field_2%CPTR_PGIBUG_A) +end subroutine + +function atlas_Redistribution__source(this) result(fspace) + use atlas_redistribution_c_binding + class(atlas_Redistribution), intent(in) :: this + type(atlas_FunctionSpace) :: fspace + call fspace%reset_c_ptr(atlas__Redistribution__source(this%CPTR_PGIBUG_A)) + call fspace%return() +end function + +function atlas_Redistribution__target(this) result(fspace) + use atlas_redistribution_c_binding + class(atlas_Redistribution), intent(in) :: this + type(atlas_FunctionSpace) :: fspace + call fspace%reset_c_ptr(atlas__Redistribution__target(this%CPTR_PGIBUG_A)) + call fspace%return() +end function + +! ---------------------------------------------------------------------------------------- + +#if FCKIT_FINAL_NOT_INHERITING +ATLAS_FINAL subroutine atlas_Redistribution__final_auto(this) + type(atlas_Redistribution), intent(inout) :: this +#if FCKIT_FINAL_DEBUGGING + write(0,*) "atlas_Redistribution__final_auto" +#endif +#if FCKIT_FINAL_NOT_PROPAGATING + call this%final() +#endif + FCKIT_SUPPRESS_UNUSED( this ) +end subroutine +#endif + +! ---------------------------------------------------------------------------------------- + +end module atlas_Redistribution_module diff --git a/src/tests/redistribution/CMakeLists.txt b/src/tests/redistribution/CMakeLists.txt index 0a3a5a836..904fcadcd 100644 --- a/src/tests/redistribution/CMakeLists.txt +++ b/src/tests/redistribution/CMakeLists.txt @@ -7,6 +7,17 @@ if( atlas_HAVE_ATLAS_FUNCTIONSPACE ) +if( HAVE_FORTRAN ) + add_fctest( TARGET atlas_fctest_redistribution + MPI 4 + CONDITION eckit_HAVE_MPI + LINKER_LANGUAGE Fortran + SOURCES fctest_redistribution.F90 + LIBS atlas_f + ENVIRONMENT ${ATLAS_TEST_ENVIRONMENT} + ) +endif() + ecbuild_add_test( TARGET atlas_test_redistribution_structured SOURCES test_redistribution_structured.cc MPI 8 diff --git a/src/tests/redistribution/fctest_redistribution.F90 b/src/tests/redistribution/fctest_redistribution.F90 new file mode 100644 index 000000000..a023f3e8e --- /dev/null +++ b/src/tests/redistribution/fctest_redistribution.F90 @@ -0,0 +1,132 @@ +! (C) Copyright 2013 ECMWF. +! This software is licensed under the terms of the Apache Licence Version 2.0 +! which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. +! In applying this licence, ECMWF does not waive the privileges and immunities +! granted to it by virtue of its status as an intergovernmental organisation nor +! does it submit to any jurisdiction. + +! This File contains Unit Tests for testing the +! C++ / Fortran Interfaces to the State Datastructure +! +! @author Willem Deconinck +! @author Slavko Brdar + +#include "fckit/fctest.h" + +! ----------------------------------------------------------------------------- + +module fcta_Redistribution_fxt +use atlas_module +use, intrinsic :: iso_c_binding +implicit none +character(len=1024) :: msg + +contains + +function do_redistribute(fspace_1, fspace_2) result(field_2) +use atlas_module +use atlas_redistribution_module + +implicit none + +type(atlas_FunctionSpace), intent(in) :: fspace_1, fspace_2 +type(atlas_Field) :: field_2 + +type(atlas_FunctionSpace) :: fspace_hlp +type(atlas_Redistribution) :: redist, redist_hlp +type(atlas_Field) :: field_1 !, field_2 +real(c_float), pointer :: field_1v(:), field_2v(:) + +redist = atlas_Redistribution(fspace_1, fspace_2) + +field_1 = fspace_1%create_field(atlas_real(c_float)) +field_2 = fspace_2%create_field(atlas_real(c_float)) +call field_1%data(field_1v) +field_1v = 1._c_float +call field_2%data(field_2v) +field_2v = 2._c_float + +call redist%execute(field_1, field_2) + +call field_2%data(field_2v) +call field_2%halo_exchange() + +! check access to source and target function spaces +redist_hlp = atlas_Redistribution(redist%c_ptr()) +fspace_hlp = redist%source() +fspace_hlp = redist%target() + +call field_1%final() +call redist_hlp%final() +call redist%final() +end function do_redistribute + +end module + +! ----------------------------------------------------------------------------- + +TESTSUITE(fcta_Redistribution) +!TESTSUITE_WITH_FIXTURE(fcta_Redistribution,fcta_Redistribution_fxt) + +! ----------------------------------------------------------------------------- + +TESTSUITE_INIT + use atlas_module + call atlas_library%initialise() +END_TESTSUITE_INIT + +! ----------------------------------------------------------------------------- + +TESTSUITE_FINALIZE + use atlas_module + call atlas_library%finalise() +END_TESTSUITE_FINALIZE + +! ----------------------------------------------------------------------------- + +TEST( test_redistribution ) +use atlas_module +use fcta_Redistribution_fxt +use atlas_redistribution_module + +implicit none + +type(atlas_Grid) :: grid +type(atlas_Mesh) :: mesh +type(atlas_MeshGenerator) :: meshgenerator +type(atlas_FunctionSpace) :: fspace_1, fspace_2 +type(atlas_Field) :: field +real(c_float) , pointer :: field_v(:) + +grid = atlas_Grid("O8") + +fspace_1 = atlas_functionspace_StructuredColumns(grid, atlas_Partitioner("equal_regions")) +fspace_2 = atlas_functionspace_StructuredColumns(grid, atlas_Partitioner("regular_bands")) +field = do_redistribute(fspace_1, fspace_2) +call field%data(field_v) +FCTEST_CHECK(maxval(field_v) == 1.) + +meshgenerator = atlas_MeshGenerator() +mesh = meshgenerator%generate(grid, atlas_Partitioner("equal_regions")) +fspace_1 = atlas_functionspace_NodeColumns(mesh) +mesh = meshgenerator%generate(grid, atlas_Partitioner("regular_bands")) +fspace_2 = atlas_functionspace_NodeColumns(mesh) +field = do_redistribute(fspace_1, fspace_2) +call field%data(field_v) +FCTEST_CHECK(maxval(field_v) == 1.) + +fspace_2 = atlas_functionspace_EdgeColumns(mesh) +mesh = meshgenerator%generate(grid, atlas_Partitioner("equal_regions")) +fspace_1 = atlas_functionspace_EdgeColumns(mesh) +field = do_redistribute(fspace_1, fspace_2) +call field%data(field_v) +FCTEST_CHECK(maxval(field_v) == 1.) + +call fspace_2%final() +call fspace_1%final() +call grid%final() +END_TEST + +! ----------------------------------------------------------------------------- + +END_TESTSUITE From 2ce9d2d08b86f8a03792e583423d27a9cf63287d Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Mon, 13 Nov 2023 12:27:33 +0000 Subject: [PATCH 09/25] Fix interpolation warnings --- src/atlas/interpolation/Cache.h | 1 - 1 file changed, 1 deletion(-) diff --git a/src/atlas/interpolation/Cache.h b/src/atlas/interpolation/Cache.h index 412957eb3..2e70f827c 100644 --- a/src/atlas/interpolation/Cache.h +++ b/src/atlas/interpolation/Cache.h @@ -108,7 +108,6 @@ class MatrixCache final : public Cache { public: MatrixCache() = default; MatrixCache(const Cache& c); - MatrixCache(const MatrixCache& c) : MatrixCache(Cache(c)) {} MatrixCache(Matrix&& m); MatrixCache(std::shared_ptr m, const std::string& uid = ""); MatrixCache(const Matrix* m); From 2dd5ccf24c931582937533ec56da29703b717d9c Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Mon, 13 Nov 2023 12:27:44 +0000 Subject: [PATCH 10/25] Fix logic --- src/atlas/redistribution/detail/RedistributeGeneric.cc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/atlas/redistribution/detail/RedistributeGeneric.cc b/src/atlas/redistribution/detail/RedistributeGeneric.cc index 9e86fff15..d1aa54888 100644 --- a/src/atlas/redistribution/detail/RedistributeGeneric.cc +++ b/src/atlas/redistribution/detail/RedistributeGeneric.cc @@ -121,9 +121,9 @@ std::vector getUidVec(const FunctionSpace& functionspace) { // Check UIDs are unique. if (ATLAS_BUILD_TYPE_DEBUG) { const size_t vecSize = uidVec.size(); - std::unique(uidVec.begin(), uidVec.end(), - [](const IdxUid& a, const IdxUid& b) { return a.second == b.second; }); - ATLAS_ASSERT(uidVec.size() == vecSize, "Unique ID set has duplicate members"); + auto first_duplicate = std::adjacent_find( + uidVec.begin(), uidVec.end(), [](const IdxUid& a, const IdxUid& b) { return a.second == b.second; }); + ATLAS_ASSERT(uidVec.end() == first_duplicate, "Unique ID set has duplicate members"); } return uidVec; From 4c2737598e3402b523d02c198206e82113a03fe1 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Mon, 13 Nov 2023 15:18:41 +0000 Subject: [PATCH 11/25] Cleanup --- src/atlas/redistribution/detail/RedistributeGeneric.cc | 1 - 1 file changed, 1 deletion(-) diff --git a/src/atlas/redistribution/detail/RedistributeGeneric.cc b/src/atlas/redistribution/detail/RedistributeGeneric.cc index d1aa54888..b9b3a3979 100644 --- a/src/atlas/redistribution/detail/RedistributeGeneric.cc +++ b/src/atlas/redistribution/detail/RedistributeGeneric.cc @@ -120,7 +120,6 @@ std::vector getUidVec(const FunctionSpace& functionspace) { // Check UIDs are unique. if (ATLAS_BUILD_TYPE_DEBUG) { - const size_t vecSize = uidVec.size(); auto first_duplicate = std::adjacent_find( uidVec.begin(), uidVec.end(), [](const IdxUid& a, const IdxUid& b) { return a.second == b.second; }); ATLAS_ASSERT(uidVec.end() == first_duplicate, "Unique ID set has duplicate members"); From 99207ce013c0c378e3d6d4b15bb34129a18b5be7 Mon Sep 17 00:00:00 2001 From: Slavko Brdar Date: Mon, 20 Nov 2023 17:14:11 +0100 Subject: [PATCH 12/25] Add Fortran API for functionspace::CellColumns (#164) Add FortranAPI for CellColumns including unit test --- src/atlas/CMakeLists.txt | 2 + .../detail/CellColumnsInterface.cc | 155 +++++++++ .../detail/CellColumnsInterface.h | 59 ++++ src/atlas_f/CMakeLists.txt | 4 + src/atlas_f/atlas_module.F90 | 2 + ...atlas_functionspace_CellColumns_module.F90 | 283 +++++++++++++++++ .../functionspace/fctest_functionspace.F90 | 296 +++++++++++++++++- 7 files changed, 800 insertions(+), 1 deletion(-) create mode 100644 src/atlas/functionspace/detail/CellColumnsInterface.cc create mode 100644 src/atlas/functionspace/detail/CellColumnsInterface.h create mode 100644 src/atlas_f/functionspace/atlas_functionspace_CellColumns_module.F90 diff --git a/src/atlas/CMakeLists.txt b/src/atlas/CMakeLists.txt index 6e0d3d01b..3627dd60d 100644 --- a/src/atlas/CMakeLists.txt +++ b/src/atlas/CMakeLists.txt @@ -500,6 +500,8 @@ functionspace/detail/BlockStructuredColumns.h functionspace/detail/BlockStructuredColumns.cc functionspace/detail/BlockStructuredColumnsInterface.h functionspace/detail/BlockStructuredColumnsInterface.cc +functionspace/detail/CellColumnsInterface.h +functionspace/detail/CellColumnsInterface.cc functionspace/detail/FunctionSpaceImpl.h functionspace/detail/FunctionSpaceImpl.cc functionspace/detail/FunctionSpaceInterface.h diff --git a/src/atlas/functionspace/detail/CellColumnsInterface.cc b/src/atlas/functionspace/detail/CellColumnsInterface.cc new file mode 100644 index 000000000..b33e52028 --- /dev/null +++ b/src/atlas/functionspace/detail/CellColumnsInterface.cc @@ -0,0 +1,155 @@ +/* + * (C) Copyright 2013 ECMWF. + * + * This software is licensed under the terms of the Apache Licence Version 2.0 + * which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. + * In applying this licence, ECMWF does not waive the privileges and immunities + * granted to it by virtue of its status as an intergovernmental organisation + * nor does it submit to any jurisdiction. + */ + +#include + +#include "CellColumnsInterface.h" +#include "atlas/field/FieldSet.h" +#include "atlas/field/detail/FieldImpl.h" +#include "atlas/runtime/Exception.h" + +namespace atlas { +namespace functionspace { +namespace detail { + +using atlas::FieldSet; +using atlas::field::FieldImpl; +using atlas::field::FieldSetImpl; + +// ---------------------------------------------------------------------- + +extern "C" { +const CellColumns* atlas__CellsFunctionSpace__new(Mesh::Implementation* mesh, const eckit::Configuration* config) { + ATLAS_ASSERT(mesh); + Mesh m(mesh); + return new CellColumns(m, *config); +} + +void atlas__CellsFunctionSpace__delete(CellColumns* This) { + ATLAS_ASSERT(This != nullptr, "Cannot access uninitialised atlas_functionspace_CellColumns"); + delete (This); +} + +int atlas__CellsFunctionSpace__nb_cells(const CellColumns* This) { + ATLAS_ASSERT(This != nullptr, "Cannot access uninitialised atlas_functionspace_CellColumns"); + return This->nb_cells(); +} + +const Mesh::Implementation* atlas__CellsFunctionSpace__mesh(const CellColumns* This) { + ATLAS_ASSERT(This != nullptr, "Cannot access uninitialised atlas_functionspace_CellColumns"); + return This->mesh().get(); +} + +const mesh::HybridElements* atlas__CellsFunctionSpace__cells(const CellColumns* This) { + ATLAS_ASSERT(This != nullptr, "Cannot access uninitialised atlas_functionspace_CellColumns"); + return &This->cells(); +} + +void atlas__CellsFunctionSpace__halo_exchange_fieldset(const CellColumns* This, field::FieldSetImpl* fieldset) { + ATLAS_ASSERT(This != nullptr, "Cannot access uninitialised atlas_functionspace_CellColumns"); + ATLAS_ASSERT(fieldset != nullptr, "Cannot access uninitialised atlas_FieldSet"); + FieldSet f(fieldset); + This->haloExchange(f); +} + +void atlas__CellsFunctionSpace__halo_exchange_field(const CellColumns* This, field::FieldImpl* field) { + ATLAS_ASSERT(This != nullptr, "Cannot access uninitialised atlas_functionspace_CellColumns"); + ATLAS_ASSERT(field != nullptr, "Cannot access uninitialised atlas_Field"); + Field f(field); + This->haloExchange(f); +} + +const parallel::HaloExchange* atlas__CellsFunctionSpace__get_halo_exchange(const CellColumns* This) { + ATLAS_ASSERT(This != nullptr, "Cannot access uninitialised atlas_functionspace_CellColumns"); + return &This->halo_exchange(); +} + +void atlas__CellsFunctionSpace__gather_fieldset(const CellColumns* This, const field::FieldSetImpl* local, + field::FieldSetImpl* global) { + ATLAS_ASSERT(This != nullptr, "Cannot access uninitialised atlas_functionspace_CellColumns"); + ATLAS_ASSERT(local != nullptr, "Cannot access uninitialised local atlas_FieldSet"); + ATLAS_ASSERT(global != nullptr, "Cannot access uninitialised global atlas_FieldSet"); + const FieldSet l(local); + FieldSet g(global); + This->gather(l, g); +} + +void atlas__CellsFunctionSpace__gather_field(const CellColumns* This, const field::FieldImpl* local, + field::FieldImpl* global) { + ATLAS_ASSERT(This != nullptr, "Cannot access uninitialised atlas_functionspace_CellColumns"); + ATLAS_ASSERT(local != nullptr, "Cannot access uninitialised local atlas_Field"); + ATLAS_ASSERT(global != nullptr, "Cannot access uninitialised global atlas_Field"); + const Field l(local); + Field g(global); + This->gather(l, g); +} + +const parallel::GatherScatter* atlas__CellsFunctionSpace__get_gather(const CellColumns* This) { + ATLAS_ASSERT(This != nullptr, "Cannot access uninitialised atlas_functionspace_CellColumns"); + return &This->gather(); +} + +const parallel::GatherScatter* atlas__CellsFunctionSpace__get_scatter(const CellColumns* This) { + ATLAS_ASSERT(This != nullptr, "Cannot access uninitialised atlas_functionspace_CellColumns"); + return &This->scatter(); +} + +void atlas__CellsFunctionSpace__scatter_fieldset(const CellColumns* This, const field::FieldSetImpl* global, + field::FieldSetImpl* local) { + ATLAS_ASSERT(This != nullptr, "Cannot access uninitialised atlas_functionspace_CellColumns"); + ATLAS_ASSERT(local != nullptr, "Cannot access uninitialised local atlas_FieldSet"); + ATLAS_ASSERT(global != nullptr, "Cannot access uninitialised global atlas_FieldSet"); + const FieldSet g(global); + FieldSet l(local); + This->scatter(g, l); +} + +void atlas__CellsFunctionSpace__scatter_field(const CellColumns* This, const field::FieldImpl* global, + field::FieldImpl* local) { + ATLAS_ASSERT(This != nullptr, "Cannot access uninitialised atlas_functionspace_CellColumns"); + ATLAS_ASSERT(local != nullptr, "Cannot access uninitialised local atlas_Field"); + ATLAS_ASSERT(global != nullptr, "Cannot access uninitialised global atlas_Field"); + const Field g(global); + Field l(local); + This->scatter(g, l); +} + +const parallel::Checksum* atlas__CellsFunctionSpace__get_checksum(const CellColumns* This) { + ATLAS_ASSERT(This != nullptr, "Cannot access uninitialised atlas_functionspace_CellColumns"); + return &This->checksum(); +} + +void atlas__CellsFunctionSpace__checksum_fieldset(const CellColumns* This, const field::FieldSetImpl* fieldset, + char*& checksum, int& size, int& allocated) { + ATLAS_ASSERT(This != nullptr, "Cannot access uninitialised atlas_functionspace_CellColumns"); + ATLAS_ASSERT(fieldset != nullptr, "Cannot access uninitialised atlas_FieldSet"); + std::string checksum_str(This->checksum(fieldset)); + size = static_cast(checksum_str.size()); + checksum = new char[size + 1]; + allocated = true; + std::strncpy(checksum, checksum_str.c_str(), size + 1); +} + +void atlas__CellsFunctionSpace__checksum_field(const CellColumns* This, const field::FieldImpl* field, char*& checksum, + int& size, int& allocated) { + ATLAS_ASSERT(This != nullptr, "Cannot access uninitialised atlas_functionspace_CellColumns"); + ATLAS_ASSERT(field != nullptr, "Cannot access uninitialised atlas_Field"); + std::string checksum_str(This->checksum(field)); + size = static_cast(checksum_str.size()); + checksum = new char[size + 1]; + allocated = true; + std::strncpy(checksum, checksum_str.c_str(), size + 1); +} + +} // extern C + +} // namespace detail +} // namespace functionspace +} // namespace atlas diff --git a/src/atlas/functionspace/detail/CellColumnsInterface.h b/src/atlas/functionspace/detail/CellColumnsInterface.h new file mode 100644 index 000000000..86ca7d0e9 --- /dev/null +++ b/src/atlas/functionspace/detail/CellColumnsInterface.h @@ -0,0 +1,59 @@ +/* + * (C) Copyright 2013 ECMWF. + * + * This software is licensed under the terms of the Apache Licence Version 2.0 + * which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. + * In applying this licence, ECMWF does not waive the privileges and immunities + * granted to it by virtue of its status as an intergovernmental organisation + * nor does it submit to any jurisdiction. + */ + +#pragma once + +#include "atlas/functionspace/CellColumns.h" +#include "atlas/mesh/Mesh.h" + +namespace atlas { +namespace field { +class FieldSetImpl; +class FieldImpl; +} // namespace field +} // namespace atlas + +namespace atlas { +namespace functionspace { +namespace detail { + +extern "C" { +const CellColumns* atlas__CellsFunctionSpace__new(Mesh::Implementation* mesh, const eckit::Configuration* config); +void atlas__CellsFunctionSpace__delete(CellColumns* This); +int atlas__CellsFunctionSpace__nb_cells(const CellColumns* This); +const Mesh::Implementation* atlas__CellsFunctionSpace__mesh(const CellColumns* This); +const mesh::HybridElements* atlas__CellsFunctionSpace__cells(const CellColumns* This); + +void atlas__CellsFunctionSpace__halo_exchange_fieldset(const CellColumns* This, field::FieldSetImpl* fieldset); +void atlas__CellsFunctionSpace__halo_exchange_field(const CellColumns* This, field::FieldImpl* field); +const parallel::HaloExchange* atlas__CellsFunctionSpace__get_halo_exchange(const CellColumns* This); + +void atlas__CellsFunctionSpace__gather_fieldset(const CellColumns* This, const field::FieldSetImpl* local, + field::FieldSetImpl* global); +void atlas__CellsFunctionSpace__gather_field(const CellColumns* This, const field::FieldImpl* local, + field::FieldImpl* global); +const parallel::GatherScatter* atlas__CellsFunctionSpace__get_gather(const CellColumns* This); + +void atlas__CellsFunctionSpace__scatter_fieldset(const CellColumns* This, const field::FieldSetImpl* global, + field::FieldSetImpl* local); +void atlas__CellsFunctionSpace__scatter_field(const CellColumns* This, const field::FieldImpl* global, + field::FieldImpl* local); +const parallel::GatherScatter* atlas__CellsFunctionSpace__get_scatter(const CellColumns* This); + +void atlas__CellsFunctionSpace__checksum_fieldset(const CellColumns* This, const field::FieldSetImpl* fieldset, + char*& checksum, int& size, int& allocated); +void atlas__CellsFunctionSpace__checksum_field(const CellColumns* This, const field::FieldImpl* field, char*& checksum, + int& size, int& allocated); +const parallel::Checksum* atlas__CellsFunctionSpace__get_checksum(const CellColumns* This); +} + +} // namespace detail +} // namespace functionspace +} // namespace atlas diff --git a/src/atlas_f/CMakeLists.txt b/src/atlas_f/CMakeLists.txt index a59e7f9c2..f1b831e3c 100644 --- a/src/atlas_f/CMakeLists.txt +++ b/src/atlas_f/CMakeLists.txt @@ -121,6 +121,9 @@ generate_fortran_bindings(FORTRAN_BINDINGS ../atlas/functionspace/detail/Structu generate_fortran_bindings(FORTRAN_BINDINGS ../atlas/functionspace/detail/BlockStructuredColumnsInterface.h MODULE atlas_functionspace_BlockStructuredColumns_c_binding OUTPUT functionspace_BlockStructuredColumns_c_binding.f90 ) +generate_fortran_bindings(FORTRAN_BINDINGS ../atlas/functionspace/detail/CellColumnsInterface.h + MODULE atlas_functionspace_CellColumns_c_binding + OUTPUT functionspace_CellColumns_c_binding.f90) generate_fortran_bindings(FORTRAN_BINDINGS ../atlas/functionspace/detail/NodeColumnsInterface.h MODULE atlas_functionspace_NodeColumns_c_binding OUTPUT functionspace_NodeColumns_c_binding.f90) @@ -213,6 +216,7 @@ ecbuild_add_library( TARGET atlas_f domain/atlas_Domain_module.F90 functionspace/atlas_FunctionSpace_module.F90 functionspace/atlas_functionspace_EdgeColumns_module.F90 + functionspace/atlas_functionspace_CellColumns_module.F90 functionspace/atlas_functionspace_NodeColumns_module.fypp functionspace/atlas_functionspace_StructuredColumns_module.F90 functionspace/atlas_functionspace_BlockStructuredColumns_module.F90 diff --git a/src/atlas_f/atlas_module.F90 b/src/atlas_f/atlas_module.F90 index d82553e86..48ffe33ae 100644 --- a/src/atlas_f/atlas_module.F90 +++ b/src/atlas_f/atlas_module.F90 @@ -91,6 +91,8 @@ module atlas_module & atlas_Vertical use atlas_functionspace_EdgeColumns_module, only: & & atlas_functionspace_EdgeColumns +use atlas_functionspace_CellColumns_module, only: & + & atlas_functionspace_CellColumns use atlas_functionspace_NodeColumns_module, only: & & atlas_functionspace_NodeColumns use atlas_functionspace_PointCloud_module, only: & diff --git a/src/atlas_f/functionspace/atlas_functionspace_CellColumns_module.F90 b/src/atlas_f/functionspace/atlas_functionspace_CellColumns_module.F90 new file mode 100644 index 000000000..c67f5a148 --- /dev/null +++ b/src/atlas_f/functionspace/atlas_functionspace_CellColumns_module.F90 @@ -0,0 +1,283 @@ +! (C) Copyright 2013 ECMWF. +! +! This software is licensed under the terms of the Apache Licence Version 2.0 +! which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. +! In applying this licence, ECMWF does not waive the privileges and immunities +! granted to it by virtue of its status as an intergovernmental organisation nor +! does it submit to any jurisdiction. + +#include "atlas/atlas_f.h" + +module atlas_functionspace_CellColumns_module + +use fckit_c_interop_module, only : c_str, c_ptr_to_string, c_ptr_free +use atlas_functionspace_module, only : atlas_FunctionSpace +use atlas_Field_module, only: atlas_Field +use atlas_FieldSet_module, only: atlas_FieldSet +use atlas_Mesh_module, only: atlas_Mesh +use atlas_mesh_Cells_module, only: atlas_mesh_Cells +use atlas_GatherScatter_module, only: atlas_GatherScatter +use atlas_HaloExchange_module, only: atlas_HaloExchange +use atlas_Checksum_module, only: atlas_Checksum +use atlas_Config_module, only: atlas_Config +use atlas_kinds_module, only: ATLAS_KIND_GIDX + +implicit none + +private :: c_str, c_ptr_to_string, c_ptr_free +private :: atlas_FunctionSpace +private :: atlas_Field +private :: atlas_FieldSet +private :: atlas_mesh_Cells +private :: atlas_GatherScatter +private :: atlas_HaloExchange +private :: atlas_Checksum +private :: atlas_Mesh +private :: atlas_Config +private :: ATLAS_KIND_GIDX + +public :: atlas_functionspace_CellColumns + +private + +!------------------------------------------------------------------------------ +TYPE, extends(atlas_FunctionSpace) :: atlas_functionspace_CellColumns + +! Purpose : +! ------- +! *atlas_functionspace_CellColumns* : Interpretes fields defined in cells + +! Methods : +! ------- + +! Author : +! ------ +! August-2015 Willem Deconinck *ECMWF* + +!------------------------------------------------------------------------------ +contains + + + procedure, public :: nb_cells + procedure, public :: mesh + procedure, public :: cells + + procedure, public :: get_halo_exchange + + procedure, private :: gather_fieldset + procedure, private :: gather_field + generic, public :: gather => gather_fieldset, gather_field + procedure, public :: get_gather + + procedure, private :: scatter_fieldset + procedure, private :: scatter_field + generic, public :: scatter => scatter_fieldset, scatter_field + procedure, public :: get_scatter + + procedure, private :: checksum_fieldset + procedure, private :: checksum_field + generic, public :: checksum => checksum_fieldset, checksum_field + procedure, public :: get_checksum + +#if FCKIT_FINAL_NOT_INHERITING + final :: atlas_functionspace_CellColumns__final_auto +#endif + +END TYPE atlas_functionspace_CellColumns + +interface atlas_functionspace_CellColumns + module procedure constructor__cptr + module procedure constructor +end interface + +!------------------------------------------------------------------------------ + +!======================================================== +contains +!======================================================== + +!------------------------------------------------------------------------------ + +function constructor__cptr(cptr) result(this) + use, intrinsic :: iso_c_binding, only : c_ptr + type(atlas_functionspace_CellColumns) :: this + type(c_ptr), intent(in) :: cptr + call this%reset_c_ptr( cptr ) + call this%return() +end function + +!------------------------------------------------------------------------------ + +function constructor(mesh,halo,levels) result(this) + use atlas_functionspace_CellColumns_c_binding + type(atlas_functionspace_CellColumns) :: this + type(atlas_Mesh), intent(inout) :: mesh + integer, intent(in), optional :: halo + integer, intent(in), optional :: levels + type(atlas_Config) :: config + config = atlas_Config() + if( present(halo) ) call config%set("halo",halo) + if( present(levels) ) call config%set("levels",levels) + call this%reset_c_ptr( atlas__CellsFunctionSpace__new(mesh%CPTR_PGIBUG_A,config%CPTR_PGIBUG_B) ) + call config%final() + call this%return() +end function + +!------------------------------------------------------------------------------ + +function nb_cells(this) + use atlas_functionspace_CellColumns_c_binding + integer :: nb_cells + class(atlas_functionspace_CellColumns), intent(in) :: this + nb_cells = atlas__CellsFunctionSpace__nb_cells(this%CPTR_PGIBUG_A) +end function + +!------------------------------------------------------------------------------ + +function mesh(this) + use atlas_functionspace_CellColumns_c_binding + type(atlas_Mesh) :: mesh + class(atlas_functionspace_CellColumns), intent(in) :: this + call mesh%reset_c_ptr( atlas__CellsFunctionSpace__mesh(this%CPTR_PGIBUG_A) ) + call mesh%return() +end function + +!------------------------------------------------------------------------------ + +function cells(this) + use atlas_functionspace_CellColumns_c_binding + type(atlas_mesh_Cells) :: cells + class(atlas_functionspace_CellColumns), intent(in) :: this + call cells%reset_c_ptr( atlas__CellsFunctionSpace__cells(this%CPTR_PGIBUG_A) ) + call cells%return() +end function + +!------------------------------------------------------------------------------ + +function get_gather(this) result(gather) + use atlas_functionspace_CellColumns_c_binding + type(atlas_GatherScatter) :: gather + class(atlas_functionspace_CellColumns), intent(in) :: this + call gather%reset_c_ptr( atlas__CellsFunctioNSpace__get_gather(this%CPTR_PGIBUG_A) ) +end function + +!------------------------------------------------------------------------------ + +function get_scatter(this) result(gather) + use atlas_functionspace_CellColumns_c_binding + type(atlas_GatherScatter) :: gather + class(atlas_functionspace_CellColumns), intent(in) :: this + call gather%reset_c_ptr( atlas__CellsFunctioNSpace__get_scatter(this%CPTR_PGIBUG_A) ) +end function + +!------------------------------------------------------------------------------ + +subroutine gather_fieldset(this,local,global) + use atlas_functionspace_CellColumns_c_binding + class(atlas_functionspace_CellColumns), intent(in) :: this + type(atlas_FieldSet), intent(in) :: local + type(atlas_FieldSet), intent(inout) :: global + call atlas__CellsFunctionSpace__gather_fieldset(this%CPTR_PGIBUG_A,local%CPTR_PGIBUG_A,global%CPTR_PGIBUG_A) +end subroutine + +!------------------------------------------------------------------------------ + +subroutine gather_field(this,local,global) + use atlas_functionspace_CellColumns_c_binding + class(atlas_functionspace_CellColumns), intent(in) :: this + type(atlas_Field), intent(in) :: local + type(atlas_Field), intent(inout) :: global + call atlas__CellsFunctionSpace__gather_field(this%CPTR_PGIBUG_A,local%CPTR_PGIBUG_A,global%CPTR_PGIBUG_A) +end subroutine + +!------------------------------------------------------------------------------ + +subroutine scatter_fieldset(this,global,local) + use atlas_functionspace_CellColumns_c_binding + class(atlas_functionspace_CellColumns), intent(in) :: this + type(atlas_FieldSet), intent(in) :: global + type(atlas_FieldSet), intent(inout) :: local + call atlas__CellsFunctionSpace__scatter_fieldset(this%CPTR_PGIBUG_A,global%CPTR_PGIBUG_A,local%CPTR_PGIBUG_A) +end subroutine + +!------------------------------------------------------------------------------ + +subroutine scatter_field(this,global,local) + use atlas_functionspace_CellColumns_c_binding + class(atlas_functionspace_CellColumns), intent(in) :: this + type(atlas_Field), intent(in) :: global + type(atlas_Field), intent(inout) :: local + call atlas__CellsFunctionSpace__scatter_field(this%CPTR_PGIBUG_A,global%CPTR_PGIBUG_A,local%CPTR_PGIBUG_A) +end subroutine + +!------------------------------------------------------------------------------ + +function get_halo_exchange(this) result(halo_exchange) + use atlas_functionspace_CellColumns_c_binding + type(atlas_HaloExchange) :: halo_exchange + class(atlas_functionspace_CellColumns), intent(in) :: this + call halo_exchange%reset_c_ptr( atlas__CellsFunctioNSpace__get_halo_exchange(this%CPTR_PGIBUG_A) ) +end function + +!------------------------------------------------------------------------------ + +function get_checksum(this) result(checksum) + use atlas_functionspace_CellColumns_c_binding + type(atlas_Checksum) :: checksum + class(atlas_functionspace_CellColumns), intent(in) :: this + call checksum%reset_c_ptr( atlas__CellsFunctioNSpace__get_checksum(this%CPTR_PGIBUG_A) ) +end function + +!------------------------------------------------------------------------------ + +function checksum_fieldset(this,fieldset) result(checksum) + use atlas_functionspace_CellColumns_c_binding + use, intrinsic :: iso_c_binding, only : c_ptr + character(len=:), allocatable :: checksum + class(atlas_functionspace_CellColumns), intent(in) :: this + type(atlas_FieldSet), intent(in) :: fieldset + type(c_ptr) :: checksum_cptr + integer :: checksum_size, checksum_allocated + call atlas__CellsFunctionSpace__checksum_fieldset( & + this%CPTR_PGIBUG_A,fieldset%CPTR_PGIBUG_A,checksum_cptr,checksum_size,checksum_allocated) + allocate(character(len=checksum_size) :: checksum ) + checksum = c_ptr_to_string(checksum_cptr) + if( checksum_allocated == 1 ) call c_ptr_free(checksum_cptr) +end function + +!------------------------------------------------------------------------------ + +function checksum_field(this,field) result(checksum) + use atlas_functionspace_CellColumns_c_binding + use, intrinsic :: iso_c_binding, only : c_ptr + character(len=:), allocatable :: checksum + class(atlas_functionspace_CellColumns), intent(in) :: this + type(atlas_Field), intent(in) :: field + type(c_ptr) :: checksum_cptr + integer :: checksum_size, checksum_allocated + call atlas__CellsFunctionSpace__checksum_field( & + this%CPTR_PGIBUG_A,field%CPTR_PGIBUG_A,checksum_cptr,checksum_size,checksum_allocated) + allocate(character(len=checksum_size) :: checksum ) + checksum = c_ptr_to_string(checksum_cptr) + if( checksum_allocated == 1 ) call c_ptr_free(checksum_cptr) +end function + +!------------------------------------------------------------------------------ + +#if FCKIT_FINAL_NOT_INHERITING +ATLAS_FINAL subroutine atlas_functionspace_CellColumns__final_auto(this) + type(atlas_functionspace_CellColumns), intent(inout) :: this +#if FCKIT_FINAL_DEBUGGING + write(0,*) "atlas_functionspace_CellColumns__final_auto" +#endif +#if FCKIT_FINAL_NOT_PROPAGATING + call this%final() +#endif + FCKIT_SUPPRESS_UNUSED( this ) +end subroutine +#endif + +!------------------------------------------------------------------------------ + +end module atlas_functionspace_CellColumns_module + diff --git a/src/tests/functionspace/fctest_functionspace.F90 b/src/tests/functionspace/fctest_functionspace.F90 index fd2011d11..ee63cc600 100644 --- a/src/tests/functionspace/fctest_functionspace.F90 +++ b/src/tests/functionspace/fctest_functionspace.F90 @@ -247,7 +247,7 @@ module fcta_FunctionSpace_fxt ! ----------------------------------------------------------------------------- -TEST( test_collectives ) +TEST( test_node_collectives ) #if 1 use fckit_mpi_module type(atlas_StructuredGrid) :: grid @@ -365,6 +365,300 @@ module fcta_FunctionSpace_fxt #endif END_TEST +! ----------------------------------------------------------------------------- + +TEST( test_cell_collectives ) +#if 1 +use fckit_mpi_module +type(atlas_StructuredGrid) :: grid +type(atlas_MeshGenerator) :: meshgenerator +type(atlas_Mesh) :: mesh +type(atlas_functionspace_CellColumns) :: fs2d +type(atlas_Field) :: field, global, scal +type(atlas_Metadata) :: metadata +type(fckit_mpi_comm) :: mpi +real(c_float), pointer :: scalvalues(:) +real(c_float), pointer :: values(:,:) +real(c_float), pointer :: values3d(:,:,:) +!real(c_float) :: minimum, maximum, sum, oisum, mean, stddev +!real(c_float), allocatable :: minimumv(:), maximumv(:), meanv(:), stddevv(:) +integer :: halo_size, levels +integer(ATLAS_KIND_GIDX) :: glb_idx +integer(ATLAS_KIND_GIDX), allocatable :: glb_idxv (:) +integer(c_int) :: test_broadcast +mpi = fckit_mpi_comm() +halo_size = 1 +levels = 10 + +grid = atlas_StructuredGrid("N24") +meshgenerator = atlas_MeshGenerator() +mesh = meshgenerator%generate(grid) +call meshgenerator%final() +fs2d = atlas_functionspace_CellColumns(mesh,halo_size) + +field = fs2d%create_field(kind=atlas_real(c_float),variables=2) +global = fs2d%create_field(field,global=.True.) +scal = fs2d%create_field(kind=atlas_real(c_float)) + +write(msg,*) "field: rank",field%rank(), " shape [",field%shape(), "] size ", field%size(); call atlas_log%info(msg) +write(msg,*) "global: rank",global%rank()," shape [",global%shape(),"] size ", global%size(); call atlas_log%info(msg) + +call fs2d%gather(field,global) +call fs2d%halo_exchange(field) + +metadata = global%metadata() +if( mpi%rank() == 0 ) then + call metadata%set("test_broadcast",123) +endif + +call fs2d%scatter(global,field) +metadata = field%metadata() +call metadata%get("test_broadcast",test_broadcast) +FCTEST_CHECK_EQUAL( test_broadcast, 123 ) +call field%data(values) +call scal%data(scalvalues) +values = 2. +scalvalues = 2. + +call atlas_log%info(fs2d%checksum(field)) + +values = mpi%rank() +scalvalues = mpi%rank() + +call scal%final() +call field%final() +call global%final() + +field = fs2d%create_field(kind=atlas_real(c_float),levels=levels,variables=2*3) +global = fs2d%create_field(field,global=.True.,owner=mpi%size()-1) + +write(msg,*) "field: rank",field%rank(), " shape [",field%shape(), "] size ", field%size(); call atlas_log%info(msg) +write(msg,*) "global: rank",global%rank()," shape [",global%shape(),"] size ", global%size(); call atlas_log%info(msg) + +call fs2d%gather(field,global) +call fs2d%halo_exchange(field) +call fs2d%scatter(global,field) + +call field%data(values3d) +values3d = 2. + +call atlas_log%info(fs2d%checksum(field)) +call field%final() +call global%final() +call fs2d%final() + +call mesh%final() +call grid%final() +#endif +END_TEST + +TEST( test_cells ) +#if 1 +type(atlas_StructuredGrid) :: grid +type(atlas_MeshGenerator) :: meshgenerator +type(atlas_Mesh) :: mesh +type(atlas_functionspace_CellColumns) :: fs +type(atlas_Field) :: field, template +type(atlas_mesh_Nodes) :: cells +integer :: halo_size, nb_cells +halo_size = 1 + +grid = atlas_StructuredGrid("N24") +meshgenerator = atlas_MeshGenerator() +mesh = meshgenerator%generate(grid) +call meshgenerator%final() +fs = atlas_functionspace_CellColumns(mesh,halo_size) +cells = fs%cells() +nb_cells = fs%nb_cells() +write(msg,*) "nb_cells = ",nb_cells; call atlas_log%info(msg) + +field = fs%create_field(atlas_real(c_float)) +FCTEST_CHECK_EQUAL( field%rank() , 1 ) +FCTEST_CHECK_EQUAL( field%name() , "" ) +FCTEST_CHECK_EQUAL( field%kind() , atlas_real(c_float) ) +call field%final() + +field = fs%create_field(name="field",kind=atlas_real(c_float)) +FCTEST_CHECK_EQUAL( field%rank() , 1 ) +FCTEST_CHECK_EQUAL( field%name() , "field" ) +FCTEST_CHECK_EQUAL( field%kind() , atlas_real(c_float) ) +call field%final() + +field = fs%create_field(atlas_real(c_float),variables=2) +FCTEST_CHECK_EQUAL( field%rank() , 2 ) +FCTEST_CHECK_EQUAL( field%name() , "" ) +call field%final() + +field = fs%create_field(name="field",kind=atlas_integer(c_int),variables=2*2) +FCTEST_CHECK_EQUAL( field%rank() , 2 ) +FCTEST_CHECK_EQUAL( field%name() , "field" ) +template = field + +field = fs%create_field(template) +FCTEST_CHECK_EQUAL( field%rank() , 2 ) +FCTEST_CHECK_EQUAL( field%name() , template%name() ) +call field%final() + +field = fs%create_field(template,name="field") +FCTEST_CHECK_EQUAL( field%rank() , 2 ) +FCTEST_CHECK_EQUAL( field%name() , "field" ) +call field%final() +call template%final() + + +field = fs%create_field(atlas_real(c_float),global=.True.) +FCTEST_CHECK_EQUAL( field%rank() , 1 ) +FCTEST_CHECK_EQUAL( field%name() , "" ) +FCTEST_CHECK_EQUAL( field%kind() , atlas_real(c_float) ) +call field%final() + +field = fs%create_field(name="field",kind=atlas_real(c_float),global=.True.) +FCTEST_CHECK_EQUAL( field%rank() , 1 ) +FCTEST_CHECK_EQUAL( field%name() , "field" ) +FCTEST_CHECK_EQUAL( field%kind() , atlas_real(c_float) ) +call field%final() + +field = fs%create_field(atlas_real(c_float),variables=2,global=.True.) +FCTEST_CHECK_EQUAL( field%rank() , 2 ) +FCTEST_CHECK_EQUAL( field%name() , "" ) +call field%final() + +field = fs%create_field(name="field",kind=atlas_integer(c_int),variables=2*2,global=.True.) +FCTEST_CHECK_EQUAL( field%rank() , 2 ) +FCTEST_CHECK_EQUAL( field%name() , "field" ) +template = field + +field = fs%create_field(template,global=.True.) +FCTEST_CHECK_EQUAL( field%rank() , 2 ) +FCTEST_CHECK_EQUAL( field%name() , template%name() ) +call field%final() + +field = fs%create_field(template,name="field",global=.True.) +FCTEST_CHECK_EQUAL( field%rank() , 2 ) +FCTEST_CHECK_EQUAL( field%name() , "field" ) +call field%final() +call template%final() + +call fs%final() +call mesh%final() +call grid%final() +#else +#warning test test_cells disabled +#endif +END_TEST + +! ----------------------------------------------------------------------------- + + +TEST( test_cellscolumns ) +#if 1 +type(atlas_StructuredGrid) :: grid +type(atlas_MeshGenerator) :: meshgenerator +type(atlas_Mesh) :: mesh +type(atlas_functionspace_CellColumns) :: fs +type(atlas_Field) :: field, template +integer :: halo_size, levels +halo_size = 1 +levels = 10 + +grid = atlas_StructuredGrid("N24") +meshgenerator = atlas_MeshGenerator() +mesh = meshgenerator%generate(grid) +call meshgenerator%final() +fs = atlas_functionspace_CellColumns(mesh,halo_size) + +!levels = fs%nb_levels() +write(msg,*) "nb_levels = ",levels; call atlas_log%info(msg) + +field = fs%create_field(atlas_real(c_float),levels=levels) +FCTEST_CHECK_EQUAL( field%rank() , 2 ) +FCTEST_CHECK_EQUAL( field%name() , "" ) +FCTEST_CHECK_EQUAL( field%kind() , atlas_real(c_float) ) +call field%final() + +field = fs%create_field(name="field",kind=atlas_real(c_float),levels=levels) +FCTEST_CHECK_EQUAL( field%rank() , 2 ) +FCTEST_CHECK_EQUAL( field%name() , "field" ) +FCTEST_CHECK_EQUAL( field%kind() , atlas_real(c_float) ) +call field%final() + +field = fs%create_field(atlas_real(c_float),levels=levels,variables=2) +FCTEST_CHECK_EQUAL( field%rank() , 3 ) +FCTEST_CHECK_EQUAL( field%name() , "" ) +call field%final() + +field = fs%create_field(name="field",kind=atlas_integer(c_int),levels=levels,variables=2*2) +FCTEST_CHECK_EQUAL( field%rank() , 3 ) +FCTEST_CHECK_EQUAL( field%name() , "field" ) +template = field + +field = fs%create_field(template) +FCTEST_CHECK_EQUAL( field%rank() , 3 ) +FCTEST_CHECK_EQUAL( field%name() , template%name() ) +call field%final() + +field = fs%create_field(template,name="field") +FCTEST_CHECK_EQUAL( field%rank() , 3 ) +FCTEST_CHECK_EQUAL( field%name() , "field" ) +call field%final() +call template%final() + + +field = fs%create_field(atlas_real(c_float),levels=levels,global=.True.) +FCTEST_CHECK_EQUAL( field%rank() , 2 ) +FCTEST_CHECK_EQUAL( field%name() , "" ) +FCTEST_CHECK_EQUAL( field%kind() , atlas_real(c_float) ) +call field%final() + +field = fs%create_field(name="field",kind=atlas_real(c_float),levels=levels,global=.True.) +FCTEST_CHECK_EQUAL( field%rank() , 2 ) +FCTEST_CHECK_EQUAL( field%name() , "field" ) +FCTEST_CHECK_EQUAL( field%kind() , atlas_real(c_float) ) +call field%final() + +field = fs%create_field(atlas_real(c_float),levels=levels,variables=2,global=.True.) +FCTEST_CHECK_EQUAL( field%rank() , 3 ) +FCTEST_CHECK_EQUAL( field%name() , "" ) +call field%final() + +field = fs%create_field(name="field",kind=atlas_integer(c_int),levels=levels,variables=2*2,global=.True.) +FCTEST_CHECK_EQUAL( field%rank() , 3 ) +FCTEST_CHECK_EQUAL( field%name() , "field" ) +template = field + +field = fs%create_field(template,global=.True.) +FCTEST_CHECK_EQUAL( field%rank() , 3 ) +FCTEST_CHECK_EQUAL( field%name() , template%name() ) +call field%final() + +field = fs%create_field(template,name="field",global=.True.) +FCTEST_CHECK_EQUAL( field%rank() , 3 ) +FCTEST_CHECK_EQUAL( field%name() , "field" ) +call field%final() +call template%final() + +fs = atlas_functionspace_CellColumns(mesh,levels=5) +field = fs%create_field(atlas_real(c_float)) +FCTEST_CHECK_EQUAL( field%rank() , 2 ) +FCTEST_CHECK_EQUAL( field%name() , "" ) +FCTEST_CHECK_EQUAL( field%kind() , atlas_real(c_float) ) +call field%final() + +FCTEST_CHECK_EQUAL( fs%owners(), 1 ) +call fs%final() + +FCTEST_CHECK_EQUAL( mesh%owners(), 1 ) +call mesh%final() + +FCTEST_CHECK_EQUAL( grid%owners(), 1 ) +call grid%final() +#else +#warning test test_cellscolumns disabled +#endif +END_TEST + +! ----------------------------------------------------------------------------- + From 93082b9a674dcd38c24109a9e6eb42bc389ae7c7 Mon Sep 17 00:00:00 2001 From: Willem Deconinck Date: Wed, 22 Nov 2023 15:40:37 +0000 Subject: [PATCH 13/25] Add compile flag -fno-finite-math-only for Intel LLVM compiler (icx, icpx) --- cmake/atlas_compile_flags.cmake | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/cmake/atlas_compile_flags.cmake b/cmake/atlas_compile_flags.cmake index 5473f870a..8b334f149 100644 --- a/cmake/atlas_compile_flags.cmake +++ b/cmake/atlas_compile_flags.cmake @@ -24,4 +24,11 @@ endif() if( CMAKE_CXX_COMPILER_ID MATCHES NVHPC ) ecbuild_add_cxx_flags("--diag_suppress declared_but_not_referenced --display_error_number" NAME atlas_cxx_disable_warnings ) # For all the variables with side effects (constructor/dectructor functionality) -endif() \ No newline at end of file +endif() + +if( CMAKE_CXX_COMPILER_ID MATCHES IntelLLVM ) + # Turn off -ffinite-math-only which gets included by some optimisation levels which assumes values can never be NaN. + # Then results in std::isnan(value) always retrun false. + ecbuild_add_cxx_flags("-fno-finite-math-only") +endif() + From 894755f25b35dbc3f3aea834aa015f324846706b Mon Sep 17 00:00:00 2001 From: Willem Deconinck Date: Thu, 23 Nov 2023 09:48:44 +0100 Subject: [PATCH 14/25] Fix intel compiler version in github actions, and add IntelLLVM --- .github/workflows/build.yml | 27 +++++++++++++++++++++++++-- tools/install-intel-oneapi.sh | 10 +++++----- 2 files changed, 30 insertions(+), 7 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index f3c581ce6..fbb41bf93 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -37,6 +37,7 @@ jobs: - linux clang-12 # - linux nvhpc-22.11 - linux intel + - linux intel-classic - macos include: @@ -102,7 +103,16 @@ jobs: - name : linux intel os: ubuntu-20.04 - compiler: intel-oneapi + compiler: intel + compiler_cc: icx + compiler_cxx: icpx + compiler_fc: ifx + caching: true + coverage: false + + - name : linux intel-classic + os: ubuntu-20.04 + compiler: intel-classic compiler_cc: icc compiler_cxx: icpc compiler_fc: ifort @@ -179,7 +189,7 @@ jobs: ${ATLAS_TOOLS}/install-intel-oneapi.sh source /opt/intel/oneapi/setvars.sh printenv >> $GITHUB_ENV - echo "CACHE_SUFFIX=$(icc -dumpversion)" >> $GITHUB_ENV + echo "CACHE_SUFFIX=$CC-$($CC -dumpversion)" >> $GITHUB_ENV - name: Install MPI shell: bash -eux {0} @@ -220,6 +230,19 @@ jobs: # Add mpirun to path for testing [ -z ${MPI_HOME+x} ] || echo "${MPI_HOME}/bin" >> $GITHUB_PATH + if [[ "${{matrix.compiler}}" == intel-classic ]]; then + echo "CFLAGS=-diag-disable=10441" >> $GITHUB_ENV + echo "CXXFLAGS=-diag-disable=10441" >> $GITHUB_ENV + echo "FCFLAGS=-diag-disable=10441" >> $GITHUB_ENV + echo "FFLAGS=-diag-disable=10441" >> $GITHUB_ENV + fi + + if [[ "${{matrix.compiler}}" == intel ]]; then + echo "CFLAGS=-Rno-debug-disables-optimization" >> $GITHUB_ENV + echo "CXXFLAGS=-Rno-debug-disables-optimization" >> $GITHUB_ENV + fi + + - name: Build & Test id: build-test diff --git a/tools/install-intel-oneapi.sh b/tools/install-intel-oneapi.sh index a954274d8..a5d757188 100755 --- a/tools/install-intel-oneapi.sh +++ b/tools/install-intel-oneapi.sh @@ -1,5 +1,6 @@ -#!/bin/sh +#!/usr/bin/env bash +version=2023.2.0 KEY=GPG-PUB-KEY-INTEL-SW-PRODUCTS.PUB wget https://apt.repos.intel.com/intel-gpg-keys/$KEY sudo apt-key add $KEY @@ -7,8 +8,7 @@ rm $KEY echo "deb https://apt.repos.intel.com/oneapi all main" | sudo tee /etc/apt/sources.list.d/oneAPI.list sudo apt-get update sudo apt-get install \ - intel-oneapi-compiler-fortran \ - intel-oneapi-compiler-dpcpp-cpp-and-cpp-classic \ + intel-oneapi-compiler-fortran-$version \ + intel-oneapi-compiler-dpcpp-cpp-and-cpp-classic-$version \ intel-oneapi-mpi \ - intel-oneapi-mpi-devel \ - intel-oneapi-mkl + intel-oneapi-mkl-$version From 04080a6a13bc104fc35f81e1e9ad9155c096beab Mon Sep 17 00:00:00 2001 From: Willem Deconinck Date: Fri, 24 Nov 2023 16:14:43 +0100 Subject: [PATCH 15/25] GHA: Install intel-oneapi with mpi-devel for access to MPI headers and Fortran modules --- tools/install-intel-oneapi.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/install-intel-oneapi.sh b/tools/install-intel-oneapi.sh index a5d757188..b6db3853b 100755 --- a/tools/install-intel-oneapi.sh +++ b/tools/install-intel-oneapi.sh @@ -10,5 +10,5 @@ sudo apt-get update sudo apt-get install \ intel-oneapi-compiler-fortran-$version \ intel-oneapi-compiler-dpcpp-cpp-and-cpp-classic-$version \ - intel-oneapi-mpi \ + intel-oneapi-mpi-devel-2021.10.0 \ intel-oneapi-mkl-$version From e86460549361604e28c32e5cec7bf343dbd672c0 Mon Sep 17 00:00:00 2001 From: Willem Deconinck Date: Mon, 27 Nov 2023 10:43:55 +0100 Subject: [PATCH 16/25] Fix failing tests for IntelLLVM Release builds --- src/tests/functionspace/test_pointcloud_halo_creation.cc | 8 +++++--- src/tests/redistribution/test_redistribution_generic.cc | 5 +++++ 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/src/tests/functionspace/test_pointcloud_halo_creation.cc b/src/tests/functionspace/test_pointcloud_halo_creation.cc index 2ee1593a1..32e817308 100644 --- a/src/tests/functionspace/test_pointcloud_halo_creation.cc +++ b/src/tests/functionspace/test_pointcloud_halo_creation.cc @@ -28,6 +28,8 @@ using namespace atlas::util; namespace atlas { namespace test { +constexpr double tol = 1.e-12; + //----------------------------------------------------------------------------- CASE("Distributed creation from unstructured grid with halo") { @@ -237,7 +239,7 @@ for (idx_t i=0; i = nullptr> Value castValue(const double& inVal) { + constexpr double eps = 1.e-12; + Value rounded_minus_half = std::round(inVal-0.5); + if (std::abs(rounded_minus_half - (inVal-0.5)) < eps) { + return static_cast(rounded_minus_half); + } return static_cast(std::round(inVal)); } From b3c491807e285dc1e46daba0899eef1a3ef28eae Mon Sep 17 00:00:00 2001 From: Slavko Brdar Date: Tue, 28 Nov 2023 10:25:44 +0100 Subject: [PATCH 17/25] Feature/fortran api init functions (#165) * add Fortran API for MDPI initial functions * add a fortran unit test for Fortran API for util/function/MDPI_functions --- src/atlas/util/function/MDPI_functions.cc | 15 ++++ src/atlas/util/function/MDPI_functions.h | 7 ++ src/atlas_f/CMakeLists.txt | 1 + src/atlas_f/atlas_module.F90 | 1 + src/atlas_f/util/atlas_functions_module.F90 | 83 +++++++++++++++++++ src/tests/util/CMakeLists.txt | 7 ++ src/tests/util/fctest_functions.F90 | 88 +++++++++++++++++++++ 7 files changed, 202 insertions(+) create mode 100644 src/atlas_f/util/atlas_functions_module.F90 create mode 100644 src/tests/util/fctest_functions.F90 diff --git a/src/atlas/util/function/MDPI_functions.cc b/src/atlas/util/function/MDPI_functions.cc index 121d2602d..f570ac5b7 100644 --- a/src/atlas/util/function/MDPI_functions.cc +++ b/src/atlas/util/function/MDPI_functions.cc @@ -118,6 +118,21 @@ double MDPI_gulfstream(double lon, double lat) { return background_func + dc * (std::max(1000. * std::sin(0.4 * (0.5 * dr + dth) + 0.007 * std::cos(50. * dth) + 0.37 * M_PI), 999.) - 999.); } +extern "C" { + double atlas__functions__MDPI_sinusoid(double& lon, double& lat) { + return MDPI_sinusoid(lon, lat); + } + double atlas__functions__MDPI_harmonic(double& lon, double& lat) { + return MDPI_harmonic(lon, lat); + } + double atlas__functions__MDPI_vortex(double& lon, double& lat) { + return MDPI_vortex(lon, lat); + } + double atlas__functions__MDPI_gulfstream(double& lon, double& lat) { + return MDPI_gulfstream(lon, lat); + } +} + } // namespace function } // namespace util } // namespace atlas diff --git a/src/atlas/util/function/MDPI_functions.h b/src/atlas/util/function/MDPI_functions.h index b60544536..73ff406ac 100644 --- a/src/atlas/util/function/MDPI_functions.h +++ b/src/atlas/util/function/MDPI_functions.h @@ -30,6 +30,13 @@ double MDPI_harmonic(double lon, double lat); double MDPI_vortex(double lon, double lat); double MDPI_gulfstream(double lon, double lat); +extern "C" { + double atlas__functions__MDPI_sinusoid(double& lon, double& lat); + double atlas__functions__MDPI_harmonic(double& lon, double& lat); + double atlas__functions__MDPI_vortex(double& lon, double& lat); + double atlas__functions__MDPI_gulfstream(double& lon, double& lat); +} + } // namespace function } // namespace util diff --git a/src/atlas_f/CMakeLists.txt b/src/atlas_f/CMakeLists.txt index f1b831e3c..3c3d396e0 100644 --- a/src/atlas_f/CMakeLists.txt +++ b/src/atlas_f/CMakeLists.txt @@ -205,6 +205,7 @@ ecbuild_add_library( TARGET atlas_f SOURCES ${FORTRAN_BINDINGS} atlas_module.F90 + util/atlas_functions_module.F90 util/atlas_kinds_module.F90 util/atlas_JSON_module.F90 util/atlas_Config_module.F90 diff --git a/src/atlas_f/atlas_module.F90 b/src/atlas_f/atlas_module.F90 index 48ffe33ae..975ea4e92 100644 --- a/src/atlas_f/atlas_module.F90 +++ b/src/atlas_f/atlas_module.F90 @@ -150,6 +150,7 @@ module atlas_module & atlas_output_Gmsh use atlas_trace_module, only : & & atlas_Trace +use atlas_functions_module use fckit_log_module, only: atlas_log => fckit_log diff --git a/src/atlas_f/util/atlas_functions_module.F90 b/src/atlas_f/util/atlas_functions_module.F90 new file mode 100644 index 000000000..ee94b80e2 --- /dev/null +++ b/src/atlas_f/util/atlas_functions_module.F90 @@ -0,0 +1,83 @@ +! (C) Copyright 2013 ECMWF. +! +! This software is licensed under the terms of the Apache Licence Version 2.0 +! which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. +! In applying this licence, ECMWF does not waive the privileges and immunities +! granted to it by virtue of its status as an intergovernmental organisation nor +! does it submit to any jurisdiction. + +#include "atlas/atlas_f.h" + +module atlas_functions_module + +use, intrinsic :: iso_c_binding + +implicit none + +interface + +pure function atlas__functions__MDPI_sinusoid( lon, lat ) bind(C,name="atlas__functi& + &ons__MDPI_sinusoid") + use iso_c_binding, only: c_double + real(c_double) :: atlas__functions__MDPI_sinusoid + real(c_double), intent(in) :: lon, lat +end function + +pure function atlas__functions__MDPI_harmonic( lon, lat ) bind(C,name="atlas__functi& + &ons__MDPI_harmonic") + use iso_c_binding, only: c_double + real(c_double) :: atlas__functions__MDPI_harmonic + real(c_double), intent(in) :: lon, lat +end function + +pure function atlas__functions__MDPI_vortex( lon, lat ) bind(C,name="atlas__function& + &s__MDPI_vortex") + use iso_c_binding, only: c_double + real(c_double) :: atlas__functions__MDPI_vortex + real(c_double), intent(in) :: lon, lat +end function + +pure function atlas__functions__MDPI_gulfstream( lon, lat ) bind(C,name="atlas__func& + &tions__MDPI_gulfstream") + use iso_c_binding, only: c_double + real(c_double) :: atlas__functions__MDPI_gulfstream + real(c_double), intent(in) :: lon, lat +end function + +end interface + +contains + +elemental function MDPI_sinusoid(lon, lat) result(val) + real(c_double), intent(in) :: lon, lat + real(c_double) :: val + val = atlas__functions__MDPI_sinusoid(lon, lat) +end function MDPI_sinusoid + +! ----------------------------------------------------------------------------- + +elemental function MDPI_harmonic(lon, lat) result(val) + real(c_double), intent(in) :: lon, lat + real(c_double) :: val + val = atlas__functions__MDPI_harmonic(lon, lat) +end function MDPI_harmonic + +! ----------------------------------------------------------------------------- + +elemental function MDPI_vortex(lon, lat) result(val) + real(c_double), intent(in) :: lon, lat + real(c_double) :: val + val = atlas__functions__MDPI_vortex(lon, lat) +end function MDPI_vortex + +! ----------------------------------------------------------------------------- + +elemental function MDPI_gulfstream(lon, lat) result(val) + real(c_double), intent(in) :: lon, lat + real(c_double) :: val + val = atlas__functions__MDPI_gulfstream(lon, lat) +end function MDPI_gulfstream + +! ----------------------------------------------------------------------------- + +end module atlas_functions_module diff --git a/src/tests/util/CMakeLists.txt b/src/tests/util/CMakeLists.txt index 0566bd3f9..4e6e0daf0 100644 --- a/src/tests/util/CMakeLists.txt +++ b/src/tests/util/CMakeLists.txt @@ -9,6 +9,13 @@ if( HAVE_FCTEST ) + add_fctest( TARGET atlas_fctest_functions + LINKER_LANGUAGE Fortran + SOURCES fctest_functions.F90 + LIBS atlas_f + ENVIRONMENT ${ATLAS_TEST_ENVIRONMENT} + ) + add_fctest( TARGET atlas_fctest_logging LINKER_LANGUAGE Fortran SOURCES fctest_logging.F90 diff --git a/src/tests/util/fctest_functions.F90 b/src/tests/util/fctest_functions.F90 new file mode 100644 index 000000000..7b2fa94ff --- /dev/null +++ b/src/tests/util/fctest_functions.F90 @@ -0,0 +1,88 @@ +! (C) Copyright 2013 ECMWF. +! This software is licensed under the terms of the Apache Licence Version 2.0 +! which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. +! In applying this licence, ECMWF does not waive the privileges and immunities +! granted to it by virtue of its status as an intergovernmental organisation nor +! does it submit to any jurisdiction. + +! This File contains Unit Tests for testing the +! C++ / Fortran Interfaces to the logging facilities +! @author Willem Deconinck + +#include "fckit/fctest.h" + +! ----------------------------------------------------------------------------- + +module fcta_functions_fxt +use atlas_module +use, intrinsic :: iso_c_binding +implicit none +character(len=1024) :: msg + +end module fcta_functions_fxt + +! ----------------------------------------------------------------------------- + +TESTSUITE_WITH_FIXTURE(fctest_atlas_functions,fcta_functions_fxt) + +! ----------------------------------------------------------------------------- +TESTSUITE_INIT + call atlas_library%initialise() +END_TESTSUITE_INIT + +! ----------------------------------------------------------------------------- + +TESTSUITE_FINALIZE + call atlas_library%finalise() +END_TESTSUITE_FINALIZE + +! ----------------------------------------------------------------------------- + +TEST( test_atlas_Functions ) + real(c_double) :: val + val = MDPI_sinusoid(1._c_double, 1._c_double) + FCTEST_CHECK_CLOSE(val, 1.0002115216773033_c_double, 1e-12_c_double) + val = MDPI_harmonic(1._c_double, 1._c_double) + FCTEST_CHECK_CLOSE(val, 2.0000000000000000_c_double, 1e-12_c_double) + val = MDPI_vortex(1._c_double, 1._c_double) + FCTEST_CHECK_CLOSE(val, 2.7267489215500755_c_double, 1e-12_c_double) + val = MDPI_gulfstream(1._c_double, 1._c_double) + FCTEST_CHECK_CLOSE(val, 1.0002115216773033_c_double, 1e-12_c_double) +END_TEST + +TEST( test_atlas_Functions_vector ) + real(c_double), dimension(3) :: val, lon, lat, val_ref + lon = [ 1._c_double, 2._c_double, 3._c_double ] + lat = [ 1._c_double, 2._c_double, 3._c_double ] + val = MDPI_sinusoid(lon, lat) + val_ref = [1.0002115216773033_c_double, 1.0008458683590891_c_double, 1.0019023851484181_c_double] + FCTEST_CHECK_CLOSE(val, val_ref, 1e-12_c_double) + val = MDPI_harmonic(lon, lat) + val_ref = [2.0000000000000000_c_double, 2.0000000000000000_c_double, 2.0000000000000000_c_double] + FCTEST_CHECK_CLOSE(val, val_ref, 1e-12_c_double) + val = MDPI_vortex(lon, lat) + val_ref = [2.7267489215500755_c_double, 2.7520839004022091_c_double, 2.7755506683886928_c_double] + FCTEST_CHECK_CLOSE(val, val_ref, 1e-12_c_double) + val = MDPI_gulfstream(lon, lat) + val_ref = [1.0002115216773033_c_double, 1.0008458683590891_c_double, 1.0019023851484181_c_double] + FCTEST_CHECK_CLOSE(val, val_ref, 1e-12_c_double) +END_TEST + +TEST( test_initialise_field ) + type(atlas_Field) :: field_xy, field_val + real(c_double), dimension(:,:), pointer :: field_xy_v + real(c_double), dimension(:), pointer :: field_val_v + real(c_double), dimension(3) :: field_val_ref + field_xy = atlas_Field(kind=atlas_real(c_double), shape=[2,3]) + field_val = atlas_Field(kind=atlas_real(c_double), shape=[3]) + call field_xy%data(field_xy_v) + field_xy_v = 1._c_double + call field_val%data(field_val_v) + field_val_v = MDPI_sinusoid(field_xy_v(1,:), field_xy_v(2,:)) + field_val_ref = [1.0002115216773033_c_double, 1.0002115216773033_c_double, 1.0002115216773033_c_double] + FCTEST_CHECK_CLOSE(field_val_v, field_val_ref, 1e-12_c_double) +END_TEST + +! ----------------------------------------------------------------------------- + +END_TESTSUITE From f3f83fcefbf7a6ca7c7fb62b28f67de66ebec3f0 Mon Sep 17 00:00:00 2001 From: Willem Deconinck Date: Wed, 6 Dec 2023 18:08:15 +0000 Subject: [PATCH 18/25] Fix MDPI_gulfstream: 180 degrees phase shift corrected --- src/atlas/util/function/MDPI_functions.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/atlas/util/function/MDPI_functions.cc b/src/atlas/util/function/MDPI_functions.cc index f570ac5b7..58713a037 100644 --- a/src/atlas/util/function/MDPI_functions.cc +++ b/src/atlas/util/function/MDPI_functions.cc @@ -93,7 +93,7 @@ double MDPI_gulfstream(double lon, double lat) { double dr1 = std::sqrt(sqr(gf_dmp_lon - gf_ori_lon) + sqr(gf_dmp_lat - gf_ori_lat)); double gf_per_lon = [lon,d2r]() { - double gf_per_lon = lon - 180.; + double gf_per_lon = lon; while (gf_per_lon > 180.) { gf_per_lon -= 360.; } From 68b09acef60294f10e455dfe905a86a7c96c9620 Mon Sep 17 00:00:00 2001 From: Willem Deconinck Date: Wed, 6 Dec 2023 17:02:20 +0000 Subject: [PATCH 19/25] Fix MatchingMeshPartitionerBruteForce --- .../partitioner/MatchingMeshPartitionerBruteForce.cc | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/atlas/grid/detail/partitioner/MatchingMeshPartitionerBruteForce.cc b/src/atlas/grid/detail/partitioner/MatchingMeshPartitionerBruteForce.cc index c99afe0c1..408014ba8 100644 --- a/src/atlas/grid/detail/partitioner/MatchingMeshPartitionerBruteForce.cc +++ b/src/atlas/grid/detail/partitioner/MatchingMeshPartitionerBruteForce.cc @@ -16,7 +16,7 @@ #include "atlas/array/ArrayView.h" #include "atlas/field/Field.h" -#include "atlas/grid/Grid.h" +#include "atlas/grid.h" #include "atlas/mesh/Elements.h" #include "atlas/mesh/Mesh.h" #include "atlas/mesh/Nodes.h" @@ -93,21 +93,23 @@ void MatchingMeshPartitionerBruteForce::partition(const Grid& grid, int partitio auto lonlat_src = array::make_view(prePartitionedMesh_.nodes().lonlat()); std::vector coordinates; + coordinates.reserve(lonlat_src.shape(0)); PointLonLat coordinatesMin = PointLonLat(lonlat_src(0, LON), lonlat_src(0, LAT)); PointLonLat coordinatesMax = coordinatesMin; - for (idx_t i = 0; i < lonlat_src.size(); ++i) { + for (idx_t i = 0; i < lonlat_src.shape(0); ++i) { PointLonLat A(lonlat_src(i, LON), lonlat_src(i, LAT)); coordinatesMin = PointLonLat::componentsMin(coordinatesMin, A); coordinatesMax = PointLonLat::componentsMax(coordinatesMax, A); - coordinates.push_back(A); + coordinates.emplace_back(A); } { eckit::ProgressTimer timer("Partitioning target", grid.size(), "point", double(10), atlas::Log::trace()); - for (idx_t i = 0; i < grid.size(); ++i, ++timer) { + auto grid_iter = grid.lonlat().begin(); + for (idx_t i = 0; i < grid.size(); ++i, ++grid_iter) { partitioning[i] = -1; - const PointLonLat& P(coordinates[i]); + const PointLonLat& P = *grid_iter; if (coordinatesMin[LON] <= P[LON] && P[LON] <= coordinatesMax[LON] && coordinatesMin[LAT] <= P[LAT] && P[LAT] <= coordinatesMax[LAT]) { From de9c9fde6d17a6e18c17a4c5176f2da10ad33f9f Mon Sep 17 00:00:00 2001 From: Willem Deconinck Date: Thu, 7 Dec 2023 11:05:17 +0000 Subject: [PATCH 20/25] Add fallback mechanism to MatchingMeshPartitionerLonLatPolygon --- .../MatchingMeshPartitionerLonLatPolygon.cc | 55 +++++++++++++++---- .../MatchingMeshPartitionerLonLatPolygon.h | 5 +- 2 files changed, 47 insertions(+), 13 deletions(-) diff --git a/src/atlas/grid/detail/partitioner/MatchingMeshPartitionerLonLatPolygon.cc b/src/atlas/grid/detail/partitioner/MatchingMeshPartitionerLonLatPolygon.cc index d517c8b2b..0e06d587e 100644 --- a/src/atlas/grid/detail/partitioner/MatchingMeshPartitionerLonLatPolygon.cc +++ b/src/atlas/grid/detail/partitioner/MatchingMeshPartitionerLonLatPolygon.cc @@ -28,6 +28,9 @@ #include "atlas/util/CoordinateEnums.h" #include "atlas/util/PolygonXY.h" + +#include "atlas/util/KDTree.h" + namespace atlas { namespace grid { namespace detail { @@ -37,6 +40,12 @@ namespace { PartitionerBuilder __builder("lonlat-polygon"); } +MatchingMeshPartitionerLonLatPolygon::MatchingMeshPartitionerLonLatPolygon(const Mesh& mesh, const eckit::Parametrisation& config): + MatchingMeshPartitioner(mesh, config) { + config.get("fallback_nearest", fallback_nearest_); + } + + void MatchingMeshPartitionerLonLatPolygon::partition(const Grid& grid, int partitioning[]) const { const auto& comm = mpi::comm(prePartitionedMesh_.mpi_comm()); const int mpi_rank = int(comm.rank()); @@ -122,6 +131,7 @@ void MatchingMeshPartitionerLonLatPolygon::partition(const Grid& grid, int parti } return false; }(); + if (min < 0) { size_t i = 0; size_t max_failures = grid.size(); @@ -137,20 +147,41 @@ void MatchingMeshPartitionerLonLatPolygon::partition(const Grid& grid, int parti ++i; } size_t nb_failures = failed_index.size(); - std::stringstream err; - err.precision(20); - err << "Could not find partition of " << nb_failures - << " target grid points (source mesh does not contain all target grid points)\n" - << "Tried first normalizing coordinates with west=" << east - 360.; - if (second_try) { - err << "Tried second time normalizing coordinates with west=" << west - eps << "\n"; + + if (fallback_nearest_) { + util::IndexKDTree3D kdtree; + kdtree.reserve(grid.size()); + size_t j=0; + for (auto& p: grid.lonlat()) { + if (partitioning[j] >= 0) { + kdtree.insert(p,partitioning[j]); + } + ++j; + } + kdtree.build(); + for (size_t n = 0; n < nb_failures; ++n) { + auto closest = kdtree.closestPoint(failed_lonlat[n]); + partitioning[failed_index[n]] = closest.payload(); + } } - err << "Failed target grid points with global index:\n"; - for (size_t n = 0; n < nb_failures; ++n) { - err << " - " << std::setw(10) << std::left << failed_index[n] + 1 << " {lon,lat} : " << failed_lonlat[n] - << "\n"; + else { + std::stringstream err; + err.precision(20); + err << "Could not find partition of " << nb_failures + << " target grid points (source mesh does not contain all target grid points)\n" + << "Tried first normalizing coordinates with west=" << east - 360. << "\n"; + if (second_try) { + err << "Tried second time normalizing coordinates with west=" << west - eps << "\n"; + } + + err << "Failed target grid points with global index:\n"; + for (size_t n = 0; n < nb_failures; ++n) { + err << " - " << std::setw(10) << std::left << failed_index[n] + 1 << " {lon,lat} : " << failed_lonlat[n] + << "\n"; + } + // prePartitionedMesh_.polygon(0).outputPythonScript("partitions.py"); + throw_Exception(err.str(), Here()); } - throw_Exception(err.str(), Here()); } } diff --git a/src/atlas/grid/detail/partitioner/MatchingMeshPartitionerLonLatPolygon.h b/src/atlas/grid/detail/partitioner/MatchingMeshPartitionerLonLatPolygon.h index f0b11e5d3..4dd45f0ec 100644 --- a/src/atlas/grid/detail/partitioner/MatchingMeshPartitionerLonLatPolygon.h +++ b/src/atlas/grid/detail/partitioner/MatchingMeshPartitionerLonLatPolygon.h @@ -22,7 +22,7 @@ class MatchingMeshPartitionerLonLatPolygon : public MatchingMeshPartitioner { static std::string static_type() { return "lonlat-polygon"; } public: - MatchingMeshPartitionerLonLatPolygon(const Mesh& mesh, const eckit::Parametrisation& config): MatchingMeshPartitioner(mesh, config) {} + MatchingMeshPartitionerLonLatPolygon(const Mesh& mesh, const eckit::Parametrisation& config); MatchingMeshPartitionerLonLatPolygon(): MatchingMeshPartitioner() {} @@ -44,6 +44,9 @@ class MatchingMeshPartitionerLonLatPolygon : public MatchingMeshPartitioner { void partition(const Grid& grid, int partitioning[]) const; virtual std::string type() const { return static_type(); } + +private: + bool fallback_nearest_{false}; }; } // namespace partitioner From bdc4ccf276f8bb944251ee03fa95d70323f08117 Mon Sep 17 00:00:00 2001 From: Willem Deconinck Date: Thu, 7 Dec 2023 12:02:08 +0000 Subject: [PATCH 21/25] Add EqualAreaPartitioner which is geometry based compared to EqualRegionsPartitioner which is loadbalanced --- src/atlas/CMakeLists.txt | 2 + .../partitioner/EqualAreaPartitioner.cc | 56 +++++++++++++++++++ .../detail/partitioner/EqualAreaPartitioner.h | 43 ++++++++++++++ .../partitioner/EqualRegionsPartitioner.h | 8 ++- 4 files changed, 106 insertions(+), 3 deletions(-) create mode 100644 src/atlas/grid/detail/partitioner/EqualAreaPartitioner.cc create mode 100644 src/atlas/grid/detail/partitioner/EqualAreaPartitioner.h diff --git a/src/atlas/CMakeLists.txt b/src/atlas/CMakeLists.txt index 3627dd60d..02d2ec38d 100644 --- a/src/atlas/CMakeLists.txt +++ b/src/atlas/CMakeLists.txt @@ -288,6 +288,8 @@ grid/detail/partitioner/CubedSpherePartitioner.cc grid/detail/partitioner/CubedSpherePartitioner.h grid/detail/partitioner/EqualBandsPartitioner.cc grid/detail/partitioner/EqualBandsPartitioner.h +grid/detail/partitioner/EqualAreaPartitioner.cc +grid/detail/partitioner/EqualAreaPartitioner.h grid/detail/partitioner/EqualRegionsPartitioner.cc grid/detail/partitioner/EqualRegionsPartitioner.h grid/detail/partitioner/MatchingMeshPartitioner.h diff --git a/src/atlas/grid/detail/partitioner/EqualAreaPartitioner.cc b/src/atlas/grid/detail/partitioner/EqualAreaPartitioner.cc new file mode 100644 index 000000000..ced5a3957 --- /dev/null +++ b/src/atlas/grid/detail/partitioner/EqualAreaPartitioner.cc @@ -0,0 +1,56 @@ +/* + * (C) Copyright 2013 ECMWF. + * + * This software is licensed under the terms of the Apache Licence Version 2.0 + * which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. + * In applying this licence, ECMWF does not waive the privileges and immunities + * granted to it by virtue of its status as an intergovernmental organisation + * nor does it submit to any jurisdiction. + */ + +#include "atlas/grid/detail/partitioner/EqualAreaPartitioner.h" + +#include "atlas/grid/Grid.h" +#include "atlas/grid/Iterator.h" +#include "atlas/util/Constants.h" + +namespace atlas { +namespace grid { +namespace detail { +namespace partitioner { + +EqualAreaPartitioner::EqualAreaPartitioner(): + Partitioner(), partitioner_() { +} + +EqualAreaPartitioner::EqualAreaPartitioner(int N): + EqualAreaPartitioner(N, util::NoConfig()) { +} + +EqualAreaPartitioner::EqualAreaPartitioner(int N, const eckit::Parametrisation& config): + Partitioner(N,config), partitioner_(N,config) { +} + +EqualAreaPartitioner::EqualAreaPartitioner(const eckit::Parametrisation& config): + Partitioner(config), partitioner_(config) { +} + +void EqualAreaPartitioner::partition(const Grid& g, int part[]) const { + size_t j{0}; + for (PointLonLat p : g.lonlat()) { + p.lon() *= util::Constants::degreesToRadians(); + p.lat() *= util::Constants::degreesToRadians(); + part[j++] = partitioner_.partition(p.lon(), p.lat()); + } +} + + +} // namespace partitioner +} // namespace detail +} // namespace grid +} // namespace atlas + +namespace { +atlas::grid::detail::partitioner::PartitionerBuilder + __EqualArea("equal_area"); +} diff --git a/src/atlas/grid/detail/partitioner/EqualAreaPartitioner.h b/src/atlas/grid/detail/partitioner/EqualAreaPartitioner.h new file mode 100644 index 000000000..87f43e024 --- /dev/null +++ b/src/atlas/grid/detail/partitioner/EqualAreaPartitioner.h @@ -0,0 +1,43 @@ +/* + * (C) Copyright 2023 ECMWF. + * + * This software is licensed under the terms of the Apache Licence Version 2.0 + * which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. + * In applying this licence, ECMWF does not waive the privileges and immunities + * granted to it by virtue of its status as an intergovernmental organisation + * nor does it submit to any jurisdiction. + */ + +#pragma once + +#include + +#include "atlas/grid/detail/partitioner/EqualRegionsPartitioner.h" +#include "atlas/grid/detail/partitioner/Partitioner.h" + +namespace atlas { +namespace grid { +namespace detail { +namespace partitioner { + +class EqualAreaPartitioner : public Partitioner { +public: + EqualAreaPartitioner(); + EqualAreaPartitioner(int N); + EqualAreaPartitioner(int N, const eckit::Parametrisation& config); + EqualAreaPartitioner(const eckit::Parametrisation& config); + + using Partitioner::partition; + void partition(const Grid&, int part[]) const override; + + std::string type() const override { return "equal_area"; } + +private: + EqualRegionsPartitioner partitioner_; +}; + + +} // namespace partitioner +} // namespace detail +} // namespace grid +} // namespace atlas diff --git a/src/atlas/grid/detail/partitioner/EqualRegionsPartitioner.h b/src/atlas/grid/detail/partitioner/EqualRegionsPartitioner.h index a795a6f15..511879993 100644 --- a/src/atlas/grid/detail/partitioner/EqualRegionsPartitioner.h +++ b/src/atlas/grid/detail/partitioner/EqualRegionsPartitioner.h @@ -75,6 +75,7 @@ namespace partitioner { void eq_caps(int N, std::vector& n_regions, std::vector& s_cap); void eq_regions(int N, double xmin[], double xmax[], double ymin[], double ymax[]); +class EqualAreaPartitioner; class EqualRegionsPartitioner : public Partitioner { public: EqualRegionsPartitioner(); @@ -121,15 +122,16 @@ class EqualRegionsPartitioner : public Partitioner { // algorithm is used internally void partition(int nb_nodes, NodeInt nodes[], int part[]) const; - // x and y in radians - int partition(const double& x, const double& y) const; - + friend class EqualAreaPartitioner; // y in radians int band(const double& y) const; // x in radians int sector(int band, const double& x) const; + // x and y in radians + int partition(const double& x, const double& y) const; + private: int N_; std::vector bands_; From 5517a960965886161925d7a8a2482433605107c5 Mon Sep 17 00:00:00 2001 From: Willem Deconinck Date: Thu, 7 Dec 2023 15:15:51 +0000 Subject: [PATCH 22/25] Performance improvement in EqualAreaPartitioner for StructuredGrid --- src/apps/atlas-grid-points.cc | 2 +- .../partitioner/EqualAreaPartitioner.cc | 35 +++++++++++++++---- .../partitioner/EqualRegionsPartitioner.cc | 10 +++--- src/atlas/util/GridPointsJSONWriter.cc | 5 +++ 4 files changed, 40 insertions(+), 12 deletions(-) diff --git a/src/apps/atlas-grid-points.cc b/src/apps/atlas-grid-points.cc index 86cf4c674..8a74c83c0 100644 --- a/src/apps/atlas-grid-points.cc +++ b/src/apps/atlas-grid-points.cc @@ -55,7 +55,7 @@ Program::Program(int argc, char** argv): AtlasTool(argc, argv) { add_option(new SimpleOption("field","Field to output. [\"lonlat\"(D),\"index\",\"partition\"]")); add_option(new Separator("Advanced")); add_option(new SimpleOption("partitioner.type", - "Partitioner [equal_regions,checkerboard,equal_bands,regular_bands]")); + "Partitioner [equal_regions,equal_area,checkerboard,equal_bands,regular_bands]")); add_option(new SimpleOption("partition", "partition [0:partitions-1]")); add_option(new SimpleOption("partitions", "Number of partitions")); add_option(new SimpleOption("json.precision", "Number of digits after decimal in output")); diff --git a/src/atlas/grid/detail/partitioner/EqualAreaPartitioner.cc b/src/atlas/grid/detail/partitioner/EqualAreaPartitioner.cc index ced5a3957..ac585e316 100644 --- a/src/atlas/grid/detail/partitioner/EqualAreaPartitioner.cc +++ b/src/atlas/grid/detail/partitioner/EqualAreaPartitioner.cc @@ -10,7 +10,7 @@ #include "atlas/grid/detail/partitioner/EqualAreaPartitioner.h" -#include "atlas/grid/Grid.h" +#include "atlas/grid.h" #include "atlas/grid/Iterator.h" #include "atlas/util/Constants.h" @@ -35,13 +35,34 @@ EqualAreaPartitioner::EqualAreaPartitioner(const eckit::Parametrisation& config) Partitioner(config), partitioner_(config) { } -void EqualAreaPartitioner::partition(const Grid& g, int part[]) const { - size_t j{0}; - for (PointLonLat p : g.lonlat()) { - p.lon() *= util::Constants::degreesToRadians(); - p.lat() *= util::Constants::degreesToRadians(); - part[j++] = partitioner_.partition(p.lon(), p.lat()); +void EqualAreaPartitioner::partition(const Grid& grid, int part[]) const { + + if( partitioner_.coordinates_ == EqualRegionsPartitioner::Coordinates::XY && StructuredGrid(grid) ) { + StructuredGrid g(grid); + size_t n = 0; + for (idx_t j=0; j 2. * M_PI) { - xreg -= 2. * M_PI; + else if (x > two_pi) { + xreg -= two_pi; } - return std::floor(xreg * sectors_[band] / (2. * M_PI + 1e-8)); + return std::floor(xreg * sectors_[band] * div_two_pi); } void EqualRegionsPartitioner::where(int partition, int& band, int& sector) const { diff --git a/src/atlas/util/GridPointsJSONWriter.cc b/src/atlas/util/GridPointsJSONWriter.cc index e7066ad77..7888a0c9a 100644 --- a/src/atlas/util/GridPointsJSONWriter.cc +++ b/src/atlas/util/GridPointsJSONWriter.cc @@ -98,6 +98,11 @@ void GridPointsJSONWriter::write(std::ostream& out, eckit::Channel& info) const //------------------------------------------------------------------------------ void GridPointsJSONWriter::write(std::ostream& out, std::ostream* info) const { + + if (field_ == "none") { + return; + } + int points_newline = pretty_ ? true : false; int points_indent = pretty_ ? 2 : 0; int partition_indent = 0; From 2ffed1dd47a5361a7dc058da6de6c62387b4fa86 Mon Sep 17 00:00:00 2001 From: Willem Deconinck Date: Thu, 7 Dec 2023 15:32:18 +0000 Subject: [PATCH 23/25] Add atlas_Redistribution to atlas_module --- src/atlas_f/atlas_module.F90 | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/atlas_f/atlas_module.F90 b/src/atlas_f/atlas_module.F90 index 975ea4e92..97ddb45ae 100644 --- a/src/atlas_f/atlas_module.F90 +++ b/src/atlas_f/atlas_module.F90 @@ -151,7 +151,8 @@ module atlas_module use atlas_trace_module, only : & & atlas_Trace use atlas_functions_module - +use atlas_Redistribution_module, only : & + & atlas_Redistribution use fckit_log_module, only: atlas_log => fckit_log implicit none From f2e0bc286f23e13736796f58d67abe98f882771d Mon Sep 17 00:00:00 2001 From: Willem Deconinck Date: Wed, 6 Dec 2023 15:18:50 +0000 Subject: [PATCH 24/25] Version 0.36.0 --- VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION b/VERSION index 731b95d7f..93d4c1ef0 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -0.35.1 +0.36.0 From 7fd018d5eb3f44d28238c4c95dff4125c6b973a2 Mon Sep 17 00:00:00 2001 From: Willem Deconinck Date: Mon, 11 Dec 2023 13:18:58 +0100 Subject: [PATCH 25/25] Update Changelog --- CHANGELOG.md | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 15d1a9c05..55f29a917 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,7 +7,21 @@ This project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html ## [Unreleased] -## [0.35.1] - 2023-24-10 +## [0.36.0] - 2023-12-11 +### Added +- Add TriangularMeshBuilder with Fortran API, so far for serial meshes only +- Add Fortran API for CellCollumns functionspace +- Add EqualAreaPartitioner which is geometry based rather than loadbalanced like EqualRegionsPartitioner + +### Fixed +- Compilation with Intel LLVM compiler +- Fix 180 degrees phase shift error in MDPI_gulfstream function + +### Changed +- Update install scripts +- Preparation for using eckit::codec as backend for atlas_io + +## [0.35.1] - 2023-10-24 ### Added - Don't output with output::Gmsh the triangle elements with wrong orientation when coordinates are "lonlat" - Add control to skip Gmsh-output of triangles with too large edge length ratio @@ -500,6 +514,7 @@ Fix StructuredInterpolation2D with retry for failed stencils ## 0.13.0 - 2018-02-16 [Unreleased]: https://github.com/ecmwf/atlas/compare/master...develop +[0.36.0]: https://github.com/ecmwf/atlas/compare/0.35.1...0.36.0 [0.35.1]: https://github.com/ecmwf/atlas/compare/0.35.0...0.35.1 [0.35.0]: https://github.com/ecmwf/atlas/compare/0.34.0...0.35.0 [0.34.0]: https://github.com/ecmwf/atlas/compare/0.33.0...0.34.0