diff --git a/.gitignore b/.gitignore index 34208165b..92db20bec 100755 --- a/.gitignore +++ b/.gitignore @@ -5,3 +5,6 @@ doc/html doc/latex *.sublime-workspace .nfs* +build/* +install/* +env.sh diff --git a/.travis.yml b/.travis.yml index d32f179b3..4adb31759 100644 --- a/.travis.yml +++ b/.travis.yml @@ -67,7 +67,13 @@ matrix: - CXX_COMPILER='clang++' C_COMPILER='clang' Fortran_COMPILER='gfortran' - MPI=openmpi - ATLAS_CMAKE_OPTIONS="-DCMAKE_BUILD_TYPE=DEBUG" - osx_image: xcode9 + osx_image: xcode10.1 + addons: + homebrew: + packages: + - openmpi + - cgal + - fftw ################################## # KNOWN TO FAIL, so comment @@ -92,16 +98,6 @@ matrix: before_install: - ################################################################# - # Fixes to pre-installed packages - ################################################################# - - | - ### Fix pre-installed packages - if [[ "${TRAVIS_OS_NAME}" == "osx" ]]; then - brew update - brew list oclint || brew cask uninstall oclint # Prevent conflict with gcc - fi - ################################################################# # Set compilers ################################################################# @@ -135,7 +131,9 @@ install: - | ### Install gcc (homebrew) if [[ "${TRAVIS_OS_NAME}" == "osx" ]]; then - brew upgrade gcc || brew install gcc + export HOMEBREW_NO_AUTO_UPDATE=1 + brew install gcc + brew link gcc fi - | ### Install PGI community edition @@ -165,28 +163,26 @@ install: mkdir -p ${DEPS_DIR}/cmake && travis_retry wget --no-check-certificate --quiet -O - ${CMAKE_URL} | tar --strip-components=1 -xz -C ${DEPS_DIR}/cmake fi export PATH=${DEPS_DIR}/cmake/bin:${PATH} - else - brew upgrade cmake || brew install cmake fi cmake --version ################################################################# # Install FFTW ################################################################# - - | - ### Install FFTW - if [[ "${TRAVIS_OS_NAME}" == "osx" ]]; then - brew upgrade fftw || brew install fftw - fi + # - | + # ### Install FFTW + # if [[ "${TRAVIS_OS_NAME}" == "osx" ]]; then + # brew ls --versions fftw || brew install fftw + # fi ################################################################# # Install CGAL ################################################################# - - | - ### Install CGAL - if [[ "${TRAVIS_OS_NAME}" == "osx" ]]; then - brew upgrade cgal || brew install cgal - fi + # - | + # ### Install CGAL + # if [[ "${TRAVIS_OS_NAME}" == "osx" ]]; then + # brew ls --versions cgal || brew install cgal + # fi ################################################################# # Install ecbuild @@ -240,7 +236,7 @@ script: ################################################################# # Test Atlas ################################################################# - - ctest -VV + - ctest after_success: diff --git a/CHANGELOG.md b/CHANGELOG.md index b3ee8a03e..dd56d2128 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,28 @@ This project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html ## [Unreleased] +## [0.16.0] - 2018-02-14 +### Changed +- Interpolation makes use of OpenMP +- Cleanup of header includes +- fypp Fortran preprocessor is ported to fckit 0.6 + +### Added +- Parallel structured interpolation methods (2D,3D): linear, cubic, quasicubic +- Interpolation for multi-level and multi-variable fields +- atlas_Trace: Fortran API and use within OpenMP parallel regions +- StructuredColumns halo-exchange for vector fields +- Field::halo_exchange() function + +### Fixed +- Fortran compilation with PGI 18.10 +- Access to Field view within OpenMP parallel region +- FunctionSpaces use only required halo, even if larger halo is available in mesh +- Fixed faulty name of a Field when created through Fortran API, wrapping existing memory +- Fix NodeColumns functionspace when mesh is created from projected grid. +- Parallel interpolation from regular lonlat grid. +- Spectral spherical harmonics transforms for large cases + ## [0.15.2] - 2018-08-31 ### Changed - Initialisation of Fields to signalling NaN in debug builds, uninitialised in @@ -58,6 +80,7 @@ This project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html ## 0.13.0 - 2018-02-16 [Unreleased]: https://github.com/ecmwf/atlas/compare/master...develop +[0.16.0]: https://github.com/ecmwf/atlas/compare/0.15.2...0.16.0 [0.15.2]: https://github.com/ecmwf/atlas/compare/0.15.1...0.15.2 [0.15.1]: https://github.com/ecmwf/atlas/compare/0.15.0...0.15.1 [0.15.0]: https://github.com/ecmwf/atlas/compare/0.14.0...0.15.0 diff --git a/CMakeLists.txt b/CMakeLists.txt index 657d07dfe..250f835da 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -44,7 +44,7 @@ ecbuild_find_python() ecbuild_add_option( FEATURE FORTRAN DESCRIPTION "Provide Fortran bindings" - REQUIRED_PACKAGES "PROJECT fckit VERSION 0.5" ) + REQUIRED_PACKAGES "PROJECT fckit VERSION 0.6" ) if( ATLAS_HAVE_FORTRAN ) @@ -123,6 +123,9 @@ if( ATLAS_HAVE_TESSELATION ) list( APPEND CGAL_INCLUDE_DIRS ${Boost_INCLUDE_DIRS} ) if ( TARGET CGAL::CGAL ) list( APPEND CGAL_LIBRARIES CGAL::CGAL ${CGAL_3RD_PARTY_LIBRARIES} ${GMP_LIBRARIES} ${MPFR_LIBRARIES} ${Boost_THREAD_LIBRARY} ${Boost_SYSTEM_LIBRARY} ) + # Reset INTERFACE_COMPILE_OPTIONS ( see ATLAS-193 ) + get_target_property( CGAL_COMPILE_FLAGS CGAL::CGAL INTERFACE_COMPILE_OPTIONS ) + set_target_properties( CGAL::CGAL PROPERTIES INTERFACE_COMPILE_OPTIONS "" ) else() list( APPEND CGAL_LIBRARIES ${CGAL_LIBRARY} ${CGAL_3RD_PARTY_LIBRARIES} ${GMP_LIBRARIES} ${MPFR_LIBRARIES} ${Boost_THREAD_LIBRARY} ${Boost_SYSTEM_LIBRARY} ) endif() @@ -187,6 +190,7 @@ ecbuild_add_option( FEATURE EIGEN ### Type for Global indices and unique point id's set( ATLAS_BITS_GLOBAL 64 ) +set( ATLAS_BITS_LOCAL 32 ) ### Bounds checking if( ${CMAKE_BUILD_TYPE} MATCHES "Debug" ) diff --git a/README.md b/README.md index e93a28e98..be49fb28d 100644 --- a/README.md +++ b/README.md @@ -1,11 +1,12 @@ Atlas ===== +[![atlas release version](https://img.shields.io/github/release/ecmwf/atlas.svg)](https://github.com/ecmwf/atlas/releases/latest) [![travis master](https://img.shields.io/travis/ecmwf/atlas/master.svg?label=master&logo=travis)](http://travis-ci.org/ecmwf/atlas "master") [![travis develop](https://img.shields.io/travis/ecmwf/atlas/develop.svg?label=develop&logo=travis)](http://travis-ci.org/ecmwf/atlas "develop") [![codecov](https://codecov.io/gh/ecmwf/atlas/branch/develop/graph/badge.svg)](https://codecov.io/gh/ecmwf/atlas) -Project home: https://software.ecmwf.int/wiki/display/ATLAS +Project home: https://confluence.ecmwf.int/display/ATLAS Contact: Willem Deconinck (willem.deconinck@ecmwf.int) Publication: > [Deconinck et al, 2017](https://doi.org/10.1016/j.cpc.2017.07.006) --- diff --git a/VERSION.cmake b/VERSION.cmake index dc6a640b7..c76c47b02 100644 --- a/VERSION.cmake +++ b/VERSION.cmake @@ -6,5 +6,5 @@ # granted to it by virtue of its status as an intergovernmental organisation nor # does it submit to any jurisdiction. -set ( ${PROJECT_NAME}_VERSION_STR "0.15.2" ) +set ( ${PROJECT_NAME}_VERSION_STR "0.16.0" ) diff --git a/bamboo/CLANG-env.sh b/bamboo/CLANG-env.sh index 7549c741d..c7bfda5aa 100644 --- a/bamboo/CLANG-env.sh +++ b/bamboo/CLANG-env.sh @@ -1,15 +1,24 @@ -# No module environment on the Mac -[[ $(uname) == "Darwin" ]] && return -# Initialise module environment if it is not +#!/bin/bash + +if [[ $(uname) == "Darwin" ]]; then + # Up to date CMake version required + export PATH=${HOME}/Applications/CMake.app/Contents/bin:${PATH} + # No module environment on the Mac + return +fi + +# initialise module environment if it is not if [[ ! $(command -v module > /dev/null 2>&1) ]]; then . /usr/local/apps/module/init/bash fi +module unload grib_api module unload eccodes module unload emos module unload fftw module unload libemos +module unload metview -module switch gnu clang -export FC=/usr/local/apps/gcc/6.3.0/bin/gfortran +module load cmake/3.10.2 +module switch gnu clang diff --git a/bamboo/CMakeLists.txt b/bamboo/CMakeLists.txt new file mode 100644 index 000000000..18b8087af --- /dev/null +++ b/bamboo/CMakeLists.txt @@ -0,0 +1,4 @@ +file( GLOB_RECURSE bamboo_files RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} "*" ) + +ecbuild_add_resources( TARGET ${PROJECT_NAME}_bamboo + SOURCES_DONT_PACK ${bamboo_files} ) diff --git a/bamboo/GCC-env.sh b/bamboo/GCC-env.sh new file mode 100644 index 000000000..3d58400c9 --- /dev/null +++ b/bamboo/GCC-env.sh @@ -0,0 +1,17 @@ +#!/bin/bash + +[[ $(uname) == "Darwin" ]] && return + +# initialise module environment if it is not +if [[ ! $(command -v module > /dev/null 2>&1) ]]; then + . /usr/local/apps/module/init/bash +fi + +module unload grib_api +module unload eccodes +module unload emos +module unload fftw +module unload libemos +module unload metview + +module load cmake/3.10.2 diff --git a/bamboo/INTEL-env.sh b/bamboo/INTEL-env.sh index 6715f9e8c..4b2e13f19 100644 --- a/bamboo/INTEL-env.sh +++ b/bamboo/INTEL-env.sh @@ -10,7 +10,8 @@ module unload eccodes module unload emos module unload fftw module unload libemos +module unload metview module load cmake/3.10.2 -module switch gnu intel/16.0.3 \ No newline at end of file +module switch gnu intel/17.0.3 diff --git a/bamboo/env.sh b/bamboo/env.sh new file mode 100644 index 000000000..393031a9d --- /dev/null +++ b/bamboo/env.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash + +# export ctest_parallel="no" + diff --git a/cmake/CompileFlags.cmake b/cmake/CompileFlags.cmake index ef238a21e..c391c849e 100644 --- a/cmake/CompileFlags.cmake +++ b/cmake/CompileFlags.cmake @@ -1,3 +1,11 @@ +# (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. + if( CMAKE_CXX_COMPILER_ID MATCHES Cray ) ecbuild_add_cxx_flags("-hnomessage=3140") # colon separated numbers diff --git a/cmake/atlas_host_device.cmake b/cmake/atlas_host_device.cmake index 77060a956..3a404a8e4 100644 --- a/cmake/atlas_host_device.cmake +++ b/cmake/atlas_host_device.cmake @@ -15,6 +15,8 @@ function( create_cuda_wrapper variable ) get_filename_component(directory ${_PAR_SOURCE} DIRECTORY) get_filename_component(base ${_PAR_SOURCE} NAME_WE) get_filename_component(name ${_PAR_SOURCE} NAME) + get_filename_component(abspath ${_PAR_SOURCE} ABSOLUTE) + if( directory ) set(cuda_wrapper ${CMAKE_CURRENT_BINARY_DIR}/${directory}/${base}.cu) else() @@ -25,7 +27,9 @@ function( create_cuda_wrapper variable ) " #include \"atlas/${directory}/${name}\" ") - file(WRITE ${cuda_wrapper} "${content}") + if( ${abspath} IS_NEWER_THAN ${cuda_wrapper} ) + file(WRITE ${cuda_wrapper} "${content}") + endif() endfunction() diff --git a/doc/user-guide/core-functionalities/fields/fields.cc b/doc/user-guide/core-functionalities/fields/fields.cc index 5f8cea3e3..cfdf0f7a9 100644 --- a/doc/user-guide/core-functionalities/fields/fields.cc +++ b/doc/user-guide/core-functionalities/fields/fields.cc @@ -8,7 +8,6 @@ using atlas::Field; using atlas::FieldSet; using atlas::Log; -using atlas::array::ArrayView; using atlas::array::make_datatype; using atlas::array::make_shape; using atlas::array::make_view; diff --git a/doc/user-guide/core-functionalities/functionspace/NodeColumns.cc b/doc/user-guide/core-functionalities/functionspace/NodeColumns.cc index df3bb57a8..8f0c5c65b 100644 --- a/doc/user-guide/core-functionalities/functionspace/NodeColumns.cc +++ b/doc/user-guide/core-functionalities/functionspace/NodeColumns.cc @@ -5,17 +5,17 @@ #include "atlas/library/Library.h" #include "atlas/mesh/Mesh.h" #include "atlas/mesh/Nodes.h" -#include "atlas/meshgenerator/StructuredMeshGenerator.h" +#include "atlas/meshgenerator.h" #include "atlas/output/Gmsh.h" #include "atlas/runtime/Log.h" using namespace atlas; +using atlas::StructuredMeshGenerator; using atlas::array::make_shape; using atlas::array::make_view; using atlas::functionspace::NodeColumns; using atlas::gidx_t; using atlas::grid::StructuredGrid; -using atlas::meshgenerator::StructuredMeshGenerator; using atlas::output::Gmsh; int main( int argc, char* argv[] ) { diff --git a/doc/user-guide/core-functionalities/functionspace/StructuredColumns.cc b/doc/user-guide/core-functionalities/functionspace/StructuredColumns.cc index 15a7086d8..f93e061f1 100644 --- a/doc/user-guide/core-functionalities/functionspace/StructuredColumns.cc +++ b/doc/user-guide/core-functionalities/functionspace/StructuredColumns.cc @@ -5,15 +5,14 @@ #include "atlas/grid.h" #include "atlas/library/Library.h" #include "atlas/mesh.h" -#include "atlas/meshgenerator/StructuredMeshGenerator.h" +#include "atlas/meshgenerator.h" #include "atlas/output/Gmsh.h" #include "atlas/util/CoordinateEnums.h" using namespace atlas; -using atlas::array::ArrayView; +using atlas::StructuredMeshGenerator; using atlas::array::make_view; using atlas::functionspace::StructuredColumns; -using atlas::meshgenerator::StructuredMeshGenerator; using atlas::output::Gmsh; int main( int argc, char* argv[] ) { diff --git a/doc/user-guide/core-functionalities/meshes/meshes-Structured.cc b/doc/user-guide/core-functionalities/meshes/meshes-Structured.cc index bcf3dc901..c7cc08bf8 100644 --- a/doc/user-guide/core-functionalities/meshes/meshes-Structured.cc +++ b/doc/user-guide/core-functionalities/meshes/meshes-Structured.cc @@ -1,13 +1,13 @@ #include "atlas/grid/Grid.h" #include "atlas/library/Library.h" #include "atlas/mesh/Mesh.h" -#include "atlas/meshgenerator/StructuredMeshGenerator.h" +#include "atlas/meshgenerator.h" #include "atlas/output/Gmsh.h" #include "atlas/util/Config.h" using atlas::Grid; using atlas::Mesh; -using atlas::meshgenerator::StructuredMeshGenerator; +using atlas::StructuredMeshGenerator; using atlas::output::Gmsh; using atlas::util::Config; diff --git a/src/apps/atlas-benchmark.cc b/src/apps/atlas-benchmark.cc index 8186332e5..7836a6a13 100644 --- a/src/apps/atlas-benchmark.cc +++ b/src/apps/atlas-benchmark.cc @@ -37,9 +37,6 @@ #include #include -#include "eckit/exception/Exceptions.h" -#include "eckit/log/Timer.h" - #include "atlas/functionspace.h" #include "atlas/grid.h" #include "atlas/library/Library.h" @@ -57,6 +54,7 @@ #include "atlas/parallel/mpi/mpi.h" #include "atlas/parallel/omp/omp.h" #include "atlas/runtime/AtlasTool.h" +#include "atlas/runtime/Exception.h" #include "atlas/runtime/Trace.h" #include "atlas/util/CoordinateEnums.h" #include "atlas/util/Earth.h" @@ -151,17 +149,18 @@ class AtlasBenchmark : public AtlasTool { private: Mesh mesh; functionspace::NodeColumns nodes_fs; + functionspace::NodeColumns edges_fs; Field scalar_field; Field grad_field; - vector pole_edges; + vector pole_edges; vector is_ghost; - size_t nnodes; - size_t nedges; - size_t nlev; - size_t niter; - size_t exclude; + idx_t nnodes; + idx_t nedges; + idx_t nlev; + idx_t niter; + idx_t exclude; bool output; long omp_threads; double dz; @@ -169,7 +168,7 @@ class AtlasBenchmark : public AtlasTool { TimerStats iteration_timer; TimerStats haloexchange_timer; - size_t iter; + idx_t iter; bool progress; public: @@ -280,14 +279,14 @@ void AtlasBenchmark::initial_condition( const Field& field, const double& beta ) auto lonlat_deg = array::make_view( mesh.nodes().lonlat() ); auto var = array::make_view( field ); - size_t nnodes = mesh.nodes().size(); - for ( size_t jnode = 0; jnode < nnodes; ++jnode ) { + idx_t nnodes = mesh.nodes().size(); + for ( idx_t jnode = 0; jnode < nnodes; ++jnode ) { double x = lonlat_deg( jnode, LON ) * deg2rad; double y = lonlat_deg( jnode, LAT ) * deg2rad; double Ux = pvel * ( std::cos( beta ) + std::tan( y ) * std::cos( x ) * std::sin( beta ) ) * radius * std::cos( y ); double Uy = -pvel * std::sin( x ) * std::sin( beta ) * radius; - for ( size_t jlev = 0; jlev < field.levels(); ++jlev ) + for ( idx_t jlev = 0; jlev < field.levels(); ++jlev ) var( jnode, jlev ) = std::sqrt( Ux * Ux + Uy * Uy ); } } @@ -295,7 +294,7 @@ void AtlasBenchmark::initial_condition( const Field& field, const double& beta ) //---------------------------------------------------------------------------------------------------------------------- void AtlasBenchmark::setup() { - size_t halo = 1; + idx_t halo = 1; StructuredGrid grid; ATLAS_TRACE_SCOPE( "Create grid" ) { grid = Grid( gridname ); } @@ -304,8 +303,7 @@ void AtlasBenchmark::setup() { } ATLAS_TRACE_SCOPE( "Create node_fs" ) { nodes_fs = functionspace::NodeColumns( mesh, option::halo( halo ) ); } - ATLAS_TRACE_SCOPE( "build_edges" ) { build_edges( mesh ); } - ATLAS_TRACE_SCOPE( "build_pole_edges" ) { build_pole_edges( mesh ); } + ATLAS_TRACE_SCOPE( "Create edges_fs" ) { edges_fs = functionspace::EdgeColumns( mesh, option::halo( halo ) ); } // mesh.polygon(0).outputPythonScript("plot_polygon.py"); // atlas::output::Output gmsh = atlas::output::Gmsh( "edges.msh", @@ -316,7 +314,6 @@ void AtlasBenchmark::setup() { // util::Config("ghost",true)("edges",false)("elements",true) ); // gmsh.write( mesh ); - ATLAS_TRACE_SCOPE( "build_edges_parallel_fiels" ) { build_edges_parallel_fields( mesh ); } ATLAS_TRACE_SCOPE( "build_median_dual_mesh" ) { build_median_dual_mesh( mesh ); } ATLAS_TRACE_SCOPE( "build_node_to_edge_connectivity" ) { build_node_to_edge_connectivity( mesh ); } @@ -330,14 +327,13 @@ void AtlasBenchmark::setup() { auto lonlat = array::make_view( mesh.nodes().xy() ); auto V = array::make_view( mesh.nodes().field( "dual_volumes" ) ); auto S = array::make_view( mesh.edges().field( "dual_normals" ) ); - auto field = array::make_view( scalar_field ); initial_condition( scalar_field, 0. ); double radius = 6371.22e+03; // Earth's radius double height = 80.e+03; // Height of atmosphere double deg2rad = M_PI / 180.; - atlas_omp_parallel_for( size_t jnode = 0; jnode < nnodes; ++jnode ) { + atlas_omp_parallel_for( idx_t jnode = 0; jnode < nnodes; ++jnode ) { lonlat( jnode, LON ) = lonlat( jnode, LON ) * deg2rad; lonlat( jnode, LAT ) = lonlat( jnode, LAT ) * deg2rad; double y = lonlat( jnode, LAT ); @@ -346,22 +342,21 @@ void AtlasBenchmark::setup() { double G = hx * hy; V( jnode ) *= std::pow( deg2rad, 2 ) * G; } - atlas_omp_parallel_for( size_t jedge = 0; jedge < nedges; ++jedge ) { + atlas_omp_parallel_for( idx_t jedge = 0; jedge < nedges; ++jedge ) { S( jedge, LON ) *= deg2rad; S( jedge, LAT ) *= deg2rad; } dz = height / static_cast( nlev ); - auto edge_is_pole = array::make_view( mesh.edges().field( "is_pole_edge" ) ); const mesh::Connectivity& node2edge = mesh.nodes().edge_connectivity(); const mesh::MultiBlockConnectivity& edge2node = mesh.edges().node_connectivity(); auto node2edge_sign = array::make_view( mesh.nodes().add( Field( "to_edge_sign", array::make_datatype(), array::make_shape( nnodes, node2edge.maxcols() ) ) ) ); - atlas_omp_parallel_for( size_t jnode = 0; jnode < nnodes; ++jnode ) { - for ( size_t jedge = 0; jedge < node2edge.cols( jnode ); ++jedge ) { - size_t iedge = node2edge( jnode, jedge ); - size_t ip1 = edge2node( iedge, 0 ); + atlas_omp_parallel_for( idx_t jnode = 0; jnode < nnodes; ++jnode ) { + for ( idx_t jedge = 0; jedge < node2edge.cols( jnode ); ++jedge ) { + idx_t iedge = node2edge( jnode, jedge ); + idx_t ip1 = edge2node( iedge, 0 ); if ( jnode == ip1 ) node2edge_sign( jnode, jedge ) = 1.; else @@ -369,18 +364,21 @@ void AtlasBenchmark::setup() { } } - vector tmp( nedges ); + auto edge_flags = array::make_view( mesh.edges().flags() ); + auto is_pole_edge = [&]( size_t e ) { return Topology::check( edge_flags( e ), Topology::POLE ); }; + + vector tmp( nedges ); int c( 0 ); - for ( size_t jedge = 0; jedge < nedges; ++jedge ) { - if ( edge_is_pole( jedge ) ) tmp[c++] = jedge; + for ( idx_t jedge = 0; jedge < nedges; ++jedge ) { + if ( is_pole_edge( jedge ) ) tmp[c++] = jedge; } pole_edges.reserve( c ); - for ( int jedge = 0; jedge < c; ++jedge ) + for ( idx_t jedge = 0; jedge < c; ++jedge ) pole_edges.push_back( tmp[jedge] ); - auto flags = array::make_view( mesh.nodes().field( "flags" ) ); + auto flags = array::make_view( mesh.nodes().flags() ); is_ghost.reserve( nnodes ); - for ( size_t jnode = 0; jnode < nnodes; ++jnode ) { + for ( idx_t jnode = 0; jnode < nnodes; ++jnode ) { is_ghost.push_back( Topology::check( flags( jnode ), Topology::GHOST ) ); } } @@ -398,38 +396,34 @@ void AtlasBenchmark::iteration() { const auto V = array::make_view( mesh.nodes().field( "dual_volumes" ) ); const auto node2edge_sign = array::make_view( mesh.nodes().field( "to_edge_sign" ) ); - auto grad = array::make_view( grad_field ); - auto avgS = array::make_view( *avgS_arr ); - auto node_glb_idx = array::make_view( mesh.nodes().global_index() ); - auto node_part = array::make_view( mesh.nodes().partition() ); - auto edge_part = array::make_view( mesh.edges().partition() ); - auto edge_glb_idx = array::make_view( mesh.edges().global_index() ); + auto grad = array::make_view( grad_field ); + auto avgS = array::make_view( *avgS_arr ); - atlas_omp_parallel_for( size_t jedge = 0; jedge < nedges; ++jedge ) { - int ip1 = edge2node( jedge, 0 ); - int ip2 = edge2node( jedge, 1 ); + atlas_omp_parallel_for( idx_t jedge = 0; jedge < nedges; ++jedge ) { + idx_t ip1 = edge2node( jedge, 0 ); + idx_t ip2 = edge2node( jedge, 1 ); - for ( size_t jlev = 0; jlev < nlev; ++jlev ) { + for ( idx_t jlev = 0; jlev < nlev; ++jlev ) { double avg = ( field( ip1, jlev ) + field( ip2, jlev ) ) * 0.5; avgS( jedge, jlev, LON ) = S( jedge, LON ) * avg; avgS( jedge, jlev, LAT ) = S( jedge, LAT ) * avg; } } - atlas_omp_parallel_for( size_t jnode = 0; jnode < nnodes; ++jnode ) { - for ( size_t jlev = 0; jlev < nlev; ++jlev ) { + atlas_omp_parallel_for( idx_t jnode = 0; jnode < nnodes; ++jnode ) { + for ( idx_t jlev = 0; jlev < nlev; ++jlev ) { grad( jnode, jlev, LON ) = 0.; grad( jnode, jlev, LAT ) = 0.; } - for ( size_t jedge = 0; jedge < node2edge.cols( jnode ); ++jedge ) { - size_t iedge = node2edge( jnode, jedge ); - double add = node2edge_sign( jnode, jedge ); - for ( size_t jlev = 0; jlev < nlev; ++jlev ) { + for ( idx_t jedge = 0; jedge < node2edge.cols( jnode ); ++jedge ) { + idx_t iedge = node2edge( jnode, jedge ); + double add = node2edge_sign( jnode, jedge ); + for ( idx_t jlev = 0; jlev < nlev; ++jlev ) { grad( jnode, jlev, LON ) += add * avgS( iedge, jlev, LON ); grad( jnode, jlev, LAT ) += add * avgS( iedge, jlev, LAT ); } } - for ( size_t jlev = 0; jlev < nlev; ++jlev ) { + for ( idx_t jlev = 0; jlev < nlev; ++jlev ) { grad( jnode, jlev, LON ) /= V( jnode ); grad( jnode, jlev, LAT ) /= V( jnode ); } @@ -437,19 +431,19 @@ void AtlasBenchmark::iteration() { // special treatment for the north & south pole cell faces // Sx == 0 at pole, and Sy has same sign at both sides of pole for ( size_t jedge = 0; jedge < pole_edges.size(); ++jedge ) { - int iedge = pole_edges[jedge]; - int ip2 = edge2node( iedge, 1 ); + idx_t iedge = pole_edges[jedge]; + idx_t ip2 = edge2node( iedge, 1 ); // correct for wrong Y-derivatives in previous loop - for ( size_t jlev = 0; jlev < nlev; ++jlev ) + for ( idx_t jlev = 0; jlev < nlev; ++jlev ) grad( ip2, jlev, LAT ) += 2. * avgS( iedge, jlev, LAT ) / V( ip2 ); } double dzi = 1. / dz; double dzi_2 = 0.5 * dzi; - atlas_omp_parallel_for( size_t jnode = 0; jnode < nnodes; ++jnode ) { + atlas_omp_parallel_for( idx_t jnode = 0; jnode < nnodes; ++jnode ) { if ( nlev > 2 ) { - for ( size_t jlev = 1; jlev < nlev - 1; ++jlev ) { + for ( idx_t jlev = 1; jlev < nlev - 1; ++jlev ) { grad( jnode, jlev, ZZ ) = ( field( jnode, jlev + 1 ) - field( jnode, jlev - 1 ) ) * dzi_2; } } @@ -498,11 +492,9 @@ double AtlasBenchmark::result() { double norm = 0.; nodes_fs.haloExchange( grad_field ); - auto glb_idx = array::make_view( mesh.nodes().global_index() ); - auto part = array::make_view( mesh.nodes().partition() ); - for ( size_t jnode = 0; jnode < nnodes; ++jnode ) { + for ( idx_t jnode = 0; jnode < nnodes; ++jnode ) { if ( !is_ghost[jnode] ) { - for ( size_t jlev = 0; jlev < 1; ++jlev ) { + for ( idx_t jlev = 0; jlev < 1; ++jlev ) { const double scaling = 1.e12; grad( jnode, jlev, LON ) *= scaling; grad( jnode, jlev, LAT ) *= scaling; diff --git a/src/apps/atlas-gaussian-latitudes.cc b/src/apps/atlas-gaussian-latitudes.cc index 51337cbce..6cc899623 100644 --- a/src/apps/atlas-gaussian-latitudes.cc +++ b/src/apps/atlas-gaussian-latitudes.cc @@ -11,6 +11,7 @@ #include #include #include +#include #include #include #include @@ -18,12 +19,12 @@ #include #include "eckit/config/Resource.h" -#include "eckit/exception/Exceptions.h" #include "eckit/runtime/Main.h" #include "eckit/runtime/Tool.h" #include "atlas/grid/detail/spacing/GaussianSpacing.h" #include "atlas/library/Library.h" +#include "atlas/runtime/Exception.h" //------------------------------------------------------------------------------------------------------ diff --git a/src/apps/atlas-gmsh-extract.cc b/src/apps/atlas-gmsh-extract.cc index a4e48d2c7..6a1c1032c 100644 --- a/src/apps/atlas-gmsh-extract.cc +++ b/src/apps/atlas-gmsh-extract.cc @@ -18,12 +18,12 @@ #include #include "eckit/config/Resource.h" -#include "eckit/exception/Exceptions.h" #include "eckit/filesystem/PathName.h" #include "eckit/runtime/Main.h" #include "eckit/runtime/Tool.h" #include "atlas/library/Library.h" +#include "atlas/runtime/Exception.h" //------------------------------------------------------------------------------------------------------ @@ -107,7 +107,7 @@ class gmsh_extract : public eckit::Tool { } } - if ( in_files.empty() ) throw UserError( "missing input filename, parameter -i\n" + help_str, Here() ); + if ( in_files.empty() ) throw_Exception( "missing input filename, parameter -i\n" + help_str, Here() ); } private: @@ -131,7 +131,7 @@ void gmsh_extract::run() { std::ofstream out_file; if ( !out_filename.empty() ) { out_file.open( out_filename.c_str(), std::ios::out | std::ios::binary ); - if ( !out_file.is_open() ) throw eckit::CantOpenFile( out_filename ); + if ( !out_file.is_open() ) throw_CantOpenFile( out_filename ); } std::ostream& out = out_filename.empty() ? std::cout : out_file; @@ -146,7 +146,7 @@ void gmsh_extract::run() { std::ifstream in_file; in_file.open( gmsh_file.localPath(), std::ios::in | std::ios::binary ); - if ( !in_file.is_open() ) throw eckit::CantOpenFile( gmsh_file ); + if ( !in_file.is_open() ) throw_CantOpenFile( gmsh_file ); std::string line; std::string ctxt = ""; diff --git a/src/apps/atlas-grids.cc b/src/apps/atlas-grids.cc index 7645a79a7..b9b7d40c3 100644 --- a/src/apps/atlas-grids.cc +++ b/src/apps/atlas-grids.cc @@ -11,31 +11,30 @@ #include #include #include +#include #include #include #include #include #include -#include "atlas/grid.h" -#include "atlas/library/Library.h" -#include "atlas/runtime/AtlasTool.h" -#include "atlas/runtime/Log.h" - #include "eckit/config/Resource.h" -#include "eckit/exception/Exceptions.h" #include "eckit/filesystem/PathName.h" #include "eckit/log/Bytes.h" #include "eckit/log/Log.h" -#include "eckit/memory/Builder.h" -#include "eckit/memory/Factory.h" #include "eckit/parser/JSON.h" #include "eckit/parser/Tokenizer.h" #include "eckit/runtime/Main.h" +#include "atlas/grid.h" +#include "atlas/grid/detail/grid/GridFactory.h" +#include "atlas/library/Library.h" +#include "atlas/runtime/AtlasTool.h" +#include "atlas/runtime/Exception.h" +#include "atlas/runtime/Log.h" + using namespace atlas; using namespace atlas::grid; -using eckit::Factory; using eckit::JSON; //---------------------------------------------------------------------------------------------------------------------- @@ -102,11 +101,10 @@ void AtlasGrids::execute( const Args& args ) { Log::error() << "Option wrong or missing after '" << key << "'" << std::endl; } if ( list ) { - std::vector keys = Factory::instance().keys(); Log::info() << "usage: atlas-grids GRID [OPTION]... [--help]\n" << std::endl; Log::info() << "Available grids:" << std::endl; - for ( size_t i = 0; i < keys.size(); ++i ) { - Log::info() << " -- " << keys[i] << std::endl; + for ( const auto& key : GridFactory::keys() ) { + Log::info() << " -- " << key << std::endl; } } @@ -115,7 +113,7 @@ void AtlasGrids::execute( const Args& args ) { try { grid = Grid( key ); } - catch ( eckit::BadParameter& err ) { + catch ( eckit::Exception& ) { } if ( !grid ) return; @@ -175,7 +173,7 @@ void AtlasGrids::execute( const Args& args ) { if ( rtable ) { std::stringstream stream; stream << "&NAMRGRI\n"; - for ( size_t j = 0; j < grid.ny(); ++j ) + for ( idx_t j = 0; j < grid.ny(); ++j ) stream << " NRGRI(" << std::setfill( '0' ) << std::setw( 5 ) << 1 + j << ")=" << std::setfill( ' ' ) << std::setw( 5 ) << grid.nx( j ) << ",\n"; stream << "/" << std::flush; diff --git a/src/apps/atlas-loadbalance.cc b/src/apps/atlas-loadbalance.cc index 17f254ca3..d337619a5 100644 --- a/src/apps/atlas-loadbalance.cc +++ b/src/apps/atlas-loadbalance.cc @@ -11,18 +11,20 @@ #include #include +#include "eckit/config/Resource.h" +#include "eckit/runtime/Tool.h" + #include "atlas/functionspace/NodeColumns.h" #include "atlas/grid.h" #include "atlas/library/Library.h" #include "atlas/mesh/Mesh.h" #include "atlas/mesh/Nodes.h" #include "atlas/mesh/actions/WriteLoadBalanceReport.h" -#include "atlas/meshgenerator/MeshGenerator.h" +#include "atlas/meshgenerator.h" #include "atlas/parallel/mpi/mpi.h" +#include "atlas/runtime/Exception.h" #include "atlas/runtime/Log.h" -#include "eckit/config/Resource.h" -#include "eckit/exception/Exceptions.h" -#include "eckit/runtime/Tool.h" + //------------------------------------------------------------------------------------------------------ using eckit::Resource; @@ -99,7 +101,7 @@ void AtlasLoadbalance::run() { try { grid = Grid( key ); } - catch ( eckit::BadParameter& err ) { + catch ( eckit::Exception& err ) { } if ( !grid ) return; diff --git a/src/apps/atlas-meshgen.cc b/src/apps/atlas-meshgen.cc index 955610cc6..32c08fdb1 100644 --- a/src/apps/atlas-meshgen.cc +++ b/src/apps/atlas-meshgen.cc @@ -17,6 +17,7 @@ #include #include +#include "atlas/functionspace/EdgeColumns.h" #include "atlas/functionspace/NodeColumns.h" #include "atlas/grid.h" #include "atlas/library/Library.h" @@ -30,7 +31,7 @@ #include "atlas/mesh/actions/BuildStatistics.h" #include "atlas/mesh/actions/BuildTorusXYZField.h" #include "atlas/mesh/actions/BuildXYZField.h" -#include "atlas/meshgenerator/MeshGenerator.h" +#include "atlas/meshgenerator.h" #include "atlas/output/Gmsh.h" #include "atlas/output/detail/GmshIO.h" #include "atlas/parallel/mpi/mpi.h" @@ -71,14 +72,9 @@ class Meshgen2Gmsh : public AtlasTool { bool brick; bool stats; bool info; - bool with_pole; - bool stitch_pole; bool ghost; bool binary; std::string identifier; - std::vector reg_nlon_nlat; - std::vector fgg_nlon_nlat; - std::vector rgg_nlon; PathName path_in; PathName path_out; }; @@ -163,7 +159,7 @@ void Meshgen2Gmsh::execute( const Args& args ) { try { grid = Grid( key ); } - catch ( eckit::BadParameter& e ) { + catch ( eckit::Exception& ) { } } else if ( path_in.path().size() ) { @@ -172,7 +168,7 @@ void Meshgen2Gmsh::execute( const Args& args ) { try { grid = Grid( Config( path_in ) ); } - catch ( eckit::BadParameter& e ) { + catch ( eckit::Exception& ) { } } else { @@ -196,7 +192,7 @@ void Meshgen2Gmsh::execute( const Args& args ) { try { mesh = meshgenerator.generate( grid ); } - catch ( eckit::BadParameter& e ) { + catch ( eckit::Exception& e ) { Log::error() << e.what() << std::endl; Log::error() << e.callStack() << std::endl; throw e; @@ -209,10 +205,8 @@ void Meshgen2Gmsh::execute( const Args& args ) { << std::endl; Log::warning() << "units: " << grid.projection().units() << std::endl; } - if ( edges ) { - build_edges( mesh ); - build_pole_edges( mesh ); - build_edges_parallel_fields( mesh ); + if ( edges && grid.projection().units() == "degrees" ) { + functionspace::EdgeColumns edges_fs( mesh, option::halo( halo ) ); if ( brick ) build_brick_dual_mesh( grid, mesh ); else @@ -242,7 +236,7 @@ void Meshgen2Gmsh::execute( const Args& args ) { if ( info ) { Log::info() << "Partitioning graph: \n" << mesh.partitionGraph() << std::endl; Log::info() << "Mesh partition footprint: " << eckit::Bytes( mesh.footprint() ) << std::endl; - for ( size_t jhalo = 0; jhalo <= halo; ++jhalo ) { + for ( idx_t jhalo = 0; jhalo <= halo; ++jhalo ) { mesh.polygon( jhalo ).outputPythonScript( "polygon_halo" + std::to_string( jhalo ) + ".py" ); } } diff --git a/src/apps/atlas-numerics-nabla.F90 b/src/apps/atlas-numerics-nabla.F90 index ed96d0223..bd2372d6a 100644 --- a/src/apps/atlas-numerics-nabla.F90 +++ b/src/apps/atlas-numerics-nabla.F90 @@ -148,8 +148,8 @@ SUBROUTINE FV_GRADIENT(PVAR,PGRAD) TYPE(ATLAS_CONNECTIVITY) :: EDGE2NODE, NODE2EDGE REAL(KIND=JPRB), POINTER :: ZLONLAT(:,:),ZDUAL_VOLUMES(:),ZDUAL_NORMALS(:,:),& & ZNODE2EDGE_SIGN(:,:) -INTEGER(KIND=JPIM),POINTER :: IEDGE2NODE(:,:) -INTEGER(KIND=JPIM),POINTER :: INODE2EDGE(:) +INTEGER(KIND=ATLAS_KIND_IDX),POINTER :: IEDGE2NODE(:,:) +INTEGER(KIND=ATLAS_KIND_IDX),POINTER :: INODE2EDGE(:) INTEGER(KIND=JPIM) :: INODE2EDGE_SIZE INTEGER(KIND=JPIM) :: JNODE,JEDGE,JLEV,INEDGES,IP1,IP2,IEDGE,INODES REAL(KIND=JPRB) :: ZAVG,ZSIGN,ZMETRIC_X,ZMETRIC_Y,ZSCALE diff --git a/src/atlas/CMakeLists.txt b/src/atlas/CMakeLists.txt index b31ed29cb..615cd4e27 100644 --- a/src/atlas/CMakeLists.txt +++ b/src/atlas/CMakeLists.txt @@ -28,8 +28,6 @@ list( APPEND atlas_srcs library/config.h library/Library.h library/Library.cc -runtime/ErrorHandling.cc -runtime/ErrorHandling.cc runtime/AtlasTool.h runtime/AtlasTool.cc runtime/Log.h @@ -37,6 +35,8 @@ runtime/Log.cc runtime/Trace.h runtime/trace/CallStack.h runtime/trace/CallStack.cc +runtime/trace/CodeLocation.cc +runtime/trace/CodeLocation.h runtime/trace/TraceT.h runtime/trace/Nesting.cc runtime/trace/Nesting.h @@ -74,6 +74,8 @@ projection/detail/SchmidtProjection.cc projection/detail/SchmidtProjection.h projection/detail/MercatorProjection.cc projection/detail/MercatorProjection.h +projection/detail/ProjectionFactory.h +projection/detail/ProjectionFactory.cc domain.h domain/Domain.cc @@ -88,10 +90,16 @@ domain/detail/GlobalDomain.h domain/detail/GlobalDomain.cc domain/detail/ZonalBandDomain.h domain/detail/ZonalBandDomain.cc +domain/detail/DomainFactory.h +domain/detail/DomainFactory.cc grid.h grid/Grid.cc grid/Grid.h +grid/StructuredGrid.cc +grid/StructuredGrid.h +grid/UnstructuredGrid.cc +grid/UnstructuredGrid.h grid/Distribution.cc grid/Distribution.h @@ -100,9 +108,17 @@ grid/Spacing.h grid/Partitioner.h grid/Partitioner.cc grid/Iterator.h +grid/Iterator.cc +grid/Vertical.h +grid/Vertical.cc +grid/Stencil.h +grid/StencilComputer.h +grid/StencilComputer.cc grid/detail/grid/GridBuilder.h grid/detail/grid/GridBuilder.cc +grid/detail/grid/GridFactory.h +grid/detail/grid/GridFactory.cc grid/detail/grid/Grid.h grid/detail/grid/Grid.cc grid/detail/grid/Structured.cc @@ -116,11 +132,18 @@ grid/detail/grid/LonLat.cc grid/detail/grid/Regional.h grid/detail/grid/Regional.cc +grid/detail/distribution/DistributionImpl.h +grid/detail/distribution/DistributionImpl.cc + +grid/detail/vertical/VerticalInterface.h +grid/detail/vertical/VerticalInterface.cc + grid/detail/partitioner/CheckerboardPartitioner.cc grid/detail/partitioner/CheckerboardPartitioner.h grid/detail/partitioner/EqualRegionsPartitioner.cc grid/detail/partitioner/EqualRegionsPartitioner.h grid/detail/partitioner/MatchingMeshPartitioner.h +grid/detail/partitioner/MatchingMeshPartitioner.cc grid/detail/partitioner/MatchingMeshPartitionerBruteForce.cc grid/detail/partitioner/MatchingMeshPartitionerBruteForce.h grid/detail/partitioner/MatchingMeshPartitionerLonLatPolygon.cc @@ -132,6 +155,8 @@ grid/detail/partitioner/Partitioner.h grid/detail/spacing/Spacing.cc grid/detail/spacing/Spacing.h +grid/detail/spacing/SpacingFactory.cc +grid/detail/spacing/SpacingFactory.h grid/detail/spacing/CustomSpacing.h grid/detail/spacing/CustomSpacing.cc grid/detail/spacing/LinearSpacing.h @@ -203,6 +228,12 @@ list( APPEND atlas_grid_srcs ) endif() +# Append CGAL_COMPLE_FLAGS only to this file ( see ATLAS-193 ) +if( CGAL_COMPILE_FLAGS ) + set_source_files_properties( mesh/actions/BuildConvexHull3D.cc + PROPERTIES COMPILE_FLAGS "${CGAL_COMPILE_FLAGS}" ) +endif() + list( APPEND atlas_mesh_srcs mesh.h mesh/Connectivity.cc @@ -250,18 +281,24 @@ mesh/actions/BuildStatistics.h mesh/actions/BuildXYZField.cc mesh/actions/BuildXYZField.h mesh/actions/WriteLoadBalanceReport.cc +mesh/actions/BuildTorusXYZField.h +mesh/actions/BuildTorusXYZField.cc meshgenerator.h -meshgenerator/DelaunayMeshGenerator.h -meshgenerator/DelaunayMeshGenerator.cc meshgenerator/MeshGenerator.cc meshgenerator/MeshGenerator.h -meshgenerator/StructuredMeshGenerator.h -meshgenerator/StructuredMeshGenerator.cc -meshgenerator/RegularMeshGenerator.cc -meshgenerator/RegularMeshGenerator.h -mesh/actions/BuildTorusXYZField.h -mesh/actions/BuildTorusXYZField.cc +meshgenerator/detail/DelaunayMeshGenerator.h +meshgenerator/detail/DelaunayMeshGenerator.cc +meshgenerator/detail/StructuredMeshGenerator.h +meshgenerator/detail/StructuredMeshGenerator.cc +meshgenerator/detail/RegularMeshGenerator.cc +meshgenerator/detail/RegularMeshGenerator.h +meshgenerator/detail/MeshGeneratorFactory.cc +meshgenerator/detail/MeshGeneratorFactory.h +meshgenerator/detail/MeshGeneratorImpl.cc +meshgenerator/detail/MeshGeneratorImpl.h +meshgenerator/detail/MeshGeneratorInterface.cc +meshgenerator/detail/MeshGeneratorInterface.h ) list( APPEND atlas_output_srcs @@ -287,6 +324,8 @@ field/State.h field/State.cc field/detail/FieldImpl.h field/detail/FieldImpl.cc +field/detail/FieldInterface.h +field/detail/FieldInterface.cc ) list( APPEND atlas_functionspace_srcs @@ -297,14 +336,20 @@ functionspace/FunctionSpace.h functionspace/FunctionSpace.cc functionspace/NodeColumns.h functionspace/NodeColumns.cc -functionspace/NodeColumnsInterface.h -functionspace/NodeColumnsInterface.cc functionspace/StructuredColumns.h functionspace/StructuredColumns.cc functionspace/Spectral.h functionspace/Spectral.cc functionspace/PointCloud.h functionspace/PointCloud.cc +functionspace/detail/FunctionSpaceImpl.h +functionspace/detail/FunctionSpaceImpl.cc +functionspace/detail/FunctionSpaceInterface.h +functionspace/detail/FunctionSpaceInterface.cc +functionspace/detail/NodeColumnsInterface.h +functionspace/detail/NodeColumnsInterface.cc +functionspace/detail/StructuredColumnsInterface.h +functionspace/detail/StructuredColumnsInterface.cc ) list( APPEND atlas_numerics_srcs @@ -333,7 +378,10 @@ trans/local/VorDivToUVLocal.h trans/local/VorDivToUVLocal.cc trans/local/LegendreCacheCreatorLocal.h trans/local/LegendreCacheCreatorLocal.cc - +trans/detail/TransFactory.h +trans/detail/TransFactory.cc +trans/detail/TransImpl.h +trans/detail/TransImpl.cc ) if( ATLAS_HAVE_TRANS ) list( APPEND atlas_numerics_srcs @@ -354,30 +402,59 @@ list( APPEND atlas_interpolation_srcs interpolation.h interpolation/Interpolation.h interpolation/Interpolation.cc +interpolation/Vector2D.cc interpolation/Vector2D.h +interpolation/Vector3D.cc interpolation/Vector3D.h interpolation/element/Quad3D.cc interpolation/element/Quad3D.h interpolation/element/Triag3D.cc interpolation/element/Triag3D.h -interpolation/method/FiniteElement.cc -interpolation/method/FiniteElement.h interpolation/method/Intersect.cc interpolation/method/Intersect.h -interpolation/method/KNearestNeighbours.cc -interpolation/method/KNearestNeighbours.h -interpolation/method/KNearestNeighboursBase.cc -interpolation/method/KNearestNeighboursBase.h interpolation/method/Method.cc interpolation/method/Method.h -interpolation/method/NearestNeighbour.cc -interpolation/method/NearestNeighbour.h +interpolation/method/MethodFactory.cc +interpolation/method/MethodFactory.h interpolation/method/PointIndex3.cc interpolation/method/PointIndex3.h interpolation/method/PointSet.cc interpolation/method/PointSet.h interpolation/method/Ray.cc interpolation/method/Ray.h +interpolation/method/fe/FiniteElement.cc +interpolation/method/fe/FiniteElement.h +interpolation/method/knn/KNearestNeighbours.cc +interpolation/method/knn/KNearestNeighbours.h +interpolation/method/knn/KNearestNeighboursBase.cc +interpolation/method/knn/KNearestNeighboursBase.h +interpolation/method/knn/NearestNeighbour.cc +interpolation/method/knn/NearestNeighbour.h +interpolation/method/structured/StructuredInterpolation2D.tcc +interpolation/method/structured/StructuredInterpolation2D.h +interpolation/method/structured/StructuredInterpolation3D.tcc +interpolation/method/structured/StructuredInterpolation3D.h +interpolation/method/structured/kernels/LinearHorizontalKernel.h +interpolation/method/structured/kernels/Linear3DKernel.h +interpolation/method/structured/kernels/LinearVerticalKernel.h +interpolation/method/structured/kernels/CubicHorizontalKernel.h +interpolation/method/structured/kernels/Cubic3DKernel.h +interpolation/method/structured/kernels/CubicVerticalKernel.h +interpolation/method/structured/kernels/QuasiCubicHorizontalKernel.h +interpolation/method/structured/kernels/QuasiCubic3DKernel.cc +interpolation/method/structured/kernels/QuasiCubic3DKernel.h +interpolation/method/structured/Linear2D.cc +interpolation/method/structured/Linear2D.h +interpolation/method/structured/Linear3D.cc +interpolation/method/structured/Linear3D.h +interpolation/method/structured/Cubic2D.cc +interpolation/method/structured/Cubic2D.h +interpolation/method/structured/Cubic3D.cc +interpolation/method/structured/Cubic3D.h +interpolation/method/structured/QuasiCubic2D.cc +interpolation/method/structured/QuasiCubic2D.h +interpolation/method/structured/QuasiCubic3D.cc +interpolation/method/structured/QuasiCubic3D.h ) @@ -397,12 +474,15 @@ array/ArrayUtil.h array/ArrayView.h array/ArrayViewUtil.h array/ArrayViewDefs.h +array/DataType.cc array/DataType.h array/IndexView.h array/LocalView.cc array/LocalView.h array/Range.h array/Vector.h +array/Vector.cc +array/SVector.h array/helpers/ArrayInitializer.h array/helpers/ArrayAssigner.h array/helpers/ArrayWriter.h @@ -451,8 +531,8 @@ parallel/HaloExchange.cc parallel/HaloExchange.h parallel/HaloExchangeImpl.h parallel/mpi/Buffer.h -runtime/ErrorHandling.cc -runtime/ErrorHandling.h +runtime/Exception.cc +runtime/Exception.h util/Config.cc util/Config.h util/Constants.h @@ -463,6 +543,8 @@ util/LonLatPolygon.cc util/LonLatPolygon.h util/Metadata.cc util/Metadata.h +util/Point.cc +util/Point.h util/Polygon.cc util/Polygon.h util/Rotation.cc @@ -478,6 +560,12 @@ util/detail/Debug.h list( APPEND atlas_internals_srcs mesh/detail/AccumulateFacets.h mesh/detail/AccumulateFacets.cc +util/Object.h +util/Object.cc +util/ObjectHandle.h +util/ObjectHandle.cc +util/Factory.h +util/Factory.cc util/Bitflags.h util/Checksum.h util/Checksum.cc @@ -485,16 +573,16 @@ util/MicroDeg.h mesh/IsGhostNode.h util/LonLatMicroDeg.h util/CoordinateEnums.h -mesh/detail/PeriodicTransform.h +util/PeriodicTransform.h util/Unique.h +util/Unique.cc +util/Allocate.h +util/Allocate.cc #parallel/detail/MPLArrayView.h ) ### atlas c++ library -ecbuild_debug_var(CGAL_LIBRARIES) -ecbuild_debug_var(CGAL_INCLUDE_DIRS) - if( NOT ATLAS_HAVE_TRANS ) unset( TRANSI_INCLUDE_DIRS ) unset( TRANSI_LIBRARIES ) diff --git a/src/atlas/array/Array.h b/src/atlas/array/Array.h index c56f8e37f..6006d4d05 100644 --- a/src/atlas/array/Array.h +++ b/src/atlas/array/Array.h @@ -10,9 +10,10 @@ #pragma once +#include #include -#include "eckit/memory/Owned.h" +#include "atlas/util/Object.h" #include "atlas/array/ArrayUtil.h" #include "atlas/array/DataType.h" @@ -32,7 +33,7 @@ class ArrayT_impl; // -------------------------------------------------------------------------------------------- -class Array : public eckit::Owned { +class Array : public util::Object { public: virtual ~Array(); @@ -43,15 +44,15 @@ class Array : public eckit::Owned { virtual size_t footprint() const = 0; template - static Array* create( size_t size0 ); + static Array* create( idx_t size0 ); template - static Array* create( size_t size0, size_t size1 ); + static Array* create( idx_t size0, idx_t size1 ); template - static Array* create( size_t size0, size_t size1, size_t size2 ); + static Array* create( idx_t size0, idx_t size1, idx_t size2 ); template - static Array* create( size_t size0, size_t size1, size_t size2, size_t size3 ); + static Array* create( idx_t size0, idx_t size1, idx_t size2, idx_t size3 ); template - static Array* create( size_t size0, size_t size1, size_t size2, size_t size3, size_t size4 ); + static Array* create( idx_t size0, idx_t size1, idx_t size2, idx_t size3, idx_t size4 ); template static Array* create( const ArrayShape& shape ); @@ -65,15 +66,15 @@ class Array : public eckit::Owned { template static Array* wrap( Value* data, const ArraySpec& spec ); - size_t bytes() const { return sizeof_data() * spec().allocatedSize(); } + idx_t bytes() const { return sizeof_data() * spec().allocatedSize(); } - size_t size() const { return spec_.size(); } + idx_t size() const { return spec_.size(); } - size_t rank() const { return spec_.rank(); } + idx_t rank() const { return spec_.rank(); } - size_t stride( size_t i ) const { return spec_.strides()[i]; } + idx_t stride( idx_t i ) const { return spec_.strides()[i]; } - size_t shape( size_t i ) const { return spec_.shape()[i]; } + idx_t shape( idx_t i ) const { return spec_.shape()[i]; } const ArrayStrides& strides() const { return spec_.strides(); } @@ -89,17 +90,17 @@ class Array : public eckit::Owned { virtual array::DataType datatype() const = 0; - virtual size_t sizeof_data() const = 0; + virtual idx_t sizeof_data() const = 0; virtual void resize( const ArrayShape& shape ) = 0; - virtual void resize( size_t size0 ) = 0; - virtual void resize( size_t size0, size_t size1 ) = 0; - virtual void resize( size_t size0, size_t size1, size_t size2 ) = 0; - virtual void resize( size_t size0, size_t size1, size_t size2, size_t size3 ) = 0; - virtual void resize( size_t size0, size_t size1, size_t size2, size_t size3, size_t size4 ) = 0; + virtual void resize( idx_t size0 ) = 0; + virtual void resize( idx_t size0, idx_t size1 ) = 0; + virtual void resize( idx_t size0, idx_t size1, idx_t size2 ) = 0; + virtual void resize( idx_t size0, idx_t size1, idx_t size2, idx_t size3 ) = 0; + virtual void resize( idx_t size0, idx_t size1, idx_t size2, idx_t size3, idx_t size4 ) = 0; - virtual void insert( size_t idx1, size_t size1 ) = 0; + virtual void insert( idx_t idx1, idx_t size1 ) = 0; virtual void dump( std::ostream& os ) const = 0; @@ -170,11 +171,11 @@ class Array : public eckit::Owned { template class ArrayT : public Array { public: - ArrayT( size_t size0 ); - ArrayT( size_t size0, size_t size1 ); - ArrayT( size_t size0, size_t size1, size_t size2 ); - ArrayT( size_t size0, size_t size1, size_t size2, size_t size3 ); - ArrayT( size_t size0, size_t size1, size_t size2, size_t size3, size_t size4 ); + ArrayT( idx_t size0 ); + ArrayT( idx_t size0, idx_t size1 ); + ArrayT( idx_t size0, idx_t size1, idx_t size2 ); + ArrayT( idx_t size0, idx_t size1, idx_t size2, idx_t size3 ); + ArrayT( idx_t size0, idx_t size1, idx_t size2, idx_t size3, idx_t size4 ); ArrayT( const ArraySpec& ); @@ -182,19 +183,19 @@ class ArrayT : public Array { ArrayT( const ArrayShape&, const ArrayLayout& ); - virtual void insert( size_t idx1, size_t size1 ); + virtual void insert( idx_t idx1, idx_t size1 ); virtual void resize( const ArrayShape& ); - virtual void resize( size_t size0 ); - virtual void resize( size_t size0, size_t size1 ); - virtual void resize( size_t size0, size_t size1, size_t size2 ); - virtual void resize( size_t size0, size_t size1, size_t size2, size_t size3 ); - virtual void resize( size_t size0, size_t size1, size_t size2, size_t size3, size_t size4 ); + virtual void resize( idx_t size0 ); + virtual void resize( idx_t size0, idx_t size1 ); + virtual void resize( idx_t size0, idx_t size1, idx_t size2 ); + virtual void resize( idx_t size0, idx_t size1, idx_t size2, idx_t size3 ); + virtual void resize( idx_t size0, idx_t size1, idx_t size2, idx_t size3, idx_t size4 ); virtual array::DataType datatype() const { return array::DataType::create(); } - virtual size_t sizeof_data() const { return sizeof( Value ); } + virtual idx_t sizeof_data() const { return sizeof( Value ); } virtual void dump( std::ostream& os ) const; @@ -212,5 +213,10 @@ class ArrayT : public Array { mutable bool acc_map_{false}; }; +extern template class ArrayT; +extern template class ArrayT; +extern template class ArrayT; +extern template class ArrayT; + } // namespace array } // namespace atlas diff --git a/src/atlas/array/ArrayIdx.h b/src/atlas/array/ArrayIdx.h index 89269fdf7..a03295bfb 100644 --- a/src/atlas/array/ArrayIdx.h +++ b/src/atlas/array/ArrayIdx.h @@ -4,7 +4,7 @@ * 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 size_tergovernmental organisation + * granted to it by virtue of its status as an intergovernmental organisation * nor does it submit to any jurisdiction. */ @@ -12,32 +12,33 @@ #include #include +#include "atlas/library/config.h" //------------------------------------------------------------------------------------------------------ namespace atlas { namespace array { -typedef std::vector ArrayIdx; +typedef std::vector ArrayIdx; -inline ArrayIdx make_idx( size_t size1 ) { - return std::vector( 1, size1 ); +inline ArrayIdx make_idx( idx_t size1 ) { + return std::vector( 1, size1 ); } -inline ArrayIdx make_idx( size_t size1, size_t size2 ) { - std::vector v( 2 ); +inline ArrayIdx make_idx( idx_t size1, idx_t size2 ) { + std::vector v( 2 ); v[0] = size1; v[1] = size2; return v; } -inline ArrayIdx make_idx( size_t size1, size_t size2, size_t size3 ) { - std::vector v( 3 ); +inline ArrayIdx make_idx( idx_t size1, idx_t size2, idx_t size3 ) { + std::vector v( 3 ); v[0] = size1; v[1] = size2; v[2] = size3; return v; } -inline ArrayIdx make_idx( size_t size1, size_t size2, size_t size3, size_t size4 ) { - std::vector v( 4 ); +inline ArrayIdx make_idx( idx_t size1, idx_t size2, idx_t size3, idx_t size4 ) { + std::vector v( 4 ); v[0] = size1; v[1] = size2; v[2] = size3; diff --git a/src/atlas/array/ArrayLayout.h b/src/atlas/array/ArrayLayout.h index 0437831cf..82dbdf373 100644 --- a/src/atlas/array/ArrayLayout.h +++ b/src/atlas/array/ArrayLayout.h @@ -4,13 +4,14 @@ * 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 size_tergovernmental organisation + * granted to it by virtue of its status as an intergovernmental organisation * nor does it submit to any jurisdiction. */ #pragma once -#include +#include +#include #include //------------------------------------------------------------------------------------------------------ @@ -18,29 +19,29 @@ namespace atlas { namespace array { -class ArrayLayout : public std::vector { +class ArrayLayout : public std::vector { private: - using Base = std::vector; + using Base = std::vector; public: ArrayLayout() {} - ArrayLayout( std::initializer_list list ) : Base( list ) {} + ArrayLayout( std::initializer_list list ) : Base( list ) {} ArrayLayout( Base&& base ) : Base( std::forward( base ) ) {} }; -inline ArrayLayout make_layout( size_t size1 ) { +inline ArrayLayout make_layout( idx_t size1 ) { return ArrayLayout{size1}; } -inline ArrayLayout make_layout( size_t size1, size_t size2 ) { +inline ArrayLayout make_layout( idx_t size1, idx_t size2 ) { return ArrayLayout{size1, size2}; } -inline ArrayLayout make_layout( size_t size1, size_t size2, size_t size3 ) { +inline ArrayLayout make_layout( idx_t size1, idx_t size2, idx_t size3 ) { return ArrayLayout{size1, size2, size3}; } -inline ArrayLayout make_layout( size_t size1, size_t size2, size_t size3, size_t size4 ) { +inline ArrayLayout make_layout( idx_t size1, idx_t size2, idx_t size3, idx_t size4 ) { return ArrayLayout{size1, size2, size3, size4}; } -inline ArrayLayout make_layout( size_t size1, size_t size2, size_t size3, size_t size4, size_t size5 ) { +inline ArrayLayout make_layout( idx_t size1, idx_t size2, idx_t size3, idx_t size4, idx_t size5 ) { return ArrayLayout{size1, size2, size3, size4, size5}; } diff --git a/src/atlas/array/ArrayShape.h b/src/atlas/array/ArrayShape.h index 2c9ecf626..a4273667e 100644 --- a/src/atlas/array/ArrayShape.h +++ b/src/atlas/array/ArrayShape.h @@ -4,7 +4,7 @@ * 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 size_tergovernmental organisation + * granted to it by virtue of its status as an intergovernmental organisation * nor does it submit to any jurisdiction. */ @@ -12,6 +12,7 @@ #include #include +#include "atlas/library/config.h" //------------------------------------------------------------------------------------------------------ @@ -28,33 +29,41 @@ class ArrayAlignment { int alignment_; }; -class ArrayShape : public std::vector { +class ArrayShape : public std::vector { private: - using Base = std::vector; + using Base = std::vector; public: ArrayShape() {} ArrayShape( Base&& base ) : Base( std::forward( base ) ) {} - ArrayShape( std::initializer_list list ) : Base( list ) {} + ArrayShape( std::initializer_list list ) : Base( list ) {} + ArrayShape( idx_t data[], size_t size ) : Base( data, data + size ) {} }; -inline ArrayShape make_shape( std::initializer_list sizes ) { +inline ArrayShape make_shape( std::initializer_list sizes ) { return ArrayShape( sizes ); } -inline ArrayShape make_shape( size_t size1 ) { - return ArrayShape{size1}; +template +inline ArrayShape make_shape( Int size1 ) { + return ArrayShape{static_cast( size1 )}; } -inline ArrayShape make_shape( size_t size1, size_t size2 ) { - return ArrayShape{size1, size2}; +template +inline ArrayShape make_shape( Int1 size1, Int2 size2 ) { + return ArrayShape{static_cast( size1 ), static_cast( size2 )}; } -inline ArrayShape make_shape( size_t size1, size_t size2, size_t size3 ) { - return ArrayShape{size1, size2, size3}; +template +inline ArrayShape make_shape( Int1 size1, Int2 size2, Int3 size3 ) { + return ArrayShape{static_cast( size1 ), static_cast( size2 ), static_cast( size3 )}; } -inline ArrayShape make_shape( size_t size1, size_t size2, size_t size3, size_t size4 ) { - return ArrayShape{size1, size2, size3, size4}; +template +inline ArrayShape make_shape( Int1 size1, Int2 size2, Int3 size3, Int4 size4 ) { + return ArrayShape{static_cast( size1 ), static_cast( size2 ), static_cast( size3 ), + static_cast( size4 )}; } -inline ArrayShape make_shape( size_t size1, size_t size2, size_t size3, size_t size4, size_t size5 ) { - return ArrayShape{size1, size2, size3, size4, size5}; +template +inline ArrayShape make_shape( Int1 size1, Int2 size2, Int3 size3, Int4 size4, Int5 size5 ) { + return ArrayShape{static_cast( size1 ), static_cast( size2 ), static_cast( size3 ), + static_cast( size4 ), static_cast( size5 )}; } //------------------------------------------------------------------------------------------------------ diff --git a/src/atlas/array/ArraySpec.cc b/src/atlas/array/ArraySpec.cc index 8d4c2174b..b78529ac3 100644 --- a/src/atlas/array/ArraySpec.cc +++ b/src/atlas/array/ArraySpec.cc @@ -10,18 +10,18 @@ #include -#include "eckit/exception/Exceptions.h" - #include "atlas/array/ArrayUtil.h" +#include "atlas/library/config.h" +#include "atlas/runtime/Exception.h" namespace atlas { namespace array { namespace { -size_t compute_allocated_size( size_t size, int alignment ) { - int div = size / alignment; - int mod = size % alignment; - size_t _allocated_size = div * alignment; +idx_t compute_allocated_size( idx_t size, idx_t alignment ) { + idx_t div = size / alignment; + idx_t mod = size % alignment; + idx_t _allocated_size = div * alignment; if ( mod > 0 ) _allocated_size += alignment; return _allocated_size; } @@ -32,9 +32,9 @@ ArraySpec::ArraySpec() : size_(), rank_(), allocated_size_(), contiguous_( true ArraySpec::ArraySpec( const ArrayShape& shape ) : ArraySpec( shape, ArrayAlignment() ) {} ArraySpec::ArraySpec( const ArrayShape& shape, ArrayAlignment&& alignment ) { - if ( int( alignment ) > 1 ) NOTIMP; // innermost dimension needs to be padded + if ( int( alignment ) > 1 ) ATLAS_NOTIMPLEMENTED; // innermost dimension needs to be padded - rank_ = shape.size(); + rank_ = static_cast( shape.size() ); size_ = 1; shape_.resize( rank_ ); strides_.resize( rank_ ); @@ -48,16 +48,19 @@ ArraySpec::ArraySpec( const ArrayShape& shape, ArrayAlignment&& alignment ) { allocated_size_ = compute_allocated_size( size_, alignment ); contiguous_ = true; default_layout_ = true; + +#ifdef ATLAS_HAVE_FORTRAN + allocate_fortran_specs(); +#endif }; ArraySpec::ArraySpec( const ArrayShape& shape, const ArrayStrides& strides ) : ArraySpec( shape, strides, ArrayAlignment() ) {} ArraySpec::ArraySpec( const ArrayShape& shape, const ArrayStrides& strides, ArrayAlignment&& alignment ) { - if ( shape.size() != strides.size() ) - throw eckit::BadParameter( "dimensions of shape and stride don't match", Here() ); + ATLAS_ASSERT( shape.size() == strides.size(), "dimensions of shape and stride don't match" ); - rank_ = shape.size(); + rank_ = static_cast( shape.size() ); size_ = 1; shape_.resize( rank_ ); strides_.resize( rank_ ); @@ -71,6 +74,10 @@ ArraySpec::ArraySpec( const ArrayShape& shape, const ArrayStrides& strides, Arra allocated_size_ = compute_allocated_size( shape_[0] * strides_[0], alignment ); contiguous_ = ( size_ == allocated_size_ ); default_layout_ = true; + +#ifdef ATLAS_HAVE_FORTRAN + allocate_fortran_specs(); +#endif } ArraySpec::ArraySpec( const ArrayShape& shape, const ArrayStrides& strides, const ArrayLayout& layout ) : @@ -78,10 +85,9 @@ ArraySpec::ArraySpec( const ArrayShape& shape, const ArrayStrides& strides, cons ArraySpec::ArraySpec( const ArrayShape& shape, const ArrayStrides& strides, const ArrayLayout& layout, ArrayAlignment&& alignment ) { - if ( shape.size() != strides.size() ) - throw eckit::BadParameter( "dimensions of shape and stride don't match", Here() ); + ATLAS_ASSERT( shape.size() == strides.size(), "dimensions of shape and stride don't match" ); - rank_ = shape.size(); + rank_ = static_cast( shape.size() ); size_ = 1; shape_.resize( rank_ ); strides_.resize( rank_ ); @@ -92,29 +98,32 @@ ArraySpec::ArraySpec( const ArrayShape& shape, const ArrayStrides& strides, cons strides_[j] = strides[j]; layout_[j] = layout[j]; size_ *= shape_[j]; - if ( layout_[j] != size_t( j ) ) { default_layout_ = false; } + if ( layout_[j] != idx_t( j ) ) { default_layout_ = false; } } allocated_size_ = compute_allocated_size( shape_[layout_[0]] * strides_[layout_[0]], alignment ); contiguous_ = ( size_ == allocated_size_ ); + +#ifdef ATLAS_HAVE_FORTRAN + allocate_fortran_specs(); +#endif } const std::vector& ArraySpec::shapef() const { - if ( shapef_.empty() ) { - shapef_.resize( rank_ ); - for ( size_t j = 0; j < rank_; ++j ) { - shapef_[j] = shape_[rank_ - 1 - layout_[j]]; - } - } return shapef_; } const std::vector& ArraySpec::stridesf() const { - if ( stridesf_.empty() ) { - stridesf_.resize( strides().size() ); - std::reverse_copy( strides().begin(), strides().end(), stridesf_.begin() ); - } return stridesf_; } +void ArraySpec::allocate_fortran_specs() { + shapef_.resize( rank_ ); + for ( idx_t j = 0; j < rank_; ++j ) { + shapef_[j] = shape_[rank_ - 1 - layout_[j]]; + } + stridesf_.resize( strides_.size() ); + std::reverse_copy( strides_.begin(), strides_.end(), stridesf_.begin() ); +} + } // namespace array } // namespace atlas diff --git a/src/atlas/array/ArraySpec.h b/src/atlas/array/ArraySpec.h index a47236180..863f5eea0 100644 --- a/src/atlas/array/ArraySpec.h +++ b/src/atlas/array/ArraySpec.h @@ -4,7 +4,7 @@ * 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 size_tergovernmental organisation + * granted to it by virtue of its status as an intergovernmental organisation * nor does it submit to any jurisdiction. */ @@ -17,6 +17,7 @@ #include "atlas/array/ArrayLayout.h" #include "atlas/array/ArrayShape.h" #include "atlas/array/ArrayStrides.h" +#include "atlas/library/config.h" //------------------------------------------------------------------------------------------------------ @@ -25,15 +26,15 @@ namespace array { class ArraySpec { private: - size_t size_; - size_t rank_; - size_t allocated_size_; + idx_t size_; + idx_t rank_; + idx_t allocated_size_; ArrayShape shape_; ArrayStrides strides_; ArrayLayout layout_; ArrayAlignment alignment_; - mutable std::vector shapef_; - mutable std::vector stridesf_; + std::vector shapef_; + std::vector stridesf_; bool contiguous_; bool default_layout_; @@ -45,9 +46,9 @@ class ArraySpec { ArraySpec( const ArrayShape&, ArrayAlignment&& ); ArraySpec( const ArrayShape&, const ArrayStrides&, ArrayAlignment&& ); ArraySpec( const ArrayShape&, const ArrayStrides&, const ArrayLayout&, ArrayAlignment&& ); - size_t allocatedSize() const { return allocated_size_; } - size_t size() const { return size_; } - size_t rank() const { return rank_; } + idx_t allocatedSize() const { return allocated_size_; } + idx_t size() const { return size_; } + idx_t rank() const { return rank_; } const ArrayShape& shape() const { return shape_; } const ArrayAlignment& alignment() const { return alignment_; } const ArrayStrides& strides() const { return strides_; } @@ -56,6 +57,9 @@ class ArraySpec { const std::vector& stridesf() const; bool contiguous() const { return contiguous_; } bool hasDefaultLayout() const { return default_layout_; } + +private: + void allocate_fortran_specs(); }; //------------------------------------------------------------------------------------------------------ diff --git a/src/atlas/array/ArrayStrides.h b/src/atlas/array/ArrayStrides.h index d7be323da..44af9140b 100644 --- a/src/atlas/array/ArrayStrides.h +++ b/src/atlas/array/ArrayStrides.h @@ -4,7 +4,7 @@ * 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 size_tergovernmental organisation + * granted to it by virtue of its status as an intergovernmental organisation * nor does it submit to any jurisdiction. */ @@ -13,39 +13,44 @@ #include #include #include +#include "atlas/library/config.h" //------------------------------------------------------------------------------------------------------ namespace atlas { namespace array { -class ArrayStrides : public std::vector { +class ArrayStrides : public std::vector { private: - using Base = std::vector; + using Base = std::vector; public: ArrayStrides() {} - ArrayStrides( std::initializer_list list ) : Base( list ) {} + ArrayStrides( std::initializer_list list ) : Base( list ) {} ArrayStrides( Base&& base ) : Base( std::forward( base ) ) {} }; -inline ArrayStrides make_strides( std::initializer_list list ) { - return ArrayStrides( list ); +template +inline ArrayStrides make_strides( Int size1 ) { + return ArrayStrides{static_cast( size1 )}; } -inline ArrayStrides make_strides( size_t size1 ) { - return ArrayStrides{size1}; +template +inline ArrayStrides make_strides( Int1 size1, Int2 size2 ) { + return ArrayStrides{static_cast( size1 ), static_cast( size2 )}; } -inline ArrayStrides make_strides( size_t size1, size_t size2 ) { - return ArrayStrides{size1, size2}; +template +inline ArrayStrides make_strides( Int1 size1, Int2 size2, Int3 size3 ) { + return ArrayStrides{static_cast( size1 ), static_cast( size2 ), static_cast( size3 )}; } -inline ArrayStrides make_strides( size_t size1, size_t size2, size_t size3 ) { - return ArrayStrides{size1, size2, size3}; +template +inline ArrayStrides make_strides( Int1 size1, Int2 size2, Int3 size3, Int4 size4 ) { + return ArrayStrides{static_cast( size1 ), static_cast( size2 ), static_cast( size3 ), + static_cast( size4 )}; } -inline ArrayStrides make_strides( size_t size1, size_t size2, size_t size3, size_t size4 ) { - return ArrayStrides{size1, size2, size3, size4}; -} -inline ArrayStrides make_strides( size_t size1, size_t size2, size_t size3, size_t size4, size_t size5 ) { - return ArrayStrides{size1, size2, size3, size4, size5}; +template +inline ArrayStrides make_strides( Int1 size1, Int2 size2, Int3 size3, Int4 size4, Int5 size5 ) { + return ArrayStrides{static_cast( size1 ), static_cast( size2 ), static_cast( size3 ), + static_cast( size4 ), static_cast( size5 )}; } //------------------------------------------------------------------------------------------------------ diff --git a/src/atlas/array/ArrayUtil.cc b/src/atlas/array/ArrayUtil.cc index 0fedb760d..8cb7667d1 100644 --- a/src/atlas/array/ArrayUtil.cc +++ b/src/atlas/array/ArrayUtil.cc @@ -10,9 +10,8 @@ #include -#include "eckit/exception/Exceptions.h" - #include "atlas/array/ArrayUtil.h" +#include "atlas/runtime/Exception.h" namespace atlas { namespace array { @@ -20,7 +19,7 @@ namespace array { void throw_OutOfRange( const std::string& class_name, char idx_str, int idx, int max ) { std::ostringstream msg; msg << class_name << " index " << idx << " out of bounds: " << idx << " >= " << max; - throw eckit::OutOfRange( msg.str(), Here() ); + throw_Exception( msg.str(), Here() ); } } // namespace array diff --git a/src/atlas/array/ArrayUtil.h b/src/atlas/array/ArrayUtil.h index 85ae42beb..516af5663 100644 --- a/src/atlas/array/ArrayUtil.h +++ b/src/atlas/array/ArrayUtil.h @@ -4,7 +4,7 @@ * 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 size_tergovernmental organisation + * granted to it by virtue of its status as an intergovernmental organisation * nor does it submit to any jurisdiction. */ diff --git a/src/atlas/array/ArrayView.h b/src/atlas/array/ArrayView.h index a09df34aa..0f6ad6401 100644 --- a/src/atlas/array/ArrayView.h +++ b/src/atlas/array/ArrayView.h @@ -21,11 +21,11 @@ /// /// Example 1: /// int[] array = { 1, 2, 3, 4, 5, 6, 7, 8, 9}; -/// int[2] strides = { 3, 1 }; -/// int[2] shape = { 3, 3 }; +/// idx_t[2] strides = { 3, 1 }; +/// idx_t[2] shape = { 3, 3 }; /// ArrayView matrix( array, shape, strides ); -/// for( size_t i=0; i matrix( array, shape ); /// which is identical for this matrix to previous Example 1 /// @@ -56,3 +56,32 @@ #else #include "atlas/array/native/NativeArrayView.h" #endif + +namespace atlas { +namespace array { + +#define EXPLICIT_TEMPLATE_INSTANTIATION( Rank ) \ + extern template class ArrayView; \ + extern template class ArrayView; \ + extern template class ArrayView; \ + extern template class ArrayView; \ + extern template class ArrayView; \ + extern template class ArrayView; \ + extern template class ArrayView; \ + extern template class ArrayView; + +// For each NDims in [1..9] +EXPLICIT_TEMPLATE_INSTANTIATION( 1 ) +EXPLICIT_TEMPLATE_INSTANTIATION( 2 ) +EXPLICIT_TEMPLATE_INSTANTIATION( 3 ) +EXPLICIT_TEMPLATE_INSTANTIATION( 4 ) +EXPLICIT_TEMPLATE_INSTANTIATION( 5 ) +EXPLICIT_TEMPLATE_INSTANTIATION( 6 ) +EXPLICIT_TEMPLATE_INSTANTIATION( 7 ) +EXPLICIT_TEMPLATE_INSTANTIATION( 8 ) +EXPLICIT_TEMPLATE_INSTANTIATION( 9 ) + +#undef EXPLICIT_TEMPLATE_INSTANTIATION + +} // namespace array +} // namespace atlas diff --git a/src/atlas/array/ArrayViewDefs.h b/src/atlas/array/ArrayViewDefs.h index bf0fcfdaa..610cc6a7a 100644 --- a/src/atlas/array/ArrayViewDefs.h +++ b/src/atlas/array/ArrayViewDefs.h @@ -4,7 +4,7 @@ * 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 size_tergovernmental organisation + * granted to it by virtue of its status as an intergovernmental organisation * nor does it submit to any jurisdiction. */ diff --git a/src/atlas/array/ArrayViewUtil.h b/src/atlas/array/ArrayViewUtil.h index b8b27d5db..f2a53ab29 100644 --- a/src/atlas/array/ArrayViewUtil.h +++ b/src/atlas/array/ArrayViewUtil.h @@ -15,20 +15,20 @@ namespace atlas { namespace array { template -constexpr typename std::enable_if<( cnt == RANK ), size_t>::type get_var_size_impl( +constexpr typename std::enable_if<( cnt == RANK ), idx_t>::type get_var_size_impl( array::ArrayView& field ) { return 1; } template -constexpr typename std::enable_if<( cnt != RANK ), size_t>::type get_var_size_impl( +constexpr typename std::enable_if<( cnt != RANK ), idx_t>::type get_var_size_impl( array::ArrayView& field ) { return ( cnt == DimSkip ) ? get_var_size_impl( field ) : get_var_size_impl( field ) * field.template shape(); } template -constexpr size_t get_var_size( array::ArrayView& field ) { +constexpr idx_t get_var_size( array::ArrayView& field ) { return get_var_size_impl<0, DimSkip>( field ); } diff --git a/src/atlas/array/DataType.cc b/src/atlas/array/DataType.cc new file mode 100644 index 000000000..47b03dcb1 --- /dev/null +++ b/src/atlas/array/DataType.cc @@ -0,0 +1,38 @@ +/* + * (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 "DataType.h" + +#include + +#include "atlas/runtime/Exception.h" + +//------------------------------------------------------------------------------------------------------ + +namespace atlas { +namespace array { + +void DataType::throw_not_recognised( kind_t kind ) { + std::stringstream msg; + msg << "kind " << kind << " not recognised."; + throw_Exception( msg.str(), Here() ); +} + +void DataType::throw_not_recognised( std::string datatype ) { + std::stringstream msg; + msg << "datatype " << datatype << " not recognised."; + throw_Exception( msg.str(), Here() ); +} + + +//------------------------------------------------------------------------------------------------------ + +} // namespace array +} // namespace atlas diff --git a/src/atlas/array/DataType.h b/src/atlas/array/DataType.h index 40f9cfeb2..d4f55b156 100644 --- a/src/atlas/array/DataType.h +++ b/src/atlas/array/DataType.h @@ -4,16 +4,14 @@ * 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 size_tergovernmental organisation + * granted to it by virtue of its status as an intergovernmental organisation * nor does it submit to any jurisdiction. */ #pragma once -#include #include -#include "eckit/exception/Exceptions.h" //------------------------------------------------------------------------------------------------------ @@ -58,12 +56,16 @@ class DataType { static std::string real64_str() { return "real64"; } static std::string uint64_str() { return "uint64"; } + [[noreturn]] static void throw_not_recognised( kind_t ); + [[noreturn]] static void throw_not_recognised( std::string datatype ); + public: DataType( const std::string& ); DataType( long ); DataType( const DataType& ); std::string str() const { return kind_to_str( kind_ ); } kind_t kind() const { return kind_; } + size_t size() const { return ( kind_ == KIND_UINT64 ) ? 8 : std::abs( kind_ ); } friend bool operator==( DataType dt1, DataType dt2 ); friend bool operator!=( DataType dt1, DataType dt2 ); @@ -170,7 +172,7 @@ inline DataType::kind_t DataType::str_to_kind( const std::string& datatype ) { else if ( datatype == "real64" ) kind = KIND_REAL64; else { - throw eckit::Exception( "datatype " + datatype + " not recognised.", Here() ); + throw_not_recognised( datatype ); } return kind; } @@ -187,9 +189,7 @@ inline std::string DataType::kind_to_str( kind_t kind ) { case KIND_REAL64: return real64_str(); default: - std::stringstream msg; - msg << "kind " << kind << " not recognised."; - throw eckit::Exception( msg.str(), Here() ); + throw_not_recognised( kind ); } } inline bool DataType::kind_valid( kind_t kind ) { diff --git a/src/atlas/array/IndexView.h b/src/atlas/array/IndexView.h index 71daae95e..c12033119 100644 --- a/src/atlas/array/IndexView.h +++ b/src/atlas/array/IndexView.h @@ -23,11 +23,11 @@ /// /// Example: /// int[] array = { 1, 2, 3, 4, 5, 6, 7, 8, 9}; -/// int[2] strides = { 3, 1 }; -/// int[2] shape = { 3, 3 }; +/// idx_t[2] strides = { 3, 1 }; +/// idx_t[2] shape = { 3, 3 }; /// IndexView matrix( array, strides, shape ); -/// for( size_t i=0; i -#include "eckit/exception/Exceptions.h" - #include "atlas/array/helpers/ArrayAssigner.h" +#include "atlas/runtime/Exception.h" //------------------------------------------------------------------------------------------------------ @@ -32,17 +31,31 @@ void LocalView::assign( const value_type& value ) { template void LocalView::dump( std::ostream& os ) const { - ASSERT( contiguous() ); + ATLAS_ASSERT( contiguous(), "Cannot dump non-contiguous view" ); const value_type* data_ = data(); os << "size: " << size() << " , values: "; os << "[ "; - for ( size_t j = 0; j < size(); ++j ) + for ( idx_t j = 0; j < size(); ++j ) os << data_[j] << " "; os << "]"; } //------------------------------------------------------------------------------------------------------ +template +LocalView make_view( const Value data[], const ArrayShape& shape ) { + return LocalView( data, shape ); +} + +//------------------------------------------------------------------------------------------------------ + +template +LocalView make_view( const Value data[], size_t size ) { + return LocalView( data, ArrayShape{idx_t( size )} ); +} + +//------------------------------------------------------------------------------------------------------ + } // namespace array } // namespace atlas @@ -50,17 +63,51 @@ void LocalView::dump( std::ostream& os ) const { // Explicit instantiation namespace atlas { namespace array { -#define EXPLICIT_TEMPLATE_INSTANTIATION( Rank ) \ - template class LocalView; \ - template class LocalView; \ - template class LocalView; \ - template class LocalView; \ - template class LocalView; \ - template class LocalView; \ - template class LocalView; \ - template class LocalView; \ - template class LocalView; \ - template class LocalView; +#define EXPLICIT_TEMPLATE_INSTANTIATION( Rank ) \ + template class LocalView; \ + template class LocalView; \ + template class LocalView; \ + template class LocalView; \ + template class LocalView; \ + template class LocalView; \ + template class LocalView; \ + template class LocalView; \ + template class LocalView; \ + template class LocalView; \ + template LocalView make_view( const int data[], \ + const ArrayShape& ); \ + template LocalView make_view( const int data[], \ + const ArrayShape& ); \ + template LocalView make_view( const long data[], \ + const ArrayShape& ); \ + template LocalView make_view( const long data[], \ + const ArrayShape& ); \ + template LocalView make_view( const float data[], \ + const ArrayShape& ); \ + template LocalView make_view( const float data[], \ + const ArrayShape& ); \ + template LocalView make_view( const double data[], \ + const ArrayShape& ); \ + template LocalView make_view( \ + const double data[], const ArrayShape& ); \ + \ + template LocalView make_view( const int data[], \ + size_t ); \ + template LocalView make_view( const int data[], \ + size_t ); \ + template LocalView make_view( const long data[], \ + size_t ); \ + template LocalView make_view( const long data[], \ + size_t ); \ + template LocalView make_view( const float data[], \ + size_t ); \ + template LocalView make_view( const float data[], \ + size_t ); \ + template LocalView make_view( const double data[], \ + size_t ); \ + template LocalView make_view( \ + const double data[], size_t ); + // For each NDims in [1..9] EXPLICIT_TEMPLATE_INSTANTIATION( 1 ) @@ -74,5 +121,5 @@ EXPLICIT_TEMPLATE_INSTANTIATION( 8 ) EXPLICIT_TEMPLATE_INSTANTIATION( 9 ) #undef EXPLICIT_TEMPLATE_INSTANTIATION -} +} // namespace array } // namespace atlas diff --git a/src/atlas/array/LocalView.h b/src/atlas/array/LocalView.h index 12144f654..1d8c37cc5 100644 --- a/src/atlas/array/LocalView.h +++ b/src/atlas/array/LocalView.h @@ -24,8 +24,8 @@ /// int[2] strides = { 3, 1 }; /// int[2] shape = { 3, 3 }; /// LocalView matrix( array, shape, strides ); -/// for( size_t i=0; i( data ) ) { size_ = 1; - for ( size_t j = 0; j < Rank; ++j ) { + for ( idx_t j = 0; j < Rank; ++j ) { shape_[j] = shape[j]; strides_[j] = strides[j]; size_ *= shape_[j]; } } - LocalView( const value_type* data, const size_t shape[] ) : data_( const_cast( data ) ) { + LocalView( const value_type* data, const idx_t shape[] ) : data_( const_cast( data ) ) { size_ = 1; for ( int j = Rank - 1; j >= 0; --j ) { shape_[j] = shape[j]; @@ -126,11 +126,29 @@ class LocalView { return data_[index( idx... )]; } - size_t size() const { return size_; } + template + typename std::enable_if<( Rank == 1 && EnableBool ), const value_type&>::type operator[]( Int idx ) const { + check_bounds( idx ); + return data_[idx]; + } + + template + typename std::enable_if<( Rank == 1 && EnableBool ), value_type&>::type operator[]( Int idx ) { + check_bounds( idx ); + return data_[idx]; + } - size_t shape( size_t idx ) const { return shape_[idx]; } + idx_t size() const { return size_; } - size_t stride( size_t idx ) const { return strides_[idx]; } + template + idx_t shape( Int idx ) const { + return shape_[idx]; + } + + template + idx_t stride( Int idx ) const { + return strides_[idx]; + } value_type const* data() const { return data_; } @@ -142,7 +160,7 @@ class LocalView { void dump( std::ostream& os ) const; - static constexpr size_t rank() { return Rank; } + static constexpr idx_t rank() { return Rank; } template typename slice_t::type slice( Args... args ) { @@ -158,17 +176,17 @@ class LocalView { // -- Private methods template - constexpr int index_part( Int idx, Ints... next_idx ) const { + constexpr idx_t index_part( Int idx, Ints... next_idx ) const { return idx * strides_[Dim] + index_part( next_idx... ); } template - constexpr int index_part( Int last_idx ) const { + constexpr idx_t index_part( Int last_idx ) const { return last_idx * strides_[Dim]; } template - constexpr int index( Ints... idx ) const { + constexpr idx_t index( Ints... idx ) const { return index_part<0>( idx... ); } @@ -191,13 +209,13 @@ class LocalView { template void check_bounds_part( Int idx, Ints... next_idx ) const { - if ( size_t( idx ) >= shape_[Dim] ) { throw_OutOfRange( "LocalView", array_dim(), idx, shape_[Dim] ); } + if ( idx_t( idx ) >= shape_[Dim] ) { throw_OutOfRange( "LocalView", array_dim(), idx, shape_[Dim] ); } check_bounds_part( next_idx... ); } template void check_bounds_part( Int last_idx ) const { - if ( size_t( last_idx ) >= shape_[Dim] ) { + if ( idx_t( last_idx ) >= shape_[Dim] ) { throw_OutOfRange( "LocalView", array_dim(), last_idx, shape_[Dim] ); } } @@ -206,9 +224,9 @@ class LocalView { // -- Private data value_type* data_; - size_t size_; - size_t shape_[Rank]; - size_t strides_[Rank]; + idx_t size_; + idx_t shape_[Rank]; + idx_t strides_[Rank]; }; } // namespace array diff --git a/src/atlas/array/MakeView.h b/src/atlas/array/MakeView.h index b6062ae6a..26daaef50 100644 --- a/src/atlas/array/MakeView.h +++ b/src/atlas/array/MakeView.h @@ -1,5 +1,84 @@ +/* + * (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/array/ArrayView.h" #include "atlas/array/IndexView.h" +#include "atlas/array/LocalView.h" #include "atlas/array_fwd.h" + +namespace atlas { +namespace array { + +extern template IndexView make_indexview( const Array& ); + +#define EXPLICIT_TEMPLATE_INSTANTIATION( Rank ) \ + extern template ArrayView make_view( const Array& ); \ + extern template ArrayView make_view( const Array& ); \ + extern template ArrayView make_view( const Array& ); \ + extern template ArrayView make_view( const Array& ); \ + extern template ArrayView make_view( const Array& ); \ + extern template ArrayView make_view( \ + const Array& ); \ + extern template ArrayView make_view( \ + const Array& ); \ + extern template ArrayView make_view( \ + const Array& ); \ + \ + extern template LocalView make_view( \ + const int data[], const ArrayShape& ); \ + extern template LocalView make_view( \ + const int data[], const ArrayShape& ); \ + extern template LocalView make_view( \ + const long data[], const ArrayShape& ); \ + extern template LocalView make_view( \ + const long data[], const ArrayShape& ); \ + extern template LocalView make_view( \ + const float data[], const ArrayShape& ); \ + extern template LocalView make_view( \ + const float data[], const ArrayShape& ); \ + extern template LocalView make_view( \ + const double data[], const ArrayShape& ); \ + extern template LocalView make_view( \ + const double data[], const ArrayShape& ); \ + \ + extern template LocalView make_view( const int data[], \ + size_t ); \ + extern template LocalView make_view( const int data[], \ + size_t ); \ + extern template LocalView make_view( \ + const long data[], size_t ); \ + extern template LocalView make_view( \ + const long data[], size_t ); \ + extern template LocalView make_view( \ + const float data[], size_t ); \ + extern template LocalView make_view( \ + const float data[], size_t ); \ + extern template LocalView make_view( \ + const double data[], size_t ); \ + extern template LocalView make_view( \ + const double data[], size_t ); + +// For each NDims in [1..9] +EXPLICIT_TEMPLATE_INSTANTIATION( 1 ) +EXPLICIT_TEMPLATE_INSTANTIATION( 2 ) +EXPLICIT_TEMPLATE_INSTANTIATION( 3 ) +EXPLICIT_TEMPLATE_INSTANTIATION( 4 ) +EXPLICIT_TEMPLATE_INSTANTIATION( 5 ) +EXPLICIT_TEMPLATE_INSTANTIATION( 6 ) +EXPLICIT_TEMPLATE_INSTANTIATION( 7 ) +EXPLICIT_TEMPLATE_INSTANTIATION( 8 ) +EXPLICIT_TEMPLATE_INSTANTIATION( 9 ) + +#undef EXPLICIT_TEMPLATE_INSTANTIATION + +} // namespace array +} // namespace atlas diff --git a/src/atlas/array/Range.h b/src/atlas/array/Range.h index c8eb10535..b0db5f79a 100644 --- a/src/atlas/array/Range.h +++ b/src/atlas/array/Range.h @@ -103,6 +103,8 @@ class Range : public helpers::RangeBase { int start() const { return start_; } int end() const { return end_; } + Range() : Range( 0, 0 ) {} + private: int start_; int end_; diff --git a/src/atlas/array/SVector.cc b/src/atlas/array/SVector.cc new file mode 100644 index 000000000..40b45a624 --- /dev/null +++ b/src/atlas/array/SVector.cc @@ -0,0 +1,37 @@ +/* +* (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 "SVector.h" + +namespace atlas { +namespace array { + +//------------------------------------------------------------------------------ + +extern "C" { +void allocate_managedmem_double( double** a, int N ) { + allocate_managedmem( *a, N ); +} +void allocate_managedmem_float( double** a, int N ) { + allocate_managedmem( *a, N ); +} +void allocate_managedmem_int( int** a, int N ) { + allocate_managedmem( *a, N ); +} +void allocate_managedmem_long( long** a, int N ) { + allocate_managedmem( *a, N ); +} +} + +//------------------------------------------------------------------------------ + +} // namespace array +} // namespace atlas diff --git a/src/atlas/array/SVector.h b/src/atlas/array/SVector.h index cb74eebd1..89041bf2e 100644 --- a/src/atlas/array/SVector.h +++ b/src/atlas/array/SVector.h @@ -10,15 +10,12 @@ #pragma once +#include #include #include #include "atlas/library/config.h" -#include "atlas/runtime/ErrorHandling.h" - -#if ATLAS_GRIDTOOLS_STORAGE_BACKEND_CUDA -#include -#endif +#include "atlas/util/Allocate.h" namespace atlas { namespace array { @@ -32,48 +29,59 @@ class SVector { SVector() : data_( nullptr ), size_( 0 ), externally_allocated_( false ) {} ATLAS_HOST_DEVICE - SVector( SVector const& other ) : + SVector( const T* data, const idx_t size ) : data_( data ), size_( size ), externally_allocated_( true ) {} + + ATLAS_HOST_DEVICE + SVector( SVector const& other ) : data_( other.data_ ), size_( other.size_ ), externally_allocated_( true ) {} + + ATLAS_HOST_DEVICE + SVector( SVector&& other ) : data_( other.data_ ), size_( other.size_ ), externally_allocated_( other.externally_allocated_ ) {} ATLAS_HOST_DEVICE - SVector( T* data, size_t size ) : data_( data ), size_( size ) {} - - SVector( size_t N ) : data_( nullptr ), size_( N ), externally_allocated_( false ) { - if ( N != 0 ) { -#if ATLAS_GRIDTOOLS_STORAGE_BACKEND_CUDA - cudaError_t err = cudaMallocManaged( &data_, N * sizeof( T ) ); - if ( err != cudaSuccess ) throw eckit::AssertionFailed( "failed to allocate GPU memory" ); -#else - data_ = (T*)malloc( N * sizeof( T ) ); -#endif - } + SVector& operator=( SVector const& other ) { + data_ = other.data_; + size_ = other.size_; + externally_allocated_ = true; + return *this; + } + + SVector& operator=( SVector&& other ) = default; + + ATLAS_HOST_DEVICE + SVector( T* data, idx_t size ) : data_( data ), size_( size ), externally_allocated_( true ) {} + + SVector( idx_t N ) : data_( nullptr ), size_( N ), externally_allocated_( false ) { + util::allocate_managedmem( data_, N ); } ATLAS_HOST_DEVICE ~SVector() { #ifndef __CUDA_ARCH__ - if ( !externally_allocated_ ) delete_managedmem( data_ ); + if ( !externally_allocated_ ) util::delete_managedmem( data_ ); #endif } - void delete_managedmem( T*& data ) { - if ( data ) { -#if ATLAS_GRIDTOOLS_STORAGE_BACKEND_CUDA - cudaError_t err = cudaDeviceSynchronize(); - if ( err != cudaSuccess ) throw eckit::AssertionFailed( "failed to synchronize memory" ); + void insert( idx_t pos, idx_t dimsize ) { + T* data; + util::allocate_managedmem( data, size_ + dimsize ); - err = cudaFree( data ); - // The following throws an invalid device memory - - if ( err != cudaSuccess ) throw eckit::AssertionFailed( "failed to free GPU memory" ); - -#else - free( data_ ); -#endif - data_ = NULL; + for ( idx_t c = 0; c < pos; ++c ) { + data[c] = data_[c]; + } + for ( idx_t c = pos; c < size_; ++c ) { + data[c + dimsize] = data_[c]; } + + T* oldptr = data_; + data_ = data; + util::delete_managedmem( oldptr ); + size_ += dimsize; } + + size_t footprint() const { return sizeof( T ) * size_; } + ATLAS_HOST_DEVICE T* data() { return data_; } @@ -81,57 +89,59 @@ class SVector { T const* data() const { return data_; } ATLAS_HOST_DEVICE - T& operator()( const size_t idx ) { + T& operator()( const idx_t idx ) { assert( data_ && idx < size_ ); return data_[idx]; } ATLAS_HOST_DEVICE - T const& operator()( const size_t idx ) const { + T const& operator()( const idx_t idx ) const { assert( data_ && idx < size_ ); return data_[idx]; } ATLAS_HOST_DEVICE - T& operator[]( const size_t idx ) { + T& operator[]( const idx_t idx ) { assert( data_ && idx < size_ ); return data_[idx]; } ATLAS_HOST_DEVICE - T const& operator[]( const size_t idx ) const { + T const& operator[]( const idx_t idx ) const { assert( data_ && idx < size_ ); return data_[idx]; } ATLAS_HOST_DEVICE - size_t size() const { return size_; } + idx_t size() const { return size_; } - void resize_impl( size_t N ) { - assert( N >= size_ ); + void resize_impl( idx_t N ) { if ( N == size_ ) return; - T* d_; -#if ATLAS_GRIDTOOLS_STORAGE_BACKEND_CUDA - cudaError_t err = cudaMallocManaged( &d_, sizeof( T ) * N ); - if ( err != cudaSuccess ) throw eckit::AssertionFailed( "failed to allocate GPU memory" ); - -#else - d_ = (T*)malloc( sizeof( T ) * N ); -#endif - for ( unsigned int c = 0; c < size_; ++c ) { + T* d_ = nullptr; + util::allocate_managedmem( d_, N ); + for ( idx_t c = 0; c < std::min( size_, N ); ++c ) { d_[c] = data_[c]; } - delete_managedmem( data_ ); + util::delete_managedmem( data_ ); data_ = d_; } - void resize( size_t N ) { + void resize( idx_t N ) { resize_impl( N ); size_ = N; } + + void resize( idx_t N, T&& val ) { + const int oldsize = size_; + resize( N ); + for ( idx_t c = oldsize; c < size_; ++c ) { + data_[c] = val; + } + } + private: T* data_; - size_t size_; + idx_t size_; bool externally_allocated_; }; diff --git a/src/atlas/array/Table.cc b/src/atlas/array/Table.cc index 34b2e0f81..abf59e35f 100644 --- a/src/atlas/array/Table.cc +++ b/src/atlas/array/Table.cc @@ -8,12 +8,15 @@ * nor does it submit to any jurisdiction. */ -#include "atlas/array/Table.h" +#include "Table.h" + +#include #include + #include "atlas/array.h" #include "atlas/array/DataType.h" #include "atlas/library/defines.h" -#include "atlas/runtime/ErrorHandling.h" +#include "atlas/runtime/Exception.h" #if ATLAS_HAVE_FORTRAN #define FORTRAN_BASE 1 @@ -128,8 +131,8 @@ void Table::resize_values( size_t old_size, size_t new_size, bool initialize, co // ---------------------------------------------------------------------------- void Table::resize_counts_and_displs( size_t size ) { - ASSERT( data_[_displs_] != 0 ); - ASSERT( data_[_counts_] != 0 ); + ATLAS_ASSERT( data_[_displs_] != 0 ); + ATLAS_ASSERT( data_[_counts_] != 0 ); data_[_displs_]->resize( size ); data_[_counts_]->resize( size ); displs_ = make_host_view( *( data_[_displs_] ) ); @@ -139,8 +142,8 @@ void Table::resize_counts_and_displs( size_t size ) { // ---------------------------------------------------------------------------- void Table::insert_counts_and_displs( size_t position, size_t rows ) { - ASSERT( data_[_displs_] != 0 ); - ASSERT( data_[_counts_] != 0 ); + ATLAS_ASSERT( data_[_displs_] != 0 ); + ATLAS_ASSERT( data_[_counts_] != 0 ); data_[_displs_]->insert( position, rows ); data_[_counts_]->insert( position, rows ); displs_ = make_host_view( *( data_[_displs_] ) ); @@ -150,7 +153,7 @@ void Table::insert_counts_and_displs( size_t position, size_t rows ) { // ---------------------------------------------------------------------------- void Table::resize_values( size_t size ) { - ASSERT( data_[_values_] != 0 ); + ATLAS_ASSERT( data_[_values_] != 0 ); data_[_values_]->resize( size ); values_ = make_host_view( *( data_[_values_] ) ); } @@ -158,7 +161,7 @@ void Table::resize_values( size_t size ) { // ---------------------------------------------------------------------------- void Table::insert_values( size_t position, size_t size ) { - ASSERT( data_[_values_] != 0 ); + ATLAS_ASSERT( data_[_values_] != 0 ); data_[_values_]->insert( position, size ); values_ = make_host_view( *( data_[_values_] ) ); } @@ -166,7 +169,7 @@ void Table::insert_values( size_t position, size_t size ) { // ---------------------------------------------------------------------------- void Table::add( size_t rows, size_t cols, const idx_t values[], bool fortran_array ) { - if ( !owns_ ) throw eckit::AssertionFailed( "HybridConnectivity must be owned to be resized directly" ); + ATLAS_ASSERT( owns_, "HybridConnectivity must be owned to be resized directly" ); size_t old_size = size(); if ( rows_ == 0 ) old_size = 0; @@ -190,7 +193,7 @@ void Table::add( size_t rows, size_t cols, const idx_t values[], bool fortran_ar // ---------------------------------------------------------------------------- void Table::add( size_t rows, const size_t cols[] ) { - if ( !owns_ ) throw eckit::AssertionFailed( "HybridConnectivity must be owned to be resized directly" ); + ATLAS_ASSERT( owns_, "HybridConnectivity must be owned to be resized directly" ); size_t old_size = size(); size_t new_size = old_size; for ( size_t j = 0; j < rows; ++j ) @@ -211,7 +214,7 @@ void Table::add( size_t rows, const size_t cols[] ) { // ---------------------------------------------------------------------------- void Table::add( size_t rows, size_t cols ) { - if ( !owns_ ) throw eckit::AssertionFailed( "HybridConnectivity must be owned to be resized directly" ); + ATLAS_ASSERT( owns_, "HybridConnectivity must be owned to be resized directly" ); size_t old_size = size(); if ( rows_ == 0 ) old_size = 0; @@ -228,14 +231,14 @@ void Table::add( size_t rows, size_t cols ) { mincols_ = std::min( mincols_, cols ); const bool dummy_arg_fortran_array = false; - const idx_t* dummy_arg_values = NULL; + const idx_t* dummy_arg_values = nullptr; resize_values( old_size, new_size, false, dummy_arg_values, dummy_arg_fortran_array ); } // ---------------------------------------------------------------------------- void Table::insert( size_t position, size_t rows, size_t cols, const idx_t values[], bool fortran_array ) { - if ( !owns_ ) throw eckit::AssertionFailed( "HybridConnectivity must be owned to be resized directly" ); + ATLAS_ASSERT( owns_, "HybridConnectivity must be owned to be resized directly" ); size_t position_displs = displs_( position ); insert_counts_and_displs( position, rows ); @@ -251,7 +254,7 @@ void Table::insert( size_t position, size_t rows, size_t cols, const idx_t value insert_values( position_displs, rows * cols ); - if ( values == NULL ) { + if ( values == nullptr ) { for ( size_t c = position_displs; c < position_displs + rows * cols; ++c ) { values_( c ) = missing_value() TO_FORTRAN; } @@ -268,13 +271,13 @@ void Table::insert( size_t position, size_t rows, size_t cols, const idx_t value // ---------------------------------------------------------------------------- void Table::insert( size_t position, size_t rows, size_t cols ) { - Table::insert( position, rows, cols, NULL, false ); + Table::insert( position, rows, cols, nullptr, false ); } // ---------------------------------------------------------------------------- void Table::insert( size_t position, size_t rows, const size_t cols[] ) { - if ( !owns_ ) throw eckit::AssertionFailed( "HybridConnectivity must be owned to be resized directly" ); + ATLAS_ASSERT( owns_, "HybridConnectivity must be owned to be resized directly" ); size_t position_displs = displs_( position ); if ( rows_ == 0 ) { diff --git a/src/atlas/array/Table.h b/src/atlas/array/Table.h index f4a257bc9..b9cfdc0ec 100644 --- a/src/atlas/array/Table.h +++ b/src/atlas/array/Table.h @@ -19,7 +19,7 @@ #include #include -#include "eckit/memory/Owned.h" +#include "atlas/util/Object.h" #include "atlas/array.h" #include "atlas/library/config.h" @@ -52,7 +52,7 @@ namespace array { /// In the first mode of construction, the connectivity table cannot be resized. /// In the second mode of construction, resizing is possible -class Table : public eckit::Owned { +class Table : public util::Object { private: static constexpr unsigned short _values_ = 0; static constexpr unsigned short _displs_ = 1; diff --git a/src/atlas/array/TableView.h b/src/atlas/array/TableView.h index 8b4a4bb55..976838d2c 100644 --- a/src/atlas/array/TableView.h +++ b/src/atlas/array/TableView.h @@ -139,7 +139,7 @@ class TableRow { // ------------------------------------------------------------------------------------------------------ template -class TableView : public eckit::Owned { +class TableView : public util::Object { #if ATLAS_HAVE_FORTRAN using Index = typename std::conditional::type; #else diff --git a/src/atlas/array/Vector.cc b/src/atlas/array/Vector.cc new file mode 100644 index 000000000..3a45d1c41 --- /dev/null +++ b/src/atlas/array/Vector.cc @@ -0,0 +1,17 @@ +/* +* (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 "Vector.h" + +namespace atlas { +namespace array { +namespace detail {} // namespace detail +} // namespace array +} // namespace atlas diff --git a/src/atlas/array/Vector.h b/src/atlas/array/Vector.h index 5c785509f..ceddb2cda 100644 --- a/src/atlas/array/Vector.h +++ b/src/atlas/array/Vector.h @@ -14,7 +14,7 @@ #include #include "atlas/library/config.h" -#include "atlas/runtime/ErrorHandling.h" +#include "atlas/runtime/Exception.h" #if ATLAS_GRIDTOOLS_STORAGE_BACKEND_CUDA #include @@ -28,29 +28,29 @@ namespace array { template class Vector { public: - Vector( size_t N = 0 ) : data_( N ? new T[N] : nullptr ), data_gpu_( nullptr ), size_( N ) {} + Vector( idx_t N = 0 ) : data_( N ? new T[N] : nullptr ), data_gpu_( nullptr ), size_( N ) {} - void resize_impl( size_t N ) { - if ( data_gpu_ ) throw eckit::AssertionFailed( "we can not resize a vector after has been cloned to device" ); - assert( N >= size_ ); + void resize_impl( idx_t N ) { + ATLAS_ASSERT( not data_gpu_, "we can not resize a vector after has been cloned to device" ); + ATLAS_ASSERT( N >= size_ ); if ( N == size_ ) return; T* d_ = new T[N]; - for ( unsigned int c = 0; c < size_; ++c ) { + for ( idx_t c = 0; c < size_; ++c ) { d_[c] = data_[c]; } if ( data_ ) delete[] data_; data_ = d_; } - void resize( size_t N ) { + void resize( idx_t N ) { resize_impl( N ); size_ = N; } - void resize( size_t N, T val ) { + void resize( idx_t N, T val ) { resize_impl( N ); - for ( unsigned int c = size_; c < N; ++c ) { + for ( idx_t c = size_; c < N; ++c ) { data_[c] = val; } @@ -64,7 +64,7 @@ class Vector { T* buff = new T[size_]; - for ( size_t i = 0; i < size(); ++i ) { + for ( idx_t i = 0; i < size(); ++i ) { data_[i]->cloneToDevice(); buff[i] = data_[i]->gpu_object_ptr(); } @@ -76,9 +76,9 @@ class Vector { size_gpu_ = size_; } else { - assert( size_gpu_ == size_ ); + ATLAS_ASSERT( size_gpu_ == size_ ); #if ATLAS_GRIDTOOLS_STORAGE_BACKEND_CUDA - for ( size_t i = 0; i < size(); ++i ) { + for ( idx_t i = 0; i < size(); ++i ) { data_[i]->cloneToDevice(); assert( data_gpu_[i] == data_[i]->gpu_object_ptr() ); } @@ -86,11 +86,11 @@ class Vector { } } void cloneFromDevice() { - assert( data_gpu_ ); + ATLAS_ASSERT( data_gpu_ != nullptr ); #if ATLAS_GRIDTOOLS_STORAGE_BACKEND_CUDA - for ( size_t i = 0; i < size(); ++i ) { + for ( idx_t i = 0; i < size(); ++i ) { data_[i]->cloneFromDevice(); } #endif @@ -101,30 +101,30 @@ class Vector { T* data() { return data_; } T* data_gpu() { return data_gpu_; } - size_t size() const { return size_; } + idx_t size() const { return size_; } private: T* data_; T* data_gpu_; - size_t size_; - size_t size_gpu_; + idx_t size_; + idx_t size_gpu_; }; template class VectorView { public: - VectorView() : vector_( NULL ), data_( NULL ), size_( 0 ) {} + VectorView() : vector_( nullptr ), data_( nullptr ), size_( 0 ) {} VectorView( Vector const& vector, T* data ) : vector_( &vector ), data_( data ), size_( vector.size() ) {} ATLAS_HOST_DEVICE - T& operator[]( size_t idx ) { + T& operator[]( idx_t idx ) { assert( idx < size_ ); return data_[idx]; } ATLAS_HOST_DEVICE - T const& operator[]( size_t idx ) const { + T const& operator[]( idx_t idx ) const { assert( idx < size_ ); return data_[idx]; } @@ -132,14 +132,14 @@ class VectorView { T base() { return *data_; } ATLAS_HOST_DEVICE - size_t size() const { return size_; } + idx_t size() const { return size_; } - bool is_valid( Vector& vector ) { return ( &vector ) == vector_ && ( data_ != NULL ); } + bool is_valid( Vector& vector ) { return ( &vector ) == vector_ && ( data_ != nullptr ); } public: Vector const* vector_; T* data_; - size_t size_; + idx_t size_; }; template diff --git a/src/atlas/array/gridtools/GridToolsArray.cc b/src/atlas/array/gridtools/GridToolsArray.cc index a2c88c39a..9a472a63a 100644 --- a/src/atlas/array/gridtools/GridToolsArray.cc +++ b/src/atlas/array/gridtools/GridToolsArray.cc @@ -22,10 +22,11 @@ #include "atlas/array/gridtools/GridToolsTraits.h" #include "atlas/array/helpers/ArrayInitializer.h" #include "atlas/array_fwd.h" +#include "atlas/runtime/Log.h" + #if ATLAS_HAVE_ACC #include "atlas_acc_support/atlas_acc_map_data.h" #endif -#include "eckit/exception/Exceptions.h" //------------------------------------------------------------------------------ @@ -85,14 +86,14 @@ class ArrayT_impl { default: { std::stringstream err; err << "shape not recognized"; - throw eckit::BadParameter( err.str(), Here() ); + throw_Exception( err.str(), Here() ); } } } void construct( const ArrayShape& shape, const ArrayLayout& layout ) { - ASSERT( shape.size() > 0 ); - ASSERT( shape.size() == layout.size() ); + ATLAS_ASSERT( shape.size() > 0 ); + ATLAS_ASSERT( shape.size() == layout.size() ); switch ( shape.size() ) { case 1: return construct( shape[0] ); @@ -142,7 +143,7 @@ class ArrayT_impl { err << layout[j] << " "; err << "> not implemented in Atlas."; } - throw eckit::BadParameter( err.str(), Here() ); + throw_Exception( err.str(), Here() ); } } } @@ -162,14 +163,12 @@ class ArrayT_impl { std::stringstream err; err << "Trying to resize an array of Rank " << array_.rank() << " by dimensions with Rank " << sizeof...( c ) << std::endl; - throw eckit::BadParameter( err.str(), Here() ); + throw_Exception( err.str(), Here() ); } - check_dimension_lengths( array_.shape(), c... ); - if ( array_.valid() ) array_.syncHostDevice(); - Array* resized = Array::create( ArrayShape{(unsigned int)c...} ); + Array* resized = Array::create( ArrayShape{(idx_t)c...} ); array_initializer::apply( array_, *resized ); array_.replace( *resized ); @@ -188,23 +187,23 @@ class ArrayT_impl { //------------------------------------------------------------------------------ template -Array* Array::create( size_t dim0 ) { +Array* Array::create( idx_t dim0 ) { return new ArrayT( dim0 ); } template -Array* Array::create( size_t dim0, size_t dim1 ) { +Array* Array::create( idx_t dim0, idx_t dim1 ) { return new ArrayT( dim0, dim1 ); } template -Array* Array::create( size_t dim0, size_t dim1, size_t dim2 ) { +Array* Array::create( idx_t dim0, idx_t dim1, idx_t dim2 ) { return new ArrayT( dim0, dim1, dim2 ); } template -Array* Array::create( size_t dim0, size_t dim1, size_t dim2, size_t dim3 ) { +Array* Array::create( idx_t dim0, idx_t dim1, idx_t dim2, idx_t dim3 ) { return new ArrayT( dim0, dim1, dim2, dim3 ); } template -Array* Array::create( size_t dim0, size_t dim1, size_t dim2, size_t dim3, size_t dim4 ) { +Array* Array::create( idx_t dim0, idx_t dim1, idx_t dim2, idx_t dim3, idx_t dim4 ) { return new ArrayT( dim0, dim1, dim2, dim3, dim4 ); } template @@ -262,7 +261,7 @@ Array* Array::wrap( Value* data, const ArraySpec& spec ) { default: { std::stringstream err; err << "shape not recognized"; - throw eckit::BadParameter( err.str(), Here() ); + throw_Exception( err.str(), Here() ); } } } @@ -286,10 +285,9 @@ Array* Array::create( DataType datatype, const ArrayShape& shape ) { default: { std::stringstream err; err << "data kind " << datatype.kind() << " not recognised."; - throw eckit::BadParameter( err.str(), Here() ); + throw_Exception( err.str(), Here() ); } } - return 0; } Array* Array::create( DataType datatype, const ArrayShape& shape, const ArrayLayout& layout ) { @@ -308,10 +306,9 @@ Array* Array::create( DataType datatype, const ArrayShape& shape, const ArrayLay default: { std::stringstream err; err << "data kind " << datatype.kind() << " not recognised."; - throw eckit::BadParameter( err.str(), Here() ); + throw_Exception( err.str(), Here() ); } } - return 0; } //------------------------------------------------------------------------------ @@ -344,16 +341,14 @@ bool ArrayT::accMap() const { //------------------------------------------------------------------------------ template -void ArrayT::insert( size_t idx1, size_t size1 ) { +void ArrayT::insert( idx_t idx1, idx_t size1 ) { // if( hostNeedsUpdate() ) { // cloneFromDevice(); //} - if ( not hasDefaultLayout() ) NOTIMP; + if ( not hasDefaultLayout() ) ATLAS_NOTIMPLEMENTED; ArrayShape nshape = shape(); - if ( idx1 > nshape[0] ) { - throw eckit::BadParameter( "can not insert into an array at a position beyond its size", Here() ); - } + if ( idx1 > nshape[0] ) { throw_Exception( "can not insert into an array at a position beyond its size", Here() ); } nshape[0] += size1; Array* resized = Array::create( nshape ); @@ -367,27 +362,27 @@ void ArrayT::insert( size_t idx1, size_t size1 ) { //------------------------------------------------------------------------------ template -void ArrayT::resize( size_t dim0 ) { +void ArrayT::resize( idx_t dim0 ) { ArrayT_impl( *this ).resize_variadic( dim0 ); } template -void ArrayT::resize( size_t dim0, size_t dim1 ) { +void ArrayT::resize( idx_t dim0, idx_t dim1 ) { ArrayT_impl( *this ).resize_variadic( dim0, dim1 ); } template -void ArrayT::resize( size_t dim0, size_t dim1, size_t dim2 ) { +void ArrayT::resize( idx_t dim0, idx_t dim1, idx_t dim2 ) { ArrayT_impl( *this ).resize_variadic( dim0, dim1, dim2 ); } template -void ArrayT::resize( size_t dim0, size_t dim1, size_t dim2, size_t dim3 ) { +void ArrayT::resize( idx_t dim0, idx_t dim1, idx_t dim2, idx_t dim3 ) { ArrayT_impl( *this ).resize_variadic( dim0, dim1, dim2, dim3 ); } template -void ArrayT::resize( size_t dim0, size_t dim1, size_t dim2, size_t dim3, size_t dim4 ) { +void ArrayT::resize( idx_t dim0, idx_t dim1, idx_t dim2, idx_t dim3, idx_t dim4 ) { ArrayT_impl( *this ).resize_variadic( dim0, dim1, dim2, dim3, dim4 ); } @@ -422,7 +417,7 @@ void ArrayT::dump( std::ostream& out ) const { make_host_view( *this ).dump( out ); break; default: - NOTIMP; + ATLAS_NOTIMPLEMENTED; } } @@ -451,7 +446,7 @@ void ArrayT::resize( const ArrayShape& shape ) { default: { std::stringstream err; err << "shape not recognized"; - throw eckit::BadParameter( err.str(), Here() ); + throw_Exception( err.str(), Here() ); } } } @@ -466,23 +461,23 @@ ArrayT::ArrayT( ArrayDataStore* ds, const ArraySpec& spec ) { } template -ArrayT::ArrayT( size_t dim0 ) { +ArrayT::ArrayT( idx_t dim0 ) { ArrayT_impl( *this ).construct( dim0 ); } template -ArrayT::ArrayT( size_t dim0, size_t dim1 ) { +ArrayT::ArrayT( idx_t dim0, idx_t dim1 ) { ArrayT_impl( *this ).construct( dim0, dim1 ); } template -ArrayT::ArrayT( size_t dim0, size_t dim1, size_t dim2 ) { +ArrayT::ArrayT( idx_t dim0, idx_t dim1, idx_t dim2 ) { ArrayT_impl( *this ).construct( dim0, dim1, dim2 ); } template -ArrayT::ArrayT( size_t dim0, size_t dim1, size_t dim2, size_t dim3 ) { +ArrayT::ArrayT( idx_t dim0, idx_t dim1, idx_t dim2, idx_t dim3 ) { ArrayT_impl( *this ).construct( dim0, dim1, dim2, dim3 ); } template -ArrayT::ArrayT( size_t dim0, size_t dim1, size_t dim2, size_t dim3, size_t dim4 ) { +ArrayT::ArrayT( idx_t dim0, idx_t dim1, idx_t dim2, idx_t dim3, idx_t dim4 ) { ArrayT_impl( *this ).construct( dim0, dim1, dim2, dim3, dim4 ); } @@ -498,7 +493,7 @@ ArrayT::ArrayT( const ArrayShape& shape, const ArrayLayout& layout ) { template ArrayT::ArrayT( const ArraySpec& spec ) { - if ( not spec.contiguous() ) NOTIMP; + if ( not spec.contiguous() ) ATLAS_NOTIMPLEMENTED; ArrayT_impl( *this ).construct( spec.shape(), spec.layout() ); } @@ -518,35 +513,35 @@ template class ArrayT; template class ArrayT; template class ArrayT; -template Array* Array::create( size_t ); -template Array* Array::create( size_t ); -template Array* Array::create( size_t ); -template Array* Array::create( size_t ); -template Array* Array::create( size_t ); - -template Array* Array::create( size_t, size_t ); -template Array* Array::create( size_t, size_t ); -template Array* Array::create( size_t, size_t ); -template Array* Array::create( size_t, size_t ); -template Array* Array::create( size_t, size_t ); - -template Array* Array::create( size_t, size_t, size_t ); -template Array* Array::create( size_t, size_t, size_t ); -template Array* Array::create( size_t, size_t, size_t ); -template Array* Array::create( size_t, size_t, size_t ); -template Array* Array::create( size_t, size_t, size_t ); - -template Array* Array::create( size_t, size_t, size_t, size_t ); -template Array* Array::create( size_t, size_t, size_t, size_t ); -template Array* Array::create( size_t, size_t, size_t, size_t ); -template Array* Array::create( size_t, size_t, size_t, size_t ); -template Array* Array::create( size_t, size_t, size_t, size_t ); - -template Array* Array::create( size_t, size_t, size_t, size_t, size_t ); -template Array* Array::create( size_t, size_t, size_t, size_t, size_t ); -template Array* Array::create( size_t, size_t, size_t, size_t, size_t ); -template Array* Array::create( size_t, size_t, size_t, size_t, size_t ); -template Array* Array::create( size_t, size_t, size_t, size_t, size_t ); +template Array* Array::create( idx_t ); +template Array* Array::create( idx_t ); +template Array* Array::create( idx_t ); +template Array* Array::create( idx_t ); +template Array* Array::create( idx_t ); + +template Array* Array::create( idx_t, idx_t ); +template Array* Array::create( idx_t, idx_t ); +template Array* Array::create( idx_t, idx_t ); +template Array* Array::create( idx_t, idx_t ); +template Array* Array::create( idx_t, idx_t ); + +template Array* Array::create( idx_t, idx_t, idx_t ); +template Array* Array::create( idx_t, idx_t, idx_t ); +template Array* Array::create( idx_t, idx_t, idx_t ); +template Array* Array::create( idx_t, idx_t, idx_t ); +template Array* Array::create( idx_t, idx_t, idx_t ); + +template Array* Array::create( idx_t, idx_t, idx_t, idx_t ); +template Array* Array::create( idx_t, idx_t, idx_t, idx_t ); +template Array* Array::create( idx_t, idx_t, idx_t, idx_t ); +template Array* Array::create( idx_t, idx_t, idx_t, idx_t ); +template Array* Array::create( idx_t, idx_t, idx_t, idx_t ); + +template Array* Array::create( idx_t, idx_t, idx_t, idx_t, idx_t ); +template Array* Array::create( idx_t, idx_t, idx_t, idx_t, idx_t ); +template Array* Array::create( idx_t, idx_t, idx_t, idx_t, idx_t ); +template Array* Array::create( idx_t, idx_t, idx_t, idx_t, idx_t ); +template Array* Array::create( idx_t, idx_t, idx_t, idx_t, idx_t ); template Array* Array::create( const ArrayShape& ); template Array* Array::create( const ArrayShape& ); diff --git a/src/atlas/array/gridtools/GridToolsArrayHelpers.h b/src/atlas/array/gridtools/GridToolsArrayHelpers.h index 651227bce..cff711378 100644 --- a/src/atlas/array/gridtools/GridToolsArrayHelpers.h +++ b/src/atlas/array/gridtools/GridToolsArrayHelpers.h @@ -15,14 +15,13 @@ #include #include -#include "eckit/exception/Exceptions.h" - #include "atlas/array.h" #include "atlas/array/ArrayUtil.h" #include "atlas/array/DataType.h" #include "atlas/array/gridtools/GridToolsTraits.h" #include "atlas/array_fwd.h" #include "atlas/library/config.h" +#include "atlas/runtime/Exception.h" #include "atlas/runtime/Log.h" //------------------------------------------------------------------------------ @@ -32,8 +31,8 @@ namespace array { namespace gridtools { template -std::array get_array_from_vector( std::vector const& values ) { - std::array array; +std::array get_array_from_vector( std::vector const& values ) { + std::array array; std::copy( values.begin(), values.end(), array.begin() ); return array; } @@ -46,7 +45,7 @@ struct check_dimension_lengths_impl { std::stringstream err; err << "Attempt to resize array with original size for dimension " << Dim << " of " << shape[Dim] << " by " << first_dim << std::endl; - throw eckit::BadParameter( err.str(), Here() ); + throw_Exception( err.str(), Here() ); } check_dimension_lengths_impl::apply( shape, d... ); } @@ -61,7 +60,7 @@ struct check_dimension_lengths_impl; }; - using type = typename get_layout::type>::type; + using type = typename get_layout<::gridtools::make_gt_integer_sequence<::gridtools::uint_t, Rank>>::type; }; template @@ -111,7 +110,7 @@ struct get_layout_map_component { }; }; -template +template struct get_stride_component { template struct get_component { @@ -127,17 +126,20 @@ struct get_stride_component { }; }; -template +template struct get_shape_component { - ATLAS_HOST_DEVICE - constexpr get_shape_component() {} - - template - ATLAS_HOST_DEVICE constexpr static size_t apply( StorageInfoPtr a ) { - static_assert( (::gridtools::is_storage_info::type>::value ), - "Error: not a storage_info" ); - return a->template unaligned_dim(); - } + template + struct get_component { + ATLAS_HOST_DEVICE + constexpr get_component() {} + + template + ATLAS_HOST_DEVICE constexpr static Value apply( StorageInfoPtr a ) { + static_assert( (::gridtools::is_storage_info::type>::value ), + "Error: not a storage_info" ); + return a->template total_length(); + } + }; }; // indirection around C++11 sizeof... since it is buggy for nvcc and cray @@ -169,24 +171,29 @@ create_gt_storage( UInts... dims ) { template static gridtools::storage_traits::data_store_t>* -wrap_gt_storage( Value* data, std::array&& shape, std::array&& strides ) { +wrap_gt_storage( Value* data, std::array&& shape, std::array&& strides ) { static_assert( ( Rank > 0 ), "Error: can not create storages without any dimension" ); typedef gridtools::storage_traits::storage_info_t<0, Rank, ::gridtools::zero_halo> storage_info_ty; typedef gridtools::storage_traits::data_store_t data_store_t; - - storage_info_ty si( shape, strides ); + ::gridtools::array<::gridtools::uint_t, Rank> _shape; + ::gridtools::array<::gridtools::uint_t, Rank> _strides; + for ( unsigned int i = 0; i < Rank; ++i ) { + _shape[i] = shape[i]; + _strides[i] = strides[i]; + } + storage_info_ty si( _shape, _strides ); data_store_t* ds = new data_store_t( si, data ); return ds; } -constexpr size_t zero( std::size_t ) { +constexpr idx_t zero( idx_t ) { return 0; } -template -ArrayShape make_null_strides(::gridtools::gt_integer_sequence ) { - return make_strides( {zero( Is )...} ); +template +ArrayStrides make_null_strides(::gridtools::gt_integer_sequence ) { + return make_strides( zero( Is )... ); } template @@ -223,24 +230,19 @@ ArraySpec ATLAS_HOST make_spec( DataStore* gt_data_store_ptr, Dims... dims ) { using Layout = typename DataStore::storage_info_t::layout_t; using Alignment = typename DataStore::storage_info_t::alignment_t; - using seq = - my_apply_gt_integer_sequence::type>; + using seq = my_apply_gt_integer_sequence<::gridtools::make_gt_integer_sequence>; ArraySpec spec( - ArrayShape{(unsigned long)dims...}, - seq::template apply< - ArrayStrides, - get_stride_component::type>::template get_component>( - storage_info_ptr ), - seq::template apply::template get_component>(), + ArrayShape{(idx_t)dims...}, + seq::template apply::template get_component>( storage_info_ptr ), + seq::template apply::template get_component>(), ArrayAlignment( Alignment::value ) ); - ASSERT( spec.allocatedSize() == storage_info_ptr->padded_total_length() ); + ATLAS_ASSERT( spec.allocatedSize() == storage_info_ptr->padded_total_length() ); return spec; } else { - return ArraySpec( - make_shape( {dims...} ), - make_null_strides( typename ::gridtools::make_gt_integer_sequence::type() ) ); + return ArraySpec( make_shape( {dims...} ), + make_null_strides(::gridtools::make_gt_integer_sequence() ) ); } } #endif diff --git a/src/atlas/array/gridtools/GridToolsArrayView.cc b/src/atlas/array/gridtools/GridToolsArrayView.cc index 8f98835ce..9630b5ed5 100644 --- a/src/atlas/array/gridtools/GridToolsArrayView.cc +++ b/src/atlas/array/gridtools/GridToolsArrayView.cc @@ -14,7 +14,7 @@ #include "atlas/array/helpers/ArrayAssigner.h" #include "atlas/array/helpers/ArrayInitializer.h" #include "atlas/array/helpers/ArrayWriter.h" -#include "eckit/exception/Exceptions.h" +#include "atlas/runtime/Exception.h" namespace atlas { namespace array { @@ -31,6 +31,8 @@ struct host_device_array { ATLAS_HOST_DEVICE const T* data() const { return data_; } + T operator[]( int i ) const { return data_[i]; } + T data_[Rank]; }; @@ -39,8 +41,8 @@ ArrayView::ArrayView( const ArrayView& other ) : gt_data_view_( other.gt_data_view_ ), data_store_orig_( other.data_store_orig_ ), array_( other.array_ ) { - std::memcpy( shape_, other.shape_, sizeof( size_t ) * Rank ); - std::memcpy( strides_, other.strides_, sizeof( size_t ) * Rank ); + std::memcpy( shape_, other.shape_, sizeof( ArrayShape::value_type ) * Rank ); + std::memcpy( strides_, other.strides_, sizeof( ArrayStrides::value_type ) * Rank ); size_ = other.size_; // TODO: check compatibility } @@ -51,8 +53,7 @@ ArrayView::ArrayView( data_view_t data_view, const Arra data_store_orig_( array.data_store() ), array_( &array ) { if ( data_view.valid() ) { - using seq = - ::gridtools::apply_gt_integer_sequence::type>; + using seq = ::gridtools::apply_gt_integer_sequence<::gridtools::make_gt_integer_sequence>; constexpr static unsigned int ndims = data_view_t::data_store_t::storage_info_t::ndims; @@ -62,16 +63,19 @@ ArrayView::ArrayView( data_view_t data_view, const Arra auto storage_info_ = *( ( reinterpret_cast( const_cast( array.storage() ) ) )->get_storage_info_ptr() ); - auto stridest = seq::template apply, - atlas::array::gridtools::get_stride_component< - unsigned long, ::gridtools::static_uint>::template get_component>( + auto stridest = seq::template apply< + host_device_array, + atlas::array::gridtools::get_stride_component::template get_component>( + &( storage_info_ ) ); + auto shapet = seq::template apply< + host_device_array, + atlas::array::gridtools::get_shape_component::template get_component>( &( storage_info_ ) ); - auto shapet = - seq::template apply, atlas::array::gridtools::get_shape_component>( - &( storage_info_ ) ); - std::memcpy( strides_, stridest.data(), sizeof( size_t ) * Rank ); - std::memcpy( shape_, shapet.data(), sizeof( size_t ) * Rank ); + for ( int i = 0; i < Rank; ++i ) { + strides_[i] = stridest[i]; + shape_[i] = shapet[i]; + } size_ = storage_info_.total_length(); } @@ -95,7 +99,7 @@ void ArrayView::assign( const value_type& value ) { template void ArrayView::assign( const std::initializer_list& list ) { - ASSERT( list.size() == size_ ); + ATLAS_ASSERT( list.size() == size_ ); helpers::array_assigner::apply( *this, list ); } @@ -140,5 +144,5 @@ EXPLICIT_TEMPLATE_INSTANTIATION( 8 ) EXPLICIT_TEMPLATE_INSTANTIATION( 9 ) #undef EXPLICIT_TEMPLATE_INSTANTIATION -} +} // namespace array } // namespace atlas diff --git a/src/atlas/array/gridtools/GridToolsArrayView.cu b/src/atlas/array/gridtools/GridToolsArrayView.cu index 5441c6fe2..fe607a93b 100644 --- a/src/atlas/array/gridtools/GridToolsArrayView.cu +++ b/src/atlas/array/gridtools/GridToolsArrayView.cu @@ -1 +1,11 @@ +/* + * (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 "GridToolsArrayView.cc" diff --git a/src/atlas/array/gridtools/GridToolsArrayView.h b/src/atlas/array/gridtools/GridToolsArrayView.h index 22508d9de..65f38d73c 100644 --- a/src/atlas/array/gridtools/GridToolsArrayView.h +++ b/src/atlas/array/gridtools/GridToolsArrayView.h @@ -72,8 +72,20 @@ class ArrayView { return gt_data_view_( c... ); } + template + ATLAS_HOST_DEVICE typename std::enable_if<( Rank == 1 && EnableBool ), const value_type&>::type operator[]( + Int idx ) const { + return gt_data_view_( idx ); + } + + template + ATLAS_HOST_DEVICE typename std::enable_if<( Rank == 1 && EnableBool ), value_type&>::type operator[]( Int idx ) { + check_bounds( idx ); + return gt_data_view_( idx ); + } + template - ATLAS_HOST_DEVICE size_t shape() const { + ATLAS_HOST_DEVICE idx_t shape() const { return gt_data_view_.template length(); } @@ -83,12 +95,12 @@ class ArrayView { data_view_t const& data_view() const { return gt_data_view_; } template - ATLAS_HOST_DEVICE size_t stride() const { + ATLAS_HOST_DEVICE idx_t stride() const { return gt_data_view_.storage_info().template stride(); } - static constexpr size_t rank() { return Rank; } - size_t size() const { return size_; } + static constexpr idx_t rank() { return Rank; } + idx_t size() const { return size_; } bool valid() const; bool contiguous() const { return ( size_ == shape_[0] * strides_[0] ? true : false ); } @@ -99,13 +111,19 @@ class ArrayView { void assign( const std::initializer_list& ); - const size_t* strides() const { return strides_; } + const idx_t* strides() const { return strides_; } - const size_t* shape() const { return shape_; } + const idx_t* shape() const { return shape_; } - size_t shape( size_t idx ) const { return shape_[idx]; } + template + idx_t shape( Int idx ) const { + return shape_[idx]; + } - size_t stride( size_t idx ) const { return strides_[idx]; } + template + idx_t stride( Int idx ) const { + return strides_[idx]; + } template typename slice_t::type slice( Args... args ) { @@ -119,9 +137,9 @@ class ArrayView { private: data_view_t gt_data_view_; - size_t shape_[Rank]; - size_t strides_[Rank]; - size_t size_; + idx_t shape_[Rank]; + idx_t strides_[Rank]; + idx_t size_; ArrayDataStore const* data_store_orig_; Array const* array_; }; diff --git a/src/atlas/array/gridtools/GridToolsIndexView.cc b/src/atlas/array/gridtools/GridToolsIndexView.cc index 921989ba8..1406cf9c2 100644 --- a/src/atlas/array/gridtools/GridToolsIndexView.cc +++ b/src/atlas/array/gridtools/GridToolsIndexView.cc @@ -40,5 +40,6 @@ namespace atlas { namespace array { template class IndexView; -} +template class IndexView; +} // namespace array } // namespace atlas diff --git a/src/atlas/array/gridtools/GridToolsIndexView.cu b/src/atlas/array/gridtools/GridToolsIndexView.cu index 5abeea37d..a4a8427b2 100644 --- a/src/atlas/array/gridtools/GridToolsIndexView.cu +++ b/src/atlas/array/gridtools/GridToolsIndexView.cu @@ -1 +1,11 @@ +/* + * (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 "GridToolsIndexView.cc" diff --git a/src/atlas/array/gridtools/GridToolsIndexView.h b/src/atlas/array/gridtools/GridToolsIndexView.h index 5c198355a..d3b398eff 100644 --- a/src/atlas/array/gridtools/GridToolsIndexView.h +++ b/src/atlas/array/gridtools/GridToolsIndexView.h @@ -115,13 +115,13 @@ class IndexView { return gt_data_view_( c... ) FROM_FORTRAN; } - size_t size() const { return size_; } + idx_t size() const { return size_; } void dump( std::ostream& os ) const; private: data_view_t gt_data_view_; - size_t size_; + idx_t size_; #undef INDEX_REF #undef TO_FORTRAN diff --git a/src/atlas/array/gridtools/GridToolsMakeView.cc b/src/atlas/array/gridtools/GridToolsMakeView.cc index c875af7cf..3e9a6fe48 100644 --- a/src/atlas/array/gridtools/GridToolsMakeView.cc +++ b/src/atlas/array/gridtools/GridToolsMakeView.cc @@ -1,9 +1,22 @@ +/* + * (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/array/gridtools/GridToolsMakeView.h" + +#include #include + #include "atlas/array.h" #include "atlas/array/ArrayView.h" #include "atlas/array/IndexView.h" +#include "atlas/runtime/Exception.h" #include "atlas/library/config.h" #if ATLAS_HAVE_GRIDTOOLS_STORAGE @@ -20,12 +33,12 @@ static void check_metadata( const Array& array ) { if ( array.rank() != Rank ) { std::stringstream err; err << "Number of dimensions do not match: template argument " << Rank << " expected to be " << array.rank(); - throw eckit::BadParameter( err.str(), Here() ); + throw_Exception( err.str(), Here() ); } if ( array.datatype() != array::DataType::create() ) { std::stringstream err; err << "Data Type does not match: template argument expected to be " << array.datatype().str(); - throw eckit::BadParameter( err.str(), Here() ); + throw_Exception( err.str(), Here() ); } } } // namespace @@ -151,6 +164,12 @@ namespace array { template IndexView make_host_indexview( const Array& ); \ template IndexView make_host_indexview( const Array& ); \ \ + template IndexView make_indexview( const Array& ); \ + template IndexView make_indexview( const Array& ); \ + \ + template IndexView make_host_indexview( const Array& ); \ + template IndexView make_host_indexview( const Array& ); \ + \ namespace gridtools { \ template data_view_tt \ make_gt_host_view( const Array& array ); \ @@ -207,5 +226,5 @@ EXPLICIT_TEMPLATE_INSTANTIATION( 8 ) EXPLICIT_TEMPLATE_INSTANTIATION( 9 ) #undef EXPLICIT_TEMPLATE_INSTANTIATION -} +} // namespace array } // namespace atlas diff --git a/src/atlas/array/gridtools/GridToolsTraits.h b/src/atlas/array/gridtools/GridToolsTraits.h index 2be09472c..28caa0065 100644 --- a/src/atlas/array/gridtools/GridToolsTraits.h +++ b/src/atlas/array/gridtools/GridToolsTraits.h @@ -1,3 +1,13 @@ +/* + * (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 "gridtools/common/generic_metafunctions/accumulate.hpp" @@ -16,9 +26,9 @@ namespace gridtools { //------------------------------------------------------------------------------ #if ATLAS_GRIDTOOLS_STORAGE_BACKEND_CUDA -using storage_traits = ::gridtools::storage_traits<::gridtools::enumtype::Cuda>; +using storage_traits = ::gridtools::storage_traits<::gridtools::target::cuda>; #elif ATLAS_GRIDTOOLS_STORAGE_BACKEND_HOST -using storage_traits = ::gridtools::storage_traits<::gridtools::enumtype::Host>; +using storage_traits = ::gridtools::storage_traits<::gridtools::target::x86>; #else #error ATLAS_GRIDTOOLS_STORAGE_BACKEND_ not set #endif diff --git a/src/atlas/array/helpers/ArrayAssigner.h b/src/atlas/array/helpers/ArrayAssigner.h index 9bbda4552..dbefbfb58 100644 --- a/src/atlas/array/helpers/ArrayAssigner.h +++ b/src/atlas/array/helpers/ArrayAssigner.h @@ -11,6 +11,7 @@ #pragma once #include "atlas/array.h" +#include "atlas/runtime/Exception.h" //------------------------------------------------------------------------------ @@ -31,14 +32,14 @@ template struct array_assigner_impl { template static void apply( View& arr, Value value, DimIndex... idxs ) { - for ( size_t i = 0; i < arr.shape( Dim ); ++i ) { + for ( idx_t i = 0; i < arr.shape( Dim ); ++i ) { array_assigner_impl::apply( arr, value, idxs..., i ); } } template static void apply( View& arr, Iterator& it, DimIndex... idxs ) { - for ( size_t i = 0; i < arr.shape( Dim ); ++i ) { + for ( idx_t i = 0; i < arr.shape( Dim ); ++i ) { array_assigner_impl::apply( arr, it, idxs..., i ); } } @@ -69,13 +70,13 @@ struct array_assigner { } static void apply( ArrayView&, Value ) { - throw eckit::AssertionFailed( "Cannot assign ReadOnly array", Here() ); + throw_Exception( "Cannot assign ReadOnly array", Here() ); // TODO use SFINAE to disallow at compile time } template static void apply( ArrayView&, const Iterable& ) { - throw eckit::AssertionFailed( "Cannot assign ReadOnly array", Here() ); + throw_Exception( "Cannot assign ReadOnly array", Here() ); // TODO use SFINAE to disallow at compile time } @@ -88,11 +89,11 @@ struct array_assigner { static void apply( ArrayView& arr, const Iterable& iterable ) { typename Iterable::const_iterator it = iterable.begin(); array_assigner_impl::apply( arr, it ); - ASSERT( it = iterable.end() ); + ATLAS_ASSERT( it = iterable.end() ); } - static void apply( LocalView&, Value value ) { - throw eckit::AssertionFailed( "Cannot assign ReadOnly array", Here() ); + static void apply( LocalView&, Value ) { + throw_Exception( "Cannot assign ReadOnly array", Here() ); // TODO use SFINAE to disallow at compile time } diff --git a/src/atlas/array/helpers/ArrayInitializer.h b/src/atlas/array/helpers/ArrayInitializer.h index ab909d060..f99596471 100644 --- a/src/atlas/array/helpers/ArrayInitializer.h +++ b/src/atlas/array/helpers/ArrayInitializer.h @@ -10,13 +10,14 @@ #pragma once +#include +#include #include -#include "eckit/exception/Exceptions.h" - #include "atlas/array.h" #include "atlas/array/DataType.h" #include "atlas/array_fwd.h" +#include "atlas/runtime/Exception.h" //------------------------------------------------------------------------------ @@ -26,15 +27,15 @@ namespace helpers { //------------------------------------------------------------------------------ -template +template struct array_initializer; -template +template struct array_initializer_partitioned; //------------------------------------------------------------------------------ -template +template struct array_initializer_impl { static void apply( Array const& orig, Array& array_resized ) { array_initializer_impl::apply( make_view( orig ), @@ -43,7 +44,8 @@ struct array_initializer_impl { template static void apply( ArrayView const&& orig, ArrayView&& array_resized, DimIndex... idxs ) { - for ( size_t i = 0; i < orig.shape( Dim ); ++i ) { + const idx_t N = std::min( array_resized.shape( Dim ), orig.shape( Dim ) ); + for ( idx_t i = 0; i < N; ++i ) { array_initializer_impl::apply( std::move( orig ), std::move( array_resized ), idxs..., i ); } @@ -52,7 +54,7 @@ struct array_initializer_impl { //------------------------------------------------------------------------------ -template +template struct array_initializer_impl { template static void apply( ArrayView const&& orig, ArrayView&& array_resized, DimIndex... idxs ) { @@ -62,7 +64,7 @@ struct array_initializer_impl { //------------------------------------------------------------------------------ -template +template struct array_initializer { static void apply( Array const& orig, Array& array_resized ) { switch ( orig.datatype().kind() ) { @@ -79,7 +81,7 @@ struct array_initializer { default: { std::stringstream err; err << "data kind " << orig.datatype().kind() << " not recognised."; - throw eckit::BadParameter( err.str(), Here() ); + throw_NotImplemented( err.str(), Here() ); } } } @@ -87,20 +89,20 @@ struct array_initializer { //------------------------------------------------------------------------------ -template +template struct array_initializer_partitioned_val_impl { - static void apply( Array const& orig, Array& dest, unsigned int pos, unsigned int offset ) { + static void apply( Array const& orig, Array& dest, idx_t pos, idx_t offset ) { array_initializer_partitioned_val_impl::apply( make_view( orig ), make_view( dest ), pos, offset ); } template - static void apply( ArrayView const&& orig, ArrayView&& dest, unsigned int pos, - unsigned int offset, DimIndexPair... idxs ) { - for ( size_t i = 0; i < orig.shape( Dim ); ++i ) { - unsigned int displ = i; + static void apply( ArrayView const&& orig, ArrayView&& dest, idx_t pos, idx_t offset, + DimIndexPair... idxs ) { + for ( idx_t i = 0; i < orig.shape( Dim ); ++i ) { + idx_t displ = i; if ( Dim == PartDim && i >= pos ) { displ += offset; } - std::pair pair_idx{i, displ}; + std::pair pair_idx{i, displ}; array_initializer_partitioned_val_impl::apply( std::move( orig ), std::move( dest ), pos, offset, idxs..., pair_idx ); } @@ -122,11 +124,11 @@ struct array_initializer_partitioned_val_impl { //------------------------------------------------------------------------------ -template +template struct array_initializer_partitioned_val_impl { template - static void apply( ArrayView const&& orig, ArrayView&& dest, unsigned int pos, - unsigned int offset, DimIndexPair... idxs ) { + static void apply( ArrayView const&& orig, ArrayView&& dest, idx_t /*pos*/, + idx_t /*offset*/, DimIndexPair... idxs ) { // Log::info() << print_array(std::array{std::get<0>(idxs)...}) << // " --> " << print_array(std::array{std::get<1>(idxs)...}) << " // " << orig(std::get<0>(idxs)...) << std::endl; @@ -136,9 +138,9 @@ struct array_initializer_partitioned_val_impl { //------------------------------------------------------------------------------ -template +template struct array_initializer_partitioned_impl { - static void apply( Array const& orig, Array& dest, unsigned int pos, unsigned int offset ) { + static void apply( Array const& orig, Array& dest, idx_t pos, idx_t offset ) { switch ( orig.datatype().kind() ) { case DataType::KIND_REAL64: return array_initializer_partitioned_val_impl::apply( orig, dest, pos, @@ -156,7 +158,7 @@ struct array_initializer_partitioned_impl { default: { std::stringstream err; err << "data kind " << orig.datatype().kind() << " not recognised."; - throw eckit::BadParameter( err.str(), Here() ); + throw_NotImplemented( err.str(), Here() ); } } } @@ -164,9 +166,9 @@ struct array_initializer_partitioned_impl { //------------------------------------------------------------------------------ -template +template struct array_initializer_partitioned { - static void apply( Array const& orig, Array& dest, unsigned int pos, unsigned int offset ) { + static void apply( Array const& orig, Array& dest, idx_t pos, idx_t offset ) { switch ( orig.rank() ) { case 1: return array_initializer_partitioned_impl<1, PartDim>::apply( orig, dest, pos, offset ); @@ -189,7 +191,7 @@ struct array_initializer_partitioned { default: { std::stringstream err; err << "too high Rank"; - throw eckit::BadParameter( err.str(), Here() ); + throw_NotImplemented( err.str(), Here() ); } } } diff --git a/src/atlas/array/helpers/ArraySlicer.h b/src/atlas/array/helpers/ArraySlicer.h index b87c464bf..ad6c40b3d 100644 --- a/src/atlas/array/helpers/ArraySlicer.h +++ b/src/atlas/array/helpers/ArraySlicer.h @@ -10,9 +10,11 @@ #pragma once +#include + #include "atlas/array/ArrayViewDefs.h" #include "atlas/array/Range.h" -#include "atlas/runtime/Log.h" +#include "atlas/library/config.h" namespace atlas { namespace array { @@ -131,13 +133,16 @@ class ArraySlicer { template typename Slice::type apply( const Args... args ) const { using slicer_t = Slicer::type, ( SliceRank::value == 0 )>; + static_assert( + View::RANK <= sizeof...( Args ), + "Not enough arguments passed to slice() function. Pehaps you forgot to add a array::Range::all()" ); return slicer_t::apply( view_, args... ); } private: template struct array { - using type = typename std::array::value>; + using type = typename std::array::value>; }; template @@ -248,7 +253,6 @@ class ArraySlicer { int i_slice( 0 ); int i_view( 0 ); shape_part<0>( view, result, i_view, i_slice, args... ); - ASSERT( i_view == view.rank() ); return result; } @@ -282,7 +286,7 @@ class ArraySlicer { ++i_view; } template - static void update_strides( View& view, Strides& strides, int& /*i_view*/, int& i_slice, + static void update_strides( View& /*view*/, Strides& strides, int& /*i_view*/, int& i_slice, const RangeDummy& /*range*/ ) { strides[i_slice] = 0; ++i_slice; @@ -306,7 +310,6 @@ class ArraySlicer { int i_slice( 0 ); int i_view( 0 ); strides_part<0>( view, result, i_view, i_slice, args... ); - ASSERT( i_view == view.rank() ); return result; } diff --git a/src/atlas/array/helpers/ArrayWriter.h b/src/atlas/array/helpers/ArrayWriter.h index bd6356ae2..97d4aa173 100644 --- a/src/atlas/array/helpers/ArrayWriter.h +++ b/src/atlas/array/helpers/ArrayWriter.h @@ -31,7 +31,7 @@ template struct array_writer_impl { template static void apply( View& arr, std::ostream& out, DimIndex... idxs ) { - for ( size_t i = 0; i < arr.shape( Dim ); ++i ) { + for ( idx_t i = 0; i < arr.shape( Dim ); ++i ) { array_writer_impl::apply( arr, out, idxs..., i ); if ( i < arr.shape( Dim ) - 1 ) out << " "; } diff --git a/src/atlas/array/native/NativeArray.cc b/src/atlas/array/native/NativeArray.cc index ef87cad2f..242f0d67f 100644 --- a/src/atlas/array/native/NativeArray.cc +++ b/src/atlas/array/native/NativeArray.cc @@ -1,3 +1,13 @@ +/* + * (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 "atlas/array.h" @@ -6,6 +16,7 @@ #include "atlas/array/helpers/ArrayInitializer.h" #include "atlas/array/helpers/ArrayWriter.h" #include "atlas/array/native/NativeDataStore.h" +#include "atlas/runtime/Exception.h" using namespace atlas::array::helpers; @@ -13,23 +24,23 @@ namespace atlas { namespace array { template -Array* Array::create( size_t dim0 ) { +Array* Array::create( idx_t dim0 ) { return new ArrayT( dim0 ); } template -Array* Array::create( size_t dim0, size_t dim1 ) { +Array* Array::create( idx_t dim0, idx_t dim1 ) { return new ArrayT( dim0, dim1 ); } template -Array* Array::create( size_t dim0, size_t dim1, size_t dim2 ) { +Array* Array::create( idx_t dim0, idx_t dim1, idx_t dim2 ) { return new ArrayT( dim0, dim1, dim2 ); } template -Array* Array::create( size_t dim0, size_t dim1, size_t dim2, size_t dim3 ) { +Array* Array::create( idx_t dim0, idx_t dim1, idx_t dim2, idx_t dim3 ) { return new ArrayT( dim0, dim1, dim2, dim3 ); } template -Array* Array::create( size_t dim0, size_t dim1, size_t dim2, size_t dim3, size_t dim4 ) { +Array* Array::create( idx_t dim0, idx_t dim1, idx_t dim2, idx_t dim3, idx_t dim4 ) { return new ArrayT( dim0, dim1, dim2, dim3, dim4 ); } template @@ -66,7 +77,7 @@ Array* Array::create( DataType datatype, const ArrayShape& shape ) { default: { std::stringstream err; err << "data kind " << datatype.kind() << " not recognised."; - throw eckit::BadParameter( err.str(), Here() ); + throw_NotImplemented( err.str(), Here() ); } } } @@ -78,35 +89,35 @@ ArrayT::ArrayT( ArrayDataStore* ds, const ArraySpec& spec ) { } template -ArrayT::ArrayT( size_t dim0 ) { +ArrayT::ArrayT( idx_t dim0 ) { spec_ = ArraySpec( make_shape( dim0 ) ); data_store_ = std::unique_ptr( new native::DataStore( spec_.size() ) ); } template -ArrayT::ArrayT( size_t dim0, size_t dim1 ) { +ArrayT::ArrayT( idx_t dim0, idx_t dim1 ) { spec_ = ArraySpec( make_shape( dim0, dim1 ) ); data_store_ = std::unique_ptr( new native::DataStore( spec_.size() ) ); } template -ArrayT::ArrayT( size_t dim0, size_t dim1, size_t dim2 ) { +ArrayT::ArrayT( idx_t dim0, idx_t dim1, idx_t dim2 ) { spec_ = ArraySpec( make_shape( dim0, dim1, dim2 ) ); data_store_ = std::unique_ptr( new native::DataStore( spec_.size() ) ); } template -ArrayT::ArrayT( size_t dim0, size_t dim1, size_t dim2, size_t dim3 ) { +ArrayT::ArrayT( idx_t dim0, idx_t dim1, idx_t dim2, idx_t dim3 ) { spec_ = ArraySpec( make_shape( dim0, dim1, dim2, dim3 ) ); data_store_ = std::unique_ptr( new native::DataStore( spec_.size() ) ); } template -ArrayT::ArrayT( size_t dim0, size_t dim1, size_t dim2, size_t dim3, size_t dim4 ) { +ArrayT::ArrayT( idx_t dim0, idx_t dim1, idx_t dim2, idx_t dim3, idx_t dim4 ) { spec_ = ArraySpec( make_shape( dim0, dim1, dim2, dim3, dim4 ) ); data_store_ = std::unique_ptr( new native::DataStore( spec_.size() ) ); } template ArrayT::ArrayT( const ArrayShape& shape ) { - ASSERT( shape.size() > 0 ); - size_t size = 1; + ATLAS_ASSERT( shape.size() > 0 ); + idx_t size = 1; for ( size_t j = 0; j < shape.size(); ++j ) size *= shape[j]; data_store_ = std::unique_ptr( new native::DataStore( size ) ); @@ -118,30 +129,22 @@ ArrayT::ArrayT( const ArrayShape& shape, const ArrayLayout& layout ) { spec_ = ArraySpec( shape ); data_store_ = std::unique_ptr( new native::DataStore( spec_.size() ) ); for ( size_t j = 0; j < layout.size(); ++j ) - ASSERT( spec_.layout()[j] == layout[j] ); + ATLAS_ASSERT( spec_.layout()[j] == layout[j] ); } template ArrayT::ArrayT( const ArraySpec& spec ) { - if ( not spec.contiguous() ) NOTIMP; + if ( not spec.contiguous() ) ATLAS_NOTIMPLEMENTED; spec_ = spec; data_store_ = std::unique_ptr( new native::DataStore( spec_.size() ) ); } template void ArrayT::resize( const ArrayShape& _shape ) { - if ( rank() != _shape.size() ) { + if ( rank() != static_cast( _shape.size() ) ) { std::stringstream msg; msg << "Cannot resize existing Array with rank " << rank() << " with a shape of rank " << _shape.size(); - throw eckit::BadParameter( msg.str(), Here() ); - } - for ( size_t j = 0; j < rank(); ++j ) { - if ( _shape[j] < shape( j ) ) { - std::stringstream msg; - msg << "Cannot resize existing array by shrinking dimension " << j << " from " << shape( j ) << " to " - << _shape[j]; - throw eckit::BadParameter( msg.str(), Here() ); - } + throw_Exception( msg.str(), Here() ); } Array* resized = Array::create( _shape ); @@ -175,7 +178,7 @@ void ArrayT::resize( const ArrayShape& _shape ) { array_initializer<9>::apply( *this, *resized ); break; default: - NOTIMP; + ATLAS_NOTIMPLEMENTED; } replace( *resized ); @@ -183,11 +186,9 @@ void ArrayT::resize( const ArrayShape& _shape ) { } template -void ArrayT::insert( size_t idx1, size_t size1 ) { +void ArrayT::insert( idx_t idx1, idx_t size1 ) { ArrayShape nshape = shape(); - if ( idx1 > nshape[0] ) { - throw eckit::BadParameter( "Cannot insert into an array at a position beyond its size", Here() ); - } + if ( idx1 > nshape[0] ) { throw_Exception( "Cannot insert into an array at a position beyond its size", Here() ); } nshape[0] += size1; Array* resized = Array::create( nshape ); @@ -198,27 +199,27 @@ void ArrayT::insert( size_t idx1, size_t size1 ) { } template -void ArrayT::resize( size_t size1 ) { +void ArrayT::resize( idx_t size1 ) { resize( make_shape( size1 ) ); } template -void ArrayT::resize( size_t size1, size_t size2 ) { +void ArrayT::resize( idx_t size1, idx_t size2 ) { resize( make_shape( size1, size2 ) ); } template -void ArrayT::resize( size_t size1, size_t size2, size_t size3 ) { +void ArrayT::resize( idx_t size1, idx_t size2, idx_t size3 ) { resize( make_shape( size1, size2, size3 ) ); } template -void ArrayT::resize( size_t size1, size_t size2, size_t size3, size_t size4 ) { +void ArrayT::resize( idx_t size1, idx_t size2, idx_t size3, idx_t size4 ) { resize( make_shape( size1, size2, size3, size4 ) ); } template -void ArrayT::resize( size_t size1, size_t size2, size_t size3, size_t size4, size_t size5 ) { +void ArrayT::resize( idx_t size1, idx_t size2, idx_t size3, idx_t size4, idx_t size5 ) { resize( make_shape( size1, size2, size3, size4, size5 ) ); } @@ -253,7 +254,7 @@ void ArrayT::dump( std::ostream& out ) const { make_host_view( *this ).dump( out ); break; default: - NOTIMP; + ATLAS_NOTIMPLEMENTED; } } @@ -263,7 +264,7 @@ template size_t ArrayT::footprint() const { size_t size = sizeof( *this ); size += bytes(); - if ( not contiguous() ) NOTIMP; + if ( not contiguous() ) ATLAS_NOTIMPLEMENTED; return size; } @@ -274,35 +275,35 @@ bool ArrayT::accMap() const { //------------------------------------------------------------------------------ -template Array* Array::create( size_t ); -template Array* Array::create( size_t ); -template Array* Array::create( size_t ); -template Array* Array::create( size_t ); -template Array* Array::create( size_t ); - -template Array* Array::create( size_t, size_t ); -template Array* Array::create( size_t, size_t ); -template Array* Array::create( size_t, size_t ); -template Array* Array::create( size_t, size_t ); -template Array* Array::create( size_t, size_t ); - -template Array* Array::create( size_t, size_t, size_t ); -template Array* Array::create( size_t, size_t, size_t ); -template Array* Array::create( size_t, size_t, size_t ); -template Array* Array::create( size_t, size_t, size_t ); -template Array* Array::create( size_t, size_t, size_t ); - -template Array* Array::create( size_t, size_t, size_t, size_t ); -template Array* Array::create( size_t, size_t, size_t, size_t ); -template Array* Array::create( size_t, size_t, size_t, size_t ); -template Array* Array::create( size_t, size_t, size_t, size_t ); -template Array* Array::create( size_t, size_t, size_t, size_t ); - -template Array* Array::create( size_t, size_t, size_t, size_t, size_t ); -template Array* Array::create( size_t, size_t, size_t, size_t, size_t ); -template Array* Array::create( size_t, size_t, size_t, size_t, size_t ); -template Array* Array::create( size_t, size_t, size_t, size_t, size_t ); -template Array* Array::create( size_t, size_t, size_t, size_t, size_t ); +template Array* Array::create( idx_t ); +template Array* Array::create( idx_t ); +template Array* Array::create( idx_t ); +template Array* Array::create( idx_t ); +template Array* Array::create( idx_t ); + +template Array* Array::create( idx_t, idx_t ); +template Array* Array::create( idx_t, idx_t ); +template Array* Array::create( idx_t, idx_t ); +template Array* Array::create( idx_t, idx_t ); +template Array* Array::create( idx_t, idx_t ); + +template Array* Array::create( idx_t, idx_t, idx_t ); +template Array* Array::create( idx_t, idx_t, idx_t ); +template Array* Array::create( idx_t, idx_t, idx_t ); +template Array* Array::create( idx_t, idx_t, idx_t ); +template Array* Array::create( idx_t, idx_t, idx_t ); + +template Array* Array::create( idx_t, idx_t, idx_t, idx_t ); +template Array* Array::create( idx_t, idx_t, idx_t, idx_t ); +template Array* Array::create( idx_t, idx_t, idx_t, idx_t ); +template Array* Array::create( idx_t, idx_t, idx_t, idx_t ); +template Array* Array::create( idx_t, idx_t, idx_t, idx_t ); + +template Array* Array::create( idx_t, idx_t, idx_t, idx_t, idx_t ); +template Array* Array::create( idx_t, idx_t, idx_t, idx_t, idx_t ); +template Array* Array::create( idx_t, idx_t, idx_t, idx_t, idx_t ); +template Array* Array::create( idx_t, idx_t, idx_t, idx_t, idx_t ); +template Array* Array::create( idx_t, idx_t, idx_t, idx_t, idx_t ); template Array* Array::create( const ArrayShape& ); template Array* Array::create( const ArrayShape& ); diff --git a/src/atlas/array/native/NativeArrayView.cc b/src/atlas/array/native/NativeArrayView.cc index a9ca0b695..44e5ac339 100644 --- a/src/atlas/array/native/NativeArrayView.cc +++ b/src/atlas/array/native/NativeArrayView.cc @@ -8,9 +8,8 @@ * nor does it submit to any jurisdiction. */ -#include - -#include "eckit/exception/Exceptions.h" +#include +#include #include "atlas/array/ArrayView.h" #include "atlas/array/helpers/ArrayAssigner.h" @@ -78,5 +77,5 @@ EXPLICIT_TEMPLATE_INSTANTIATION( 8 ) EXPLICIT_TEMPLATE_INSTANTIATION( 9 ) #undef EXPLICIT_TEMPLATE_INSTANTIATION -} +} // namespace array } // namespace atlas diff --git a/src/atlas/array/native/NativeArrayView.h b/src/atlas/array/native/NativeArrayView.h index a5edb9ba4..5b0b7acdd 100644 --- a/src/atlas/array/native/NativeArrayView.h +++ b/src/atlas/array/native/NativeArrayView.h @@ -24,8 +24,8 @@ /// int[2] strides = { 3, 1 }; /// int[2] shape = { 3, 3 }; /// ArrayView matrix( array, shape, strides ); -/// for( size_t i=0; i #include #include +#include #include #include "atlas/array/ArrayUtil.h" @@ -125,27 +126,45 @@ class ArrayView { return data_[index( idx... )]; } + template + typename std::enable_if<( Rank == 1 && EnableBool ), const value_type&>::type operator[]( Int idx ) const { + check_bounds( idx ); + return data_[idx]; + } + + template + typename std::enable_if<( Rank == 1 && EnableBool ), value_type&>::type operator[]( Int idx ) { + check_bounds( idx ); + return data_[idx]; + } + template - size_t shape() const { + idx_t shape() const { return shape( Dim ); } template - size_t stride() const { + idx_t stride() const { return stride( Dim ); } - size_t size() const { return size_; } + idx_t size() const { return size_; } - static constexpr size_t rank() { return Rank; } + static constexpr idx_t rank() { return Rank; } - const size_t* strides() const { return strides_.data(); } + const idx_t* strides() const { return strides_.data(); } - const size_t* shape() const { return shape_.data(); } + const idx_t* shape() const { return shape_.data(); } - size_t shape( size_t idx ) const { return shape_[idx]; } + template + idx_t shape( Int idx ) const { + return shape_[idx]; + } - size_t stride( size_t idx ) const { return strides_[idx]; } + template + idx_t stride( Int idx ) const { + return strides_[idx]; + } value_type const* data() const { return data_; } @@ -175,17 +194,17 @@ class ArrayView { // -- Private methods template - constexpr int index_part( Int idx, Ints... next_idx ) const { + constexpr idx_t index_part( Int idx, Ints... next_idx ) const { return idx * strides_[Dim] + index_part( next_idx... ); } template - constexpr int index_part( Int last_idx ) const { + constexpr idx_t index_part( Int last_idx ) const { return last_idx * strides_[Dim]; } template - constexpr int index( Ints... idx ) const { + constexpr idx_t index( Ints... idx ) const { return index_part<0>( idx... ); } @@ -197,7 +216,9 @@ class ArrayView { } #else template - void check_bounds( Ints... ) const {} + void check_bounds( Ints... idx ) const { + static_assert( sizeof...( idx ) == Rank, "Expected number of indices is different from rank of array" ); + } #endif template @@ -208,13 +229,13 @@ class ArrayView { template void check_bounds_part( Int idx, Ints... next_idx ) const { - if ( size_t( idx ) >= shape_[Dim] ) { throw_OutOfRange( "ArrayView", array_dim(), idx, shape_[Dim] ); } + if ( idx_t( idx ) >= shape_[Dim] ) { throw_OutOfRange( "ArrayView", array_dim(), idx, shape_[Dim] ); } check_bounds_part( next_idx... ); } template void check_bounds_part( Int last_idx ) const { - if ( size_t( last_idx ) >= shape_[Dim] ) { + if ( idx_t( last_idx ) >= shape_[Dim] ) { throw_OutOfRange( "ArrayView", array_dim(), last_idx, shape_[Dim] ); } } @@ -222,9 +243,9 @@ class ArrayView { // -- Private data value_type* data_; - size_t size_; - std::array shape_; - std::array strides_; + idx_t size_; + std::array shape_; + std::array strides_; }; //------------------------------------------------------------------------------------------------------ diff --git a/src/atlas/array/native/NativeIndexView.cc b/src/atlas/array/native/NativeIndexView.cc index 9fc7457da..2aac81e51 100644 --- a/src/atlas/array/native/NativeIndexView.cc +++ b/src/atlas/array/native/NativeIndexView.cc @@ -20,7 +20,7 @@ namespace array { //------------------------------------------------------------------------------------------------------ template -IndexView::IndexView( Value* data, const size_t shape[1] ) : data_( const_cast( data ) ) { +IndexView::IndexView( Value* data, const idx_t shape[1] ) : data_( const_cast( data ) ) { strides_[0] = 1; shape_[0] = shape[0]; } @@ -29,7 +29,7 @@ template void IndexView::dump( std::ostream& os ) const { os << "size: " << size() << " , values: "; os << "[ "; - for ( size_t j = 0; j < size(); ++j ) + for ( idx_t j = 0; j < size(); ++j ) os << ( *this )( j ) << " "; os << "]" << std::endl; } @@ -39,6 +39,8 @@ void IndexView::dump( std::ostream& os ) const { template class IndexView; template class IndexView; +template class IndexView; +template class IndexView; //------------------------------------------------------------------------------------------------------ diff --git a/src/atlas/array/native/NativeIndexView.h b/src/atlas/array/native/NativeIndexView.h index c170219b1..7036dbee5 100644 --- a/src/atlas/array/native/NativeIndexView.h +++ b/src/atlas/array/native/NativeIndexView.h @@ -120,7 +120,7 @@ class IndexView { #endif public: - IndexView( Value* data, const size_t shape[Rank] ); + IndexView( Value* data, const idx_t shape[Rank] ); // -- Access methods @@ -139,17 +139,17 @@ class IndexView { // -- Private methods template - constexpr int index_part( Int idx, Ints... next_idx ) const { + constexpr idx_t index_part( Int idx, Ints... next_idx ) const { return idx * strides_[Dim] + index_part( next_idx... ); } template - constexpr int index_part( Int last_idx ) const { + constexpr idx_t index_part( Int last_idx ) const { return last_idx * strides_[Dim]; } template - constexpr int index( Ints... idx ) const { + constexpr idx_t index( Ints... idx ) const { return index_part<0>( idx... ); } @@ -172,25 +172,25 @@ class IndexView { template void check_bounds_part( Int idx, Ints... next_idx ) const { - if ( size_t( idx ) >= shape_[Dim] ) { throw_OutOfRange( "IndexView", array_dim(), idx, shape_[Dim] ); } + if ( idx_t( idx ) >= shape_[Dim] ) { throw_OutOfRange( "IndexView", array_dim(), idx, shape_[Dim] ); } check_bounds_part( next_idx... ); } template void check_bounds_part( Int last_idx ) const { - if ( size_t( last_idx ) >= shape_[Dim] ) { + if ( idx_t( last_idx ) >= shape_[Dim] ) { throw_OutOfRange( "IndexView", array_dim(), last_idx, shape_[Dim] ); } } - size_t size() const { return shape_[0]; } + idx_t size() const { return shape_[0]; } void dump( std::ostream& os ) const; private: Value* data_; - size_t strides_[Rank]; - size_t shape_[Rank]; + idx_t strides_[Rank]; + idx_t shape_[Rank]; }; //------------------------------------------------------------------------------------------------------ diff --git a/src/atlas/array/native/NativeMakeView.cc b/src/atlas/array/native/NativeMakeView.cc index a39e238e4..de5582e8c 100644 --- a/src/atlas/array/native/NativeMakeView.cc +++ b/src/atlas/array/native/NativeMakeView.cc @@ -1,8 +1,20 @@ +/* + * (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 "atlas/array.h" #include "atlas/array/ArrayView.h" #include "atlas/array/IndexView.h" #include "atlas/library/config.h" +#include "atlas/runtime/Exception.h" namespace atlas { namespace array { @@ -13,12 +25,12 @@ inline static void check_metadata( const Array& array ) { if ( array.rank() != Rank ) { std::stringstream err; err << "Number of dimensions do not match: template argument " << Rank << " expected to be " << array.rank(); - throw eckit::BadParameter( err.str(), Here() ); + throw_Exception( err.str(), Here() ); } if ( array.datatype() != array::DataType::create() ) { std::stringstream err; err << "Data Type does not match: template argument expected to be " << array.datatype().str(); - throw eckit::BadParameter( err.str(), Here() ); + throw_Exception( err.str(), Here() ); } } } // namespace @@ -115,6 +127,16 @@ template IndexView make_host_indexview( const template IndexView make_host_indexview( const Array& ); template IndexView make_host_indexview( const Array& ); +template IndexView make_indexview( const Array& ); +template IndexView make_indexview( const Array& ); +template IndexView make_indexview( const Array& ); +template IndexView make_indexview( const Array& ); + +template IndexView make_host_indexview( const Array& ); +template IndexView make_host_indexview( const Array& ); +template IndexView make_host_indexview( const Array& ); +template IndexView make_host_indexview( const Array& ); + // For each Rank in [1..9] EXPLICIT_TEMPLATE_INSTANTIATION( 1 ) EXPLICIT_TEMPLATE_INSTANTIATION( 2 ) diff --git a/src/atlas/array_fwd.h b/src/atlas/array_fwd.h index 1d14fee36..dd2e01656 100644 --- a/src/atlas/array_fwd.h +++ b/src/atlas/array_fwd.h @@ -12,8 +12,10 @@ #pragma once +#include #include "atlas/array/ArrayViewDefs.h" + namespace atlas { namespace array { @@ -21,6 +23,10 @@ class DataType; class ArraySpec; +class ArrayShape; + +class ArrayStrides; + class Array; template @@ -29,12 +35,21 @@ class ArrayT; template class ArrayView; +template +class LocalView; + template class IndexView; template ArrayView make_view( const Array& array ); +template +LocalView make_view( const Value data[], const ArrayShape& ); + +template +LocalView make_view( const Value data[], size_t ); + template ArrayView make_host_view( const Array& array ); diff --git a/src/atlas/domain/Domain.cc b/src/atlas/domain/Domain.cc index ea4b9583d..3149f625a 100644 --- a/src/atlas/domain/Domain.cc +++ b/src/atlas/domain/Domain.cc @@ -20,13 +20,7 @@ using ZD = atlas::domain::ZonalBandDomain; namespace atlas { -Domain::Domain() : domain_() {} - -Domain::Domain( const Domain& domain ) : domain_( domain.domain_ ) {} - -Domain::Domain( const Implementation* domain ) : domain_( domain ) {} - -Domain::Domain( const eckit::Parametrisation& p ) : domain_( atlas::domain::Domain::create( p ) ) {} +Domain::Domain( const eckit::Parametrisation& p ) : Handle( atlas::domain::Domain::create( p ) ) {} RectangularDomain::RectangularDomain( const Interval& x, const Interval& y, const std::string& units ) : Domain( ( RD::is_global( x, y, units ) ) @@ -36,7 +30,31 @@ RectangularDomain::RectangularDomain( const Interval& x, const Interval& y, cons RectangularDomain::RectangularDomain( const Domain& domain ) : Domain( domain ), - domain_( dynamic_cast( domain.get() ) ) {} + domain_( dynamic_cast( get() ) ) {} + +bool RectangularDomain::contains_x( double x ) const { + return domain_->contains_x( x ); +} + +bool RectangularDomain::contains_y( double y ) const { + return domain_->contains_y( y ); +} + +double RectangularDomain::xmin() const { + return domain_->xmin(); +} + +double RectangularDomain::xmax() const { + return domain_->xmax(); +} + +double RectangularDomain::ymin() const { + return domain_->ymin(); +} + +double RectangularDomain::ymax() const { + return domain_->ymax(); +} ZonalBandDomain::ZonalBandDomain( const Interval& y ) : RectangularDomain( ( ZD::is_global( y ) ) ? new atlas::domain::GlobalDomain() @@ -44,6 +62,55 @@ ZonalBandDomain::ZonalBandDomain( const Interval& y ) : ZonalBandDomain::ZonalBandDomain( const Domain& domain ) : RectangularDomain( domain ), - domain_( dynamic_cast( domain.get() ) ) {} + domain_( dynamic_cast( get() ) ) {} + +std::string atlas::Domain::type() const { + return get()->type(); +} + +bool Domain::contains( double x, double y ) const { + return get()->contains( x, y ); +} + +bool Domain::contains( const PointXY& p ) const { + return get()->contains( p ); +} + +std::string Domain::units() const { + return get()->units(); +} + +Domain::Spec Domain::spec() const { + return get()->spec(); +} + +bool Domain::global() const { + return get()->global(); +} + +bool Domain::empty() const { + return get()->empty(); +} + +void Domain::hash( eckit::Hash& h ) const { + get()->hash( h ); +} + +bool Domain::containsNorthPole() const { + return get()->containsNorthPole(); +} + +bool Domain::containsSouthPole() const { + return get()->containsSouthPole(); +} + +void Domain::print( std::ostream& os ) const { + return get()->print( os ); +} + +std::ostream& operator<<( std::ostream& os, const Domain& d ) { + d.print( os ); + return os; +} } // namespace atlas diff --git a/src/atlas/domain/Domain.h b/src/atlas/domain/Domain.h index 832a3bc32..d049d436e 100644 --- a/src/atlas/domain/Domain.h +++ b/src/atlas/domain/Domain.h @@ -11,13 +11,9 @@ #pragma once #include +#include -#include "eckit/memory/SharedPtr.h" - -#include "atlas/domain/detail/Domain.h" -#include "atlas/domain/detail/RectangularDomain.h" -#include "atlas/domain/detail/ZonalBandDomain.h" -#include "atlas/projection/Projection.h" +#include "atlas/util/ObjectHandle.h" //--------------------------------------------------------------------------------------------------------------------- @@ -30,22 +26,27 @@ class Hash; //--------------------------------------------------------------------------------------------------------------------- namespace atlas { +class PointXY; + +namespace util { +class Config; +} // namespace util + +namespace domain { +class Domain; +} //--------------------------------------------------------------------------------------------------------------------- -class Domain { +class Domain : public util::ObjectHandle { public: - using Implementation = atlas::domain::Domain; - using Spec = atlas::domain::Domain::Spec; + using Spec = util::Config; public: - Domain(); - Domain( const Domain& ); - Domain( const Implementation* ); + using Handle::Handle; + Domain() = default; Domain( const eckit::Parametrisation& ); - operator bool() const { return domain_; } - /// Type of the domain std::string type() const; @@ -78,60 +79,19 @@ class Domain { /// String that defines units of the domain ("degrees" or "meters") std::string units() const; - /// Access pointer to implementation (PIMPL) - const Implementation* get() const { return domain_.get(); } - private: /// Output to stream void print( std::ostream& ) const; friend std::ostream& operator<<( std::ostream& s, const Domain& d ); - - eckit::SharedPtr domain_; }; //--------------------------------------------------------------------------------------------------------------------- -inline std::string Domain::type() const { - return domain_.get()->type(); -} -inline bool Domain::contains( double x, double y ) const { - return domain_.get()->contains( x, y ); -} -inline bool Domain::contains( const PointXY& p ) const { - return domain_.get()->contains( p ); -} -inline Domain::Spec Domain::spec() const { - return domain_.get()->spec(); -} -inline bool Domain::global() const { - return domain_.get()->global(); -} -inline bool Domain::empty() const { - return domain_.get()->empty(); -} -inline void Domain::hash( eckit::Hash& h ) const { - domain_.get()->hash( h ); -} -inline bool Domain::containsNorthPole() const { - return domain_.get()->containsNorthPole(); -} -inline bool Domain::containsSouthPole() const { - return domain_.get()->containsSouthPole(); -} -inline void Domain::print( std::ostream& os ) const { - return domain_.get()->print( os ); -} -inline std::ostream& operator<<( std::ostream& os, const Domain& d ) { - d.print( os ); - return os; -} -inline std::string Domain::units() const { - return domain_.get()->units(); +namespace domain { +class RectangularDomain; } -//--------------------------------------------------------------------------------------------------------------------- - class RectangularDomain : public Domain { public: using Interval = std::array; @@ -145,18 +105,18 @@ class RectangularDomain : public Domain { operator bool() { return domain_; } /// Checks if the x-value is contained in the domain - bool contains_x( double x ) const { return domain_.get()->contains_x( x ); } + bool contains_x( double x ) const; /// Checks if the y-value is contained in the domain - bool contains_y( double y ) const { return domain_.get()->contains_y( y ); } + bool contains_y( double y ) const; - double xmin() const { return domain_.get()->xmin(); } - double xmax() const { return domain_.get()->xmax(); } - double ymin() const { return domain_.get()->ymin(); } - double ymax() const { return domain_.get()->ymax(); } + double xmin() const; + double xmax() const; + double ymin() const; + double ymax() const; private: - eckit::SharedPtr domain_; + const ::atlas::domain::RectangularDomain* domain_; }; //--------------------------------------------------------------------------------------------------------------------- @@ -177,7 +137,7 @@ class ZonalBandDomain : public RectangularDomain { operator bool() { return domain_; } private: - eckit::SharedPtr domain_; + const ::atlas::domain::ZonalBandDomain* domain_; }; //--------------------------------------------------------------------------------------------------------------------- diff --git a/src/atlas/domain/detail/Domain.cc b/src/atlas/domain/detail/Domain.cc index 6a36c9732..0caa806e4 100644 --- a/src/atlas/domain/detail/Domain.cc +++ b/src/atlas/domain/detail/Domain.cc @@ -1,24 +1,34 @@ -#include "eckit/exception/Exceptions.h" +/* + * (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/domain/detail/Domain.h" +#include "atlas/domain/detail/DomainFactory.h" #include "atlas/projection/Projection.h" +#include "atlas/runtime/Exception.h" namespace atlas { namespace domain { -Domain* Domain::create() { +const Domain* Domain::create() { // default: global domain util::Config projParams; projParams.set( "type", "global" ); return Domain::create( projParams ); } -Domain* Domain::create( const eckit::Parametrisation& p ) { +const Domain* Domain::create( const eckit::Parametrisation& p ) { std::string domain_type; - if ( p.get( "type", domain_type ) ) { return eckit::Factory::instance().get( domain_type ).create( p ); } + if ( p.get( "type", domain_type ) ) { return DomainFactory::build( domain_type, p ); } // should return error here - throw eckit::BadParameter( "type missing in Params", Here() ); + throw_Exception( "type missing in Params", Here() ); } } // namespace domain diff --git a/src/atlas/domain/detail/Domain.h b/src/atlas/domain/detail/Domain.h index 17b70b4b2..5377789a4 100644 --- a/src/atlas/domain/detail/Domain.h +++ b/src/atlas/domain/detail/Domain.h @@ -1,40 +1,38 @@ /* - -The Domain class describes the extent of a grid in projected "grid coordinates" - -daand: - - I simply removed the original Domain.h, which only described boxes in -(lon,lat)-space. - - The Domain class has become a purely abstract class to allow for other -domain shapes (circular, frame, and what not...) - - I didn't implement hashes, (copy) constructors, comparators, etc. for now. + * (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 "eckit/config/Parametrisation.h" -#include "eckit/memory/Builder.h" -#include "eckit/memory/Owned.h" +#include #include "atlas/util/Config.h" +#include "atlas/util/Object.h" #include "atlas/util/Point.h" +namespace eckit { +class Parametrisation; +} + namespace atlas { class Projection; namespace domain { -class Domain : public eckit::Owned { +class Domain : public util::Object { public: using Spec = util::Config; - typedef const eckit::Parametrisation& ARG1; - typedef eckit::BuilderT1 builder_t; - static std::string className() { return "atlas.Domain"; } public: - static Domain* create(); // Create a global domain + static const Domain* create(); // Create a global domain - static Domain* create( const eckit::Parametrisation& ); + static const Domain* create( const eckit::Parametrisation& ); virtual std::string type() const = 0; diff --git a/src/atlas/domain/detail/DomainFactory.cc b/src/atlas/domain/detail/DomainFactory.cc new file mode 100644 index 000000000..fa914523e --- /dev/null +++ b/src/atlas/domain/detail/DomainFactory.cc @@ -0,0 +1,53 @@ +/* + * (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 "atlas/domain/detail/Domain.h" +#include "atlas/domain/detail/DomainFactory.h" +#include "atlas/domain/detail/EmptyDomain.h" +#include "atlas/domain/detail/GlobalDomain.h" +#include "atlas/domain/detail/RectangularDomain.h" +#include "atlas/domain/detail/ZonalBandDomain.h" + +namespace atlas { +namespace domain { + +//---------------------------------------------------------------------------------------------------------------------- + +namespace { +void force_link() { + static struct Link { + Link() { + DomainBuilder(); + DomainBuilder(); + DomainBuilder(); + DomainBuilder(); + } + } link; +} +} // namespace + +//---------------------------------------------------------------------------------------------------------------------- + +const Domain* DomainFactory::build( const std::string& builder ) { + return build( builder, util::NoConfig() ); +} + +const Domain* DomainFactory::build( const std::string& builder, const eckit::Parametrisation& param ) { + force_link(); + auto factory = get( builder ); + return factory->make( param ); +} + +//---------------------------------------------------------------------------------------------------------------------- + +} // namespace domain +} // namespace atlas diff --git a/src/atlas/domain/detail/DomainFactory.h b/src/atlas/domain/detail/DomainFactory.h new file mode 100644 index 000000000..508fed48c --- /dev/null +++ b/src/atlas/domain/detail/DomainFactory.h @@ -0,0 +1,50 @@ +/* + * (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 + +#include "atlas/util/Config.h" +#include "atlas/util/Factory.h" + +namespace atlas { +namespace domain { + +class Domain; + +//---------------------------------------------------------------------------------------------------------------------- + +class DomainFactory : public util::Factory { +public: + static std::string className() { return "DomainFactory"; } + static const Domain* build( const std::string& ); + static const Domain* build( const std::string&, const eckit::Parametrisation& ); + using Factory::Factory; + +private: + virtual const Domain* make( const eckit::Parametrisation& ) = 0; +}; + +//---------------------------------------------------------------------------------------------------------------------- + +template +class DomainBuilder : public DomainFactory { +private: + virtual const Domain* make( const eckit::Parametrisation& param ) { return new T( param ); } + +public: + using DomainFactory::DomainFactory; +}; + +//---------------------------------------------------------------------------------------------------------------------- + +} // namespace domain +} // namespace atlas diff --git a/src/atlas/domain/detail/EmptyDomain.cc b/src/atlas/domain/detail/EmptyDomain.cc index 7be5bc250..c7153bd8f 100644 --- a/src/atlas/domain/detail/EmptyDomain.cc +++ b/src/atlas/domain/detail/EmptyDomain.cc @@ -1,4 +1,20 @@ +/* + * (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 "eckit/utils/Hash.h" + +#include "atlas/domain/detail/DomainFactory.h" #include "atlas/domain/detail/EmptyDomain.h" +#include "atlas/runtime/Exception.h" namespace atlas { namespace domain { @@ -22,10 +38,12 @@ void EmptyDomain::hash( eckit::Hash& h ) const { } std::string EmptyDomain::units() const { - NOTIMP; + ATLAS_NOTIMPLEMENTED; } -register_BuilderT1( Domain, EmptyDomain, EmptyDomain::static_type() ); +namespace { +static DomainBuilder register_builder( EmptyDomain::static_type() ); +} } // namespace domain } // namespace atlas diff --git a/src/atlas/domain/detail/EmptyDomain.h b/src/atlas/domain/detail/EmptyDomain.h index d9a5358b5..4f74c48ff 100644 --- a/src/atlas/domain/detail/EmptyDomain.h +++ b/src/atlas/domain/detail/EmptyDomain.h @@ -1,3 +1,13 @@ +/* + * (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/domain/detail/Domain.h" diff --git a/src/atlas/domain/detail/GlobalDomain.cc b/src/atlas/domain/detail/GlobalDomain.cc index cb7cb7c97..0ca20f472 100644 --- a/src/atlas/domain/detail/GlobalDomain.cc +++ b/src/atlas/domain/detail/GlobalDomain.cc @@ -1,3 +1,18 @@ +/* + * (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 "eckit/utils/Hash.h" + +#include "atlas/domain/detail/DomainFactory.h" #include "atlas/domain/detail/GlobalDomain.h" namespace atlas { @@ -13,7 +28,7 @@ GlobalDomain::GlobalDomain( const double west ) : ZonalBandDomain( yrange(), wes GlobalDomain::GlobalDomain() : ZonalBandDomain( yrange() ) {} -GlobalDomain::GlobalDomain( const eckit::Parametrisation& p ) : GlobalDomain() {} +GlobalDomain::GlobalDomain( const eckit::Parametrisation& ) : GlobalDomain() {} GlobalDomain::Spec GlobalDomain::spec() const { Spec domain_spec; @@ -29,7 +44,8 @@ void GlobalDomain::print( std::ostream& os ) const { os << "GlobalDomain"; } -register_BuilderT1( Domain, GlobalDomain, GlobalDomain::static_type() ); - +namespace { +static DomainBuilder register_builder( GlobalDomain::static_type() ); +} } // namespace domain } // namespace atlas diff --git a/src/atlas/domain/detail/GlobalDomain.h b/src/atlas/domain/detail/GlobalDomain.h index 1446f0b3d..a11ad64cf 100644 --- a/src/atlas/domain/detail/GlobalDomain.h +++ b/src/atlas/domain/detail/GlobalDomain.h @@ -1,6 +1,15 @@ +/* + * (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/domain/Domain.h" #include "atlas/domain/detail/ZonalBandDomain.h" namespace atlas { diff --git a/src/atlas/domain/detail/RectangularDomain.cc b/src/atlas/domain/detail/RectangularDomain.cc index 999204c80..66e5e52a6 100644 --- a/src/atlas/domain/detail/RectangularDomain.cc +++ b/src/atlas/domain/detail/RectangularDomain.cc @@ -1,6 +1,19 @@ +/* + * (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 +#include "atlas/domain/detail/DomainFactory.h" #include "atlas/domain/detail/RectangularDomain.h" +#include "atlas/runtime/Exception.h" namespace atlas { namespace domain { @@ -12,9 +25,9 @@ namespace { static std::array get_interval_x( const eckit::Parametrisation& params ) { double xmin, xmax; - if ( !params.get( "xmin", xmin ) ) throw eckit::BadParameter( "xmin missing in Params", Here() ); + if ( !params.get( "xmin", xmin ) ) throw_Exception( "xmin missing in Params", Here() ); - if ( !params.get( "xmax", xmax ) ) throw eckit::BadParameter( "xmax missing in Params", Here() ); + if ( !params.get( "xmax", xmax ) ) throw_Exception( "xmax missing in Params", Here() ); return {xmin, xmax}; } @@ -22,16 +35,16 @@ static std::array get_interval_x( const eckit::Parametrisation& param static std::array get_interval_y( const eckit::Parametrisation& params ) { double ymin, ymax; - if ( !params.get( "ymin", ymin ) ) throw eckit::BadParameter( "ymin missing in Params", Here() ); + if ( !params.get( "ymin", ymin ) ) throw_Exception( "ymin missing in Params", Here() ); - if ( !params.get( "ymax", ymax ) ) throw eckit::BadParameter( "ymax missing in Params", Here() ); + if ( !params.get( "ymax", ymax ) ) throw_Exception( "ymax missing in Params", Here() ); return {ymin, ymax}; } static std::string get_units( const eckit::Parametrisation& params ) { std::string units; - if ( !params.get( "units", units ) ) throw eckit::BadParameter( "units missing in Params", Here() ); + if ( !params.get( "units", units ) ) throw_Exception( "units missing in Params", Here() ); return units; } @@ -107,7 +120,9 @@ bool RectangularDomain::containsSouthPole() const { return unit_degrees_ && ymin_tol_ <= -90.; } -register_BuilderT1( Domain, RectangularDomain, RectangularDomain::static_type() ); +namespace { +static DomainBuilder register_builder( RectangularDomain::static_type() ); +} } // namespace domain } // namespace atlas diff --git a/src/atlas/domain/detail/RectangularDomain.h b/src/atlas/domain/detail/RectangularDomain.h index d7450e9b2..010d383f2 100644 --- a/src/atlas/domain/detail/RectangularDomain.h +++ b/src/atlas/domain/detail/RectangularDomain.h @@ -1,7 +1,17 @@ +/* + * (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 -#include +#include #include "atlas/domain/detail/Domain.h" diff --git a/src/atlas/domain/detail/ZonalBandDomain.cc b/src/atlas/domain/detail/ZonalBandDomain.cc index 509e70ba6..410c4cc5d 100644 --- a/src/atlas/domain/detail/ZonalBandDomain.cc +++ b/src/atlas/domain/detail/ZonalBandDomain.cc @@ -1,4 +1,18 @@ +/* + * (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 "atlas/domain/detail/DomainFactory.h" #include "atlas/domain/detail/ZonalBandDomain.h" +#include "atlas/runtime/Exception.h" namespace atlas { namespace domain { @@ -13,9 +27,9 @@ static bool _is_global( double ymin, double ymax ) { static std::array get_interval_y( const eckit::Parametrisation& params ) { double ymin, ymax; - if ( !params.get( "ymin", ymin ) ) throw eckit::BadParameter( "ymin missing in Params", Here() ); + if ( !params.get( "ymin", ymin ) ) throw_Exception( "ymin missing in Params", Here() ); - if ( !params.get( "ymax", ymax ) ) throw eckit::BadParameter( "ymax missing in Params", Here() ); + if ( !params.get( "ymax", ymax ) ) throw_Exception( "ymax missing in Params", Here() ); return {ymin, ymax}; } @@ -75,7 +89,9 @@ bool ZonalBandDomain::containsSouthPole() const { return ymin_tol_ <= -90.; } -register_BuilderT1( Domain, ZonalBandDomain, ZonalBandDomain::static_type() ); +namespace { +static DomainBuilder register_builder( ZonalBandDomain::static_type() ); +} } // namespace domain } // namespace atlas diff --git a/src/atlas/domain/detail/ZonalBandDomain.h b/src/atlas/domain/detail/ZonalBandDomain.h index f08635a9e..e277112dd 100644 --- a/src/atlas/domain/detail/ZonalBandDomain.h +++ b/src/atlas/domain/detail/ZonalBandDomain.h @@ -1,9 +1,18 @@ +/* + * (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 -#include +#include -#include "atlas/domain/Domain.h" #include "atlas/domain/detail/RectangularDomain.h" namespace atlas { diff --git a/src/atlas/field/Field.cc b/src/atlas/field/Field.cc index e06069877..5b57a50dd 100644 --- a/src/atlas/field/Field.cc +++ b/src/atlas/field/Field.cc @@ -13,361 +13,261 @@ #include "atlas/field/Field.h" #include "atlas/field/detail/FieldImpl.h" +#include "atlas/functionspace/FunctionSpace.h" namespace atlas { // ------------------------------------------------------------------ std::ostream& operator<<( std::ostream& os, const Field& f ) { - os << ( *f.field_ ); + os << ( *f.get() ); return os; } -Field::Field() : field_( nullptr ) {} - -Field::Field( const Field& field ) : field_( field.field_ ) { - field_->attach(); -} - -Field::Field( const Implementation* field ) : field_( const_cast( field ) ) { - field_->attach(); -} - -Field::Field( const eckit::Parametrisation& config ) : field_( Implementation::create( config ) ) { - field_->attach(); -} +Field::Field( const eckit::Parametrisation& config ) : Handle( Implementation::create( config ) ) {} Field::Field( const std::string& name, array::DataType datatype, const array::ArrayShape& shape ) : - field_( Implementation::create( name, datatype, shape ) ) { - field_->attach(); -} - -Field::Field( const std::string& name, array::Array* array ) : field_( Implementation::create( name, array ) ) { - field_->attach(); -} - -template <> -Field::Field( const std::string& name, double* data, const array::ArraySpec& spec ) : - field_( Implementation::wrap( name, data, spec ) ) { - field_->attach(); -} - -template <> -Field::Field( const std::string& name, double* data, const array::ArrayShape& shape ) : - field_( Implementation::wrap( name, data, shape ) ) { - field_->attach(); -} - -template <> -Field::Field( const std::string& name, float* data, const array::ArraySpec& spec ) : - field_( Implementation::wrap( name, data, spec ) ) { - field_->attach(); -} - -template <> -Field::Field( const std::string& name, float* data, const array::ArrayShape& shape ) : - field_( Implementation::wrap( name, data, shape ) ) { - field_->attach(); -} - -template <> -Field::Field( const std::string& name, long* data, const array::ArraySpec& spec ) : - field_( Implementation::wrap( name, data, spec ) ) { - field_->attach(); -} - -template <> -Field::Field( const std::string& name, long* data, const array::ArrayShape& shape ) : - field_( Implementation::wrap( name, data, shape ) ) { - field_->attach(); -} + Handle( Implementation::create( name, datatype, shape ) ) {} -template <> -Field::Field( const std::string& name, int* data, const array::ArraySpec& spec ) : - field_( Implementation::wrap( name, data, spec ) ) { - field_->attach(); -} +Field::Field( const std::string& name, array::Array* array ) : Handle( Implementation::create( name, array ) ) {} -template <> -Field::Field( const std::string& name, int* data, const array::ArrayShape& shape ) : - field_( Implementation::wrap( name, data, shape ) ) { - field_->attach(); -} +template +Field::Field( const std::string& name, DATATYPE* data, const array::ArraySpec& spec ) : + Handle( Implementation::wrap( name, data, spec ) ) {} -Field::~Field() { - if ( field_ ) { - field_->detach(); - if ( not field_->owners() ) { delete field_; } - } -} - -const Field& Field::operator=( const Field& other ) { - if ( field_ != other.field_ ) { - if ( field_ ) { - if ( not field_->owners() ) { delete field_; } - } - field_ = other.field_; - field_->attach(); - } - return *this; -} +template +Field::Field( const std::string& name, DATATYPE* data, const array::ArrayShape& shape ) : + Handle( Implementation::wrap( name, data, shape ) ) {} /// @brief Implicit conversion to Array Field::operator const array::Array&() const { - return field_->array(); + return get()->array(); } Field::operator array::Array&() { - return field_->array(); + return get()->array(); } const array::Array& Field::array() const { - return field_->array(); + return get()->array(); } array::Array& Field::array() { - return field_->array(); + return get()->array(); } // -- Accessors /// @brief Access to raw data void* Field::storage() { - return field_->storage(); + return get()->storage(); } /// @brief Internal data type of field array::DataType Field::datatype() const { - return field_->datatype(); + return get()->datatype(); } /// @brief Name associated to this field const std::string& Field::name() const { - return field_->name(); + return get()->name(); } /// @brief Rename this field void Field::rename( const std::string& name ) { - field_->rename( name ); + get()->rename( name ); } /// @brief Access to metadata associated to this field const util::Metadata& Field::metadata() const { - return field_->metadata(); + return get()->metadata(); } util::Metadata& Field::metadata() { - return field_->metadata(); + return get()->metadata(); } /// @brief Resize field to given shape void Field::resize( const array::ArrayShape& shape ) { - field_->resize( shape ); + get()->resize( shape ); } -void Field::insert( size_t idx1, size_t size1 ) { - field_->insert( idx1, size1 ); +void Field::insert( idx_t idx1, idx_t size1 ) { + get()->insert( idx1, size1 ); } /// @brief Shape of this field in Fortran style (reverse order of C style) const std::vector& Field::shapef() const { - return field_->shapef(); + return get()->shapef(); } /// @brief Strides of this field in Fortran style (reverse order of C style) const std::vector& Field::stridesf() const { - return field_->stridesf(); + return get()->stridesf(); } /// @brief Shape of this field (reverse order of Fortran style) const array::ArrayShape& Field::shape() const { - return field_->shape(); + return get()->shape(); } /// @brief Strides of this field const array::ArrayStrides& Field::strides() const { - return field_->strides(); + return get()->strides(); } /// @brief Shape of this field associated to index 'i' -size_t Field::shape( size_t i ) const { - return field_->shape( i ); +idx_t Field::shape( idx_t i ) const { + return get()->shape( i ); } /// @brief Stride of this field associated to index 'i' -size_t Field::stride( size_t i ) const { - return field_->stride( i ); +idx_t Field::stride( idx_t i ) const { + return get()->stride( i ); } /// @brief Number of values stored in this field -size_t Field::size() const { - return field_->size(); +idx_t Field::size() const { + return get()->size(); } /// @brief Rank of field -size_t Field::rank() const { - return field_->rank(); +idx_t Field::rank() const { + return get()->rank(); } /// @brief Number of bytes occupied by the values of this field -double Field::bytes() const { - return field_->bytes(); +size_t Field::bytes() const { + return get()->bytes(); } /// @brief Output information of field plus raw data void Field::dump( std::ostream& os ) const { - field_->dump( os ); + get()->dump( os ); } /// Metadata that is more intrinsic to the Field, and queried often -void Field::set_levels( size_t n ) { - field_->set_levels( n ); +void Field::set_levels( idx_t n ) { + get()->set_levels( n ); } -size_t Field::levels() const { - return field_->levels(); +idx_t Field::levels() const { + return get()->levels(); } /// Metadata that is more intrinsic to the Field, and queried often -void Field::set_variables( size_t n ) { - field_->set_variables( n ); +void Field::set_variables( idx_t n ) { + get()->set_variables( n ); } -size_t Field::variables() const { - return field_->variables(); +idx_t Field::variables() const { + return get()->variables(); } void Field::set_functionspace( const FunctionSpace& functionspace ) { - field_->set_functionspace( functionspace ); + get()->set_functionspace( functionspace ); } const FunctionSpace& Field::functionspace() const { - return field_->functionspace(); + return get()->functionspace(); } /// @brief Return the memory footprint of the Field size_t Field::footprint() const { - return field_->footprint(); + return get()->footprint(); } -// -- dangerous methods -template <> -double const* Field::host_data() const { - return field_->host_data(); -} -template <> -double* Field::host_data() { - return field_->host_data(); -} -template <> -double const* Field::device_data() const { - return field_->device_data(); -} -template <> -double* Field::device_data() { - return field_->device_data(); -} -template <> -double const* Field::data() const { - return field_->host_data(); -} -template <> -double* Field::data() { - return field_->host_data(); +bool Field::dirty() const { + return get()->dirty(); } -template <> -float const* Field::host_data() const { - return field_->host_data(); -} -template <> -float* Field::host_data() { - return field_->host_data(); -} -template <> -float const* Field::device_data() const { - return field_->device_data(); -} -template <> -float* Field::device_data() { - return field_->device_data(); -} -template <> -float const* Field::data() const { - return field_->host_data(); -} -template <> -float* Field::data() { - return field_->host_data(); +void Field::set_dirty( bool value ) const { + return get()->set_dirty( value ); } -template <> -long const* Field::host_data() const { - return field_->host_data(); -} -template <> -long* Field::host_data() { - return field_->host_data(); -} -template <> -long const* Field::device_data() const { - return field_->device_data(); -} -template <> -long* Field::device_data() { - return field_->device_data(); -} -template <> -long const* Field::data() const { - return field_->host_data(); -} -template <> -long* Field::data() { - return field_->host_data(); +void Field::haloExchange( bool on_device ) const { + get()->haloExchange( on_device ); } -template <> -int const* Field::host_data() const { - return field_->host_data(); +// -- dangerous methods +template +DATATYPE const* Field::data() const { + return get()->host_data(); } -template <> -int* Field::host_data() { - return field_->host_data(); +template +DATATYPE* Field::data() { + return get()->host_data(); } -template <> -int const* Field::device_data() const { - return field_->device_data(); +template +DATATYPE const* Field::host_data() const { + return get()->host_data(); } -template <> -int* Field::device_data() { - return field_->device_data(); +template +DATATYPE* Field::host_data() { + return get()->host_data(); } -template <> -int const* Field::data() const { - return field_->host_data(); +template +DATATYPE const* Field::device_data() const { + return get()->device_data(); } -template <> -int* Field::data() { - return field_->host_data(); +template +DATATYPE* Field::device_data() { + return get()->device_data(); } // -- Methods related to host-device synchronisation, requires gridtools_storage void Field::cloneToDevice() const { - field_->cloneToDevice(); + get()->cloneToDevice(); } void Field::cloneFromDevice() const { - field_->cloneFromDevice(); + get()->cloneFromDevice(); } void Field::syncHostDevice() const { - field_->syncHostDevice(); + get()->syncHostDevice(); } bool Field::hostNeedsUpdate() const { - return field_->hostNeedsUpdate(); + return get()->hostNeedsUpdate(); } bool Field::deviceNeedsUpdate() const { - return field_->deviceNeedsUpdate(); + return get()->deviceNeedsUpdate(); } void Field::reactivateDeviceWriteViews() const { - field_->reactivateDeviceWriteViews(); + get()->reactivateDeviceWriteViews(); } void Field::reactivateHostWriteViews() const { - field_->reactivateHostWriteViews(); + get()->reactivateHostWriteViews(); } // ------------------------------------------------------------------ +template Field::Field( const std::string&, float*, const array::ArraySpec& ); +template Field::Field( const std::string&, float*, const array::ArrayShape& ); +template Field::Field( const std::string&, double*, const array::ArraySpec& ); +template Field::Field( const std::string&, double*, const array::ArrayShape& ); +template Field::Field( const std::string&, long*, const array::ArraySpec& ); +template Field::Field( const std::string&, long*, const array::ArrayShape& ); +template Field::Field( const std::string&, int*, const array::ArraySpec& ); +template Field::Field( const std::string&, int*, const array::ArrayShape& ); +template double const* Field::data() const; +template double* Field::data(); +template float const* Field::data() const; +template float* Field::data(); +template long const* Field::data() const; +template long* Field::data(); +template int const* Field::data() const; +template int* Field::data(); +template double const* Field::host_data() const; +template double* Field::host_data(); +template float const* Field::host_data() const; +template float* Field::host_data(); +template long const* Field::host_data() const; +template long* Field::host_data(); +template int const* Field::host_data() const; +template int* Field::host_data(); +template double const* Field::device_data() const; +template double* Field::device_data(); +template float const* Field::device_data() const; +template float* Field::device_data(); +template long const* Field::device_data() const; +template long* Field::device_data(); +template int const* Field::device_data() const; +template int* Field::device_data(); + +// ------------------------------------------------------------------ + + } // namespace atlas diff --git a/src/atlas/field/Field.h b/src/atlas/field/Field.h index 420d55f3d..0ba7fe451 100644 --- a/src/atlas/field/Field.h +++ b/src/atlas/field/Field.h @@ -13,9 +13,13 @@ #pragma once +#include +#include + #include "atlas/array/ArrayShape.h" #include "atlas/array/DataType.h" #include "atlas/array_fwd.h" +#include "atlas/util/ObjectHandle.h" namespace eckit { class Parametrisation; @@ -26,21 +30,6 @@ class FieldImpl; } } // namespace atlas namespace atlas { -namespace array { -class Array; -} -} // namespace atlas -namespace atlas { -namespace array { -class ArraySpec; -} -} // namespace atlas -namespace atlas { -namespace array { -class ArrayStrides; -} -} // namespace atlas -namespace atlas { namespace util { class Metadata; } @@ -51,17 +40,10 @@ class FunctionSpace; namespace atlas { -class Field { +class Field : public util::ObjectHandle { public: - using Implementation = field::FieldImpl; - -private: - Implementation* field_{nullptr}; - -public: - Field(); - Field( const Field& ); - Field( const Implementation* ); + using Handle::Handle; + Field() = default; /// @brief Create field from parametrisation Field( const eckit::Parametrisation& ); @@ -82,8 +64,6 @@ class Field { template Field( const std::string& name, DATATYPE* data, const array::ArrayShape& ); - ~Field(); - // -- Conversion /// @brief Implicit conversion to Array @@ -93,13 +73,7 @@ class Field { const array::Array& array() const; array::Array& array(); - bool valid() const { return field_; } - operator bool() const { return valid(); } - - Implementation* get() { return field_; } - const Implementation* get() const { return field_; } - - const Field& operator=( const Field& ); + bool valid() const { return get() != nullptr; } // -- Accessors @@ -122,7 +96,7 @@ class Field { /// @brief Resize field to given shape void resize( const array::ArrayShape& shape ); - void insert( size_t idx1, size_t size1 ); + void insert( idx_t idx1, idx_t size1 ); /// @brief Shape of this field in Fortran style (reverse order of C style) const std::vector& shapef() const; @@ -137,19 +111,19 @@ class Field { const array::ArrayStrides& strides() const; /// @brief Shape of this field associated to index 'i' - size_t shape( size_t i ) const; + idx_t shape( idx_t i ) const; /// @brief Stride of this field associated to index 'i' - size_t stride( size_t i ) const; + idx_t stride( idx_t i ) const; /// @brief Number of values stored in this field - size_t size() const; + idx_t size() const; /// @brief Rank of field - size_t rank() const; + idx_t rank() const; /// @brief Number of bytes occupied by the values of this field - double bytes() const; + size_t bytes() const; /// @brief Output information of field friend std::ostream& operator<<( std::ostream& os, const Field& v ); @@ -158,12 +132,12 @@ class Field { void dump( std::ostream& os ) const; /// Metadata that is more intrinsic to the Field, and queried often - void set_levels( size_t n ); - size_t levels() const; + void set_levels( idx_t n ); + idx_t levels() const; /// Metadata that is more intrinsic to the Field, and queried often - void set_variables( size_t n ); - size_t variables() const; + void set_variables( idx_t n ); + idx_t variables() const; void set_functionspace( const FunctionSpace& functionspace ); const FunctionSpace& functionspace() const; @@ -171,6 +145,12 @@ class Field { /// @brief Return the memory footprint of the Field size_t footprint() const; + bool dirty() const; + + void set_dirty( bool = true ) const; + + void haloExchange( bool on_device = false ) const; + // -- dangerous methods template DATATYPE const* host_data() const; @@ -196,6 +176,39 @@ class Field { void reactivateHostWriteViews() const; }; +extern template Field::Field( const std::string&, float*, const array::ArraySpec& ); +extern template Field::Field( const std::string&, float*, const array::ArrayShape& ); +extern template Field::Field( const std::string&, double*, const array::ArraySpec& ); +extern template Field::Field( const std::string&, double*, const array::ArrayShape& ); +extern template Field::Field( const std::string&, long*, const array::ArraySpec& ); +extern template Field::Field( const std::string&, long*, const array::ArrayShape& ); +extern template Field::Field( const std::string&, int*, const array::ArraySpec& ); +extern template Field::Field( const std::string&, int*, const array::ArrayShape& ); +extern template double const* Field::data() const; +extern template double* Field::data(); +extern template float const* Field::data() const; +extern template float* Field::data(); +extern template long const* Field::data() const; +extern template long* Field::data(); +extern template int const* Field::data() const; +extern template int* Field::data(); +extern template double const* Field::host_data() const; +extern template double* Field::host_data(); +extern template float const* Field::host_data() const; +extern template float* Field::host_data(); +extern template long const* Field::host_data() const; +extern template long* Field::host_data(); +extern template int const* Field::host_data() const; +extern template int* Field::host_data(); +extern template double const* Field::device_data() const; +extern template double* Field::device_data(); +extern template float const* Field::device_data() const; +extern template float* Field::device_data(); +extern template long const* Field::device_data() const; +extern template long* Field::device_data(); +extern template int const* Field::device_data() const; +extern template int* Field::device_data(); + //------------------------------------------------------------------------------------------------------ } // namespace atlas diff --git a/src/atlas/field/FieldCreator.cc b/src/atlas/field/FieldCreator.cc index a263cb754..b9faf4bb5 100644 --- a/src/atlas/field/FieldCreator.cc +++ b/src/atlas/field/FieldCreator.cc @@ -14,8 +14,6 @@ #include #include -#include "eckit/exception/Exceptions.h" -#include "eckit/os/BackTrace.h" #include "eckit/thread/AutoLock.h" #include "eckit/thread/Mutex.h" @@ -23,6 +21,7 @@ #include "atlas/field/FieldCreatorArraySpec.h" #include "atlas/field/FieldCreatorIFS.h" #include "atlas/grid/Grid.h" +#include "atlas/runtime/Exception.h" #include "atlas/runtime/Log.h" namespace { @@ -66,9 +65,8 @@ FieldCreatorFactory::FieldCreatorFactory( const std::string& name ) : name_( nam eckit::AutoLock lock( local_mutex ); if ( m->find( name ) != m->end() ) { - std::string backtrace = eckit::BackTrace::dump(); - throw eckit::SeriousBug( "FieldCreatorFactory [" + name + "] already registered\n\nBacktrace:\n" + backtrace, - Here() ); + throw_Exception( "FieldCreatorFactory [" + name + "] already registered\n\nBacktrace:\n" + backtrace(), + Here() ); } ( *m )[name] = this; } @@ -106,7 +104,7 @@ FieldCreator* FieldCreatorFactory::build( const std::string& name ) { Log::error() << "FieldCreatorFactories are:" << '\n'; for ( j = m->begin(); j != m->end(); ++j ) Log::error() << " " << ( *j ).first << '\n'; - throw eckit::SeriousBug( std::string( "No FieldCreatorFactory called " ) + name ); + throw_Exception( std::string( "No FieldCreatorFactory called " ) + name ); } return ( *j ).second->make(); @@ -126,7 +124,7 @@ FieldCreator* FieldCreatorFactory::build( const std::string& name, const eckit:: Log::error() << "FieldCreatorFactories are:" << '\n'; for ( j = m->begin(); j != m->end(); ++j ) Log::error() << " " << ( *j ).first << '\n'; - throw eckit::SeriousBug( std::string( "No FieldCreatorFactory called " ) + name ); + throw_Exception( std::string( "No FieldCreatorFactory called " ) + name ); } return ( *j ).second->make( param ); diff --git a/src/atlas/field/FieldCreator.h b/src/atlas/field/FieldCreator.h index 3de70e62e..408ea269c 100644 --- a/src/atlas/field/FieldCreator.h +++ b/src/atlas/field/FieldCreator.h @@ -16,7 +16,7 @@ #include -#include "eckit/memory/Owned.h" +#include "atlas/util/Object.h" #include "atlas/field/Field.h" @@ -43,7 +43,7 @@ namespace field { * ); * \endcode */ -class FieldCreator : public eckit::Owned { +class FieldCreator : public util::Object { public: FieldCreator(); diff --git a/src/atlas/field/FieldCreatorArraySpec.cc b/src/atlas/field/FieldCreatorArraySpec.cc index 044f34201..1c7dca179 100644 --- a/src/atlas/field/FieldCreatorArraySpec.cc +++ b/src/atlas/field/FieldCreatorArraySpec.cc @@ -14,20 +14,19 @@ #include #include "eckit/config/Parametrisation.h" -#include "eckit/exception/Exceptions.h" #include "atlas/array/DataType.h" #include "atlas/field/detail/FieldImpl.h" +#include "atlas/runtime/Exception.h" namespace atlas { namespace field { FieldImpl* FieldCreatorArraySpec::createField( const eckit::Parametrisation& params ) const { std::vector shape; - if ( !params.get( "shape", shape ) ) - throw eckit::Exception( "Could not find parameter 'shape' in Parametrisation" ); + if ( !params.get( "shape", shape ) ) throw_Exception( "Could not find parameter 'shape' in Parametrisation" ); - std::vector s( shape.size() ); + std::vector s( shape.size() ); bool fortran( false ); params.get( "fortran", fortran ); @@ -45,7 +44,7 @@ FieldImpl* FieldCreatorArraySpec::createField( const eckit::Parametrisation& par if ( !array::DataType::kind_valid( kind ) ) { std::stringstream msg; msg << "Could not create field. kind parameter unrecognized"; - throw eckit::Exception( msg.str() ); + throw_Exception( msg.str() ); } datatype = array::DataType( kind ); } diff --git a/src/atlas/field/FieldCreatorIFS.cc b/src/atlas/field/FieldCreatorIFS.cc index 5596f6289..652c1a69c 100644 --- a/src/atlas/field/FieldCreatorIFS.cc +++ b/src/atlas/field/FieldCreatorIFS.cc @@ -10,15 +10,16 @@ #include "atlas/field/FieldCreatorIFS.h" +#include #include #include "eckit/config/Parametrisation.h" -#include "eckit/exception/Exceptions.h" #include "atlas/array/ArrayUtil.h" #include "atlas/array/DataType.h" #include "atlas/field/detail/FieldImpl.h" #include "atlas/grid/Grid.h" +#include "atlas/runtime/Exception.h" #include "atlas/runtime/Log.h" namespace atlas { @@ -31,8 +32,7 @@ FieldImpl* FieldCreatorIFS::createField( const eckit::Parametrisation& params ) size_t nproma = 1; size_t nlev = 1; - if ( !params.get( "ngptot", ngptot ) ) - throw eckit::Exception( "Could not find parameter 'ngptot' in Parametrisation" ); + if ( !params.get( "ngptot", ngptot ) ) throw_Exception( "Could not find parameter 'ngptot' in Parametrisation" ); params.get( "nproma", nproma ); params.get( "nlev", nlev ); params.get( "nvar", nvar ); @@ -46,7 +46,7 @@ FieldImpl* FieldCreatorIFS::createField( const eckit::Parametrisation& params ) if ( !array::DataType::kind_valid( kind ) ) { std::stringstream msg; msg << "Could not create field. kind parameter unrecognized"; - throw eckit::Exception( msg.str() ); + throw_Exception( msg.str() ); } datatype = array::DataType( kind ); } diff --git a/src/atlas/field/FieldSet.cc b/src/atlas/field/FieldSet.cc index 8f5c738ee..4fac20b0f 100644 --- a/src/atlas/field/FieldSet.cc +++ b/src/atlas/field/FieldSet.cc @@ -8,17 +8,19 @@ * nor does it submit to any jurisdiction. */ -#include "atlas/field/FieldSet.h" +#include + #include "atlas/field/Field.h" +#include "atlas/field/FieldSet.h" #include "atlas/grid/Grid.h" -#include "atlas/runtime/ErrorHandling.h" +#include "atlas/runtime/Exception.h" namespace atlas { namespace field { //------------------------------------------------------------------------------------------------------ -FieldSetImpl::FieldSetImpl( const std::string& name ) : name_() {} +FieldSetImpl::FieldSetImpl( const std::string& /*name*/ ) : name_() {} void FieldSetImpl::clear() { index_.clear(); @@ -26,11 +28,11 @@ void FieldSetImpl::clear() { } Field FieldSetImpl::add( const Field& field ) { - if ( field.name().size() ) { index_[field.name()] = fields_.size(); } + if ( field.name().size() ) { index_[field.name()] = size(); } else { std::stringstream name; - name << name_ << "[" << fields_.size() << "]"; - index_[name.str()] = fields_.size(); + name << name_ << "[" << size() << "]"; + index_[name.str()] = size(); } fields_.push_back( field ); return field; @@ -44,11 +46,23 @@ Field& FieldSetImpl::field( const std::string& name ) const { if ( !has_field( name ) ) { const std::string msg( "FieldSet" + ( name_.length() ? " \"" + name_ + "\"" : "" ) + ": cannot find field \"" + name + "\"" ); - throw eckit::OutOfRange( msg, Here() ); + throw_Exception( msg, Here() ); } return const_cast( fields_[index_.at( name )] ); } +void FieldSetImpl::haloExchange( bool on_device ) const { + for ( idx_t i = 0; i < size(); ++i ) { + field( i ).haloExchange( on_device ); + } +} + +void FieldSetImpl::set_dirty( bool value ) const { + for ( idx_t i = 0; i < size(); ++i ) { + field( i ).set_dirty( value ); + } +} + std::vector FieldSetImpl::field_names() const { std::vector ret; @@ -63,37 +77,50 @@ std::vector FieldSetImpl::field_names() const { extern "C" { FieldSetImpl* atlas__FieldSet__new( char* name ) { - ATLAS_ERROR_HANDLING( FieldSetImpl* fset = new FieldSetImpl( std::string( name ) ); fset->name() = name; - return fset; ); - return NULL; + FieldSetImpl* fset = new FieldSetImpl( std::string( name ) ); + fset->name() = name; + return fset; } void atlas__FieldSet__delete( FieldSetImpl* This ) { - ATLAS_ERROR_HANDLING( ASSERT( This != NULL ); delete This; ); + ATLAS_ASSERT( This != nullptr, "Reason: Use of uninitialised atlas_FieldSet" ); + delete This; } void atlas__FieldSet__add_field( FieldSetImpl* This, FieldImpl* field ) { - ATLAS_ERROR_HANDLING( ASSERT( This != NULL ); This->add( field ); ); + ATLAS_ASSERT( This != nullptr, "Reason: Use of uninitialised atlas_FieldSet" ); + ATLAS_ASSERT( field != nullptr, "Reason: Use of uninitialised atlas_Field" ); + This->add( field ); } int atlas__FieldSet__has_field( const FieldSetImpl* This, char* name ) { - ATLAS_ERROR_HANDLING( ASSERT( This != NULL ); return This->has_field( std::string( name ) ); ); - return 0; + ATLAS_ASSERT( This != nullptr, "Reason: Use of uninitialised atlas_FieldSet" ); + return This->has_field( std::string( name ) ); } -size_t atlas__FieldSet__size( const FieldSetImpl* This ) { - ATLAS_ERROR_HANDLING( ASSERT( This != NULL ); return This->size(); ); - return 0; +idx_t atlas__FieldSet__size( const FieldSetImpl* This ) { + ATLAS_ASSERT( This != nullptr, "Reason: Use of uninitialised atlas_FieldSet" ); + return This->size(); } FieldImpl* atlas__FieldSet__field_by_name( FieldSetImpl* This, char* name ) { - ATLAS_ERROR_HANDLING( ASSERT( This != NULL ); return This->field( std::string( name ) ).get(); ); - return NULL; + ATLAS_ASSERT( This != nullptr, "Reason: Use of uninitialised atlas_FieldSet" ); + return This->field( std::string( name ) ).get(); +} + +FieldImpl* atlas__FieldSet__field_by_idx( FieldSetImpl* This, idx_t idx ) { + ATLAS_ASSERT( This != nullptr, "Reason: Use of uninitialised atlas_FieldSet" ); + return This->operator[]( idx ).get(); } -FieldImpl* atlas__FieldSet__field_by_idx( FieldSetImpl* This, size_t idx ) { - ATLAS_ERROR_HANDLING( ASSERT( This != NULL ); return This->operator[]( idx ).get(); ); - return NULL; +void atlas__FieldSet__set_dirty( FieldSetImpl* This, int value ) { + ATLAS_ASSERT( This != nullptr, "Reason: Use of uninitialised atlas_FieldSet" ); + This->set_dirty( value ); +} + +void atlas__FieldSet__halo_exchange( FieldSetImpl* This, int on_device ) { + ATLAS_ASSERT( This != nullptr, "Reason: Use of uninitialised atlas_FieldSet" ); + This->haloExchange( on_device ); } } //----------------------------------------------------------------------------- @@ -102,11 +129,15 @@ FieldImpl* atlas__FieldSet__field_by_idx( FieldSetImpl* This, size_t idx ) { //------------------------------------------------------------------------------------------------------ -FieldSet::FieldSet( const std::string& name ) : fieldset_( new Implementation( name ) ) {} +FieldSet::FieldSet( const std::string& name ) : Handle( new Implementation( name ) ) {} -FieldSet::FieldSet( const Implementation* fieldset ) : fieldset_( const_cast( fieldset ) ) {} +FieldSet::FieldSet( const Field& field ) : Handle( new Implementation() ) { + get()->add( field ); +} -FieldSet::FieldSet( const FieldSet& fieldset ) : fieldset_( fieldset.fieldset_ ) {} +void FieldSet::set_dirty( bool value ) const { + get()->set_dirty( value ); +} //------------------------------------------------------------------------------------------------------ diff --git a/src/atlas/field/FieldSet.h b/src/atlas/field/FieldSet.h index 40038637a..c6c4e9a99 100644 --- a/src/atlas/field/FieldSet.h +++ b/src/atlas/field/FieldSet.h @@ -15,12 +15,15 @@ #pragma once #include +#include +#include #include -#include "eckit/memory/Owned.h" -#include "eckit/memory/SharedPtr.h" - #include "atlas/field/Field.h" +#include "atlas/library/config.h" +#include "atlas/runtime/Exception.h" +#include "atlas/util/Object.h" +#include "atlas/util/ObjectHandle.h" namespace atlas { @@ -31,16 +34,16 @@ namespace field { /** * @brief Represents a set of fields, where order is preserved */ -class FieldSetImpl : public eckit::Owned { +class FieldSetImpl : public util::Object { public: // types - typedef std::vector::iterator iterator; - typedef std::vector::const_iterator const_iterator; + using iterator = std::vector::iterator; + using const_iterator = std::vector::const_iterator; public: // methods /// Constructs an empty FieldSet FieldSetImpl( const std::string& name = "untitled" ); - size_t size() const { return fields_.size(); } + idx_t size() const { return static_cast( fields_.size() ); } bool empty() const { return !fields_.size(); } void clear(); @@ -48,18 +51,18 @@ class FieldSetImpl : public eckit::Owned { const std::string& name() const { return name_; } std::string& name() { return name_; } - const Field& operator[]( const size_t& i ) const { return field( i ); } - Field& operator[]( const size_t& i ) { return field( i ); } + const Field& operator[]( const idx_t& i ) const { return field( i ); } + Field& operator[]( const idx_t& i ) { return field( i ); } const Field& operator[]( const std::string& name ) const { return field( name ); } Field& operator[]( const std::string& name ) { return field( name ); } - const Field& field( const size_t& i ) const { - ASSERT( i < size() ); + const Field& field( const idx_t& i ) const { + if ( i >= size() ) throw_OutOfRange( "fieldset", i, size(), Here() ); return fields_[i]; } - Field& field( const size_t& i ) { - ASSERT( i < size() ); + Field& field( const idx_t& i ) { + if ( i >= size() ) throw_OutOfRange( "fieldset", i, size(), Here() ); return fields_[i]; } @@ -78,21 +81,29 @@ class FieldSetImpl : public eckit::Owned { const_iterator cbegin() const { return fields_.begin(); } const_iterator cend() const { return fields_.end(); } -protected: // data - std::vector fields_; ///< field storage - std::string name_; ///< internal name - std::map index_; ///< name-to-index map, to refer fields by name + void haloExchange( bool on_device = false ) const; + void set_dirty( bool = true ) const; + +protected: // data + std::vector fields_; ///< field storage + std::string name_; ///< internal name + std::map index_; ///< name-to-index map, to refer fields by name }; + +class FieldImpl; + // C wrapper interfaces to C++ routines extern "C" { FieldSetImpl* atlas__FieldSet__new( char* name ); void atlas__FieldSet__delete( FieldSetImpl* This ); void atlas__FieldSet__add_field( FieldSetImpl* This, FieldImpl* field ); int atlas__FieldSet__has_field( const FieldSetImpl* This, char* name ); -size_t atlas__FieldSet__size( const FieldSetImpl* This ); +idx_t atlas__FieldSet__size( const FieldSetImpl* This ); FieldImpl* atlas__FieldSet__field_by_name( FieldSetImpl* This, char* name ); -FieldImpl* atlas__FieldSet__field_by_idx( FieldSetImpl* This, size_t idx ); +FieldImpl* atlas__FieldSet__field_by_idx( FieldSetImpl* This, idx_t idx ); +void atlas__FieldSet__set_dirty( FieldSetImpl* This, int value ); +void atlas__FieldSet__halo_exchange( FieldSetImpl* This, int on_device ); } } // namespace field @@ -102,51 +113,53 @@ FieldImpl* atlas__FieldSet__field_by_idx( FieldSetImpl* This, size_t idx ); /** * @brief Represents a set of fields, where order is preserved */ -class FieldSet { +class FieldSet : public util::ObjectHandle { public: // types - using Implementation = field::FieldSetImpl; using iterator = Implementation::iterator; using const_iterator = Implementation::const_iterator; public: // methods + using Handle::Handle; FieldSet( const std::string& name = "untitled" ); - FieldSet( const Implementation* ); - FieldSet( const FieldSet& ); + FieldSet( const Field& ); + + idx_t size() const { return get()->size(); } + bool empty() const { return get()->empty(); } - size_t size() const { return fieldset_->size(); } - bool empty() const { return fieldset_->empty(); } + void clear() { get()->clear(); } - void clear() { fieldset_->clear(); } + const std::string& name() const { return get()->name(); } + std::string& name() { return get()->name(); } - const std::string& name() const { return fieldset_->name(); } - std::string& name() { return fieldset_->name(); } + const Field& operator[]( const idx_t& i ) const { return get()->operator[]( i ); } + Field& operator[]( const idx_t& i ) { return get()->operator[]( i ); } - const Field& operator[]( const size_t& i ) const { return fieldset_->operator[]( i ); } - Field& operator[]( const size_t& i ) { return fieldset_->operator[]( i ); } + const Field& operator[]( const std::string& name ) const { return get()->operator[]( name ); } + Field& operator[]( const std::string& name ) { return get()->operator[]( name ); } - const Field& operator[]( const std::string& name ) const { return fieldset_->operator[]( name ); } - Field& operator[]( const std::string& name ) { return fieldset_->operator[]( name ); } + const Field& operator[]( const char* name ) const { return get()->operator[]( name ); } + Field& operator[]( const char* name ) { return get()->operator[]( name ); } - const Field& field( const size_t& i ) const { return fieldset_->field( i ); } - Field& field( const size_t& i ) { return fieldset_->field( i ); } + const Field& field( const idx_t& i ) const { return get()->field( i ); } + Field& field( const idx_t& i ) { return get()->field( i ); } - std::vector field_names() const { return fieldset_->field_names(); } + std::vector field_names() const { return get()->field_names(); } - Field add( const Field& field ) { return fieldset_->add( field ); } + Field add( const Field& field ) { return get()->add( field ); } - bool has_field( const std::string& name ) const { return fieldset_->has_field( name ); } + bool has_field( const std::string& name ) const { return get()->has_field( name ); } - Field& field( const std::string& name ) const { return fieldset_->field( name ); } + Field& field( const std::string& name ) const { return get()->field( name ); } - iterator begin() { return fieldset_->begin(); } - iterator end() { return fieldset_->end(); } - const_iterator begin() const { return fieldset_->begin(); } - const_iterator end() const { return fieldset_->end(); } - const_iterator cbegin() const { return fieldset_->begin(); } - const_iterator cend() const { return fieldset_->end(); } + iterator begin() { return get()->begin(); } + iterator end() { return get()->end(); } + const_iterator begin() const { return get()->begin(); } + const_iterator end() const { return get()->end(); } + const_iterator cbegin() const { return get()->begin(); } + const_iterator cend() const { return get()->end(); } -private: // data - eckit::SharedPtr fieldset_; + void haloExchange( bool on_device = false ) const { get()->haloExchange( on_device ); } + void set_dirty( bool = true ) const; }; } // namespace atlas diff --git a/src/atlas/field/State.cc b/src/atlas/field/State.cc index 68fd1d808..80de91240 100644 --- a/src/atlas/field/State.cc +++ b/src/atlas/field/State.cc @@ -21,7 +21,7 @@ #include "atlas/field/Field.h" #include "atlas/grid/Grid.h" #include "atlas/mesh/Mesh.h" -#include "atlas/runtime/ErrorHandling.h" +#include "atlas/runtime/Exception.h" #include "atlas/runtime/Log.h" namespace atlas { @@ -73,19 +73,19 @@ util::Metadata& State::metadata() { } Field State::add( Field field ) { - ASSERT( field ); + ATLAS_ASSERT( field ); if ( field.name().empty() ) { std::stringstream new_name; new_name << "field_" << std::setw( 5 ) << std::setfill( '0' ) << fields_.size(); - ASSERT( !has( new_name.str() ) ); + ATLAS_ASSERT( !has( new_name.str() ) ); field.rename( new_name.str() ); } if ( has( field.name() ) ) { std::stringstream msg; msg << "Trying to add field '" << field.name() << "' to State, but State already has a field with this name."; - throw eckit::Exception( msg.str(), Here() ); + throw_AssertionFailed( msg.str(), Here() ); } fields_[field.name()] = field; return field; @@ -93,9 +93,9 @@ Field State::add( Field field ) { const Field& State::field( const std::string& name ) const { if ( !has( name ) ) { - std::stringstream msg; + std::ostringstream msg; msg << "Trying to access field `" << name << "' in State, but no field with this name is present in State."; - throw eckit::Exception( msg.str(), Here() ); + throw_AssertionFailed( msg.str(), Here() ); } return fields_.find( name )->second; } @@ -104,20 +104,20 @@ Field& State::field( const std::string& name ) { return const_cast( static_cast( this )->field( name ) ); } -const Field& State::field( const size_t idx ) const { - if ( idx >= fields_.size() ) { - std::stringstream msg; - msg << "Trying to access field in State with index " << idx << ", but there exist only " << fields_.size() +const Field& State::field( const idx_t idx ) const { + if ( idx >= size() ) { + std::ostringstream msg; + msg << "Trying to access field in State with index " << idx << ", but there exist only " << size() << " fields in State."; - throw eckit::Exception( msg.str(), Here() ); + throw_AssertionFailed( msg.str(), Here() ); } FieldMap::const_iterator it = fields_.begin(); - for ( size_t i = 0; i < idx; ++i ) + for ( idx_t i = 0; i < idx; ++i ) ++it; return it->second; } -Field& State::field( const size_t idx ) { +Field& State::field( const idx_t idx ) { return const_cast( static_cast( this )->field( idx ) ); } @@ -135,7 +135,7 @@ void State::remove( const std::string& name ) { if ( fields_.find( name ) == fields_.end() ) { std::stringstream msg; msg << "Trying to remove field '" << name << "' from State, but it is not present in State."; - throw eckit::Exception( msg.str(), Here() ); + throw_AssertionFailed( msg.str(), Here() ); } fields_.erase( name ); } @@ -162,7 +162,7 @@ StateGenerator* StateGeneratorFactory::build( const std::string& name, const eck Log::error() << "StateFactories are:" << std::endl; for ( j = m->begin(); j != m->end(); ++j ) Log::error() << " " << ( *j ).first << std::endl; - throw eckit::SeriousBug( std::string( "No StateGeneratorFactory called " ) + name ); + throw_Exception( std::string( "No StateGeneratorFactory called " ) + name, Here() ); } return ( *j ).second->make( param ); @@ -197,7 +197,7 @@ StateGeneratorFactory::StateGeneratorFactory( const std::string& name ) : name_( eckit::AutoLock lock( local_mutex ); - ASSERT( m->find( name ) == m->end() ); + ATLAS_ASSERT( m->find( name ) == m->end() ); ( *m )[name] = this; } @@ -216,56 +216,47 @@ State* atlas__State__new() { } void atlas__State__initialize( State* This, const char* generator, const eckit::Parametrisation* params ) { - ASSERT( This ); - ASSERT( params ); - ATLAS_ERROR_HANDLING( This->initialize( std::string( generator ), *params ) ); + ATLAS_ASSERT( This != nullptr, "Reason: Use of uninitialised atlas_State" ); + This->initialize( std::string( generator ), *params ); } void atlas__State__delete( State* This ) { - ASSERT( This ); + ATLAS_ASSERT( This != nullptr, "Reason: Use of uninitialised atlas_State" ); delete This; } void atlas__State__add( State* This, FieldImpl* field ) { - ASSERT( This ); - ATLAS_ERROR_HANDLING( This->add( field ); ); + ATLAS_ASSERT( This != nullptr, "Reason: Use of uninitialised atlas_State" ); + This->add( field ); } void atlas__State__remove( State* This, const char* name ) { - ASSERT( This ); - ATLAS_ERROR_HANDLING( This->remove( name ); ); + ATLAS_ASSERT( This != nullptr, "Reason: Use of uninitialised atlas_State" ); + This->remove( name ); } int atlas__State__has( State* This, const char* name ) { - ASSERT( This ); - int has_field( 0 ); - ATLAS_ERROR_HANDLING( has_field = This->has( name ); ); - return has_field; + ATLAS_ASSERT( This != nullptr, "Reason: Use of uninitialised atlas_State" ); + return This->has( name ); } FieldImpl* atlas__State__field_by_name( State* This, const char* name ) { - ASSERT( This ); - FieldImpl* field( 0 ); - ATLAS_ERROR_HANDLING( field = This->field( std::string( name ) ).get(); ); - return field; + ATLAS_ASSERT( This != nullptr, "Reason: Use of uninitialised atlas_State" ); + return This->field( std::string( name ) ).get(); } -FieldImpl* atlas__State__field_by_index( State* This, int index ) { - ASSERT( This ); - FieldImpl* field( 0 ); - ATLAS_ERROR_HANDLING( field = This->field( index ).get() ); - return field; +FieldImpl* atlas__State__field_by_index( State* This, idx_t index ) { + ATLAS_ASSERT( This != nullptr, "Reason: Use of uninitialised atlas_State" ); + return This->field( index ).get(); } -int atlas__State__size( const State* This ) { - ASSERT( This ); - int nb_fields( 0 ); - ATLAS_ERROR_HANDLING( nb_fields = This->size(); ); - return nb_fields; +idx_t atlas__State__size( const State* This ) { + ATLAS_ASSERT( This != nullptr, "Reason: Use of uninitialised atlas_State" ); + return This->size(); } util::Metadata* atlas__State__metadata( State* This ) { - ASSERT( This ); + ATLAS_ASSERT( This != nullptr, "Reason: Use of uninitialised atlas_State" ); return &This->metadata(); } } diff --git a/src/atlas/field/State.h b/src/atlas/field/State.h index 4c86d1e76..96f5be5fd 100644 --- a/src/atlas/field/State.h +++ b/src/atlas/field/State.h @@ -13,11 +13,12 @@ #pragma once +#include + #include "atlas/field/Field.h" #include "atlas/util/Config.h" #include "atlas/util/Metadata.h" -#include "eckit/memory/Owned.h" -#include "eckit/memory/SharedPtr.h" +#include "atlas/util/Object.h" namespace eckit { class Parametrisation; @@ -29,10 +30,7 @@ namespace field { /** * \brief State class that owns a collection of fields */ -class State : public eckit::Owned { -public: // types - typedef eckit::SharedPtr Ptr; - +class State : public util::Object { public: // methods //-- Constructors State(); @@ -46,12 +44,12 @@ class State : public eckit::Owned { bool has( const std::string& name ) const { return ( fields_.find( name ) != fields_.end() ); } std::vector field_names() const; - const Field& field( const size_t idx ) const; - Field& field( const size_t idx ); - size_t size() const { return fields_.size(); } + const Field& field( const idx_t idx ) const; + Field& field( const idx_t idx ); + idx_t size() const { return static_cast( fields_.size() ); } - const Field& operator[]( const size_t idx ) const { return field( idx ); } - Field& operator[]( const size_t idx ) { return field( idx ); } + const Field& operator[]( const idx_t idx ) const { return field( idx ); } + Field& operator[]( const idx_t idx ) { return field( idx ); } const Field& operator[]( const std::string& name ) const { return field( name ); } Field& operator[]( const std::string& name ) { return field( name ); } @@ -77,7 +75,7 @@ class State : public eckit::Owned { //------------------------------------------------------------------------------------------------------ -class StateGenerator : public eckit::Owned { +class StateGenerator : public util::Object { public: StateGenerator( const eckit::Parametrisation& = util::Config() ); @@ -131,8 +129,8 @@ void atlas__State__add( State* This, FieldImpl* field ); void atlas__State__remove( State* This, const char* name ); int atlas__State__has( State* This, const char* name ); FieldImpl* atlas__State__field_by_name( State* This, const char* name ); -FieldImpl* atlas__State__field_by_index( State* This, int index ); -int atlas__State__size( const State* This ); +FieldImpl* atlas__State__field_by_index( State* This, idx_t index ); +idx_t atlas__State__size( const State* This ); util::Metadata* atlas__State__metadata( State* This ); } diff --git a/src/atlas/field/detail/FieldImpl.cc b/src/atlas/field/detail/FieldImpl.cc index 19500835c..a9e5eb3ba 100644 --- a/src/atlas/field/detail/FieldImpl.cc +++ b/src/atlas/field/detail/FieldImpl.cc @@ -8,21 +8,14 @@ * nor does it submit to any jurisdiction. */ +#include #include -#include -#include - -#include "eckit/exception/Exceptions.h" -#include "eckit/memory/ScopedPtr.h" #include "atlas/array/MakeView.h" #include "atlas/field/FieldCreator.h" #include "atlas/field/detail/FieldImpl.h" #include "atlas/functionspace/FunctionSpace.h" -#include "atlas/grid/Grid.h" -#include "atlas/mesh/Mesh.h" -#include "atlas/runtime/ErrorHandling.h" -#include "atlas/runtime/Log.h" +#include "atlas/runtime/Exception.h" namespace atlas { namespace field { @@ -33,11 +26,11 @@ namespace field { FieldImpl* FieldImpl::create( const eckit::Parametrisation& params ) { std::string creator_factory; if ( params.get( "creator", creator_factory ) ) { - eckit::ScopedPtr creator( field::FieldCreatorFactory::build( creator_factory, params ) ); + std::unique_ptr creator( field::FieldCreatorFactory::build( creator_factory, params ) ); return creator->createField( params ); } else - throw eckit::Exception( + throw_Exception( "Could not find parameter 'creator' " "in Parametrisation for call to FieldImpl::create()" ); } @@ -52,7 +45,8 @@ FieldImpl* FieldImpl::create( const std::string& name, array::Array* array ) { // ------------------------------------------------------------------------- -FieldImpl::FieldImpl( const std::string& name, array::DataType datatype, const array::ArrayShape& shape ) { +FieldImpl::FieldImpl( const std::string& name, array::DataType datatype, const array::ArrayShape& shape ) : + functionspace_( new FunctionSpace() ) { array_ = array::Array::create( datatype, shape ); array_->attach(); rename( name ); @@ -60,7 +54,7 @@ FieldImpl::FieldImpl( const std::string& name, array::DataType datatype, const a set_variables( 0 ); } -FieldImpl::FieldImpl( const std::string& name, array::Array* array ) { +FieldImpl::FieldImpl( const std::string& name, array::Array* array ) : functionspace_( new FunctionSpace() ) { array_ = array; array_->attach(); rename( name ); @@ -71,17 +65,26 @@ FieldImpl::FieldImpl( const std::string& name, array::Array* array ) { FieldImpl::~FieldImpl() { array_->detach(); if ( array_->owners() == 0 ) delete array_; + delete functionspace_; } size_t FieldImpl::footprint() const { size_t size = sizeof( *this ); - size += functionspace_.footprint(); + size += functionspace_->footprint(); size += array_->footprint(); size += metadata_.footprint(); size += name_.capacity() * sizeof( std::string::value_type ); return size; } +bool FieldImpl::dirty() const { + return metadata().getBool( "dirty", true ); +} + +void FieldImpl::set_dirty( bool value ) const { + const_cast( *this ).metadata().set( "dirty", value ); +} + void FieldImpl::dump( std::ostream& os ) const { print( os, true ); } @@ -131,232 +134,26 @@ void FieldImpl::resize( const array::ArrayShape& shape ) { array_->resize( shape ); } -void FieldImpl::insert( size_t idx1, size_t size1 ) { +void FieldImpl::insert( idx_t idx1, idx_t size1 ) { array_->insert( idx1, size1 ); } void FieldImpl::set_functionspace( const FunctionSpace& functionspace ) { - functionspace_ = functionspace; -} - -// ------------------------------------------------------------------ -// C wrapper interfaces to C++ routines - -namespace { -template -void atlas__Field__host_data_specf( FieldImpl* This, Value*& data, int& rank, int*& shapef, int*& stridesf ) { - ATLAS_ERROR_HANDLING( ASSERT( This ); This->array().accMap(); data = This->host_data(); - shapef = const_cast( This->shapef().data() ); - stridesf = const_cast( This->stridesf().data() ); rank = This->shapef().size(); ); -} -} // namespace - -extern "C" { - -FieldImpl* atlas__Field__wrap_int_specf( const char* name, int data[], int rank, int shapef[], int stridesf[] ) { - ATLAS_ERROR_HANDLING( array::ArrayShape shape; shape.resize( rank ); array::ArrayStrides strides; - strides.resize( rank ); size_t jf = rank - 1; for ( int j = 0; j < rank; ++j ) { - shape[j] = shapef[jf]; - strides[j] = stridesf[jf]; - --jf; - } FieldImpl * field; - { - Field wrapped( std::string( name ), data, array::ArraySpec( shape, strides ) ); - field = wrapped.get(); - field->attach(); - } field->detach(); - ASSERT( field ); return field; ); - return 0; -} - -FieldImpl* atlas__Field__wrap_long_specf( const char* name, long data[], int rank, int shapef[], int stridesf[] ) { - ATLAS_ERROR_HANDLING( array::ArrayShape shape; shape.resize( rank ); array::ArrayStrides strides; - strides.resize( rank ); size_t jf = rank - 1; for ( int j = 0; j < rank; ++j ) { - shape[j] = shapef[jf]; - strides[j] = stridesf[jf]; - --jf; - } FieldImpl * field; - { - Field wrapped( std::string( name ), data, array::ArraySpec( shape, strides ) ); - field = wrapped.get(); - field->attach(); - } field->detach(); - ASSERT( field ); return field; ); - return 0; -} - -FieldImpl* atlas__Field__wrap_float_specf( const char* name, float data[], int rank, int shapef[], int stridesf[] ) { - ATLAS_ERROR_HANDLING( array::ArrayShape shape; shape.resize( rank ); array::ArrayStrides strides; - strides.resize( rank ); size_t jf = rank - 1; for ( int j = 0; j < rank; ++j ) { - shape[j] = shapef[jf]; - strides[j] = stridesf[jf]; - --jf; - } FieldImpl * field; - { - Field wrapped( std::string( name ), data, array::ArraySpec( shape, strides ) ); - field = wrapped.get(); - field->attach(); - } field->detach(); - ASSERT( field ); return field; ); - return 0; -} - -FieldImpl* atlas__Field__wrap_double_specf( const char* name, double data[], int rank, int shapef[], int stridesf[] ) { - ATLAS_ERROR_HANDLING( array::ArrayShape shape; shape.resize( rank ); array::ArrayStrides strides; - strides.resize( rank ); size_t jf = rank - 1; for ( int j = 0; j < rank; ++j ) { - shape[j] = shapef[jf]; - strides[j] = stridesf[jf]; - --jf; - } FieldImpl * field; - { - Field wrapped( std::string( name ), data, array::ArraySpec( shape, strides ) ); - field = wrapped.get(); - field->attach(); - } field->detach(); - ASSERT( field ); return field; ); - return 0; -} - -FieldImpl* atlas__Field__create( eckit::Parametrisation* params ) { - ATLAS_ERROR_HANDLING( ASSERT( params ); FieldImpl * field; { - Field f( *params ); - field = f.get(); - field->attach(); - } field->detach(); - - ASSERT( field ); return field; ); - return 0; -} - -void atlas__Field__delete( FieldImpl* This ) { - delete This; -} - -const char* atlas__Field__name( FieldImpl* This ) { - ATLAS_ERROR_HANDLING( ASSERT( This ); return This->name().c_str(); ); - return 0; -} - -void atlas__Field__datatype( FieldImpl* This, char*& datatype, int& size, int& allocated ) { - ATLAS_ERROR_HANDLING( ASSERT( This ); std::string s = This->datatype().str(); size = s.size() + 1; - datatype = new char[size]; strcpy( datatype, s.c_str() ); allocated = true; ); -} - -int atlas__Field__size( FieldImpl* This ) { - ATLAS_ERROR_HANDLING( ASSERT( This ); return This->size(); ); - return 0; -} - -int atlas__Field__rank( FieldImpl* This ) { - ATLAS_ERROR_HANDLING( ASSERT( This ); return This->rank(); ); - return 0; -} - -int atlas__Field__kind( FieldImpl* This ) { - ATLAS_ERROR_HANDLING( ASSERT( This ); return This->datatype().kind(); ); - return 0; -} - -double atlas__Field__bytes( FieldImpl* This ) { - ATLAS_ERROR_HANDLING( ASSERT( This ); return This->bytes(); ); - return 0; + *functionspace_ = functionspace; } -int atlas__Field__levels( FieldImpl* This ) { - ATLAS_ERROR_HANDLING( ASSERT( This ); return This->levels(); ); - return 0; +const FunctionSpace& FieldImpl::functionspace() const { + return *functionspace_; } -util::Metadata* atlas__Field__metadata( FieldImpl* This ) { - ATLAS_ERROR_HANDLING( ASSERT( This ); return &This->metadata(); ); - return 0; -} - -int atlas__Field__has_functionspace( FieldImpl* This ) { - ATLAS_ERROR_HANDLING( ASSERT( This ); return ( This->functionspace() != 0 ); ); - return 0; -} - -const functionspace::FunctionSpaceImpl* atlas__Field__functionspace( FieldImpl* This ) { - ATLAS_ERROR_HANDLING( ASSERT( This ); return This->functionspace().get(); ); - return 0; -} - -void atlas__Field__shapef( FieldImpl* This, int*& shape, int& rank ) { - ATLAS_ERROR_HANDLING( ASSERT( This ); shape = const_cast( &This->shapef().front() ); - rank = This->shapef().size(); ); -} - -void atlas__Field__host_data_int_specf( FieldImpl* This, int*& data, int& rank, int*& shapef, int*& stridesf ) { - atlas__Field__host_data_specf( This, data, rank, shapef, stridesf ); -} - -void atlas__Field__host_data_long_specf( FieldImpl* This, long*& data, int& rank, int*& shapef, int*& stridesf ) { - atlas__Field__host_data_specf( This, data, rank, shapef, stridesf ); -} - -void atlas__Field__host_data_float_specf( FieldImpl* This, float*& data, int& rank, int*& shapef, int*& stridesf ) { - atlas__Field__host_data_specf( This, data, rank, shapef, stridesf ); -} - -void atlas__Field__host_data_double_specf( FieldImpl* This, double*& data, int& rank, int*& shapef, int*& stridesf ) { - atlas__Field__host_data_specf( This, data, rank, shapef, stridesf ); -} - -void atlas__Field__device_data_int_specf( FieldImpl* This, int*& data, int& rank, int*& shapef, int*& stridesf ) { - ATLAS_ERROR_HANDLING( ASSERT( This ); data = This->device_data(); - shapef = const_cast( This->shapef().data() ); - stridesf = const_cast( This->stridesf().data() ); rank = This->shapef().size(); ); -} - -void atlas__Field__device_data_long_specf( FieldImpl* This, long*& data, int& rank, int*& shapef, int*& stridesf ) { - ATLAS_ERROR_HANDLING( ASSERT( This ); data = This->device_data(); - shapef = const_cast( This->shapef().data() ); - stridesf = const_cast( This->stridesf().data() ); rank = This->shapef().size(); ); -} - -void atlas__Field__device_data_float_specf( FieldImpl* This, float*& data, int& rank, int*& shapef, int*& stridesf ) { - ATLAS_ERROR_HANDLING( ASSERT( This ); data = This->device_data(); - shapef = const_cast( This->shapef().data() ); - stridesf = const_cast( This->stridesf().data() ); rank = This->shapef().size(); ); -} - -void atlas__Field__device_data_double_specf( FieldImpl* This, double*& data, int& rank, int*& shapef, int*& stridesf ) { - ATLAS_ERROR_HANDLING( ASSERT( This ); data = This->device_data(); - shapef = const_cast( This->shapef().data() ); - stridesf = const_cast( This->stridesf().data() ); rank = This->shapef().size(); ); -} - -int atlas__Field__host_needs_update( const FieldImpl* This ) { - return This->hostNeedsUpdate(); -} - -int atlas__Field__device_needs_update( const FieldImpl* This ) { - return This->deviceNeedsUpdate(); -} - -void atlas__Field__rename( FieldImpl* This, const char* name ) { - ATLAS_ERROR_HANDLING( ASSERT( This ); This->rename( std::string( name ) ); ); -} - -void atlas__Field__set_levels( FieldImpl* This, int levels ) { - ATLAS_ERROR_HANDLING( ASSERT( This ); This->set_levels( levels ); ); -} - -void atlas__Field__set_functionspace( FieldImpl* This, const functionspace::FunctionSpaceImpl* functionspace ) { - ATLAS_ERROR_HANDLING( ASSERT( This ); ASSERT( functionspace ); This->set_functionspace( functionspace ); ); +void FieldImpl::haloExchange( bool on_device ) const { + if ( dirty() ) { + ATLAS_ASSERT( functionspace() ); + functionspace().haloExchange( Field( this ), on_device ); + set_dirty( false ); + } } -void atlas__Field__clone_to_device( FieldImpl* This ) { - This->cloneToDevice(); -} -void atlas__Field__clone_from_device( FieldImpl* This ) { - This->cloneFromDevice(); -} -void atlas__Field__sync_host_device( FieldImpl* This ) { - This->syncHostDevice(); -} -} // ------------------------------------------------------------------ diff --git a/src/atlas/field/detail/FieldImpl.h b/src/atlas/field/detail/FieldImpl.h index 7413365bc..98fbb4533 100644 --- a/src/atlas/field/detail/FieldImpl.h +++ b/src/atlas/field/detail/FieldImpl.h @@ -16,24 +16,27 @@ #include #include -#include "eckit/memory/Owned.h" +#include "atlas/util/Object.h" #include "atlas/array.h" #include "atlas/array/ArrayUtil.h" #include "atlas/array/DataType.h" -#include "atlas/functionspace/FunctionSpace.h" #include "atlas/util/Metadata.h" namespace eckit { class Parametrisation; } +namespace atlas { +class FunctionSpace; +} // namespace atlas + namespace atlas { namespace field { //---------------------------------------------------------------------------------------------------------------------- -class FieldImpl : public eckit::Owned { +class FieldImpl : public util::Object { public: // Static methods /// @brief Create field from parametrisation static FieldImpl* create( const eckit::Parametrisation& ); @@ -49,11 +52,6 @@ class FieldImpl : public eckit::Owned { /// @brief Create field with given name, and take ownership of given Array static FieldImpl* create( const std::string& name, array::Array* ); - /// @brief Create field with given name, and share ownership of given Array - /// @note nawd: Not so sure we should go this route - /// static FieldImpl* create( const std::string& name, const - /// eckit::SharedPtr& ); - /// @brief Create field by wrapping existing data, Datatype of template and /// ArraySpec template @@ -71,10 +69,6 @@ class FieldImpl : public eckit::Owned { /// Transfer ownership of Array FieldImpl( const std::string& name, array::Array* ); - /// Share ownership of Array - /// @note We could go this route... - /// Field(const std::string& name, const eckit::SharedPtr& ); - public: // Destructor virtual ~FieldImpl(); @@ -108,7 +102,7 @@ class FieldImpl : public eckit::Owned { /// @brief Resize field to given shape void resize( const array::ArrayShape& ); - void insert( size_t idx1, size_t size1 ); + void insert( idx_t idx1, idx_t size1 ); /// @brief Shape of this field in Fortran style (reverse order of C style) const std::vector& shapef() const { return array_->shapef(); } @@ -123,19 +117,19 @@ class FieldImpl : public eckit::Owned { const array::ArrayStrides& strides() const { return array_->strides(); } /// @brief Shape of this field associated to index 'i' - size_t shape( size_t i ) const { return array_->shape( i ); } + idx_t shape( idx_t i ) const { return array_->shape( i ); } /// @brief Stride of this field associated to index 'i' - size_t stride( size_t i ) const { return array_->stride( i ); } + idx_t stride( idx_t i ) const { return array_->stride( i ); } /// @brief Number of values stored in this field - size_t size() const { return array_->size(); } + idx_t size() const { return array_->size(); } /// @brief Rank of field - size_t rank() const { return array_->rank(); } + idx_t rank() const { return array_->rank(); } /// @brief Number of bytes occupied by the values of this field - double bytes() const { return array_->bytes(); } + size_t bytes() const { return array_->bytes(); } /// @brief Output information of field friend std::ostream& operator<<( std::ostream& os, const FieldImpl& v ); @@ -144,17 +138,21 @@ class FieldImpl : public eckit::Owned { void dump( std::ostream& os ) const; /// Metadata that is more intrinsic to the Field, and queried often - void set_levels( size_t n ) { metadata().set( "levels", n ); } - void set_variables( size_t n ) { metadata().set( "variables", n ); } - size_t levels() const { return metadata().get( "levels" ); } - size_t variables() const { return metadata().get( "variables" ); } + void set_levels( idx_t n ) { metadata().set( "levels", n ); } + void set_variables( idx_t n ) { metadata().set( "variables", n ); } + idx_t levels() const { return metadata().get( "levels" ); } + idx_t variables() const { return metadata().get( "variables" ); } void set_functionspace( const FunctionSpace& ); - const FunctionSpace& functionspace() const { return functionspace_; } + const FunctionSpace& functionspace() const; /// @brief Return the memory footprint of the Field size_t footprint() const; + bool dirty() const; + + void set_dirty( bool = true ) const; + // -- dangerous methods template DATATYPE const* host_data() const { @@ -191,6 +189,8 @@ class FieldImpl : public eckit::Owned { void reactivateDeviceWriteViews() const { array_->reactivateDeviceWriteViews(); } void reactivateHostWriteViews() const { array_->reactivateHostWriteViews(); } + void haloExchange( bool on_device = false ) const; + private: // methods void print( std::ostream& os, bool dump = false ) const; @@ -198,7 +198,7 @@ class FieldImpl : public eckit::Owned { mutable std::string name_; util::Metadata metadata_; array::Array* array_; - FunctionSpace functionspace_; + FunctionSpace* functionspace_; }; //---------------------------------------------------------------------------------------------------------------------- @@ -210,61 +210,17 @@ FieldImpl* FieldImpl::create( const std::string& name, const array::ArrayShape& template FieldImpl* FieldImpl::wrap( const std::string& name, DATATYPE* data, const array::ArraySpec& spec ) { - return create( name, array::Array::wrap( data, spec ) ); + FieldImpl* wrapped = create( name, array::Array::wrap( data, spec ) ); + wrapped->set_dirty( false ); + return wrapped; } template FieldImpl* FieldImpl::wrap( const std::string& name, DATATYPE* data, const array::ArrayShape& shape ) { - return create( name, array::Array::wrap( data, shape ) ); -} - -//---------------------------------------------------------------------------------------------------------------------- - -// C wrapper interfaces to C++ routines -// #define Char char -extern "C" { -FieldImpl* atlas__Field__wrap_int_specf( const char* name, int data[], int rank, int shapef[], int stridesf[] ); -FieldImpl* atlas__Field__wrap_long_specf( const char* name, long data[], int rank, int shapef[], int stridesf[] ); -FieldImpl* atlas__Field__wrap_float_specf( const char* name, float data[], int rank, int shapef[], int stridesf[] ); -FieldImpl* atlas__Field__wrap_double_specf( const char* name, double data[], int rank, int shapef[], int stridesf[] ); -FieldImpl* atlas__Field__create( eckit::Parametrisation* params ); -void atlas__Field__delete( FieldImpl* This ); -const char* atlas__Field__name( FieldImpl* This ); -void atlas__Field__datatype( FieldImpl* This, char*& datatype, int& size, int& allocated ); -int atlas__Field__kind( FieldImpl* This ); -int atlas__Field__rank( FieldImpl* This ); -int atlas__Field__size( FieldImpl* This ); -int atlas__Field__levels( FieldImpl* This ); -double atlas__Field__bytes( FieldImpl* This ); -void atlas__Field__shapef( FieldImpl* This, int*& shape, int& rank ); -void atlas__Field__host_data_int_specf( FieldImpl* This, int*& field_data, int& rank, int*& field_shapef, - int*& field_stridesf ); -void atlas__Field__host_data_long_specf( FieldImpl* This, long*& field_data, int& rank, int*& field_shapef, - int*& field_stridesf ); -void atlas__Field__host_data_float_specf( FieldImpl* This, float*& field_data, int& rank, int*& field_shapef, - int*& field_stridesf ); -void atlas__Field__host_data_double_specf( FieldImpl* This, double*& field_data, int& rank, int*& field_shapef, - int*& field_stridesf ); -void atlas__Field__device_data_int_specf( FieldImpl* This, int*& field_data, int& rank, int*& field_shapef, - int*& field_stridesf ); -void atlas__Field__device_data_long_specf( FieldImpl* This, long*& field_data, int& rank, int*& field_shapef, - int*& field_stridesf ); -void atlas__Field__device_data_float_specf( FieldImpl* This, float*& field_data, int& rank, int*& field_shapef, - int*& field_stridesf ); -void atlas__Field__device_data_double_specf( FieldImpl* This, double*& field_data, int& rank, int*& field_shapef, - int*& field_stridesf ); -util::Metadata* atlas__Field__metadata( FieldImpl* This ); -const functionspace::FunctionSpaceImpl* atlas__Field__functionspace( FieldImpl* This ); -void atlas__Field__rename( FieldImpl* This, const char* name ); -void atlas__Field__set_levels( FieldImpl* This, int levels ); -void atlas__Field__set_functionspace( FieldImpl* This, const functionspace::FunctionSpaceImpl* functionspace ); -int atlas__Field__host_needs_update( const FieldImpl* This ); -int atlas__Field__device_needs_update( const FieldImpl* This ); -void atlas__Field__clone_to_device( FieldImpl* This ); -void atlas__Field__clone_from_device( FieldImpl* This ); -void atlas__Field__sync_host_device( FieldImpl* This ); + FieldImpl* wrapped = create( name, array::Array::wrap( data, shape ) ); + wrapped->set_dirty( false ); + return wrapped; } -// #undef Char //---------------------------------------------------------------------------------------------------------------------- diff --git a/src/atlas/field/detail/FieldInterface.cc b/src/atlas/field/detail/FieldInterface.cc new file mode 100644 index 000000000..9553a2b0d --- /dev/null +++ b/src/atlas/field/detail/FieldInterface.cc @@ -0,0 +1,280 @@ +/* + * (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 "atlas/field/Field.h" +#include "atlas/field/detail/FieldImpl.h" +#include "atlas/functionspace/FunctionSpace.h" +#include "atlas/runtime/Exception.h" + +namespace atlas { +namespace field { + +// ------------------------------------------------------------------ +// C wrapper interfaces to C++ routines + +namespace { +template +void atlas__Field__data_specf( FieldImpl* This, Value*& data, int& rank, int*& shapef, int*& stridesf ) { + ATLAS_ASSERT( This != nullptr, "Cannot access data of uninitialised atlas_Field" ); + if ( This->datatype() != array::make_datatype() ) { + throw_Exception( "Datatype mismatch for accessing field data" ); + } + This->array().accMap(); + data = This->data(); + shapef = const_cast( This->shapef().data() ); + stridesf = const_cast( This->stridesf().data() ); + rank = This->shapef().size(); +} +} // namespace + +extern "C" { + +FieldImpl* atlas__Field__wrap_int_specf( const char* name, int data[], int rank, int shapef[], int stridesf[] ) { + array::ArrayShape shape; + shape.resize( rank ); + array::ArrayStrides strides; + strides.resize( rank ); + idx_t jf = rank - 1; + for ( int j = 0; j < rank; ++j ) { + shape[j] = shapef[jf]; + strides[j] = stridesf[jf]; + --jf; + } + FieldImpl* field; + { + Field wrapped( std::string( name ), data, array::ArraySpec( shape, strides ) ); + field = wrapped.get(); + field->attach(); + } + field->detach(); + ATLAS_ASSERT( field ); + return field; +} + +FieldImpl* atlas__Field__wrap_long_specf( const char* name, long data[], int rank, int shapef[], int stridesf[] ) { + array::ArrayShape shape; + shape.resize( rank ); + array::ArrayStrides strides; + strides.resize( rank ); + idx_t jf = rank - 1; + for ( int j = 0; j < rank; ++j ) { + shape[j] = shapef[jf]; + strides[j] = stridesf[jf]; + --jf; + } + FieldImpl* field; + { + Field wrapped( std::string( name ), data, array::ArraySpec( shape, strides ) ); + field = wrapped.get(); + field->attach(); + } + field->detach(); + ATLAS_ASSERT( field ); + return field; +} + +FieldImpl* atlas__Field__wrap_float_specf( const char* name, float data[], int rank, int shapef[], int stridesf[] ) { + array::ArrayShape shape; + shape.resize( rank ); + array::ArrayStrides strides; + strides.resize( rank ); + idx_t jf = rank - 1; + for ( int j = 0; j < rank; ++j ) { + shape[j] = shapef[jf]; + strides[j] = stridesf[jf]; + --jf; + } + FieldImpl* field; + { + Field wrapped( std::string( name ), data, array::ArraySpec( shape, strides ) ); + field = wrapped.get(); + field->attach(); + } + field->detach(); + ATLAS_ASSERT( field ); + return field; +} + +FieldImpl* atlas__Field__wrap_double_specf( const char* name, double data[], int rank, int shapef[], int stridesf[] ) { + array::ArrayShape shape; + shape.resize( rank ); + array::ArrayStrides strides; + strides.resize( rank ); + idx_t jf = rank - 1; + for ( int j = 0; j < rank; ++j ) { + shape[j] = shapef[jf]; + strides[j] = stridesf[jf]; + --jf; + } + FieldImpl* field; + { + Field wrapped( std::string( name ), data, array::ArraySpec( shape, strides ) ); + field = wrapped.get(); + field->attach(); + } + field->detach(); + ATLAS_ASSERT( field ); + return field; +} + +FieldImpl* atlas__Field__create( eckit::Parametrisation* params ) { + ATLAS_ASSERT( params != nullptr ); + FieldImpl* field; + { + Field f( *params ); + field = f.get(); + field->attach(); + } + field->detach(); + ATLAS_ASSERT( field ); + return field; +} + +void atlas__Field__delete( FieldImpl* This ) { + delete This; +} + +const char* atlas__Field__name( FieldImpl* This ) { + ATLAS_ASSERT( This != nullptr, "Cannot access name of uninitialised atlas_Field" ); + return This->name().c_str(); +} + +void atlas__Field__datatype( FieldImpl* This, char*& datatype, int& size, int& allocated ) { + ATLAS_ASSERT( This != nullptr, "Cannot access datatype of uninitialised atlas_Field" ); + std::string s = This->datatype().str(); + size = s.size() + 1; + datatype = new char[size]; + strcpy( datatype, s.c_str() ); + allocated = true; +} + +int atlas__Field__size( FieldImpl* This ) { + ATLAS_ASSERT( This != nullptr, "Cannot access size of uninitialised atlas_Field" ); + return This->size(); +} + +int atlas__Field__rank( FieldImpl* This ) { + ATLAS_ASSERT( This != nullptr, "Cannot access rank of uninitialised atlas_Field" ); + return This->rank(); +} + +int atlas__Field__kind( FieldImpl* This ) { + ATLAS_ASSERT( This != nullptr, "Cannot access data kind of uninitialised atlas_Field" ); + return This->datatype().kind(); +} + +double atlas__Field__bytes( FieldImpl* This ) { + ATLAS_ASSERT( This != nullptr, "Cannot access bytes occupied by uninitialised atlas_Field" ); + return This->bytes(); +} + +int atlas__Field__levels( FieldImpl* This ) { + ATLAS_ASSERT( This != nullptr, "Cannot access levels of uninitialised atlas_Field" ); + return This->levels(); +} + +util::Metadata* atlas__Field__metadata( FieldImpl* This ) { + ATLAS_ASSERT( This != nullptr, "Cannot access metadata of uninitialised atlas_Field" ); + return &This->metadata(); +} + +int atlas__Field__has_functionspace( FieldImpl* This ) { + ATLAS_ASSERT( This != nullptr, "Cannot access uninitialised atlas_Field" ); + return ( This->functionspace() != 0 ); +} + +const functionspace::FunctionSpaceImpl* atlas__Field__functionspace( FieldImpl* This ) { + ATLAS_ASSERT( This != nullptr, "Cannot access uninitialised atlas_Field" ); + return This->functionspace().get(); +} + +void atlas__Field__shapef( FieldImpl* This, int*& shape, int& rank ) { + ATLAS_ASSERT( This != nullptr, "Cannot access bytes occupied by uninitialised atlas_Field" ); + shape = const_cast( &This->shapef().front() ); + rank = This->shapef().size(); +} + +void atlas__Field__data_int_specf( FieldImpl* This, int*& data, int& rank, int*& shapef, int*& stridesf ) { + atlas__Field__data_specf( This, data, rank, shapef, stridesf ); +} + +void atlas__Field__data_long_specf( FieldImpl* This, long*& data, int& rank, int*& shapef, int*& stridesf ) { + atlas__Field__data_specf( This, data, rank, shapef, stridesf ); +} + +void atlas__Field__data_float_specf( FieldImpl* This, float*& data, int& rank, int*& shapef, int*& stridesf ) { + atlas__Field__data_specf( This, data, rank, shapef, stridesf ); +} + +void atlas__Field__data_double_specf( FieldImpl* This, double*& data, int& rank, int*& shapef, int*& stridesf ) { + atlas__Field__data_specf( This, data, rank, shapef, stridesf ); +} + +int atlas__Field__host_needs_update( const FieldImpl* This ) { + return This->hostNeedsUpdate(); +} + +int atlas__Field__device_needs_update( const FieldImpl* This ) { + return This->deviceNeedsUpdate(); +} + +void atlas__Field__rename( FieldImpl* This, const char* name ) { + ATLAS_ASSERT( This, "Cannot rename uninitialised atlas_Field" ); + This->rename( std::string( name ) ); +} + +void atlas__Field__set_levels( FieldImpl* This, int levels ) { + ATLAS_ASSERT( This != nullptr, "Cannot set levels of uninitialised atlas_Field" ); + This->set_levels( levels ); +} + +void atlas__Field__set_functionspace( FieldImpl* This, const functionspace::FunctionSpaceImpl* functionspace ) { + ATLAS_ASSERT( This != nullptr, "Cannot set functionspace in uninitialised atlas_Field" ); + ATLAS_ASSERT( functionspace != nullptr, "Cannot set uninitialised atlas_FunctionSpace in atlas_Field" ); + This->set_functionspace( functionspace ); +} + +void atlas__Field__clone_to_device( FieldImpl* This ) { + ATLAS_ASSERT( This != nullptr, "Cannot access uninitialised atlas_Field" ); + This->cloneToDevice(); +} + +void atlas__Field__clone_from_device( FieldImpl* This ) { + ATLAS_ASSERT( This != nullptr, "Cannot access uninitialised atlas_Field" ); + This->cloneFromDevice(); +} + +void atlas__Field__sync_host_device( FieldImpl* This ) { + ATLAS_ASSERT( This != nullptr, "Cannot access uninitialised atlas_Field" ); + This->syncHostDevice(); +} + +void atlas__Field__set_dirty( FieldImpl* This, int value ) { + ATLAS_ASSERT( This != nullptr, "Cannot access uninitialised atlas_Field" ); + This->set_dirty( value ); +} + +int atlas__Field__dirty( FieldImpl* This ) { + ATLAS_ASSERT( This != nullptr, "Cannot access uninitialised atlas_Field" ); + return This->dirty(); +} + +void atlas__Field__halo_exchange( FieldImpl* This, int on_device ) { + ATLAS_ASSERT( This != nullptr, "Cannot halo-exchange uninitialised atlas_Field" ); + return This->haloExchange( on_device ); +} +} + +// ------------------------------------------------------------------ + +} // namespace field +} // namespace atlas diff --git a/src/atlas/field/detail/FieldInterface.h b/src/atlas/field/detail/FieldInterface.h new file mode 100644 index 000000000..830f654ed --- /dev/null +++ b/src/atlas/field/detail/FieldInterface.h @@ -0,0 +1,71 @@ +/* + * (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. + */ + +/// @author Willem Deconinck +/// @date Sep 2014 + +#pragma once + +#include "atlas/field/detail/FieldImpl.h" + +namespace atlas { +namespace functionspace { +class FunctionSpaceImpl; +} +} // namespace atlas + +namespace atlas { +namespace field { + +//---------------------------------------------------------------------------------------------------------------------- + +// C wrapper interfaces to C++ routines +extern "C" { +FieldImpl* atlas__Field__wrap_int_specf( const char* name, int data[], int rank, int shapef[], int stridesf[] ); +FieldImpl* atlas__Field__wrap_long_specf( const char* name, long data[], int rank, int shapef[], int stridesf[] ); +FieldImpl* atlas__Field__wrap_float_specf( const char* name, float data[], int rank, int shapef[], int stridesf[] ); +FieldImpl* atlas__Field__wrap_double_specf( const char* name, double data[], int rank, int shapef[], int stridesf[] ); +FieldImpl* atlas__Field__create( eckit::Parametrisation* params ); +void atlas__Field__delete( FieldImpl* This ); +const char* atlas__Field__name( FieldImpl* This ); +void atlas__Field__datatype( FieldImpl* This, char*& datatype, int& size, int& allocated ); +int atlas__Field__kind( FieldImpl* This ); +int atlas__Field__rank( FieldImpl* This ); +int atlas__Field__size( FieldImpl* This ); +int atlas__Field__levels( FieldImpl* This ); +double atlas__Field__bytes( FieldImpl* This ); +void atlas__Field__shapef( FieldImpl* This, int*& shape, int& rank ); +void atlas__Field__data_int_specf( FieldImpl* This, int*& field_data, int& rank, int*& field_shapef, + int*& field_stridesf ); +void atlas__Field__data_long_specf( FieldImpl* This, long*& field_data, int& rank, int*& field_shapef, + int*& field_stridesf ); +void atlas__Field__data_float_specf( FieldImpl* This, float*& field_data, int& rank, int*& field_shapef, + int*& field_stridesf ); +void atlas__Field__data_double_specf( FieldImpl* This, double*& field_data, int& rank, int*& field_shapef, + int*& field_stridesf ); +util::Metadata* atlas__Field__metadata( FieldImpl* This ); +const functionspace::FunctionSpaceImpl* atlas__Field__functionspace( FieldImpl* This ); +void atlas__Field__rename( FieldImpl* This, const char* name ); +void atlas__Field__set_levels( FieldImpl* This, int levels ); +void atlas__Field__set_functionspace( FieldImpl* This, const functionspace::FunctionSpaceImpl* functionspace ); +int atlas__Field__host_needs_update( const FieldImpl* This ); +int atlas__Field__device_needs_update( const FieldImpl* This ); +void atlas__Field__clone_to_device( FieldImpl* This ); +void atlas__Field__clone_from_device( FieldImpl* This ); +void atlas__Field__sync_host_device( FieldImpl* This ); +void atlas__Field__set_dirty( FieldImpl* This, int value ); +void atlas__Field__halo_exchange( FieldImpl* This, int on_device ); +int atlas__Field__dirty( FieldImpl* This ); +} + +//---------------------------------------------------------------------------------------------------------------------- + +} // namespace field +} // namespace atlas diff --git a/src/atlas/functionspace/EdgeColumns.cc b/src/atlas/functionspace/EdgeColumns.cc index e90d6d78f..41bc5462c 100644 --- a/src/atlas/functionspace/EdgeColumns.cc +++ b/src/atlas/functionspace/EdgeColumns.cc @@ -20,6 +20,7 @@ #include "atlas/mesh/HybridElements.h" #include "atlas/mesh/IsGhostNode.h" #include "atlas/mesh/Mesh.h" +#include "atlas/mesh/actions/BuildEdges.h" #include "atlas/mesh/actions/BuildHalo.h" #include "atlas/mesh/actions/BuildParallelFields.h" #include "atlas/mesh/actions/BuildPeriodicBoundaries.h" @@ -27,11 +28,13 @@ #include "atlas/parallel/GatherScatter.h" #include "atlas/parallel/HaloExchange.h" #include "atlas/parallel/omp/omp.h" -#include "atlas/runtime/ErrorHandling.h" +#include "atlas/runtime/Exception.h" #include "atlas/runtime/Log.h" #include "atlas/runtime/Trace.h" #include "atlas/util/detail/Cache.h" +#include "atlas/field/detail/FieldImpl.h" + #if ATLAS_HAVE_FORTRAN #define REMOTE_IDX_BASE 1 #else @@ -74,7 +77,7 @@ class EdgeColumnsHaloExchangeCache : public util::Cache get_or_create( const Mesh& mesh ) { + util::ObjectHandle get_or_create( const Mesh& mesh ) { creator_type creator = std::bind( &EdgeColumnsHaloExchangeCache::create, mesh ); return Base::get_or_create( key( *mesh.get() ), creator ); } @@ -91,7 +94,7 @@ class EdgeColumnsHaloExchangeCache : public util::CacheattachObserver( instance() ); value_type* value = new value_type(); value->setup( array::make_view( mesh.edges().partition() ).data(), - array::make_view( mesh.edges().remote_index() ).data(), REMOTE_IDX_BASE, + array::make_view( mesh.edges().remote_index() ).data(), REMOTE_IDX_BASE, mesh.edges().size() ); return value; } @@ -108,7 +111,7 @@ class EdgeColumnsGatherScatterCache : public util::Cache get_or_create( const Mesh& mesh ) { + util::ObjectHandle get_or_create( const Mesh& mesh ) { creator_type creator = std::bind( &EdgeColumnsGatherScatterCache::create, mesh ); return Base::get_or_create( key( *mesh.get() ), creator ); } @@ -125,7 +128,7 @@ class EdgeColumnsGatherScatterCache : public util::CacheattachObserver( instance() ); value_type* value = new value_type(); value->setup( array::make_view( mesh.edges().partition() ).data(), - array::make_view( mesh.edges().remote_index() ).data(), REMOTE_IDX_BASE, + array::make_view( mesh.edges().remote_index() ).data(), REMOTE_IDX_BASE, array::make_view( mesh.edges().global_index() ).data(), mesh.edges().size() ); return value; } @@ -142,7 +145,7 @@ class EdgeColumnsChecksumCache : public util::Cache get_or_create( const Mesh& mesh ) { + util::ObjectHandle get_or_create( const Mesh& mesh ) { creator_type creator = std::bind( &EdgeColumnsChecksumCache::create, mesh ); return Base::get_or_create( key( *mesh.get() ), creator ); } @@ -158,7 +161,7 @@ class EdgeColumnsChecksumCache : public util::CacheattachObserver( instance() ); value_type* value = new value_type(); - eckit::SharedPtr gather( + util::ObjectHandle gather( EdgeColumnsGatherScatterCache::instance().get_or_create( mesh ) ); value->setup( gather ); return value; @@ -171,31 +174,32 @@ void EdgeColumns::set_field_metadata( const eckit::Configuration& config, Field& bool global( false ); if ( config.get( "global", global ) ) { if ( global ) { - size_t owner( 0 ); + idx_t owner( 0 ); config.get( "owner", owner ); field.metadata().set( "owner", owner ); } } field.metadata().set( "global", global ); - size_t levels( nb_levels_ ); + idx_t levels( nb_levels_ ); config.get( "levels", levels ); field.set_levels( levels ); - size_t variables( 0 ); + idx_t variables( 0 ); config.get( "variables", variables ); field.set_variables( variables ); } -size_t EdgeColumns::config_size( const eckit::Configuration& config ) const { - size_t size = nb_edges(); +idx_t EdgeColumns::config_size( const eckit::Configuration& config ) const { + const idx_t rank = static_cast( mpi::comm().rank() ); + idx_t size = nb_edges(); bool global( false ); if ( config.get( "global", global ) ) { if ( global ) { - size_t owner( 0 ); + idx_t owner( 0 ); config.get( "owner", owner ); - size_t _nb_edges_global( nb_edges_global() ); - size = ( mpi::comm().rank() == owner ? _nb_edges_global : 0 ); + idx_t _nb_edges_global( nb_edges_global() ); + size = ( rank == owner ? _nb_edges_global : 0 ); } } return size; @@ -203,7 +207,7 @@ size_t EdgeColumns::config_size( const eckit::Configuration& config ) const { array::DataType EdgeColumns::config_datatype( const eckit::Configuration& config ) const { array::DataType::kind_t kind; - if ( !config.get( "datatype", kind ) ) throw eckit::AssertionFailed( "datatype missing", Here() ); + if ( !config.get( "datatype", kind ) ) throw_Exception( "datatype missing", Here() ); return array::DataType( kind ); } @@ -213,8 +217,8 @@ std::string EdgeColumns::config_name( const eckit::Configuration& config ) const return name; } -size_t EdgeColumns::config_levels( const eckit::Configuration& config ) const { - size_t levels( nb_levels_ ); +idx_t EdgeColumns::config_levels( const eckit::Configuration& config ) const { + idx_t levels( nb_levels_ ); config.get( "levels", levels ); return levels; } @@ -224,77 +228,49 @@ array::ArrayShape EdgeColumns::config_shape( const eckit::Configuration& config shape.push_back( config_size( config ) ); - size_t levels( nb_levels_ ); + idx_t levels( nb_levels_ ); config.get( "levels", levels ); if ( levels > 0 ) shape.push_back( levels ); - size_t variables( 0 ); + idx_t variables( 0 ); config.get( "variables", variables ); if ( variables > 0 ) shape.push_back( variables ); return shape; } -EdgeColumns::EdgeColumns( const Mesh& mesh, const eckit::Configuration& params ) : - mesh_( mesh ), - nb_levels_( 0 ), - edges_( mesh_.edges() ), - nb_edges_( 0 ) { - nb_levels_ = config_levels( params ); - - size_t mesh_halo( 0 ); - mesh.metadata().get( "halo", mesh_halo ); - - size_t halo = mesh_halo; - params.get( "halo", halo ); - - ASSERT( mesh_halo == halo ); - - constructor(); -} - -EdgeColumns::EdgeColumns( const Mesh& mesh, const mesh::Halo& halo, const eckit::Configuration& params ) : +EdgeColumns::EdgeColumns( const Mesh& mesh, const eckit::Configuration& config ) : mesh_( mesh ), - nb_levels_( 0 ), edges_( mesh_.edges() ), + nb_levels_( config.getInt( "levels", 0 ) ), nb_edges_( 0 ) { - size_t mesh_halo_size_; - mesh.metadata().get( "halo", mesh_halo_size_ ); - ASSERT( mesh_halo_size_ == halo.size() ); - - nb_levels_ = config_levels( params ); - - constructor(); -} - -EdgeColumns::EdgeColumns( const Mesh& mesh, const mesh::Halo& halo ) : - mesh_( mesh ), - nb_levels_( 0 ), - edges_( mesh_.edges() ), - nb_edges_( 0 ) { - size_t mesh_halo_size_; - mesh.metadata().get( "halo", mesh_halo_size_ ); - ASSERT( mesh_halo_size_ == halo.size() ); - constructor(); -} - -void EdgeColumns::constructor() { - ATLAS_TRACE( "EdgeColumns()" ); - - nb_edges_ = mesh().edges().size(); + ATLAS_TRACE(); + if ( config.has( "halo" ) ) { halo_ = mesh::Halo( config.getInt( "halo" ) ); } + else { + halo_ = mesh::Halo( mesh_ ); + } - // ATLAS_TRACE_SCOPE("HaloExchange") { - // halo_exchange_ = EdgeColumnsHaloExchangeCache::instance().get( mesh_ ); - // } + auto get_nb_edges_from_metadata = [&]() { + idx_t _nb_edges( 0 ); + std::stringstream ss; + ss << "nb_edges_including_halo[" << halo_.size() << "]"; + mesh_.metadata().get( ss.str(), _nb_edges ); + return _nb_edges; + }; - // ATLAS_TRACE_SCOPE("Setup gather_scatter") { - // gather_scatter_.reset( EdgeColumnsGatherScatterCache::instance().get( - // mesh_ ) ); - // } + mesh::actions::build_nodes_parallel_fields( mesh_.nodes() ); + mesh::actions::build_periodic_boundaries( mesh_ ); - // ATLAS_TRACE_SCOPE("Setup checksum") { - // checksum_.reset( EdgeColumnsChecksumCache::instance().get( mesh_ ) ); - // } + if ( halo_.size() > 0 ) { + mesh::actions::build_halo( mesh_, halo_.size() ); + nb_edges_ = get_nb_edges_from_metadata(); + } + if ( !nb_edges_ ) { + mesh::actions::build_edges( mesh_, config ); + mesh::actions::build_edges_parallel_fields( mesh_ ); + nb_edges_ = get_nb_edges_from_metadata(); + } + ATLAS_ASSERT( nb_edges_ ); } EdgeColumns::~EdgeColumns() {} @@ -309,18 +285,17 @@ std::string EdgeColumns::distribution() const { return mesh().metadata().getString( "distribution" ); } -size_t EdgeColumns::nb_edges() const { +idx_t EdgeColumns::nb_edges() const { return nb_edges_; } -size_t EdgeColumns::nb_edges_global() const { +idx_t EdgeColumns::nb_edges_global() const { if ( nb_edges_global_ >= 0 ) return nb_edges_global_; nb_edges_global_ = gather().glb_dof(); return nb_edges_global_; } Field EdgeColumns::createField( const eckit::Configuration& options ) const { - size_t nb_edges = config_size( options ); Field field( config_name( options ), config_datatype( options ), config_shape( options ) ); set_field_metadata( options, field ); return field; @@ -331,29 +306,30 @@ Field EdgeColumns::createField( const Field& other, const eckit::Configuration& option::variables( other.variables() ) | config ); } -void EdgeColumns::haloExchange( FieldSet& fieldset ) const { - for ( size_t f = 0; f < fieldset.size(); ++f ) { - Field& field = fieldset[f]; +void EdgeColumns::haloExchange( const FieldSet& fieldset, bool on_device ) const { + for ( idx_t f = 0; f < fieldset.size(); ++f ) { + Field& field = const_cast( fieldset )[f]; if ( field.datatype() == array::DataType::kind() ) { - halo_exchange().execute( field.array(), false ); + halo_exchange().execute( field.array(), on_device ); } else if ( field.datatype() == array::DataType::kind() ) { - halo_exchange().execute( field.array(), false ); + halo_exchange().execute( field.array(), on_device ); } else if ( field.datatype() == array::DataType::kind() ) { - halo_exchange().execute( field.array(), false ); + halo_exchange().execute( field.array(), on_device ); } else if ( field.datatype() == array::DataType::kind() ) { - halo_exchange().execute( field.array(), false ); + halo_exchange().execute( field.array(), on_device ); } else - throw eckit::Exception( "datatype not supported", Here() ); + throw_Exception( "datatype not supported", Here() ); + field.set_dirty( false ); } } -void EdgeColumns::haloExchange( Field& field ) const { +void EdgeColumns::haloExchange( const Field& field, bool on_device ) const { FieldSet fieldset; fieldset.add( field ); - haloExchange( fieldset ); + haloExchange( fieldset, on_device ); } const parallel::HaloExchange& EdgeColumns::halo_exchange() const { if ( halo_exchange_ ) return *halo_exchange_; @@ -362,13 +338,13 @@ const parallel::HaloExchange& EdgeColumns::halo_exchange() const { } void EdgeColumns::gather( const FieldSet& local_fieldset, FieldSet& global_fieldset ) const { - ASSERT( local_fieldset.size() == global_fieldset.size() ); + ATLAS_ASSERT( local_fieldset.size() == global_fieldset.size() ); - for ( size_t f = 0; f < local_fieldset.size(); ++f ) { - const Field& loc = local_fieldset[f]; - Field& glb = global_fieldset[f]; - const size_t nb_fields = 1; - size_t root( 0 ); + for ( idx_t f = 0; f < local_fieldset.size(); ++f ) { + const Field& loc = local_fieldset[f]; + Field& glb = global_fieldset[f]; + const idx_t nb_fields = 1; + idx_t root( 0 ); glb.metadata().get( "owner", root ); if ( loc.datatype() == array::DataType::kind() ) { parallel::Field loc_field( make_leveled_view( loc ) ); @@ -391,7 +367,7 @@ void EdgeColumns::gather( const FieldSet& local_fieldset, FieldSet& global_field gather().gather( &loc_field, &glb_field, nb_fields, root ); } else - throw eckit::Exception( "datatype not supported", Here() ); + throw_Exception( "datatype not supported", Here() ); } } @@ -414,13 +390,13 @@ const parallel::GatherScatter& EdgeColumns::scatter() const { } void EdgeColumns::scatter( const FieldSet& global_fieldset, FieldSet& local_fieldset ) const { - ASSERT( local_fieldset.size() == global_fieldset.size() ); + ATLAS_ASSERT( local_fieldset.size() == global_fieldset.size() ); - for ( size_t f = 0; f < local_fieldset.size(); ++f ) { - const Field& glb = global_fieldset[f]; - Field& loc = local_fieldset[f]; - const size_t nb_fields = 1; - size_t root( 0 ); + for ( idx_t f = 0; f < local_fieldset.size(); ++f ) { + const Field& glb = global_fieldset[f]; + Field& loc = local_fieldset[f]; + const idx_t nb_fields = 1; + idx_t root( 0 ); glb.metadata().get( "owner", root ); if ( loc.datatype() == array::DataType::kind() ) { @@ -444,7 +420,7 @@ void EdgeColumns::scatter( const FieldSet& global_fieldset, FieldSet& local_fiel scatter().scatter( &glb_field, &loc_field, nb_fields, root ); } else - throw eckit::Exception( "datatype not supported", Here() ); + throw_Exception( "datatype not supported", Here() ); glb.metadata().broadcast( loc.metadata(), root ); loc.metadata().set( "global", false ); @@ -464,10 +440,10 @@ std::string checksum_3d_field( const parallel::Checksum& checksum, const Field& array::ArrayView values = array::make_view( field ); array::ArrayT surface_field( field.shape( 0 ), field.shape( 2 ) ); array::ArrayView surface = array::make_view( surface_field ); - for ( size_t n = 0; n < values.shape( 0 ); ++n ) { - for ( size_t j = 0; j < surface.shape( 1 ); ++j ) { + for ( idx_t n = 0; n < values.shape( 0 ); ++n ) { + for ( idx_t j = 0; j < surface.shape( 1 ); ++j ) { surface( n, j ) = 0.; - for ( size_t l = 0; l < values.shape( 1 ); ++l ) + for ( idx_t l = 0; l < values.shape( 1 ); ++l ) surface( n, j ) += values( n, l, j ); } } @@ -483,7 +459,7 @@ std::string checksum_2d_field( const parallel::Checksum& checksum, const Field& std::string EdgeColumns::checksum( const FieldSet& fieldset ) const { eckit::MD5 md5; - for ( size_t f = 0; f < fieldset.size(); ++f ) { + for ( idx_t f = 0; f < fieldset.size(); ++f ) { const Field& field = fieldset[f]; if ( field.datatype() == array::DataType::kind() ) { if ( field.levels() ) @@ -510,7 +486,7 @@ std::string EdgeColumns::checksum( const FieldSet& fieldset ) const { md5 << checksum_2d_field( checksum(), field ); } else - throw eckit::Exception( "datatype not supported", Here() ); + throw_Exception( "datatype not supported", Here() ); } return md5; } @@ -535,36 +511,37 @@ extern "C" { //------------------------------------------------------------------------------ EdgeColumns* atlas__fs__EdgeColumns__new( Mesh::Implementation* mesh, const eckit::Configuration* config ) { - EdgeColumns* edges( 0 ); - ATLAS_ERROR_HANDLING( ASSERT( mesh ); Mesh m( mesh ); edges = new EdgeColumns( m, *config ); ); - return edges; + ATLAS_ASSERT( mesh != nullptr ); + Mesh m( mesh ); + return new EdgeColumns( m, *config ); } //------------------------------------------------------------------------------ void atlas__fs__EdgeColumns__delete( EdgeColumns* This ) { - ATLAS_ERROR_HANDLING( ASSERT( This ); delete ( This ); ); + ATLAS_ASSERT( This != nullptr ); + delete ( This ); } //------------------------------------------------------------------------------ int atlas__fs__EdgeColumns__nb_edges( const EdgeColumns* This ) { - ATLAS_ERROR_HANDLING( ASSERT( This ); return This->nb_edges(); ); - return 0; + ATLAS_ASSERT( This != nullptr ); + return This->nb_edges(); } //------------------------------------------------------------------------------ Mesh::Implementation* atlas__fs__EdgeColumns__mesh( EdgeColumns* This ) { - ATLAS_ERROR_HANDLING( ASSERT( This ); return This->mesh().get(); ); - return 0; + ATLAS_ASSERT( This != nullptr ); + return This->mesh().get(); } //------------------------------------------------------------------------------ mesh::Edges* atlas__fs__EdgeColumns__edges( EdgeColumns* This ) { - ATLAS_ERROR_HANDLING( ASSERT( This ); return &This->edges(); ); - return 0; + ATLAS_ASSERT( This != nullptr ); + return &This->edges(); } //------------------------------------------------------------------------------ @@ -573,13 +550,16 @@ using field::FieldImpl; using field::FieldSetImpl; field::FieldImpl* atlas__fs__EdgeColumns__create_field( const EdgeColumns* This, const eckit::Configuration* options ) { - ATLAS_ERROR_HANDLING( ASSERT( This ); ASSERT( options ); FieldImpl * field; { + ATLAS_ASSERT( This ); + ATLAS_ASSERT( options ); + FieldImpl* field; + { Field f = This->createField( *options ); field = f.get(); field->attach(); - } field->detach(); - return field ); - return 0; + } + field->detach(); + return field; } //------------------------------------------------------------------------------ @@ -587,8 +567,8 @@ field::FieldImpl* atlas__fs__EdgeColumns__create_field( const EdgeColumns* This, field::FieldImpl* atlas__fs__EdgeColumns__create_field_template( const EdgeColumns* This, const field::FieldImpl* field_template, const eckit::Configuration* options ) { - ASSERT( This ); - ASSERT( options ); + ATLAS_ASSERT( This ); + ATLAS_ASSERT( options ); FieldImpl* field; { Field f = This->createField( Field( field_template ), *options ); @@ -602,91 +582,121 @@ field::FieldImpl* atlas__fs__EdgeColumns__create_field_template( const EdgeColum // ----------------------------------------------------------------------------------- void atlas__fs__EdgeColumns__halo_exchange_fieldset( const EdgeColumns* This, field::FieldSetImpl* fieldset ) { - ATLAS_ERROR_HANDLING( ASSERT( This ); ASSERT( fieldset ); FieldSet f( fieldset ); This->haloExchange( f ); ); + ATLAS_ASSERT( This != nullptr ); + ATLAS_ASSERT( fieldset != nullptr ); + FieldSet f( fieldset ); + This->haloExchange( f ); } // ----------------------------------------------------------------------------------- void atlas__fs__EdgeColumns__halo_exchange_field( const EdgeColumns* This, field::FieldImpl* field ) { - ATLAS_ERROR_HANDLING( ASSERT( This ); ASSERT( field ); Field f( field ); This->haloExchange( f ); ); + ATLAS_ASSERT( This != nullptr ); + ATLAS_ASSERT( field != nullptr ); + Field f( field ); + This->haloExchange( f ); } // ----------------------------------------------------------------------------------- const parallel::HaloExchange* atlas__fs__EdgeColumns__get_halo_exchange( const EdgeColumns* This ) { - ATLAS_ERROR_HANDLING( ASSERT( This ); return &This->halo_exchange(); ); - return 0; + ATLAS_ASSERT( This != nullptr ); + return &This->halo_exchange(); } // ----------------------------------------------------------------------------------- void atlas__fs__EdgeColumns__gather_fieldset( const EdgeColumns* This, const field::FieldSetImpl* local, field::FieldSetImpl* global ) { - ATLAS_ERROR_HANDLING( ASSERT( This ); ASSERT( local ); ASSERT( global ); const FieldSet l( local ); - FieldSet g( global ); This->gather( l, g ); ); + ATLAS_ASSERT( This ); + ATLAS_ASSERT( local ); + ATLAS_ASSERT( global ); + const FieldSet l( local ); + FieldSet g( global ); + This->gather( l, g ); } // ----------------------------------------------------------------------------------- void atlas__fs__EdgeColumns__gather_field( const EdgeColumns* This, const field::FieldImpl* local, field::FieldImpl* global ) { - ATLAS_ERROR_HANDLING( ASSERT( This ); ASSERT( local ); ASSERT( global ); const Field l( local ); Field g( global ); - This->gather( l, g ); ); + ATLAS_ASSERT( This ); + ATLAS_ASSERT( local ); + ATLAS_ASSERT( global ); + const Field l( local ); + Field g( global ); + This->gather( l, g ); } // ----------------------------------------------------------------------------------- const parallel::GatherScatter* atlas__fs__EdgeColumns__get_gather( const EdgeColumns* This ) { - ATLAS_ERROR_HANDLING( ASSERT( This ); return &This->gather(); ); - return 0; + ATLAS_ASSERT( This ); + return &This->gather(); } // ----------------------------------------------------------------------------------- const parallel::GatherScatter* atlas__fs__EdgeColumns__get_scatter( const EdgeColumns* This ) { - ATLAS_ERROR_HANDLING( ASSERT( This ); return &This->scatter(); ); - return 0; + ATLAS_ASSERT( This ); + return &This->scatter(); } // ----------------------------------------------------------------------------------- void atlas__fs__EdgeColumns__scatter_fieldset( const EdgeColumns* This, const field::FieldSetImpl* global, field::FieldSetImpl* local ) { - ATLAS_ERROR_HANDLING( ASSERT( This ); ASSERT( local ); ASSERT( global ); const FieldSet g( global ); - FieldSet l( local ); This->scatter( g, l ); ); + ATLAS_ASSERT( This ); + ATLAS_ASSERT( local ); + ATLAS_ASSERT( global ); + const FieldSet g( global ); + FieldSet l( local ); + This->scatter( g, l ); } // ----------------------------------------------------------------------------------- void atlas__fs__EdgeColumns__scatter_field( const EdgeColumns* This, const field::FieldImpl* global, field::FieldImpl* local ) { - ATLAS_ERROR_HANDLING( ASSERT( This ); ASSERT( global ); ASSERT( local ); const Field g( global ); Field l( local ); - This->scatter( g, l ); ); + ATLAS_ASSERT( This ); + ATLAS_ASSERT( global ); + ATLAS_ASSERT( local ); + const Field g( global ); + Field l( local ); + This->scatter( g, l ); } // ----------------------------------------------------------------------------------- const parallel::Checksum* atlas__fs__EdgeColumns__get_checksum( const EdgeColumns* This ) { - ATLAS_ERROR_HANDLING( ASSERT( This ); return &This->checksum(); ); - return 0; + ATLAS_ASSERT( This ); + return &This->checksum(); } // ----------------------------------------------------------------------------------- void atlas__fs__EdgeColumns__checksum_fieldset( const EdgeColumns* This, const field::FieldSetImpl* fieldset, char*& checksum, int& size, int& allocated ) { - ATLAS_ERROR_HANDLING( ASSERT( This ); ASSERT( fieldset ); std::string checksum_str( This->checksum( fieldset ) ); - size = checksum_str.size(); checksum = new char[size + 1]; allocated = true; - strcpy( checksum, checksum_str.c_str() ); ); + ATLAS_ASSERT( This ); + ATLAS_ASSERT( fieldset ); + std::string checksum_str( This->checksum( fieldset ) ); + size = checksum_str.size(); + checksum = new char[size + 1]; + allocated = true; + strcpy( checksum, checksum_str.c_str() ); } // ----------------------------------------------------------------------------------- void atlas__fs__EdgeColumns__checksum_field( const EdgeColumns* This, const field::FieldImpl* field, char*& checksum, int& size, int& allocated ) { - ATLAS_ERROR_HANDLING( ASSERT( This ); ASSERT( field ); std::string checksum_str( This->checksum( field ) ); - size = checksum_str.size(); checksum = new char[size + 1]; allocated = true; - strcpy( checksum, checksum_str.c_str() ); ); + ATLAS_ASSERT( This ); + ATLAS_ASSERT( field ); + std::string checksum_str( This->checksum( field ) ); + size = checksum_str.size(); + checksum = new char[size + 1]; + allocated = true; + strcpy( checksum, checksum_str.c_str() ); } } @@ -702,23 +712,19 @@ EdgeColumns::EdgeColumns( const FunctionSpace& functionspace ) : FunctionSpace( functionspace ), functionspace_( dynamic_cast( get() ) ) {} -EdgeColumns::EdgeColumns( const Mesh& mesh, const mesh::Halo& halo, const eckit::Configuration& config ) : - FunctionSpace( new detail::EdgeColumns( mesh, halo, config ) ), - functionspace_( dynamic_cast( get() ) ) {} - -EdgeColumns::EdgeColumns( const Mesh& mesh, const mesh::Halo& halo ) : - FunctionSpace( new detail::EdgeColumns( mesh, halo ) ), +EdgeColumns::EdgeColumns( const Mesh& mesh, const eckit::Configuration& config ) : + FunctionSpace( new detail::EdgeColumns( mesh, config ) ), functionspace_( dynamic_cast( get() ) ) {} EdgeColumns::EdgeColumns( const Mesh& mesh ) : FunctionSpace( new detail::EdgeColumns( mesh ) ), functionspace_( dynamic_cast( get() ) ) {} -size_t EdgeColumns::nb_edges() const { +idx_t EdgeColumns::nb_edges() const { return functionspace_->nb_edges(); } -size_t EdgeColumns::nb_edges_global() const { // Only on MPI rank 0, will this be different from 0 +idx_t EdgeColumns::nb_edges_global() const { // Only on MPI rank 0, will this be different from 0 return functionspace_->nb_edges_global(); } @@ -730,14 +736,6 @@ const mesh::HybridElements& EdgeColumns::edges() const { return functionspace_->edges(); } -void EdgeColumns::haloExchange( FieldSet& fieldset ) const { - functionspace_->haloExchange( fieldset ); -} - -void EdgeColumns::haloExchange( Field& field ) const { - functionspace_->haloExchange( field ); -} - const parallel::HaloExchange& EdgeColumns::halo_exchange() const { return functionspace_->halo_exchange(); } diff --git a/src/atlas/functionspace/EdgeColumns.h b/src/atlas/functionspace/EdgeColumns.h index 65edb55de..edb4971e4 100644 --- a/src/atlas/functionspace/EdgeColumns.h +++ b/src/atlas/functionspace/EdgeColumns.h @@ -10,10 +10,9 @@ #pragma once -#include "eckit/memory/SharedPtr.h" - #include "atlas/field/FieldSet.h" #include "atlas/functionspace/FunctionSpace.h" +#include "atlas/functionspace/detail/FunctionSpaceImpl.h" #include "atlas/mesh/Halo.h" #include "atlas/mesh/Mesh.h" #include "atlas/option.h" @@ -42,19 +41,17 @@ namespace detail { class EdgeColumns : public FunctionSpaceImpl { public: - EdgeColumns( const Mesh&, const mesh::Halo&, const eckit::Configuration& ); - EdgeColumns( const Mesh&, const mesh::Halo& ); EdgeColumns( const Mesh&, const eckit::Configuration& = util::NoConfig() ); - virtual ~EdgeColumns(); + virtual ~EdgeColumns() override; - virtual std::string type() const { return "Edges"; } + virtual std::string type() const override { return "Edges"; } - virtual std::string distribution() const; + virtual std::string distribution() const override; - size_t nb_edges() const; - size_t nb_edges_global() const; // Only on MPI rank 0, will this be different from 0 - std::vector nb_edges_global_foreach_rank() const; + idx_t nb_edges() const; + idx_t nb_edges_global() const; // Only on MPI rank 0, will this be different from 0 + std::vector nb_edges_global_foreach_rank() const; const Mesh& mesh() const { return mesh_; } Mesh& mesh() { return mesh_; } @@ -64,14 +61,14 @@ class EdgeColumns : public FunctionSpaceImpl { // -- Field creation methods - virtual Field createField( const eckit::Configuration& ) const; + virtual Field createField( const eckit::Configuration& ) const override; - virtual Field createField( const Field&, const eckit::Configuration& ) const; + virtual Field createField( const Field&, const eckit::Configuration& ) const override; // -- Parallelisation aware methods - void haloExchange( FieldSet& ) const; - void haloExchange( Field& ) const; + virtual void haloExchange( const FieldSet&, bool on_device = false ) const override; + virtual void haloExchange( const Field&, bool on_device = false ) const override; const parallel::HaloExchange& halo_exchange() const; void gather( const FieldSet&, FieldSet& ) const; @@ -86,25 +83,27 @@ class EdgeColumns : public FunctionSpaceImpl { std::string checksum( const Field& ) const; const parallel::Checksum& checksum() const; + virtual idx_t size() const override { return nb_edges_; } + private: // methods - void constructor(); - size_t config_size( const eckit::Configuration& config ) const; + idx_t config_size( const eckit::Configuration& config ) const; array::DataType config_datatype( const eckit::Configuration& ) const; std::string config_name( const eckit::Configuration& ) const; - size_t config_levels( const eckit::Configuration& ) const; + idx_t config_levels( const eckit::Configuration& ) const; array::ArrayShape config_shape( const eckit::Configuration& ) const; void set_field_metadata( const eckit::Configuration&, Field& ) const; - size_t footprint() const; + virtual size_t footprint() const override; -private: // data - Mesh mesh_; // non-const because functionspace may modify mesh - size_t nb_levels_; +private: // data + Mesh mesh_; // non-const because functionspace may modify mesh mesh::HybridElements& edges_; // non-const because functionspace may modify mesh - size_t nb_edges_; + idx_t nb_levels_; + mesh::Halo halo_; + idx_t nb_edges_; mutable long nb_edges_global_{-1}; - mutable eckit::SharedPtr gather_scatter_; // without ghost - mutable eckit::SharedPtr halo_exchange_; - mutable eckit::SharedPtr checksum_; + mutable util::ObjectHandle gather_scatter_; // without ghost + mutable util::ObjectHandle halo_exchange_; + mutable util::ObjectHandle checksum_; }; // ------------------------------------------------------------------- @@ -152,24 +151,20 @@ class EdgeColumns : public FunctionSpace { public: EdgeColumns(); EdgeColumns( const FunctionSpace& ); - EdgeColumns( const Mesh&, const mesh::Halo&, const eckit::Configuration& ); - EdgeColumns( const Mesh& mesh, const mesh::Halo& ); + EdgeColumns( const Mesh&, const eckit::Configuration& ); EdgeColumns( const Mesh& mesh ); operator bool() const { return valid(); } bool valid() const { return functionspace_; } - size_t nb_edges() const; - size_t nb_edges_global() const; // Only on MPI rank 0, will this be different from 0 + idx_t nb_edges() const; + idx_t nb_edges_global() const; // Only on MPI rank 0, will this be different from 0 const Mesh& mesh() const; const mesh::HybridElements& edges() const; // -- Parallelisation aware methods - - void haloExchange( FieldSet& ) const; - void haloExchange( Field& ) const; const parallel::HaloExchange& halo_exchange() const; void gather( const FieldSet&, FieldSet& ) const; diff --git a/src/atlas/functionspace/FunctionSpace.cc b/src/atlas/functionspace/FunctionSpace.cc index 7fed4d8a1..b3563683d 100644 --- a/src/atlas/functionspace/FunctionSpace.cc +++ b/src/atlas/functionspace/FunctionSpace.cc @@ -8,117 +8,78 @@ * nor does it submit to any jurisdiction. */ -#include "atlas/functionspace/FunctionSpace.h" - -#include -#include -#include -#include - -#include "eckit/exception/Exceptions.h" -#include "eckit/types/Types.h" -#include "atlas/array/DataType.h" +#include "atlas/functionspace/FunctionSpace.h" #include "atlas/field/Field.h" -#include "atlas/field/detail/FieldImpl.h" -#include "atlas/library/config.h" -#include "atlas/mesh/actions/BuildParallelFields.h" -#include "atlas/runtime/ErrorHandling.h" +#include "atlas/functionspace/detail/FunctionSpaceImpl.h" namespace atlas { -namespace functionspace { -//----------------------------------------------------------------------------- +FunctionSpace::FunctionSpace() : Handle( new functionspace::NoFunctionSpace() ) {} -// C wrapper interfaces to C++ routines -extern "C" { -void atlas__FunctionSpace__delete( FunctionSpaceImpl* This ) { - ATLAS_ERROR_HANDLING( ASSERT( This ); delete This; This = 0; ); -} -void atlas__FunctionSpace__name( const FunctionSpaceImpl* This, char*& name, int& size ) { - ATLAS_ERROR_HANDLING( ASSERT( This ); std::string s = This->type(); size = s.size() + 1; name = new char[size]; - strcpy( name, s.c_str() ); ); +std::string FunctionSpace::type() const { + return get()->type(); } -field::FieldImpl* atlas__FunctionSpace__create_field( const FunctionSpaceImpl* This, - const eckit::Configuration* options ) { - ATLAS_ERROR_HANDLING( ASSERT( This ); ASSERT( options ); field::FieldImpl * field; { - Field f = This->createField( *options ); - field = f.get(); - field->attach(); - } field->detach(); - return field ); - return 0; +FunctionSpace::operator bool() const { + return get()->operator bool(); } -//------------------------------------------------------------------------------ - -field::FieldImpl* atlas__FunctionSpace__create_field_template( const FunctionSpaceImpl* This, - const field::FieldImpl* field_template, - const eckit::Configuration* options ) { - ASSERT( This ); - ASSERT( options ); - field::FieldImpl* field; - { - Field f = This->createField( Field( field_template ), *options ); - field = f.get(); - field->attach(); - } - field->detach(); - return field; -} +size_t FunctionSpace::footprint() const { + return get()->footprint(); } -// ------------------------------------------------------------------ - -atlas::Field FunctionSpaceImpl::createField( const atlas::Field& field ) const { - return createField( field, util::NoConfig() ); +Field FunctionSpace::createField( const eckit::Configuration& config ) const { + return get()->createField( config ); } -Field NoFunctionSpace::createField( const eckit::Configuration& ) const { - NOTIMP; -} -Field NoFunctionSpace::createField( const Field&, const eckit::Configuration& ) const { - NOTIMP; +Field FunctionSpace::createField( const Field& other ) const { + return get()->createField( other ); } -// ------------------------------------------------------------------ - -} // namespace functionspace - -// ------------------------------------------------------------------ - -FunctionSpace::FunctionSpace() : functionspace_( new functionspace::NoFunctionSpace() ) {} - -FunctionSpace::FunctionSpace( const Implementation* functionspace ) : functionspace_( functionspace ) {} - -FunctionSpace::FunctionSpace( const FunctionSpace& functionspace ) : functionspace_( functionspace.functionspace_ ) {} +Field FunctionSpace::createField( const Field& other, const eckit::Configuration& config ) const { + return get()->createField( other, config ); +} -std::string FunctionSpace::type() const { - return functionspace_->type(); +std::string FunctionSpace::distribution() const { + return get()->distribution(); } -FunctionSpace::operator bool() const { - return functionspace_->operator bool(); +void FunctionSpace::haloExchange( const Field& field, bool on_device ) const { + return get()->haloExchange( field, on_device ); } -size_t FunctionSpace::footprint() const { - return functionspace_->footprint(); +idx_t FunctionSpace::size() const { + return get()->size(); } -Field FunctionSpace::createField( const eckit::Configuration& config ) const { - return functionspace_->createField( config ); +void FunctionSpace::haloExchange( const FieldSet& fields, bool on_device ) const { + return get()->haloExchange( fields, on_device ); } -Field FunctionSpace::createField( const Field& other, const eckit::Configuration& config ) const { - return functionspace_->createField( other, config ); + +template +Field FunctionSpace::createField() const { + return get()->createField(); } -std::string FunctionSpace::distribution() const { - return functionspace_->distribution(); +template +Field FunctionSpace::createField( const eckit::Configuration& options ) const { + return get()->createField( options ); } +template Field FunctionSpace::createField() const; +template Field FunctionSpace::createField() const; +template Field FunctionSpace::createField() const; +template Field FunctionSpace::createField() const; + +template Field FunctionSpace::createField( const eckit::Configuration& ) const; +template Field FunctionSpace::createField( const eckit::Configuration& ) const; +template Field FunctionSpace::createField( const eckit::Configuration& ) const; +template Field FunctionSpace::createField( const eckit::Configuration& ) const; + + // ------------------------------------------------------------------ } // namespace atlas diff --git a/src/atlas/functionspace/FunctionSpace.h b/src/atlas/functionspace/FunctionSpace.h index 753552b3c..e069e0302 100644 --- a/src/atlas/functionspace/FunctionSpace.h +++ b/src/atlas/functionspace/FunctionSpace.h @@ -12,166 +12,62 @@ #include -#include "eckit/memory/Owned.h" -#include "eckit/memory/SharedPtr.h" +#include "atlas/library/config.h" +#include "atlas/util/ObjectHandle.h" -#include "atlas/field/Field.h" -#include "atlas/option.h" -#include "atlas/util/Config.h" +namespace eckit { +class Configuration; +} namespace atlas { +class Field; +class FieldSet; namespace functionspace { - -#define FunctionspaceT_nonconst typename FunctionSpaceImpl::remove_const::type -#define FunctionspaceT_const typename FunctionSpaceImpl::add_const::type - -/// @brief FunctionSpace class helps to interprete Fields. -/// @note Abstract base class -class FunctionSpaceImpl : public eckit::Owned { -private: - template - struct remove_const { - typedef T type; - }; - template - struct remove_const { - typedef T type; - }; - - template - struct add_const { - typedef const typename remove_const::type type; - }; - template - struct add_const { - typedef const T type; - }; - -public: - FunctionSpaceImpl() {} - virtual ~FunctionSpaceImpl() = 0; - virtual std::string type() const = 0; - virtual operator bool() const { return true; } - virtual size_t footprint() const = 0; - - virtual atlas::Field createField( const eckit::Configuration& ) const = 0; - - virtual atlas::Field createField( const atlas::Field&, const eckit::Configuration& ) const = 0; - - atlas::Field createField( const atlas::Field& ) const; - - template - atlas::Field createField( const eckit::Configuration& ) const; - - template - atlas::Field createField() const; - - const util::Metadata& metadata() const { return metadata_; } - util::Metadata& metadata() { return metadata_; } - - template - FunctionspaceT_nonconst* cast(); - - template - FunctionspaceT_const* cast() const; - - virtual std::string distribution() const = 0; - -private: - util::Metadata metadata_; -}; - -inline FunctionSpaceImpl::~FunctionSpaceImpl() {} - -template -inline Field FunctionSpaceImpl::createField( const eckit::Configuration& options ) const { - return createField( option::datatypeT() | options ); -} - -template -inline Field FunctionSpaceImpl::createField() const { - return createField( option::datatypeT() ); -} - -template -inline FunctionspaceT_nonconst* FunctionSpaceImpl::cast() { - return dynamic_cast( this ); -} - -template -inline FunctionspaceT_const* FunctionSpaceImpl::cast() const { - return dynamic_cast( this ); -} - -#undef FunctionspaceT_const -#undef FunctionspaceT_nonconst - -//------------------------------------------------------------------------------------------------------ - -/// @brief Dummy Functionspace class that evaluates to false -class NoFunctionSpace : public FunctionSpaceImpl { -public: - NoFunctionSpace() {} - virtual ~NoFunctionSpace() {} - virtual std::string type() const { return "NoFunctionSpace"; } - virtual operator bool() const { return false; } - virtual size_t footprint() const { return sizeof( *this ); } - virtual std::string distribution() const { return std::string(); } - - virtual Field createField( const eckit::Configuration& ) const; - virtual Field createField( const Field&, const eckit::Configuration& ) const; -}; - -//------------------------------------------------------------------------------------------------------ - -// C wrapper interfaces to C++ routines -extern "C" { -void atlas__FunctionSpace__delete( FunctionSpaceImpl* This ); -void atlas__FunctionSpace__name( const FunctionSpaceImpl* This, char*& name, int& size ); -field::FieldImpl* atlas__FunctionSpace__create_field( const FunctionSpaceImpl* This, - const eckit::Configuration* options ); -field::FieldImpl* atlas__FunctionSpace__create_field_template( const FunctionSpaceImpl* This, - const field::FieldImpl* field_template, - const eckit::Configuration* options ); +class FunctionSpaceImpl; } +} // namespace atlas -//------------------------------------------------------------------------------------------------------ - -} // namespace functionspace +namespace atlas { //------------------------------------------------------------------------------------------------------ -class FunctionSpace { -public: - using Implementation = functionspace::FunctionSpaceImpl; - -private: - eckit::SharedPtr functionspace_; - +class FunctionSpace : public util::ObjectHandle { public: + using Handle::Handle; FunctionSpace(); - FunctionSpace( const Implementation* ); - FunctionSpace( const FunctionSpace& ); std::string type() const; operator bool() const; size_t footprint() const; std::string distribution() const; - const Implementation* get() const { return functionspace_.get(); } + Field createField( const eckit::Configuration& ) const; - atlas::Field createField( const eckit::Configuration& ) const; + Field createField( const Field& ) const; + Field createField( const Field&, const eckit::Configuration& ) const; - atlas::Field createField( const atlas::Field&, const eckit::Configuration& = util::NoConfig() ) const; + template + Field createField( const eckit::Configuration& ) const; template - Field createField( const eckit::Configuration& = util::NoConfig() ) const; + Field createField() const; + + void haloExchange( const FieldSet&, bool on_device = false ) const; + void haloExchange( const Field&, bool on_device = false ) const; + + idx_t size() const; }; -template -Field FunctionSpace::createField( const eckit::Configuration& options ) const { - return functionspace_->createField( options ); -} +//------------------------------------------------------------------------------------------------------ + +extern template Field FunctionSpace::createField() const; +extern template Field FunctionSpace::createField() const; +extern template Field FunctionSpace::createField() const; +extern template Field FunctionSpace::createField() const; +extern template Field FunctionSpace::createField( const eckit::Configuration& ) const; +extern template Field FunctionSpace::createField( const eckit::Configuration& ) const; +extern template Field FunctionSpace::createField( const eckit::Configuration& ) const; +extern template Field FunctionSpace::createField( const eckit::Configuration& ) const; //------------------------------------------------------------------------------------------------------ diff --git a/src/atlas/functionspace/NodeColumns.cc b/src/atlas/functionspace/NodeColumns.cc index d73e60f53..42c950afd 100644 --- a/src/atlas/functionspace/NodeColumns.cc +++ b/src/atlas/functionspace/NodeColumns.cc @@ -16,7 +16,9 @@ #include "eckit/utils/MD5.h" -#include "atlas/array/ArrayView.h" +#include "atlas/array.h" +#include "atlas/field/Field.h" +#include "atlas/field/FieldSet.h" #include "atlas/functionspace/NodeColumns.h" #include "atlas/grid/Grid.h" #include "atlas/library/config.h" @@ -30,10 +32,11 @@ #include "atlas/parallel/GatherScatter.h" #include "atlas/parallel/HaloExchange.h" #include "atlas/parallel/omp/omp.h" -#include "atlas/runtime/ErrorHandling.h" +#include "atlas/runtime/Exception.h" #include "atlas/runtime/Trace.h" #include "atlas/util/detail/Cache.h" + #undef atlas_omp_critical_ordered #define atlas_omp_critical_ordered atlas_omp_critical @@ -108,7 +111,7 @@ class NodeColumnsHaloExchangeCache : public util::Cache get_or_create( const Mesh& mesh, long halo ) { + util::ObjectHandle get_or_create( const Mesh& mesh, long halo ) { creator_type creator = std::bind( &NodeColumnsHaloExchangeCache::create, mesh, halo ); return Base::get_or_create( key( *mesh.get(), halo ), creator ); } @@ -132,11 +135,11 @@ class NodeColumnsHaloExchangeCache : public util::Cachesetup( array::make_view( mesh.nodes().partition() ).data(), - array::make_view( mesh.nodes().remote_index() ).data(), REMOTE_IDX_BASE, nb_nodes ); + array::make_view( mesh.nodes().remote_index() ).data(), REMOTE_IDX_BASE, nb_nodes ); return value; } @@ -153,7 +156,7 @@ class NodeColumnsGatherScatterCache : public util::Cache get_or_create( const Mesh& mesh ) { + util::ObjectHandle get_or_create( const Mesh& mesh ) { creator_type creator = std::bind( &NodeColumnsGatherScatterCache::create, mesh ); return Base::get_or_create( key( *mesh.get() ), creator ); } @@ -173,8 +176,8 @@ class NodeColumnsGatherScatterCache : public util::Cache mask( mesh.nodes().size() ); - const size_t npts = mask.size(); - atlas_omp_parallel_for( size_t n = 0; n < npts; ++n ) { + const idx_t npts = mask.size(); + atlas_omp_parallel_for( idx_t n = 0; n < npts; ++n ) { mask[n] = is_ghost( n ) ? 1 : 0; // --> This would add periodic west-bc to the gather, but means that @@ -186,7 +189,7 @@ class NodeColumnsGatherScatterCache : public util::Cachesetup( array::make_view( mesh.nodes().partition() ).data(), - array::make_view( mesh.nodes().remote_index() ).data(), REMOTE_IDX_BASE, + array::make_view( mesh.nodes().remote_index() ).data(), REMOTE_IDX_BASE, array::make_view( mesh.nodes().global_index() ).data(), mask.data(), mesh.nodes().size() ); return value; @@ -204,7 +207,7 @@ class NodeColumnsChecksumCache : public util::Cache get_or_create( const Mesh& mesh ) { + util::ObjectHandle get_or_create( const Mesh& mesh ) { creator_type creator = std::bind( &NodeColumnsChecksumCache::create, mesh ); return Base::get_or_create( key( *mesh.get() ), creator ); } @@ -220,7 +223,7 @@ class NodeColumnsChecksumCache : public util::CacheattachObserver( instance() ); value_type* value = new value_type(); - eckit::SharedPtr gather( + util::ObjectHandle gather( NodeColumnsGatherScatterCache::instance().get_or_create( mesh ) ); value->setup( gather ); return value; @@ -233,17 +236,13 @@ NodeColumns::NodeColumns( Mesh mesh, const eckit::Configuration& config ) : mesh_( mesh ), nodes_( mesh_.nodes() ), nb_levels_( config.getInt( "levels", 0 ) ), - nb_nodes_( nodes_.size() ) { + nb_nodes_( 0 ) { ATLAS_TRACE(); if ( config.has( "halo" ) ) { halo_ = mesh::Halo( config.getInt( "halo" ) ); } else { halo_ = mesh::Halo( mesh ); } - constructor(); -} - -void NodeColumns::constructor() { - ASSERT( mesh_ ); + ATLAS_ASSERT( mesh_ ); mesh::actions::build_nodes_parallel_fields( mesh_.nodes() ); mesh::actions::build_periodic_boundaries( mesh_ ); @@ -258,22 +257,6 @@ void NodeColumns::constructor() { ss << "nb_nodes_including_halo[" << halo_.size() << "]"; if ( !mesh_.metadata().get( ss.str(), nb_nodes_ ) ) { nb_nodes_ = mesh_.nodes().size(); } } - - // ATLAS_TRACE_SCOPE("HaloExchange") { - // halo_exchange_.reset( - // NodeColumnsHaloExchangeCache::instance().get(mesh_,halo_.size()) ); - // } - - // ATLAS_TRACE_SCOPE("GatherScatter") { - // gather_scatter_.reset( - // NodeColumnsGatherScatterCache::instance().get(mesh_) ); - // } - - // ATLAS_TRACE_SCOPE("Checksum") { - // checksum_.reset( NodeColumnsChecksumCache::instance().get(mesh_) ); - // } - - // nb_nodes_global_ = gather().glb_dof(); } NodeColumns::~NodeColumns() {} @@ -282,17 +265,11 @@ std::string NodeColumns::distribution() const { return mesh().metadata().getString( "distribution" ); } -size_t NodeColumns::footprint() const { - size_t size = sizeof( *this ); - // TODO - return size; -} - -size_t NodeColumns::nb_nodes() const { +idx_t NodeColumns::nb_nodes() const { return nb_nodes_; } -size_t NodeColumns::nb_nodes_global() const { +idx_t NodeColumns::nb_nodes_global() const { if ( nb_nodes_global_ >= 0 ) return nb_nodes_global_; if ( Grid grid = mesh().grid() ) { nb_nodes_global_ = grid.size(); } else { @@ -301,15 +278,15 @@ size_t NodeColumns::nb_nodes_global() const { return nb_nodes_global_; } -size_t NodeColumns::config_nb_nodes( const eckit::Configuration& config ) const { - size_t size = nb_nodes(); +idx_t NodeColumns::config_nb_nodes( const eckit::Configuration& config ) const { + idx_t size = nb_nodes(); bool global( false ); if ( config.get( "global", global ) ) { if ( global ) { - size_t owner( 0 ); + idx_t owner( 0 ); config.get( "owner", owner ); - size_t _nb_nodes_global = nb_nodes_global(); - size = ( mpi::comm().rank() == owner ? _nb_nodes_global : 0 ); + idx_t _nb_nodes_global = nb_nodes_global(); + size = ( idx_t( mpi::comm().rank() ) == owner ? _nb_nodes_global : 0 ); } } return size; @@ -321,25 +298,25 @@ void NodeColumns::set_field_metadata( const eckit::Configuration& config, Field& bool global( false ); if ( config.get( "global", global ) ) { if ( global ) { - size_t owner( 0 ); + idx_t owner( 0 ); config.get( "owner", owner ); field.metadata().set( "owner", owner ); } } field.metadata().set( "global", global ); - size_t levels( nb_levels_ ); + idx_t levels( nb_levels_ ); config.get( "levels", levels ); field.set_levels( levels ); - size_t variables( 0 ); + idx_t variables( 0 ); config.get( "variables", variables ); field.set_variables( variables ); } array::DataType NodeColumns::config_datatype( const eckit::Configuration& config ) const { array::DataType::kind_t kind; - if ( !config.get( "datatype", kind ) ) throw eckit::AssertionFailed( "datatype missing", Here() ); + if ( !config.get( "datatype", kind ) ) throw_Exception( "datatype missing", Here() ); return array::DataType( kind ); } @@ -349,8 +326,8 @@ std::string NodeColumns::config_name( const eckit::Configuration& config ) const return name; } -size_t NodeColumns::config_levels( const eckit::Configuration& config ) const { - size_t levels( nb_levels_ ); +idx_t NodeColumns::config_levels( const eckit::Configuration& config ) const { + idx_t levels( nb_levels_ ); config.get( "levels", levels ); return levels; } @@ -360,11 +337,11 @@ array::ArrayShape NodeColumns::config_shape( const eckit::Configuration& config shape.push_back( config_nb_nodes( config ) ); - size_t levels( nb_levels_ ); + idx_t levels( nb_levels_ ); config.get( "levels", levels ); if ( levels > 0 ) shape.push_back( levels ); - size_t variables( 0 ); + idx_t variables( 0 ); config.get( "variables", variables ); if ( variables > 0 ) shape.push_back( variables ); @@ -406,13 +383,14 @@ void dispatch_haloExchange( Field& field, const parallel::HaloExchange& halo_exc halo_exchange.template execute( field.array(), on_device ); } else - throw eckit::Exception( "datatype not supported", Here() ); + throw_Exception( "datatype not supported", Here() ); + field.set_dirty( false ); } } // namespace -void NodeColumns::haloExchange( FieldSet& fieldset, bool on_device ) const { - for ( size_t f = 0; f < fieldset.size(); ++f ) { - Field& field = fieldset[f]; +void NodeColumns::haloExchange( const FieldSet& fieldset, bool on_device ) const { + for ( idx_t f = 0; f < fieldset.size(); ++f ) { + Field& field = const_cast( fieldset )[f]; switch ( field.rank() ) { case 1: dispatch_haloExchange<1>( field, halo_exchange(), on_device ); @@ -427,12 +405,12 @@ void NodeColumns::haloExchange( FieldSet& fieldset, bool on_device ) const { dispatch_haloExchange<4>( field, halo_exchange(), on_device ); break; default: - throw eckit::Exception( "Rank not supported", Here() ); + throw_Exception( "Rank not supported", Here() ); } } } -void NodeColumns::haloExchange( Field& field, bool on_device ) const { +void NodeColumns::haloExchange( const Field& field, bool on_device ) const { FieldSet fieldset; fieldset.add( field ); haloExchange( fieldset, on_device ); @@ -444,13 +422,13 @@ const parallel::HaloExchange& NodeColumns::halo_exchange() const { } void NodeColumns::gather( const FieldSet& local_fieldset, FieldSet& global_fieldset ) const { - ASSERT( local_fieldset.size() == global_fieldset.size() ); + ATLAS_ASSERT( local_fieldset.size() == global_fieldset.size() ); - for ( size_t f = 0; f < local_fieldset.size(); ++f ) { - const Field& loc = local_fieldset[f]; - Field& glb = global_fieldset[f]; - const size_t nb_fields = 1; - size_t root( 0 ); + for ( idx_t f = 0; f < local_fieldset.size(); ++f ) { + const Field& loc = local_fieldset[f]; + Field& glb = global_fieldset[f]; + const idx_t nb_fields = 1; + idx_t root( 0 ); glb.metadata().get( "owner", root ); if ( loc.datatype() == array::DataType::kind() ) { @@ -474,7 +452,7 @@ void NodeColumns::gather( const FieldSet& local_fieldset, FieldSet& global_field gather().gather( &loc_field, &glb_field, nb_fields, root ); } else - throw eckit::Exception( "datatype not supported", Here() ); + throw_Exception( "datatype not supported", Here() ); } } @@ -497,13 +475,13 @@ const parallel::GatherScatter& NodeColumns::scatter() const { } void NodeColumns::scatter( const FieldSet& global_fieldset, FieldSet& local_fieldset ) const { - ASSERT( local_fieldset.size() == global_fieldset.size() ); + ATLAS_ASSERT( local_fieldset.size() == global_fieldset.size() ); - for ( size_t f = 0; f < local_fieldset.size(); ++f ) { - const Field& glb = global_fieldset[f]; - Field& loc = local_fieldset[f]; - const size_t nb_fields = 1; - size_t root( 0 ); + for ( idx_t f = 0; f < local_fieldset.size(); ++f ) { + const Field& glb = global_fieldset[f]; + Field& loc = local_fieldset[f]; + const idx_t nb_fields = 1; + idx_t root( 0 ); glb.metadata().get( "owner", root ); if ( loc.datatype() == array::DataType::kind() ) { @@ -527,7 +505,7 @@ void NodeColumns::scatter( const FieldSet& global_fieldset, FieldSet& local_fiel scatter().scatter( &glb_field, &loc_field, nb_fields, root ); } else - throw eckit::Exception( "datatype not supported", Here() ); + throw_Exception( "datatype not supported", Here() ); glb.metadata().broadcast( loc.metadata(), root ); loc.metadata().set( "global", false ); @@ -548,11 +526,11 @@ std::string checksum_3d_field( const parallel::Checksum& checksum, const Field& array::LocalView values = make_leveled_view( field ); array::ArrayT surface_field( values.shape( 0 ), values.shape( 2 ) ); array::ArrayView surface = array::make_view( surface_field ); - const size_t npts = values.shape( 0 ); - atlas_omp_for( size_t n = 0; n < npts; ++n ) { - for ( size_t j = 0; j < surface.shape( 1 ); ++j ) { + const idx_t npts = values.shape( 0 ); + atlas_omp_for( idx_t n = 0; n < npts; ++n ) { + for ( idx_t j = 0; j < surface.shape( 1 ); ++j ) { surface( n, j ) = 0.; - for ( size_t l = 0; l < values.shape( 1 ); ++l ) + for ( idx_t l = 0; l < values.shape( 1 ); ++l ) surface( n, j ) += values( n, l, j ); } } @@ -562,7 +540,7 @@ std::string checksum_3d_field( const parallel::Checksum& checksum, const Field& std::string NodeColumns::checksum( const FieldSet& fieldset ) const { eckit::MD5 md5; - for ( size_t f = 0; f < fieldset.size(); ++f ) { + for ( idx_t f = 0; f < fieldset.size(); ++f ) { const Field& field = fieldset[f]; if ( field.datatype() == array::DataType::kind() ) md5 << checksum_3d_field( checksum(), field ); @@ -573,7 +551,7 @@ std::string NodeColumns::checksum( const FieldSet& fieldset ) const { else if ( field.datatype() == array::DataType::kind() ) md5 << checksum_3d_field( checksum(), field ); else - throw eckit::Exception( "datatype not supported", Here() ); + throw_Exception( "datatype not supported", Here() ); } return md5; } @@ -593,7 +571,7 @@ const parallel::Checksum& NodeColumns::checksum() const { // const parallel::Checksum& checksum = mesh_.checksum().get(checksum_name()); // eckit::MD5 md5; -// for( size_t f=0; f() ) // md5 << checksum.execute( field.data(), field.stride(0) ); @@ -603,7 +581,7 @@ const parallel::Checksum& NodeColumns::checksum() const { // md5 << checksum.execute( field.data(), field.stride(0) ); // else if( field.datatype() == array::DataType::kind() ) // md5 << checksum.execute( field.data(), field.stride(0) ); -// else throw eckit::Exception("datatype not supported",Here()); +// else throw_Exception("datatype not supported",Here()); // } // return md5; //} @@ -622,15 +600,15 @@ inline double sqr( const double& val ) { namespace detail { // Collectives implementation template -void dispatch_sum( const NodeColumns& fs, const Field& field, T& result, size_t& N ) { +void dispatch_sum( const NodeColumns& fs, const Field& field, T& result, idx_t& N ) { const mesh::IsGhostNode is_ghost( fs.nodes() ); const array::LocalView arr = make_leveled_scalar_view( field ); T local_sum = 0; - const size_t npts = std::min( arr.shape( 0 ), fs.nb_nodes() ); + const idx_t npts = std::min( arr.shape( 0 ), fs.nb_nodes() ); atlas_omp_pragma( omp parallel for default(shared) reduction(+:local_sum) ) - for( size_t n=0; n -void sum( const NodeColumns& fs, const Field& field, T& result, size_t& N ) { +void sum( const NodeColumns& fs, const Field& field, T& result, idx_t& N ) { if ( field.datatype() == array::DataType::kind() ) { return dispatch_sum( fs, field, result, N ); } else { switch ( field.datatype().kind() ) { @@ -669,33 +647,33 @@ void sum( const NodeColumns& fs, const Field& field, T& result, size_t& N ) { return; } default: - throw eckit::Exception( "datatype not supported", Here() ); + throw_Exception( "datatype not supported", Here() ); } } } template -void dispatch_sum( const NodeColumns& fs, const Field& field, std::vector& result, size_t& N ) { +void dispatch_sum( const NodeColumns& fs, const Field& field, std::vector& result, idx_t& N ) { const array::LocalView arr = make_leveled_view( field ); const mesh::IsGhostNode is_ghost( fs.nodes() ); - const size_t nvar = arr.shape( 2 ); + const idx_t nvar = arr.shape( 2 ); std::vector local_sum( nvar, 0 ); result.resize( nvar ); atlas_omp_parallel { std::vector local_sum_private( nvar, 0 ); - const size_t npts = arr.shape( 0 ); - atlas_omp_for( size_t n = 0; n < npts; ++n ) { + const idx_t npts = arr.shape( 0 ); + atlas_omp_for( idx_t n = 0; n < npts; ++n ) { if ( !is_ghost( n ) ) { - for ( size_t l = 0; l < arr.shape( 1 ); ++l ) { - for ( size_t j = 0; j < arr.shape( 2 ); ++j ) { + for ( idx_t l = 0; l < arr.shape( 1 ); ++l ) { + for ( idx_t j = 0; j < arr.shape( 2 ); ++j ) { local_sum_private[j] += arr( n, l, j ); } } } } atlas_omp_critical { - for ( size_t j = 0; j < nvar; ++j ) { + for ( idx_t j = 0; j < nvar; ++j ) { local_sum[j] += local_sum_private[j]; } } @@ -707,7 +685,7 @@ void dispatch_sum( const NodeColumns& fs, const Field& field, std::vector& re } template -void sum( const NodeColumns& fs, const Field& field, std::vector& result, size_t& N ) { +void sum( const NodeColumns& fs, const Field& field, std::vector& result, idx_t& N ) { if ( field.datatype() == array::DataType::kind() ) { return dispatch_sum( fs, field, result, N ); } else { switch ( field.datatype().kind() ) { @@ -736,18 +714,18 @@ void sum( const NodeColumns& fs, const Field& field, std::vector& result, siz return; } default: - throw eckit::Exception( "datatype not supported", Here() ); + throw_Exception( "datatype not supported", Here() ); } } } template -void dispatch_sum_per_level( const NodeColumns& fs, const Field& field, Field& sum, size_t& N ) { +void dispatch_sum_per_level( const NodeColumns& fs, const Field& field, Field& sum, idx_t& N ) { mesh::IsGhostNode is_ghost( fs.nodes() ); array::ArrayShape shape; shape.reserve( field.rank() - 1 ); - for ( size_t j = 1; j < field.rank(); ++j ) + for ( idx_t j = 1; j < field.rank(); ++j ) shape.push_back( field.shape( j ) ); sum.resize( shape ); @@ -755,8 +733,8 @@ void dispatch_sum_per_level( const NodeColumns& fs, const Field& field, Field& s auto sum_per_level = make_per_level_view( sum ); - for ( size_t l = 0; l < sum_per_level.shape( 0 ); ++l ) { - for ( size_t j = 0; j < sum_per_level.shape( 1 ); ++j ) { + for ( idx_t l = 0; l < sum_per_level.shape( 0 ); ++l ) { + for ( idx_t j = 0; j < sum_per_level.shape( 1 ); ++j ) { sum_per_level( l, j ) = 0; } } @@ -765,25 +743,25 @@ void dispatch_sum_per_level( const NodeColumns& fs, const Field& field, Field& s array::ArrayT sum_per_level_private( sum_per_level.shape( 0 ), sum_per_level.shape( 1 ) ); array::ArrayView sum_per_level_private_view = array::make_view( sum_per_level_private ); - for ( size_t l = 0; l < sum_per_level_private_view.shape( 0 ); ++l ) { - for ( size_t j = 0; j < sum_per_level_private_view.shape( 1 ); ++j ) { + for ( idx_t l = 0; l < sum_per_level_private_view.shape( 0 ); ++l ) { + for ( idx_t j = 0; j < sum_per_level_private_view.shape( 1 ); ++j ) { sum_per_level_private_view( l, j ) = 0; } } - const size_t npts = arr.shape( 0 ); - atlas_omp_for( size_t n = 0; n < npts; ++n ) { + const idx_t npts = arr.shape( 0 ); + atlas_omp_for( idx_t n = 0; n < npts; ++n ) { if ( !is_ghost( n ) ) { - for ( size_t l = 0; l < arr.shape( 1 ); ++l ) { - for ( size_t j = 0; j < arr.shape( 2 ); ++j ) { + for ( idx_t l = 0; l < arr.shape( 1 ); ++l ) { + for ( idx_t j = 0; j < arr.shape( 2 ); ++j ) { sum_per_level_private_view( l, j ) += arr( n, l, j ); } } } } atlas_omp_critical { - for ( size_t l = 0; l < sum_per_level_private.shape( 0 ); ++l ) { - for ( size_t j = 0; j < sum_per_level_private.shape( 1 ); ++j ) { + for ( idx_t l = 0; l < sum_per_level_private.shape( 0 ); ++l ) { + for ( idx_t j = 0; j < sum_per_level_private.shape( 1 ); ++j ) { sum_per_level( l, j ) += sum_per_level_private_view( l, j ); } } @@ -795,10 +773,8 @@ void dispatch_sum_per_level( const NodeColumns& fs, const Field& field, Field& s N = fs.nb_nodes_global(); } -void sum_per_level( const NodeColumns& fs, const Field& field, Field& sum, size_t& N ) { - if ( field.datatype() != sum.datatype() ) { - throw eckit::Exception( "Field and sum are not of same datatype.", Here() ); - } +void sum_per_level( const NodeColumns& fs, const Field& field, Field& sum, idx_t& N ) { + if ( field.datatype() != sum.datatype() ) { throw_Exception( "Field and sum are not of same datatype.", Here() ); } switch ( field.datatype().kind() ) { case array::DataType::KIND_INT32: return dispatch_sum_per_level( fs, field, sum, N ); @@ -809,18 +785,18 @@ void sum_per_level( const NodeColumns& fs, const Field& field, Field& sum, size_ case array::DataType::KIND_REAL64: return dispatch_sum_per_level( fs, field, sum, N ); default: - throw eckit::Exception( "datatype not supported", Here() ); + throw_Exception( "datatype not supported", Here() ); } } template -void dispatch_order_independent_sum_2d( const NodeColumns& fs, const Field& field, DATATYPE& result, size_t& N ) { - size_t root = 0; +void dispatch_order_independent_sum_2d( const NodeColumns& fs, const Field& field, DATATYPE& result, idx_t& N ) { + idx_t root = 0; Field global = fs.createField( field, option::global() ); fs.gather( field, global ); result = 0; auto glb = array::make_view( global ); - for ( size_t jnode = 0; jnode < glb.size(); ++jnode ) { + for ( idx_t jnode = 0; jnode < glb.size(); ++jnode ) { result += glb( jnode ); } ATLAS_TRACE_MPI( BROADCAST ) { mpi::comm().broadcast( &result, 1, root ); } @@ -828,16 +804,18 @@ void dispatch_order_independent_sum_2d( const NodeColumns& fs, const Field& fiel } template -void dispatch_order_independent_sum( const NodeColumns& fs, const Field& field, T& result, size_t& N ) { +void dispatch_order_independent_sum( const NodeColumns& fs, const Field& field, T& result, idx_t& N ) { if ( field.levels() ) { const array::LocalView arr = make_leveled_scalar_view( field ); Field surface_field = fs.createField( option::name( "surface" ) | option::levels( false ) ); auto surface = array::make_view( surface_field ); - for ( size_t n = 0; n < arr.shape( 0 ); ++n ) { + const idx_t N0 = std::min( surface.shape( 0 ), arr.shape( 0 ) ); + const idx_t N1 = arr.shape( 1 ); + for ( idx_t n = 0; n < N0; ++n ) { surface( n ) = 0; - for ( size_t l = 0; l < arr.shape( 1 ); ++l ) { + for ( idx_t l = 0; l < N1; ++l ) { surface( n ) += arr( n, l ); } } @@ -850,7 +828,7 @@ void dispatch_order_independent_sum( const NodeColumns& fs, const Field& field, } template -void order_independent_sum( const NodeColumns& fs, const Field& field, T& result, size_t& N ) { +void order_independent_sum( const NodeColumns& fs, const Field& field, T& result, idx_t& N ) { if ( field.datatype() == array::DataType::kind() ) { return dispatch_order_independent_sum( fs, field, result, N ); } @@ -881,52 +859,52 @@ void order_independent_sum( const NodeColumns& fs, const Field& field, T& result return; } default: - throw eckit::Exception( "datatype not supported", Here() ); + throw_Exception( "datatype not supported", Here() ); } } } template void dispatch_order_independent_sum_2d( const NodeColumns& fs, const Field& field, std::vector& result, - size_t& N ) { - size_t nvar = field.variables(); + idx_t& N ) { + idx_t nvar = field.variables(); result.resize( nvar ); - for ( size_t j = 0; j < nvar; ++j ) + for ( idx_t j = 0; j < nvar; ++j ) result[j] = 0.; Field global = fs.createField( field, option::name( "global" ) | option::global() ); fs.gather( field, global ); if ( mpi::comm().rank() == 0 ) { const auto glb = make_surface_view( global ); - for ( size_t n = 0; n < fs.nb_nodes_global(); ++n ) { - for ( size_t j = 0; j < nvar; ++j ) { + for ( idx_t n = 0; n < fs.nb_nodes_global(); ++n ) { + for ( idx_t j = 0; j < nvar; ++j ) { result[j] += glb( n, j ); } } } - size_t root = global.metadata().get( "owner" ); + idx_t root = global.metadata().get( "owner" ); ATLAS_TRACE_MPI( BROADCAST ) { mpi::comm().broadcast( result, root ); } N = fs.nb_nodes_global(); } template -void dispatch_order_independent_sum( const NodeColumns& fs, const Field& field, std::vector& result, size_t& N ) { +void dispatch_order_independent_sum( const NodeColumns& fs, const Field& field, std::vector& result, idx_t& N ) { if ( field.levels() ) { - const size_t nvar = field.variables(); - const auto arr = make_leveled_view( field ); + const idx_t nvar = field.variables(); + const auto arr = make_leveled_view( field ); Field surface_field = fs.createField( option::name( "surface" ) | option::variables( nvar ) | option::levels( false ) ); auto surface = make_surface_view( surface_field ); - atlas_omp_for( size_t n = 0; n < arr.shape( 0 ); ++n ) { - for ( size_t j = 0; j < arr.shape( 2 ); ++j ) { + atlas_omp_for( idx_t n = 0; n < arr.shape( 0 ); ++n ) { + for ( idx_t j = 0; j < arr.shape( 2 ); ++j ) { surface( n, j ) = 0; } } - for ( size_t n = 0; n < arr.shape( 0 ); ++n ) { - for ( size_t l = 0; l < arr.shape( 1 ); ++l ) { - for ( size_t j = 0; j < arr.shape( 2 ); ++j ) { + for ( idx_t n = 0; n < arr.shape( 0 ); ++n ) { + for ( idx_t l = 0; l < arr.shape( 1 ); ++l ) { + for ( idx_t j = 0; j < arr.shape( 2 ); ++j ) { surface( n, j ) += arr( n, l, j ); } } @@ -941,7 +919,7 @@ void dispatch_order_independent_sum( const NodeColumns& fs, const Field& field, } template -void order_independent_sum( const NodeColumns& fs, const Field& field, std::vector& result, size_t& N ) { +void order_independent_sum( const NodeColumns& fs, const Field& field, std::vector& result, idx_t& N ) { if ( field.datatype() == array::DataType::kind() ) { return dispatch_order_independent_sum( fs, field, result, N ); } @@ -972,22 +950,22 @@ void order_independent_sum( const NodeColumns& fs, const Field& field, std::vect return; } default: - throw eckit::Exception( "datatype not supported", Here() ); + throw_Exception( "datatype not supported", Here() ); } } } template -void dispatch_order_independent_sum_per_level( const NodeColumns& fs, const Field& field, Field& sumfield, size_t& N ) { +void dispatch_order_independent_sum_per_level( const NodeColumns& fs, const Field& field, Field& sumfield, idx_t& N ) { array::ArrayShape shape; shape.reserve( field.rank() - 1 ); - for ( size_t j = 1; j < field.rank(); ++j ) + for ( idx_t j = 1; j < field.rank(); ++j ) shape.push_back( field.shape( j ) ); sumfield.resize( shape ); auto sum = make_per_level_view( sumfield ); - for ( size_t l = 0; l < sum.shape( 0 ); ++l ) { - for ( size_t j = 0; j < sum.shape( 1 ); ++j ) { + for ( idx_t l = 0; l < sum.shape( 0 ); ++l ) { + for ( idx_t j = 0; j < sum.shape( 1 ); ++j ) { sum( l, j ) = 0.; } } @@ -999,9 +977,9 @@ void dispatch_order_independent_sum_per_level( const NodeColumns& fs, const Fiel if ( mpi::comm().rank() == 0 ) { const array::LocalView glb = make_leveled_view( global ); - for ( size_t n = 0; n < glb.shape( 0 ); ++n ) { - for ( size_t l = 0; l < glb.shape( 1 ); ++l ) { - for ( size_t j = 0; j < glb.shape( 2 ); ++j ) { + for ( idx_t n = 0; n < glb.shape( 0 ); ++n ) { + for ( idx_t l = 0; l < glb.shape( 1 ); ++l ) { + for ( idx_t j = 0; j < glb.shape( 2 ); ++j ) { sum( l, j ) += glb( n, l, j ); } } @@ -1010,18 +988,18 @@ void dispatch_order_independent_sum_per_level( const NodeColumns& fs, const Fiel ATLAS_TRACE_MPI( BROADCAST ) { std::vector sum_array( sumfield.size() ); if ( mpi::comm().rank() == root ) { - size_t c( 0 ); - for ( size_t l = 0; l < sum.shape( 0 ); ++l ) { - for ( size_t j = 0; j < sum.shape( 1 ); ++j ) { + idx_t c( 0 ); + for ( idx_t l = 0; l < sum.shape( 0 ); ++l ) { + for ( idx_t j = 0; j < sum.shape( 1 ); ++j ) { sum_array[c++] = sum( l, j ); } } } mpi::comm().broadcast( sum_array, root ); if ( mpi::comm().rank() != root ) { - size_t c( 0 ); - for ( size_t l = 0; l < sum.shape( 0 ); ++l ) { - for ( size_t j = 0; j < sum.shape( 1 ); ++j ) { + idx_t c( 0 ); + for ( idx_t l = 0; l < sum.shape( 0 ); ++l ) { + for ( idx_t j = 0; j < sum.shape( 1 ); ++j ) { sum( l, j ) = sum_array[c++]; } } @@ -1030,10 +1008,8 @@ void dispatch_order_independent_sum_per_level( const NodeColumns& fs, const Fiel N = fs.nb_nodes_global(); } -void order_independent_sum_per_level( const NodeColumns& fs, const Field& field, Field& sum, size_t& N ) { - if ( field.datatype() != sum.datatype() ) { - throw eckit::Exception( "Field and sum are not of same datatype.", Here() ); - } +void order_independent_sum_per_level( const NodeColumns& fs, const Field& field, Field& sum, idx_t& N ) { + if ( field.datatype() != sum.datatype() ) { throw_Exception( "Field and sum are not of same datatype.", Here() ); } switch ( field.datatype().kind() ) { case array::DataType::KIND_INT32: return dispatch_order_independent_sum_per_level( fs, field, sum, N ); @@ -1044,28 +1020,28 @@ void order_independent_sum_per_level( const NodeColumns& fs, const Field& field, case array::DataType::KIND_REAL64: return dispatch_order_independent_sum_per_level( fs, field, sum, N ); default: - throw eckit::Exception( "datatype not supported", Here() ); + throw_Exception( "datatype not supported", Here() ); } } template void dispatch_minimum( const NodeColumns& fs, const Field& field, std::vector& min ) { const array::LocalView arr = make_leveled_view( field ); - const size_t nvar = arr.shape( 2 ); + const idx_t nvar = arr.shape( 2 ); min.resize( nvar ); std::vector local_minimum( nvar, std::numeric_limits::max() ); atlas_omp_parallel { std::vector local_minimum_private( nvar, std::numeric_limits::max() ); - const size_t npts = arr.shape( 0 ); - atlas_omp_for( size_t n = 0; n < npts; ++n ) { - for ( size_t l = 0; l < arr.shape( 1 ); ++l ) { - for ( size_t j = 0; j < arr.shape( 2 ); ++j ) { + const idx_t npts = std::min( arr.shape( 0 ), fs.size() ); + atlas_omp_for( idx_t n = 0; n < npts; ++n ) { + for ( idx_t l = 0; l < arr.shape( 1 ); ++l ) { + for ( idx_t j = 0; j < arr.shape( 2 ); ++j ) { local_minimum_private[j] = std::min( arr( n, l, j ), local_minimum_private[j] ); } } } atlas_omp_critical { - for ( size_t j = 0; j < arr.shape( 2 ); ++j ) { + for ( idx_t j = 0; j < arr.shape( 2 ); ++j ) { local_minimum[j] = std::min( local_minimum_private[j], local_minimum[j] ); } } @@ -1104,7 +1080,7 @@ void minimum( const NodeColumns& fs, const Field& field, std::vector& min ) { return; } default: - throw eckit::Exception( "datatype not supported", Here() ); + throw_Exception( "datatype not supported", Here() ); } } } @@ -1112,21 +1088,21 @@ void minimum( const NodeColumns& fs, const Field& field, std::vector& min ) { template void dispatch_maximum( const NodeColumns& fs, const Field& field, std::vector& max ) { const array::LocalView arr = make_leveled_view( field ); - const size_t nvar = arr.shape( 2 ); + const idx_t nvar = arr.shape( 2 ); max.resize( nvar ); std::vector local_maximum( nvar, -std::numeric_limits::max() ); atlas_omp_parallel { std::vector local_maximum_private( nvar, -std::numeric_limits::max() ); - const size_t npts = arr.shape( 0 ); - atlas_omp_for( size_t n = 0; n < npts; ++n ) { - for ( size_t l = 0; l < arr.shape( 1 ); ++l ) { - for ( size_t j = 0; j < nvar; ++j ) { + const idx_t npts = std::min( arr.shape( 0 ), fs.size() ); + atlas_omp_for( idx_t n = 0; n < npts; ++n ) { + for ( idx_t l = 0; l < arr.shape( 1 ); ++l ) { + for ( idx_t j = 0; j < nvar; ++j ) { local_maximum_private[j] = std::max( arr( n, l, j ), local_maximum_private[j] ); } } } atlas_omp_critical { - for ( size_t j = 0; j < nvar; ++j ) { + for ( idx_t j = 0; j < nvar; ++j ) { local_maximum[j] = std::max( local_maximum_private[j], local_maximum[j] ); } } @@ -1164,7 +1140,7 @@ void maximum( const NodeColumns& fs, const Field& field, std::vector& max ) { return; } default: - throw eckit::Exception( "datatype not supported", Here() ); + throw_Exception( "datatype not supported", Here() ); } } } @@ -1187,13 +1163,13 @@ template void dispatch_minimum_per_level( const NodeColumns& fs, const Field& field, Field& min_field ) { array::ArrayShape shape; shape.reserve( field.rank() - 1 ); - for ( size_t j = 1; j < field.rank(); ++j ) + for ( idx_t j = 1; j < field.rank(); ++j ) shape.push_back( field.shape( j ) ); min_field.resize( shape ); auto min = make_per_level_view( min_field ); - for ( size_t l = 0; l < min.shape( 0 ); ++l ) { - for ( size_t j = 0; j < min.shape( 1 ); ++j ) { + for ( idx_t l = 0; l < min.shape( 0 ); ++l ) { + for ( idx_t j = 0; j < min.shape( 1 ); ++j ) { min( l, j ) = std::numeric_limits::max(); } } @@ -1202,23 +1178,23 @@ void dispatch_minimum_per_level( const NodeColumns& fs, const Field& field, Fiel atlas_omp_parallel { array::ArrayT min_private( min.shape( 0 ), min.shape( 1 ) ); array::ArrayView min_private_view = array::make_view( min_private ); - for ( size_t l = 0; l < min.shape( 0 ); ++l ) { - for ( size_t j = 0; j < min.shape( 1 ); ++j ) { + for ( idx_t l = 0; l < min.shape( 0 ); ++l ) { + for ( idx_t j = 0; j < min.shape( 1 ); ++j ) { min_private_view( l, j ) = std::numeric_limits::max(); } } - const size_t npts = arr.shape( 0 ); - atlas_omp_for( size_t n = 0; n < npts; ++n ) { - for ( size_t l = 0; l < arr.shape( 1 ); ++l ) { - for ( size_t j = 0; j < arr.shape( 2 ); ++j ) { + const idx_t npts = arr.shape( 0 ); + atlas_omp_for( idx_t n = 0; n < npts; ++n ) { + for ( idx_t l = 0; l < arr.shape( 1 ); ++l ) { + for ( idx_t j = 0; j < arr.shape( 2 ); ++j ) { min_private_view( l, j ) = std::min( arr( n, l, j ), min_private_view( l, j ) ); } } } atlas_omp_critical { - for ( size_t l = 0; l < arr.shape( 1 ); ++l ) { - for ( size_t j = 0; j < arr.shape( 2 ); ++j ) { + for ( idx_t l = 0; l < arr.shape( 1 ); ++l ) { + for ( idx_t j = 0; j < arr.shape( 2 ); ++j ) { min( l, j ) = std::min( min_private_view( l, j ), min( l, j ) ); } } @@ -1228,9 +1204,7 @@ void dispatch_minimum_per_level( const NodeColumns& fs, const Field& field, Fiel } void minimum_per_level( const NodeColumns& fs, const Field& field, Field& min ) { - if ( field.datatype() != min.datatype() ) { - throw eckit::Exception( "Field and min are not of same datatype.", Here() ); - } + if ( field.datatype() != min.datatype() ) { throw_Exception( "Field and min are not of same datatype.", Here() ); } switch ( field.datatype().kind() ) { case array::DataType::KIND_INT32: return dispatch_minimum_per_level( fs, field, min ); @@ -1241,7 +1215,7 @@ void minimum_per_level( const NodeColumns& fs, const Field& field, Field& min ) case array::DataType::KIND_REAL64: return dispatch_minimum_per_level( fs, field, min ); default: - throw eckit::Exception( "datatype not supported", Here() ); + throw_Exception( "datatype not supported", Here() ); } } @@ -1249,13 +1223,13 @@ template void dispatch_maximum_per_level( const NodeColumns& fs, const Field& field, Field& max_field ) { array::ArrayShape shape; shape.reserve( field.rank() - 1 ); - for ( size_t j = 1; j < field.rank(); ++j ) + for ( idx_t j = 1; j < field.rank(); ++j ) shape.push_back( field.shape( j ) ); max_field.resize( shape ); auto max = make_per_level_view( max_field ); - for ( size_t l = 0; l < max.shape( 0 ); ++l ) { - for ( size_t j = 0; j < max.shape( 1 ); ++j ) { + for ( idx_t l = 0; l < max.shape( 0 ); ++l ) { + for ( idx_t j = 0; j < max.shape( 1 ); ++j ) { max( l, j ) = -std::numeric_limits::max(); } } @@ -1265,23 +1239,23 @@ void dispatch_maximum_per_level( const NodeColumns& fs, const Field& field, Fiel array::ArrayT max_private( max.shape( 0 ), max.shape( 1 ) ); array::ArrayView max_private_view = array::make_view( max_private ); - for ( size_t l = 0; l < max_private_view.shape( 0 ); ++l ) { - for ( size_t j = 0; j < max_private_view.shape( 1 ); ++j ) { + for ( idx_t l = 0; l < max_private_view.shape( 0 ); ++l ) { + for ( idx_t j = 0; j < max_private_view.shape( 1 ); ++j ) { max_private_view( l, j ) = -std::numeric_limits::max(); } } - const size_t npts = arr.shape( 0 ); - atlas_omp_for( size_t n = 0; n < npts; ++n ) { - for ( size_t l = 0; l < arr.shape( 1 ); ++l ) { - for ( size_t j = 0; j < arr.shape( 2 ); ++j ) { + const idx_t npts = arr.shape( 0 ); + atlas_omp_for( idx_t n = 0; n < npts; ++n ) { + for ( idx_t l = 0; l < arr.shape( 1 ); ++l ) { + for ( idx_t j = 0; j < arr.shape( 2 ); ++j ) { max_private_view( l, j ) = std::max( arr( n, l, j ), max_private_view( l, j ) ); } } } atlas_omp_critical { - for ( size_t l = 0; l < arr.shape( 1 ); ++l ) { - for ( size_t j = 0; j < arr.shape( 2 ); ++j ) { + for ( idx_t l = 0; l < arr.shape( 1 ); ++l ) { + for ( idx_t j = 0; j < arr.shape( 2 ); ++j ) { max( l, j ) = std::max( max_private_view( l, j ), max( l, j ) ); } } @@ -1291,9 +1265,7 @@ void dispatch_maximum_per_level( const NodeColumns& fs, const Field& field, Fiel } void maximum_per_level( const NodeColumns& fs, const Field& field, Field& max ) { - if ( field.datatype() != max.datatype() ) { - throw eckit::Exception( "Field and max are not of same datatype.", Here() ); - } + if ( field.datatype() != max.datatype() ) { throw_Exception( "Field and max are not of same datatype.", Here() ); } switch ( field.datatype().kind() ) { case array::DataType::KIND_INT32: return dispatch_maximum_per_level( fs, field, max ); @@ -1304,29 +1276,29 @@ void maximum_per_level( const NodeColumns& fs, const Field& field, Field& max ) case array::DataType::KIND_REAL64: return dispatch_maximum_per_level( fs, field, max ); default: - throw eckit::Exception( "datatype not supported", Here() ); + throw_Exception( "datatype not supported", Here() ); } } template void dispatch_minimum_and_location( const NodeColumns& fs, const Field& field, std::vector& min, - std::vector& glb_idx, std::vector& level ) { + std::vector& glb_idx, std::vector& level ) { array::LocalView arr = make_leveled_view( field ); - size_t nvar = arr.shape( 2 ); + idx_t nvar = arr.shape( 2 ); min.resize( nvar ); glb_idx.resize( nvar ); level.resize( nvar ); std::vector local_minimum( nvar, std::numeric_limits::max() ); - std::vector loc_node( nvar ); - std::vector loc_level( nvar ); + std::vector loc_node( nvar ); + std::vector loc_level( nvar ); atlas_omp_parallel { std::vector local_minimum_private( nvar, std::numeric_limits::max() ); - std::vector loc_node_private( nvar ); - std::vector loc_level_private( nvar ); - const size_t npts = arr.shape( 0 ); - atlas_omp_for( size_t n = 0; n < npts; ++n ) { - for ( size_t l = 0; l < arr.shape( 1 ); ++l ) { - for ( size_t j = 0; j < nvar; ++j ) { + std::vector loc_node_private( nvar ); + std::vector loc_level_private( nvar ); + const idx_t npts = arr.shape( 0 ); + atlas_omp_for( idx_t n = 0; n < npts; ++n ) { + for ( idx_t l = 0; l < arr.shape( 1 ); ++l ) { + for ( idx_t j = 0; j < nvar; ++j ) { if ( arr( n, l, j ) < local_minimum_private[j] ) { local_minimum_private[j] = arr( n, l, j ); loc_node_private[j] = n; @@ -1336,8 +1308,8 @@ void dispatch_minimum_and_location( const NodeColumns& fs, const Field& field, s } } atlas_omp_critical_ordered { - for ( size_t l = 0; l < arr.shape( 1 ); ++l ) { - for ( size_t j = 0; j < nvar; ++j ) { + for ( idx_t l = 0; l < arr.shape( 1 ); ++l ) { + for ( idx_t j = 0; j < nvar; ++j ) { if ( local_minimum_private[j] < local_minimum[j] ) { local_minimum[j] = local_minimum_private[j]; loc_node[j] = loc_node_private[j]; @@ -1352,11 +1324,11 @@ void dispatch_minimum_and_location( const NodeColumns& fs, const Field& field, s std::vector> min_and_gidx_glb( nvar ); std::vector> min_and_level_glb( nvar ); const array::ArrayView global_index = array::make_view( fs.nodes().global_index() ); - for ( size_t j = 0; j < nvar; ++j ) { + for ( idx_t j = 0; j < nvar; ++j ) { gidx_t glb_idx = global_index( loc_node[j] ); - ASSERT( glb_idx < std::numeric_limits::max() ); // pairs with 64bit - // integer for second not - // implemented + ATLAS_ASSERT( glb_idx < std::numeric_limits::max() ); // pairs with 64bit + // integer for second not + // implemented min_and_gidx_loc[j] = std::make_pair( local_minimum[j], glb_idx ); min_and_level_loc[j] = std::make_pair( local_minimum[j], loc_level[j] ); } @@ -1366,7 +1338,7 @@ void dispatch_minimum_and_location( const NodeColumns& fs, const Field& field, s mpi::comm().allReduce( min_and_level_loc, min_and_level_glb, eckit::mpi::minloc() ); } - for ( size_t j = 0; j < nvar; ++j ) { + for ( idx_t j = 0; j < nvar; ++j ) { min[j] = min_and_gidx_glb[j].first; glb_idx[j] = min_and_gidx_glb[j].second; level[j] = min_and_level_glb[j].second; @@ -1375,7 +1347,7 @@ void dispatch_minimum_and_location( const NodeColumns& fs, const Field& field, s template void minimum_and_location( const NodeColumns& fs, const Field& field, std::vector& min, std::vector& glb_idx, - std::vector& level ) { + std::vector& level ) { if ( field.datatype() == array::DataType::kind() ) { return dispatch_minimum_and_location( fs, field, min, glb_idx, level ); } @@ -1406,30 +1378,30 @@ void minimum_and_location( const NodeColumns& fs, const Field& field, std::vecto return; } default: - throw eckit::Exception( "datatype not supported", Here() ); + throw_Exception( "datatype not supported", Here() ); } } } template void dispatch_maximum_and_location( const NodeColumns& fs, const Field& field, std::vector& max, - std::vector& glb_idx, std::vector& level ) { + std::vector& glb_idx, std::vector& level ) { array::LocalView arr = make_leveled_view( field ); - size_t nvar = arr.shape( 2 ); + idx_t nvar = arr.shape( 2 ); max.resize( nvar ); glb_idx.resize( nvar ); level.resize( nvar ); std::vector local_maximum( nvar, -std::numeric_limits::max() ); - std::vector loc_node( nvar ); - std::vector loc_level( nvar ); + std::vector loc_node( nvar ); + std::vector loc_level( nvar ); atlas_omp_parallel { std::vector local_maximum_private( nvar, -std::numeric_limits::max() ); - std::vector loc_node_private( nvar ); - std::vector loc_level_private( nvar ); - const size_t npts = arr.shape( 0 ); - atlas_omp_for( size_t n = 0; n < npts; ++n ) { - for ( size_t l = 0; l < arr.shape( 1 ); ++l ) { - for ( size_t j = 0; j < nvar; ++j ) { + std::vector loc_node_private( nvar ); + std::vector loc_level_private( nvar ); + const idx_t npts = arr.shape( 0 ); + atlas_omp_for( idx_t n = 0; n < npts; ++n ) { + for ( idx_t l = 0; l < arr.shape( 1 ); ++l ) { + for ( idx_t j = 0; j < nvar; ++j ) { if ( arr( n, l, j ) > local_maximum_private[j] ) { local_maximum_private[j] = arr( n, l, j ); loc_node_private[j] = n; @@ -1439,8 +1411,8 @@ void dispatch_maximum_and_location( const NodeColumns& fs, const Field& field, s } } atlas_omp_critical_ordered { - for ( size_t l = 0; l < arr.shape( 1 ); ++l ) { - for ( size_t j = 0; j < nvar; ++j ) { + for ( idx_t l = 0; l < arr.shape( 1 ); ++l ) { + for ( idx_t j = 0; j < nvar; ++j ) { if ( local_maximum_private[j] > local_maximum[j] ) { local_maximum[j] = local_maximum_private[j]; loc_node[j] = loc_node_private[j]; @@ -1455,11 +1427,11 @@ void dispatch_maximum_and_location( const NodeColumns& fs, const Field& field, s std::vector> max_and_gidx_glb( nvar ); std::vector> max_and_level_glb( nvar ); const array::ArrayView global_index = array::make_view( fs.nodes().global_index() ); - for ( size_t j = 0; j < nvar; ++j ) { + for ( idx_t j = 0; j < nvar; ++j ) { gidx_t glb_idx = global_index( loc_node[j] ); - ASSERT( glb_idx < std::numeric_limits::max() ); // pairs with 64bit - // integer for second not - // implemented + ATLAS_ASSERT( glb_idx < std::numeric_limits::max() ); // pairs with 64bit + // integer for second not + // implemented max_and_gidx_loc[j] = std::make_pair( local_maximum[j], glb_idx ); max_and_level_loc[j] = std::make_pair( local_maximum[j], loc_level[j] ); } @@ -1469,7 +1441,7 @@ void dispatch_maximum_and_location( const NodeColumns& fs, const Field& field, s mpi::comm().allReduce( max_and_level_loc, max_and_level_glb, eckit::mpi::maxloc() ); } - for ( size_t j = 0; j < nvar; ++j ) { + for ( idx_t j = 0; j < nvar; ++j ) { max[j] = max_and_gidx_glb[j].first; glb_idx[j] = max_and_gidx_glb[j].second; level[j] = max_and_level_glb[j].second; @@ -1478,7 +1450,7 @@ void dispatch_maximum_and_location( const NodeColumns& fs, const Field& field, s template void maximum_and_location( const NodeColumns& fs, const Field& field, std::vector& max, std::vector& glb_idx, - std::vector& level ) { + std::vector& level ) { if ( field.datatype() == array::DataType::kind() ) { return dispatch_maximum_and_location( fs, field, max, glb_idx, level ); } @@ -1509,7 +1481,7 @@ void maximum_and_location( const NodeColumns& fs, const Field& field, std::vecto return; } default: - throw eckit::Exception( "datatype not supported", Here() ); + throw_Exception( "datatype not supported", Here() ); } } } @@ -1517,22 +1489,22 @@ void maximum_and_location( const NodeColumns& fs, const Field& field, std::vecto template void minimum_and_location( const NodeColumns& fs, const Field& field, std::vector& min, std::vector& glb_idx ) { - std::vector level; + std::vector level; minimum_and_location( fs, field, min, glb_idx, level ); } template void maximum_and_location( const NodeColumns& fs, const Field& field, std::vector& max, std::vector& glb_idx ) { - std::vector level; + std::vector level; maximum_and_location( fs, field, max, glb_idx, level ); } template -void minimum_and_location( const NodeColumns& fs, const Field& field, T& min, gidx_t& glb_idx, size_t& level ) { +void minimum_and_location( const NodeColumns& fs, const Field& field, T& min, gidx_t& glb_idx, idx_t& level ) { std::vector minv; std::vector gidxv; - std::vector levelv; + std::vector levelv; minimum_and_location( fs, field, minv, gidxv, levelv ); min = minv[0]; glb_idx = gidxv[0]; @@ -1540,10 +1512,10 @@ void minimum_and_location( const NodeColumns& fs, const Field& field, T& min, gi } template -void maximum_and_location( const NodeColumns& fs, const Field& field, T& max, gidx_t& glb_idx, size_t& level ) { +void maximum_and_location( const NodeColumns& fs, const Field& field, T& max, gidx_t& glb_idx, idx_t& level ) { std::vector maxv; std::vector gidxv; - std::vector levelv; + std::vector levelv; maximum_and_location( fs, field, maxv, gidxv, levelv ); max = maxv[0]; glb_idx = gidxv[0]; @@ -1552,13 +1524,13 @@ void maximum_and_location( const NodeColumns& fs, const Field& field, T& max, gi template void minimum_and_location( const NodeColumns& fs, const Field& field, T& min, gidx_t& glb_idx ) { - size_t level; + idx_t level; minimum_and_location( fs, field, min, glb_idx, level ); } template void maximum_and_location( const NodeColumns& fs, const Field& field, T& max, gidx_t& glb_idx ) { - size_t level; + idx_t level; maximum_and_location( fs, field, max, glb_idx, level ); } @@ -1568,16 +1540,16 @@ void dispatch_minimum_and_location_per_level( const NodeColumns& fs, const Field const array::LocalView arr = make_leveled_view( field ); array::ArrayShape shape; shape.reserve( field.rank() - 1 ); - for ( size_t j = 1; j < field.rank(); ++j ) + for ( idx_t j = 1; j < field.rank(); ++j ) shape.push_back( field.shape( j ) ); min_field.resize( shape ); glb_idx_field.resize( shape ); - const size_t nvar = arr.shape( 2 ); - auto min = make_per_level_view( min_field ); - auto glb_idx = make_per_level_view( glb_idx_field ); + const idx_t nvar = arr.shape( 2 ); + auto min = make_per_level_view( min_field ); + auto glb_idx = make_per_level_view( glb_idx_field ); - for ( size_t l = 0; l < min.shape( 0 ); ++l ) { - for ( size_t j = 0; j < min.shape( 1 ); ++j ) { + for ( idx_t l = 0; l < min.shape( 0 ); ++l ) { + for ( idx_t j = 0; j < min.shape( 1 ); ++j ) { min( l, j ) = std::numeric_limits::max(); } } @@ -1586,18 +1558,18 @@ void dispatch_minimum_and_location_per_level( const NodeColumns& fs, const Field array::ArrayT min_private( min.shape( 0 ), min.shape( 1 ) ); array::ArrayView min_private_view = array::make_view( min_private ); - for ( size_t l = 0; l < min_private_view.shape( 0 ); ++l ) { - for ( size_t j = 0; j < min_private_view.shape( 1 ); ++j ) { + for ( idx_t l = 0; l < min_private_view.shape( 0 ); ++l ) { + for ( idx_t j = 0; j < min_private_view.shape( 1 ); ++j ) { min_private_view( l, j ) = std::numeric_limits::max(); } } array::ArrayT glb_idx_private( glb_idx.shape( 0 ), glb_idx.shape( 1 ) ); array::ArrayView glb_idx_private_view = array::make_view( glb_idx_private ); - const size_t npts = arr.shape( 0 ); - atlas_omp_for( size_t n = 0; n < npts; ++n ) { - for ( size_t l = 0; l < arr.shape( 1 ); ++l ) { - for ( size_t j = 0; j < nvar; ++j ) { + const idx_t npts = arr.shape( 0 ); + atlas_omp_for( idx_t n = 0; n < npts; ++n ) { + for ( idx_t l = 0; l < arr.shape( 1 ); ++l ) { + for ( idx_t j = 0; j < nvar; ++j ) { if ( arr( n, l, j ) < min( l, j ) ) { min_private_view( l, j ) = arr( n, l, j ); glb_idx_private_view( l, j ) = n; @@ -1606,8 +1578,8 @@ void dispatch_minimum_and_location_per_level( const NodeColumns& fs, const Field } } atlas_omp_critical_ordered { - for ( size_t l = 0; l < arr.shape( 1 ); ++l ) { - for ( size_t j = 0; j < nvar; ++j ) { + for ( idx_t l = 0; l < arr.shape( 1 ); ++l ) { + for ( idx_t j = 0; j < nvar; ++j ) { if ( min_private_view( l, j ) < min( l, j ) ) { min( l, j ) = min_private_view( l, j ); glb_idx( l, j ) = glb_idx_private_view( l, j ); @@ -1616,24 +1588,24 @@ void dispatch_minimum_and_location_per_level( const NodeColumns& fs, const Field } } } - const size_t nlev = arr.shape( 1 ); + const idx_t nlev = arr.shape( 1 ); std::vector> min_and_gidx_loc( nlev * nvar ); std::vector> min_and_gidx_glb( nlev * nvar ); const array::ArrayView global_index = array::make_view( fs.nodes().global_index() ); - atlas_omp_parallel_for( size_t l = 0; l < nlev; ++l ) { - for ( size_t j = 0; j < nvar; ++j ) { + atlas_omp_parallel_for( idx_t l = 0; l < nlev; ++l ) { + for ( idx_t j = 0; j < nvar; ++j ) { gidx_t gidx = global_index( glb_idx( l, j ) ); - ASSERT( gidx < std::numeric_limits::max() ); // pairs with 64bit - // integer for second not - // implemented + ATLAS_ASSERT( gidx < std::numeric_limits::max() ); // pairs with 64bit + // integer for second not + // implemented min_and_gidx_loc[j + nvar * l] = std::make_pair( min( l, j ), gidx ); } } ATLAS_TRACE_MPI( ALLREDUCE ) { mpi::comm().allReduce( min_and_gidx_loc, min_and_gidx_glb, eckit::mpi::minloc() ); } - atlas_omp_parallel_for( size_t l = 0; l < nlev; ++l ) { - for ( size_t j = 0; j < nvar; ++j ) { + atlas_omp_parallel_for( idx_t l = 0; l < nlev; ++l ) { + for ( idx_t j = 0; j < nvar; ++j ) { min( l, j ) = min_and_gidx_glb[j + l * nvar].first; glb_idx( l, j ) = min_and_gidx_glb[j + l * nvar].second; } @@ -1641,11 +1613,9 @@ void dispatch_minimum_and_location_per_level( const NodeColumns& fs, const Field } void minimum_and_location_per_level( const NodeColumns& fs, const Field& field, Field& min, Field& glb_idx ) { - if ( field.datatype() != min.datatype() ) { - throw eckit::Exception( "Field and min are not of same datatype.", Here() ); - } + if ( field.datatype() != min.datatype() ) { throw_Exception( "Field and min are not of same datatype.", Here() ); } if ( glb_idx.datatype() != array::DataType::kind() ) { - throw eckit::Exception( "glb_idx Field is not of correct datatype", Here() ); + throw_Exception( "glb_idx Field is not of correct datatype", Here() ); } switch ( field.datatype().kind() ) { case array::DataType::KIND_INT32: @@ -1657,7 +1627,7 @@ void minimum_and_location_per_level( const NodeColumns& fs, const Field& field, case array::DataType::KIND_REAL64: return dispatch_minimum_and_location_per_level( fs, field, min, glb_idx ); default: - throw eckit::Exception( "datatype not supported", Here() ); + throw_Exception( "datatype not supported", Here() ); } } @@ -1667,16 +1637,16 @@ void dispatch_maximum_and_location_per_level( const NodeColumns& fs, const Field const array::LocalView arr = make_leveled_view( field ); array::ArrayShape shape; shape.reserve( field.rank() - 1 ); - for ( size_t j = 1; j < field.rank(); ++j ) + for ( idx_t j = 1; j < field.rank(); ++j ) shape.push_back( field.shape( j ) ); max_field.resize( shape ); glb_idx_field.resize( shape ); - const size_t nvar = arr.shape( 2 ); - auto max = make_per_level_view( max_field ); - auto glb_idx = make_per_level_view( glb_idx_field ); + const idx_t nvar = arr.shape( 2 ); + auto max = make_per_level_view( max_field ); + auto glb_idx = make_per_level_view( glb_idx_field ); - for ( size_t l = 0; l < max.shape( 0 ); ++l ) { - for ( size_t j = 0; j < max.shape( 1 ); ++j ) { + for ( idx_t l = 0; l < max.shape( 0 ); ++l ) { + for ( idx_t j = 0; j < max.shape( 1 ); ++j ) { max( l, j ) = -std::numeric_limits::max(); } } @@ -1685,18 +1655,18 @@ void dispatch_maximum_and_location_per_level( const NodeColumns& fs, const Field array::ArrayT max_private( max.shape( 0 ), max.shape( 1 ) ); array::ArrayView max_private_view = array::make_view( max_private ); - for ( size_t l = 0; l < max_private_view.shape( 0 ); ++l ) { - for ( size_t j = 0; j < max_private_view.shape( 1 ); ++j ) { + for ( idx_t l = 0; l < max_private_view.shape( 0 ); ++l ) { + for ( idx_t j = 0; j < max_private_view.shape( 1 ); ++j ) { max_private_view( l, j ) = -std::numeric_limits::max(); } } array::ArrayT glb_idx_private( glb_idx.shape( 0 ), glb_idx.shape( 1 ) ); array::ArrayView glb_idx_private_view = array::make_view( glb_idx_private ); - const size_t npts = arr.shape( 0 ); - atlas_omp_for( size_t n = 0; n < npts; ++n ) { - for ( size_t l = 0; l < arr.shape( 1 ); ++l ) { - for ( size_t j = 0; j < nvar; ++j ) { + const idx_t npts = arr.shape( 0 ); + atlas_omp_for( idx_t n = 0; n < npts; ++n ) { + for ( idx_t l = 0; l < arr.shape( 1 ); ++l ) { + for ( idx_t j = 0; j < nvar; ++j ) { if ( arr( n, l, j ) > max( l, j ) ) { max_private_view( l, j ) = arr( n, l, j ); glb_idx_private_view( l, j ) = n; @@ -1705,8 +1675,8 @@ void dispatch_maximum_and_location_per_level( const NodeColumns& fs, const Field } } atlas_omp_critical_ordered { - for ( size_t l = 0; l < arr.shape( 1 ); ++l ) { - for ( size_t j = 0; j < nvar; ++j ) { + for ( idx_t l = 0; l < arr.shape( 1 ); ++l ) { + for ( idx_t j = 0; j < nvar; ++j ) { if ( max_private_view( l, j ) > max( l, j ) ) { max( l, j ) = max_private_view( l, j ); glb_idx( l, j ) = glb_idx_private_view( l, j ); @@ -1716,24 +1686,24 @@ void dispatch_maximum_and_location_per_level( const NodeColumns& fs, const Field } } - const size_t nlev = arr.shape( 1 ); + const idx_t nlev = arr.shape( 1 ); std::vector> max_and_gidx_loc( nlev * nvar ); std::vector> max_and_gidx_glb( nlev * nvar ); const array::ArrayView global_index = array::make_view( fs.nodes().global_index() ); - atlas_omp_parallel_for( size_t l = 0; l < nlev; ++l ) { - for ( size_t j = 0; j < nvar; ++j ) { + atlas_omp_parallel_for( idx_t l = 0; l < nlev; ++l ) { + for ( idx_t j = 0; j < nvar; ++j ) { gidx_t gidx = global_index( glb_idx( l, j ) ); - ASSERT( gidx < std::numeric_limits::max() ); // pairs with 64bit - // integer for second not - // implemented + ATLAS_ASSERT( gidx < std::numeric_limits::max() ); // pairs with 64bit + // integer for second not + // implemented max_and_gidx_loc[j + nvar * l] = std::make_pair( max( l, j ), gidx ); } } ATLAS_TRACE_MPI( ALLREDUCE ) { mpi::comm().allReduce( max_and_gidx_loc, max_and_gidx_glb, eckit::mpi::maxloc() ); } - atlas_omp_parallel_for( size_t l = 0; l < nlev; ++l ) { - for ( size_t j = 0; j < nvar; ++j ) { + atlas_omp_parallel_for( idx_t l = 0; l < nlev; ++l ) { + for ( idx_t j = 0; j < nvar; ++j ) { max( l, j ) = max_and_gidx_glb[j + l * nvar].first; glb_idx( l, j ) = max_and_gidx_glb[j + l * nvar].second; } @@ -1741,11 +1711,9 @@ void dispatch_maximum_and_location_per_level( const NodeColumns& fs, const Field } void maximum_and_location_per_level( const NodeColumns& fs, const Field& field, Field& max, Field& glb_idx ) { - if ( field.datatype() != max.datatype() ) { - throw eckit::Exception( "Field and max are not of same datatype.", Here() ); - } + if ( field.datatype() != max.datatype() ) { throw_Exception( "Field and max are not of same datatype.", Here() ); } if ( glb_idx.datatype() != array::DataType::kind() ) { - throw eckit::Exception( "glb_idx Field is not of correct datatype", Here() ); + throw_Exception( "glb_idx Field is not of correct datatype", Here() ); } switch ( field.datatype().kind() ) { case array::DataType::KIND_INT32: @@ -1757,18 +1725,18 @@ void maximum_and_location_per_level( const NodeColumns& fs, const Field& field, case array::DataType::KIND_REAL64: return dispatch_maximum_and_location_per_level( fs, field, max, glb_idx ); default: - throw eckit::Exception( "datatype not supported", Here() ); + throw_Exception( "datatype not supported", Here() ); } } template -void mean( const NodeColumns& fs, const Field& field, T& result, size_t& N ) { +void mean( const NodeColumns& fs, const Field& field, T& result, idx_t& N ) { sum( fs, field, result, N ); result /= static_cast( N ); } template -void mean( const NodeColumns& fs, const Field& field, std::vector& result, size_t& N ) { +void mean( const NodeColumns& fs, const Field& field, std::vector& result, idx_t& N ) { sum( fs, field, result, N ); for ( size_t j = 0; j < result.size(); ++j ) { result[j] /= static_cast( N ); @@ -1776,20 +1744,18 @@ void mean( const NodeColumns& fs, const Field& field, std::vector& result, si } template -void dispatch_mean_per_level( const NodeColumns& fs, const Field& field, Field& mean, size_t& N ) { +void dispatch_mean_per_level( const NodeColumns& fs, const Field& field, Field& mean, idx_t& N ) { dispatch_sum_per_level( fs, field, mean, N ); auto view = make_per_level_view( mean ); - for ( size_t l = 0; l < view.shape( 0 ); ++l ) { - for ( size_t j = 0; j < view.shape( 1 ); ++j ) { + for ( idx_t l = 0; l < view.shape( 0 ); ++l ) { + for ( idx_t j = 0; j < view.shape( 1 ); ++j ) { view( l, j ) /= static_cast( N ); } } } -void mean_per_level( const NodeColumns& fs, const Field& field, Field& mean, size_t& N ) { - if ( field.datatype() != mean.datatype() ) { - throw eckit::Exception( "Field and sum are not of same datatype.", Here() ); - } +void mean_per_level( const NodeColumns& fs, const Field& field, Field& mean, idx_t& N ) { + if ( field.datatype() != mean.datatype() ) { throw_Exception( "Field and sum are not of same datatype.", Here() ); } switch ( field.datatype().kind() ) { case array::DataType::KIND_INT32: return dispatch_mean_per_level( fs, field, mean, N ); @@ -1800,12 +1766,12 @@ void mean_per_level( const NodeColumns& fs, const Field& field, Field& mean, siz case array::DataType::KIND_REAL64: return dispatch_mean_per_level( fs, field, mean, N ); default: - throw eckit::Exception( "datatype not supported", Here() ); + throw_Exception( "datatype not supported", Here() ); } } template -void mean_and_standard_deviation( const NodeColumns& fs, const Field& field, T& mu, T& sigma, size_t& N ) { +void mean_and_standard_deviation( const NodeColumns& fs, const Field& field, T& mu, T& sigma, idx_t& N ) { mean( fs, field, mu, N ); Field squared_diff_field = fs.createField( option::name( "sqr_diff" ) | option::datatype( field.datatype() ) | option::levels( field.levels() ) ); @@ -1813,9 +1779,9 @@ void mean_and_standard_deviation( const NodeColumns& fs, const Field& field, T& array::LocalView squared_diff = make_leveled_scalar_view( squared_diff_field ); array::LocalView values = make_leveled_scalar_view( field ); - const size_t npts = std::min( values.shape( 0 ), fs.nb_nodes() ); - atlas_omp_parallel_for( size_t n = 0; n < npts; ++n ) { - for ( size_t l = 0; l < values.shape( 1 ); ++l ) { + const idx_t npts = std::min( values.shape( 0 ), fs.nb_nodes() ); + atlas_omp_parallel_for( idx_t n = 0; n < npts; ++n ) { + for ( idx_t l = 0; l < values.shape( 1 ); ++l ) { squared_diff( n, l ) = sqr( values( n, l ) - mu ); } } @@ -1825,17 +1791,17 @@ void mean_and_standard_deviation( const NodeColumns& fs, const Field& field, T& template void mean_and_standard_deviation( const NodeColumns& fs, const Field& field, std::vector& mu, std::vector& sigma, - size_t& N ) { + idx_t& N ) { mean( fs, field, mu, N ); Field squared_diff_field = fs.createField( option::name( "sqr_diff" ) | option::levels( field.levels() ) | option::variables( field.variables() ) ); array::LocalView squared_diff = make_leveled_view( squared_diff_field ); array::LocalView values = make_leveled_view( field ); - const size_t npts = values.shape( 0 ); - atlas_omp_parallel_for( size_t n = 0; n < npts; ++n ) { - for ( size_t l = 0; l < values.shape( 1 ); ++l ) { - for ( size_t j = 0; j < values.shape( 2 ); ++j ) { + const idx_t npts = std::min( values.shape( 0 ), fs.nb_nodes() ); + atlas_omp_parallel_for( idx_t n = 0; n < npts; ++n ) { + for ( idx_t l = 0; l < values.shape( 1 ); ++l ) { + for ( idx_t j = 0; j < values.shape( 2 ); ++j ) { squared_diff( n, l, j ) = sqr( values( n, l, j ) - mu[j] ); } } @@ -1848,7 +1814,7 @@ void mean_and_standard_deviation( const NodeColumns& fs, const Field& field, std template void dispatch_mean_and_standard_deviation_per_level( const NodeColumns& fs, const Field& field, Field& mean, - Field& stddev, size_t& N ) { + Field& stddev, idx_t& N ) { dispatch_mean_per_level( fs, field, mean, N ); Field squared_diff_field = fs.createField( option::name( "sqr_diff" ) | option::levels( field.levels() ) | option::variables( field.variables() ) ); @@ -1856,30 +1822,30 @@ void dispatch_mean_and_standard_deviation_per_level( const NodeColumns& fs, cons auto values = make_leveled_view( field ); auto mu = make_per_level_view( mean ); - const size_t npts = values.shape( 0 ); - atlas_omp_parallel_for( size_t n = 0; n < npts; ++n ) { - for ( size_t l = 0; l < values.shape( 1 ); ++l ) { - for ( size_t j = 0; j < values.shape( 2 ); ++j ) { + const idx_t npts = std::min( values.shape( 0 ), fs.nb_nodes() ); + atlas_omp_parallel_for( idx_t n = 0; n < npts; ++n ) { + for ( idx_t l = 0; l < values.shape( 1 ); ++l ) { + for ( idx_t j = 0; j < values.shape( 2 ); ++j ) { squared_diff( n, l, j ) = sqr( values( n, l, j ) - mu( l, j ) ); } } } dispatch_mean_per_level( fs, squared_diff_field, stddev, N ); auto sigma = make_per_level_view( stddev ); - atlas_omp_for( size_t l = 0; l < sigma.shape( 0 ); ++l ) { - for ( size_t j = 0; j < sigma.shape( 1 ); ++j ) { + atlas_omp_for( idx_t l = 0; l < sigma.shape( 0 ); ++l ) { + for ( idx_t j = 0; j < sigma.shape( 1 ); ++j ) { sigma( l, j ) = std::sqrt( sigma( l, j ) ); } } } void mean_and_standard_deviation_per_level( const NodeColumns& fs, const Field& field, Field& mean, Field& stddev, - size_t& N ) { + idx_t& N ) { if ( field.datatype() != mean.datatype() ) { - throw eckit::Exception( "Field and mean are not of same datatype.", Here() ); + throw_Exception( "Field and mean are not of same datatype.", Here() ); } if ( field.datatype() != stddev.datatype() ) { - throw eckit::Exception( "Field and stddev are not of same datatype.", Here() ); + throw_Exception( "Field and stddev are not of same datatype.", Here() ); } switch ( field.datatype().kind() ) { case array::DataType::KIND_INT32: @@ -1891,7 +1857,7 @@ void mean_and_standard_deviation_per_level( const NodeColumns& fs, const Field& case array::DataType::KIND_REAL64: return dispatch_mean_and_standard_deviation_per_level( fs, field, mean, stddev, N ); default: - throw eckit::Exception( "datatype not supported", Here() ); + throw_Exception( "datatype not supported", Here() ); } } @@ -1906,31 +1872,31 @@ NodeColumns::FieldStatisticsVectorT::FieldStatisticsVectorT( const NodeC NodeColumns::FieldStatistics::FieldStatistics( const NodeColumns* f ) : functionspace( *f ) {} template -void NodeColumns::FieldStatisticsT::sum( const Field& field, Value& result, size_t& N ) const { +void NodeColumns::FieldStatisticsT::sum( const Field& field, Value& result, idx_t& N ) const { detail::sum( functionspace, field, result, N ); } template -void NodeColumns::FieldStatisticsVectorT::sum( const Field& field, Vector& result, size_t& N ) const { +void NodeColumns::FieldStatisticsVectorT::sum( const Field& field, Vector& result, idx_t& N ) const { detail::sum( functionspace, field, result, N ); } -void NodeColumns::FieldStatistics::sumPerLevel( const Field& field, Field& result, size_t& N ) const { +void NodeColumns::FieldStatistics::sumPerLevel( const Field& field, Field& result, idx_t& N ) const { detail::sum_per_level( functionspace, field, result, N ); } template -void NodeColumns::FieldStatisticsT::orderIndependentSum( const Field& field, Value& result, size_t& N ) const { +void NodeColumns::FieldStatisticsT::orderIndependentSum( const Field& field, Value& result, idx_t& N ) const { detail::order_independent_sum( functionspace, field, result, N ); } template void NodeColumns::FieldStatisticsVectorT::orderIndependentSum( const Field& field, Vector& result, - size_t& N ) const { + idx_t& N ) const { detail::order_independent_sum( functionspace, field, result, N ); } -void NodeColumns::FieldStatistics::orderIndependentSumPerLevel( const Field& field, Field& result, size_t& N ) const { +void NodeColumns::FieldStatistics::orderIndependentSumPerLevel( const Field& field, Field& result, idx_t& N ) const { detail::order_independent_sum_per_level( functionspace, field, result, N ); } @@ -1976,13 +1942,13 @@ void NodeColumns::FieldStatisticsT::maximumAndLocation( const Field& fiel template void NodeColumns::FieldStatisticsT::minimumAndLocation( const Field& field, Value& minimum, gidx_t& glb_idx, - size_t& level ) const { + idx_t& level ) const { detail::minimum_and_location( functionspace, field, minimum, glb_idx, level ); } template void NodeColumns::FieldStatisticsT::maximumAndLocation( const Field& field, Value& maximum, gidx_t& glb_idx, - size_t& level ) const { + idx_t& level ) const { detail::maximum_and_location( functionspace, field, maximum, glb_idx, level ); } @@ -2001,14 +1967,14 @@ void NodeColumns::FieldStatisticsVectorT::maximumAndLocation( const Fiel template void NodeColumns::FieldStatisticsVectorT::minimumAndLocation( const Field& field, Vector& minimum, std::vector& glb_idx, - std::vector& level ) const { + std::vector& level ) const { detail::minimum_and_location( functionspace, field, minimum, glb_idx, level ); } template void NodeColumns::FieldStatisticsVectorT::maximumAndLocation( const Field& field, Vector& maximum, std::vector& glb_idx, - std::vector& level ) const { + std::vector& level ) const { detail::maximum_and_location( functionspace, field, maximum, glb_idx, level ); } @@ -2023,33 +1989,33 @@ void NodeColumns::FieldStatistics::maximumAndLocationPerLevel( const Field& fiel } template -void NodeColumns::FieldStatisticsT::mean( const Field& field, Value& mean, size_t& N ) const { +void NodeColumns::FieldStatisticsT::mean( const Field& field, Value& mean, idx_t& N ) const { detail::mean( functionspace, field, mean, N ); } template -void NodeColumns::FieldStatisticsVectorT::mean( const Field& field, Vector& mean, size_t& N ) const { +void NodeColumns::FieldStatisticsVectorT::mean( const Field& field, Vector& mean, idx_t& N ) const { detail::mean( functionspace, field, mean, N ); } -void NodeColumns::FieldStatistics::meanPerLevel( const Field& field, Field& mean, size_t& N ) const { +void NodeColumns::FieldStatistics::meanPerLevel( const Field& field, Field& mean, idx_t& N ) const { detail::mean_per_level( functionspace, field, mean, N ); } template void NodeColumns::FieldStatisticsT::meanAndStandardDeviation( const Field& field, Value& mean, Value& stddev, - size_t& N ) const { + idx_t& N ) const { detail::mean_and_standard_deviation( functionspace, field, mean, stddev, N ); } template void NodeColumns::FieldStatisticsVectorT::meanAndStandardDeviation( const Field& field, Vector& mean, - Vector& stddev, size_t& N ) const { + Vector& stddev, idx_t& N ) const { detail::mean_and_standard_deviation( functionspace, field, mean, stddev, N ); } void NodeColumns::FieldStatistics::meanAndStandardDeviationPerLevel( const Field& field, Field& mean, Field& stddev, - size_t& N ) const { + idx_t& N ) const { detail::mean_and_standard_deviation_per_level( functionspace, field, mean, stddev, N ); } @@ -2087,11 +2053,11 @@ NodeColumns::NodeColumns( Mesh mesh, const eckit::Configuration& config ) : FunctionSpace( make_functionspace( mesh, config ) ), functionspace_( dynamic_cast( get() ) ) {} -size_t NodeColumns::nb_nodes() const { +idx_t NodeColumns::nb_nodes() const { return functionspace_->nb_nodes(); } -size_t NodeColumns::nb_nodes_global() const { // All MPI ranks will have same output +idx_t NodeColumns::nb_nodes_global() const { // All MPI ranks will have same output return functionspace_->nb_nodes_global(); } @@ -2109,11 +2075,11 @@ const mesh::Halo& NodeColumns::halo() const { return functionspace_->halo(); } -void NodeColumns::haloExchange( FieldSet& fieldset, bool on_device ) const { +void NodeColumns::haloExchange( const FieldSet& fieldset, bool on_device ) const { functionspace_->haloExchange( fieldset, on_device ); } -void NodeColumns::haloExchange( Field& field, bool on_device ) const { +void NodeColumns::haloExchange( const Field& field, bool on_device ) const { functionspace_->haloExchange( field, on_device ); } diff --git a/src/atlas/functionspace/NodeColumns.h b/src/atlas/functionspace/NodeColumns.h index 05bc3b83a..a83637410 100644 --- a/src/atlas/functionspace/NodeColumns.h +++ b/src/atlas/functionspace/NodeColumns.h @@ -10,10 +10,8 @@ #pragma once -#include "eckit/memory/SharedPtr.h" - -#include "atlas/field/FieldSet.h" #include "atlas/functionspace/FunctionSpace.h" +#include "atlas/functionspace/detail/FunctionSpaceImpl.h" #include "atlas/library/config.h" #include "atlas/mesh/Halo.h" #include "atlas/mesh/Mesh.h" @@ -23,6 +21,10 @@ // Forward declarations namespace atlas { +namespace array { +class ArrayShape; +} + namespace mesh { class Nodes; } @@ -51,19 +53,19 @@ class NodeColumns : public FunctionSpaceImpl { NodeColumns( Mesh mesh, const eckit::Configuration& ); NodeColumns( Mesh mesh ); - virtual ~NodeColumns(); + virtual ~NodeColumns() override; static std::string static_type() { return "NodeColumns"; } - virtual std::string type() const { return static_type(); } + virtual std::string type() const override { return static_type(); } - virtual std::string distribution() const; + virtual std::string distribution() const override; - size_t nb_nodes() const; - size_t nb_nodes_global() const; // All MPI ranks will have same output + idx_t nb_nodes() const; + idx_t nb_nodes_global() const; // All MPI ranks will have same output const Mesh& mesh() const { return mesh_; } - size_t levels() const { return nb_levels_; } + idx_t levels() const { return nb_levels_; } mesh::Nodes& nodes() const { return nodes_; } @@ -72,16 +74,16 @@ class NodeColumns : public FunctionSpaceImpl { using FunctionSpaceImpl::createField; /// @brief Create a field - virtual Field createField( const eckit::Configuration& ) const; + virtual Field createField( const eckit::Configuration& ) const override; - virtual Field createField( const Field&, const eckit::Configuration& ) const; + virtual Field createField( const Field&, const eckit::Configuration& ) const override; // -- Parallelisation aware methods const mesh::Halo& halo() const { return halo_; } - void haloExchange( FieldSet&, bool on_device = false ) const; - void haloExchange( Field&, bool on_device = false ) const; + void haloExchange( const FieldSet&, bool on_device = false ) const override; + void haloExchange( const Field&, bool on_device = false ) const override; const parallel::HaloExchange& halo_exchange() const; void gather( const FieldSet&, FieldSet& ) const; @@ -101,7 +103,7 @@ class NodeColumns : public FunctionSpaceImpl { /// @param [out] N Number of values that are contained in the sum /// (nodes*levels) template - void sum( const Field&, Value& sum, size_t& N ) const; + void sum( const Field&, Value& sum, idx_t& N ) const; // /// @brief Compute sum of field for each variable // /// @param [out] sum For each field-variable, the sum of the full 3D @@ -109,19 +111,19 @@ class NodeColumns : public FunctionSpaceImpl { // /// @param [out] N Number of values that are contained in the sum // (nodes*levels) // template< typename Value > - // void sum( const Field&, std::vector& sum, size_t& N ) const; + // void sum( const Field&, std::vector& sum, idx_t& N ) const; /// @brief Compute sum of field for each vertical level separately /// @param [out] sum Field of dimension of input without the nodes index /// @param [out] N Number of nodes used to sum each level - void sumPerLevel( const Field&, Field& sum, size_t& N ) const; + void sumPerLevel( const Field&, Field& sum, idx_t& N ) const; /// @brief Compute order independent sum of scalar field /// @param [out] sum Scalar value containing the sum of the full 3D field /// @param [out] N Number of values that are contained in the sum /// (nodes*levels) template - void orderIndependentSum( const Field&, Value& sum, size_t& N ) const; + void orderIndependentSum( const Field&, Value& sum, idx_t& N ) const; // /// @brief Compute order independent sum of field for each variable // /// @param [out] sum For each field-variable, the sum of the full 3D @@ -129,14 +131,14 @@ class NodeColumns : public FunctionSpaceImpl { // /// @param [out] N Number of values that are contained in the sum // (nodes*levels) // template< typename Value > - // void orderIndependentSum( const Field&, std::vector&, size_t& N ) + // void orderIndependentSum( const Field&, std::vector&, idx_t& N ) // const; /// @brief Compute order independent sum of field for each vertical level /// separately /// @param [out] sum Field of dimension of input without the nodes index /// @param [out] N Number of nodes used to sum each level - void orderIndependentSumPerLevel( const Field&, Field& sum, size_t& N ) const; + void orderIndependentSumPerLevel( const Field&, Field& sum, idx_t& N ) const; /// @brief Compute minimum of scalar field template @@ -175,12 +177,12 @@ class NodeColumns : public FunctionSpaceImpl { /// @brief Compute minimum of scalar field, as well as the global index and /// level. template - void minimumAndLocation( const Field&, Value& minimum, gidx_t& glb_idx, size_t& level ) const; + void minimumAndLocation( const Field&, Value& minimum, gidx_t& glb_idx, idx_t& level ) const; /// @brief Compute maximum of scalar field, as well as the global index and /// level. template - void maximumAndLocation( const Field&, Value& maximum, gidx_t& glb_idx, size_t& level ) const; + void maximumAndLocation( const Field&, Value& maximum, gidx_t& glb_idx, idx_t& level ) const; /// @brief Compute minimum of field for each field-variable, as well as the /// global indices and levels. @@ -196,13 +198,13 @@ class NodeColumns : public FunctionSpaceImpl { /// global indices and levels. template void minimumAndLocation( const Field&, Vector& minimum, std::vector& glb_idx, - std::vector& level ) const; + std::vector& level ) const; /// @brief Compute maximum of field for each field-variable, as well as the /// global indices and levels. template void maximumAndLocation( const Field&, Vector& maximum, std::vector& glb_idx, - std::vector& level ) const; + std::vector& level ) const; /// @brief Compute minimum and its location of a field for each vertical level /// separately @@ -216,25 +218,25 @@ class NodeColumns : public FunctionSpaceImpl { /// @param [out] mean Mean value /// @param [out] N Number of value used to create the mean template - void mean( const Field&, Value& mean, size_t& N ) const; + void mean( const Field&, Value& mean, idx_t& N ) const; // /// @brief Compute mean value of field for each field-variable // /// @param [out] mean Mean values for each variable // /// @param [out] N Number of values used to create the means // template< typename Value > - // void mean( const Field&, std::vector& mean, size_t& N ) const; + // void mean( const Field&, std::vector& mean, idx_t& N ) const; /// @brief Compute mean values of field for vertical level separately /// @param [out] mean Field of dimension of input without the nodes index /// @param [out] N Number of values used to create the means - void meanPerLevel( const Field&, Field& mean, size_t& N ) const; + void meanPerLevel( const Field&, Field& mean, idx_t& N ) const; /// @brief Compute mean value and standard deviation of scalar field /// @param [out] mean Mean value /// @param [out] stddev Standard deviation /// @param [out] N Number of value used to create the mean template - void meanAndStandardDeviation( const Field&, Value& mean, Value& stddev, size_t& N ) const; + void meanAndStandardDeviation( const Field&, Value& mean, Value& stddev, idx_t& N ) const; // /// @brief Compute mean values and standard deviations of scalar field // for each field-variable @@ -243,84 +245,86 @@ class NodeColumns : public FunctionSpaceImpl { // /// @param [out] N Number of value used to create the means // template< typename Value > // void meanAndStandardDeviation( const Field&, std::vector& mean, - // std::vector& stddev, size_t& N ) const; + // std::vector& stddev, idx_t& N ) const; /// @brief Compute mean values and standard deviations of field for vertical /// level separately /// @param [out] mean Field of dimension of input without the nodes index /// @param [out] stddev Field of dimension of input without the nodes index /// @param [out] N Number of values used to create the means - void meanAndStandardDeviationPerLevel( const Field&, Field& mean, Field& stddev, size_t& N ) const; + void meanAndStandardDeviationPerLevel( const Field&, Field& mean, Field& stddev, idx_t& N ) const; + + virtual idx_t size() const override { return nb_nodes_; } private: // methods void constructor(); - size_t config_nb_nodes( const eckit::Configuration& ) const; + idx_t config_nb_nodes( const eckit::Configuration& ) const; array::DataType config_datatype( const eckit::Configuration& ) const; std::string config_name( const eckit::Configuration& ) const; - size_t config_levels( const eckit::Configuration& ) const; + idx_t config_levels( const eckit::Configuration& ) const; array::ArrayShape config_shape( const eckit::Configuration& ) const; void set_field_metadata( const eckit::Configuration&, Field& ) const; - size_t footprint() const; + virtual size_t footprint() const override { return 0; } private: // data Mesh mesh_; // non-const because functionspace may modify mesh mesh::Nodes& nodes_; // non-const because functionspace may modify mesh mesh::Halo halo_; - size_t nb_nodes_; - mutable long nb_nodes_global_{-1}; - size_t nb_levels_; + idx_t nb_levels_; + idx_t nb_nodes_; + mutable idx_t nb_nodes_global_{-1}; - mutable eckit::SharedPtr gather_scatter_; // without ghost - mutable eckit::SharedPtr halo_exchange_; - mutable eckit::SharedPtr checksum_; + mutable util::ObjectHandle gather_scatter_; // without ghost + mutable util::ObjectHandle halo_exchange_; + mutable util::ObjectHandle checksum_; private: template struct FieldStatisticsT { FieldStatisticsT( const NodeColumns* ); - void sum( const Field&, Value& sum, size_t& N ) const; - void orderIndependentSum( const Field&, Value& sum, size_t& N ) const; + void sum( const Field&, Value& sum, idx_t& N ) const; + void orderIndependentSum( const Field&, Value& sum, idx_t& N ) const; void minimum( const Field&, Value& minimum ) const; void maximum( const Field&, Value& maximum ) const; void minimumAndLocation( const Field&, Value& minimum, gidx_t& glb_idx ) const; void maximumAndLocation( const Field&, Value& maximum, gidx_t& glb_idx ) const; - void minimumAndLocation( const Field&, Value& minimum, gidx_t& glb_idx, size_t& level ) const; - void maximumAndLocation( const Field&, Value& maximum, gidx_t& glb_idx, size_t& level ) const; - void mean( const Field&, Value& mean, size_t& N ) const; - void meanAndStandardDeviation( const Field&, Value& mean, Value& stddev, size_t& N ) const; + void minimumAndLocation( const Field&, Value& minimum, gidx_t& glb_idx, idx_t& level ) const; + void maximumAndLocation( const Field&, Value& maximum, gidx_t& glb_idx, idx_t& level ) const; + void mean( const Field&, Value& mean, idx_t& N ) const; + void meanAndStandardDeviation( const Field&, Value& mean, Value& stddev, idx_t& N ) const; const NodeColumns& functionspace; }; template struct FieldStatisticsVectorT { FieldStatisticsVectorT( const NodeColumns* ); - void sum( const Field&, Vector& sum, size_t& N ) const; - void orderIndependentSum( const Field&, Vector&, size_t& N ) const; + void sum( const Field&, Vector& sum, idx_t& N ) const; + void orderIndependentSum( const Field&, Vector&, idx_t& N ) const; void minimum( const Field&, Vector& ) const; void maximum( const Field&, Vector& ) const; void minimumAndLocation( const Field&, Vector& minimum, std::vector& glb_idx ) const; void maximumAndLocation( const Field&, Vector& maximum, std::vector& glb_idx ) const; void minimumAndLocation( const Field&, Vector& minimum, std::vector& glb_idx, - std::vector& level ) const; + std::vector& level ) const; void maximumAndLocation( const Field&, Vector& maximum, std::vector& glb_idx, - std::vector& level ) const; - void mean( const Field&, Vector& mean, size_t& N ) const; - void meanAndStandardDeviation( const Field&, Vector& mean, Vector& stddev, size_t& N ) const; + std::vector& level ) const; + void mean( const Field&, Vector& mean, idx_t& N ) const; + void meanAndStandardDeviation( const Field&, Vector& mean, Vector& stddev, idx_t& N ) const; const NodeColumns& functionspace; }; struct FieldStatistics { FieldStatistics( const NodeColumns* ); - void sumPerLevel( const Field&, Field& sum, size_t& N ) const; - void orderIndependentSumPerLevel( const Field&, Field& sum, size_t& N ) const; + void sumPerLevel( const Field&, Field& sum, idx_t& N ) const; + void orderIndependentSumPerLevel( const Field&, Field& sum, idx_t& N ) const; void minimumPerLevel( const Field&, Field& min ) const; void maximumPerLevel( const Field&, Field& max ) const; void minimumAndLocationPerLevel( const Field&, Field& column, Field& glb_idx ) const; void maximumAndLocationPerLevel( const Field&, Field& column, Field& glb_idx ) const; - void meanPerLevel( const Field&, Field& mean, size_t& N ) const; - void meanAndStandardDeviationPerLevel( const Field&, Field& mean, Field& stddev, size_t& N ) const; + void meanPerLevel( const Field&, Field& mean, idx_t& N ) const; + void meanAndStandardDeviationPerLevel( const Field&, Field& mean, Field& stddev, idx_t& N ) const; const NodeColumns& functionspace; }; @@ -334,20 +338,20 @@ class NodeColumns : public FunctionSpaceImpl { // ------------------------------------------------------------------- template -void NodeColumns::sum( const Field& field, Value& sum, size_t& N ) const { +void NodeColumns::sum( const Field& field, Value& sum, idx_t& N ) const { typename FieldStatisticsSelector::type( this ).sum( field, sum, N ); } -inline void NodeColumns::sumPerLevel( const Field& field, Field& sum, size_t& N ) const { +inline void NodeColumns::sumPerLevel( const Field& field, Field& sum, idx_t& N ) const { FieldStatistics( this ).sumPerLevel( field, sum, N ); } template -void NodeColumns::orderIndependentSum( const Field& field, Value& sum, size_t& N ) const { +void NodeColumns::orderIndependentSum( const Field& field, Value& sum, idx_t& N ) const { typename FieldStatisticsSelector::type( this ).orderIndependentSum( field, sum, N ); } -inline void NodeColumns::orderIndependentSumPerLevel( const Field& field, Field& sum, size_t& N ) const { +inline void NodeColumns::orderIndependentSumPerLevel( const Field& field, Field& sum, idx_t& N ) const { FieldStatistics( this ).orderIndependentSumPerLevel( field, sum, N ); } @@ -380,12 +384,12 @@ void NodeColumns::maximumAndLocation( const Field& field, Value& maximum, gidx_t } template -void NodeColumns::minimumAndLocation( const Field& field, Value& minimum, gidx_t& glb_idx, size_t& level ) const { +void NodeColumns::minimumAndLocation( const Field& field, Value& minimum, gidx_t& glb_idx, idx_t& level ) const { FieldStatisticsT( this ).minimumAndLocation( field, minimum, glb_idx, level ); } template -void NodeColumns::maximumAndLocation( const Field& field, Value& maximum, gidx_t& glb_idx, size_t& level ) const { +void NodeColumns::maximumAndLocation( const Field& field, Value& maximum, gidx_t& glb_idx, idx_t& level ) const { FieldStatisticsT( this ).maximumAndLocation( field, maximum, glb_idx, level ); } @@ -401,13 +405,13 @@ void NodeColumns::maximumAndLocation( const Field& field, Vector& maximum, std:: template void NodeColumns::minimumAndLocation( const Field& field, Vector& minimum, std::vector& glb_idx, - std::vector& level ) const { + std::vector& level ) const { FieldStatisticsVectorT( this ).minimumAndLocation( field, minimum, glb_idx, level ); } template void NodeColumns::maximumAndLocation( const Field& field, Vector& maximum, std::vector& glb_idx, - std::vector& level ) const { + std::vector& level ) const { FieldStatisticsVectorT( this ).maximumAndLocation( field, maximum, glb_idx, level ); } @@ -420,21 +424,21 @@ inline void NodeColumns::maximumAndLocationPerLevel( const Field& field, Field& } template -void NodeColumns::mean( const Field& field, Value& mean, size_t& N ) const { +void NodeColumns::mean( const Field& field, Value& mean, idx_t& N ) const { typename FieldStatisticsSelector::type( this ).mean( field, mean, N ); } -inline void NodeColumns::meanPerLevel( const Field& field, Field& mean, size_t& N ) const { +inline void NodeColumns::meanPerLevel( const Field& field, Field& mean, idx_t& N ) const { FieldStatistics( this ).meanPerLevel( field, mean, N ); } template -void NodeColumns::meanAndStandardDeviation( const Field& field, Value& mean, Value& stddev, size_t& N ) const { +void NodeColumns::meanAndStandardDeviation( const Field& field, Value& mean, Value& stddev, idx_t& N ) const { typename FieldStatisticsSelector::type( this ).meanAndStandardDeviation( field, mean, stddev, N ); } inline void NodeColumns::meanAndStandardDeviationPerLevel( const Field& field, Field& mean, Field& stddev, - size_t& N ) const { + idx_t& N ) const { FieldStatistics( this ).meanAndStandardDeviationPerLevel( field, mean, stddev, N ); } @@ -455,12 +459,12 @@ class NodeColumns : public FunctionSpace { operator bool() const { return valid(); } bool valid() const { return functionspace_; } - size_t nb_nodes() const; - size_t nb_nodes_global() const; // All MPI ranks will have same output + idx_t nb_nodes() const; + idx_t nb_nodes_global() const; // All MPI ranks will have same output const Mesh& mesh() const; - size_t levels() const; + idx_t levels() const; mesh::Nodes& nodes() const; @@ -468,8 +472,8 @@ class NodeColumns : public FunctionSpace { const mesh::Halo& halo() const; - void haloExchange( FieldSet&, bool on_device = false ) const; - void haloExchange( Field&, bool on_device = false ) const; + void haloExchange( const FieldSet&, bool on_device = false ) const; + void haloExchange( const Field&, bool on_device = false ) const; const parallel::HaloExchange& halo_exchange() const; void gather( const FieldSet&, FieldSet& ) const; @@ -489,7 +493,7 @@ class NodeColumns : public FunctionSpace { /// @param [out] N Number of values that are contained in the sum /// (nodes*levels) template - void sum( const Field&, Value& sum, size_t& N ) const; + void sum( const Field&, Value& sum, idx_t& N ) const; // /// @brief Compute sum of field for each variable // /// @param [out] sum For each field-variable, the sum of the full 3D @@ -497,19 +501,19 @@ class NodeColumns : public FunctionSpace { // /// @param [out] N Number of values that are contained in the sum // (nodes*levels) // template< typename Value > - // void sum( const Field&, std::vector& sum, size_t& N ) const; + // void sum( const Field&, std::vector& sum, idx_t& N ) const; /// @brief Compute sum of field for each vertical level separately /// @param [out] sum Field of dimension of input without the nodes index /// @param [out] N Number of nodes used to sum each level - void sumPerLevel( const Field&, Field& sum, size_t& N ) const; + void sumPerLevel( const Field&, Field& sum, idx_t& N ) const; /// @brief Compute order independent sum of scalar field /// @param [out] sum Scalar value containing the sum of the full 3D field /// @param [out] N Number of values that are contained in the sum /// (nodes*levels) template - void orderIndependentSum( const Field&, Value& sum, size_t& N ) const; + void orderIndependentSum( const Field&, Value& sum, idx_t& N ) const; // /// @brief Compute order independent sum of field for each variable // /// @param [out] sum For each field-variable, the sum of the full 3D @@ -517,14 +521,14 @@ class NodeColumns : public FunctionSpace { // /// @param [out] N Number of values that are contained in the sum // (nodes*levels) // template< typename Value > - // void orderIndependentSum( const Field&, std::vector&, size_t& N ) + // void orderIndependentSum( const Field&, std::vector&, idx_t& N ) // const; /// @brief Compute order independent sum of field for each vertical level /// separately /// @param [out] sum Field of dimension of input without the nodes index /// @param [out] N Number of nodes used to sum each level - void orderIndependentSumPerLevel( const Field&, Field& sum, size_t& N ) const; + void orderIndependentSumPerLevel( const Field&, Field& sum, idx_t& N ) const; /// @brief Compute minimum of scalar field template @@ -563,12 +567,12 @@ class NodeColumns : public FunctionSpace { /// @brief Compute minimum of scalar field, as well as the global index and /// level. template - void minimumAndLocation( const Field&, Value& minimum, gidx_t& glb_idx, size_t& level ) const; + void minimumAndLocation( const Field&, Value& minimum, gidx_t& glb_idx, idx_t& level ) const; /// @brief Compute maximum of scalar field, as well as the global index and /// level. template - void maximumAndLocation( const Field&, Value& maximum, gidx_t& glb_idx, size_t& level ) const; + void maximumAndLocation( const Field&, Value& maximum, gidx_t& glb_idx, idx_t& level ) const; /// @brief Compute minimum of field for each field-variable, as well as the /// global indices and levels. @@ -584,13 +588,13 @@ class NodeColumns : public FunctionSpace { /// global indices and levels. template void minimumAndLocation( const Field&, std::vector& minimum, std::vector& glb_idx, - std::vector& level ) const; + std::vector& level ) const; /// @brief Compute maximum of field for each field-variable, as well as the /// global indices and levels. template void maximumAndLocation( const Field&, std::vector& maximum, std::vector& glb_idx, - std::vector& level ) const; + std::vector& level ) const; /// @brief Compute minimum and its location of a field for each vertical level /// separately @@ -604,25 +608,25 @@ class NodeColumns : public FunctionSpace { /// @param [out] mean Mean value /// @param [out] N Number of value used to create the mean template - void mean( const Field&, Value& mean, size_t& N ) const; + void mean( const Field&, Value& mean, idx_t& N ) const; // /// @brief Compute mean value of field for each field-variable // /// @param [out] mean Mean values for each variable // /// @param [out] N Number of values used to create the means // template< typename Value > - // void mean( const Field&, std::vector& mean, size_t& N ) const; + // void mean( const Field&, std::vector& mean, idx_t& N ) const; /// @brief Compute mean values of field for vertical level separately /// @param [out] mean Field of dimension of input without the nodes index /// @param [out] N Number of values used to create the means - void meanPerLevel( const Field&, Field& mean, size_t& N ) const; + void meanPerLevel( const Field&, Field& mean, idx_t& N ) const; /// @brief Compute mean value and standard deviation of scalar field /// @param [out] mean Mean value /// @param [out] stddev Standard deviation /// @param [out] N Number of value used to create the mean template - void meanAndStandardDeviation( const Field&, Value& mean, Value& stddev, size_t& N ) const; + void meanAndStandardDeviation( const Field&, Value& mean, Value& stddev, idx_t& N ) const; // /// @brief Compute mean values and standard deviations of scalar field // for each field-variable @@ -631,14 +635,14 @@ class NodeColumns : public FunctionSpace { // /// @param [out] N Number of value used to create the means // template< typename Value > // void meanAndStandardDeviation( const Field&, std::vector& mean, - // std::vector& stddev, size_t& N ) const; + // std::vector& stddev, idx_t& N ) const; /// @brief Compute mean values and standard deviations of field for vertical /// level separately /// @param [out] mean Field of dimension of input without the nodes index /// @param [out] stddev Field of dimension of input without the nodes index /// @param [out] N Number of values used to create the means - void meanAndStandardDeviationPerLevel( const Field&, Field& mean, Field& stddev, size_t& N ) const; + void meanAndStandardDeviationPerLevel( const Field&, Field& mean, Field& stddev, idx_t& N ) const; private: const detail::NodeColumns* functionspace_; @@ -646,25 +650,25 @@ class NodeColumns : public FunctionSpace { // ------------------------------------------------------------------- -inline size_t NodeColumns::levels() const { +inline idx_t NodeColumns::levels() const { return functionspace_->levels(); } template -void NodeColumns::sum( const Field& field, Value& sum, size_t& N ) const { +void NodeColumns::sum( const Field& field, Value& sum, idx_t& N ) const { functionspace_->sum( field, sum, N ); } -inline void NodeColumns::sumPerLevel( const Field& field, Field& sum, size_t& N ) const { +inline void NodeColumns::sumPerLevel( const Field& field, Field& sum, idx_t& N ) const { functionspace_->sumPerLevel( field, sum, N ); } template -void NodeColumns::orderIndependentSum( const Field& field, Value& sum, size_t& N ) const { +void NodeColumns::orderIndependentSum( const Field& field, Value& sum, idx_t& N ) const { functionspace_->orderIndependentSum( field, sum, N ); } -inline void NodeColumns::orderIndependentSumPerLevel( const Field& field, Field& sum, size_t& N ) const { +inline void NodeColumns::orderIndependentSumPerLevel( const Field& field, Field& sum, idx_t& N ) const { functionspace_->orderIndependentSumPerLevel( field, sum, N ); } @@ -697,12 +701,12 @@ void NodeColumns::maximumAndLocation( const Field& field, Value& maximum, gidx_t } template -void NodeColumns::minimumAndLocation( const Field& field, Value& minimum, gidx_t& glb_idx, size_t& level ) const { +void NodeColumns::minimumAndLocation( const Field& field, Value& minimum, gidx_t& glb_idx, idx_t& level ) const { functionspace_->minimumAndLocation( field, minimum, glb_idx, level ); } template -void NodeColumns::maximumAndLocation( const Field& field, Value& maximum, gidx_t& glb_idx, size_t& level ) const { +void NodeColumns::maximumAndLocation( const Field& field, Value& maximum, gidx_t& glb_idx, idx_t& level ) const { functionspace_->maximumAndLocation( field, maximum, glb_idx, level ); } @@ -720,13 +724,13 @@ void NodeColumns::maximumAndLocation( const Field& field, std::vector& ma template void NodeColumns::minimumAndLocation( const Field& field, std::vector& minimum, std::vector& glb_idx, - std::vector& level ) const { + std::vector& level ) const { functionspace_->minimumAndLocation( field, minimum, glb_idx, level ); } template void NodeColumns::maximumAndLocation( const Field& field, std::vector& maximum, std::vector& glb_idx, - std::vector& level ) const { + std::vector& level ) const { functionspace_->maximumAndLocation( field, maximum, glb_idx, level ); } @@ -739,21 +743,21 @@ inline void NodeColumns::maximumAndLocationPerLevel( const Field& field, Field& } template -void NodeColumns::mean( const Field& field, Value& mean, size_t& N ) const { +void NodeColumns::mean( const Field& field, Value& mean, idx_t& N ) const { functionspace_->mean( field, mean, N ); } -inline void NodeColumns::meanPerLevel( const Field& field, Field& mean, size_t& N ) const { +inline void NodeColumns::meanPerLevel( const Field& field, Field& mean, idx_t& N ) const { functionspace_->meanPerLevel( field, mean, N ); } template -void NodeColumns::meanAndStandardDeviation( const Field& field, Value& mean, Value& stddev, size_t& N ) const { +void NodeColumns::meanAndStandardDeviation( const Field& field, Value& mean, Value& stddev, idx_t& N ) const { functionspace_->meanAndStandardDeviation( field, mean, stddev, N ); } inline void NodeColumns::meanAndStandardDeviationPerLevel( const Field& field, Field& mean, Field& stddev, - size_t& N ) const { + idx_t& N ) const { functionspace_->meanAndStandardDeviationPerLevel( field, mean, stddev, N ); } diff --git a/src/atlas/functionspace/NodeColumnsInterface.cc b/src/atlas/functionspace/NodeColumnsInterface.cc deleted file mode 100644 index c139649e8..000000000 --- a/src/atlas/functionspace/NodeColumnsInterface.cc +++ /dev/null @@ -1,1003 +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/functionspace/NodeColumnsInterface.h" -#include "atlas/field/detail/FieldImpl.h" -#include "atlas/runtime/ErrorHandling.h" - -namespace atlas { -namespace functionspace { -namespace detail { - -using atlas::FieldSet; -using atlas::field::FieldImpl; -using atlas::field::FieldSetImpl; - -// ---------------------------------------------------------------------- - -extern "C" { -const NodeColumns* atlas__NodesFunctionSpace__new( Mesh::Implementation* mesh, const eckit::Configuration* config ) { - ASSERT( mesh ); - Mesh m( mesh ); - return new NodeColumns( m, *config ); -} - -void atlas__NodesFunctionSpace__delete( NodeColumns* This ) { - ASSERT( This ); - delete ( This ); -} - -int atlas__NodesFunctionSpace__nb_nodes( const NodeColumns* This ) { - ASSERT( This ); - return This->nb_nodes(); -} - -const Mesh::Implementation* atlas__NodesFunctionSpace__mesh( const NodeColumns* This ) { - ASSERT( This ); - return This->mesh().get(); -} - -mesh::Nodes* atlas__NodesFunctionSpace__nodes( const NodeColumns* This ) { - ASSERT( This ); - return &This->nodes(); -} - -field::FieldImpl* atlas__NodesFunctionSpace__create_field( const NodeColumns* This, - const eckit::Configuration* options ) { - ASSERT( This ); - ASSERT( options ); - FieldImpl* field; - { - Field f = This->createField( util::Config( *options ) ); - field = f.get(); - field->attach(); - } - field->detach(); - return field; -} - -field::FieldImpl* atlas__NodesFunctionSpace__create_field_template( const NodeColumns* This, - const field::FieldImpl* field_template, - const eckit::Configuration* options ) { - ASSERT( This ); - ASSERT( options ); - FieldImpl* field; - { - Field f = This->createField( Field( field_template ), *options ); - field = f.get(); - field->attach(); - } - field->detach(); - return field; -} - -void atlas__NodesFunctionSpace__halo_exchange_fieldset( const NodeColumns* This, field::FieldSetImpl* fieldset ) { - ASSERT( This ); - ASSERT( fieldset ); - FieldSet f( fieldset ); - ATLAS_ERROR_HANDLING( This->haloExchange( f ); ); -} - -void atlas__NodesFunctionSpace__halo_exchange_field( const NodeColumns* This, field::FieldImpl* field ) { - ASSERT( This ); - ASSERT( field ); - Field f( field ); - ATLAS_ERROR_HANDLING( This->haloExchange( f ); ); -} - -const parallel::HaloExchange* atlas__NodesFunctionSpace__get_halo_exchange( const NodeColumns* This ) { - ASSERT( This ); - ATLAS_ERROR_HANDLING( return &This->halo_exchange(); ); - return 0; -} - -void atlas__NodesFunctionSpace__gather_fieldset( const NodeColumns* This, const field::FieldSetImpl* local, - field::FieldSetImpl* global ) { - ASSERT( This ); - ASSERT( local ); - ASSERT( global ); - const FieldSet l( local ); - FieldSet g( global ); - ATLAS_ERROR_HANDLING( This->gather( l, g ); ); -} - -void atlas__NodesFunctionSpace__gather_field( const NodeColumns* This, const field::FieldImpl* local, - field::FieldImpl* global ) { - ASSERT( This ); - ASSERT( local ); - ASSERT( global ); - const Field l( local ); - Field g( global ); - ATLAS_ERROR_HANDLING( This->gather( l, g ); ); -} - -const parallel::GatherScatter* atlas__NodesFunctionSpace__get_gather( const NodeColumns* This ) { - ASSERT( This ); - ATLAS_ERROR_HANDLING( return &This->gather(); ); - return 0; -} - -const parallel::GatherScatter* atlas__NodesFunctionSpace__get_scatter( const NodeColumns* This ) { - ASSERT( This ); - ATLAS_ERROR_HANDLING( return &This->scatter(); ); - return 0; -} - -void atlas__NodesFunctionSpace__scatter_fieldset( const NodeColumns* This, const field::FieldSetImpl* global, - field::FieldSetImpl* local ) { - ASSERT( This ); - ASSERT( local ); - ASSERT( global ); - const FieldSet g( global ); - FieldSet l( local ); - ATLAS_ERROR_HANDLING( This->scatter( g, l ); ); -} - -void atlas__NodesFunctionSpace__scatter_field( const NodeColumns* This, const field::FieldImpl* global, - field::FieldImpl* local ) { - ASSERT( This ); - ASSERT( global ); - ASSERT( local ); - const Field g( global ); - Field l( local ); - ATLAS_ERROR_HANDLING( This->scatter( g, l ); ); -} - -const parallel::Checksum* atlas__NodesFunctionSpace__get_checksum( const NodeColumns* This ) { - ASSERT( This ); - ATLAS_ERROR_HANDLING( return &This->checksum(); ); - return 0; -} - -void atlas__NodesFunctionSpace__checksum_fieldset( const NodeColumns* This, const field::FieldSetImpl* fieldset, - char*& checksum, int& size, int& allocated ) { - ASSERT( This ); - ASSERT( fieldset ); - ATLAS_ERROR_HANDLING( std::string checksum_str( This->checksum( fieldset ) ); size = checksum_str.size(); - checksum = new char[size + 1]; allocated = true; strcpy( checksum, checksum_str.c_str() ); ); -} - -void atlas__NodesFunctionSpace__checksum_field( const NodeColumns* This, const field::FieldImpl* field, char*& checksum, - int& size, int& allocated ) { - ASSERT( This ); - ASSERT( field ); - ATLAS_ERROR_HANDLING( std::string checksum_str( This->checksum( field ) ); size = checksum_str.size(); - checksum = new char[size + 1]; allocated = true; strcpy( checksum, checksum_str.c_str() ); ); -} - -void atlas__NodesFunctionSpace__sum_double( const NodeColumns* This, const field::FieldImpl* field, double& sum, - int& N ) { - ASSERT( This ); - ASSERT( field ); - size_t size_t_N; - ATLAS_ERROR_HANDLING( This->sum( field, sum, size_t_N ) ); - N = size_t_N; -} - -void atlas__NodesFunctionSpace__sum_float( const NodeColumns* This, const field::FieldImpl* field, float& sum, - int& N ) { - ASSERT( This ); - ASSERT( field ); - size_t size_t_N; - ATLAS_ERROR_HANDLING( This->sum( field, sum, size_t_N ) ); - N = size_t_N; -} - -void atlas__NodesFunctionSpace__sum_long( const NodeColumns* This, const field::FieldImpl* field, long& sum, int& N ) { - ASSERT( This ); - ASSERT( field ); - size_t size_t_N; - ATLAS_ERROR_HANDLING( This->sum( field, sum, size_t_N ) ); - N = size_t_N; -} - -void atlas__NodesFunctionSpace__sum_int( const NodeColumns* This, const field::FieldImpl* field, int& sum, int& N ) { - ASSERT( This ); - ASSERT( field ); - size_t size_t_N; - ATLAS_ERROR_HANDLING( This->sum( field, sum, size_t_N ) ); - N = size_t_N; -} - -void atlas__NodesFunctionSpace__sum_arr_double( const NodeColumns* This, const field::FieldImpl* field, double*& sum, - int& size, int& N ) { - ASSERT( This ); - ASSERT( field ); - size_t size_t_N; - ATLAS_ERROR_HANDLING( std::vector sumvec; This->orderIndependentSum( field, sumvec, size_t_N ); - size = sumvec.size(); sum = new double[size]; - for ( size_t j = 0; j < (size_t)size; ++j ) sum[j] = sumvec[j]; ); - N = size_t_N; -} - -void atlas__NodesFunctionSpace__sum_arr_float( const NodeColumns* This, const field::FieldImpl* field, float*& sum, - int& size, int& N ) { - ASSERT( This ); - ASSERT( field ); - size_t size_t_N; - ATLAS_ERROR_HANDLING( std::vector sumvec; This->orderIndependentSum( field, sumvec, size_t_N ); - size = sumvec.size(); sum = new float[size]; - for ( size_t j = 0; j < (size_t)size; ++j ) sum[j] = sumvec[j]; ); - N = size_t_N; -} - -void atlas__NodesFunctionSpace__sum_arr_long( const NodeColumns* This, const field::FieldImpl* field, long*& sum, - int& size, int& N ) { - ASSERT( This ); - ASSERT( field ); - size_t size_t_N; - ATLAS_ERROR_HANDLING( std::vector sumvec; This->orderIndependentSum( field, sumvec, size_t_N ); - size = sumvec.size(); sum = new long[size]; - for ( size_t j = 0; j < (size_t)size; ++j ) sum[j] = sumvec[j]; ); - N = size_t_N; -} - -void atlas__NodesFunctionSpace__sum_arr_int( const NodeColumns* This, const field::FieldImpl* field, int*& sum, - int& size, int& N ) { - ASSERT( This ); - ASSERT( field ); - size_t size_t_N; - ATLAS_ERROR_HANDLING( std::vector sumvec; This->orderIndependentSum( field, sumvec, size_t_N ); - size = sumvec.size(); sum = new int[size]; - for ( size_t j = 0; j < (size_t)size; ++j ) sum[j] = sumvec[j]; ); - N = size_t_N; -} - -void atlas__NodesFunctionSpace__oisum_double( const NodeColumns* This, const field::FieldImpl* field, double& sum, - int& N ) { - ASSERT( This ); - ASSERT( field ); - size_t size_t_N; - ATLAS_ERROR_HANDLING( This->orderIndependentSum( field, sum, size_t_N ) ); - N = size_t_N; -} - -void atlas__NodesFunctionSpace__oisum_float( const NodeColumns* This, const field::FieldImpl* field, float& sum, - int& N ) { - ASSERT( This ); - ASSERT( field ); - size_t size_t_N; - ATLAS_ERROR_HANDLING( This->orderIndependentSum( field, sum, size_t_N ) ); - N = size_t_N; -} - -void atlas__NodesFunctionSpace__oisum_arr_double( const NodeColumns* This, const field::FieldImpl* field, double*& sum, - int& size, int& N ) { - ASSERT( This ); - ASSERT( field ); - size_t size_t_N; - ATLAS_ERROR_HANDLING( std::vector sumvec; This->orderIndependentSum( field, sumvec, size_t_N ); - size = sumvec.size(); sum = new double[size]; - for ( size_t j = 0; j < (size_t)size; ++j ) sum[j] = sumvec[j]; ); - N = size_t_N; -} - -void atlas__NodesFunctionSpace__oisum_arr_float( const NodeColumns* This, const field::FieldImpl* field, float*& sum, - int& size, int& N ) { - ASSERT( This ); - ASSERT( field ); - size_t size_t_N; - ATLAS_ERROR_HANDLING( std::vector sumvec; This->orderIndependentSum( field, sumvec, size_t_N ); - size = sumvec.size(); sum = new float[size]; - for ( size_t j = 0; j < (size_t)size; ++j ) sum[j] = sumvec[j]; ); - N = size_t_N; -} - -void atlas__NodesFunctionSpace__min_double( const NodeColumns* This, const field::FieldImpl* field, double& minimum ) { - ASSERT( This ); - ASSERT( field ); - ATLAS_ERROR_HANDLING( This->minimum( field, minimum ) ); -} - -void atlas__NodesFunctionSpace__min_float( const NodeColumns* This, const field::FieldImpl* field, float& minimum ) { - ASSERT( This ); - ASSERT( field ); - ATLAS_ERROR_HANDLING( This->minimum( field, minimum ) ); -} - -void atlas__NodesFunctionSpace__min_long( const NodeColumns* This, const field::FieldImpl* field, long& minimum ) { - ASSERT( This ); - ASSERT( field ); - ATLAS_ERROR_HANDLING( This->minimum( field, minimum ) ); -} - -void atlas__NodesFunctionSpace__min_int( const NodeColumns* This, const field::FieldImpl* field, int& minimum ) { - ASSERT( This ); - ASSERT( field ); - ATLAS_ERROR_HANDLING( This->minimum( field, minimum ) ); -} - -void atlas__NodesFunctionSpace__max_double( const NodeColumns* This, const field::FieldImpl* field, double& maximum ) { - ASSERT( This ); - ASSERT( field ); - ATLAS_ERROR_HANDLING( This->maximum( field, maximum ) ); -} - -void atlas__NodesFunctionSpace__max_float( const NodeColumns* This, const field::FieldImpl* field, float& maximum ) { - ASSERT( This ); - ASSERT( field ); - ATLAS_ERROR_HANDLING( This->maximum( field, maximum ) ); -} - -void atlas__NodesFunctionSpace__max_long( const NodeColumns* This, const field::FieldImpl* field, long& maximum ) { - ASSERT( This ); - ASSERT( field ); - ATLAS_ERROR_HANDLING( This->maximum( field, maximum ) ); -} - -void atlas__NodesFunctionSpace__max_int( const NodeColumns* This, const field::FieldImpl* field, int& maximum ) { - ASSERT( This ); - ASSERT( field ); - ATLAS_ERROR_HANDLING( This->maximum( field, maximum ) ); -} - -void atlas__NodesFunctionSpace__min_arr_double( const NodeColumns* This, const field::FieldImpl* field, - double*& minimum, int& size ) { - ASSERT( This ); - ASSERT( field ); - ATLAS_ERROR_HANDLING( std::vector minvec; This->minimum( field, minvec ); size = minvec.size(); - minimum = new double[size]; - for ( size_t j = 0; j < (size_t)size; ++j ) minimum[j] = minvec[j]; ); -} - -void atlas__NodesFunctionSpace__min_arr_float( const NodeColumns* This, const field::FieldImpl* field, float*& minimum, - int& size ) { - ASSERT( This ); - ASSERT( field ); - ATLAS_ERROR_HANDLING( std::vector minvec; This->minimum( field, minvec ); size = minvec.size(); - minimum = new float[size]; - for ( size_t j = 0; j < (size_t)size; ++j ) minimum[j] = minvec[j]; ); -} - -void atlas__NodesFunctionSpace__min_arr_long( const NodeColumns* This, const field::FieldImpl* field, long*& minimum, - int& size ) { - ASSERT( This ); - ASSERT( field ); - ATLAS_ERROR_HANDLING( std::vector minvec; This->minimum( field, minvec ); size = minvec.size(); - minimum = new long[size]; - for ( size_t j = 0; j < (size_t)size; ++j ) minimum[j] = minvec[j]; ); -} - -void atlas__NodesFunctionSpace__min_arr_int( const NodeColumns* This, const field::FieldImpl* field, int*& minimum, - int& size ) { - ASSERT( This ); - ASSERT( field ); - ATLAS_ERROR_HANDLING( std::vector minvec; This->minimum( field, minvec ); size = minvec.size(); - minimum = new int[size]; - for ( size_t j = 0; j < (size_t)size; ++j ) minimum[j] = minvec[j]; ); -} - -void atlas__NodesFunctionSpace__max_arr_double( const NodeColumns* This, const field::FieldImpl* field, - double*& maximum, int& size ) { - ASSERT( This ); - ASSERT( field ); - ATLAS_ERROR_HANDLING( std::vector maxvec; This->maximum( field, maxvec ); size = maxvec.size(); - maximum = new double[size]; - for ( size_t j = 0; j < (size_t)size; ++j ) maximum[j] = maxvec[j]; ); -} - -void atlas__NodesFunctionSpace__max_arr_float( const NodeColumns* This, const field::FieldImpl* field, float*& maximum, - int& size ) { - ASSERT( This ); - ASSERT( field ); - ATLAS_ERROR_HANDLING( std::vector maxvec; This->maximum( field, maxvec ); size = maxvec.size(); - maximum = new float[size]; - for ( size_t j = 0; j < (size_t)size; ++j ) maximum[j] = maxvec[j]; ); -} - -void atlas__NodesFunctionSpace__max_arr_long( const NodeColumns* This, const field::FieldImpl* field, long*& maximum, - int& size ) { - ASSERT( This ); - ASSERT( field ); - ATLAS_ERROR_HANDLING( std::vector maxvec; This->maximum( field, maxvec ); size = maxvec.size(); - maximum = new long[size]; - for ( size_t j = 0; j < (size_t)size; ++j ) maximum[j] = maxvec[j]; ); -} - -void atlas__NodesFunctionSpace__max_arr_int( const NodeColumns* This, const field::FieldImpl* field, int*& maximum, - int& size ) { - ASSERT( This ); - ASSERT( field ); - ATLAS_ERROR_HANDLING( std::vector maxvec; This->maximum( field, maxvec ); size = maxvec.size(); - maximum = new int[size]; - for ( size_t j = 0; j < (size_t)size; ++j ) maximum[j] = maxvec[j]; ); -} - -void atlas__NodesFunctionSpace__minloc_double( const NodeColumns* This, const field::FieldImpl* field, double& minimum, - long& glb_idx ) { - ASSERT( This ); - ASSERT( field ); - gidx_t gidx; - ATLAS_ERROR_HANDLING( This->minimumAndLocation( field, minimum, gidx ) ); - glb_idx = gidx; -} - -void atlas__NodesFunctionSpace__minloc_float( const NodeColumns* This, const field::FieldImpl* field, float& minimum, - long& glb_idx ) { - ASSERT( This ); - ASSERT( field ); - gidx_t gidx; - ATLAS_ERROR_HANDLING( This->minimumAndLocation( field, minimum, gidx ) ); - glb_idx = gidx; -} - -void atlas__NodesFunctionSpace__minloc_long( const NodeColumns* This, const field::FieldImpl* field, long& minimum, - long& glb_idx ) { - ASSERT( This ); - ASSERT( field ); - gidx_t gidx; - ATLAS_ERROR_HANDLING( This->minimumAndLocation( field, minimum, gidx ) ); - glb_idx = gidx; -} - -void atlas__NodesFunctionSpace__minloc_int( const NodeColumns* This, const field::FieldImpl* field, int& minimum, - long& glb_idx ) { - ASSERT( This ); - ASSERT( field ); - gidx_t gidx; - ATLAS_ERROR_HANDLING( This->minimumAndLocation( field, minimum, gidx ) ); - glb_idx = gidx; -} - -void atlas__NodesFunctionSpace__maxloc_double( const NodeColumns* This, const field::FieldImpl* field, double& maximum, - long& glb_idx ) { - ASSERT( This ); - ASSERT( field ); - gidx_t gidx; - ATLAS_ERROR_HANDLING( This->maximumAndLocation( field, maximum, gidx ) ); - glb_idx = gidx; -} - -void atlas__NodesFunctionSpace__maxloc_float( const NodeColumns* This, const field::FieldImpl* field, float& maximum, - long& glb_idx ) { - ASSERT( This ); - ASSERT( field ); - gidx_t gidx; - ATLAS_ERROR_HANDLING( This->maximumAndLocation( field, maximum, gidx ) ); - glb_idx = gidx; -} - -void atlas__NodesFunctionSpace__maxloc_long( const NodeColumns* This, const field::FieldImpl* field, long& maximum, - long& glb_idx ) { - ASSERT( This ); - ASSERT( field ); - gidx_t gidx; - ATLAS_ERROR_HANDLING( This->maximumAndLocation( field, maximum, gidx ) ); - glb_idx = gidx; -} - -void atlas__NodesFunctionSpace__maxloc_int( const NodeColumns* This, const field::FieldImpl* field, int& maximum, - long& glb_idx ) { - ASSERT( This ); - ASSERT( field ); - gidx_t gidx; - ATLAS_ERROR_HANDLING( This->maximumAndLocation( field, maximum, gidx ) ); - glb_idx = gidx; -} - -void atlas__NodesFunctionSpace__minloc_arr_double( const NodeColumns* This, const field::FieldImpl* field, - double*& minimum, long*& glb_idx, int& size ) { - ASSERT( This ); - ASSERT( field ); - ATLAS_ERROR_HANDLING( std::vector minvec; std::vector gidxvec; - This->minimumAndLocation( field, minvec, gidxvec ); size = minvec.size(); - minimum = new double[size]; glb_idx = new long[size]; - for ( size_t j = 0; j < (size_t)size; ++j ) { - minimum[j] = minvec[j]; - glb_idx[j] = gidxvec[j]; - } ); -} - -void atlas__NodesFunctionSpace__minloc_arr_float( const NodeColumns* This, const field::FieldImpl* field, - float*& minimum, long*& glb_idx, int& size ) { - ASSERT( This ); - ASSERT( field ); - ATLAS_ERROR_HANDLING( std::vector minvec; std::vector gidxvec; - This->minimumAndLocation( field, minvec, gidxvec ); size = minvec.size(); - minimum = new float[size]; glb_idx = new long[size]; - for ( size_t j = 0; j < (size_t)size; ++j ) { - minimum[j] = minvec[j]; - glb_idx[j] = gidxvec[j]; - } ); -} - -void atlas__NodesFunctionSpace__minloc_arr_long( const NodeColumns* This, const field::FieldImpl* field, long*& minimum, - long*& glb_idx, int& size ) { - ASSERT( This ); - ASSERT( field ); - ATLAS_ERROR_HANDLING( std::vector minvec; std::vector gidxvec; - This->minimumAndLocation( field, minvec, gidxvec ); size = minvec.size(); - minimum = new long[size]; glb_idx = new long[size]; - for ( size_t j = 0; j < (size_t)size; ++j ) { - minimum[j] = minvec[j]; - glb_idx[j] = gidxvec[j]; - } ); -} - -void atlas__NodesFunctionSpace__minloc_arr_int( const NodeColumns* This, const field::FieldImpl* field, int*& minimum, - long*& glb_idx, int& size ) { - ASSERT( This ); - ASSERT( field ); - ATLAS_ERROR_HANDLING( std::vector minvec; std::vector gidxvec; - This->minimumAndLocation( field, minvec, gidxvec ); size = minvec.size(); - minimum = new int[size]; glb_idx = new long[size]; - for ( size_t j = 0; j < (size_t)size; ++j ) { - minimum[j] = minvec[j]; - glb_idx[j] = gidxvec[j]; - } ); -} - -void atlas__NodesFunctionSpace__maxloc_arr_double( const NodeColumns* This, const field::FieldImpl* field, - double*& maximum, long*& glb_idx, int& size ) { - ASSERT( This ); - ASSERT( field ); - ATLAS_ERROR_HANDLING( std::vector maxvec; std::vector gidxvec; - This->maximumAndLocation( field, maxvec, gidxvec ); size = maxvec.size(); - maximum = new double[size]; glb_idx = new long[size]; - for ( size_t j = 0; j < (size_t)size; ++j ) { - maximum[j] = maxvec[j]; - glb_idx[j] = gidxvec[j]; - } ); -} - -void atlas__NodesFunctionSpace__maxloc_arr_float( const NodeColumns* This, const field::FieldImpl* field, - float*& maximum, long*& glb_idx, int& size ) { - ASSERT( This ); - ASSERT( field ); - ATLAS_ERROR_HANDLING( std::vector maxvec; std::vector gidxvec; - This->maximumAndLocation( field, maxvec, gidxvec ); size = maxvec.size(); - maximum = new float[size]; glb_idx = new long[size]; - for ( size_t j = 0; j < (size_t)size; ++j ) { - maximum[j] = maxvec[j]; - glb_idx[j] = gidxvec[j]; - } ); -} - -void atlas__NodesFunctionSpace__maxloc_arr_long( const NodeColumns* This, const field::FieldImpl* field, long*& maximum, - long*& glb_idx, int& size ) { - ASSERT( This ); - ASSERT( field ); - ATLAS_ERROR_HANDLING( std::vector maxvec; std::vector gidxvec; - This->maximumAndLocation( field, maxvec, gidxvec ); size = maxvec.size(); - maximum = new long[size]; glb_idx = new long[size]; - for ( size_t j = 0; j < (size_t)size; ++j ) { - maximum[j] = maxvec[j]; - glb_idx[j] = gidxvec[j]; - } ); -} - -void atlas__NodesFunctionSpace__maxloc_arr_int( const NodeColumns* This, const field::FieldImpl* field, int*& maximum, - long*& glb_idx, int& size ) { - ASSERT( This ); - ASSERT( field ); - ATLAS_ERROR_HANDLING( std::vector maxvec; std::vector gidxvec; - This->maximumAndLocation( field, maxvec, gidxvec ); size = maxvec.size(); - maximum = new int[size]; glb_idx = new long[size]; - for ( size_t j = 0; j < (size_t)size; ++j ) { - maximum[j] = maxvec[j]; - glb_idx[j] = gidxvec[j]; - } ); -} - -void atlas__NodesFunctionSpace__mean_double( const NodeColumns* This, const field::FieldImpl* field, double& mean, - int& N ) { - ASSERT( This ); - ASSERT( field ); - size_t size_t_N; - ATLAS_ERROR_HANDLING( This->mean( field, mean, size_t_N ) ); - N = size_t_N; -} - -void atlas__NodesFunctionSpace__mean_float( const NodeColumns* This, const field::FieldImpl* field, float& mean, - int& N ) { - ASSERT( This ); - ASSERT( field ); - size_t size_t_N; - ATLAS_ERROR_HANDLING( This->mean( field, mean, size_t_N ) ); - N = size_t_N; -} - -void atlas__NodesFunctionSpace__mean_long( const NodeColumns* This, const field::FieldImpl* field, long& mean, - int& N ) { - NOTIMP; -} - -void atlas__NodesFunctionSpace__mean_int( const NodeColumns* This, const field::FieldImpl* field, int& mean, int& N ) { - NOTIMP; -} - -void atlas__NodesFunctionSpace__mean_arr_double( const NodeColumns* This, const field::FieldImpl* field, double*& mean, - int& size, int& N ) { - ASSERT( This ); - ASSERT( field ); - size_t size_t_N; - ATLAS_ERROR_HANDLING( std::vector meanvec; This->mean( field, meanvec, size_t_N ); size = meanvec.size(); - mean = new double[size]; for ( size_t j = 0; j < (size_t)size; ++j ) mean[j] = meanvec[j]; ); - N = size_t_N; -} - -void atlas__NodesFunctionSpace__mean_arr_float( const NodeColumns* This, const field::FieldImpl* field, float*& mean, - int& size, int& N ) { - ASSERT( This ); - ASSERT( field ); - size_t size_t_N; - ATLAS_ERROR_HANDLING( std::vector meanvec; This->mean( field, meanvec, size_t_N ); size = meanvec.size(); - mean = new float[size]; for ( size_t j = 0; j < (size_t)size; ++j ) mean[j] = meanvec[j]; ); - N = size_t_N; -} - -void atlas__NodesFunctionSpace__mean_arr_long( const NodeColumns* This, const field::FieldImpl* field, long*& mean, - int& size, int& N ) { - NOTIMP; -} - -void atlas__NodesFunctionSpace__mean_arr_int( const NodeColumns* This, const field::FieldImpl* field, int*& mean, - int& size, int& N ) { - NOTIMP; -} - -void atlas__NodesFunctionSpace__mean_and_stddev_double( const NodeColumns* This, const field::FieldImpl* field, - double& mean, double& stddev, int& N ) { - ASSERT( This ); - ASSERT( field ); - size_t size_t_N; - ATLAS_ERROR_HANDLING( This->meanAndStandardDeviation( field, mean, stddev, size_t_N ) ); - N = size_t_N; -} - -void atlas__NodesFunctionSpace__mean_and_stddev_float( const NodeColumns* This, const field::FieldImpl* field, - float& mean, float& stddev, int& N ) { - ASSERT( This ); - ASSERT( field ); - size_t size_t_N; - ATLAS_ERROR_HANDLING( This->meanAndStandardDeviation( field, mean, stddev, size_t_N ) ); - N = size_t_N; -} - -void atlas__NodesFunctionSpace__mean_and_stddev_long( const NodeColumns* This, const field::FieldImpl* field, - long& mean, long& stddev, int& N ) { - NOTIMP; -} - -void atlas__NodesFunctionSpace__mean_and_stddev_int( const NodeColumns* This, const field::FieldImpl* field, int& mean, - int& stddev, int& N ) { - NOTIMP; -} - -void atlas__NodesFunctionSpace__mean_and_stddev_arr_double( const NodeColumns* This, const field::FieldImpl* field, - double*& mean, double*& stddev, int& size, int& N ) { - ASSERT( This ); - ASSERT( field ); - size_t size_t_N; - ATLAS_ERROR_HANDLING( std::vector meanvec; std::vector stddevvec; - This->meanAndStandardDeviation( field, meanvec, stddevvec, size_t_N ); size = meanvec.size(); - mean = new double[size]; stddev = new double[size]; - for ( size_t j = 0; j < (size_t)size; ++j ) { - mean[j] = meanvec[j]; - stddev[j] = stddevvec[j]; - } ); - N = size_t_N; -} - -void atlas__NodesFunctionSpace__mean_and_stddev_arr_float( const NodeColumns* This, const field::FieldImpl* field, - float*& mean, float*& stddev, int& size, int& N ) { - ASSERT( This ); - ASSERT( field ); - size_t size_t_N; - ATLAS_ERROR_HANDLING( std::vector meanvec; std::vector stddevvec; - This->meanAndStandardDeviation( field, meanvec, stddevvec, size_t_N ); size = meanvec.size(); - mean = new float[size]; stddev = new float[size]; - for ( size_t j = 0; j < (size_t)size; ++j ) { - mean[j] = meanvec[j]; - stddev[j] = stddevvec[j]; - } ); - N = size_t_N; -} - -void atlas__NodesFunctionSpace__mean_and_stddev_arr_long( const NodeColumns* This, const field::FieldImpl* field, - long*& mean, long*& stddev, int& size, int& N ) { - NOTIMP; -} - -void atlas__NodesFunctionSpace__mean_and_stddev_arr_int( const NodeColumns* This, const field::FieldImpl* field, - int*& mean, int*& stddev, int& size, int& N ) { - NOTIMP; -} - -void atlas__NodesFunctionSpace__minloclev_double( const NodeColumns* This, const field::FieldImpl* field, - double& minimum, long& glb_idx, int& level ) { - ASSERT( This ); - ASSERT( field ); - gidx_t gidx; - size_t lev; - ATLAS_ERROR_HANDLING( This->minimumAndLocation( field, minimum, gidx, lev ) ); - glb_idx = gidx; - level = lev; -} - -void atlas__NodesFunctionSpace__minloclev_float( const NodeColumns* This, const field::FieldImpl* field, float& minimum, - long& glb_idx, int& level ) { - ASSERT( This ); - ASSERT( field ); - gidx_t gidx; - size_t lev; - ATLAS_ERROR_HANDLING( This->minimumAndLocation( field, minimum, gidx, lev ) ); - glb_idx = gidx; - level = lev; -} - -void atlas__NodesFunctionSpace__minloclev_long( const NodeColumns* This, const field::FieldImpl* field, long& minimum, - long& glb_idx, int& level ) { - ASSERT( This ); - ASSERT( field ); - gidx_t gidx; - size_t lev; - ATLAS_ERROR_HANDLING( This->minimumAndLocation( field, minimum, gidx, lev ) ); - glb_idx = gidx; - level = lev; -} - -void atlas__NodesFunctionSpace__minloclev_int( const NodeColumns* This, const field::FieldImpl* field, int& minimum, - long& glb_idx, int& level ) { - ASSERT( This ); - ASSERT( field ); - gidx_t gidx; - size_t lev; - ATLAS_ERROR_HANDLING( This->minimumAndLocation( field, minimum, gidx, lev ) ); - glb_idx = gidx; - level = lev; -} - -void atlas__NodesFunctionSpace__maxloclev_double( const NodeColumns* This, const field::FieldImpl* field, - double& maximum, long& glb_idx, int& level ) { - ASSERT( This ); - ASSERT( field ); - gidx_t gidx; - size_t lev; - ATLAS_ERROR_HANDLING( This->maximumAndLocation( field, maximum, gidx, lev ) ); - glb_idx = gidx; - level = lev; -} - -void atlas__NodesFunctionSpace__maxloclev_float( const NodeColumns* This, const field::FieldImpl* field, float& maximum, - long& glb_idx, int& level ) { - ASSERT( This ); - ASSERT( field ); - gidx_t gidx; - size_t lev; - ATLAS_ERROR_HANDLING( This->maximumAndLocation( field, maximum, gidx, lev ) ); - glb_idx = gidx; - level = lev; -} - -void atlas__NodesFunctionSpace__maxloclev_long( const NodeColumns* This, const field::FieldImpl* field, long& maximum, - long& glb_idx, int& level ) { - ASSERT( This ); - ASSERT( field ); - gidx_t gidx; - size_t lev; - ATLAS_ERROR_HANDLING( This->maximumAndLocation( field, maximum, gidx, lev ) ); - glb_idx = gidx; - level = lev; -} - -void atlas__NodesFunctionSpace__maxloclev_int( const NodeColumns* This, const field::FieldImpl* field, int& maximum, - long& glb_idx, int& level ) { - ASSERT( This ); - ASSERT( field ); - gidx_t gidx; - size_t lev; - ATLAS_ERROR_HANDLING( This->maximumAndLocation( field, maximum, gidx, lev ) ); - glb_idx = gidx; - level = lev; -} - -void atlas__NodesFunctionSpace__minloclev_arr_double( const NodeColumns* This, const field::FieldImpl* field, - double*& minimum, long*& glb_idx, int*& level, int& size ) { - ASSERT( This ); - ASSERT( field ); - ATLAS_ERROR_HANDLING( std::vector minvec; std::vector gidxvec; std::vector levvec; - This->minimumAndLocation( field, minvec, gidxvec, levvec ); size = minvec.size(); - minimum = new double[size]; glb_idx = new long[size]; level = new int[size]; - for ( size_t j = 0; j < (size_t)size; ++j ) { - minimum[j] = minvec[j]; - glb_idx[j] = gidxvec[j]; - level[j] = levvec[j]; - } ); -} - -void atlas__NodesFunctionSpace__minloclev_arr_float( const NodeColumns* This, const field::FieldImpl* field, - float*& minimum, long*& glb_idx, int*& level, int& size ) { - ASSERT( This ); - ASSERT( field ); - ATLAS_ERROR_HANDLING( std::vector minvec; std::vector gidxvec; std::vector levvec; - This->minimumAndLocation( field, minvec, gidxvec, levvec ); size = minvec.size(); - minimum = new float[size]; glb_idx = new long[size]; level = new int[size]; - for ( size_t j = 0; j < (size_t)size; ++j ) { - minimum[j] = minvec[j]; - glb_idx[j] = gidxvec[j]; - level[j] = levvec[j]; - } ); -} - -void atlas__NodesFunctionSpace__minloclev_arr_long( const NodeColumns* This, const field::FieldImpl* field, - long*& minimum, long*& glb_idx, int*& level, int& size ) { - ASSERT( This ); - ASSERT( field ); - ATLAS_ERROR_HANDLING( std::vector minvec; std::vector gidxvec; std::vector levvec; - This->minimumAndLocation( field, minvec, gidxvec, levvec ); size = minvec.size(); - minimum = new long[size]; glb_idx = new long[size]; level = new int[size]; - for ( size_t j = 0; j < (size_t)size; ++j ) { - minimum[j] = minvec[j]; - glb_idx[j] = gidxvec[j]; - level[j] = levvec[j]; - } ); -} - -void atlas__NodesFunctionSpace__minloclev_arr_int( const NodeColumns* This, const field::FieldImpl* field, - int*& minimum, long*& glb_idx, int*& level, int& size ) { - ASSERT( This ); - ASSERT( field ); - ATLAS_ERROR_HANDLING( std::vector minvec; std::vector gidxvec; std::vector levvec; - This->minimumAndLocation( field, minvec, gidxvec, levvec ); size = minvec.size(); - minimum = new int[size]; glb_idx = new long[size]; level = new int[size]; - for ( size_t j = 0; j < (size_t)size; ++j ) { - minimum[j] = minvec[j]; - glb_idx[j] = gidxvec[j]; - level[j] = levvec[j]; - } ); -} - -void atlas__NodesFunctionSpace__maxloclev_arr_double( const NodeColumns* This, const field::FieldImpl* field, - double*& maximum, long*& glb_idx, int*& level, int& size ) { - ASSERT( This ); - ASSERT( field ); - ATLAS_ERROR_HANDLING( std::vector maxvec; std::vector gidxvec; std::vector levvec; - This->maximumAndLocation( field, maxvec, gidxvec, levvec ); size = maxvec.size(); - maximum = new double[size]; glb_idx = new long[size]; level = new int[size]; - for ( size_t j = 0; j < (size_t)size; ++j ) { - maximum[j] = maxvec[j]; - glb_idx[j] = gidxvec[j]; - level[j] = levvec[j]; - } ); -} - -void atlas__NodesFunctionSpace__maxloclev_arr_float( const NodeColumns* This, const field::FieldImpl* field, - float*& maximum, long*& glb_idx, int*& level, int& size ) { - ASSERT( This ); - ASSERT( field ); - ATLAS_ERROR_HANDLING( std::vector maxvec; std::vector gidxvec; std::vector levvec; - This->maximumAndLocation( field, maxvec, gidxvec, levvec ); size = maxvec.size(); - maximum = new float[size]; glb_idx = new long[size]; level = new int[size]; - for ( size_t j = 0; j < (size_t)size; ++j ) { - maximum[j] = maxvec[j]; - glb_idx[j] = gidxvec[j]; - level[j] = levvec[j]; - } ); -} - -void atlas__NodesFunctionSpace__maxloclev_arr_long( const NodeColumns* This, const field::FieldImpl* field, - long*& maximum, long*& glb_idx, int*& level, int& size ) { - ASSERT( This ); - ASSERT( field ); - ATLAS_ERROR_HANDLING( std::vector maxvec; std::vector gidxvec; std::vector levvec; - This->maximumAndLocation( field, maxvec, gidxvec, levvec ); size = maxvec.size(); - maximum = new long[size]; glb_idx = new long[size]; level = new int[size]; - for ( size_t j = 0; j < (size_t)size; ++j ) { - maximum[j] = maxvec[j]; - glb_idx[j] = gidxvec[j]; - level[j] = levvec[j]; - } ); -} - -void atlas__NodesFunctionSpace__maxloclev_arr_int( const NodeColumns* This, const field::FieldImpl* field, - int*& maximum, long*& glb_idx, int*& level, int& size ) { - ASSERT( This ); - ASSERT( field ); - ATLAS_ERROR_HANDLING( std::vector maxvec; std::vector gidxvec; std::vector levvec; - This->maximumAndLocation( field, maxvec, gidxvec, levvec ); size = maxvec.size(); - maximum = new int[size]; glb_idx = new long[size]; level = new int[size]; - for ( size_t j = 0; j < (size_t)size; ++j ) { - maximum[j] = maxvec[j]; - glb_idx[j] = gidxvec[j]; - level[j] = levvec[j]; - } ); -} - -void atlas__NodesFunctionSpace__sum_per_level( const NodeColumns* This, const field::FieldImpl* field, - field::FieldImpl* column, int& N ) { - ASSERT( This ); - ASSERT( field ); - ASSERT( column ); - size_t size_t_N; - Field sum( column ); - ATLAS_ERROR_HANDLING( This->sumPerLevel( field, sum, size_t_N ); ); - N = size_t_N; -} - -void atlas__NodesFunctionSpace__oisum_per_level( const NodeColumns* This, const field::FieldImpl* field, - field::FieldImpl* column, int& N ) { - ASSERT( This ); - ASSERT( field ); - ASSERT( column ); - size_t size_t_N; - Field sum( column ); - ATLAS_ERROR_HANDLING( This->orderIndependentSumPerLevel( field, sum, size_t_N ); ); - N = size_t_N; -} - -void atlas__NodesFunctionSpace__min_per_level( const NodeColumns* This, const field::FieldImpl* field, - field::FieldImpl* min ) { - ASSERT( This ); - ASSERT( field ); - ASSERT( min ); - Field fmin( min ); - ATLAS_ERROR_HANDLING( This->minimumPerLevel( field, fmin ); ); -} - -void atlas__NodesFunctionSpace__max_per_level( const NodeColumns* This, const field::FieldImpl* field, - field::FieldImpl* max ) { - ASSERT( This ); - ASSERT( field ); - ASSERT( max ); - Field fmax( max ); - ATLAS_ERROR_HANDLING( This->maximumPerLevel( field, fmax ); ); -} - -void atlas__NodesFunctionSpace__minloc_per_level( const NodeColumns* This, const field::FieldImpl* field, - field::FieldImpl* min, field::FieldImpl* glb_idx ) { - ASSERT( This ); - ASSERT( field ); - ASSERT( min ); - ASSERT( glb_idx ); - Field fmin( min ); - Field fglb_idx( glb_idx ); - ATLAS_ERROR_HANDLING( This->minimumAndLocationPerLevel( field, fmin, fglb_idx ); ); -} - -void atlas__NodesFunctionSpace__maxloc_per_level( const NodeColumns* This, const field::FieldImpl* field, - field::FieldImpl* max, field::FieldImpl* glb_idx ) { - ASSERT( This ); - ASSERT( field ); - ASSERT( max ); - ASSERT( glb_idx ); - Field fmax( max ); - Field fglb_idx( glb_idx ); - ATLAS_ERROR_HANDLING( This->maximumAndLocationPerLevel( field, fmax, fglb_idx ); ); -} - -void atlas__NodesFunctionSpace__mean_per_level( const NodeColumns* This, const field::FieldImpl* field, - field::FieldImpl* mean, int& N ) { - ASSERT( This ); - ASSERT( field ); - ASSERT( mean ); - size_t size_t_N; - Field fmean( mean ); - ATLAS_ERROR_HANDLING( This->meanPerLevel( field, fmean, size_t_N ); ); - N = size_t_N; -} - -void atlas__NodesFunctionSpace__mean_and_stddev_per_level( const NodeColumns* This, const field::FieldImpl* field, - field::FieldImpl* mean, field::FieldImpl* stddev, int& N ) { - ASSERT( This ); - ASSERT( field ); - ASSERT( mean ); - ASSERT( stddev ); - size_t size_t_N; - Field fmean( mean ); - Field fstddev( stddev ); - ATLAS_ERROR_HANDLING( This->meanAndStandardDeviationPerLevel( field, fmean, fstddev, size_t_N ); ); - N = size_t_N; -} -} - -} // namespace detail -} // namespace functionspace -} // namespace atlas diff --git a/src/atlas/functionspace/PointCloud.cc b/src/atlas/functionspace/PointCloud.cc index 48793d6ba..c214a2254 100644 --- a/src/atlas/functionspace/PointCloud.cc +++ b/src/atlas/functionspace/PointCloud.cc @@ -8,20 +8,40 @@ * nor does it submit to any jurisdiction. */ + #include "atlas/functionspace/PointCloud.h" #include "atlas/array.h" +#include "atlas/grid/Grid.h" +#include "atlas/grid/Iterator.h" +#include "atlas/option/Options.h" +#include "atlas/runtime/Exception.h" + namespace atlas { namespace functionspace { namespace detail { +PointCloud::PointCloud( PointXY, const std::vector& points ) : PointCloud( points ) {} + PointCloud::PointCloud( const std::vector& points ) { lonlat_ = Field( "lonlat", array::make_datatype(), array::make_shape( points.size(), 2 ) ); auto lonlat = array::make_view( lonlat_ ); - for ( size_t j = 0; j < points.size(); ++j ) { + for ( idx_t j = 0, size = points.size(); j < size; ++j ) { + lonlat( j, 0 ) = points[j].x(); + lonlat( j, 1 ) = points[j].y(); + } +} + +PointCloud::PointCloud( PointXYZ, const std::vector& points ) { + lonlat_ = Field( "lonlat", array::make_datatype(), array::make_shape( points.size(), 2 ) ); + vertical_ = Field( "vertical", array::make_datatype(), array::make_shape( points.size() ) ); + auto lonlat = array::make_view( lonlat_ ); + auto vertical = array::make_view( vertical_ ); + for ( idx_t j = 0, size = points.size(); j < size; ++j ) { lonlat( j, 0 ) = points[j].x(); lonlat( j, 1 ) = points[j].y(); + vertical( j ) = points[j].z(); } } @@ -29,6 +49,18 @@ PointCloud::PointCloud( const Field& lonlat ) : lonlat_( lonlat ) {} PointCloud::PointCloud( const Field& lonlat, const Field& ghost ) : lonlat_( lonlat ), ghost_( ghost ) {} +PointCloud::PointCloud( const Grid& grid ) { + lonlat_ = Field( "lonlat", array::make_datatype(), array::make_shape( grid.size(), 2 ) ); + auto lonlat = array::make_view( lonlat_ ); + + idx_t j{0}; + for ( auto p : grid.lonlat() ) { + lonlat( j, 0 ) = p.lon(); + lonlat( j, 1 ) = p.lat(); + ++j; + } +} + const Field& PointCloud::ghost() const { if ( not ghost_ ) { ghost_ = Field( "ghost", array::make_datatype(), array::make_shape( size() ) ); @@ -37,8 +69,8 @@ const Field& PointCloud::ghost() const { return ghost_; } -Field PointCloud::createField( const eckit::Configuration& options ) const { - NOTIMP; +Field PointCloud::createField( const eckit::Configuration& ) const { + ATLAS_NOTIMPLEMENTED; } Field PointCloud::createField( const Field& other, const eckit::Configuration& config ) const { @@ -49,6 +81,55 @@ std::string PointCloud::distribution() const { return std::string( "serial" ); } +atlas::functionspace::detail::PointCloud::IteratorXYZ::IteratorXYZ( const atlas::functionspace::detail::PointCloud& fs, + bool begin ) : + fs_( fs ), + xy_( array::make_view( fs_.lonlat() ) ), + z_( array::make_view( fs_.vertical() ) ), + n_( begin ? 0 : fs_.size() ) {} + +bool atlas::functionspace::detail::PointCloud::IteratorXYZ::next( PointXYZ& xyz ) { + if ( n_ < fs_.size() ) { + xyz.x() = xy_( n_, 0 ); + xyz.y() = xy_( n_, 1 ); + xyz.z() = z_( n_ ); + ++n_; + return true; + } + return false; +} + +atlas::functionspace::detail::PointCloud::IteratorXY::IteratorXY( const atlas::functionspace::detail::PointCloud& fs, + bool begin ) : + fs_( fs ), + xy_( array::make_view( fs_.lonlat() ) ), + n_( begin ? 0 : fs_.size() ) {} + +bool atlas::functionspace::detail::PointCloud::IteratorXY::next( PointXY& xyz ) { + if ( n_ < fs_.size() ) { + xyz.x() = xy_( n_, 0 ); + xyz.y() = xy_( n_, 1 ); + ++n_; + return true; + } + return false; +} + +const PointXY atlas::functionspace::detail::PointCloud::IteratorXY::operator*() const { + PointXY xy; + xy.x() = xy_( n_, 0 ); + xy.y() = xy_( n_, 1 ); + return xy; +} + +const PointXYZ atlas::functionspace::detail::PointCloud::IteratorXYZ::operator*() const { + PointXYZ xyz; + xyz.x() = xy_( n_, 0 ); + xyz.y() = xy_( n_, 1 ); + xyz.z() = z_( n_ ); + return xyz; +} + } // namespace detail PointCloud::PointCloud( const FunctionSpace& functionspace ) : @@ -63,5 +144,18 @@ PointCloud::PointCloud( const std::vector& points ) : FunctionSpace( new detail::PointCloud( points ) ), functionspace_( dynamic_cast( get() ) ) {} +PointCloud::PointCloud( PointXY p, const std::vector& points ) : + FunctionSpace( new detail::PointCloud( p, points ) ), + functionspace_( dynamic_cast( get() ) ) {} + +PointCloud::PointCloud( PointXYZ p, const std::vector& points ) : + FunctionSpace( new detail::PointCloud( p, points ) ), + functionspace_( dynamic_cast( get() ) ) {} + +PointCloud::PointCloud( const Grid& grid ) : + FunctionSpace( new detail::PointCloud( grid ) ), + functionspace_( dynamic_cast( get() ) ) {} + + } // namespace functionspace } // namespace atlas diff --git a/src/atlas/functionspace/PointCloud.h b/src/atlas/functionspace/PointCloud.h index 33db66c13..401376dd8 100644 --- a/src/atlas/functionspace/PointCloud.h +++ b/src/atlas/functionspace/PointCloud.h @@ -10,11 +10,15 @@ #pragma once +#include "atlas/array/ArrayView.h" #include "atlas/field/Field.h" #include "atlas/functionspace/FunctionSpace.h" +#include "atlas/functionspace/detail/FunctionSpaceImpl.h" #include "atlas/util/Point.h" namespace atlas { +class Grid; + namespace functionspace { //------------------------------------------------------------------------------------------------------ @@ -24,27 +28,128 @@ namespace detail { class PointCloud : public FunctionSpaceImpl { public: PointCloud( const std::vector& ); + PointCloud( PointXY, const std::vector& ); + PointCloud( PointXYZ, const std::vector& ); PointCloud( const Field& lonlat ); PointCloud( const Field& lonlat, const Field& ghost ); - virtual ~PointCloud() {} - virtual std::string type() const { return "PointCloud"; } - virtual operator bool() const { return true; } - virtual size_t footprint() const { return sizeof( *this ); } - virtual std::string distribution() const; + PointCloud( const Grid& ); + virtual ~PointCloud() override {} + virtual std::string type() const override { return "PointCloud"; } + virtual operator bool() const override { return true; } + virtual size_t footprint() const override { return sizeof( *this ); } + virtual std::string distribution() const override; const Field& lonlat() const { return lonlat_; } + const Field& vertical() const { return vertical_; } const Field& ghost() const; - size_t size() const { return lonlat_.shape( 0 ); } + virtual idx_t size() const override { return lonlat_.shape( 0 ); } /// @brief Create a spectral field using FunctionSpaceImpl::createField; - virtual Field createField( const eckit::Configuration& ) const; - virtual Field createField( const Field&, const eckit::Configuration& ) const; + virtual Field createField( const eckit::Configuration& ) const override; + virtual Field createField( const Field&, const eckit::Configuration& ) const override; + + + class IteratorXYZ { + public: + IteratorXYZ( const PointCloud& fs, bool begin = true ); + + bool next( PointXYZ& xyz ); + + const PointXYZ operator*() const; + + const IteratorXYZ& operator++() { + ++n_; + return *this; + } + + bool operator==( const IteratorXYZ& other ) const { return n_ == static_cast( other ).n_; } + + virtual bool operator!=( const IteratorXYZ& other ) const { + return n_ != static_cast( other ).n_; + } + + private: + const PointCloud& fs_; + const array::ArrayView xy_; + const array::ArrayView z_; + idx_t n_; + }; + + + class IterateXYZ { + public: + using iterator = IteratorXYZ; + using const_iterator = iterator; + + public: + IterateXYZ( const PointCloud& fs ) : fs_( fs ) {} + iterator begin() const { return IteratorXYZ( fs_ ); } + iterator end() const { return IteratorXYZ( fs_, false ); } + + private: + const PointCloud& fs_; + }; + + class IteratorXY { + public: + IteratorXY( const PointCloud& fs, bool begin = true ); + + bool next( PointXY& xyz ); + + const PointXY operator*() const; + + const IteratorXY& operator++() { + ++n_; + return *this; + } + + bool operator==( const IteratorXY& other ) const { return n_ == static_cast( other ).n_; } + + virtual bool operator!=( const IteratorXY& other ) const { + return n_ != static_cast( other ).n_; + } + + private: + const PointCloud& fs_; + const array::ArrayView xy_; + idx_t n_; + }; + + class IterateXY { + public: + using iterator = IteratorXY; + using const_iterator = iterator; + + public: + IterateXY( const PointCloud& fs ) : fs_( fs ) {} + iterator begin() const { return IteratorXY( fs_ ); } + iterator end() const { return IteratorXY( fs_, false ); } + + private: + const PointCloud& fs_; + }; + + + class Iterate { + public: + Iterate( const PointCloud& fs ) : fs_( fs ) {} + IterateXYZ xyz() const { return IterateXYZ( fs_ ); } + IterateXY xy() const { return IterateXY( fs_ ); } + + private: + const PointCloud& fs_; + }; + + Iterate iterate() const { return Iterate( *this ); } private: Field lonlat_; + Field vertical_; mutable Field ghost_; }; +//------------------------------------------------------------------------------------------------------ + } // namespace detail //------------------------------------------------------------------------------------------------------ @@ -54,13 +159,19 @@ class PointCloud : public FunctionSpace { PointCloud( const FunctionSpace& ); PointCloud( const Field& points ); PointCloud( const std::vector& ); + PointCloud( PointXY, const std::vector& ); + PointCloud( PointXYZ, const std::vector& ); + PointCloud( const Grid& grid ); operator bool() const { return valid(); } bool valid() const { return functionspace_; } const Field& lonlat() const { return functionspace_->lonlat(); } + const Field& vertical() const { return functionspace_->vertical(); } const Field& ghost() const { return functionspace_->ghost(); } - size_t size() const { return functionspace_->size(); } + + detail::PointCloud::Iterate iterate() const { return functionspace_->iterate(); } + private: const detail::PointCloud* functionspace_; diff --git a/src/atlas/functionspace/Spectral.cc b/src/atlas/functionspace/Spectral.cc index f5aab2087..8ce8ca9af 100644 --- a/src/atlas/functionspace/Spectral.cc +++ b/src/atlas/functionspace/Spectral.cc @@ -18,7 +18,7 @@ #include "atlas/mesh/Mesh.h" #include "atlas/option.h" #include "atlas/parallel/mpi/mpi.h" -#include "atlas/runtime/ErrorHandling.h" +#include "atlas/runtime/Exception.h" #include "atlas/runtime/Log.h" #include "atlas/trans/Trans.h" @@ -31,7 +31,7 @@ void trans_check( const int code, const char* msg, const eckit::CodeLocation& lo std::stringstream errmsg; errmsg << "atlas::trans ERROR: " << msg << " failed: \n"; errmsg << ::trans_error_msg( code ); - throw eckit::Exception( errmsg.str(), location ); + atlas::throw_Exception( errmsg.str(), location ); } } #define TRANS_CHECK( CALL ) trans_check( CALL, #CALL, Here() ) @@ -82,7 +82,7 @@ void Spectral::set_field_metadata( const eckit::Configuration& config, Field& fi bool global( false ); if ( config.get( "global", global ) ) { if ( global ) { - size_t owner( 0 ); + idx_t owner( 0 ); config.get( "owner", owner ); field.metadata().set( "owner", owner ); } @@ -93,14 +93,14 @@ void Spectral::set_field_metadata( const eckit::Configuration& config, Field& fi field.set_variables( 0 ); } -size_t Spectral::config_size( const eckit::Configuration& config ) const { - size_t size = nb_spectral_coefficients(); +idx_t Spectral::config_size( const eckit::Configuration& config ) const { + idx_t size = nb_spectral_coefficients(); bool global( false ); if ( config.get( "global", global ) ) { if ( global ) { - size_t owner( 0 ); + idx_t owner( 0 ); config.get( "owner", owner ); - size = ( mpi::comm().rank() == owner ? nb_spectral_coefficients_global() : 0 ); + size = ( idx_t( mpi::comm().rank() ) == owner ? nb_spectral_coefficients_global() : 0 ); } } return size; @@ -114,20 +114,20 @@ Spectral::Spectral( const eckit::Configuration& config ) : // ---------------------------------------------------------------------- Spectral::Spectral( const int truncation, const eckit::Configuration& config ) : + nb_levels_( 0 ), truncation_( truncation ), - parallelisation_( new Parallelisation( truncation_ ) ), - nb_levels_( 0 ) { + parallelisation_( new Parallelisation( truncation_ ) ) { config.get( "levels", nb_levels_ ); } Spectral::Spectral( const trans::Trans& trans, const eckit::Configuration& config ) : + nb_levels_( 0 ), truncation_( trans.truncation() ), #if ATLAS_HAVE_TRANS - parallelisation_( new Parallelisation( dynamic_cast( *trans.get() ).trans_ ) ), + parallelisation_( new Parallelisation( dynamic_cast( *trans.get() ).trans_ ) ) { #else - parallelisation_( new Parallelisation( truncation_ ) ), + parallelisation_( new Parallelisation( truncation_ ) ) { #endif - nb_levels_( 0 ) { config.get( "levels", nb_levels_ ); } @@ -143,17 +143,17 @@ size_t Spectral::footprint() const { return size; } -size_t Spectral::nb_spectral_coefficients() const { +idx_t Spectral::nb_spectral_coefficients() const { return parallelisation_->nb_spectral_coefficients(); } -size_t Spectral::nb_spectral_coefficients_global() const { +idx_t Spectral::nb_spectral_coefficients_global() const { return parallelisation_->nb_spectral_coefficients_global(); } array::DataType Spectral::config_datatype( const eckit::Configuration& config ) const { array::DataType::kind_t kind; - if ( !config.get( "datatype", kind ) ) throw eckit::AssertionFailed( "datatype missing", Here() ); + if ( !config.get( "datatype", kind ) ) throw_Exception( "datatype missing", Here() ); return array::DataType( kind ); } @@ -163,8 +163,8 @@ std::string Spectral::config_name( const eckit::Configuration& config ) const { return name; } -size_t Spectral::config_levels( const eckit::Configuration& config ) const { - size_t levels( nb_levels_ ); +idx_t Spectral::config_levels( const eckit::Configuration& config ) const { + idx_t levels( nb_levels_ ); config.get( "levels", levels ); return levels; } @@ -172,10 +172,10 @@ size_t Spectral::config_levels( const eckit::Configuration& config ) const { Field Spectral::createField( const eckit::Configuration& options ) const { array::ArrayShape array_shape; - size_t nb_spec_coeffs = config_size( options ); + idx_t nb_spec_coeffs = config_size( options ); array_shape.push_back( nb_spec_coeffs ); - size_t levels = config_levels( options ); + idx_t levels = config_levels( options ); if ( levels ) array_shape.push_back( levels ); Field field = Field( config_name( options ), config_datatype( options ), array_shape ); @@ -189,23 +189,24 @@ Field Spectral::createField( const Field& other, const eckit::Configuration& con } void Spectral::gather( const FieldSet& local_fieldset, FieldSet& global_fieldset ) const { - ASSERT( local_fieldset.size() == global_fieldset.size() ); + ATLAS_ASSERT( local_fieldset.size() == global_fieldset.size() ); - for ( size_t f = 0; f < local_fieldset.size(); ++f ) { + for ( idx_t f = 0; f < local_fieldset.size(); ++f ) { const Field& loc = local_fieldset[f]; if ( loc.datatype() != array::DataType::str() ) { std::stringstream err; err << "Cannot gather spectral field " << loc.name() << " of datatype " << loc.datatype().str() << "."; err << "Only " << array::DataType::str() << " supported."; - throw eckit::BadValue( err.str() ); + throw_Exception( err.str(), Here() ); } #if ATLAS_HAVE_TRANS - Field& glb = global_fieldset[f]; - size_t root = 0; + Field& glb = global_fieldset[f]; + idx_t root = 0; + idx_t rank = static_cast( mpi::comm().rank() ); glb.metadata().get( "owner", root ); - ASSERT( loc.shape( 0 ) == nb_spectral_coefficients() ); - if ( mpi::comm().rank() == root ) ASSERT( glb.shape( 0 ) == nb_spectral_coefficients_global() ); + ATLAS_ASSERT( loc.shape( 0 ) == nb_spectral_coefficients() ); + if ( rank == root ) ATLAS_ASSERT( glb.shape( 0 ) == nb_spectral_coefficients_global() ); std::vector nto( 1, root + 1 ); if ( loc.rank() > 1 ) { nto.resize( loc.stride( 0 ) ); @@ -221,7 +222,7 @@ void Spectral::gather( const FieldSet& local_fieldset, FieldSet& global_fieldset TRANS_CHECK(::trans_gathspec( &args ) ); #else - throw eckit::Exception( + throw_Exception( "Cannot gather spectral fields because Atlas has " "not been compiled with TRANS support." ); #endif @@ -236,23 +237,25 @@ void Spectral::gather( const Field& local, Field& global ) const { } void Spectral::scatter( const FieldSet& global_fieldset, FieldSet& local_fieldset ) const { - ASSERT( local_fieldset.size() == global_fieldset.size() ); + ATLAS_ASSERT( local_fieldset.size() == global_fieldset.size() ); - for ( size_t f = 0; f < local_fieldset.size(); ++f ) { + for ( idx_t f = 0; f < local_fieldset.size(); ++f ) { const Field& glb = global_fieldset[f]; Field& loc = local_fieldset[f]; if ( loc.datatype() != array::DataType::str() ) { std::stringstream err; err << "Cannot scatter spectral field " << glb.name() << " of datatype " << glb.datatype().str() << "."; err << "Only " << array::DataType::str() << " supported."; - throw eckit::BadValue( err.str() ); + throw_Exception( err.str(), Here() ); } #if ATLAS_HAVE_TRANS - size_t root = 0; + idx_t root = 0; + idx_t rank = static_cast( mpi::comm().rank() ); + glb.metadata().get( "owner", root ); - ASSERT( loc.shape( 0 ) == nb_spectral_coefficients() ); - if ( mpi::comm().rank() == root ) ASSERT( glb.shape( 0 ) == nb_spectral_coefficients_global() ); + ATLAS_ASSERT( loc.shape( 0 ) == nb_spectral_coefficients() ); + if ( rank == root ) ATLAS_ASSERT( glb.shape( 0 ) == nb_spectral_coefficients_global() ); std::vector nfrom( 1, root + 1 ); if ( loc.rank() > 1 ) { nfrom.resize( loc.stride( 0 ) ); @@ -261,7 +264,7 @@ void Spectral::scatter( const FieldSet& global_fieldset, FieldSet& local_fieldse } struct ::DistSpec_t args = new_distspec( *parallelisation_ ); - args.nfld = nfrom.size(); + args.nfld = int( nfrom.size() ); args.rspecg = glb.data(); args.nfrom = nfrom.data(); args.rspec = loc.data(); @@ -270,7 +273,7 @@ void Spectral::scatter( const FieldSet& global_fieldset, FieldSet& local_fieldse glb.metadata().broadcast( loc.metadata(), root ); loc.metadata().set( "global", false ); #else - throw eckit::Exception( + throw_Exception( "Cannot scatter spectral fields because Atlas has " "not been compiled with TRANS support." ); #endif @@ -284,9 +287,9 @@ void Spectral::scatter( const Field& global, Field& local ) const { scatter( global_fields, local_fields ); } -std::string Spectral::checksum( const FieldSet& fieldset ) const { +std::string Spectral::checksum( const FieldSet& ) const { eckit::MD5 md5; - NOTIMP; + ATLAS_NOTIMPLEMENTED; } std::string Spectral::checksum( const Field& field ) const { FieldSet fieldset; @@ -296,7 +299,8 @@ std::string Spectral::checksum( const Field& field ) const { void Spectral::norm( const Field& field, double& norm, int rank ) const { #if ATLAS_HAVE_TRANS - ASSERT( std::max( 1, field.levels() ) == 1 ); + ATLAS_ASSERT( std::max( 1, field.levels() ) == 1, + "Only a single-level field can be used for computing single norm." ); struct ::SpecNorm_t args = new_specnorm( *parallelisation_ ); args.nfld = 1; args.rspec = field.data(); @@ -304,14 +308,13 @@ void Spectral::norm( const Field& field, double& norm, int rank ) const { args.nmaster = rank + 1; TRANS_CHECK(::trans_specnorm( &args ) ); #else - throw eckit::Exception( + throw_Exception( "Cannot compute spectral norms because Atlas has not " "been compiled with TRANS support." ); #endif } void Spectral::norm( const Field& field, double norm_per_level[], int rank ) const { #if ATLAS_HAVE_TRANS - ASSERT( std::max( 1, field.levels() ) == 1 ); struct ::SpecNorm_t args = new_specnorm( *parallelisation_ ); args.nfld = std::max( 1, field.levels() ); args.rspec = field.data(); @@ -319,25 +322,13 @@ void Spectral::norm( const Field& field, double norm_per_level[], int rank ) con args.nmaster = rank + 1; TRANS_CHECK(::trans_specnorm( &args ) ); #else - throw eckit::Exception( + throw_Exception( "Cannot compute spectral norms because Atlas has not " "been compiled with TRANS support." ); #endif } void Spectral::norm( const Field& field, std::vector& norm_per_level, int rank ) const { -#if ATLAS_HAVE_TRANS - norm_per_level.resize( std::max( 1, field.levels() ) ); - struct ::SpecNorm_t args = new_specnorm( *parallelisation_ ); - args.nfld = norm_per_level.size(); - args.rspec = field.data(); - args.rnorm = norm_per_level.data(); - args.nmaster = rank + 1; - TRANS_CHECK(::trans_specnorm( &args ) ); -#else - throw eckit::Exception( - "Cannot compute spectral norms because Atlas has not " - "been compiled with TRANS support." ); -#endif + norm( field, norm_per_level.data(), rank ); } } // namespace detail @@ -352,7 +343,7 @@ Spectral::Spectral( const eckit::Configuration& config ) : FunctionSpace( new detail::Spectral( config ) ), functionspace_( dynamic_cast( get() ) ) {} -Spectral::Spectral( const size_t truncation, const eckit::Configuration& config ) : +Spectral::Spectral( const int truncation, const eckit::Configuration& config ) : FunctionSpace( new detail::Spectral( truncation, config ) ), functionspace_( dynamic_cast( get() ) ) {} @@ -360,11 +351,11 @@ Spectral::Spectral( const trans::Trans& trans, const eckit::Configuration& confi FunctionSpace( new detail::Spectral( trans, config ) ), functionspace_( dynamic_cast( get() ) ) {} -size_t Spectral::nb_spectral_coefficients() const { +idx_t Spectral::nb_spectral_coefficients() const { return functionspace_->nb_spectral_coefficients(); } -size_t Spectral::nb_spectral_coefficients_global() const { +idx_t Spectral::nb_spectral_coefficients_global() const { return functionspace_->nb_spectral_coefficients_global(); } @@ -412,58 +403,82 @@ void Spectral::norm( const Field& field, std::vector& norm_per_level, in extern "C" { const detail::Spectral* atlas__SpectralFunctionSpace__new__config( const eckit::Configuration* config ) { - ATLAS_ERROR_HANDLING( return new detail::Spectral( *config ); ); - return 0; + ATLAS_ASSERT( config != nullptr ); + return new detail::Spectral( *config ); } const detail::Spectral* atlas__SpectralFunctionSpace__new__trans( trans::TransImpl* trans, const eckit::Configuration* config ) { - ATLAS_ERROR_HANDLING( return new detail::Spectral( trans::Trans( trans ), *config ); ); - return 0; + ATLAS_ASSERT( trans != nullptr ); + ATLAS_ASSERT( config != nullptr ); + return new detail::Spectral( trans::Trans( trans ), *config ); } void atlas__SpectralFunctionSpace__delete( detail::Spectral* This ) { - ATLAS_ERROR_HANDLING( ASSERT( This ); delete This; ); + ATLAS_ASSERT( This != nullptr ); + delete This; } field::FieldImpl* atlas__fs__Spectral__create_field( const detail::Spectral* This, const eckit::Configuration* options ) { - ATLAS_ERROR_HANDLING( ASSERT( This ); ASSERT( options ); field::FieldImpl * field; { + ATLAS_ASSERT( This != nullptr ); + ATLAS_ASSERT( options ); + field::FieldImpl* field; + { Field f = This->createField( *options ); field = f.get(); field->attach(); - } field->detach(); - return field; ); - return 0; + } + field->detach(); + return field; } void atlas__SpectralFunctionSpace__gather( const detail::Spectral* This, const field::FieldImpl* local, field::FieldImpl* global ) { - ATLAS_ERROR_HANDLING( ASSERT( This ); ASSERT( global ); ASSERT( local ); const Field l( local ); Field g( global ); - This->gather( l, g ); ); + ATLAS_ASSERT( This != nullptr ); + ATLAS_ASSERT( global != nullptr ); + ATLAS_ASSERT( local != nullptr ); + const Field l( local ); + Field g( global ); + This->gather( l, g ); } void atlas__SpectralFunctionSpace__scatter( const detail::Spectral* This, const field::FieldImpl* global, field::FieldImpl* local ) { - ATLAS_ERROR_HANDLING( ASSERT( This ); ASSERT( global ); ASSERT( local ); const Field g( global ); Field l( local ); - This->scatter( g, l ); ); + ATLAS_ASSERT( This != nullptr ); + ATLAS_ASSERT( global != nullptr ); + ATLAS_ASSERT( local != nullptr ); + const Field g( global ); + Field l( local ); + This->scatter( g, l ); } void atlas__SpectralFunctionSpace__gather_fieldset( const detail::Spectral* This, const field::FieldSetImpl* local, field::FieldSetImpl* global ) { - ATLAS_ERROR_HANDLING( ASSERT( This ); ASSERT( global ); ASSERT( local ); const FieldSet l( local ); - FieldSet g( global ); This->gather( l, g ); ); + ATLAS_ASSERT( This != nullptr ); + ATLAS_ASSERT( global != nullptr ); + ATLAS_ASSERT( local != nullptr ); + const FieldSet l( local ); + FieldSet g( global ); + This->gather( l, g ); } void atlas__SpectralFunctionSpace__scatter_fieldset( const detail::Spectral* This, const field::FieldSetImpl* global, field::FieldSetImpl* local ) { - ATLAS_ERROR_HANDLING( ASSERT( This ); ASSERT( global ); ASSERT( local ); const FieldSet g( global ); - FieldSet l( local ); This->scatter( g, l ); ); + ATLAS_ASSERT( This != nullptr ); + ATLAS_ASSERT( global != nullptr ); + ATLAS_ASSERT( local != nullptr ); + const FieldSet g( global ); + FieldSet l( local ); + This->scatter( g, l ); } void atlas__SpectralFunctionSpace__norm( const detail::Spectral* This, const field::FieldImpl* field, double norm[], int rank ) { - ATLAS_ERROR_HANDLING( ASSERT( This ); ASSERT( field ); ASSERT( norm ); This->norm( field, norm, rank ); ); + ATLAS_ASSERT( This != nullptr ); + ATLAS_ASSERT( field != nullptr ); + ATLAS_ASSERT( norm != nullptr ); + This->norm( field, norm, rank ); } } diff --git a/src/atlas/functionspace/Spectral.h b/src/atlas/functionspace/Spectral.h index ff945ed56..af89c7544 100644 --- a/src/atlas/functionspace/Spectral.h +++ b/src/atlas/functionspace/Spectral.h @@ -12,6 +12,7 @@ #include "atlas/field/Field.h" #include "atlas/functionspace/FunctionSpace.h" +#include "atlas/functionspace/detail/FunctionSpaceImpl.h" #include "atlas/library/config.h" #include "atlas/util/Config.h" @@ -40,16 +41,16 @@ class Spectral : public FunctionSpaceImpl { Spectral( const trans::Trans&, const eckit::Configuration& = util::NoConfig() ); - virtual ~Spectral(); + virtual ~Spectral() override; - virtual std::string type() const { return "Spectral"; } + virtual std::string type() const override { return "Spectral"; } - virtual std::string distribution() const; + virtual std::string distribution() const override; /// @brief Create a spectral field using FunctionSpaceImpl::createField; - virtual Field createField( const eckit::Configuration& ) const; - virtual Field createField( const Field&, const eckit::Configuration& ) const; + virtual Field createField( const eckit::Configuration& ) const override; + virtual Field createField( const Field&, const eckit::Configuration& ) const override; void gather( const FieldSet&, FieldSet& ) const; void gather( const Field&, Field& ) const; @@ -65,21 +66,22 @@ class Spectral : public FunctionSpaceImpl { void norm( const Field&, std::vector& norm_per_level, int rank = 0 ) const; public: // methods - size_t nb_spectral_coefficients() const; - size_t nb_spectral_coefficients_global() const; + idx_t nb_spectral_coefficients() const; + idx_t nb_spectral_coefficients_global() const; int truncation() const { return truncation_; } + virtual idx_t size() const override { return nb_spectral_coefficients(); } + private: // methods array::DataType config_datatype( const eckit::Configuration& ) const; std::string config_name( const eckit::Configuration& ) const; - size_t config_size( const eckit::Configuration& ) const; - size_t config_levels( const eckit::Configuration& ) const; + idx_t config_size( const eckit::Configuration& ) const; + idx_t config_levels( const eckit::Configuration& ) const; void set_field_metadata( const eckit::Configuration&, Field& ) const; - size_t footprint() const; + size_t footprint() const override; private: // data - size_t nb_levels_; - + idx_t nb_levels_; int truncation_; class Parallelisation; @@ -94,7 +96,7 @@ class Spectral : public FunctionSpace { public: Spectral( const FunctionSpace& ); Spectral( const eckit::Configuration& ); - Spectral( const size_t truncation, const eckit::Configuration& = util::NoConfig() ); + Spectral( const int truncation, const eckit::Configuration& = util::NoConfig() ); Spectral( const trans::Trans&, const eckit::Configuration& = util::NoConfig() ); operator bool() const { return valid(); } @@ -113,8 +115,8 @@ class Spectral : public FunctionSpace { void norm( const Field&, double norm_per_level[], int rank = 0 ) const; void norm( const Field&, std::vector& norm_per_level, int rank = 0 ) const; - size_t nb_spectral_coefficients() const; - size_t nb_spectral_coefficients_global() const; + idx_t nb_spectral_coefficients() const; + idx_t nb_spectral_coefficients_global() const; int truncation() const; private: diff --git a/src/atlas/functionspace/StructuredColumns.cc b/src/atlas/functionspace/StructuredColumns.cc index d3c392052..3eb2c3e7a 100644 --- a/src/atlas/functionspace/StructuredColumns.cc +++ b/src/atlas/functionspace/StructuredColumns.cc @@ -12,25 +12,36 @@ #include #include +#include +#include +#include #include "eckit/utils/MD5.h" #include "atlas/array/MakeView.h" #include "atlas/field/FieldSet.h" #include "atlas/field/detail/FieldImpl.h" +#include "atlas/grid/Distribution.h" +#include "atlas/grid/Partitioner.h" +#include "atlas/grid/StructuredGrid.h" +#include "atlas/library/Library.h" #include "atlas/mesh/Mesh.h" #include "atlas/parallel/Checksum.h" #include "atlas/parallel/GatherScatter.h" #include "atlas/parallel/HaloExchange.h" +#include "atlas/parallel/mpi/Statistics.h" #include "atlas/parallel/mpi/mpi.h" #include "atlas/parallel/omp/omp.h" -#include "atlas/runtime/ErrorHandling.h" +#include "atlas/runtime/Exception.h" #include "atlas/runtime/Trace.h" #include "atlas/util/Checksum.h" #include "atlas/util/CoordinateEnums.h" +#include "atlas/util/detail/Cache.h" #define IDX( i, j ) "(" << i << "," << j << ")" +#define REMOTE_IDX_BASE 0 + namespace atlas { namespace functionspace { namespace detail { @@ -61,11 +72,11 @@ std::string checksum_3d_field( const parallel::Checksum& checksum, const Field& array::LocalView values = make_leveled_view( field ); array::ArrayT surface_field( values.shape( 0 ), values.shape( 2 ) ); array::ArrayView surface = array::make_view( surface_field ); - const size_t npts = values.shape( 0 ); - atlas_omp_for( size_t n = 0; n < npts; ++n ) { - for ( size_t j = 0; j < surface.shape( 1 ); ++j ) { + const idx_t npts = values.shape( 0 ); + atlas_omp_for( idx_t n = 0; n < npts; ++n ) { + for ( idx_t j = 0; j < surface.shape( 1 ); ++j ) { surface( n, j ) = 0.; - for ( size_t l = 0; l < values.shape( 1 ); ++l ) + for ( idx_t l = 0; l < values.shape( 1 ); ++l ) surface( n, j ) += values( n, l, j ); } } @@ -77,8 +88,10 @@ struct GridPoint { idx_t i, j; idx_t r; - GridPoint() {} GridPoint( idx_t _i, idx_t _j ) : i( _i ), j( _j ) {} + GridPoint( idx_t _i, idx_t _j, idx_t _r ) : i( _i ), j( _j ), r( _r ) {} + + /* No longer used: bool operator<( const GridPoint& other ) const { if ( j < other.j ) return true; @@ -86,22 +99,27 @@ struct GridPoint { return false; } - //bool operator==( const GridPoint& other ) const { return ( j == other.j && i == other.i ); } + bool operator==( const GridPoint& other ) const { return ( j == other.j && i == other.i ); } + + */ }; + struct GridPointSet { public: - // idx_t r{0}; - std::set set; + GridPointSet() = default; + GridPointSet( size_t size ) { set.reserve( size ); } + + std::vector set; bool insert( idx_t i, idx_t j ) { - auto inserted = set.insert( GridPoint( i, j ) ); - if ( inserted.second ) { const_cast( *inserted.first ).r = set.size() - 1; } - return inserted.second; + idx_t r = set.size(); + set.emplace_back( i, j, r ); + return true; } - size_t size() const { return set.size(); } + idx_t size() const { return static_cast( set.size() ); } - using const_iterator = std::set::const_iterator; + using const_iterator = decltype( set )::const_iterator; const_iterator begin() const { return set.begin(); } const_iterator end() const { return set.end(); } @@ -109,31 +127,167 @@ struct GridPointSet { } // namespace +class StructuredColumnsHaloExchangeCache : public util::Cache +// , public mesh::detail::MeshObserver +{ +private: + using Base = util::Cache; + StructuredColumnsHaloExchangeCache() : Base( "StructuredColumnsHaloExchangeCache" ) {} + +public: + static StructuredColumnsHaloExchangeCache& instance() { + static StructuredColumnsHaloExchangeCache inst; + return inst; + } + util::ObjectHandle get_or_create( const detail::StructuredColumns& grid ) { + creator_type creator = std::bind( &StructuredColumnsHaloExchangeCache::create, &grid ); + return Base::get_or_create( key( grid ), creator ); + } + virtual void onGridDestruction( detail::StructuredColumns& grid ) { remove( key( grid ) ); } + +private: + static Base::key_type key( const detail::StructuredColumns& grid ) { + std::ostringstream key; + key << "grid[address=" << &grid << "]"; + return key.str(); + } + + static value_type* create( const detail::StructuredColumns* grid ) { + //mesh.get()->attachObserver( instance() ); + + value_type* value = new value_type(); + + value->setup( array::make_view( grid->partition() ).data(), + array::make_view( grid->remote_index() ).data(), REMOTE_IDX_BASE, grid->sizeHalo() ); + return value; + } + virtual ~StructuredColumnsHaloExchangeCache() {} +}; + +class StructuredColumnsGatherScatterCache : public util::Cache +// , public mesh::detail::MeshObserver +{ +private: + using Base = util::Cache; + StructuredColumnsGatherScatterCache() : Base( "StructuredColumnsGatherScatterCache" ) {} + +public: + static StructuredColumnsGatherScatterCache& instance() { + static StructuredColumnsGatherScatterCache inst; + return inst; + } + util::ObjectHandle get_or_create( const detail::StructuredColumns& grid ) { + creator_type creator = std::bind( &StructuredColumnsGatherScatterCache::create, &grid ); + return Base::get_or_create( key( grid ), creator ); + } + virtual void onGridDestruction( detail::StructuredColumns& grid ) { remove( key( grid ) ); } + +private: + static Base::key_type key( const detail::StructuredColumns& grid ) { + std::ostringstream key; + key << "grid[address=" << &grid << "]"; + return key.str(); + } + + static value_type* create( const detail::StructuredColumns* grid ) { + //mesh.get()->attachObserver( instance() ); + + value_type* value = new value_type(); + + value->setup( array::make_view( grid->partition() ).data(), + array::make_view( grid->remote_index() ).data(), REMOTE_IDX_BASE, + array::make_view( grid->global_index() ).data(), grid->sizeOwned() ); + return value; + } + virtual ~StructuredColumnsGatherScatterCache() {} +}; + +class StructuredColumnsChecksumCache : public util::Cache +// , public mesh::detail::MeshObserver +{ +private: + using Base = util::Cache; + StructuredColumnsChecksumCache() : Base( "StructuredColumnsChecksumCache" ) {} + +public: + static StructuredColumnsChecksumCache& instance() { + static StructuredColumnsChecksumCache inst; + return inst; + } + util::ObjectHandle get_or_create( const detail::StructuredColumns& grid ) { + creator_type creator = std::bind( &StructuredColumnsChecksumCache::create, &grid ); + return Base::get_or_create( key( grid ), creator ); + } + //virtual void onMeshDestruction( mesh::detail::MeshImpl& mesh ) { remove( key( mesh ) ); } + +private: + static Base::key_type key( const detail::StructuredColumns& grid ) { + std::ostringstream key; + key << "mesh[address=" << &grid << "]"; + return key.str(); + } + + static value_type* create( const detail::StructuredColumns* grid ) { + //mesh.get()->attachObserver( instance() ); + value_type* value = new value_type(); + util::ObjectHandle gather( + StructuredColumnsGatherScatterCache::instance().get_or_create( *grid ) ); + value->setup( gather ); + return value; + } + virtual ~StructuredColumnsChecksumCache() {} +}; + + +const parallel::GatherScatter& StructuredColumns::gather() const { + if ( gather_scatter_ ) return *gather_scatter_; + gather_scatter_ = StructuredColumnsGatherScatterCache::instance().get_or_create( *this ); + return *gather_scatter_; +} + +const parallel::GatherScatter& StructuredColumns::scatter() const { + if ( gather_scatter_ ) return *gather_scatter_; + gather_scatter_ = StructuredColumnsGatherScatterCache::instance().get_or_create( *this ); + return *gather_scatter_; +} + +const parallel::Checksum& StructuredColumns::checksum() const { + if ( checksum_ ) return *checksum_; + checksum_ = StructuredColumnsChecksumCache::instance().get_or_create( *this ); + return *checksum_; +} + +const parallel::HaloExchange& StructuredColumns::halo_exchange() const { + if ( halo_exchange_ ) return *halo_exchange_; + halo_exchange_ = StructuredColumnsHaloExchangeCache::instance().get_or_create( *this ); + return *halo_exchange_; +} + void StructuredColumns::set_field_metadata( const eckit::Configuration& config, Field& field ) const { field.set_functionspace( this ); bool global( false ); if ( config.get( "global", global ) ) { if ( global ) { - size_t owner( 0 ); + idx_t owner( 0 ); config.get( "owner", owner ); field.metadata().set( "owner", owner ); } } field.metadata().set( "global", global ); - size_t levels( nb_levels_ ); + idx_t levels( nb_levels_ ); config.get( "levels", levels ); field.set_levels( levels ); - size_t variables( 0 ); + idx_t variables( 0 ); config.get( "variables", variables ); field.set_variables( variables ); } array::DataType StructuredColumns::config_datatype( const eckit::Configuration& config ) const { array::DataType::kind_t kind; - if ( !config.get( "datatype", kind ) ) throw eckit::AssertionFailed( "datatype missing", Here() ); + if ( !config.get( "datatype", kind ) ) throw_Exception( "datatype missing", Here() ); return array::DataType( kind ); } @@ -143,8 +297,8 @@ std::string StructuredColumns::config_name( const eckit::Configuration& config ) return name; } -size_t StructuredColumns::config_levels( const eckit::Configuration& config ) const { - size_t levels( nb_levels_ ); +idx_t StructuredColumns::config_levels( const eckit::Configuration& config ) const { + idx_t levels( nb_levels_ ); config.get( "levels", levels ); return levels; } @@ -154,16 +308,21 @@ array::ArrayShape StructuredColumns::config_shape( const eckit::Configuration& c shape.push_back( config_size( config ) ); - size_t levels( nb_levels_ ); + idx_t levels( nb_levels_ ); config.get( "levels", levels ); if ( levels > 0 ) shape.push_back( levels ); - size_t variables( 0 ); + idx_t variables( 0 ); config.get( "variables", variables ); if ( variables > 0 ) shape.push_back( variables ); return shape; } +size_t StructuredColumns::Map2to1::footprint() const { + size_t size = sizeof( *this ); + size += data_.size() * sizeof( decltype( data_ )::value_type ); + return size; +} void StructuredColumns::Map2to1::print( std::ostream& out ) const { for ( idx_t j = j_min_; j <= j_max_; ++j ) { @@ -171,9 +330,9 @@ void StructuredColumns::Map2to1::print( std::ostream& out ) const { for ( idx_t i = i_min_; i <= i_max_; ++i ) { idx_t v = operator()( i, j ); if ( v == missing() ) - out << std::setw( 4 ) << "X"; + out << std::setw( 6 ) << "X"; else - out << std::setw( 4 ) << v; + out << std::setw( 6 ) << v; } out << '\n'; } @@ -190,14 +349,14 @@ void StructuredColumns::IndexRange::print( std::ostream& out ) const { out << '\n'; } -size_t StructuredColumns::config_size( const eckit::Configuration& config ) const { - size_t size = size_halo_; +idx_t StructuredColumns::config_size( const eckit::Configuration& config ) const { + idx_t size = size_halo_; bool global( false ); if ( config.get( "global", global ) ) { if ( global ) { - size_t owner( 0 ); + idx_t owner( 0 ); config.get( "owner", owner ); - size = ( mpi::comm().rank() == owner ? grid_.size() : 0 ); + size = ( static_cast( mpi::comm().rank() ) == owner ? grid_->size() : 0 ); } } return size; @@ -207,6 +366,19 @@ std::string StructuredColumns::distribution() const { return distribution_; } +void StructuredColumns::throw_outofbounds( idx_t i, idx_t j ) const { + std::stringstream ss; + if ( j < j_begin_halo() || j >= j_end_halo() ) { + ss << "OutofBounds: j out of range! : (i,j) = (" << i << "," << j << ") --- Expected: " << j_begin_halo() + << " <= j < " << j_end_halo(); + } + if ( i < i_begin_halo( j ) || i >= i_end_halo( j ) ) { + ss << "OutofBounds: i out of range! : (i,j) = (" << i << "," << j << ") --- Expected: " << i_begin_halo( j ) + << " <= i < " << i_end_halo( j ); + } + throw_Exception( ss.str(), Here() ); +} + // ---------------------------------------------------------------------------- // Constructor // ---------------------------------------------------------------------------- @@ -215,21 +387,31 @@ StructuredColumns::StructuredColumns( const Grid& grid, const eckit::Configurati StructuredColumns::StructuredColumns( const Grid& grid, const grid::Partitioner& p, const eckit::Configuration& config ) : - grid_( grid ), - nb_levels_( 0 ) { - ATLAS_TRACE( "Generating StructuredColumns..." ); - nb_levels_ = config_levels( config ); - if ( not grid_ ) { throw eckit::BadCast( "Grid is not a grid::Structured type", Here() ); } - const eckit::mpi::Comm& comm = mpi::comm(); + StructuredColumns( grid, Vertical( config ), p, config ) {} + +StructuredColumns::StructuredColumns( const Grid& grid, const grid::Distribution& distribution, + const eckit::Configuration& config ) : + StructuredColumns( grid, distribution, Vertical( config ), config ) {} + +StructuredColumns::StructuredColumns( const Grid& grid, const grid::Distribution& distribution, + const Vertical& vertical, const eckit::Configuration& config ) : + vertical_( vertical ), + nb_levels_( vertical_.size() ), + grid_( new StructuredGrid( grid ) ) { + setup( distribution, config ); +} +StructuredColumns::StructuredColumns( const Grid& grid, const Vertical& vertical, const eckit::Configuration& config ) : + StructuredColumns( grid, vertical, grid::Partitioner(), config ) {} + +StructuredColumns::StructuredColumns( const Grid& grid, const Vertical& vertical, const grid::Partitioner& p, + const eckit::Configuration& config ) : + vertical_( vertical ), + nb_levels_( vertical_.size() ), + grid_( new StructuredGrid( grid ) ) { grid::Partitioner partitioner( p ); if ( not partitioner ) { - if ( grid_.domain().global() ) { - if ( grid::Partitioner::exists( "trans" ) ) - partitioner = grid::Partitioner( "trans" ); - else - partitioner = grid::Partitioner( "equal_regions" ); - } + if ( grid_->domain().global() ) { partitioner = grid::Partitioner( "equal_regions" ); } else { partitioner = grid::Partitioner( "checkerboard" ); } @@ -237,18 +419,33 @@ StructuredColumns::StructuredColumns( const Grid& grid, const grid::Partitioner& grid::Distribution distribution; ATLAS_TRACE_SCOPE( "Partitioning grid ..." ) { distribution = grid::Distribution( grid, partitioner ); } + + setup( distribution, config ); +} + +void StructuredColumns::setup( const grid::Distribution& distribution, const eckit::Configuration& config ) { + ATLAS_TRACE( "Generating StructuredColumns..." ); + bool periodic_points = config.getInt( "periodic_points", false ); + if ( not( *grid_ ) ) { throw_Exception( "Grid is not a grid::Structured type", Here() ); } + const eckit::mpi::Comm& comm = mpi::comm(); + + + ny_ = grid_->ny(); + north_pole_included_ = 90. - grid_->y( 0 ) == 0.; + south_pole_included_ = 90. + grid_->y( ny_ - 1 ) == 0; + distribution_ = distribution.type(); - int mpi_rank = mpi::comm().rank(); + int mpi_rank = int( mpi::comm().rank() ); j_begin_ = std::numeric_limits::max(); j_end_ = std::numeric_limits::min(); - i_begin_.resize( grid_.ny(), std::numeric_limits::max() ); - i_end_.resize( grid_.ny(), std::numeric_limits::min() ); - size_t c( 0 ); - size_t owned( 0 ); - for ( size_t j = 0; j < grid_.ny(); ++j ) { - for ( size_t i = 0; i < grid_.nx( j ); ++i, ++c ) { + i_begin_.resize( grid_->ny(), std::numeric_limits::max() ); + i_end_.resize( grid_->ny(), std::numeric_limits::min() ); + idx_t c( 0 ); + idx_t owned( 0 ); + for ( idx_t j = 0; j < grid_->ny(); ++j ) { + for ( idx_t i = 0; i < grid_->nx( j ); ++i, ++c ) { if ( distribution.partition( c ) == mpi_rank ) { j_begin_ = std::min( j_begin_, j ); j_end_ = std::max( j_end_, j + 1 ); @@ -259,26 +456,18 @@ StructuredColumns::StructuredColumns( const Grid& grid, const grid::Partitioner& } } - int halo = config.getInt( "halo", 0 ); - - GridPointSet gridpoints; - for ( idx_t j = j_begin_; j < j_end_; ++j ) { - for ( idx_t i = i_begin_[j]; i < i_end_[j]; ++i ) { - gridpoints.insert( i, j ); - } - } - - ASSERT( gridpoints.size() == owned ); + size_owned_ = owned; - size_owned_ = gridpoints.size(); + int halo = config.getInt( "halo", 0 ); + halo_ = halo; j_begin_halo_ = j_begin_ - halo; j_end_halo_ = j_end_ + halo; - i_begin_halo_.resize( -halo, grid_.ny() - 1 + halo ); - i_end_halo_.resize( -halo, grid_.ny() - 1 + halo ); + i_begin_halo_.resize( -halo, grid_->ny() - 1 + halo ); + i_end_halo_.resize( -halo, grid_->ny() - 1 + halo ); auto compute_i = [this]( idx_t i, idx_t j ) -> idx_t { - const idx_t nx = grid_.nx( j ); + const idx_t nx = grid_->nx( j ); while ( i >= nx ) { i -= nx; } @@ -290,12 +479,12 @@ StructuredColumns::StructuredColumns( const Grid& grid, const grid::Partitioner& std::function compute_j; compute_j = [this, &compute_j]( idx_t j ) -> idx_t { - if ( j < 0 ) { j = ( grid_.y( 0 ) == 90 ) ? -j : -j - 1; } - else if ( j >= grid_.ny() ) { - idx_t jlast = grid_.ny() - 1; - j = ( grid_.y( jlast ) == -90 ) ? jlast - 1 - ( j - grid_.ny() ) : jlast - ( j - grid_.ny() ); + if ( j < 0 ) { j = ( grid_->y( 0 ) == 90. ) ? -j : -j - 1; } + else if ( j >= grid_->ny() ) { + idx_t jlast = grid_->ny() - 1; + j = ( grid_->y( jlast ) == -90. ) ? jlast - 1 - ( j - grid_->ny() ) : jlast - ( j - grid_->ny() ); } - if ( j < 0 or j >= grid_.ny() ) { j = compute_j( j ); } + if ( j < 0 or j >= grid_->ny() ) { j = compute_j( j ); } return j; }; @@ -304,27 +493,26 @@ StructuredColumns::StructuredColumns( const Grid& grid, const grid::Partitioner& double x; jj = compute_j( j ); ii = compute_i( i, jj ); // guaranteed between 0 and nx(jj) - const idx_t nx = grid_.nx( jj ); + const idx_t nx = grid_->nx( jj ); const double a = ( ii - i ) / nx; - x = grid_.x( ii, jj ) - a * grid_.x( nx, jj ); + x = grid_->x( ii, jj ) - a * grid_->x( nx, jj ); return x; }; auto compute_y = [this, &compute_j]( idx_t j ) -> double { idx_t jj; double y; - jj = compute_j( j ); - const idx_t ny = grid_.ny(); - y = ( j < 0 ) ? 90. + ( 90. - grid_.y( jj ) ) - : ( j >= grid_.ny() ) ? -90. + ( -90. - grid_.y( jj ) ) : grid_.y( jj ); + jj = compute_j( j ); + y = ( j < 0 ) ? 90. + ( 90. - grid_->y( jj ) ) + : ( j >= grid_->ny() ) ? -90. + ( -90. - grid_->y( jj ) ) : grid_->y( jj ); return y; }; - std::vector global_offsets( grid_.ny() ); - size_t grid_idx = 0; - for ( size_t j = 0; j < grid_.ny(); ++j ) { + std::vector global_offsets( grid_->ny() ); + idx_t grid_idx = 0; + for ( idx_t j = 0; j < grid_->ny(); ++j ) { global_offsets[j] = grid_idx; - grid_idx += grid_.nx( j ); + grid_idx += grid_->nx( j ); } auto compute_g = [this, &global_offsets, &compute_i, &compute_j]( idx_t i, idx_t j ) -> gidx_t { @@ -333,9 +521,9 @@ StructuredColumns::StructuredColumns( const Grid& grid, const grid::Partitioner& jj = compute_j( j ); ii = compute_i( i, jj ); if ( jj != j ) { - ASSERT( grid_.nx( jj ) % 2 == 0 ); // assert even number of points - ii = ( ii < grid_.nx( jj ) / 2 ) ? ii + grid_.nx( jj ) / 2 - : ( ii >= grid_.nx( jj ) / 2 ) ? ii - grid_.nx( jj ) / 2 : ii; + ATLAS_ASSERT( grid_->nx( jj ) % 2 == 0 ); // assert even number of points + ii = ( ii < grid_->nx( jj ) / 2 ) ? ii + grid_->nx( jj ) / 2 + : ( ii >= grid_->nx( jj ) / 2 ) ? ii - grid_->nx( jj ) / 2 : ii; } g = global_offsets[jj] + ii + 1; return g; @@ -347,9 +535,9 @@ StructuredColumns::StructuredColumns( const Grid& grid, const grid::Partitioner& jj = compute_j( j ); ii = compute_i( i, jj ); if ( jj != j ) { - ASSERT( grid_.nx( jj ) % 2 == 0 ); // assert even number of points - ii = ( ii < grid_.nx( jj ) / 2 ) ? ii + grid_.nx( jj ) / 2 - : ( ii >= grid_.nx( jj ) / 2 ) ? ii - grid_.nx( jj ) / 2 : ii; + ATLAS_ASSERT( grid_->nx( jj ) % 2 == 0 ); // assert even number of points + ii = ( ii < grid_->nx( jj ) / 2 ) ? ii + grid_->nx( jj ) / 2 + : ( ii >= grid_->nx( jj ) / 2 ) ? ii - grid_->nx( jj ) / 2 : ii; } p = distribution.partition( global_offsets[jj] + ii ); return p; @@ -359,90 +547,187 @@ StructuredColumns::StructuredColumns( const Grid& grid, const grid::Partitioner& ATLAS_TRACE_SCOPE( "Load imbalance" ) { comm.barrier(); } } + GridPointSet gridpoints; + ATLAS_TRACE_SCOPE( "Compute mapping ..." ) { idx_t imin = std::numeric_limits::max(); idx_t imax = -std::numeric_limits::max(); idx_t jmin = std::numeric_limits::max(); idx_t jmax = -std::numeric_limits::max(); - for ( idx_t j = j_begin_halo_; j < j_end_halo_; ++j ) { - i_begin_halo_( j ) = imin; - i_end_halo_( j ) = imax; + + ATLAS_TRACE_SCOPE( "Compute bounds" ) { + for ( idx_t j = j_begin_halo_; j < j_end_halo_; ++j ) { + i_begin_halo_( j ) = imin; + i_end_halo_( j ) = imax; + } + double eps = 1.e-12; + for ( idx_t j = j_begin_; j < j_end_; ++j ) { + for ( idx_t i : {i_begin_[j], i_end_[j] - 1} ) { + // Following line only, increases periodic halo on the east side by 1 + if ( periodic_points && i == grid_->nx( j ) - 1 ) { ++i; } + + double x = grid_->x( i, j ); + double x_next = grid_->x( i + 1, j ); + double x_prev = grid_->x( i - 1, j ); + for ( idx_t jj = j - halo; jj <= j + halo; ++jj ) { + idx_t last = grid_->nx( compute_j( jj ) ) - 1; + if ( i == grid_->nx( j ) ) { ++last; } + + jmin = std::min( jmin, jj ); + jmax = std::max( jmax, jj ); + // Compute ii as index less-equal of x + // + // x(i,j) + // |-----|-----|-----|-----| + // ii-halo ii + // + // x(i,j) + // |-----|-----|--+--|-----| + // ii-halo ii + + idx_t ii = -halo; + while ( compute_x( ii, jj ) < x - eps ) { + ii++; + } + + // ATLAS-186 workaround + // This while should not have to be there, but is here because of + // the MatchingMeshDomainDecomposition algorithm. that may lead to points + // left of the point ii. + while ( compute_x( ii - 1, jj ) > x_prev + eps ) { + --ii; + } + + idx_t i_minus_halo = ii - halo; + + // Compute ii as index less-equal of x_next + // + // x(i,j) x_next(i,j) + // |-----|-----|-+---|-+---|-----| + // ii-halo iii iii+halo + // + idx_t iii = ii; + while ( compute_x( iii + 1, jj ) < x_next - eps ) { + ++iii; + } + iii = std::min( iii, last ); + idx_t i_plus_halo = iii + halo; + + imin = std::min( imin, i_minus_halo ); + imax = std::max( imax, i_plus_halo ); + i_begin_halo_( jj ) = std::min( i_begin_halo_( jj ), i_minus_halo ); + i_end_halo_( jj ) = std::max( i_end_halo_( jj ), i_plus_halo + 1 ); + } + } + } + } + + int extra_halo{0}; + for ( idx_t j = j_begin_halo_; j < j_begin_; ++j ) { + extra_halo += i_end_halo_( j ) - i_begin_halo_( j ); } - double eps = 1.e-12; for ( idx_t j = j_begin_; j < j_end_; ++j ) { - for ( idx_t i : {i_begin_[j], i_end_[j] - 1} ) { - double x = grid_.x( i, j ); - for ( idx_t jj = j - halo; jj <= j + halo; ++jj ) { - jmin = std::min( jmin, jj ); - jmax = std::max( jmax, jj ); - idx_t ii = -halo; - while ( compute_x( ii, jj ) < x - eps ) { - ii++; - } - idx_t i_minus_halo = ii - halo; - idx_t i_plus_halo = ( x + eps > compute_x( ii, jj ) ) ? ii + halo : ii + std::max( 0, halo - 1 ); - imin = std::min( imin, i_minus_halo ); - imax = std::max( imax, i_plus_halo ); - i_begin_halo_( jj ) = std::min( i_begin_halo_( jj ), i_minus_halo ); - i_end_halo_( jj ) = std::max( i_end_halo_( jj ), i_plus_halo + 1 ); + extra_halo += i_begin_[j] - i_begin_halo_( j ); + extra_halo += i_end_halo_( j ) - i_end_[j]; + } + for ( idx_t j = j_end_; j < j_end_halo_; ++j ) { + extra_halo += i_end_halo_( j ) - i_begin_halo_( j ); + } + + + gridpoints = GridPointSet{static_cast( owned + extra_halo )}; + + ATLAS_TRACE_SCOPE( "Assemble gridpoints" ) { + for ( idx_t j = j_begin_; j < j_end_; ++j ) { + for ( idx_t i = i_begin_[j]; i < i_end_[j]; ++i ) { + gridpoints.insert( i, j ); + } + } + + ATLAS_ASSERT( gridpoints.size() == owned ); + + for ( idx_t j = j_begin_halo_; j < j_begin_; ++j ) { + for ( idx_t i = i_begin_halo_( j ); i < i_end_halo_( j ); ++i ) { + gridpoints.insert( i, j ); + } + } + for ( idx_t j = j_begin_; j < j_end_; ++j ) { + for ( idx_t i = i_begin_halo_( j ); i < i_begin_[j]; ++i ) { + gridpoints.insert( i, j ); + } + for ( idx_t i = i_end_[j]; i < i_end_halo_( j ); ++i ) { + gridpoints.insert( i, j ); + } + } + for ( idx_t j = j_end_; j < j_end_halo_; ++j ) { + for ( idx_t i = i_begin_halo_( j ); i < i_end_halo_( j ); ++i ) { + gridpoints.insert( i, j ); } } + + ATLAS_ASSERT( gridpoints.size() == owned + extra_halo ); } - for ( idx_t j = j_begin_halo_; j < j_end_halo_; ++j ) { - for ( idx_t i = i_begin_halo_( j ); i < i_end_halo_( j ); ++i ) { - gridpoints.insert( i, j ); + + ATLAS_TRACE_SCOPE( "Fill in ij2gp " ) { + ij2gp_.resize( {imin, imax}, {jmin, jmax} ); + + for ( const GridPoint& gp : gridpoints ) { + ij2gp_.set( gp.i, gp.j, gp.r ); } } + } - ij2gp_.resize( {imin, imax}, {jmin, jmax} ); + ATLAS_TRACE_SCOPE( "Create fields" ) { + size_halo_ = gridpoints.size(); + field_partition_ = Field( "partition", array::make_datatype(), array::make_shape( size_halo_ ) ); + field_global_index_ = Field( "glb_idx", array::make_datatype(), array::make_shape( size_halo_ ) ); + field_index_i_ = Field( "index_i", array::make_datatype(), array::make_shape( size_halo_ ) ); + field_index_j_ = Field( "index_j", array::make_datatype(), array::make_shape( size_halo_ ) ); + field_xy_ = Field( "xy", array::make_datatype(), array::make_shape( size_halo_, 2 ) ); + + auto xy = array::make_view( field_xy_ ); + auto part = array::make_view( field_partition_ ); + auto global_idx = array::make_view( field_global_index_ ); + auto index_i = array::make_indexview( field_index_i_ ); + auto index_j = array::make_indexview( field_index_j_ ); - field_xy_ = Field( "xy", array::make_datatype(), array::make_shape( gridpoints.size(), 2 ) ); - auto xy = array::make_view( field_xy_ ); for ( const GridPoint& gp : gridpoints ) { - ij2gp_.set( gp.i, gp.j, gp.r ); xy( gp.r, XX ) = compute_x( gp.i, gp.j ); - if ( gp.j >= 0 && gp.j < grid_.ny() ) { xy( gp.r, YY ) = grid_.y( gp.j ); } + if ( gp.j >= 0 && gp.j < grid_->ny() ) { xy( gp.r, YY ) = grid_->y( gp.j ); } else { xy( gp.r, YY ) = compute_y( gp.j ); } + + bool in_domain( false ); + if ( gp.j >= 0 && gp.j < grid_->ny() ) { + if ( gp.i >= 0 && gp.i < grid_->nx( gp.j ) ) { + in_domain = true; + gidx_t k = global_offsets[gp.j] + gp.i; + part( gp.r ) = distribution.partition( k ); + global_idx( gp.r ) = k + 1; + } + } + if ( not in_domain ) { + global_idx( gp.r ) = compute_g( gp.i, gp.j ); + part( gp.r ) = compute_p( gp.i, gp.j ); + } + index_i( gp.r ) = gp.i; + index_j( gp.r ) = gp.j; } } +} + - size_halo_ = gridpoints.size(); - field_partition_ = Field( "partition", array::make_datatype(), array::make_shape( size_halo_ ) ); - field_global_index_ = Field( "glb_idx", array::make_datatype(), array::make_shape( size_halo_ ) ); +void StructuredColumns::create_remote_index() const { field_remote_index_ = Field( "remote_idx", array::make_datatype(), array::make_shape( size_halo_ ) ); - field_index_i_ = Field( "index_i", array::make_datatype(), array::make_shape( size_halo_ ) ); - field_index_j_ = Field( "index_j", array::make_datatype(), array::make_shape( size_halo_ ) ); - - auto part = array::make_view( field_partition_ ); - auto global_idx = array::make_view( field_global_index_ ); - auto remote_idx = array::make_view( field_remote_index_ ); - auto index_i = array::make_indexview( field_index_i_ ); - auto index_j = array::make_indexview( field_index_j_ ); - - for ( const GridPoint& gp : gridpoints ) { - bool in_domain( false ); - if ( gp.j >= 0 && gp.j < grid_.ny() ) { - if ( gp.i >= 0 && gp.i < grid_.nx( gp.j ) ) { - in_domain = true; - size_t k = global_offsets[gp.j] + gp.i; - part( gp.r ) = distribution.partition( k ); - global_idx( gp.r ) = k + 1; - remote_idx( gp.r ) = gp.r; - } - } - if ( not in_domain ) { - global_idx( gp.r ) = compute_g( gp.i, gp.j ); - part( gp.r ) = compute_p( gp.i, gp.j ); - } - index_i( gp.r ) = gp.i; - index_j( gp.r ) = gp.j; + auto remote_idx = array::make_view( field_remote_index_ ); + for ( idx_t n = 0; n < size_owned_; ++n ) { + remote_idx( n ) = n; } + ATLAS_TRACE_SCOPE( "Parallelisation ..." ) { auto build_partition_graph = [this]() -> std::unique_ptr { - const eckit::mpi::Comm& comm = mpi::comm(); const int mpi_size = int( comm.size() ); const int mpi_rank = int( comm.rank() ); @@ -451,7 +736,7 @@ StructuredColumns::StructuredColumns( const Grid& grid, const grid::Partitioner& std::set others_set; others_set.insert( mpi_rank ); - for ( size_t i = size_owned_; i < size_halo_; ++i ) { + for ( idx_t i = size_owned_; i < size_halo_; ++i ) { others_set.insert( p( i ) ); } std::vector others( others_set.begin(), others_set.end() ); @@ -460,9 +745,9 @@ StructuredColumns::StructuredColumns( const Grid& grid, const grid::Partitioner& comm.allGatherv( others.begin(), others.end(), recv_others ); - std::vector counts( recv_others.counts.begin(), recv_others.counts.end() ); - std::vector displs( recv_others.displs.begin(), recv_others.displs.end() ); - std::vector values( recv_others.buffer.begin(), recv_others.buffer.end() ); + std::vector counts( recv_others.counts.begin(), recv_others.counts.end() ); + std::vector displs( recv_others.displs.begin(), recv_others.displs.end() ); + std::vector values( recv_others.buffer.begin(), recv_others.buffer.end() ); return std::unique_ptr( new Mesh::PartitionGraph( values.data(), mpi_size, displs.data(), counts.data() ) ); }; @@ -471,57 +756,64 @@ StructuredColumns::StructuredColumns( const Grid& grid, const grid::Partitioner& ATLAS_TRACE_SCOPE( "Building partition graph..." ) { graph_ptr = build_partition_graph(); } const Mesh::PartitionGraph& graph = *graph_ptr; - ATLAS_TRACE_SCOPE( "Setup parallel fields..." ) { + ATLAS_TRACE_SCOPE( "Setup remote_index fields..." ) { auto p = array::make_view( partition() ); auto g = array::make_view( global_index() ); const eckit::mpi::Comm& comm = mpi::comm(); - const int mpi_size = int( comm.size() ); const int mpi_rank = int( comm.rank() ); - auto neighbours = graph.nearestNeighbours( mpi_rank ); - std::map part_to_neighbour; - for ( size_t j = 0; j < neighbours.size(); ++j ) { + auto neighbours = graph.nearestNeighbours( mpi_rank ); + const idx_t nb_neighbours = static_cast( neighbours.size() ); + std::unordered_map part_to_neighbour; + part_to_neighbour.reserve( nb_neighbours ); + ATLAS_TRACE_SCOPE( "part_to_neighbour" ) + for ( idx_t j = 0; j < nb_neighbours; ++j ) { part_to_neighbour[neighbours[j]] = j; } - std::vector halo_per_neighbour( neighbours.size(), 0 ); - for ( size_t i = size_owned_; i < size_halo_; ++i ) { + std::vector halo_per_neighbour( neighbours.size(), 0 ); + ATLAS_TRACE_SCOPE( "set halo_per_neighbour" ) + for ( idx_t i = size_owned_; i < size_halo_; ++i ) { halo_per_neighbour[part_to_neighbour[p( i )]]++; } std::vector> g_per_neighbour( neighbours.size() ); - for ( size_t j = 0; j < neighbours.size(); ++j ) { + for ( idx_t j = 0; j < nb_neighbours; ++j ) { g_per_neighbour[j].reserve( halo_per_neighbour[j] ); } - for ( size_t j = size_owned_; j < size_halo_; ++j ) { - g_per_neighbour[part_to_neighbour[p( j )]].push_back( g( j ) ); + for ( idx_t j = size_owned_; j < size_halo_; ++j ) { + g_per_neighbour[part_to_neighbour[p( j )]].emplace_back( g( j ) ); } - std::vector> r_per_neighbour( neighbours.size() ); - for ( size_t j = 0; j < neighbours.size(); ++j ) { + std::vector> r_per_neighbour( neighbours.size() ); + for ( idx_t j = 0; j < nb_neighbours; ++j ) { r_per_neighbour[j].resize( halo_per_neighbour[j] ); } std::vector send_requests( neighbours.size() ); std::vector recv_requests( neighbours.size() ); - std::vector recv_size( neighbours.size() ); + std::vector recv_size( neighbours.size() ); int tag = 0; - for ( size_t j = 0; j < neighbours.size(); ++j ) { - size_t g_per_neighbour_size = g_per_neighbour[j].size(); - send_requests[j] = comm.iSend( g_per_neighbour_size, neighbours[j], tag ); - recv_requests[j] = comm.iReceive( recv_size[j], neighbours[j], tag ); + ATLAS_TRACE_SCOPE( "send-receive g_per_neighbour size" ) + for ( idx_t j = 0; j < nb_neighbours; ++j ) { + idx_t g_per_neighbour_size = static_cast( g_per_neighbour[j].size() ); + send_requests[j] = comm.iSend( g_per_neighbour_size, neighbours[j], tag ); + recv_requests[j] = comm.iReceive( recv_size[j], neighbours[j], tag ); } - for ( size_t j = 0; j < neighbours.size(); ++j ) { - comm.wait( send_requests[j] ); - } + ATLAS_TRACE_MPI( WAIT ) { + for ( idx_t j = 0; j < nb_neighbours; ++j ) { + comm.wait( send_requests[j] ); + } - for ( size_t j = 0; j < neighbours.size(); ++j ) { - comm.wait( recv_requests[j] ); + for ( idx_t j = 0; j < nb_neighbours; ++j ) { + comm.wait( recv_requests[j] ); + } } std::vector> recv_g_per_neighbour( neighbours.size() ); - for ( size_t j = 0; j < neighbours.size(); ++j ) { + ATLAS_TRACE_SCOPE( "send-receive g_per_neighbour" ) + for ( idx_t j = 0; j < nb_neighbours; ++j ) { recv_g_per_neighbour[j].resize( recv_size[j] ); send_requests[j] = @@ -530,79 +822,118 @@ StructuredColumns::StructuredColumns( const Grid& grid, const grid::Partitioner& comm.iReceive( recv_g_per_neighbour[j].data(), recv_g_per_neighbour[j].size(), neighbours[j], tag ); } - std::vector> send_r_per_neighbour( neighbours.size() ); - std::map g_to_r; - for ( size_t j = 0; j < size_owned_; ++j ) { - g_to_r[g( j )] = j; - } - for ( size_t j = 0; j < neighbours.size(); ++j ) { - send_r_per_neighbour[j].reserve( recv_size[j] ); + std::vector> send_r_per_neighbour( neighbours.size() ); + + // Assemble "send_r_per_neighbour" + // Depending if we can afford memory for a globally sized array, we can have a + // much faster version of g_to_r map using std::vector. + // TODO: using c++14 we can create a polymorphic lambda to avoid duplicated + // code in the two branches of following if. + if ( comm.size() == 1 ) { + std::vector g_to_r( size_owned_ + 1 ); + + ATLAS_TRACE_SCOPE( "g_to_r (using vector)" ) + for ( idx_t j = 0; j < size_owned_; ++j ) { +#if ATLAS_ARRAYVIEW_BOUNDS_CHECKING + if ( g( j ) >= size_owned_ + 1 ) { + ATLAS_DEBUG_VAR( g( j ) ); + throw_OutOfRange( "g_to_r", g( j ), size_owned_ + 1, Here() ); + } +#endif + g_to_r[g( j )] = j; + } + for ( idx_t j = 0; j < nb_neighbours; ++j ) { + send_r_per_neighbour[j].reserve( recv_size[j] ); - comm.wait( recv_requests[j] ); // wait for recv_g_per_neighbour[j] - for ( gidx_t gidx : recv_g_per_neighbour[j] ) { - send_r_per_neighbour[j].push_back( g_to_r[gidx] ); + comm.wait( recv_requests[j] ); // wait for recv_g_per_neighbour[j] + for ( gidx_t gidx : recv_g_per_neighbour[j] ) { + send_r_per_neighbour[j].emplace_back( g_to_r[gidx] ); + } } } + else { + std::unordered_map g_to_r; + g_to_r.reserve( size_owned_ ); - for ( size_t j = 0; j < neighbours.size(); ++j ) { - comm.wait( send_requests[j] ); - send_requests[j] = - comm.iSend( send_r_per_neighbour[j].data(), send_r_per_neighbour[j].size(), neighbours[j], tag ); - recv_requests[j] = - comm.iReceive( r_per_neighbour[j].data(), r_per_neighbour[j].size(), neighbours[j], tag ); + ATLAS_TRACE_SCOPE( "g_to_r (using unordered set)" ) + for ( idx_t j = 0; j < size_owned_; ++j ) { + g_to_r[g( j )] = j; + } + for ( idx_t j = 0; j < nb_neighbours; ++j ) { + send_r_per_neighbour[j].reserve( recv_size[j] ); + + comm.wait( recv_requests[j] ); // wait for recv_g_per_neighbour[j] + for ( gidx_t gidx : recv_g_per_neighbour[j] ) { + send_r_per_neighbour[j].emplace_back( g_to_r[gidx] ); + } + } } - for ( size_t j = 0; j < neighbours.size(); ++j ) { - comm.wait( recv_requests[j] ); + ATLAS_TRACE_MPI( ALLTOALL ) { + for ( idx_t j = 0; j < nb_neighbours; ++j ) { + comm.wait( send_requests[j] ); + send_requests[j] = comm.iSend( send_r_per_neighbour[j].data(), send_r_per_neighbour[j].size(), + neighbours[j], tag ); + recv_requests[j] = + comm.iReceive( r_per_neighbour[j].data(), r_per_neighbour[j].size(), neighbours[j], tag ); + } } - std::vector counters( neighbours.size(), 0 ); - for ( size_t j = size_owned_; j < size_halo_; ++j ) { - size_t neighbour = part_to_neighbour[p( j )]; - remote_idx( j ) = r_per_neighbour[neighbour][counters[neighbour]++]; + ATLAS_TRACE_MPI( WAIT ) { + for ( idx_t j = 0; j < nb_neighbours; ++j ) { + comm.wait( recv_requests[j] ); + } } - for ( size_t j = 0; j < neighbours.size(); ++j ) { - comm.wait( send_requests[j] ); + std::vector counters( neighbours.size(), 0 ); + ATLAS_TRACE_SCOPE( "set remote_idx" ) + for ( idx_t j = size_owned_; j < size_halo_; ++j ) { + idx_t neighbour = part_to_neighbour[p( j )]; + remote_idx( j ) = r_per_neighbour[neighbour][counters[neighbour]++]; } - } - ATLAS_TRACE_SCOPE( "Setup gather_scatter..." ) { - gather_scatter_ = new parallel::GatherScatter(); - gather_scatter_->setup( part.data(), remote_idx.data(), 0, global_idx.data(), size_owned_ ); + ATLAS_TRACE_MPI( WAIT ) { + for ( idx_t j = 0; j < nb_neighbours; ++j ) { + comm.wait( send_requests[j] ); + } + } } + } +} - ATLAS_TRACE_SCOPE( "Setup checksum..." ) { - checksum_ = new parallel::Checksum(); - checksum_->setup( part.data(), remote_idx.data(), 0, global_idx.data(), size_owned_ ); - } - ATLAS_TRACE_SCOPE( "Setup halo exchange..." ) { - halo_exchange_ = new parallel::HaloExchange(); - halo_exchange_->setup( part.data(), remote_idx.data(), 0, size_halo_ ); - } +void StructuredColumns::compute_xy( idx_t i, idx_t j, PointXY& xy ) const { + idx_t jj; + if ( j < 0 ) { + jj = -j - 1 + north_pole_included_; + xy.y() = 180. - grid_->y( jj ); + } + else if ( j >= ny_ ) { + jj = 2 * ny_ - j - 1 - south_pole_included_; + xy.y() = -180. - grid_->y( jj ); } + else { + jj = j; + xy.y() = grid_->y( jj ); + } + xy.x() = grid_->x( i, jj ); } + // ---------------------------------------------------------------------------- // ---------------------------------------------------------------------------- // Destructor // ---------------------------------------------------------------------------- -StructuredColumns::~StructuredColumns() {} -// ---------------------------------------------------------------------------- - -size_t StructuredColumns::footprint() const { - size_t size = sizeof( *this ); - // TODO - return size; +StructuredColumns::~StructuredColumns() { + delete grid_; } +// ---------------------------------------------------------------------------- // ---------------------------------------------------------------------------- // Create Field // ---------------------------------------------------------------------------- Field StructuredColumns::createField( const eckit::Configuration& options ) const { - size_t npts = config_size( options ); Field field( config_name( options ), config_datatype( options ), config_shape( options ) ); set_field_metadata( options, field ); return field; @@ -618,37 +949,37 @@ Field StructuredColumns::createField( const Field& other, const eckit::Configura // Gather FieldSet // ---------------------------------------------------------------------------- void StructuredColumns::gather( const FieldSet& local_fieldset, FieldSet& global_fieldset ) const { - ASSERT( local_fieldset.size() == global_fieldset.size() ); + ATLAS_ASSERT( local_fieldset.size() == global_fieldset.size() ); - for ( size_t f = 0; f < local_fieldset.size(); ++f ) { - const Field& loc = local_fieldset[f]; - Field& glb = global_fieldset[f]; - const size_t nb_fields = 1; - size_t root( 0 ); + for ( idx_t f = 0; f < local_fieldset.size(); ++f ) { + const Field& loc = local_fieldset[f]; + Field& glb = global_fieldset[f]; + const idx_t nb_fields = 1; + idx_t root( 0 ); glb.metadata().get( "owner", root ); if ( loc.datatype() == array::DataType::kind() ) { parallel::Field loc_field( make_leveled_view( loc ) ); parallel::Field glb_field( make_leveled_view( glb ) ); - gather_scatter_->gather( &loc_field, &glb_field, nb_fields, root ); + gather().gather( &loc_field, &glb_field, nb_fields, root ); } else if ( loc.datatype() == array::DataType::kind() ) { parallel::Field loc_field( make_leveled_view( loc ) ); parallel::Field glb_field( make_leveled_view( glb ) ); - gather_scatter_->gather( &loc_field, &glb_field, nb_fields, root ); + gather().gather( &loc_field, &glb_field, nb_fields, root ); } else if ( loc.datatype() == array::DataType::kind() ) { parallel::Field loc_field( make_leveled_view( loc ) ); parallel::Field glb_field( make_leveled_view( glb ) ); - gather_scatter_->gather( &loc_field, &glb_field, nb_fields, root ); + gather().gather( &loc_field, &glb_field, nb_fields, root ); } else if ( loc.datatype() == array::DataType::kind() ) { parallel::Field loc_field( make_leveled_view( loc ) ); parallel::Field glb_field( make_leveled_view( glb ) ); - gather_scatter_->gather( &loc_field, &glb_field, nb_fields, root ); + gather().gather( &loc_field, &glb_field, nb_fields, root ); } else - throw eckit::Exception( "datatype not supported", Here() ); + throw_Exception( "datatype not supported", Here() ); } } // ---------------------------------------------------------------------------- @@ -669,37 +1000,37 @@ void StructuredColumns::gather( const Field& local, Field& global ) const { // Scatter FieldSet // ---------------------------------------------------------------------------- void StructuredColumns::scatter( const FieldSet& global_fieldset, FieldSet& local_fieldset ) const { - ASSERT( local_fieldset.size() == global_fieldset.size() ); + ATLAS_ASSERT( local_fieldset.size() == global_fieldset.size() ); - for ( size_t f = 0; f < local_fieldset.size(); ++f ) { - const Field& glb = global_fieldset[f]; - Field& loc = local_fieldset[f]; - const size_t nb_fields = 1; - size_t root( 0 ); + for ( idx_t f = 0; f < local_fieldset.size(); ++f ) { + const Field& glb = global_fieldset[f]; + Field& loc = local_fieldset[f]; + const idx_t nb_fields = 1; + idx_t root( 0 ); glb.metadata().get( "owner", root ); if ( loc.datatype() == array::DataType::kind() ) { parallel::Field glb_field( make_leveled_view( glb ) ); parallel::Field loc_field( make_leveled_view( loc ) ); - gather_scatter_->scatter( &glb_field, &loc_field, nb_fields, root ); + scatter().scatter( &glb_field, &loc_field, nb_fields, root ); } else if ( loc.datatype() == array::DataType::kind() ) { parallel::Field glb_field( make_leveled_view( glb ) ); parallel::Field loc_field( make_leveled_view( loc ) ); - gather_scatter_->scatter( &glb_field, &loc_field, nb_fields, root ); + scatter().scatter( &glb_field, &loc_field, nb_fields, root ); } else if ( loc.datatype() == array::DataType::kind() ) { parallel::Field glb_field( make_leveled_view( glb ) ); parallel::Field loc_field( make_leveled_view( loc ) ); - gather_scatter_->scatter( &glb_field, &loc_field, nb_fields, root ); + scatter().scatter( &glb_field, &loc_field, nb_fields, root ); } else if ( loc.datatype() == array::DataType::kind() ) { parallel::Field glb_field( make_leveled_view( glb ) ); parallel::Field loc_field( make_leveled_view( loc ) ); - gather_scatter_->scatter( &glb_field, &loc_field, nb_fields, root ); + scatter().scatter( &glb_field, &loc_field, nb_fields, root ); } else - throw eckit::Exception( "datatype not supported", Here() ); + throw_Exception( "datatype not supported", Here() ); glb.metadata().broadcast( loc.metadata(), root ); loc.metadata().set( "global", false ); @@ -721,18 +1052,18 @@ void StructuredColumns::scatter( const Field& global, Field& local ) const { std::string StructuredColumns::checksum( const FieldSet& fieldset ) const { eckit::MD5 md5; - for ( size_t f = 0; f < fieldset.size(); ++f ) { + for ( idx_t f = 0; f < fieldset.size(); ++f ) { const Field& field = fieldset[f]; if ( field.datatype() == array::DataType::kind() ) - md5 << checksum_3d_field( *checksum_, field ); + md5 << checksum_3d_field( checksum(), field ); else if ( field.datatype() == array::DataType::kind() ) - md5 << checksum_3d_field( *checksum_, field ); + md5 << checksum_3d_field( checksum(), field ); else if ( field.datatype() == array::DataType::kind() ) - md5 << checksum_3d_field( *checksum_, field ); + md5 << checksum_3d_field( checksum(), field ); else if ( field.datatype() == array::DataType::kind() ) - md5 << checksum_3d_field( *checksum_, field ); + md5 << checksum_3d_field( checksum(), field ); else - throw eckit::Exception( "datatype not supported", Here() ); + throw_Exception( "datatype not supported", Here() ); } return md5; } @@ -742,54 +1073,151 @@ std::string StructuredColumns::checksum( const Field& field ) const { return checksum( fieldset ); } +const StructuredGrid& StructuredColumns::grid() const { + return *grid_; +} + namespace { + + template -void dispatch_haloExchange( Field& field, const parallel::HaloExchange& halo_exchange ) { +struct FixupHaloForVectors { + FixupHaloForVectors( const StructuredColumns& ) {} + template + void apply( Field& field ) { + std::string type = field.metadata().getString( "type", "scalar" ); + if ( type == "vector " ) { ATLAS_NOTIMPLEMENTED; } + } +}; + +template <> +struct FixupHaloForVectors<2> { + static constexpr int RANK = 2; + const StructuredColumns& fs; + FixupHaloForVectors( const StructuredColumns& _fs ) : fs( _fs ) {} + + template + void apply( Field& field ) { + std::string type = field.metadata().getString( "type", "scalar" ); + if ( type == "vector" ) { + auto array = array::make_view( field ); + for ( idx_t j = fs.j_begin_halo(); j < 0; ++j ) { + for ( idx_t i = fs.i_begin_halo( j ); i < fs.i_end_halo( j ); ++i ) { + idx_t n = fs.index( i, j ); + array( n, XX ) = -array( n, XX ); + array( n, YY ) = -array( n, YY ); + } + } + for ( idx_t j = fs.grid().ny(); j < fs.j_end_halo(); ++j ) { + for ( idx_t i = fs.i_begin_halo( j ); i < fs.i_end_halo( j ); ++i ) { + idx_t n = fs.index( i, j ); + array( n, XX ) = -array( n, XX ); + array( n, YY ) = -array( n, YY ); + } + } + } + } +}; + +template <> +struct FixupHaloForVectors<3> { + static constexpr int RANK = 3; + const StructuredColumns& fs; + FixupHaloForVectors( const StructuredColumns& _fs ) : fs( _fs ) {} + + template + void apply( Field& field ) { + std::string type = field.metadata().getString( "type", "scalar" ); + if ( type == "vector" ) { + auto array = array::make_view( field ); + for ( idx_t j = fs.j_begin_halo(); j < 0; ++j ) { + for ( idx_t i = fs.i_begin_halo( j ); i < fs.i_end_halo( j ); ++i ) { + idx_t n = fs.index( i, j ); + for ( idx_t k = fs.k_begin(); k < fs.k_end(); ++k ) { + array( n, k, XX ) = -array( n, k, XX ); + array( n, k, YY ) = -array( n, k, YY ); + } + } + } + for ( idx_t j = fs.grid().ny(); j < fs.j_end_halo(); ++j ) { + for ( idx_t i = fs.i_begin_halo( j ); i < fs.i_end_halo( j ); ++i ) { + idx_t n = fs.index( i, j ); + for ( idx_t k = fs.k_begin(); k < fs.k_end(); ++k ) { + array( n, k, XX ) = -array( n, k, XX ); + array( n, k, YY ) = -array( n, k, YY ); + } + } + } + } + } +}; + + +template +void dispatch_haloExchange( Field& field, const parallel::HaloExchange& halo_exchange, const StructuredColumns& fs ) { + FixupHaloForVectors fixup_halos( fs ); if ( field.datatype() == array::DataType::kind() ) { halo_exchange.template execute( field.array(), false ); + fixup_halos.template apply( field ); } else if ( field.datatype() == array::DataType::kind() ) { halo_exchange.template execute( field.array(), false ); + fixup_halos.template apply( field ); } else if ( field.datatype() == array::DataType::kind() ) { halo_exchange.template execute( field.array(), false ); + fixup_halos.template apply( field ); } else if ( field.datatype() == array::DataType::kind() ) { halo_exchange.template execute( field.array(), false ); + fixup_halos.template apply( field ); } else - throw eckit::Exception( "datatype not supported", Here() ); + throw_Exception( "datatype not supported", Here() ); + field.set_dirty( false ); } } // namespace -void StructuredColumns::haloExchange( FieldSet& fieldset ) const { - for ( size_t f = 0; f < fieldset.size(); ++f ) { - Field& field = fieldset[f]; +void StructuredColumns::haloExchange( const FieldSet& fieldset, bool ) const { + for ( idx_t f = 0; f < fieldset.size(); ++f ) { + Field& field = const_cast( fieldset )[f]; switch ( field.rank() ) { case 1: - dispatch_haloExchange<1>( field, *halo_exchange_ ); + dispatch_haloExchange<1>( field, halo_exchange(), *this ); break; case 2: - dispatch_haloExchange<2>( field, *halo_exchange_ ); + dispatch_haloExchange<2>( field, halo_exchange(), *this ); break; case 3: - dispatch_haloExchange<3>( field, *halo_exchange_ ); + dispatch_haloExchange<3>( field, halo_exchange(), *this ); break; case 4: - dispatch_haloExchange<4>( field, *halo_exchange_ ); + dispatch_haloExchange<4>( field, halo_exchange(), *this ); break; default: - throw eckit::Exception( "Rank not supported", Here() ); + throw_Exception( "Rank not supported", Here() ); } } } -void StructuredColumns::haloExchange( Field& field ) const { +void StructuredColumns::haloExchange( const Field& field, bool ) const { FieldSet fieldset; fieldset.add( field ); haloExchange( fieldset ); } +size_t StructuredColumns::footprint() const { + size_t size = sizeof( *this ); + size += ij2gp_.footprint(); + if ( field_xy_ ) size += field_xy_.footprint(); + if ( field_partition_ ) size += field_partition_.footprint(); + if ( field_global_index_ ) size += field_global_index_.footprint(); + if ( field_remote_index_ ) size += field_remote_index_.footprint(); + if ( field_index_i_ ) size += field_index_i_.footprint(); + if ( field_index_j_ ) size += field_index_j_.footprint(); + return size; +} + } // namespace detail // ---------------------------------------------------------------------------- @@ -809,6 +1237,15 @@ StructuredColumns::StructuredColumns( const Grid& grid, const grid::Partitioner& FunctionSpace( new detail::StructuredColumns( grid, partitioner, config ) ), functionspace_( dynamic_cast( get() ) ) {} +StructuredColumns::StructuredColumns( const Grid& grid, const Vertical& vertical, const eckit::Configuration& config ) : + FunctionSpace( new detail::StructuredColumns( grid, vertical, config ) ), + functionspace_( dynamic_cast( get() ) ) {} + +StructuredColumns::StructuredColumns( const Grid& grid, const Vertical& vertical, const grid::Partitioner& partitioner, + const eckit::Configuration& config ) : + FunctionSpace( new detail::StructuredColumns( grid, vertical, partitioner, config ) ), + functionspace_( dynamic_cast( get() ) ) {} + void StructuredColumns::gather( const FieldSet& local, FieldSet& global ) const { functionspace_->gather( local, global ); } @@ -825,14 +1262,6 @@ void StructuredColumns::scatter( const Field& global, Field& local ) const { functionspace_->scatter( global, local ); } -void StructuredColumns::haloExchange( FieldSet& fields ) const { - functionspace_->haloExchange( fields ); -} - -void StructuredColumns::haloExchange( Field& field ) const { - functionspace_->haloExchange( field ); -} - std::string StructuredColumns::checksum( const FieldSet& fieldset ) const { return functionspace_->checksum( fieldset ); } @@ -841,124 +1270,6 @@ std::string StructuredColumns::checksum( const Field& field ) const { return functionspace_->checksum( field ); } -// ---------------------------------------------------------------------------- -// Fortran interfaces -// ---------------------------------------------------------------------------- -extern "C" { - -const detail::StructuredColumns* atlas__functionspace__StructuredColumns__new__grid( - const Grid::Implementation* grid, const eckit::Configuration* config ) { - ATLAS_ERROR_HANDLING( return new detail::StructuredColumns( Grid( grid ), grid::Partitioner(), *config ); ); - return 0; -} - -void atlas__functionspace__StructuredColumns__delete( detail::StructuredColumns* This ) { - ATLAS_ERROR_HANDLING( ASSERT( This ); delete This; ); -} - -field::FieldImpl* atlas__fs__StructuredColumns__create_field( const detail::StructuredColumns* This, - const eckit::Configuration* options ) { - ATLAS_ERROR_HANDLING( ASSERT( This ); field::FieldImpl * field; { - Field f = This->createField( *options ); - field = f.get(); - field->attach(); - } field->detach(); - return field; ); - return 0; -} - -void atlas__functionspace__StructuredColumns__gather( const detail::StructuredColumns* This, - const field::FieldImpl* local, field::FieldImpl* global ) { - ATLAS_ERROR_HANDLING( ASSERT( This ); ASSERT( global ); ASSERT( local ); const Field l( local ); Field g( global ); - This->gather( l, g ); ); -} - -void atlas__functionspace__StructuredColumns__scatter( const detail::StructuredColumns* This, - const field::FieldImpl* global, field::FieldImpl* local ) { - ATLAS_ERROR_HANDLING( ASSERT( This ); ASSERT( global ); ASSERT( local ); const Field g( global ); Field l( local ); - This->scatter( g, l ); ); -} - -void atlas__fs__StructuredColumns__halo_exchange_field( const detail::StructuredColumns* This, - const field::FieldImpl* field ) { - ATLAS_ERROR_HANDLING( ASSERT( This ); ASSERT( field ); Field f( field ); This->haloExchange( f ); ); -} - -void atlas__fs__StructuredColumns__halo_exchange_fieldset( const detail::StructuredColumns* This, - const field::FieldSetImpl* fieldset ) { - ATLAS_ERROR_HANDLING( ASSERT( This ); ASSERT( fieldset ); FieldSet f( fieldset ); This->haloExchange( f ); ); -} - -void atlas__fs__StructuredColumns__checksum_fieldset( const detail::StructuredColumns* This, - const field::FieldSetImpl* fieldset, char*& checksum, int& size, - int& allocated ) { - ASSERT( This ); - ASSERT( fieldset ); - ATLAS_ERROR_HANDLING( std::string checksum_str( This->checksum( fieldset ) ); size = checksum_str.size(); - checksum = new char[size + 1]; allocated = true; strcpy( checksum, checksum_str.c_str() ); ); -} - -void atlas__fs__StructuredColumns__checksum_field( const detail::StructuredColumns* This, const field::FieldImpl* field, - char*& checksum, int& size, int& allocated ) { - ASSERT( This ); - ASSERT( field ); - ATLAS_ERROR_HANDLING( std::string checksum_str( This->checksum( field ) ); size = checksum_str.size(); - checksum = new char[size + 1]; allocated = true; strcpy( checksum, checksum_str.c_str() ); ); -} - -void atlas__fs__StructuredColumns__index_host( const detail::StructuredColumns* This, int*& data, int& i_min, - int& i_max, int& j_min, int& j_max ) { - ASSERT( This ); - ATLAS_ERROR_HANDLING( data = const_cast( This )->ij2gp_.data_.data(); - i_min = This->ij2gp_.i_min_ + 1; i_max = This->ij2gp_.i_max_ + 1; - j_min = This->ij2gp_.j_min_ + 1; j_max = This->ij2gp_.j_max_ + 1; ); -} - -int atlas__fs__StructuredColumns__j_begin( const detail::StructuredColumns* This ) { - return This->j_begin() + 1; -} -int atlas__fs__StructuredColumns__j_end( const detail::StructuredColumns* This ) { - return This->j_end(); -} -int atlas__fs__StructuredColumns__i_begin( const detail::StructuredColumns* This, int j ) { - return This->i_begin( j - 1 ) + 1; -} -int atlas__fs__StructuredColumns__i_end( const detail::StructuredColumns* This, int j ) { - return This->i_end( j - 1 ); -} -int atlas__fs__StructuredColumns__j_begin_halo( const detail::StructuredColumns* This ) { - return This->j_begin_halo() + 1; -} -int atlas__fs__StructuredColumns__j_end_halo( const detail::StructuredColumns* This ) { - return This->j_end_halo(); -} -int atlas__fs__StructuredColumns__i_begin_halo( const detail::StructuredColumns* This, int j ) { - return This->i_begin_halo( j - 1 ) + 1; -} -int atlas__fs__StructuredColumns__i_end_halo( const detail::StructuredColumns* This, int j ) { - return This->i_end_halo( j - 1 ); -} - -field::FieldImpl* atlas__fs__StructuredColumns__xy( const detail::StructuredColumns* This ) { - return This->xy().get(); -} - -field::FieldImpl* atlas__fs__StructuredColumns__partition( const detail::StructuredColumns* This ) { - return This->partition().get(); -} - -field::FieldImpl* atlas__fs__StructuredColumns__global_index( const detail::StructuredColumns* This ) { - return This->global_index().get(); -} - -field::FieldImpl* atlas__fs__StructuredColumns__index_i( const detail::StructuredColumns* This ) { - return This->index_i().get(); -} - -field::FieldImpl* atlas__fs__StructuredColumns__index_j( const detail::StructuredColumns* This ) { - return This->index_j().get(); -} -} // ---------------------------------------------------------------------------- } // namespace functionspace diff --git a/src/atlas/functionspace/StructuredColumns.h b/src/atlas/functionspace/StructuredColumns.h index 9e4859bec..7dafebcec 100644 --- a/src/atlas/functionspace/StructuredColumns.h +++ b/src/atlas/functionspace/StructuredColumns.h @@ -7,7 +7,6 @@ * granted to it by virtue of its status as an intergovernmental organisation * nor does it submit to any jurisdiction. */ - #pragma once #include @@ -15,11 +14,17 @@ #include "atlas/array/DataType.h" #include "atlas/field/Field.h" #include "atlas/functionspace/FunctionSpace.h" -#include "atlas/grid/Grid.h" -#include "atlas/grid/Partitioner.h" +#include "atlas/functionspace/detail/FunctionSpaceImpl.h" +#include "atlas/grid/Vertical.h" #include "atlas/library/config.h" #include "atlas/option.h" #include "atlas/util/Config.h" +#include "atlas/util/ObjectHandle.h" +#include "atlas/util/Point.h" + +namespace eckit { +class Configuration; +} namespace atlas { namespace parallel { @@ -30,10 +35,17 @@ class Checksum; } // namespace atlas namespace atlas { +class Field; class FieldSet; -namespace field { -class FieldSetImpl; -} +class Grid; +class StructuredGrid; +} // namespace atlas + +namespace atlas { +namespace grid { +class Distribution; +class Partitioner; +} // namespace grid } // namespace atlas namespace atlas { @@ -48,16 +60,26 @@ class StructuredColumns : public FunctionSpaceImpl { StructuredColumns( const Grid&, const grid::Partitioner&, const eckit::Configuration& = util::NoConfig() ); - virtual ~StructuredColumns(); + StructuredColumns( const Grid&, const grid::Distribution&, const eckit::Configuration& = util::NoConfig() ); + + StructuredColumns( const Grid&, const grid::Distribution&, const Vertical&, + const eckit::Configuration& = util::NoConfig() ); + + StructuredColumns( const Grid&, const Vertical&, const eckit::Configuration& = util::NoConfig() ); + + StructuredColumns( const Grid&, const Vertical&, const grid::Partitioner&, + const eckit::Configuration& = util::NoConfig() ); + + virtual ~StructuredColumns() override; static std::string static_type() { return "StructuredColumns"; } - virtual std::string type() const { return static_type(); } - virtual std::string distribution() const; + virtual std::string type() const override { return static_type(); } + virtual std::string distribution() const override; /// @brief Create a Structured field - virtual Field createField( const eckit::Configuration& ) const; + virtual Field createField( const eckit::Configuration& ) const override; - virtual Field createField( const Field&, const eckit::Configuration& ) const; + virtual Field createField( const Field&, const eckit::Configuration& ) const override; void gather( const FieldSet&, FieldSet& ) const; void gather( const Field&, Field& ) const; @@ -65,17 +87,24 @@ class StructuredColumns : public FunctionSpaceImpl { void scatter( const FieldSet&, FieldSet& ) const; void scatter( const Field&, Field& ) const; - void haloExchange( FieldSet& ) const; - void haloExchange( Field& ) const; + virtual void haloExchange( const FieldSet&, bool on_device = false ) const override; + virtual void haloExchange( const Field&, bool on_device = false ) const override; + + idx_t sizeOwned() const { return size_owned_; } + idx_t sizeHalo() const { return size_halo_; } + virtual idx_t size() const override { return size_halo_; } + + idx_t levels() const { return nb_levels_; } - size_t sizeOwned() const { return size_owned_; } - size_t sizeHalo() const { return size_halo_; } - size_t size() const { return size_halo_; } + idx_t halo() const { return halo_; } std::string checksum( const FieldSet& ) const; std::string checksum( const Field& ) const; - const grid::StructuredGrid& grid() const { return grid_; } + + const Vertical& vertical() const { return vertical_; } + + const StructuredGrid& grid() const; idx_t i_begin( idx_t j ) const { return i_begin_[j]; } idx_t i_end( idx_t j ) const { return i_end_[j]; } @@ -89,40 +118,76 @@ class StructuredColumns : public FunctionSpaceImpl { idx_t j_begin_halo() const { return j_begin_halo_; } idx_t j_end_halo() const { return j_end_halo_; } - idx_t index( idx_t i, idx_t j ) const { return ij2gp_( i, j ); } + idx_t k_begin() const { return vertical_.k_begin(); } + idx_t k_end() const { return vertical_.k_end(); } + + idx_t index( idx_t i, idx_t j ) const { + check_bounds( i, j ); + return ij2gp_( i, j ); + } Field xy() const { return field_xy_; } Field partition() const { return field_partition_; } Field global_index() const { return field_global_index_; } - Field remote_index() const { return field_remote_index_; } + Field remote_index() const { + if ( not field_remote_index_ ) { create_remote_index(); } + return field_remote_index_; + } Field index_i() const { return field_index_i_; } Field index_j() const { return field_index_j_; } + void compute_xy( idx_t i, idx_t j, PointXY& xy ) const; + PointXY compute_xy( idx_t i, idx_t j ) const { + PointXY xy; + compute_xy( i, j, xy ); + return xy; + } + + virtual size_t footprint() const override; + + private: // methods - size_t config_size( const eckit::Configuration& config ) const; + idx_t config_size( const eckit::Configuration& config ) const; array::DataType config_datatype( const eckit::Configuration& ) const; std::string config_name( const eckit::Configuration& ) const; - size_t config_levels( const eckit::Configuration& ) const; + idx_t config_levels( const eckit::Configuration& ) const; array::ArrayShape config_shape( const eckit::Configuration& ) const; void set_field_metadata( const eckit::Configuration&, Field& ) const; - size_t footprint() const; + + void check_bounds( idx_t i, idx_t j ) const { +#if ATLAS_ARRAYVIEW_BOUNDS_CHECKING + if ( j < j_begin_halo() || j >= j_end_halo() ) { throw_outofbounds( i, j ); } + if ( i < i_begin_halo( j ) || i >= i_end_halo( j ) ) { throw_outofbounds( i, j ); } +#endif + } + [[noreturn]] void throw_outofbounds( idx_t i, idx_t j ) const; + + const parallel::GatherScatter& gather() const; + const parallel::GatherScatter& scatter() const; + const parallel::Checksum& checksum() const; + const parallel::HaloExchange& halo_exchange() const; + + void create_remote_index() const; private: // data std::string distribution_; - size_t size_owned_; - size_t size_halo_; - size_t nb_levels_; + const Vertical vertical_; + idx_t nb_levels_; + + idx_t size_owned_; + idx_t size_halo_; + idx_t halo_; - const grid::StructuredGrid grid_; - parallel::GatherScatter* gather_scatter_; - parallel::HaloExchange* halo_exchange_; - parallel::Checksum* checksum_; + const StructuredGrid* grid_; + mutable util::ObjectHandle gather_scatter_; + mutable util::ObjectHandle checksum_; + mutable util::ObjectHandle halo_exchange_; Field field_xy_; Field field_partition_; Field field_global_index_; - Field field_remote_index_; + mutable Field field_remote_index_; Field field_index_i_; Field field_index_j_; @@ -152,7 +217,9 @@ class StructuredColumns : public FunctionSpaceImpl { void set( idx_t i, idx_t j, idx_t n ) { data_[( i - i_min_ ) + ( j - j_min_ ) * j_stride_] = n + 1; } - idx_t missing() const { return std::numeric_limits::max() - 1; } + static idx_t missing() { return std::numeric_limits::max() - 1; } + + size_t footprint() const; private: void print( std::ostream& ) const; @@ -183,7 +250,7 @@ class StructuredColumns : public FunctionSpaceImpl { idx_t missing() const { return std::numeric_limits::max() - 1; } - size_t size() const { return data_.size(); } + idx_t size() const { return idx_t( data_.size() ); } void resize( idx_t min, idx_t max ) { min_ = min; @@ -209,8 +276,14 @@ class StructuredColumns : public FunctionSpaceImpl { IndexRange i_begin_halo_; IndexRange i_end_halo_; -public: + idx_t north_pole_included_; + idx_t south_pole_included_; + idx_t ny_; + + friend struct StructuredColumnsFortranAccess; Map2to1 ij2gp_; + + void setup( const grid::Distribution& distribution, const eckit::Configuration& config ); }; // ------------------------------------------------------------------- @@ -225,17 +298,26 @@ class StructuredColumns : public FunctionSpace { StructuredColumns( const FunctionSpace& ); StructuredColumns( const Grid&, const eckit::Configuration& = util::NoConfig() ); StructuredColumns( const Grid&, const grid::Partitioner&, const eckit::Configuration& = util::NoConfig() ); + StructuredColumns( const Grid&, const Vertical&, const eckit::Configuration& = util::NoConfig() ); + StructuredColumns( const Grid&, const Vertical&, const grid::Partitioner&, + const eckit::Configuration& = util::NoConfig() ); static std::string type() { return detail::StructuredColumns::static_type(); } operator bool() const { return valid(); } bool valid() const { return functionspace_; } - size_t size() const { return functionspace_->size(); } - size_t sizeOwned() const { return functionspace_->sizeOwned(); } - size_t sizeHalo() const { return functionspace_->sizeHalo(); } + idx_t size() const { return functionspace_->size(); } + idx_t sizeOwned() const { return functionspace_->sizeOwned(); } + idx_t sizeHalo() const { return functionspace_->sizeHalo(); } + + idx_t levels() const { return functionspace_->levels(); } + + idx_t halo() const { return functionspace_->halo(); } - const grid::StructuredGrid& grid() const { return functionspace_->grid(); } + const Vertical& vertical() const { return functionspace_->vertical(); } + + const StructuredGrid& grid() const { return functionspace_->grid(); } void gather( const FieldSet&, FieldSet& ) const; void gather( const Field&, Field& ) const; @@ -243,9 +325,6 @@ class StructuredColumns : public FunctionSpace { void scatter( const FieldSet&, FieldSet& ) const; void scatter( const Field&, Field& ) const; - void haloExchange( FieldSet& ) const; - void haloExchange( Field& ) const; - std::string checksum( const FieldSet& ) const; std::string checksum( const Field& ) const; @@ -263,53 +342,68 @@ class StructuredColumns : public FunctionSpace { idx_t j_begin_halo() const { return functionspace_->j_begin_halo(); } idx_t j_end_halo() const { return functionspace_->j_end_halo(); } + idx_t k_begin() const { return functionspace_->k_begin(); } + idx_t k_end() const { return functionspace_->k_end(); } + Field xy() const { return functionspace_->xy(); } Field partition() const { return functionspace_->partition(); } Field global_index() const { return functionspace_->global_index(); } Field remote_index() const { return functionspace_->remote_index(); } + Field index_i() const { return functionspace_->index_i(); } + Field index_j() const { return functionspace_->index_j(); } + + void compute_xy( idx_t i, idx_t j, PointXY& xy ) const { return functionspace_->compute_xy( i, j, xy ); } + PointXY compute_xy( idx_t i, idx_t j ) const { return functionspace_->compute_xy( i, j ); } + + size_t footprint() const { return functionspace_->footprint(); } + + class For { + public: + For( const StructuredColumns& fs ) : fs_( fs ) {} + + protected: + const StructuredColumns& fs_; + }; + + class For_ij : public For { + public: + using For::For; + + template + void operator()( const Functor& f ) const { + for ( auto j = fs_.j_begin(); j < fs_.j_end(); ++j ) { + for ( auto i = fs_.i_begin( j ); i < fs_.i_end( j ); ++i ) { + f( i, j ); + } + } + } + }; + + class For_n : public For { + public: + using For::For; + + template + void operator()( const Functor& f ) const { + const auto size = fs_.sizeOwned(); + for ( auto n = 0 * size; n < size; ++n ) { + f( n ); + } + } + }; + + For_ij for_ij() const { return For_ij( *this ); } + + For_n for_n() const { return For_n( *this ); } private: const detail::StructuredColumns* functionspace_; + void setup( const Grid& grid, const Vertical& vertical, const grid::Distribution& distribution, + const eckit::Configuration& config ); }; // ------------------------------------------------------------------- -// C wrapper interfaces to C++ routines -extern "C" { -const detail::StructuredColumns* atlas__functionspace__StructuredColumns__new__grid( - const Grid::Implementation* grid, const eckit::Configuration* config ); -void atlas__functionspace__StructuredColumns__delete( detail::StructuredColumns* This ); -field::FieldImpl* atlas__fs__StructuredColumns__create_field( const detail::StructuredColumns* This, - const eckit::Configuration* options ); -void atlas__functionspace__StructuredColumns__gather( const detail::StructuredColumns* This, - const field::FieldImpl* local, field::FieldImpl* global ); -void atlas__functionspace__StructuredColumns__scatter( const detail::StructuredColumns* This, - const field::FieldImpl* global, field::FieldImpl* local ); -void atlas__fs__StructuredColumns__checksum_fieldset( const detail::StructuredColumns* This, - const field::FieldSetImpl* fieldset, char*& checksum, int& size, - int& allocated ); -void atlas__fs__StructuredColumns__checksum_field( const detail::StructuredColumns* This, const field::FieldImpl* field, - char*& checksum, int& size, int& allocated ); -void atlas__fs__StructuredColumns__halo_exchange_field( const detail::StructuredColumns* This, - const field::FieldImpl* field ); -void atlas__fs__StructuredColumns__halo_exchange_fieldset( const detail::StructuredColumns* This, - const field::FieldSetImpl* fieldset ); -void atlas__fs__StructuredColumns__index_host( const detail::StructuredColumns* This, int*& data, int& i_min, - int& i_max, int& j_min, int& j_max ); -int atlas__fs__StructuredColumns__j_begin( const detail::StructuredColumns* This ); -int atlas__fs__StructuredColumns__j_end( const detail::StructuredColumns* This ); -int atlas__fs__StructuredColumns__i_begin( const detail::StructuredColumns* This, int j ); -int atlas__fs__StructuredColumns__i_end( const detail::StructuredColumns* This, int j ); -int atlas__fs__StructuredColumns__j_begin_halo( const detail::StructuredColumns* This ); -int atlas__fs__StructuredColumns__j_end_halo( const detail::StructuredColumns* This ); -int atlas__fs__StructuredColumns__i_begin_halo( const detail::StructuredColumns* This, int j ); -int atlas__fs__StructuredColumns__i_end_halo( const detail::StructuredColumns* This, int j ); - -field::FieldImpl* atlas__fs__StructuredColumns__xy( const detail::StructuredColumns* This ); -field::FieldImpl* atlas__fs__StructuredColumns__partition( const detail::StructuredColumns* This ); -field::FieldImpl* atlas__fs__StructuredColumns__global_index( const detail::StructuredColumns* This ); -field::FieldImpl* atlas__fs__StructuredColumns__index_i( const detail::StructuredColumns* This ); -field::FieldImpl* atlas__fs__StructuredColumns__index_j( const detail::StructuredColumns* This ); -} + } // namespace functionspace } // namespace atlas diff --git a/src/atlas/functionspace/detail/FunctionSpaceImpl.cc b/src/atlas/functionspace/detail/FunctionSpaceImpl.cc new file mode 100644 index 000000000..f76375571 --- /dev/null +++ b/src/atlas/functionspace/detail/FunctionSpaceImpl.cc @@ -0,0 +1,76 @@ +/* + * (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 "FunctionSpaceImpl.h" +#include "atlas/field/Field.h" +#include "atlas/option/Options.h" +#include "atlas/runtime/Exception.h" +#include "atlas/util/Metadata.h" + +namespace atlas { +namespace functionspace { + +// ------------------------------------------------------------------ + +FunctionSpaceImpl::FunctionSpaceImpl() : metadata_( new util::Metadata() ) {} + +FunctionSpaceImpl::~FunctionSpaceImpl() { + delete metadata_; +} + +atlas::Field FunctionSpaceImpl::createField( const atlas::Field& field ) const { + return createField( field, util::NoConfig() ); +} + +void FunctionSpaceImpl::haloExchange( const FieldSet&, bool ) const { + ATLAS_NOTIMPLEMENTED; +} + +void FunctionSpaceImpl::haloExchange( const Field&, bool ) const { + ATLAS_NOTIMPLEMENTED; +} + +Field NoFunctionSpace::createField( const eckit::Configuration& ) const { + ATLAS_NOTIMPLEMENTED; +} + +Field NoFunctionSpace::createField( const Field&, const eckit::Configuration& ) const { + ATLAS_NOTIMPLEMENTED; +} + +template +Field FunctionSpaceImpl::createField( const eckit::Configuration& options ) const { + return createField( option::datatypeT() | options ); +} + +template +Field FunctionSpaceImpl::createField() const { + return createField( option::datatypeT() ); +} + +template Field FunctionSpaceImpl::createField() const; +template Field FunctionSpaceImpl::createField() const; +template Field FunctionSpaceImpl::createField() const; +template Field FunctionSpaceImpl::createField() const; + + +template Field FunctionSpaceImpl::createField( const eckit::Configuration& ) const; +template Field FunctionSpaceImpl::createField( const eckit::Configuration& ) const; +template Field FunctionSpaceImpl::createField( const eckit::Configuration& ) const; +template Field FunctionSpaceImpl::createField( const eckit::Configuration& ) const; + + +// ------------------------------------------------------------------ + +} // namespace functionspace + +// ------------------------------------------------------------------ + +} // namespace atlas diff --git a/src/atlas/functionspace/detail/FunctionSpaceImpl.h b/src/atlas/functionspace/detail/FunctionSpaceImpl.h new file mode 100644 index 000000000..710675341 --- /dev/null +++ b/src/atlas/functionspace/detail/FunctionSpaceImpl.h @@ -0,0 +1,134 @@ +/* + * (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 + +#include "atlas/util/Object.h" + +#include "atlas/library/config.h" + +namespace eckit { +class Configuration; +} + +namespace atlas { +class FieldSet; +class Field; +namespace util { +class Metadata; +} +} // namespace atlas + +namespace atlas { +namespace functionspace { + +#define FunctionspaceT_nonconst typename FunctionSpaceImpl::remove_const::type +#define FunctionspaceT_const typename FunctionSpaceImpl::add_const::type + +/// @brief FunctionSpace class helps to interprete Fields. +/// @note Abstract base class +class FunctionSpaceImpl : public util::Object { +private: + template + struct remove_const { + typedef T type; + }; + template + struct remove_const { + typedef T type; + }; + + template + struct add_const { + typedef const typename remove_const::type type; + }; + template + struct add_const { + typedef const T type; + }; + +public: + FunctionSpaceImpl(); + virtual ~FunctionSpaceImpl(); + virtual std::string type() const = 0; + virtual operator bool() const { return true; } + virtual size_t footprint() const = 0; + + virtual atlas::Field createField( const eckit::Configuration& ) const = 0; + + virtual atlas::Field createField( const atlas::Field&, const eckit::Configuration& ) const = 0; + + atlas::Field createField( const atlas::Field& ) const; + + template + atlas::Field createField( const eckit::Configuration& ) const; + + template + atlas::Field createField() const; + + const util::Metadata& metadata() const { return *metadata_; } + util::Metadata& metadata() { return *metadata_; } + + template + FunctionspaceT_nonconst* cast(); + + template + FunctionspaceT_const* cast() const; + + virtual std::string distribution() const = 0; + + virtual void haloExchange( const FieldSet&, bool /*on_device*/ = false ) const; + virtual void haloExchange( const Field&, bool /* on_device*/ = false ) const; + + virtual idx_t size() const = 0; + +private: + util::Metadata* metadata_; +}; + +template +inline FunctionspaceT_nonconst* FunctionSpaceImpl::cast() { + return dynamic_cast( this ); +} + +template +inline FunctionspaceT_const* FunctionSpaceImpl::cast() const { + return dynamic_cast( this ); +} + +#undef FunctionspaceT_const +#undef FunctionspaceT_nonconst + +//------------------------------------------------------------------------------------------------------ + +/// @brief Dummy Functionspace class that evaluates to false +class NoFunctionSpace : public FunctionSpaceImpl { +public: + NoFunctionSpace() {} + virtual ~NoFunctionSpace() {} + virtual std::string type() const { return "NoFunctionSpace"; } + virtual operator bool() const { return false; } + virtual size_t footprint() const { return sizeof( *this ); } + virtual std::string distribution() const { return std::string(); } + + virtual Field createField( const eckit::Configuration& ) const; + virtual Field createField( const Field&, const eckit::Configuration& ) const; + virtual idx_t size() const { return 0; } +}; + +//------------------------------------------------------------------------------------------------------ + +} // namespace functionspace + +//------------------------------------------------------------------------------------------------------ + +} // namespace atlas diff --git a/src/atlas/functionspace/detail/FunctionSpaceInterface.cc b/src/atlas/functionspace/detail/FunctionSpaceInterface.cc new file mode 100644 index 000000000..10c03dfa4 --- /dev/null +++ b/src/atlas/functionspace/detail/FunctionSpaceInterface.cc @@ -0,0 +1,101 @@ +/* + * (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 "FunctionSpaceImpl.h" +#include "FunctionSpaceInterface.h" + +#include "atlas/field/Field.h" +#include "atlas/field/FieldSet.h" +#include "atlas/field/detail/FieldImpl.h" +#include "atlas/library/config.h" +#include "atlas/runtime/Exception.h" +#include "atlas/util/Config.h" + +namespace atlas { +namespace functionspace { + +//----------------------------------------------------------------------------- + +// C wrapper interfaces to C++ routines +extern "C" { +void atlas__FunctionSpace__delete( FunctionSpaceImpl* This ) { + ATLAS_ASSERT( This != nullptr, "Cannot access uninitialised atlas_FunctionSpace" ); + delete This; + This = nullptr; +} + +void atlas__FunctionSpace__name( const FunctionSpaceImpl* This, char*& name, int& size ) { + ATLAS_ASSERT( This != nullptr, "Cannot access uninitialised atlas_FunctionSpace" ); + std::string s = This->type(); + size = static_cast( s.size() + 1 ); + name = new char[size]; + strcpy( name, s.c_str() ); +} + +field::FieldImpl* atlas__FunctionSpace__create_field( const FunctionSpaceImpl* This, + const eckit::Configuration* options ) { + ATLAS_ASSERT( This != nullptr, "Cannot access uninitialised atlas_FunctionSpace" ); + ATLAS_ASSERT( options != nullptr ); + field::FieldImpl* field; + { + Field f = This->createField( *options ); + field = f.get(); + field->attach(); + } + field->detach(); + return field; +} + +//------------------------------------------------------------------------------ + +field::FieldImpl* atlas__FunctionSpace__create_field_template( const FunctionSpaceImpl* This, + const field::FieldImpl* field_template, + const eckit::Configuration* options ) { + ATLAS_ASSERT( This != nullptr, "Cannot access uninitialised atlas_FunctionSpace" ); + ATLAS_ASSERT( field_template != nullptr, "Cannot access uninitialised atlas_Field" ); + ATLAS_ASSERT( options != nullptr ); + field::FieldImpl* field; + { + Field f = This->createField( Field( field_template ), *options ); + field = f.get(); + field->attach(); + } + field->detach(); + return field; +} + +//------------------------------------------------------------------------------ + +void atlas__FunctionSpace__halo_exchange_field( const FunctionSpaceImpl* This, field::FieldImpl* field ) { + ATLAS_ASSERT( This != nullptr, "Cannot access uninitialised atlas_FunctionSpace" ); + ATLAS_ASSERT( field != nullptr, "Cannot access uninitialised atlas_Field" ); + Field f( field ); + This->haloExchange( f ); +} + +//------------------------------------------------------------------------------ + +void atlas__FunctionSpace__halo_exchange_fieldset( const FunctionSpaceImpl* This, field::FieldSetImpl* fieldset ) { + ATLAS_ASSERT( This != nullptr, "Cannot access uninitialised atlas_FunctionSpace" ); + ATLAS_ASSERT( fieldset != nullptr, "Cannot access uninitialised atlas_FieldSet" ); + FieldSet f( fieldset ); + This->haloExchange( f ); +} +} + +// ------------------------------------------------------------------ + +} // namespace functionspace + +// ------------------------------------------------------------------ + +} // namespace atlas diff --git a/src/atlas/functionspace/detail/FunctionSpaceInterface.h b/src/atlas/functionspace/detail/FunctionSpaceInterface.h new file mode 100644 index 000000000..c31217792 --- /dev/null +++ b/src/atlas/functionspace/detail/FunctionSpaceInterface.h @@ -0,0 +1,50 @@ +/* + * (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 field { +class FieldImpl; +class FieldSetImpl; +} // namespace field +} // namespace atlas + +namespace atlas { +namespace functionspace { +class FunctionSpaceImpl; + +//------------------------------------------------------------------------------------------------------ + +// C wrapper interfaces to C++ routines +extern "C" { +void atlas__FunctionSpace__delete( FunctionSpaceImpl* This ); +void atlas__FunctionSpace__name( const FunctionSpaceImpl* This, char*& name, int& size ); +field::FieldImpl* atlas__FunctionSpace__create_field( const FunctionSpaceImpl* This, + const eckit::Configuration* options ); +field::FieldImpl* atlas__FunctionSpace__create_field_template( const FunctionSpaceImpl* This, + const field::FieldImpl* field_template, + const eckit::Configuration* options ); +void atlas__FunctionSpace__halo_exchange_field( const FunctionSpaceImpl* This, field::FieldImpl* field ); +void atlas__FunctionSpace__halo_exchange_fieldset( const FunctionSpaceImpl* This, field::FieldSetImpl* fieldset ); +} + +//------------------------------------------------------------------------------------------------------ + +} // namespace functionspace + +//------------------------------------------------------------------------------------------------------ + +} // namespace atlas diff --git a/src/atlas/functionspace/detail/NodeColumnsInterface.cc b/src/atlas/functionspace/detail/NodeColumnsInterface.cc new file mode 100644 index 000000000..906341fb3 --- /dev/null +++ b/src/atlas/functionspace/detail/NodeColumnsInterface.cc @@ -0,0 +1,1121 @@ +/* + * (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 "NodeColumnsInterface.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 NodeColumns* atlas__NodesFunctionSpace__new( Mesh::Implementation* mesh, const eckit::Configuration* config ) { + ATLAS_ASSERT( mesh ); + Mesh m( mesh ); + return new NodeColumns( m, *config ); +} + +void atlas__NodesFunctionSpace__delete( NodeColumns* This ) { + ATLAS_ASSERT( This != nullptr, "Cannot access uninitialised atlas_functionspace_NodeColumns" ); + delete ( This ); +} + +int atlas__NodesFunctionSpace__nb_nodes( const NodeColumns* This ) { + ATLAS_ASSERT( This != nullptr, "Cannot access uninitialised atlas_functionspace_NodeColumns" ); + return This->nb_nodes(); +} + +const Mesh::Implementation* atlas__NodesFunctionSpace__mesh( const NodeColumns* This ) { + ATLAS_ASSERT( This != nullptr, "Cannot access uninitialised atlas_functionspace_NodeColumns" ); + return This->mesh().get(); +} + +mesh::Nodes* atlas__NodesFunctionSpace__nodes( const NodeColumns* This ) { + ATLAS_ASSERT( This != nullptr, "Cannot access uninitialised atlas_functionspace_NodeColumns" ); + return &This->nodes(); +} + +void atlas__NodesFunctionSpace__halo_exchange_fieldset( const NodeColumns* This, field::FieldSetImpl* fieldset ) { + ATLAS_ASSERT( This != nullptr, "Cannot access uninitialised atlas_functionspace_NodeColumns" ); + ATLAS_ASSERT( fieldset != nullptr, "Cannot access uninitialised atlas_FieldSet" ); + FieldSet f( fieldset ); + This->haloExchange( f ); +} + +void atlas__NodesFunctionSpace__halo_exchange_field( const NodeColumns* This, field::FieldImpl* field ) { + ATLAS_ASSERT( This != nullptr, "Cannot access uninitialised atlas_functionspace_NodeColumns" ); + ATLAS_ASSERT( field != nullptr, "Cannot access uninitialised atlas_Field" ); + Field f( field ); + This->haloExchange( f ); +} + +const parallel::HaloExchange* atlas__NodesFunctionSpace__get_halo_exchange( const NodeColumns* This ) { + ATLAS_ASSERT( This != nullptr, "Cannot access uninitialised atlas_functionspace_NodeColumns" ); + return &This->halo_exchange(); +} + +void atlas__NodesFunctionSpace__gather_fieldset( const NodeColumns* This, const field::FieldSetImpl* local, + field::FieldSetImpl* global ) { + ATLAS_ASSERT( This != nullptr, "Cannot access uninitialised atlas_functionspace_NodeColumns" ); + 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__NodesFunctionSpace__gather_field( const NodeColumns* This, const field::FieldImpl* local, + field::FieldImpl* global ) { + ATLAS_ASSERT( This != nullptr, "Cannot access uninitialised atlas_functionspace_NodeColumns" ); + 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__NodesFunctionSpace__get_gather( const NodeColumns* This ) { + ATLAS_ASSERT( This != nullptr, "Cannot access uninitialised atlas_functionspace_NodeColumns" ); + return &This->gather(); +} + +const parallel::GatherScatter* atlas__NodesFunctionSpace__get_scatter( const NodeColumns* This ) { + ATLAS_ASSERT( This != nullptr, "Cannot access uninitialised atlas_functionspace_NodeColumns" ); + return &This->scatter(); +} + +void atlas__NodesFunctionSpace__scatter_fieldset( const NodeColumns* This, const field::FieldSetImpl* global, + field::FieldSetImpl* local ) { + ATLAS_ASSERT( This != nullptr, "Cannot access uninitialised atlas_functionspace_NodeColumns" ); + 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__NodesFunctionSpace__scatter_field( const NodeColumns* This, const field::FieldImpl* global, + field::FieldImpl* local ) { + ATLAS_ASSERT( This != nullptr, "Cannot access uninitialised atlas_functionspace_NodeColumns" ); + 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__NodesFunctionSpace__get_checksum( const NodeColumns* This ) { + ATLAS_ASSERT( This != nullptr, "Cannot access uninitialised atlas_functionspace_NodeColumns" ); + return &This->checksum(); +} + +void atlas__NodesFunctionSpace__checksum_fieldset( const NodeColumns* This, const field::FieldSetImpl* fieldset, + char*& checksum, int& size, int& allocated ) { + ATLAS_ASSERT( This != nullptr, "Cannot access uninitialised atlas_functionspace_NodeColumns" ); + ATLAS_ASSERT( fieldset != nullptr, "Cannot access uninitialised atlas_FieldSet" ); + std::string checksum_str( This->checksum( fieldset ) ); + size = checksum_str.size(); + checksum = new char[size + 1]; + allocated = true; + strcpy( checksum, checksum_str.c_str() ); +} + +void atlas__NodesFunctionSpace__checksum_field( const NodeColumns* This, const field::FieldImpl* field, char*& checksum, + int& size, int& allocated ) { + ATLAS_ASSERT( This != nullptr, "Cannot access uninitialised atlas_functionspace_NodeColumns" ); + ATLAS_ASSERT( field != nullptr, "Cannot access uninitialised atlas_Field" ); + std::string checksum_str( This->checksum( field ) ); + size = checksum_str.size(); + checksum = new char[size + 1]; + allocated = true; + strcpy( checksum, checksum_str.c_str() ); +} + +void atlas__NodesFunctionSpace__sum_double( const NodeColumns* This, const field::FieldImpl* field, double& sum, + int& N ) { + ATLAS_ASSERT( This != nullptr, "Cannot access uninitialised atlas_functionspace_NodeColumns" ); + ATLAS_ASSERT( field != nullptr, "Cannot access uninitialised atlas_Field" ); + idx_t idx_t_N; + This->sum( field, sum, idx_t_N ); + N = idx_t_N; +} + +void atlas__NodesFunctionSpace__sum_float( const NodeColumns* This, const field::FieldImpl* field, float& sum, + int& N ) { + ATLAS_ASSERT( This != nullptr, "Cannot access uninitialised atlas_functionspace_NodeColumns" ); + ATLAS_ASSERT( field != nullptr, "Cannot access uninitialised atlas_Field" ); + idx_t idx_t_N; + This->sum( field, sum, idx_t_N ); + N = idx_t_N; +} + +void atlas__NodesFunctionSpace__sum_long( const NodeColumns* This, const field::FieldImpl* field, long& sum, int& N ) { + ATLAS_ASSERT( This != nullptr, "Cannot access uninitialised atlas_functionspace_NodeColumns" ); + ATLAS_ASSERT( field != nullptr, "Cannot access uninitialised atlas_Field" ); + idx_t idx_t_N; + This->sum( field, sum, idx_t_N ); + N = idx_t_N; +} + +void atlas__NodesFunctionSpace__sum_int( const NodeColumns* This, const field::FieldImpl* field, int& sum, int& N ) { + ATLAS_ASSERT( This != nullptr, "Cannot access uninitialised atlas_functionspace_NodeColumns" ); + ATLAS_ASSERT( field != nullptr, "Cannot access uninitialised atlas_Field" ); + idx_t idx_t_N; + This->sum( field, sum, idx_t_N ); + N = idx_t_N; +} + +void atlas__NodesFunctionSpace__sum_arr_double( const NodeColumns* This, const field::FieldImpl* field, double*& sum, + int& size, int& N ) { + ATLAS_ASSERT( This != nullptr, "Cannot access uninitialised atlas_functionspace_NodeColumns" ); + ATLAS_ASSERT( field != nullptr, "Cannot access uninitialised atlas_Field" ); + idx_t idx_t_N; + std::vector sumvec; + This->orderIndependentSum( field, sumvec, idx_t_N ); + size = sumvec.size(); + sum = new double[size]; + for ( idx_t j = 0; j < (idx_t)size; ++j ) + sum[j] = sumvec[j]; + N = idx_t_N; +} + +void atlas__NodesFunctionSpace__sum_arr_float( const NodeColumns* This, const field::FieldImpl* field, float*& sum, + int& size, int& N ) { + ATLAS_ASSERT( This != nullptr, "Cannot access uninitialised atlas_functionspace_NodeColumns" ); + ATLAS_ASSERT( field != nullptr, "Cannot access uninitialised atlas_Field" ); + idx_t idx_t_N; + std::vector sumvec; + This->orderIndependentSum( field, sumvec, idx_t_N ); + size = sumvec.size(); + sum = new float[size]; + for ( idx_t j = 0; j < (idx_t)size; ++j ) + sum[j] = sumvec[j]; + N = idx_t_N; +} + +void atlas__NodesFunctionSpace__sum_arr_long( const NodeColumns* This, const field::FieldImpl* field, long*& sum, + int& size, int& N ) { + ATLAS_ASSERT( This != nullptr, "Cannot access uninitialised atlas_functionspace_NodeColumns" ); + ATLAS_ASSERT( field != nullptr, "Cannot access uninitialised atlas_Field" ); + idx_t idx_t_N; + std::vector sumvec; + This->orderIndependentSum( field, sumvec, idx_t_N ); + size = sumvec.size(); + sum = new long[size]; + for ( idx_t j = 0; j < (idx_t)size; ++j ) + sum[j] = sumvec[j]; + N = idx_t_N; +} + +void atlas__NodesFunctionSpace__sum_arr_int( const NodeColumns* This, const field::FieldImpl* field, int*& sum, + int& size, int& N ) { + ATLAS_ASSERT( This != nullptr, "Cannot access uninitialised atlas_functionspace_NodeColumns" ); + ATLAS_ASSERT( field != nullptr, "Cannot access uninitialised atlas_Field" ); + idx_t idx_t_N; + std::vector sumvec; + This->orderIndependentSum( field, sumvec, idx_t_N ); + size = sumvec.size(); + sum = new int[size]; + for ( idx_t j = 0; j < (idx_t)size; ++j ) + sum[j] = sumvec[j]; + N = idx_t_N; +} + +void atlas__NodesFunctionSpace__oisum_double( const NodeColumns* This, const field::FieldImpl* field, double& sum, + int& N ) { + ATLAS_ASSERT( This != nullptr, "Cannot access uninitialised atlas_functionspace_NodeColumns" ); + ATLAS_ASSERT( field != nullptr, "Cannot access uninitialised atlas_Field" ); + idx_t idx_t_N; + This->orderIndependentSum( field, sum, idx_t_N ); + N = idx_t_N; +} + +void atlas__NodesFunctionSpace__oisum_float( const NodeColumns* This, const field::FieldImpl* field, float& sum, + int& N ) { + ATLAS_ASSERT( This != nullptr, "Cannot access uninitialised atlas_functionspace_NodeColumns" ); + ATLAS_ASSERT( field != nullptr, "Cannot access uninitialised atlas_Field" ); + idx_t idx_t_N; + This->orderIndependentSum( field, sum, idx_t_N ); + N = idx_t_N; +} + +void atlas__NodesFunctionSpace__oisum_long( const NodeColumns* This, const field::FieldImpl* field, long& sum, + int& N ) { + atlas__NodesFunctionSpace__sum_long( This, field, sum, N ); +} + +void atlas__NodesFunctionSpace__oisum_int( const NodeColumns* This, const field::FieldImpl* field, int& sum, int& N ) { + atlas__NodesFunctionSpace__sum_int( This, field, sum, N ); +} + +void atlas__NodesFunctionSpace__oisum_arr_double( const NodeColumns* This, const field::FieldImpl* field, double*& sum, + int& size, int& N ) { + ATLAS_ASSERT( This != nullptr, "Cannot access uninitialised atlas_functionspace_NodeColumns" ); + ATLAS_ASSERT( field != nullptr, "Cannot access uninitialised atlas_Field" ); + idx_t idx_t_N; + std::vector sumvec; + This->orderIndependentSum( field, sumvec, idx_t_N ); + size = sumvec.size(); + sum = new double[size]; + for ( idx_t j = 0; j < (idx_t)size; ++j ) + sum[j] = sumvec[j]; + N = idx_t_N; +} + +void atlas__NodesFunctionSpace__oisum_arr_float( const NodeColumns* This, const field::FieldImpl* field, float*& sum, + int& size, int& N ) { + ATLAS_ASSERT( This != nullptr, "Cannot access uninitialised atlas_functionspace_NodeColumns" ); + ATLAS_ASSERT( field != nullptr, "Cannot access uninitialised atlas_Field" ); + idx_t idx_t_N; + std::vector sumvec; + This->orderIndependentSum( field, sumvec, idx_t_N ); + size = sumvec.size(); + sum = new float[size]; + for ( idx_t j = 0; j < (idx_t)size; ++j ) + sum[j] = sumvec[j]; + N = idx_t_N; +} + +void atlas__NodesFunctionSpace__oisum_arr_int( const NodeColumns* This, const field::FieldImpl* field, int*& sum, + int& size, int& N ) { + atlas__NodesFunctionSpace__sum_arr_int( This, field, sum, size, N ); +} + +void atlas__NodesFunctionSpace__oisum_arr_long( const NodeColumns* This, const field::FieldImpl* field, long*& sum, + int& size, int& N ) { + atlas__NodesFunctionSpace__sum_arr_long( This, field, sum, size, N ); +} + + +void atlas__NodesFunctionSpace__min_double( const NodeColumns* This, const field::FieldImpl* field, double& minimum ) { + ATLAS_ASSERT( This != nullptr, "Cannot access uninitialised atlas_functionspace_NodeColumns" ); + ATLAS_ASSERT( field != nullptr, "Cannot access uninitialised atlas_Field" ); + This->minimum( field, minimum ); +} + +void atlas__NodesFunctionSpace__min_float( const NodeColumns* This, const field::FieldImpl* field, float& minimum ) { + ATLAS_ASSERT( This != nullptr, "Cannot access uninitialised atlas_functionspace_NodeColumns" ); + ATLAS_ASSERT( field != nullptr, "Cannot access uninitialised atlas_Field" ); + This->minimum( field, minimum ); +} + +void atlas__NodesFunctionSpace__min_long( const NodeColumns* This, const field::FieldImpl* field, long& minimum ) { + ATLAS_ASSERT( This != nullptr, "Cannot access uninitialised atlas_functionspace_NodeColumns" ); + ATLAS_ASSERT( field != nullptr, "Cannot access uninitialised atlas_Field" ); + This->minimum( field, minimum ); +} + +void atlas__NodesFunctionSpace__min_int( const NodeColumns* This, const field::FieldImpl* field, int& minimum ) { + ATLAS_ASSERT( This != nullptr, "Cannot access uninitialised atlas_functionspace_NodeColumns" ); + ATLAS_ASSERT( field != nullptr, "Cannot access uninitialised atlas_Field" ); + This->minimum( field, minimum ); +} + +void atlas__NodesFunctionSpace__max_double( const NodeColumns* This, const field::FieldImpl* field, double& maximum ) { + ATLAS_ASSERT( This != nullptr, "Cannot access uninitialised atlas_functionspace_NodeColumns" ); + ATLAS_ASSERT( field != nullptr, "Cannot access uninitialised atlas_Field" ); + This->maximum( field, maximum ); +} + +void atlas__NodesFunctionSpace__max_float( const NodeColumns* This, const field::FieldImpl* field, float& maximum ) { + ATLAS_ASSERT( This != nullptr, "Cannot access uninitialised atlas_functionspace_NodeColumns" ); + ATLAS_ASSERT( field != nullptr, "Cannot access uninitialised atlas_Field" ); + This->maximum( field, maximum ); +} + +void atlas__NodesFunctionSpace__max_long( const NodeColumns* This, const field::FieldImpl* field, long& maximum ) { + ATLAS_ASSERT( This != nullptr, "Cannot access uninitialised atlas_functionspace_NodeColumns" ); + ATLAS_ASSERT( field != nullptr, "Cannot access uninitialised atlas_Field" ); + This->maximum( field, maximum ); +} + +void atlas__NodesFunctionSpace__max_int( const NodeColumns* This, const field::FieldImpl* field, int& maximum ) { + ATLAS_ASSERT( This != nullptr, "Cannot access uninitialised atlas_functionspace_NodeColumns" ); + ATLAS_ASSERT( field != nullptr, "Cannot access uninitialised atlas_Field" ); + This->maximum( field, maximum ); +} + +void atlas__NodesFunctionSpace__min_arr_double( const NodeColumns* This, const field::FieldImpl* field, + double*& minimum, int& size ) { + ATLAS_ASSERT( This != nullptr, "Cannot access uninitialised atlas_functionspace_NodeColumns" ); + ATLAS_ASSERT( field != nullptr, "Cannot access uninitialised atlas_Field" ); + std::vector minvec; + This->minimum( field, minvec ); + size = minvec.size(); + minimum = new double[size]; + for ( idx_t j = 0; j < (idx_t)size; ++j ) + minimum[j] = minvec[j]; +} + +void atlas__NodesFunctionSpace__min_arr_float( const NodeColumns* This, const field::FieldImpl* field, float*& minimum, + int& size ) { + ATLAS_ASSERT( This != nullptr, "Cannot access uninitialised atlas_functionspace_NodeColumns" ); + ATLAS_ASSERT( field != nullptr, "Cannot access uninitialised atlas_Field" ); + std::vector minvec; + This->minimum( field, minvec ); + size = minvec.size(); + minimum = new float[size]; + for ( idx_t j = 0; j < (idx_t)size; ++j ) + minimum[j] = minvec[j]; +} + +void atlas__NodesFunctionSpace__min_arr_long( const NodeColumns* This, const field::FieldImpl* field, long*& minimum, + int& size ) { + ATLAS_ASSERT( This != nullptr, "Cannot access uninitialised atlas_functionspace_NodeColumns" ); + ATLAS_ASSERT( field != nullptr, "Cannot access uninitialised atlas_Field" ); + std::vector minvec; + This->minimum( field, minvec ); + size = minvec.size(); + minimum = new long[size]; + for ( idx_t j = 0; j < (idx_t)size; ++j ) + minimum[j] = minvec[j]; + ; +} + +void atlas__NodesFunctionSpace__min_arr_int( const NodeColumns* This, const field::FieldImpl* field, int*& minimum, + int& size ) { + ATLAS_ASSERT( This != nullptr, "Cannot access uninitialised atlas_functionspace_NodeColumns" ); + ATLAS_ASSERT( field != nullptr, "Cannot access uninitialised atlas_Field" ); + std::vector minvec; + This->minimum( field, minvec ); + size = minvec.size(); + minimum = new int[size]; + for ( idx_t j = 0; j < (idx_t)size; ++j ) + minimum[j] = minvec[j]; +} + +void atlas__NodesFunctionSpace__max_arr_double( const NodeColumns* This, const field::FieldImpl* field, + double*& maximum, int& size ) { + ATLAS_ASSERT( This != nullptr, "Cannot access uninitialised atlas_functionspace_NodeColumns" ); + ATLAS_ASSERT( field != nullptr, "Cannot access uninitialised atlas_Field" ); + std::vector maxvec; + This->maximum( field, maxvec ); + size = maxvec.size(); + maximum = new double[size]; + for ( idx_t j = 0; j < (idx_t)size; ++j ) { + maximum[j] = maxvec[j]; + } +} + +void atlas__NodesFunctionSpace__max_arr_float( const NodeColumns* This, const field::FieldImpl* field, float*& maximum, + int& size ) { + ATLAS_ASSERT( This != nullptr, "Cannot access uninitialised atlas_functionspace_NodeColumns" ); + ATLAS_ASSERT( field != nullptr, "Cannot access uninitialised atlas_Field" ); + std::vector maxvec; + This->maximum( field, maxvec ); + size = maxvec.size(); + maximum = new float[size]; + for ( idx_t j = 0; j < (idx_t)size; ++j ) + maximum[j] = maxvec[j]; +} + +void atlas__NodesFunctionSpace__max_arr_long( const NodeColumns* This, const field::FieldImpl* field, long*& maximum, + int& size ) { + ATLAS_ASSERT( This != nullptr, "Cannot access uninitialised atlas_functionspace_NodeColumns" ); + ATLAS_ASSERT( field != nullptr, "Cannot access uninitialised atlas_Field" ); + std::vector maxvec; + This->maximum( field, maxvec ); + size = maxvec.size(); + maximum = new long[size]; + for ( idx_t j = 0; j < (idx_t)size; ++j ) + maximum[j] = maxvec[j]; +} + +void atlas__NodesFunctionSpace__max_arr_int( const NodeColumns* This, const field::FieldImpl* field, int*& maximum, + int& size ) { + ATLAS_ASSERT( This != nullptr, "Cannot access uninitialised atlas_functionspace_NodeColumns" ); + ATLAS_ASSERT( field != nullptr, "Cannot access uninitialised atlas_Field" ); + std::vector maxvec; + This->maximum( field, maxvec ); + size = maxvec.size(); + maximum = new int[size]; + for ( idx_t j = 0; j < (idx_t)size; ++j ) + maximum[j] = maxvec[j]; +} + +void atlas__NodesFunctionSpace__minloc_double( const NodeColumns* This, const field::FieldImpl* field, double& minimum, + long& glb_idx ) { + ATLAS_ASSERT( This != nullptr, "Cannot access uninitialised atlas_functionspace_NodeColumns" ); + ATLAS_ASSERT( field != nullptr, "Cannot access uninitialised atlas_Field" ); + gidx_t gidx; + This->minimumAndLocation( field, minimum, gidx ); + glb_idx = gidx; +} + +void atlas__NodesFunctionSpace__minloc_float( const NodeColumns* This, const field::FieldImpl* field, float& minimum, + long& glb_idx ) { + ATLAS_ASSERT( This != nullptr, "Cannot access uninitialised atlas_functionspace_NodeColumns" ); + ATLAS_ASSERT( field != nullptr, "Cannot access uninitialised atlas_Field" ); + gidx_t gidx; + This->minimumAndLocation( field, minimum, gidx ); + glb_idx = gidx; +} + +void atlas__NodesFunctionSpace__minloc_long( const NodeColumns* This, const field::FieldImpl* field, long& minimum, + long& glb_idx ) { + ATLAS_ASSERT( This != nullptr, "Cannot access uninitialised atlas_functionspace_NodeColumns" ); + ATLAS_ASSERT( field != nullptr, "Cannot access uninitialised atlas_Field" ); + gidx_t gidx; + This->minimumAndLocation( field, minimum, gidx ); + glb_idx = gidx; +} + +void atlas__NodesFunctionSpace__minloc_int( const NodeColumns* This, const field::FieldImpl* field, int& minimum, + long& glb_idx ) { + ATLAS_ASSERT( This != nullptr, "Cannot access uninitialised atlas_functionspace_NodeColumns" ); + ATLAS_ASSERT( field != nullptr, "Cannot access uninitialised atlas_Field" ); + gidx_t gidx; + This->minimumAndLocation( field, minimum, gidx ); + glb_idx = gidx; +} + +void atlas__NodesFunctionSpace__maxloc_double( const NodeColumns* This, const field::FieldImpl* field, double& maximum, + long& glb_idx ) { + ATLAS_ASSERT( This != nullptr, "Cannot access uninitialised atlas_functionspace_NodeColumns" ); + ATLAS_ASSERT( field != nullptr, "Cannot access uninitialised atlas_Field" ); + gidx_t gidx; + This->maximumAndLocation( field, maximum, gidx ); + glb_idx = gidx; +} + +void atlas__NodesFunctionSpace__maxloc_float( const NodeColumns* This, const field::FieldImpl* field, float& maximum, + long& glb_idx ) { + ATLAS_ASSERT( This != nullptr, "Cannot access uninitialised atlas_functionspace_NodeColumns" ); + ATLAS_ASSERT( field != nullptr, "Cannot access uninitialised atlas_Field" ); + gidx_t gidx; + This->maximumAndLocation( field, maximum, gidx ); + glb_idx = gidx; +} + +void atlas__NodesFunctionSpace__maxloc_long( const NodeColumns* This, const field::FieldImpl* field, long& maximum, + long& glb_idx ) { + ATLAS_ASSERT( This != nullptr, "Cannot access uninitialised atlas_functionspace_NodeColumns" ); + ATLAS_ASSERT( field != nullptr, "Cannot access uninitialised atlas_Field" ); + gidx_t gidx; + This->maximumAndLocation( field, maximum, gidx ); + glb_idx = gidx; +} + +void atlas__NodesFunctionSpace__maxloc_int( const NodeColumns* This, const field::FieldImpl* field, int& maximum, + long& glb_idx ) { + ATLAS_ASSERT( This != nullptr, "Cannot access uninitialised atlas_functionspace_NodeColumns" ); + ATLAS_ASSERT( field != nullptr, "Cannot access uninitialised atlas_Field" ); + gidx_t gidx; + This->maximumAndLocation( field, maximum, gidx ); + glb_idx = gidx; +} + +void atlas__NodesFunctionSpace__minloc_arr_double( const NodeColumns* This, const field::FieldImpl* field, + double*& minimum, long*& glb_idx, int& size ) { + ATLAS_ASSERT( This != nullptr, "Cannot access uninitialised atlas_functionspace_NodeColumns" ); + ATLAS_ASSERT( field != nullptr, "Cannot access uninitialised atlas_Field" ); + std::vector minvec; + std::vector gidxvec; + This->minimumAndLocation( field, minvec, gidxvec ); + size = minvec.size(); + minimum = new double[size]; + glb_idx = new long[size]; + for ( idx_t j = 0; j < (idx_t)size; ++j ) { + minimum[j] = minvec[j]; + glb_idx[j] = gidxvec[j]; + } +} + +void atlas__NodesFunctionSpace__minloc_arr_float( const NodeColumns* This, const field::FieldImpl* field, + float*& minimum, long*& glb_idx, int& size ) { + ATLAS_ASSERT( This != nullptr, "Cannot access uninitialised atlas_functionspace_NodeColumns" ); + ATLAS_ASSERT( field != nullptr, "Cannot access uninitialised atlas_Field" ); + std::vector minvec; + std::vector gidxvec; + This->minimumAndLocation( field, minvec, gidxvec ); + size = minvec.size(); + minimum = new float[size]; + glb_idx = new long[size]; + for ( idx_t j = 0; j < (idx_t)size; ++j ) { + minimum[j] = minvec[j]; + glb_idx[j] = gidxvec[j]; + } +} + +void atlas__NodesFunctionSpace__minloc_arr_long( const NodeColumns* This, const field::FieldImpl* field, long*& minimum, + long*& glb_idx, int& size ) { + ATLAS_ASSERT( This != nullptr, "Cannot access uninitialised atlas_functionspace_NodeColumns" ); + ATLAS_ASSERT( field != nullptr, "Cannot access uninitialised atlas_Field" ); + std::vector minvec; + std::vector gidxvec; + This->minimumAndLocation( field, minvec, gidxvec ); + size = minvec.size(); + minimum = new long[size]; + glb_idx = new long[size]; + for ( idx_t j = 0; j < (idx_t)size; ++j ) { + minimum[j] = minvec[j]; + glb_idx[j] = gidxvec[j]; + } +} + +void atlas__NodesFunctionSpace__minloc_arr_int( const NodeColumns* This, const field::FieldImpl* field, int*& minimum, + long*& glb_idx, int& size ) { + ATLAS_ASSERT( This != nullptr, "Cannot access uninitialised atlas_functionspace_NodeColumns" ); + ATLAS_ASSERT( field != nullptr, "Cannot access uninitialised atlas_Field" ); + std::vector minvec; + std::vector gidxvec; + This->minimumAndLocation( field, minvec, gidxvec ); + size = minvec.size(); + minimum = new int[size]; + glb_idx = new long[size]; + for ( idx_t j = 0; j < (idx_t)size; ++j ) { + minimum[j] = minvec[j]; + glb_idx[j] = gidxvec[j]; + } +} + +void atlas__NodesFunctionSpace__maxloc_arr_double( const NodeColumns* This, const field::FieldImpl* field, + double*& maximum, long*& glb_idx, int& size ) { + ATLAS_ASSERT( This != nullptr, "Cannot access uninitialised atlas_functionspace_NodeColumns" ); + ATLAS_ASSERT( field != nullptr, "Cannot access uninitialised atlas_Field" ); + std::vector maxvec; + std::vector gidxvec; + This->maximumAndLocation( field, maxvec, gidxvec ); + size = maxvec.size(); + maximum = new double[size]; + glb_idx = new long[size]; + for ( idx_t j = 0; j < (idx_t)size; ++j ) { + maximum[j] = maxvec[j]; + glb_idx[j] = gidxvec[j]; + } +} + +void atlas__NodesFunctionSpace__maxloc_arr_float( const NodeColumns* This, const field::FieldImpl* field, + float*& maximum, long*& glb_idx, int& size ) { + ATLAS_ASSERT( This != nullptr, "Cannot access uninitialised atlas_functionspace_NodeColumns" ); + ATLAS_ASSERT( field != nullptr, "Cannot access uninitialised atlas_Field" ); + std::vector maxvec; + std::vector gidxvec; + This->maximumAndLocation( field, maxvec, gidxvec ); + size = maxvec.size(); + maximum = new float[size]; + glb_idx = new long[size]; + for ( idx_t j = 0; j < (idx_t)size; ++j ) { + maximum[j] = maxvec[j]; + glb_idx[j] = gidxvec[j]; + } +} + +void atlas__NodesFunctionSpace__maxloc_arr_long( const NodeColumns* This, const field::FieldImpl* field, long*& maximum, + long*& glb_idx, int& size ) { + ATLAS_ASSERT( This != nullptr, "Cannot access uninitialised atlas_functionspace_NodeColumns" ); + ATLAS_ASSERT( field != nullptr, "Cannot access uninitialised atlas_Field" ); + std::vector maxvec; + std::vector gidxvec; + This->maximumAndLocation( field, maxvec, gidxvec ); + size = maxvec.size(); + maximum = new long[size]; + glb_idx = new long[size]; + for ( idx_t j = 0; j < (idx_t)size; ++j ) { + maximum[j] = maxvec[j]; + glb_idx[j] = gidxvec[j]; + } +} + +void atlas__NodesFunctionSpace__maxloc_arr_int( const NodeColumns* This, const field::FieldImpl* field, int*& maximum, + long*& glb_idx, int& size ) { + ATLAS_ASSERT( This != nullptr, "Cannot access uninitialised atlas_functionspace_NodeColumns" ); + ATLAS_ASSERT( field != nullptr, "Cannot access uninitialised atlas_Field" ); + std::vector maxvec; + std::vector gidxvec; + This->maximumAndLocation( field, maxvec, gidxvec ); + size = maxvec.size(); + maximum = new int[size]; + glb_idx = new long[size]; + for ( idx_t j = 0; j < (idx_t)size; ++j ) { + maximum[j] = maxvec[j]; + glb_idx[j] = gidxvec[j]; + } +} + +void atlas__NodesFunctionSpace__mean_double( const NodeColumns* This, const field::FieldImpl* field, double& mean, + int& N ) { + ATLAS_ASSERT( This != nullptr, "Cannot access uninitialised atlas_functionspace_NodeColumns" ); + ATLAS_ASSERT( field != nullptr, "Cannot access uninitialised atlas_Field" ); + idx_t idx_t_N; + This->mean( field, mean, idx_t_N ); + N = idx_t_N; +} + +void atlas__NodesFunctionSpace__mean_float( const NodeColumns* This, const field::FieldImpl* field, float& mean, + int& N ) { + ATLAS_ASSERT( This != nullptr, "Cannot access uninitialised atlas_functionspace_NodeColumns" ); + ATLAS_ASSERT( field != nullptr, "Cannot access uninitialised atlas_Field" ); + idx_t idx_t_N; + This->mean( field, mean, idx_t_N ); + N = idx_t_N; +} + +void atlas__NodesFunctionSpace__mean_long( const NodeColumns* This, const field::FieldImpl* field, long& mean, + int& N ) { + ATLAS_NOTIMPLEMENTED; +} + +void atlas__NodesFunctionSpace__mean_int( const NodeColumns* This, const field::FieldImpl* field, int& mean, int& N ) { + ATLAS_NOTIMPLEMENTED; +} + +void atlas__NodesFunctionSpace__mean_arr_double( const NodeColumns* This, const field::FieldImpl* field, double*& mean, + int& size, int& N ) { + ATLAS_ASSERT( This != nullptr, "Cannot access uninitialised atlas_functionspace_NodeColumns" ); + ATLAS_ASSERT( field != nullptr, "Cannot access uninitialised atlas_Field" ); + idx_t idx_t_N; + std::vector meanvec; + This->mean( field, meanvec, idx_t_N ); + size = meanvec.size(); + mean = new double[size]; + for ( idx_t j = 0; j < (idx_t)size; ++j ) + mean[j] = meanvec[j]; + N = idx_t_N; +} + +void atlas__NodesFunctionSpace__mean_arr_float( const NodeColumns* This, const field::FieldImpl* field, float*& mean, + int& size, int& N ) { + ATLAS_ASSERT( This != nullptr, "Cannot access uninitialised atlas_functionspace_NodeColumns" ); + ATLAS_ASSERT( field != nullptr, "Cannot access uninitialised atlas_Field" ); + idx_t idx_t_N; + std::vector meanvec; + This->mean( field, meanvec, idx_t_N ); + size = meanvec.size(); + mean = new float[size]; + for ( idx_t j = 0; j < (idx_t)size; ++j ) + mean[j] = meanvec[j]; + N = idx_t_N; +} + +void atlas__NodesFunctionSpace__mean_arr_long( const NodeColumns* This, const field::FieldImpl* field, long*& mean, + int& size, int& N ) { + ATLAS_NOTIMPLEMENTED; +} + +void atlas__NodesFunctionSpace__mean_arr_int( const NodeColumns* This, const field::FieldImpl* field, int*& mean, + int& size, int& N ) { + ATLAS_NOTIMPLEMENTED; +} + +void atlas__NodesFunctionSpace__mean_and_stddev_double( const NodeColumns* This, const field::FieldImpl* field, + double& mean, double& stddev, int& N ) { + ATLAS_ASSERT( This != nullptr, "Cannot access uninitialised atlas_functionspace_NodeColumns" ); + ATLAS_ASSERT( field != nullptr, "Cannot access uninitialised atlas_Field" ); + idx_t idx_t_N; + This->meanAndStandardDeviation( field, mean, stddev, idx_t_N ); + N = idx_t_N; +} + +void atlas__NodesFunctionSpace__mean_and_stddev_float( const NodeColumns* This, const field::FieldImpl* field, + float& mean, float& stddev, int& N ) { + ATLAS_ASSERT( This != nullptr, "Cannot access uninitialised atlas_functionspace_NodeColumns" ); + ATLAS_ASSERT( field != nullptr, "Cannot access uninitialised atlas_Field" ); + idx_t idx_t_N; + This->meanAndStandardDeviation( field, mean, stddev, idx_t_N ); + N = idx_t_N; +} + +void atlas__NodesFunctionSpace__mean_and_stddev_long( const NodeColumns* This, const field::FieldImpl* field, + long& mean, long& stddev, int& N ) { + ATLAS_NOTIMPLEMENTED; +} + +void atlas__NodesFunctionSpace__mean_and_stddev_int( const NodeColumns* This, const field::FieldImpl* field, int& mean, + int& stddev, int& N ) { + ATLAS_NOTIMPLEMENTED; +} + +void atlas__NodesFunctionSpace__mean_and_stddev_arr_double( const NodeColumns* This, const field::FieldImpl* field, + double*& mean, double*& stddev, int& size, int& N ) { + ATLAS_ASSERT( This != nullptr, "Cannot access uninitialised atlas_functionspace_NodeColumns" ); + ATLAS_ASSERT( field != nullptr, "Cannot access uninitialised atlas_Field" ); + idx_t idx_t_N; + std::vector meanvec; + std::vector stddevvec; + This->meanAndStandardDeviation( field, meanvec, stddevvec, idx_t_N ); + size = meanvec.size(); + mean = new double[size]; + stddev = new double[size]; + for ( idx_t j = 0; j < (idx_t)size; ++j ) { + mean[j] = meanvec[j]; + stddev[j] = stddevvec[j]; + } + N = idx_t_N; +} + +void atlas__NodesFunctionSpace__mean_and_stddev_arr_float( const NodeColumns* This, const field::FieldImpl* field, + float*& mean, float*& stddev, int& size, int& N ) { + ATLAS_ASSERT( This != nullptr, "Cannot access uninitialised atlas_functionspace_NodeColumns" ); + ATLAS_ASSERT( field != nullptr, "Cannot access uninitialised atlas_Field" ); + idx_t idx_t_N; + std::vector meanvec; + std::vector stddevvec; + This->meanAndStandardDeviation( field, meanvec, stddevvec, idx_t_N ); + size = meanvec.size(); + mean = new float[size]; + stddev = new float[size]; + for ( idx_t j = 0; j < (idx_t)size; ++j ) { + mean[j] = meanvec[j]; + stddev[j] = stddevvec[j]; + } + N = idx_t_N; +} + +void atlas__NodesFunctionSpace__mean_and_stddev_arr_long( const NodeColumns* This, const field::FieldImpl* field, + long*& mean, long*& stddev, int& size, int& N ) { + ATLAS_NOTIMPLEMENTED; +} + +void atlas__NodesFunctionSpace__mean_and_stddev_arr_int( const NodeColumns* This, const field::FieldImpl* field, + int*& mean, int*& stddev, int& size, int& N ) { + ATLAS_NOTIMPLEMENTED; +} + +void atlas__NodesFunctionSpace__minloclev_double( const NodeColumns* This, const field::FieldImpl* field, + double& minimum, long& glb_idx, int& level ) { + ATLAS_ASSERT( This != nullptr, "Cannot access uninitialised atlas_functionspace_NodeColumns" ); + ATLAS_ASSERT( field != nullptr, "Cannot access uninitialised atlas_Field" ); + gidx_t gidx; + idx_t lev; + This->minimumAndLocation( field, minimum, gidx, lev ); + glb_idx = gidx; + level = lev; +} + +void atlas__NodesFunctionSpace__minloclev_float( const NodeColumns* This, const field::FieldImpl* field, float& minimum, + long& glb_idx, int& level ) { + ATLAS_ASSERT( This != nullptr, "Cannot access uninitialised atlas_functionspace_NodeColumns" ); + ATLAS_ASSERT( field != nullptr, "Cannot access uninitialised atlas_Field" ); + gidx_t gidx; + idx_t lev; + This->minimumAndLocation( field, minimum, gidx, lev ); + glb_idx = gidx; + level = lev; +} + +void atlas__NodesFunctionSpace__minloclev_long( const NodeColumns* This, const field::FieldImpl* field, long& minimum, + long& glb_idx, int& level ) { + ATLAS_ASSERT( This != nullptr, "Cannot access uninitialised atlas_functionspace_NodeColumns" ); + ATLAS_ASSERT( field != nullptr, "Cannot access uninitialised atlas_Field" ); + gidx_t gidx; + idx_t lev; + This->minimumAndLocation( field, minimum, gidx, lev ); + glb_idx = gidx; + level = lev; +} + +void atlas__NodesFunctionSpace__minloclev_int( const NodeColumns* This, const field::FieldImpl* field, int& minimum, + long& glb_idx, int& level ) { + ATLAS_ASSERT( This != nullptr, "Cannot access uninitialised atlas_functionspace_NodeColumns" ); + ATLAS_ASSERT( field != nullptr, "Cannot access uninitialised atlas_Field" ); + gidx_t gidx; + idx_t lev; + This->minimumAndLocation( field, minimum, gidx, lev ); + glb_idx = gidx; + level = lev; +} + +void atlas__NodesFunctionSpace__maxloclev_double( const NodeColumns* This, const field::FieldImpl* field, + double& maximum, long& glb_idx, int& level ) { + ATLAS_ASSERT( This != nullptr, "Cannot access uninitialised atlas_functionspace_NodeColumns" ); + ATLAS_ASSERT( field != nullptr, "Cannot access uninitialised atlas_Field" ); + gidx_t gidx; + idx_t lev; + This->maximumAndLocation( field, maximum, gidx, lev ); + glb_idx = gidx; + level = lev; +} + +void atlas__NodesFunctionSpace__maxloclev_float( const NodeColumns* This, const field::FieldImpl* field, float& maximum, + long& glb_idx, int& level ) { + ATLAS_ASSERT( This != nullptr, "Cannot access uninitialised atlas_functionspace_NodeColumns" ); + ATLAS_ASSERT( field != nullptr, "Cannot access uninitialised atlas_Field" ); + gidx_t gidx; + idx_t lev; + This->maximumAndLocation( field, maximum, gidx, lev ); + glb_idx = gidx; + level = lev; +} + +void atlas__NodesFunctionSpace__maxloclev_long( const NodeColumns* This, const field::FieldImpl* field, long& maximum, + long& glb_idx, int& level ) { + ATLAS_ASSERT( This != nullptr, "Cannot access uninitialised atlas_functionspace_NodeColumns" ); + ATLAS_ASSERT( field != nullptr, "Cannot access uninitialised atlas_Field" ); + gidx_t gidx; + idx_t lev; + This->maximumAndLocation( field, maximum, gidx, lev ); + glb_idx = gidx; + level = lev; +} + +void atlas__NodesFunctionSpace__maxloclev_int( const NodeColumns* This, const field::FieldImpl* field, int& maximum, + long& glb_idx, int& level ) { + ATLAS_ASSERT( This != nullptr, "Cannot access uninitialised atlas_functionspace_NodeColumns" ); + ATLAS_ASSERT( field != nullptr, "Cannot access uninitialised atlas_Field" ); + gidx_t gidx; + idx_t lev; + This->maximumAndLocation( field, maximum, gidx, lev ); + glb_idx = gidx; + level = lev; +} + +void atlas__NodesFunctionSpace__minloclev_arr_double( const NodeColumns* This, const field::FieldImpl* field, + double*& minimum, long*& glb_idx, int*& level, int& size ) { + ATLAS_ASSERT( This != nullptr, "Cannot access uninitialised atlas_functionspace_NodeColumns" ); + ATLAS_ASSERT( field != nullptr, "Cannot access uninitialised atlas_Field" ); + std::vector minvec; + std::vector gidxvec; + std::vector levvec; + This->minimumAndLocation( field, minvec, gidxvec, levvec ); + size = minvec.size(); + minimum = new double[size]; + glb_idx = new long[size]; + level = new int[size]; + for ( idx_t j = 0; j < (idx_t)size; ++j ) { + minimum[j] = minvec[j]; + glb_idx[j] = gidxvec[j]; + level[j] = levvec[j]; + } +} + +void atlas__NodesFunctionSpace__minloclev_arr_float( const NodeColumns* This, const field::FieldImpl* field, + float*& minimum, long*& glb_idx, int*& level, int& size ) { + ATLAS_ASSERT( This != nullptr, "Cannot access uninitialised atlas_functionspace_NodeColumns" ); + ATLAS_ASSERT( field != nullptr, "Cannot access uninitialised atlas_Field" ); + std::vector minvec; + std::vector gidxvec; + std::vector levvec; + This->minimumAndLocation( field, minvec, gidxvec, levvec ); + size = minvec.size(); + minimum = new float[size]; + glb_idx = new long[size]; + level = new int[size]; + for ( idx_t j = 0; j < (idx_t)size; ++j ) { + minimum[j] = minvec[j]; + glb_idx[j] = gidxvec[j]; + level[j] = levvec[j]; + }; +} + +void atlas__NodesFunctionSpace__minloclev_arr_long( const NodeColumns* This, const field::FieldImpl* field, + long*& minimum, long*& glb_idx, int*& level, int& size ) { + ATLAS_ASSERT( This != nullptr, "Cannot access uninitialised atlas_functionspace_NodeColumns" ); + ATLAS_ASSERT( field != nullptr, "Cannot access uninitialised atlas_Field" ); + std::vector minvec; + std::vector gidxvec; + std::vector levvec; + This->minimumAndLocation( field, minvec, gidxvec, levvec ); + size = minvec.size(); + minimum = new long[size]; + glb_idx = new long[size]; + level = new int[size]; + for ( idx_t j = 0; j < (idx_t)size; ++j ) { + minimum[j] = minvec[j]; + glb_idx[j] = gidxvec[j]; + level[j] = levvec[j]; + } +} + +void atlas__NodesFunctionSpace__minloclev_arr_int( const NodeColumns* This, const field::FieldImpl* field, + int*& minimum, long*& glb_idx, int*& level, int& size ) { + ATLAS_ASSERT( This != nullptr, "Cannot access uninitialised atlas_functionspace_NodeColumns" ); + ATLAS_ASSERT( field != nullptr, "Cannot access uninitialised atlas_Field" ); + std::vector minvec; + std::vector gidxvec; + std::vector levvec; + This->minimumAndLocation( field, minvec, gidxvec, levvec ); + size = minvec.size(); + minimum = new int[size]; + glb_idx = new long[size]; + level = new int[size]; + for ( idx_t j = 0; j < (idx_t)size; ++j ) { + minimum[j] = minvec[j]; + glb_idx[j] = gidxvec[j]; + level[j] = levvec[j]; + }; +} + +void atlas__NodesFunctionSpace__maxloclev_arr_double( const NodeColumns* This, const field::FieldImpl* field, + double*& maximum, long*& glb_idx, int*& level, int& size ) { + ATLAS_ASSERT( This != nullptr, "Cannot access uninitialised atlas_functionspace_NodeColumns" ); + ATLAS_ASSERT( field != nullptr, "Cannot access uninitialised atlas_Field" ); + std::vector maxvec; + std::vector gidxvec; + std::vector levvec; + This->maximumAndLocation( field, maxvec, gidxvec, levvec ); + size = maxvec.size(); + maximum = new double[size]; + glb_idx = new long[size]; + level = new int[size]; + for ( idx_t j = 0; j < (idx_t)size; ++j ) { + maximum[j] = maxvec[j]; + glb_idx[j] = gidxvec[j]; + level[j] = levvec[j]; + } +} + +void atlas__NodesFunctionSpace__maxloclev_arr_float( const NodeColumns* This, const field::FieldImpl* field, + float*& maximum, long*& glb_idx, int*& level, int& size ) { + ATLAS_ASSERT( This != nullptr, "Cannot access uninitialised atlas_functionspace_NodeColumns" ); + ATLAS_ASSERT( field != nullptr, "Cannot access uninitialised atlas_Field" ); + std::vector maxvec; + std::vector gidxvec; + std::vector levvec; + This->maximumAndLocation( field, maxvec, gidxvec, levvec ); + size = maxvec.size(); + maximum = new float[size]; + glb_idx = new long[size]; + level = new int[size]; + for ( idx_t j = 0; j < (idx_t)size; ++j ) { + maximum[j] = maxvec[j]; + glb_idx[j] = gidxvec[j]; + level[j] = levvec[j]; + } +} + +void atlas__NodesFunctionSpace__maxloclev_arr_long( const NodeColumns* This, const field::FieldImpl* field, + long*& maximum, long*& glb_idx, int*& level, int& size ) { + ATLAS_ASSERT( This != nullptr, "Cannot access uninitialised atlas_functionspace_NodeColumns" ); + ATLAS_ASSERT( field != nullptr, "Cannot access uninitialised atlas_Field" ); + std::vector maxvec; + std::vector gidxvec; + std::vector levvec; + This->maximumAndLocation( field, maxvec, gidxvec, levvec ); + size = maxvec.size(); + maximum = new long[size]; + glb_idx = new long[size]; + level = new int[size]; + for ( idx_t j = 0; j < (idx_t)size; ++j ) { + maximum[j] = maxvec[j]; + glb_idx[j] = gidxvec[j]; + level[j] = levvec[j]; + } +} + +void atlas__NodesFunctionSpace__maxloclev_arr_int( const NodeColumns* This, const field::FieldImpl* field, + int*& maximum, long*& glb_idx, int*& level, int& size ) { + ATLAS_ASSERT( This != nullptr, "Cannot access uninitialised atlas_functionspace_NodeColumns" ); + ATLAS_ASSERT( field != nullptr, "Cannot access uninitialised atlas_Field" ); + std::vector maxvec; + std::vector gidxvec; + std::vector levvec; + This->maximumAndLocation( field, maxvec, gidxvec, levvec ); + size = maxvec.size(); + maximum = new int[size]; + glb_idx = new long[size]; + level = new int[size]; + for ( idx_t j = 0; j < (idx_t)size; ++j ) { + maximum[j] = maxvec[j]; + glb_idx[j] = gidxvec[j]; + level[j] = levvec[j]; + } +} + +void atlas__NodesFunctionSpace__sum_per_level( const NodeColumns* This, const field::FieldImpl* field, + field::FieldImpl* column, int& N ) { + ATLAS_ASSERT( This != nullptr, "Cannot access uninitialised atlas_functionspace_NodeColumns" ); + ATLAS_ASSERT( field != nullptr, "Cannot access uninitialised atlas_Field" ); + ATLAS_ASSERT( column != nullptr, "Cannot access uninitialised atlas_Field" ); + idx_t idx_t_N; + Field sum( column ); + This->sumPerLevel( field, sum, idx_t_N ); + N = idx_t_N; +} + +void atlas__NodesFunctionSpace__oisum_per_level( const NodeColumns* This, const field::FieldImpl* field, + field::FieldImpl* column, int& N ) { + ATLAS_ASSERT( This != nullptr, "Cannot access uninitialised atlas_functionspace_NodeColumns" ); + ATLAS_ASSERT( field != nullptr, "Cannot access uninitialised atlas_Field" ); + ATLAS_ASSERT( column != nullptr, "Cannot access uninitialised atlas_Field" ); + idx_t idx_t_N; + Field sum( column ); + This->orderIndependentSumPerLevel( field, sum, idx_t_N ); + N = idx_t_N; +} + +void atlas__NodesFunctionSpace__min_per_level( const NodeColumns* This, const field::FieldImpl* field, + field::FieldImpl* min ) { + ATLAS_ASSERT( This != nullptr, "Cannot access uninitialised atlas_functionspace_NodeColumns" ); + ATLAS_ASSERT( field != nullptr, "Cannot access uninitialised atlas_Field" ); + ATLAS_ASSERT( min != nullptr, "Cannot access uninitialised min atlas_Field" ); + Field fmin( min ); + This->minimumPerLevel( field, fmin ); +} + +void atlas__NodesFunctionSpace__max_per_level( const NodeColumns* This, const field::FieldImpl* field, + field::FieldImpl* max ) { + ATLAS_ASSERT( This != nullptr, "Cannot access uninitialised atlas_functionspace_NodeColumns" ); + ATLAS_ASSERT( field != nullptr, "Cannot access uninitialised atlas_Field" ); + ATLAS_ASSERT( max != nullptr, "Cannot access uninitialised max atlas_Field" ); + Field fmax( max ); + This->maximumPerLevel( field, fmax ); +} + +void atlas__NodesFunctionSpace__minloc_per_level( const NodeColumns* This, const field::FieldImpl* field, + field::FieldImpl* min, field::FieldImpl* glb_idx ) { + ATLAS_ASSERT( This != nullptr, "Cannot access uninitialised atlas_functionspace_NodeColumns" ); + ATLAS_ASSERT( field != nullptr, "Cannot access uninitialised atlas_Field" ); + ATLAS_ASSERT( min != nullptr, "Cannot access uninitialised min atlas_Field" ); + ATLAS_ASSERT( glb_idx != nullptr, "Cannot access uninitialised glb_idx atlas_Field" ); + Field fmin( min ); + Field fglb_idx( glb_idx ); + This->minimumAndLocationPerLevel( field, fmin, fglb_idx ); +} + +void atlas__NodesFunctionSpace__maxloc_per_level( const NodeColumns* This, const field::FieldImpl* field, + field::FieldImpl* max, field::FieldImpl* glb_idx ) { + ATLAS_ASSERT( This != nullptr, "Cannot access uninitialised atlas_functionspace_NodeColumns" ); + ATLAS_ASSERT( field != nullptr, "Cannot access uninitialised atlas_Field" ); + ATLAS_ASSERT( max != nullptr, "Cannot access uninitialised max atlas_Field" ); + ATLAS_ASSERT( glb_idx != nullptr, "Cannot access uninitialised glb_idx atlas_Field" ); + Field fmax( max ); + Field fglb_idx( glb_idx ); + This->maximumAndLocationPerLevel( field, fmax, fglb_idx ); +} + +void atlas__NodesFunctionSpace__mean_per_level( const NodeColumns* This, const field::FieldImpl* field, + field::FieldImpl* mean, int& N ) { + ATLAS_ASSERT( This != nullptr, "Cannot access uninitialised atlas_functionspace_NodeColumns" ); + ATLAS_ASSERT( field != nullptr, "Cannot access uninitialised atlas_Field" ); + ATLAS_ASSERT( mean != nullptr, "Cannot access uninitialised mean atlas_Field" ); + idx_t idx_t_N; + Field fmean( mean ); + This->meanPerLevel( field, fmean, idx_t_N ); + N = idx_t_N; +} + +void atlas__NodesFunctionSpace__mean_and_stddev_per_level( const NodeColumns* This, const field::FieldImpl* field, + field::FieldImpl* mean, field::FieldImpl* stddev, int& N ) { + ATLAS_ASSERT( This != nullptr, "Cannot access uninitialised atlas_functionspace_NodeColumns" ); + ATLAS_ASSERT( field != nullptr, "Cannot access uninitialised atlas_Field" ); + ATLAS_ASSERT( mean != nullptr, "Cannot access uninitialised mean atlas_Field" ); + ATLAS_ASSERT( stddev ); + idx_t idx_t_N; + Field fmean( mean ); + Field fstddev( stddev ); + This->meanAndStandardDeviationPerLevel( field, fmean, fstddev, idx_t_N ); + N = idx_t_N; +} +} + +} // namespace detail +} // namespace functionspace +} // namespace atlas diff --git a/src/atlas/functionspace/NodeColumnsInterface.h b/src/atlas/functionspace/detail/NodeColumnsInterface.h similarity index 96% rename from src/atlas/functionspace/NodeColumnsInterface.h rename to src/atlas/functionspace/detail/NodeColumnsInterface.h index 254288ed8..65d5f43ba 100644 --- a/src/atlas/functionspace/NodeColumnsInterface.h +++ b/src/atlas/functionspace/detail/NodeColumnsInterface.h @@ -16,7 +16,8 @@ namespace atlas { namespace field { class FieldSetImpl; -} +class FieldImpl; +} // namespace field } // namespace atlas namespace atlas { @@ -29,11 +30,6 @@ void atlas__NodesFunctionSpace__delete( NodeColumns* This ); int atlas__NodesFunctionSpace__nb_nodes( const NodeColumns* This ); const Mesh::Implementation* atlas__NodesFunctionSpace__mesh( const NodeColumns* This ); mesh::Nodes* atlas__NodesFunctionSpace__nodes( const NodeColumns* This ); -field::FieldImpl* atlas__NodesFunctionSpace__create_field( const NodeColumns* This, - const eckit::Configuration* options ); -field::FieldImpl* atlas__NodesFunctionSpace__create_field_template( const NodeColumns* This, - const field::FieldImpl* field_template, - const eckit::Configuration* options ); void atlas__NodesFunctionSpace__halo_exchange_fieldset( const NodeColumns* This, field::FieldSetImpl* fieldset ); void atlas__NodesFunctionSpace__halo_exchange_field( const NodeColumns* This, field::FieldImpl* field ); @@ -75,10 +71,16 @@ void atlas__NodesFunctionSpace__oisum_double( const NodeColumns* This, const fie int& N ); void atlas__NodesFunctionSpace__oisum_float( const NodeColumns* This, const field::FieldImpl* field, float& sum, int& N ); +void atlas__NodesFunctionSpace__oisum_int( const NodeColumns* This, const field::FieldImpl* field, int& sum, int& N ); +void atlas__NodesFunctionSpace__oisum_long( const NodeColumns* This, const field::FieldImpl* field, long& sum, int& N ); void atlas__NodesFunctionSpace__oisum_arr_double( const NodeColumns* This, const field::FieldImpl* field, double*& sum, int& size, int& N ); void atlas__NodesFunctionSpace__oisum_arr_float( const NodeColumns* This, const field::FieldImpl* field, float*& sum, int& size, int& N ); +void atlas__NodesFunctionSpace__oisum_arr_int( const NodeColumns* This, const field::FieldImpl* field, int*& sum, + int& size, int& N ); +void atlas__NodesFunctionSpace__oisum_arr_long( const NodeColumns* This, const field::FieldImpl* field, long*& sum, + int& size, int& N ); void atlas__NodesFunctionSpace__min_double( const NodeColumns* This, const field::FieldImpl* field, double& minimum ); void atlas__NodesFunctionSpace__min_float( const NodeColumns* This, const field::FieldImpl* field, float& minimum ); diff --git a/src/atlas/functionspace/detail/StructuredColumnsInterface.cc b/src/atlas/functionspace/detail/StructuredColumnsInterface.cc new file mode 100644 index 000000000..f332e555f --- /dev/null +++ b/src/atlas/functionspace/detail/StructuredColumnsInterface.cc @@ -0,0 +1,168 @@ +/* + * (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 "StructuredColumnsInterface.h" + +#include "atlas/field/FieldSet.h" +#include "atlas/field/detail/FieldImpl.h" +#include "atlas/grid/Distribution.h" +#include "atlas/grid/Grid.h" +#include "atlas/grid/Partitioner.h" +#include "atlas/grid/detail/distribution/DistributionImpl.h" +#include "atlas/runtime/Exception.h" + +namespace atlas { +namespace functionspace { + +// ---------------------------------------------------------------------------- +// Fortran interfaces +// ---------------------------------------------------------------------------- + +namespace detail { +struct StructuredColumnsFortranAccess { + detail::StructuredColumns::Map2to1& ij2gp_; + StructuredColumnsFortranAccess( const detail::StructuredColumns& fs ) : + ij2gp_( const_cast( fs ).ij2gp_ ) {} +}; +} // namespace detail + + +extern "C" { + +const detail::StructuredColumns* atlas__functionspace__StructuredColumns__new__grid( + const Grid::Implementation* grid, const eckit::Configuration* config ) { + return new detail::StructuredColumns( Grid( grid ), grid::Partitioner(), *config ); +} + +const detail::StructuredColumns* atlas__functionspace__StructuredColumns__new__grid_dist( + const Grid::Implementation* grid, const grid::DistributionImpl* dist, const eckit::Configuration* config ) { + return new detail::StructuredColumns( Grid( grid ), grid::Distribution( dist ), *config ); +} + +const detail::StructuredColumns* atlas__functionspace__StructuredColumns__new__grid_dist_vert( + const Grid::Implementation* grid, const grid::DistributionImpl* dist, const Vertical* vert, + const eckit::Configuration* config ) { + return new detail::StructuredColumns( Grid( grid ), grid::Distribution( dist ), *vert, *config ); +} + +void atlas__functionspace__StructuredColumns__gather( const detail::StructuredColumns* This, + const field::FieldImpl* local, field::FieldImpl* global ) { + ATLAS_ASSERT( This != nullptr, "Cannot access uninitialised atlas_functionspace_StructuredColumns" ); + ATLAS_ASSERT( global != nullptr, "Cannot access uninitialised atlas_Field" ); + ATLAS_ASSERT( local != nullptr, "Cannot access uninitialised atlas_Field" ); + const Field l( local ); + Field g( global ); + This->gather( l, g ); +} + +void atlas__functionspace__StructuredColumns__scatter( const detail::StructuredColumns* This, + const field::FieldImpl* global, field::FieldImpl* local ) { + ATLAS_ASSERT( This != nullptr, "Cannot access uninitialised atlas_functionspace_StructuredColumns" ); + ATLAS_ASSERT( global != nullptr, "Cannot access uninitialised atlas_Field" ); + ATLAS_ASSERT( local != nullptr, "Cannot access uninitialised atlas_Field" ); + const Field g( global ); + Field l( local ); + This->scatter( g, l ); +} + +void atlas__fs__StructuredColumns__checksum_fieldset( const detail::StructuredColumns* This, + const field::FieldSetImpl* fieldset, char*& checksum, idx_t& size, + int& allocated ) { + ATLAS_ASSERT( This != nullptr, "Cannot access uninitialised atlas_functionspace_StructuredColumns" ); + 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; + strcpy( checksum, checksum_str.c_str() ); +} + +void atlas__fs__StructuredColumns__checksum_field( const detail::StructuredColumns* This, const field::FieldImpl* field, + char*& checksum, idx_t& size, int& allocated ) { + ATLAS_ASSERT( This != nullptr, "Cannot access uninitialised atlas_functionspace_StructuredColumns" ); + 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; + strcpy( checksum, checksum_str.c_str() ); +} + +void atlas__fs__StructuredColumns__index_host( const detail::StructuredColumns* This, idx_t*& data, idx_t& i_min, + idx_t& i_max, idx_t& j_min, idx_t& j_max ) { + ATLAS_ASSERT( This != nullptr, "Cannot access uninitialised atlas_functionspace_StructuredColumns" ); + auto _This = detail::StructuredColumnsFortranAccess{*This}; + data = _This.ij2gp_.data_.data(); + i_min = _This.ij2gp_.i_min_ + 1; + i_max = _This.ij2gp_.i_max_ + 1; + j_min = _This.ij2gp_.j_min_ + 1; + j_max = _This.ij2gp_.j_max_ + 1; +} + +idx_t atlas__fs__StructuredColumns__j_begin( const detail::StructuredColumns* This ) { + return This->j_begin() + 1; +} +idx_t atlas__fs__StructuredColumns__j_end( const detail::StructuredColumns* This ) { + return This->j_end(); +} +idx_t atlas__fs__StructuredColumns__i_begin( const detail::StructuredColumns* This, idx_t j ) { + return This->i_begin( j - 1 ) + 1; +} +idx_t atlas__fs__StructuredColumns__i_end( const detail::StructuredColumns* This, idx_t j ) { + return This->i_end( j - 1 ); +} +idx_t atlas__fs__StructuredColumns__j_begin_halo( const detail::StructuredColumns* This ) { + return This->j_begin_halo() + 1; +} +idx_t atlas__fs__StructuredColumns__j_end_halo( const detail::StructuredColumns* This ) { + return This->j_end_halo(); +} +idx_t atlas__fs__StructuredColumns__i_begin_halo( const detail::StructuredColumns* This, idx_t j ) { + return This->i_begin_halo( j - 1 ) + 1; +} +idx_t atlas__fs__StructuredColumns__i_end_halo( const detail::StructuredColumns* This, idx_t j ) { + return This->i_end_halo( j - 1 ); +} + +field::FieldImpl* atlas__fs__StructuredColumns__xy( const detail::StructuredColumns* This ) { + return This->xy().get(); +} + +field::FieldImpl* atlas__fs__StructuredColumns__partition( const detail::StructuredColumns* This ) { + return This->partition().get(); +} + +field::FieldImpl* atlas__fs__StructuredColumns__global_index( const detail::StructuredColumns* This ) { + return This->global_index().get(); +} + +field::FieldImpl* atlas__fs__StructuredColumns__index_i( const detail::StructuredColumns* This ) { + return This->index_i().get(); +} + +field::FieldImpl* atlas__fs__StructuredColumns__index_j( const detail::StructuredColumns* This ) { + return This->index_j().get(); +} + +idx_t atlas__fs__StructuredColumns__size( const detail::StructuredColumns* This ) { + return This->size(); +} + +idx_t atlas__fs__StructuredColumns__sizeOwned( const detail::StructuredColumns* This ) { + return This->sizeOwned(); +} +} + +// ---------------------------------------------------------------------------- + +} // namespace functionspace +} // namespace atlas diff --git a/src/atlas/functionspace/detail/StructuredColumnsInterface.h b/src/atlas/functionspace/detail/StructuredColumnsInterface.h new file mode 100644 index 000000000..519a8fc38 --- /dev/null +++ b/src/atlas/functionspace/detail/StructuredColumnsInterface.h @@ -0,0 +1,82 @@ +/* + * (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/StructuredColumns.h" + + +namespace atlas { +namespace field { +class FieldSetImpl; +} +namespace grid { +class DistributionImpl; +} +} // namespace atlas + +namespace atlas { +namespace grid { +namespace detail { +namespace grid { +class Grid; +} // namespace grid +} // namespace detail +} // namespace grid +using GridImpl = grid::detail::grid::Grid; +} // namespace atlas + +namespace atlas { +namespace functionspace { + +// ------------------------------------------------------------------- +// C wrapper interfaces to C++ routines +extern "C" { + +const detail::StructuredColumns* atlas__functionspace__StructuredColumns__new__grid( + const GridImpl* grid, const eckit::Configuration* config ); + +const detail::StructuredColumns* atlas__functionspace__StructuredColumns__new__grid_dist( + const GridImpl* grid, const grid::DistributionImpl* dist, const eckit::Configuration* config ); + +const detail::StructuredColumns* atlas__functionspace__StructuredColumns__new__grid_dist_vert( + const GridImpl* grid, const grid::DistributionImpl* dist, const Vertical* vert, + const eckit::Configuration* config ); + +void atlas__functionspace__StructuredColumns__gather( const detail::StructuredColumns* This, + const field::FieldImpl* local, field::FieldImpl* global ); +void atlas__functionspace__StructuredColumns__scatter( const detail::StructuredColumns* This, + const field::FieldImpl* global, field::FieldImpl* local ); +void atlas__fs__StructuredColumns__checksum_fieldset( const detail::StructuredColumns* This, + const field::FieldSetImpl* fieldset, char*& checksum, idx_t& size, + int& allocated ); +void atlas__fs__StructuredColumns__checksum_field( const detail::StructuredColumns* This, const field::FieldImpl* field, + char*& checksum, idx_t& size, int& allocated ); +void atlas__fs__StructuredColumns__index_host( const detail::StructuredColumns* This, idx_t*& data, idx_t& i_min, + idx_t& i_max, idx_t& j_min, idx_t& j_max ); +idx_t atlas__fs__StructuredColumns__size( const detail::StructuredColumns* This ); +idx_t atlas__fs__StructuredColumns__sizeOwned( const detail::StructuredColumns* This ); +idx_t atlas__fs__StructuredColumns__j_begin( const detail::StructuredColumns* This ); +idx_t atlas__fs__StructuredColumns__j_end( const detail::StructuredColumns* This ); +idx_t atlas__fs__StructuredColumns__i_begin( const detail::StructuredColumns* This, idx_t j ); +idx_t atlas__fs__StructuredColumns__i_end( const detail::StructuredColumns* This, idx_t j ); +idx_t atlas__fs__StructuredColumns__j_begin_halo( const detail::StructuredColumns* This ); +idx_t atlas__fs__StructuredColumns__j_end_halo( const detail::StructuredColumns* This ); +idx_t atlas__fs__StructuredColumns__i_begin_halo( const detail::StructuredColumns* This, idx_t j ); +idx_t atlas__fs__StructuredColumns__i_end_halo( const detail::StructuredColumns* This, idx_t j ); + +field::FieldImpl* atlas__fs__StructuredColumns__xy( const detail::StructuredColumns* This ); +field::FieldImpl* atlas__fs__StructuredColumns__partition( const detail::StructuredColumns* This ); +field::FieldImpl* atlas__fs__StructuredColumns__global_index( const detail::StructuredColumns* This ); +field::FieldImpl* atlas__fs__StructuredColumns__index_i( const detail::StructuredColumns* This ); +field::FieldImpl* atlas__fs__StructuredColumns__index_j( const detail::StructuredColumns* This ); +} + +} // namespace functionspace +} // namespace atlas diff --git a/src/atlas/grid.h b/src/atlas/grid.h index fe471368e..65f36bbd0 100644 --- a/src/atlas/grid.h +++ b/src/atlas/grid.h @@ -16,3 +16,5 @@ #include "atlas/grid/Grid.h" #include "atlas/grid/Iterator.h" #include "atlas/grid/Partitioner.h" +#include "atlas/grid/StructuredGrid.h" +#include "atlas/grid/UnstructuredGrid.h" diff --git a/src/atlas/grid/Distribution.cc b/src/atlas/grid/Distribution.cc index a59d54561..6fe2b4af0 100644 --- a/src/atlas/grid/Distribution.cc +++ b/src/atlas/grid/Distribution.cc @@ -10,86 +10,65 @@ #include -#include "atlas/grid/Distribution.h" +#include "Distribution.h" + #include "atlas/grid/Grid.h" #include "atlas/grid/Partitioner.h" +#include "atlas/grid/detail/distribution/DistributionImpl.h" #include "atlas/parallel/mpi/mpi.h" #include "atlas/runtime/Log.h" namespace atlas { namespace grid { -namespace { -std::string distribution_type( int N, const Partitioner& p = Partitioner() ) { - if ( N == 1 ) { return "serial"; } - if ( not p ) { return "custom"; } - return p.type(); -} -} // namespace - -Distribution::impl_t::impl_t( const Grid& grid ) : - nb_partitions_( 1 ), - part_( grid.size(), 0 ), - nb_pts_( nb_partitions_, grid.size() ), - max_pts_( grid.size() ), - min_pts_( grid.size() ), - type_( distribution_type( nb_partitions_ ) ) {} - -Distribution::impl_t::impl_t( const Grid& grid, const Partitioner& partitioner ) { - part_.resize( grid.size() ); - partitioner.partition( grid, part_.data() ); - nb_partitions_ = partitioner.nb_partitions(); - nb_pts_.resize( nb_partitions_, 0 ); - for ( size_t j = 0; j < part_.size(); ++j ) - ++nb_pts_[part_[j]]; - max_pts_ = *std::max_element( nb_pts_.begin(), nb_pts_.end() ); - min_pts_ = *std::min_element( nb_pts_.begin(), nb_pts_.end() ); - type_ = distribution_type( nb_partitions_, partitioner ); -} +Distribution::Distribution( const Grid& grid ) : Handle( new Implementation( grid ) ) {} + +Distribution::Distribution( const Grid& grid, const Partitioner& partitioner ) : + Handle( new Implementation( grid, partitioner ) ) {} + +Distribution::Distribution( idx_t npts, int part[], int part0 ) : Handle( new Implementation( npts, part, part0 ) ) {} + +Distribution::~Distribution() {} -Distribution::impl_t::impl_t( size_t npts, int part[], int part0 ) { - part_.assign( part, part + npts ); - std::set partset( part_.begin(), part_.end() ); - nb_partitions_ = partset.size(); - nb_pts_.resize( nb_partitions_, 0 ); - for ( size_t j = 0; j < part_.size(); ++j ) { - part_[j] -= part0; - ++nb_pts_[part_[j]]; - } - max_pts_ = *std::max_element( nb_pts_.begin(), nb_pts_.end() ); - min_pts_ = *std::min_element( nb_pts_.begin(), nb_pts_.end() ); - type_ = distribution_type( nb_partitions_ ); +int Distribution::partition( const gidx_t gidx ) const { + return get()->partition( gidx ); } -void Distribution::impl_t::print( std::ostream& s ) const { - s << "Distribution( " - << "type: " << type_ << ", nbPoints: " << part_.size() << ", nbPartitions: " << nb_pts_.size() << ", parts : ["; - for ( size_t i = 0; i < part_.size(); i++ ) { - if ( i != 0 ) s << ','; - s << part_[i]; - } - s << ']'; +const std::vector& Distribution::partition() const { + return get()->partition(); } -Distribution::Distribution() : impl_( nullptr ) {} +idx_t Distribution::nb_partitions() const { + return get()->nb_partitions(); +} -Distribution::Distribution( const impl_t* impl ) : impl_( impl ) {} +const int* Distribution::data() const { + return get()->data(); +} -Distribution::Distribution( const Distribution& other ) : impl_( other.impl_ ) {} +const std::vector& Distribution::nb_pts() const { + return get()->nb_pts(); +} -Distribution::Distribution( const Grid& grid ) : impl_( new impl_t( grid ) ) {} +idx_t Distribution::max_pts() const { + return get()->max_pts(); +} -Distribution::Distribution( const Grid& grid, const Partitioner& partitioner ) : - impl_( new impl_t( grid, partitioner ) ) {} +idx_t Distribution::min_pts() const { + return get()->min_pts(); +} -Distribution::Distribution( size_t npts, int part[], int part0 ) : impl_( new impl_t( npts, part, part0 ) ) {} +const std::string& Distribution::type() const { + return get()->type(); +} -Distribution::impl_t* atlas__GridDistribution__new( int npts, int part[], int part0 ) { - return new Distribution::impl_t( npts, part, part0 ); +std::ostream& operator<<( std::ostream& os, const Distribution& distribution ) { + distribution.get()->print( os ); + return os; } -void atlas__GridDistribution__delete( Distribution::impl_t* This ) { - delete This; +atlas::grid::Distribution::operator const std::vector&() const { + return *get(); } } // namespace grid diff --git a/src/atlas/grid/Distribution.h b/src/atlas/grid/Distribution.h index 9b82daf58..47b598f1a 100644 --- a/src/atlas/grid/Distribution.h +++ b/src/atlas/grid/Distribution.h @@ -12,108 +12,56 @@ #include -#include "eckit/memory/Owned.h" -#include "eckit/memory/SharedPtr.h" - +#include "atlas/grid/detail/distribution/DistributionImpl.h" #include "atlas/library/config.h" +#include "atlas/util/ObjectHandle.h" namespace atlas { class Grid; namespace grid { class Partitioner; -} +class DistributionImpl; +class Partitioner; +} // namespace grid } // namespace atlas namespace atlas { namespace grid { -class Distribution { +class Distribution : public util::ObjectHandle { friend class Partitioner; public: - class impl_t : public eckit::Owned { - public: - impl_t( const Grid& ); - - impl_t( const Grid&, const Partitioner& ); - - impl_t( size_t npts, int partition[], int part0 = 0 ); - - virtual ~impl_t() {} - - int partition( const gidx_t gidx ) const { return part_[gidx]; } - - const std::vector& partition() const { return part_; } - - size_t nb_partitions() const { return nb_partitions_; } - - operator const std::vector&() const { return part_; } - - const int* data() const { return part_.data(); } - - const std::vector& nb_pts() const { return nb_pts_; } - - size_t max_pts() const { return max_pts_; } - size_t min_pts() const { return min_pts_; } - - const std::string& type() const { return type_; } - - void print( std::ostream& ) const; - - private: - size_t nb_partitions_; - std::vector part_; - std::vector nb_pts_; - size_t max_pts_; - size_t min_pts_; - std::string type_; - }; - -public: - Distribution(); - Distribution( const impl_t* ); - Distribution( const Distribution& ); + using Handle::Handle; + Distribution() = default; Distribution( const Grid& ); Distribution( const Grid&, const Partitioner& ); - Distribution( size_t npts, int partition[], int part0 = 0 ); - - ~Distribution() {} + Distribution( idx_t npts, int partition[], int part0 = 0 ); - int partition( const gidx_t gidx ) const { return impl_->partition( gidx ); } + ~Distribution(); - const std::vector& partition() const { return impl_->partition(); } + int partition( const gidx_t gidx ) const; - size_t nb_partitions() const { return impl_->nb_partitions(); } + const std::vector& partition() const; - operator const std::vector&() const { return *impl_; } + idx_t nb_partitions() const; - const int* data() const { return impl_->data(); } + operator const std::vector&() const; - const std::vector& nb_pts() const { return impl_->nb_pts(); } + const int* data() const; - size_t max_pts() const { return impl_->max_pts(); } - size_t min_pts() const { return impl_->min_pts(); } + const std::vector& nb_pts() const; - const std::string& type() const { return impl_->type(); } + idx_t max_pts() const; + idx_t min_pts() const; - friend std::ostream& operator<<( std::ostream& os, const Distribution& distribution ) { - distribution.impl_->print( os ); - return os; - } + const std::string& type() const; - const impl_t* get() const { return impl_.get(); } - -private: - eckit::SharedPtr impl_; + friend std::ostream& operator<<( std::ostream& os, const Distribution& distribution ); }; -extern "C" { -Distribution::impl_t* atlas__GridDistribution__new( int npts, int part[], int part0 ); -void atlas__GridDistribution__delete( Distribution::impl_t* This ); -} - } // namespace grid } // namespace atlas diff --git a/src/atlas/grid/Grid.cc b/src/atlas/grid/Grid.cc index aba813870..e564c8898 100644 --- a/src/atlas/grid/Grid.cc +++ b/src/atlas/grid/Grid.cc @@ -14,105 +14,69 @@ #include #include -#include "eckit/config/Parametrisation.h" -#include "eckit/exception/Exceptions.h" - #include "atlas/domain/Domain.h" #include "atlas/grid/Grid.h" +#include "atlas/grid/Iterator.h" #include "atlas/grid/Spacing.h" -#include "atlas/grid/detail/grid/Gaussian.h" -#include "atlas/grid/detail/grid/Structured.h" #include "atlas/projection/Projection.h" +#include "atlas/runtime/Exception.h" #include "atlas/util/Config.h" namespace atlas { -Grid::Grid() : grid_( nullptr ) {} - -Grid::Grid( const Grid& grid ) : grid_( grid.grid_ ) {} - -Grid::Grid( const Grid::Implementation* grid ) : grid_( grid ) {} - -Grid::Grid( const std::string& shortname, const Domain& domain ) { - Config config; - if ( domain ) config.set( "domain", domain.spec() ); - grid_ = Grid::Implementation::create( shortname, config ); +Grid::IterateXY Grid::xy( Grid::IterateXY::Predicate p ) const { + return Grid::IterateXY( *get(), p ); } -Grid::Grid( const Grid& grid, const Grid::Domain& domain ) { - ASSERT( grid ); - grid_ = Grid::Implementation::create( *grid.get(), domain ); +Grid::IterateXY Grid::xy() const { + return Grid::IterateXY( *get() ); } -Grid::Grid( const Config& p ) { - grid_ = Grid::Implementation::create( p ); +Grid::IterateLonLat Grid::lonlat() const { + return Grid::IterateLonLat( *get() ); } -namespace grid { - -inline const UnstructuredGrid::grid_t* unstructured_grid( const Grid::Implementation* grid ) { - return dynamic_cast( grid ); -} - -UnstructuredGrid::UnstructuredGrid() : Grid(), grid_( nullptr ) {} - -UnstructuredGrid::UnstructuredGrid( const Grid& grid ) : Grid( grid ), grid_( unstructured_grid( get() ) ) {} - -UnstructuredGrid::UnstructuredGrid( const Grid::Implementation* grid ) : - Grid( grid ), - grid_( unstructured_grid( get() ) ) {} - -UnstructuredGrid::UnstructuredGrid( const Config& grid ) : Grid( grid ), grid_( unstructured_grid( get() ) ) {} - -UnstructuredGrid::UnstructuredGrid( std::vector* xy ) : - Grid( new UnstructuredGrid::grid_t( xy ) ), - grid_( unstructured_grid( get() ) ) {} +Grid::Grid( const std::string& shortname, const Domain& domain ) : + Handle( [&] { + Config config; + if ( domain ) config.set( "domain", domain.spec() ); + return Grid::Implementation::create( shortname, config ); + }() ) {} -UnstructuredGrid::UnstructuredGrid( std::vector&& xy ) : - Grid( new UnstructuredGrid::grid_t( std::forward>( xy ) ) ), - grid_( unstructured_grid( get() ) ) {} +Grid::Grid( const Grid& grid, const Grid::Domain& domain ) : + Handle( [&] { + ATLAS_ASSERT( grid ); + return Grid::Implementation::create( *grid.get(), domain ); + }() ) {} -UnstructuredGrid::UnstructuredGrid( std::initializer_list xy ) : - Grid( new UnstructuredGrid::grid_t( xy ) ), - grid_( unstructured_grid( get() ) ) {} +Grid::Grid( const Config& p ) : Handle( Grid::Implementation::create( p ) ) {} -UnstructuredGrid::UnstructuredGrid( const Grid& grid, const Grid::Domain& domain ) : - Grid( new UnstructuredGrid::grid_t( *grid.get(), domain ) ), - grid_( unstructured_grid( get() ) ) {} - -inline const StructuredGrid::grid_t* structured_grid( const Grid::Implementation* grid ) { - return dynamic_cast( grid ); +idx_t Grid::size() const { + return get()->size(); } -StructuredGrid::StructuredGrid() : Grid(), grid_( nullptr ) {} - -StructuredGrid::StructuredGrid( const Grid& grid ) : Grid( grid ), grid_( structured_grid( get() ) ) {} - -StructuredGrid::StructuredGrid( const Grid::Implementation* grid ) : Grid( grid ), grid_( structured_grid( get() ) ) {} - -StructuredGrid::StructuredGrid( const std::string& grid, const Domain& domain ) : - Grid( grid, domain ), - grid_( structured_grid( get() ) ) {} - -StructuredGrid::StructuredGrid( const Config& grid ) : Grid( grid ), grid_( structured_grid( get() ) ) {} +const Grid::Projection& Grid::projection() const { + return get()->projection(); +} -StructuredGrid::StructuredGrid( const XSpace& xspace, const YSpace& yspace, const Projection& projection, - const Domain& domain ) : - Grid( new detail::grid::Structured( xspace, yspace, projection, domain ) ), - grid_( structured_grid( get() ) ) {} +const Grid::Domain& Grid::domain() const { + return get()->domain(); +} -StructuredGrid::StructuredGrid( const Grid& grid, const Grid::Domain& domain ) : - Grid( grid, domain ), - grid_( structured_grid( get() ) ) {} +std::string Grid::name() const { + return get()->name(); +} -ReducedGaussianGrid::ReducedGaussianGrid( const std::vector& nx, const Domain& domain ) : - ReducedGaussianGrid::grid_t( detail::grid::reduced_gaussian( nx, domain ) ) {} +std::string Grid::uid() const { + return get()->uid(); +} -ReducedGaussianGrid::ReducedGaussianGrid( const std::initializer_list& nx ) : - ReducedGaussianGrid( std::vector( nx ) ) {} +void Grid::hash( eckit::Hash& h ) const { + return get()->hash( h ); +} -RegularGaussianGrid::RegularGaussianGrid( int N, const Grid::Domain& domain ) : - RegularGaussianGrid::grid_t( "F" + std::to_string( N ), domain ) {} +Grid::Spec Grid::spec() const { + return get()->spec(); +} -} // namespace grid } // namespace atlas diff --git a/src/atlas/grid/Grid.h b/src/atlas/grid/Grid.h index b3e12fd37..f6e9f4ab6 100644 --- a/src/atlas/grid/Grid.h +++ b/src/atlas/grid/Grid.h @@ -11,360 +11,77 @@ #pragma once #include - -#include "eckit/memory/SharedPtr.h" +#include +#include #include "atlas/domain/Domain.h" -#include "atlas/grid/Iterator.h" -#include "atlas/grid/detail/grid/Grid.h" -#include "atlas/grid/detail/grid/Structured.h" -#include "atlas/grid/detail/grid/Unstructured.h" +#include "atlas/library/config.h" #include "atlas/projection/Projection.h" +#include "atlas/util/ObjectHandle.h" namespace eckit { class Hash; } +namespace atlas { +class PointXY; +class PointLonLat; +namespace util { +class Config; +} +namespace grid { +class IterateXY; +class IterateLonLat; +namespace detail { +namespace grid { +class Grid; +} +} // namespace detail +} // namespace grid +} // namespace atlas namespace atlas { //--------------------------------------------------------------------------------------------------------------------- -class Grid { +class Grid : public util::ObjectHandle { public: - using Implementation = grid::detail::grid::Grid; - using Config = Implementation::Config; - using Spec = Implementation::Spec; - using Domain = atlas::Domain; - using Projection = atlas::Projection; - using PointXY = atlas::PointXY; // must be sizeof(double)*2 - using PointLonLat = atlas::PointLonLat; // must be sizeof(double)*2 - - class IterateXY { - public: - using iterator = grid::IteratorXY; - using const_iterator = iterator; - using Predicate = std::function; - - public: - IterateXY( const Implementation& grid, Predicate p ) : grid_( grid ), p_( p ), use_p_( true ) {} - IterateXY( const Implementation& grid ) : grid_( grid ) {} - iterator begin() const { return use_p_ ? grid_.xy_begin( p_ ) : grid_.xy_begin(); } - iterator end() const { return use_p_ ? grid_.xy_end( p_ ) : grid_.xy_end(); } - - private: - const Implementation& grid_; - Predicate p_; - bool use_p_{false}; - }; - - class IterateLonLat { - public: - using iterator = grid::IteratorLonLat; - using const_iterator = iterator; - - public: - IterateLonLat( const Implementation& grid ) : grid_( grid ) {} - iterator begin() const { return grid_.lonlat_begin(); } - iterator end() const { return grid_.lonlat_end(); } - - private: - const Implementation& grid_; - }; + using Config = util::Config; + using Spec = util::Config; + using Domain = atlas::Domain; + using Projection = atlas::Projection; + using PointXY = atlas::PointXY; // must be sizeof(double)*2 + using PointLonLat = atlas::PointLonLat; // must be sizeof(double)*2 + using IterateXY = grid::IterateXY; + using IterateLonLat = grid::IterateLonLat; + using Predicate = std::function; public: - IterateXY xy( IterateXY::Predicate p ) const { return IterateXY( *grid_, p ); } - IterateXY xy() const { return IterateXY( *grid_ ); } - IterateLonLat lonlat() const { return IterateLonLat( *grid_ ); } + IterateXY xy( Predicate p ) const; + IterateXY xy() const; + IterateLonLat lonlat() const; - Grid(); - Grid( const Grid& ); - Grid( const Implementation* ); + using Handle::Handle; + Grid() = default; Grid( const std::string& name, const Domain& = Domain() ); Grid( const Grid&, const Domain& ); Grid( const Config& ); - operator bool() const { return grid_; } - bool operator==( const Grid& other ) const { return uid() == other.uid(); } bool operator!=( const Grid& other ) const { return uid() != other.uid(); } - size_t size() const { return grid_->size(); } + idx_t size() const; - const Projection& projection() const { return grid_->projection(); } - const Domain& domain() const { return grid_->domain(); } - std::string name() const { return grid_->name(); } - std::string uid() const { return grid_->uid(); } + const Projection& projection() const; + const Domain& domain() const; + std::string name() const; + std::string uid() const; /// Adds to the hash the information that makes this Grid unique - void hash( eckit::Hash& h ) const { return grid_->hash( h ); } - - Spec spec() const { return grid_->spec(); } + void hash( eckit::Hash& h ) const; - const Implementation* get() const { return grid_.get(); } - -private: - eckit::SharedPtr grid_; + Spec spec() const; }; -namespace grid { - //--------------------------------------------------------------------------------------------------------------------- -// Further grid interpretation classes defined in this file - -class UnstructuredGrid; -class StructuredGrid; -class RegularGrid; -class GaussianGrid; -class ReducedGaussianGrid; -class RegularGaussianGrid; -class RegularLonLatGrid; -class ShiftedLonLatGrid; - -/* - Grid - | - +----------+----------+ - | | - StructuredGrid UnstructuredGrid - | - +--------------------+-----------------------+ - | | | - ReducedGrid GaussianGrid RegularGrid - | | | | | - +--------+--------+ +--------+--------+ +-----+ - | | | - ReducedGaussianGrid RegularGaussianGrid RegularLonLatGrid -*/ - -//--------------------------------------------------------------------------------------------------------------------- - -//--------------------------------------------------------------------------------------------------------------------- - -class UnstructuredGrid : public Grid { -public: - using grid_t = detail::grid::Unstructured; - -public: - UnstructuredGrid(); - UnstructuredGrid( const Grid& ); - UnstructuredGrid( const Config& ); - UnstructuredGrid( const Grid::Implementation* ); - UnstructuredGrid( std::vector* ); // takes ownership - UnstructuredGrid( std::vector&& ); // move constructor - UnstructuredGrid( std::initializer_list ); - UnstructuredGrid( const Grid&, const Domain& ); // Create a new unstructured grid! - - operator bool() const { return valid(); } - - bool valid() const { return grid_; } - - using Grid::xy; - void xy( size_t n, double xy[] ) const { - PointXY _xy = grid_->xy( n ); - xy[0] = _xy.x(); - xy[1] = _xy.y(); - } - - PointXY xy( size_t n ) const { return grid_->xy( n ); } - - PointLonLat lonlat( size_t n ) const { return grid_->lonlat( n ); } -private: - const grid_t* grid_; -}; - -//--------------------------------------------------------------------------------------------------------------------- - -class StructuredGrid : public Grid { -public: - using grid_t = detail::grid::Structured; - using XSpace = grid_t::XSpace; - using YSpace = grid_t::YSpace; - -public: - StructuredGrid(); - StructuredGrid( const Grid& ); - StructuredGrid( const Grid::Implementation* ); - StructuredGrid( const std::string& name, const Domain& = Domain() ); - StructuredGrid( const Config& ); - StructuredGrid( const XSpace&, const YSpace&, const Projection& = Projection(), const Domain& = Domain() ); - StructuredGrid( const Grid&, const Domain& ); - - operator bool() const { return valid(); } - - bool valid() const { return grid_; } - - inline size_t ny() const { return grid_->ny(); } - - inline size_t nx( size_t j ) const { return grid_->nx( j ); } - - inline const std::vector& nx() const { return grid_->nx(); } - - inline size_t nxmax() const { return grid_->nxmax(); } - - inline const std::vector& y() const { return grid_->y(); } - - inline double x( size_t i, size_t j ) const { return grid_->x( i, j ); } - - inline double y( size_t j ) const { return grid_->y( j ); } - - using Grid::xy; - void xy( size_t i, size_t j, double xy[] ) const { grid_->xy( i, j, xy ); } - - void lonlat( size_t i, size_t j, double lonlat[] ) const { grid_->lonlat( i, j, lonlat ); } - - PointXY xy( size_t i, size_t j ) const { return PointXY( x( i, j ), y( j ) ); } - - PointLonLat lonlat( size_t i, size_t j ) const { return grid_->lonlat( i, j ); } - - inline bool reduced() const { return grid_->reduced(); } - - inline bool regular() const { return not reduced(); } - - bool periodic() const { return grid_->periodic(); } - - const XSpace& xspace() const { return grid_->xspace(); } - - const YSpace& yspace() const { return grid_->yspace(); } - -private: - const grid_t* grid_; -}; - -//--------------------------------------------------------------------------------------------------------------------- - -class ReducedGrid : public StructuredGrid { -public: - using StructuredGrid::StructuredGrid; - - operator bool() const { return valid(); } - - bool valid() const { return StructuredGrid::valid() && reduced(); } -}; - -//--------------------------------------------------------------------------------------------------------------------- - -class RegularGrid : public StructuredGrid { -public: - using StructuredGrid::StructuredGrid; - using StructuredGrid::x; - using StructuredGrid::xy; - - operator bool() const { return valid(); } - - bool valid() const { return StructuredGrid::valid() && regular(); } - - size_t nx() const { return nxmax(); } - - inline double x( size_t i ) const { return x( i, 0 ); } - - PointXY xy( size_t i, size_t j ) const { return PointXY( x( i ), y( j ) ); } -}; - -//--------------------------------------------------------------------------------------------------------------------- - -template -class Gaussian : public Grid { -public: - using Grid::Grid; - - long N() const { return Grid::ny() / 2; } - - inline double lon( size_t i, size_t j ) const { return Grid::x( i, j ); } - - inline double lat( size_t j ) const { return Grid::y( j ); } - - PointLonLat lonlat( size_t i, size_t j ) const { return Grid::xy( i, j ); } - -protected: - bool gaussian() const { - return Grid::domain().global() && not Grid::projection() && Grid::yspace().type() == "gaussian"; - } -}; - -//--------------------------------------------------------------------------------------------------------------------- - -class GaussianGrid : public Gaussian { - using grid_t = Gaussian; - -public: - using grid_t::grid_t; - - operator bool() const { return valid(); } - - bool valid() const { return StructuredGrid::valid() && gaussian(); } -}; - -//--------------------------------------------------------------------------------------------------------------------- - -class ReducedGaussianGrid : public Gaussian { - using grid_t = Gaussian; - -public: - using grid_t::grid_t; - ReducedGaussianGrid( const std::initializer_list& pl ); - ReducedGaussianGrid( const std::vector& pl, const Domain& = Domain() ); - - operator bool() const { return valid(); } - - bool valid() const { return ReducedGrid::valid() && gaussian(); } -}; - -//--------------------------------------------------------------------------------------------------------------------- - -class RegularGaussianGrid : public Gaussian { - using grid_t = Gaussian; - -public: - using grid_t::grid_t; - RegularGaussianGrid( int N, const Domain& = Domain() ); - - inline double lon( size_t i ) const { return x( i ); } - - inline double lat( size_t j ) const { return y( j ); } - - PointLonLat lonlat( size_t i, size_t j ) const { return xy( i, j ); } - - operator bool() const { return valid(); } - - bool valid() const { return RegularGrid::valid() && gaussian(); } -}; - -//--------------------------------------------------------------------------------------------------------------------- - -class RegularLonLatGrid : public RegularGrid { -public: - using RegularGrid::RegularGrid; - -public: - operator bool() const { return valid(); } - - bool valid() const { return RegularGrid::valid() && global_lonlat(); } - - inline double lon( size_t i ) const { return x( i ); } - - inline double lat( size_t j ) const { return y( j ); } - - PointLonLat lonlat( size_t i, size_t j ) const { return xy( i, j ); } - - bool standard() const { return standard_lon() && standard_lat(); } - bool shifted() const { return shifted_lon() && shifted_lat(); } - bool shiftedLon() const { return shifted_lon() && standard_lat(); } - bool shiftedLat() const { return standard_lon() && shifted_lat(); } - -protected: - bool global_lonlat() const { return domain().global() && not projection() && yspace().type() == "linear"; } - - bool standard_lon() const { return x( 0 ) == 0.; } - - bool standard_lat() const { return y( 0 ) == 90. && ny() % 2 == 1; } - - bool shifted_lon() const { return x( 0 ) == 0.5 * 360. / nx(); } - - bool shifted_lat() const { return y( 0 ) == 90. - 0.5 * 180. / ny() && ny() % 2 == 0; } -}; - -//--------------------------------------------------------------------------------------------------------------------- - -} // namespace grid } // namespace atlas diff --git a/src/atlas/grid/Iterator.cc b/src/atlas/grid/Iterator.cc new file mode 100644 index 000000000..7928ed264 --- /dev/null +++ b/src/atlas/grid/Iterator.cc @@ -0,0 +1,35 @@ +/* + * (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/Iterator.h" + +//--------------------------------------------------------------------------------------------------------------------- + +namespace atlas { +namespace grid { + +IterateXY::iterator IterateXY::begin() const { + return use_p_ ? grid_.xy_begin( p_ ) : grid_.xy_begin(); +} + +IterateXY::iterator IterateXY::end() const { + return use_p_ ? grid_.xy_end( p_ ) : grid_.xy_end(); +} + +IterateLonLat::iterator IterateLonLat::begin() const { + return grid_.lonlat_begin(); +} + +IterateLonLat::iterator IterateLonLat::end() const { + return grid_.lonlat_end(); +} + +} // namespace grid +} // namespace atlas diff --git a/src/atlas/grid/Iterator.h b/src/atlas/grid/Iterator.h index f034feced..8c54f6e3c 100644 --- a/src/atlas/grid/Iterator.h +++ b/src/atlas/grid/Iterator.h @@ -10,7 +10,10 @@ #pragma once +#include + #include "atlas/grid/detail/grid/Grid.h" +#include "atlas/util/Point.h" //--------------------------------------------------------------------------------------------------------------------- @@ -65,5 +68,39 @@ class IteratorLonLat { //--------------------------------------------------------------------------------------------------------------------- +class IterateXY { +public: + using iterator = grid::IteratorXY; + using const_iterator = iterator; + using Predicate = std::function; + using Grid = detail::grid::Grid; + +public: + IterateXY( const Grid& grid, Predicate p ) : grid_( grid ), p_( p ), use_p_( true ) {} + IterateXY( const Grid& grid ) : grid_( grid ) {} + iterator begin() const; + iterator end() const; + +private: + const Grid& grid_; + Predicate p_; + bool use_p_{false}; +}; + +class IterateLonLat { +public: + using iterator = IteratorLonLat; + using const_iterator = iterator; + using Grid = detail::grid::Grid; + +public: + IterateLonLat( const Grid& grid ) : grid_( grid ) {} + iterator begin() const; + iterator end() const; + +private: + const Grid& grid_; +}; + } // namespace grid } // namespace atlas diff --git a/src/atlas/grid/Partitioner.cc b/src/atlas/grid/Partitioner.cc index 83c3b7f67..f8d469543 100644 --- a/src/atlas/grid/Partitioner.cc +++ b/src/atlas/grid/Partitioner.cc @@ -9,9 +9,15 @@ */ #include "atlas/grid/Partitioner.h" +#include "atlas/grid/Distribution.h" +#include "atlas/grid/Grid.h" +#include "atlas/grid/detail/distribution/DistributionImpl.h" #include "atlas/grid/detail/partitioner/Partitioner.h" +#include "atlas/mesh/Mesh.h" #include "atlas/parallel/mpi/mpi.h" +#include "atlas/runtime/Exception.h" #include "atlas/runtime/Trace.h" +#include "atlas/util/Config.h" namespace atlas { namespace grid { @@ -22,29 +28,38 @@ bool Partitioner::exists( const std::string& type ) { return Factory::has( type ); } -Partitioner::Partitioner( const detail::partitioner::Partitioner* partitioner ) : partitioner_( partitioner ) {} +Partitioner::Partitioner( const std::string& type ) : Handle( Factory::build( type ) ) {} -Partitioner::Partitioner( const std::string& type ) : partitioner_( Factory::build( type ) ) {} - -Partitioner::Partitioner( const std::string& type, const size_t nb_partitions ) : - partitioner_( Factory::build( type, nb_partitions ) ) {} +Partitioner::Partitioner( const std::string& type, const idx_t nb_partitions ) : + Handle( Factory::build( type, nb_partitions ) ) {} namespace { detail::partitioner::Partitioner* partitioner_from_config( const Partitioner::Config& config ) { std::string type; long partitions = mpi::comm().size(); - if ( not config.get( "type", type ) ) - throw eckit::BadParameter( "'type' missing in configuration for Partitioner", Here() ); + if ( not config.get( "type", type ) ) throw_Exception( "'type' missing in configuration for Partitioner", Here() ); config.get( "partitions", partitions ); return Factory::build( type, partitions ); } } // namespace -Partitioner::Partitioner( const Config& config ) : partitioner_( partitioner_from_config( config ) ) {} +Partitioner::Partitioner( const Config& config ) : Handle( partitioner_from_config( config ) ) {} void Partitioner::partition( const Grid& grid, int part[] ) const { ATLAS_TRACE(); - partitioner_->partition( grid, part ); + get()->partition( grid, part ); +} + +Distribution Partitioner::partition( const Grid& grid ) const { + return Distribution( grid, *this ); +} + +idx_t Partitioner::nb_partitions() const { + return get()->nb_partitions(); +} + +std::string Partitioner::type() const { + return get()->type(); } MatchingMeshPartitioner::MatchingMeshPartitioner() : Partitioner() {} @@ -56,6 +71,10 @@ grid::detail::partitioner::Partitioner* matching_mesh_partititioner( const Mesh& return MatchedPartitionerFactory::build( type, mesh ); } +MatchingMeshPartitioner::MatchingMeshPartitioner( const Mesh& mesh ) : + MatchingMeshPartitioner( mesh, util::NoConfig() ) {} + + MatchingMeshPartitioner::MatchingMeshPartitioner( const Mesh& mesh, const Config& config ) : Partitioner( matching_mesh_partititioner( mesh, config ) ) {} @@ -84,12 +103,12 @@ detail::partitioner::Partitioner* atlas__grid__MatchingMeshPartitioner__new( con return p; } -Distribution::impl_t* atlas__grid__Partitioner__partition( const Partitioner::Implementation* This, - const Grid::Implementation* grid ) { - Distribution::impl_t* d; +Distribution::Implementation* atlas__grid__Partitioner__partition( const Partitioner::Implementation* This, + const Grid::Implementation* grid ) { + Distribution::Implementation* d; { Distribution distribution = This->partition( Grid( grid ) ); - d = const_cast( distribution.get() ); + d = const_cast( distribution.get() ); d->attach(); } d->detach(); diff --git a/src/atlas/grid/Partitioner.h b/src/atlas/grid/Partitioner.h index 6ba0b0683..16da8246c 100644 --- a/src/atlas/grid/Partitioner.h +++ b/src/atlas/grid/Partitioner.h @@ -10,18 +10,56 @@ #pragma once -#include "eckit/memory/SharedPtr.h" +#include -#include "atlas/grid/Distribution.h" -#include "atlas/grid/Grid.h" -#include "atlas/grid/detail/partitioner/Partitioner.h" + +#include "atlas/library/config.h" +#include "atlas/util/ObjectHandle.h" + +namespace eckit { +class Parametrisation; +} + +namespace atlas { +class Grid; +class Mesh; +namespace grid { +class Distribution; +class DistributionImpl; + +namespace detail { +namespace partitioner { +class Partitioner; +} // namespace partitioner +} // namespace detail +} // namespace grid +} // namespace atlas + +namespace atlas { +namespace mesh { +namespace detail { +class MeshImpl; +} +} // namespace mesh +} // namespace atlas + +namespace atlas { +namespace grid { +namespace detail { +namespace grid { +class Grid; +} // namespace grid +} // namespace detail +} // namespace grid +using GridImpl = grid::detail::grid::Grid; +} // namespace atlas namespace atlas { namespace grid { // ------------------------------------------------------------------ -class Partitioner { +class Partitioner : public util::ObjectHandle { public: using Config = eckit::Parametrisation; using Implementation = detail::partitioner::Partitioner; @@ -30,26 +68,19 @@ class Partitioner { static bool exists( const std::string& type ); public: - Partitioner() {} - Partitioner( const Implementation* ); + using Handle::Handle; + Partitioner() = default; Partitioner( const std::string& type ); - Partitioner( const std::string& type, const size_t nb_partitions ); + Partitioner( const std::string& type, const idx_t nb_partitions ); Partitioner( const Config& ); - operator bool() const { return partitioner_; } - void partition( const Grid& grid, int part[] ) const; - Distribution partition( const Grid& grid ) const { return Distribution( grid, *this ); } - - size_t nb_partitions() const { return partitioner_->nb_partitions(); } - - std::string type() const { return partitioner_->type(); } + Distribution partition( const Grid& grid ) const; - Implementation const* get() const { return partitioner_.get(); } + idx_t nb_partitions() const; -private: - eckit::SharedPtr partitioner_; + std::string type() const; }; // ------------------------------------------------------------------ @@ -63,18 +94,18 @@ class MatchingMeshPartitioner : public Partitioner { public: MatchingMeshPartitioner(); - MatchingMeshPartitioner( const Mesh& mesh, const Config& config = util::NoConfig() ); + MatchingMeshPartitioner( const Mesh& mesh ); + MatchingMeshPartitioner( const Mesh& mesh, const Config& config ); }; // ------------------------------------------------------------------ extern "C" { Partitioner::Implementation* atlas__grid__Partitioner__new( const Partitioner::Config* config ); -Partitioner::Implementation* atlas__grid__MatchingMeshPartitioner__new( const Mesh::Implementation* mesh, +Partitioner::Implementation* atlas__grid__MatchingMeshPartitioner__new( const mesh::detail::MeshImpl* mesh, const Partitioner::Config* config ); void atlas__grid__Partitioner__delete( Partitioner::Implementation* This ); -Distribution::impl_t* atlas__grid__Partitioner__partition( const Partitioner::Implementation* This, - const Grid::Implementation* grid ); +DistributionImpl* atlas__grid__Partitioner__partition( const Partitioner::Implementation* This, const GridImpl* grid ); } } // namespace grid diff --git a/src/atlas/grid/Spacing.cc b/src/atlas/grid/Spacing.cc index 557c7dd9f..1c756bb16 100644 --- a/src/atlas/grid/Spacing.cc +++ b/src/atlas/grid/Spacing.cc @@ -11,17 +11,57 @@ #include "atlas/grid/Spacing.h" #include "atlas/grid/detail/spacing/GaussianSpacing.h" #include "atlas/grid/detail/spacing/LinearSpacing.h" +#include "atlas/grid/detail/spacing/Spacing.h" +#include "atlas/util/Config.h" namespace atlas { namespace grid { -Spacing::Spacing() : spacing_( nullptr ) {} +Spacing::Spacing( const eckit::Parametrisation& p ) : Handle( atlas::grid::spacing::Spacing::create( p ) ) {} -Spacing::Spacing( const Spacing& other ) : spacing_( other.spacing_ ) {} +size_t Spacing::size() const { + return get()->size(); +} -Spacing::Spacing( const spacing::Spacing* spacing ) : spacing_( spacing ) {} +double Spacing::operator[]( size_t i ) const { + return get()->operator[]( i ); +} -Spacing::Spacing( const eckit::Parametrisation& p ) : spacing_( atlas::grid::spacing::Spacing::create( p ) ) {} +Spacing::const_iterator Spacing::begin() const { + return get()->begin(); +} + +Spacing::const_iterator Spacing::end() const { + return get()->end(); +} + +double Spacing::front() const { + return get()->front(); +} + +double Spacing::back() const { + return get()->back(); +} + +Spacing::Interval Spacing::interval() const { + return get()->interval(); +} + +double Spacing::min() const { + return get()->min(); +} + +double Spacing::max() const { + return get()->max(); +} + +std::string Spacing::type() const { + return get()->type(); +} + +Spacing::Spec Spacing::spec() const { + return get()->spec(); +} LinearSpacing::LinearSpacing( double start, double stop, long N, bool endpoint ) : Spacing( new atlas::grid::spacing::LinearSpacing( start, stop, N, endpoint ) ) {} diff --git a/src/atlas/grid/Spacing.h b/src/atlas/grid/Spacing.h index 3439a4d08..94aa6943d 100644 --- a/src/atlas/grid/Spacing.h +++ b/src/atlas/grid/Spacing.h @@ -10,10 +10,10 @@ #pragma once -#include "eckit/memory/SharedPtr.h" +#include +#include -#include "atlas/grid/detail/spacing/Spacing.h" -#include "atlas/util/Config.h" +#include "atlas/util/ObjectHandle.h" //--------------------------------------------------------------------------------------------------------------------- @@ -21,7 +21,16 @@ namespace eckit { class Parametrisation; } - +namespace atlas { +namespace util { +class Config; +} +namespace grid { +namespace spacing { +class Spacing; +} +} // namespace grid +} // namespace atlas //--------------------------------------------------------------------------------------------------------------------- namespace atlas { @@ -29,46 +38,35 @@ namespace grid { //--------------------------------------------------------------------------------------------------------------------- -class Spacing { +class Spacing : public util::ObjectHandle { public: - using Implementation = atlas::grid::spacing::Spacing; - using const_iterator = Implementation::const_iterator; - using Interval = Implementation::Interval; - using Spec = Implementation::Spec; + using const_iterator = std::vector::const_iterator; + using Interval = std::array; + using Spec = atlas::util::Config; public: - Spacing(); - Spacing( const Spacing& ); - Spacing( const atlas::grid::spacing::Spacing* ); + using Handle::Handle; + Spacing() = default; Spacing( const eckit::Parametrisation& ); - operator bool() const { return spacing_; } - - operator const atlas::grid::spacing::Spacing*() { return spacing_.get(); } - - size_t size() const { return spacing_.get()->size(); } - - double operator[]( size_t i ) const { return spacing_.get()->operator[]( i ); } - - const_iterator begin() const { return spacing_.get()->begin(); } - const_iterator end() const { return spacing_.get()->end(); } + size_t size() const; - double front() const { return spacing_.get()->front(); } - double back() const { return spacing_.get()->back(); } + double operator[]( size_t i ) const; - Interval interval() const { return spacing_.get()->interval(); } + const_iterator begin() const; + const_iterator end() const; - double min() const { return spacing_.get()->min(); } - double max() const { return spacing_.get()->max(); } + double front() const; + double back() const; - std::string type() const { return spacing_.get()->type(); } + Interval interval() const; - Spec spec() const { return spacing_.get()->spec(); } + double min() const; + double max() const; - const atlas::grid::spacing::Spacing* get() const { return spacing_.get(); } + std::string type() const; -private: - eckit::SharedPtr spacing_; + Spec spec() const; }; //--------------------------------------------------------------------------------------------------------------------- @@ -78,6 +76,7 @@ class LinearSpacing : public Spacing { using Interval = std::array; public: + using Spacing::Spacing; LinearSpacing( double start, double stop, long N, bool endpoint = true ); LinearSpacing( const Interval&, long N, bool endpoint = true ); }; @@ -86,6 +85,7 @@ class LinearSpacing : public Spacing { class GaussianSpacing : public Spacing { public: + using Spacing::Spacing; GaussianSpacing( long N ); }; diff --git a/src/atlas/grid/Stencil.h b/src/atlas/grid/Stencil.h new file mode 100644 index 000000000..442cef8a1 --- /dev/null +++ b/src/atlas/grid/Stencil.h @@ -0,0 +1,73 @@ +/* + * (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 +#include "atlas/library/config.h" + +namespace atlas { + +//--------------------------------------------------------------------------------------------------------------------- + +template +class HorizontalStencil { + friend class ComputeHorizontalStencil; + std::array i_begin_; + idx_t j_begin_; + +public: + idx_t i( idx_t offset_i, idx_t offset_j ) const { return i_begin_[offset_j] + offset_i; } + idx_t j( idx_t offset ) const { return j_begin_ + offset; } + constexpr idx_t width() const { return StencilWidth; } +}; + +//----------------------------------------------------------------------------- + +template +class VerticalStencil { + friend class ComputeVerticalStencil; + idx_t k_begin_; + idx_t k_interval_; + // within the stencil, a point falls in a certain interval. + // e.g. for a cubic stencil: + // + |-----|-----|-----| --> k_interval_ = -1 + // |--+--|-----|-----| --> k_interval_ = 0 + // |-----|--+--|-----| --> k_interval_ = 1 (the centred case) + // |-----|-----|--+--| --> k_interval_ = 2 + // |-----|-----|-----| + --> k_interval_ = 3 +public: + idx_t k( idx_t offset ) const { return k_begin_ + offset; } + constexpr idx_t width() const { return StencilWidth; } + idx_t k_interval() const { return k_interval_; } +}; + +//----------------------------------------------------------------------------- + +template +class Stencil3D { + friend class ComputeHorizontalStencil; + friend class ComputeVerticalStencil; + std::array i_begin_; + idx_t j_begin_; + idx_t k_begin_; + idx_t k_interval_; + +public: + idx_t i( idx_t offset_i, idx_t offset_j ) const { return i_begin_[offset_j] + offset_i; } + idx_t j( idx_t offset ) const { return j_begin_ + offset; } + idx_t k( idx_t offset ) const { return k_begin_ + offset; } + constexpr idx_t width() const { return StencilWidth; } + idx_t k_interval() const { return k_interval_; } +}; + +//--------------------------------------------------------------------------------------------------------------------- + +} // namespace atlas diff --git a/src/atlas/grid/StencilComputer.cc b/src/atlas/grid/StencilComputer.cc new file mode 100644 index 000000000..c1ac3c90b --- /dev/null +++ b/src/atlas/grid/StencilComputer.cc @@ -0,0 +1,110 @@ +/* + * (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/StencilComputer.h" +#include "atlas/grid/StructuredGrid.h" +#include "atlas/runtime/Exception.h" + +namespace atlas { + +ComputeLower::ComputeLower( const Vertical& z ) { + nlev_ = z.size(); + z_.resize( nlev_ ); + double dz = std::numeric_limits::max(); + constexpr double tol = 1.e-12; + ATLAS_ASSERT( dz > 0 ); + for ( idx_t jlev = 0; jlev < nlev_; ++jlev ) { + if ( jlev + 1 < nlev_ ) { dz = std::min( dz, z[jlev + 1] - z[jlev] ); } + z_[jlev] = z[jlev] - tol; + } + + nlevaux_ = static_cast( std::round( 2. * ( z.max() - z.min() ) / dz + 0.5 ) + 1 ); + rlevaux_ = double( nlevaux_ ); + nvaux_.resize( nlevaux_ + 1 ); + double dzaux = ( z.max() - z.min() ) / rlevaux_; + + idx_t iref = 0; + for ( idx_t jlevaux = 0; jlevaux <= nlevaux_; ++jlevaux ) { + if ( iref + 1 < nlev_ && jlevaux * dzaux >= z[iref + 1] ) { ++iref; } + nvaux_[jlevaux] = iref; + } +} + +ComputeNorth::ComputeNorth( const StructuredGrid& grid, idx_t halo ) { + ATLAS_ASSERT( grid ); + if ( not grid.domain().global() ) { throw_NotImplemented( "Only implemented for global grids", Here() ); } + halo_ = halo; + ny_ = grid.ny(); + y_.resize( ny_ + 2 * halo_ ); + ATLAS_ASSERT( halo_ < ny_ ); + idx_t north_pole_included = 90. - std::abs( grid.y().front() ) < tol(); + idx_t south_pole_included = 90. - std::abs( grid.y().back() ) < tol(); + + for ( idx_t j = -halo_; j < 0; ++j ) { + idx_t jj = -j - 1 + north_pole_included; + y_[halo_ + j] = 180. - grid.y( jj ) + tol(); + } + for ( idx_t j = 0; j < ny_; ++j ) { + y_[halo_ + j] = grid.y( j ) + tol(); + } + for ( idx_t j = ny_; j < ny_ + halo_; ++j ) { + idx_t jj = 2 * ny_ - j - 1 - south_pole_included; + y_[halo_ + j] = -180. - grid.y( jj ) + tol(); + } + dy_ = std::abs( grid.y( 1 ) - grid.y( 0 ) ); +} + +ComputeWest::ComputeWest( const StructuredGrid& grid, idx_t halo ) { + ATLAS_ASSERT( grid ); + if ( not grid.domain().global() ) { throw_NotImplemented( "Only implemented for global grids", Here() ); } + halo_ = halo; + idx_t north_pole_included = 90. - std::abs( grid.y().front() ) < tol(); + idx_t south_pole_included = 90. - std::abs( grid.y().back() ) < tol(); + ny_ = grid.ny(); + dx.resize( ny_ + 2 * halo_ ); + xref.resize( ny_ + 2 * halo_ ); + for ( idx_t j = -halo_; j < 0; ++j ) { + idx_t jj = -j - 1 + north_pole_included; + dx[halo_ + j] = grid.x( 1, jj ) - grid.x( 0, jj ); + xref[halo_ + j] = grid.x( 0, jj ) - tol(); + } + for ( idx_t j = 0; j < ny_; ++j ) { + dx[halo_ + j] = std::abs( grid.x( 1, j ) - grid.x( 0, j ) ); + xref[halo_ + j] = grid.x( 0, j ) - tol(); + } + for ( idx_t j = ny_; j < ny_ + halo_; ++j ) { + idx_t jj = 2 * ny_ - j - 1 - south_pole_included; + dx[halo_ + j] = std::abs( grid.x( 1, jj ) - grid.x( 0, jj ) ); + xref[halo_ + j] = grid.x( 0, jj ) - tol(); + } +} + +ComputeHorizontalStencil::ComputeHorizontalStencil( const StructuredGrid& grid, idx_t stencil_width ) : + halo_( ( stencil_width + 1 ) / 2 ), + compute_north_( grid, halo_ ), + compute_west_( grid, halo_ ), + stencil_width_( stencil_width ) { + stencil_begin_ = stencil_width_ - idx_t( double( stencil_width_ ) / 2. + 1. ); +} + +ComputeVerticalStencil::ComputeVerticalStencil( const Vertical& vertical, idx_t stencil_width ) : + compute_lower_( vertical ), + stencil_width_( stencil_width ) { + stencil_begin_ = stencil_width_ - idx_t( double( stencil_width_ ) / 2. + 1. ); + clip_begin_ = 0; + clip_end_ = vertical.size(); + vertical_min_ = vertical[clip_begin_]; + vertical_max_ = vertical[clip_end_ - 1]; +} + + +//--------------------------------------------------------------------------------------------------------------------- + +} // namespace atlas diff --git a/src/atlas/grid/StencilComputer.h b/src/atlas/grid/StencilComputer.h new file mode 100644 index 000000000..1fd7c9792 --- /dev/null +++ b/src/atlas/grid/StencilComputer.h @@ -0,0 +1,209 @@ +/* + * (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 +#include + +#include "atlas/grid/Vertical.h" +#include "atlas/library/config.h" +#include "atlas/runtime/Exception.h" + +namespace atlas { +class StructuredGrid; +} // namespace atlas + +namespace atlas { + +//--------------------------------------------------------------------------------------------------------------------- +/// @class ComputeVertical +/// @brief Compute lower vertical level index for given coordinate +/// zcoord: +/// @verbatim +/// 0----1----2----3--...--(n-1)----(n)----(n+1) +/// --->|<---|<---|<--...-|<-------------------- +/// @endverbatim +/// If coordinate falls on vertical level (+- epsilon), that level is returned +/// If coordinate falls in range [0,1) or [n,n+1], +/// the index is snapped to 1 and (n-1) respectively. This allows reliably that +/// the returned index can be used for stencil operations. +/// +/// IFS full levels don't have a level at the boundaries (0.,1.) +/// It is the "half" levels that contain (0.,1.). For reasons of boundary conditions +/// however, the full levels also have 0. prepended and 1. appended. +/// +/// Example IFS full levels for regular distribution dz ( level 0 and n+1 are added for boundary conditions ) +/// 0 : 0.0 +/// jlev : jlev*dz - 0.5*dz +/// nlev : nlev*dz - 0.5*dz +/// nlev+1 : 1.0 + +class ComputeLower { + std::vector z_; + std::vector nvaux_; + idx_t nlev_; + idx_t nlevaux_; + double rlevaux_; + +public: + ComputeLower() = default; + + ComputeLower( const Vertical& z ); + + idx_t operator()( double z ) const { + idx_t idx = static_cast( std::floor( z * rlevaux_ ) ); +#ifndef NDEBUG + ATLAS_ASSERT( idx < static_cast( nvaux_.size() ) && idx >= 0 ); +#endif + idx = nvaux_[idx]; + if ( idx < nlev_ - 1 && z > z_[idx + 1] ) { ++idx; } + return idx; + } +}; + +//----------------------------------------------------------------------------- + +class ComputeNorth { + std::vector y_; + double dy_; + idx_t halo_; + idx_t ny_; + static constexpr double tol() { return 0.5e-6; } + +public: + ComputeNorth() = default; + + ComputeNorth( const StructuredGrid& grid, idx_t halo ); + + idx_t operator()( double y ) const { + idx_t j = static_cast( std::floor( ( y_[halo_ + 0] - y ) / dy_ ) ); + j = std::max( halo_, std::min( j, halo_ + ny_ - 1 ) ); + while ( y_[halo_ + j] > y ) { + ++j; + } + do { + --j; + } while ( y_[halo_ + j] < y ); + + return j; + } +}; + +//----------------------------------------------------------------------------- + +class ComputeWest { + std::vector dx; + std::vector xref; + idx_t halo_; // halo in north-south direction + idx_t ny_; + static constexpr double tol() { return 0.5e-6; } + +public: + ComputeWest() = default; + + ComputeWest( const StructuredGrid& grid, idx_t halo = 0 ); + + idx_t operator()( const double& x, idx_t j ) const { + idx_t jj = halo_ + j; + idx_t i = static_cast( std::floor( ( x - xref[jj] ) / dx[jj] ) ); + return i; + } +}; // namespace test + + +//----------------------------------------------------------------------------- + +// @class ComputeHorizontalStencil +// @brief Compute stencil in horizontal direction (i,j) +// +// Given a stencil width, the stencil for a given P{x,y} is: +// +// i[0] i[1] i[2] i[3] +// x x x x j + 0 +// x x x x j + 1 +// P +// x x x x j + 2 +// x x x x j + 3 +// +// In case the x-component of P is aligned with any +// stencil, gridpoint, the stencil will assume the grid point +// is on the point P's left side: +// +// i[0] i[1] i[2] i[3] +// x x x x j + 0 +// x x x x j + 1 +// P +// x x x x j + 2 +// x x x x j + 3 + +class ComputeHorizontalStencil { + idx_t halo_; + ComputeNorth compute_north_; + ComputeWest compute_west_; + idx_t stencil_width_; + idx_t stencil_begin_; + +public: + ComputeHorizontalStencil() = default; + + ComputeHorizontalStencil( const StructuredGrid& grid, idx_t stencil_width ); + + template + void operator()( const double& x, const double& y, stencil_t& stencil ) const { + stencil.j_begin_ = compute_north_( y ) - stencil_begin_; + for ( idx_t jj = 0; jj < stencil_width_; ++jj ) { + stencil.i_begin_[jj] = compute_west_( x, stencil.j_begin_ + jj ) - stencil_begin_; + } + } +}; + + +//----------------------------------------------------------------------------- + +class ComputeVerticalStencil { + ComputeLower compute_lower_; + idx_t stencil_width_; + idx_t stencil_begin_; + + idx_t clip_begin_; + idx_t clip_end_; + double vertical_min_; + double vertical_max_; + +public: + ComputeVerticalStencil() = default; + + ComputeVerticalStencil( const Vertical& vertical, idx_t stencil_width ); + + template + void operator()( const double& z, stencil_t& stencil ) const { + idx_t k_begin = compute_lower_( z ) - stencil_begin_; + idx_t k_end = k_begin + stencil_width_; + idx_t move = 0; + + if ( k_begin < clip_begin_ ) { + move = k_begin - clip_begin_; + if ( z < vertical_min_ ) { + --k_begin; + --move; + } + } + else if ( k_end > clip_end_ ) { + move = k_end - clip_end_; + } + stencil.k_begin_ = k_begin - move; + stencil.k_interval_ = stencil_begin_ + move; + } +}; + +//--------------------------------------------------------------------------------------------------------------------- + +} // namespace atlas diff --git a/src/atlas/grid/StructuredGrid.cc b/src/atlas/grid/StructuredGrid.cc new file mode 100644 index 000000000..4551df89b --- /dev/null +++ b/src/atlas/grid/StructuredGrid.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 "atlas/grid/Grid.h" + +#include +#include +#include + +#include "eckit/config/Parametrisation.h" + +#include "atlas/domain/Domain.h" +#include "atlas/grid/Grid.h" +#include "atlas/grid/Spacing.h" +#include "atlas/grid/StructuredGrid.h" +#include "atlas/grid/detail/grid/Gaussian.h" +#include "atlas/projection/Projection.h" +#include "atlas/util/Config.h" + +namespace atlas { + +inline const StructuredGrid::grid_t* structured_grid( const Grid::Implementation* grid ) { + return dynamic_cast( grid ); +} + +StructuredGrid::StructuredGrid() : Grid(), grid_( nullptr ) {} + +StructuredGrid::StructuredGrid( const Grid& grid ) : Grid( grid ), grid_( structured_grid( get() ) ) {} + +StructuredGrid::StructuredGrid( const Grid::Implementation* grid ) : Grid( grid ), grid_( structured_grid( get() ) ) {} + +StructuredGrid::StructuredGrid( const std::string& grid, const Domain& domain ) : + Grid( grid, domain ), + grid_( structured_grid( get() ) ) {} + +StructuredGrid::StructuredGrid( const Config& grid ) : Grid( grid ), grid_( structured_grid( get() ) ) {} + +StructuredGrid::StructuredGrid( const XSpace& xspace, const YSpace& yspace, const Projection& projection, + const Domain& domain ) : + Grid( new StructuredGrid::grid_t( xspace, yspace, projection, domain ) ), + grid_( structured_grid( get() ) ) {} + +StructuredGrid::StructuredGrid( const Grid& grid, const Grid::Domain& domain ) : + Grid( grid, domain ), + grid_( structured_grid( get() ) ) {} + +ReducedGaussianGrid::ReducedGaussianGrid( const std::vector& nx, const Domain& domain ) : + ReducedGaussianGrid::grid_t( grid::detail::grid::reduced_gaussian( nx, domain ) ) {} + +ReducedGaussianGrid::ReducedGaussianGrid( const std::vector& nx, const Domain& domain ) : + ReducedGaussianGrid::grid_t( grid::detail::grid::reduced_gaussian( nx, domain ) ) {} + +ReducedGaussianGrid::ReducedGaussianGrid( const std::initializer_list& nx ) : + ReducedGaussianGrid( std::vector( nx ) ) {} + +RegularGaussianGrid::RegularGaussianGrid( int N, const Grid::Domain& domain ) : + RegularGaussianGrid::grid_t( "F" + std::to_string( N ), domain ) {} + +} // namespace atlas diff --git a/src/atlas/grid/StructuredGrid.h b/src/atlas/grid/StructuredGrid.h new file mode 100644 index 000000000..38b239643 --- /dev/null +++ b/src/atlas/grid/StructuredGrid.h @@ -0,0 +1,242 @@ +/* + * (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 +#include +#include + +#include "atlas/grid/Grid.h" +#include "atlas/grid/detail/grid/Structured.h" + + +namespace atlas { + +//--------------------------------------------------------------------------------------------------------------------- +class StructuredGrid; +class RegularGrid; +class GaussianGrid; +class ReducedGaussianGrid; +class RegularGaussianGrid; +class RegularLonLatGrid; +class ShiftedLonLatGrid; + +/* + Grid + | + +----------+----------+ + | | + StructuredGrid UnstructuredGrid + | + +--------------------+-----------------------+ + | | | + ReducedGrid GaussianGrid RegularGrid + | | | | | + +--------+--------+ +--------+--------+ +-----+ + | | | + ReducedGaussianGrid RegularGaussianGrid RegularLonLatGrid +*/ + +//--------------------------------------------------------------------------------------------------------------------- + +class StructuredGrid : public Grid { +public: + using grid_t = grid::detail::grid::Structured; + using XSpace = grid_t::XSpace; + using YSpace = grid_t::YSpace; + +public: + StructuredGrid(); + StructuredGrid( const Grid& ); + StructuredGrid( const Grid::Implementation* ); + StructuredGrid( const std::string& name, const Domain& = Domain() ); + StructuredGrid( const Config& ); + StructuredGrid( const XSpace&, const YSpace&, const Projection& = Projection(), const Domain& = Domain() ); + StructuredGrid( const Grid&, const Domain& ); + + operator bool() const { return valid(); } + + bool valid() const { return grid_; } + + inline idx_t ny() const { return grid_->ny(); } + + inline idx_t nx( idx_t j ) const { return grid_->nx( j ); } + + inline const std::vector& nx() const { return grid_->nx(); } + + inline idx_t nxmax() const { return grid_->nxmax(); } + + inline const std::vector& y() const { return grid_->y(); } + + inline double x( idx_t i, idx_t j ) const { return grid_->x( i, j ); } + + inline double y( idx_t j ) const { return grid_->y( j ); } + + using Grid::xy; + void xy( idx_t i, idx_t j, double xy[] ) const { grid_->xy( i, j, xy ); } + + void lonlat( idx_t i, idx_t j, double lonlat[] ) const { grid_->lonlat( i, j, lonlat ); } + + PointXY xy( idx_t i, idx_t j ) const { return PointXY( x( i, j ), y( j ) ); } + + PointLonLat lonlat( idx_t i, idx_t j ) const { return grid_->lonlat( i, j ); } + + inline bool reduced() const { return grid_->reduced(); } + + inline bool regular() const { return not reduced(); } + + bool periodic() const { return grid_->periodic(); } + + const XSpace& xspace() const { return grid_->xspace(); } + + const YSpace& yspace() const { return grid_->yspace(); } + +private: + const grid_t* grid_; +}; + +//--------------------------------------------------------------------------------------------------------------------- + +class ReducedGrid : public StructuredGrid { +public: + using StructuredGrid::StructuredGrid; + + operator bool() const { return valid(); } + + bool valid() const { return StructuredGrid::valid() && reduced(); } +}; + +//--------------------------------------------------------------------------------------------------------------------- + +class RegularGrid : public StructuredGrid { +public: + using StructuredGrid::StructuredGrid; + using StructuredGrid::x; + using StructuredGrid::xy; + + operator bool() const { return valid(); } + + bool valid() const { return StructuredGrid::valid() && regular(); } + + idx_t nx() const { return nxmax(); } + + inline double x( idx_t i ) const { return x( i, 0 ); } + + PointXY xy( idx_t i, idx_t j ) const { return PointXY( x( i ), y( j ) ); } +}; + +//--------------------------------------------------------------------------------------------------------------------- + +template +class Gaussian : public Grid { +public: + using Grid::Grid; + + idx_t N() const { return Grid::ny() / 2; } + + inline double lon( idx_t i, idx_t j ) const { return Grid::x( i, j ); } + + inline double lat( idx_t j ) const { return Grid::y( j ); } + + PointLonLat lonlat( idx_t i, idx_t j ) const { return Grid::xy( i, j ); } + +protected: + bool gaussian() const { + return Grid::domain().global() && not Grid::projection() && Grid::yspace().type() == "gaussian"; + } +}; + +//--------------------------------------------------------------------------------------------------------------------- + +class GaussianGrid : public Gaussian { + using grid_t = Gaussian; + +public: + using grid_t::grid_t; + + operator bool() const { return valid(); } + + bool valid() const { return StructuredGrid::valid() && gaussian(); } +}; + +//--------------------------------------------------------------------------------------------------------------------- + +class ReducedGaussianGrid : public Gaussian { + using grid_t = Gaussian; + +public: + using grid_t::grid_t; + ReducedGaussianGrid( const std::initializer_list& pl ); + ReducedGaussianGrid( const std::vector& pl, const Domain& = Domain() ); + ReducedGaussianGrid( const std::vector& pl, const Domain& = Domain() ); + + operator bool() const { return valid(); } + + bool valid() const { return ReducedGrid::valid() && gaussian(); } +}; + +//--------------------------------------------------------------------------------------------------------------------- + +class RegularGaussianGrid : public Gaussian { + using grid_t = Gaussian; + +public: + using grid_t::grid_t; + RegularGaussianGrid( int N, const Domain& = Domain() ); + + inline double lon( idx_t i ) const { return x( i ); } + + inline double lat( idx_t j ) const { return y( j ); } + + PointLonLat lonlat( idx_t i, idx_t j ) const { return xy( i, j ); } + + operator bool() const { return valid(); } + + bool valid() const { return RegularGrid::valid() && gaussian(); } +}; + +//--------------------------------------------------------------------------------------------------------------------- + +class RegularLonLatGrid : public RegularGrid { +public: + using RegularGrid::RegularGrid; + +public: + operator bool() const { return valid(); } + + bool valid() const { return RegularGrid::valid() && global_lonlat(); } + + inline double lon( idx_t i ) const { return x( i ); } + + inline double lat( idx_t j ) const { return y( j ); } + + PointLonLat lonlat( idx_t i, idx_t j ) const { return xy( i, j ); } + + bool standard() const { return standard_lon() && standard_lat(); } + bool shifted() const { return shifted_lon() && shifted_lat(); } + bool shiftedLon() const { return shifted_lon() && standard_lat(); } + bool shiftedLat() const { return standard_lon() && shifted_lat(); } + +protected: + bool global_lonlat() const { return domain().global() && not projection() && yspace().type() == "linear"; } + + bool standard_lon() const { return x( 0 ) == 0.; } + + bool standard_lat() const { return y( 0 ) == 90. && ny() % 2 == 1; } + + bool shifted_lon() const { return x( 0 ) == 0.5 * 360. / nx(); } + + bool shifted_lat() const { return y( 0 ) == 90. - 0.5 * 180. / ny() && ny() % 2 == 0; } +}; + +//--------------------------------------------------------------------------------------------------------------------- + +} // namespace atlas diff --git a/src/atlas/grid/UnstructuredGrid.cc b/src/atlas/grid/UnstructuredGrid.cc new file mode 100644 index 000000000..283403ab2 --- /dev/null +++ b/src/atlas/grid/UnstructuredGrid.cc @@ -0,0 +1,57 @@ +/* + * (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/UnstructuredGrid.h" + +#include +#include +#include + +#include "eckit/config/Parametrisation.h" + +#include "atlas/domain/Domain.h" +#include "atlas/grid/Spacing.h" +#include "atlas/projection/Projection.h" +#include "atlas/util/Config.h" + +namespace atlas { + +inline const UnstructuredGrid::grid_t* unstructured_grid( const Grid::Implementation* grid ) { + return dynamic_cast( grid ); +} + +UnstructuredGrid::UnstructuredGrid() : Grid() {} + +UnstructuredGrid::UnstructuredGrid( const Grid& grid ) : Grid( grid ), grid_( unstructured_grid( get() ) ) {} + +UnstructuredGrid::UnstructuredGrid( const Grid::Implementation* grid ) : + Grid( grid ), + grid_( unstructured_grid( get() ) ) {} + +UnstructuredGrid::UnstructuredGrid( const Config& grid ) : Grid( grid ), grid_( unstructured_grid( get() ) ) {} + +UnstructuredGrid::UnstructuredGrid( std::vector* xy ) : + Grid( new UnstructuredGrid::grid_t( xy ) ), + grid_( unstructured_grid( get() ) ) {} + +UnstructuredGrid::UnstructuredGrid( std::vector&& xy ) : + Grid( new UnstructuredGrid::grid_t( std::forward>( xy ) ) ), + grid_( unstructured_grid( get() ) ) {} + +UnstructuredGrid::UnstructuredGrid( std::initializer_list xy ) : + Grid( new UnstructuredGrid::grid_t( xy ) ), + grid_( unstructured_grid( get() ) ) {} + +UnstructuredGrid::UnstructuredGrid( const Grid& grid, const Grid::Domain& domain ) : + Grid( new UnstructuredGrid::grid_t( *grid.get(), domain ) ), + grid_( unstructured_grid( get() ) ) {} + + +} // namespace atlas diff --git a/src/atlas/grid/UnstructuredGrid.h b/src/atlas/grid/UnstructuredGrid.h new file mode 100644 index 000000000..4801b1862 --- /dev/null +++ b/src/atlas/grid/UnstructuredGrid.h @@ -0,0 +1,72 @@ +/* + * (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 + +#include "atlas/grid/Grid.h" +#include "atlas/grid/detail/grid/Unstructured.h" + + +namespace atlas { + +//--------------------------------------------------------------------------------------------------------------------- +// Further grid interpretation classes defined in this file + +class UnstructuredGrid; + +/* + Grid + | + +----------+----------+ + | | + StructuredGrid UnstructuredGrid + +*/ + +//--------------------------------------------------------------------------------------------------------------------- + +class UnstructuredGrid : public Grid { +public: + using grid_t = grid::detail::grid::Unstructured; + +public: + UnstructuredGrid(); + UnstructuredGrid( const Grid& ); + UnstructuredGrid( const Config& ); + UnstructuredGrid( const Grid::Implementation* ); + UnstructuredGrid( std::vector* ); // takes ownership + UnstructuredGrid( std::initializer_list ); + UnstructuredGrid( const Grid&, const Domain& ); // Create a new unstructured grid! + + operator bool() const { return valid(); } + UnstructuredGrid( std::vector&& ); // move constructor + + bool valid() const { return grid_; } + + using Grid::xy; + void xy( idx_t n, double xy[] ) const { + PointXY _xy = grid_->xy( n ); + xy[0] = _xy.x(); + xy[1] = _xy.y(); + } + + PointXY xy( idx_t n ) const { return grid_->xy( n ); } + + PointLonLat lonlat( idx_t n ) const { return grid_->lonlat( n ); } + +private: + const grid_t* grid_; +}; + +//--------------------------------------------------------------------------------------------------------------------- + +} // namespace atlas diff --git a/src/atlas/grid/Vertical.cc b/src/atlas/grid/Vertical.cc new file mode 100644 index 000000000..289d677b9 --- /dev/null +++ b/src/atlas/grid/Vertical.cc @@ -0,0 +1,58 @@ +/* + * (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/Vertical.h" +#include "eckit/types/Types.h" + +namespace atlas { + +//--------------------------------------------------------------------------------------------------------------------- + +namespace { + +std::vector linspace( double start, double end, idx_t N, bool endpoint ) { + std::vector x_; + x_.resize( N ); + + double step; + if ( endpoint && N > 1 ) + step = ( end - start ) / double( N - 1 ); + else if ( N > 0 ) + step = ( end - start ) / double( N ); + else + step = 0.; + + for ( idx_t i = 0; i < N; ++i ) { + x_[i] = start + i * step; + } + return x_; +} + +idx_t get_levels( const util::Config& config ) { + return config.getInt( "levels", 0 ); +} + + +} // namespace + +//--------------------------------------------------------------------------------------------------------------------- + +Vertical::Vertical( const util::Config& config ) : + Vertical( get_levels( config ), linspace( 0., 1., get_levels( config ), true ), config ) {} + + +std::ostream& operator<<( std::ostream& os, const Vertical& v ) { + os << v.z_; + return os; +} + +//--------------------------------------------------------------------------------------------------------------------- + +} // namespace atlas diff --git a/src/atlas/grid/Vertical.h b/src/atlas/grid/Vertical.h new file mode 100644 index 000000000..1925184aa --- /dev/null +++ b/src/atlas/grid/Vertical.h @@ -0,0 +1,94 @@ +/* + * (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 +#include + +#include "atlas/library/config.h" +#include "atlas/util/Config.h" + +namespace atlas { + +//--------------------------------------------------------------------------------------------------------------------- + +class Vertical { +public: + template // expect "vector_t::size()" and "vector_t::operator[]" + Vertical( idx_t levels, const vector_t& z, const util::Config& config = util::NoConfig() ); + + template // expect "vector_t::size()" and "vector_t::operator[]" + Vertical( idx_t levels, const vector_t& z, const Interval& interval, + const util::Config& config = util::NoConfig() ); + + Vertical( const util::Config& config = util::NoConfig() ); + +public: + idx_t k_begin() const { return k_begin_; } + idx_t k_end() const { return k_end_; } + idx_t size() const { return size_; } + + template + double operator()( const Int k ) const { + return z_[k]; + } + + template + double operator[]( const Int k ) const { + return z_[k]; + } + + double min() const { return min_; } + double max() const { return max_; } + + double front() const { return z_.front(); } + double back() const { return z_.back(); } + + /// @brief Output information of field + friend std::ostream& operator<<( std::ostream& os, const Vertical& v ); + +private: + idx_t k_begin_; + idx_t k_end_; + idx_t size_; + std::vector z_; + double min_; + double max_; +}; + +//--------------------------------------------------------------------------------------------------------------------- + +template +Vertical::Vertical( idx_t levels, const vector_t& z, const Interval& interval, const util::Config& config ) : + Vertical( levels, z, config ) { + min_ = interval[0]; + max_ = interval[1]; +} + +//--------------------------------------------------------------------------------------------------------------------- + +template +Vertical::Vertical( idx_t levels, const vector_t& z, const util::Config& ) { + size_ = levels; + k_begin_ = 0; + k_end_ = size_; + assert( size_ == static_cast( z.size() ) ); + z_.resize( size_ ); + for ( idx_t k = 0; k < size_; ++k ) { + z_[k] = z[k]; + } + min_ = ( size_ ? z[0] : 0. ); + max_ = ( size_ ? z[size_ - 1] : 1. ); +} + +//--------------------------------------------------------------------------------------------------------------------- + +} // namespace atlas diff --git a/src/atlas/grid/detail/distribution/DistributionImpl.cc b/src/atlas/grid/detail/distribution/DistributionImpl.cc new file mode 100644 index 000000000..60c30f6aa --- /dev/null +++ b/src/atlas/grid/detail/distribution/DistributionImpl.cc @@ -0,0 +1,87 @@ +/* + * (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 "DistributionImpl.h" + +#include "atlas/grid/Grid.h" +#include "atlas/grid/Partitioner.h" +#include "atlas/parallel/mpi/mpi.h" +#include "atlas/runtime/Log.h" + +namespace atlas { +namespace grid { + +namespace { +std::string distribution_type( int N, const Partitioner& p = Partitioner() ) { + if ( N == 1 ) { return "serial"; } + if ( not p ) { return "custom"; } + return p.type(); +} +} // namespace + +DistributionImpl::DistributionImpl( const Grid& grid ) : + nb_partitions_( 1 ), + part_( grid.size(), 0 ), + nb_pts_( nb_partitions_, grid.size() ), + max_pts_( grid.size() ), + min_pts_( grid.size() ), + type_( distribution_type( nb_partitions_ ) ) {} + +DistributionImpl::DistributionImpl( const Grid& grid, const Partitioner& partitioner ) { + part_.resize( grid.size() ); + partitioner.partition( grid, part_.data() ); + nb_partitions_ = partitioner.nb_partitions(); + nb_pts_.resize( nb_partitions_, 0 ); + for ( idx_t j = 0, size = static_cast( part_.size() ); j < size; ++j ) + ++nb_pts_[part_[j]]; + max_pts_ = *std::max_element( nb_pts_.begin(), nb_pts_.end() ); + min_pts_ = *std::min_element( nb_pts_.begin(), nb_pts_.end() ); + type_ = distribution_type( nb_partitions_, partitioner ); +} + +DistributionImpl::DistributionImpl( idx_t npts, int part[], int part0 ) { + part_.assign( part, part + npts ); + std::set partset( part_.begin(), part_.end() ); + nb_partitions_ = static_cast( partset.size() ); + nb_pts_.resize( nb_partitions_, 0 ); + for ( idx_t j = 0, size = static_cast( part_.size() ); j < size; ++j ) { + part_[j] -= part0; + ++nb_pts_[part_[j]]; + } + max_pts_ = *std::max_element( nb_pts_.begin(), nb_pts_.end() ); + min_pts_ = *std::min_element( nb_pts_.begin(), nb_pts_.end() ); + type_ = distribution_type( nb_partitions_ ); +} + +DistributionImpl::~DistributionImpl() {} + +void DistributionImpl::print( std::ostream& s ) const { + s << "Distribution( " + << "type: " << type_ << ", nbPoints: " << part_.size() << ", nbPartitions: " << nb_pts_.size() << ", parts : ["; + for ( idx_t i = 0, size = static_cast( part_.size() ); i < size; i++ ) { + if ( i != 0 ) s << ','; + s << part_[i]; + } + s << ']'; +} + + +DistributionImpl* atlas__GridDistribution__new( idx_t npts, int part[], int part0 ) { + return new DistributionImpl( npts, part, part0 ); +} + +void atlas__GridDistribution__delete( DistributionImpl* This ) { + delete This; +} + +} // namespace grid +} // namespace atlas diff --git a/src/atlas/grid/detail/distribution/DistributionImpl.h b/src/atlas/grid/detail/distribution/DistributionImpl.h new file mode 100644 index 000000000..0e0c45b94 --- /dev/null +++ b/src/atlas/grid/detail/distribution/DistributionImpl.h @@ -0,0 +1,74 @@ +/* + * (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 +#include + +#include "atlas/util/Object.h" + +#include "atlas/library/config.h" + +namespace atlas { +class Grid; +namespace grid { +class Partitioner; +} +} // namespace atlas + +namespace atlas { +namespace grid { + +class DistributionImpl : public util::Object { +public: + DistributionImpl( const Grid& ); + + DistributionImpl( const Grid&, const Partitioner& ); + + DistributionImpl( idx_t npts, int partition[], int part0 = 0 ); + + virtual ~DistributionImpl(); + + int partition( const gidx_t gidx ) const { return part_[gidx]; } + + const std::vector& partition() const { return part_; } + + idx_t nb_partitions() const { return nb_partitions_; } + + operator const std::vector&() const { return part_; } + + const int* data() const { return part_.data(); } + + const std::vector& nb_pts() const { return nb_pts_; } + + idx_t max_pts() const { return max_pts_; } + idx_t min_pts() const { return min_pts_; } + + const std::string& type() const { return type_; } + + void print( std::ostream& ) const; + +private: + idx_t nb_partitions_; + std::vector part_; + std::vector nb_pts_; + idx_t max_pts_; + idx_t min_pts_; + std::string type_; +}; + +extern "C" { +DistributionImpl* atlas__GridDistribution__new( idx_t npts, int part[], int part0 ); +void atlas__GridDistribution__delete( DistributionImpl* This ); +} + +} // namespace grid +} // namespace atlas diff --git a/src/atlas/grid/detail/grid/Gaussian.cc b/src/atlas/grid/detail/grid/Gaussian.cc index 2452f4c93..dbaf517d5 100644 --- a/src/atlas/grid/detail/grid/Gaussian.cc +++ b/src/atlas/grid/detail/grid/Gaussian.cc @@ -1,7 +1,19 @@ +/* + * (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 "Gaussian.h" #include +#include #include +#include #include "eckit/utils/Translator.h" @@ -38,7 +50,7 @@ static Spacing yspace( const Grid::Config& grid ) { return Spacing( config ); } -static StructuredGrid::XSpace xspace( const std::vector& nx ) { +static StructuredGrid::XSpace xspace( const std::vector& nx ) { return StructuredGrid::XSpace( {0., 360.}, nx, false ); // XSpace( const std::array& interval, const std::vector& N, // bool endpoint=true ); @@ -83,7 +95,7 @@ static class classic_gaussian : public GridBuilder { virtual const Grid::Implementation* create( const Grid::Config& config ) const { long N; config.get( "N", N ); - std::vector nx( 2 * N ); + std::vector nx( 2 * N ); detail::pl::classic_gaussian::points_per_latitude_npole_spole( N, nx.data() ); return new StructuredGrid::grid_t( "N" + std::to_string( N ), xspace( nx ), yspace( config ), projection( config ), domain( config ) ); @@ -124,7 +136,7 @@ static class octahedral_gaussian : GridBuilder { long start = 20; config.get( "nx[0]", start ); - std::vector nx( 2 * N ); + std::vector nx( 2 * N ); for ( long j = 0; j < N; ++j ) { nx[j] = start + 4 * j; nx[2 * N - 1 - j] = nx[j]; @@ -164,7 +176,7 @@ static class regular_gaussian : GridBuilder { virtual const Grid::Implementation* create( const Grid::Config& config ) const { long N; config.get( "N", N ); - std::vector nx( 2 * N, 4 * N ); + std::vector nx( 2 * N, 4 * N ); return new StructuredGrid::grid_t( "F" + std::to_string( N ), xspace( nx ), yspace( config ), projection( config ), domain( config ) ); } @@ -193,7 +205,8 @@ StructuredGrid::grid_t* reduced_gaussian( const std::vector& nx ) { yspace.set( "end", -90.0 ); yspace.set( "N", nx.size() ); - return new StructuredGrid::grid_t( xspace( nx ), Spacing( yspace ), Projection(), Domain() ); + std::vector _nx( nx.begin(), nx.end() ); + return new StructuredGrid::grid_t( xspace( _nx ), Spacing( yspace ), Projection(), Domain() ); } StructuredGrid::grid_t* reduced_gaussian( const std::vector& nx, const Domain& domain ) { @@ -203,13 +216,36 @@ StructuredGrid::grid_t* reduced_gaussian( const std::vector& nx, const Dom yspace.set( "end", -90.0 ); yspace.set( "N", nx.size() ); - return new StructuredGrid::grid_t( xspace( nx ), Spacing( yspace ), Projection(), domain ); + std::vector _nx( nx.begin(), nx.end() ); + return new StructuredGrid::grid_t( xspace( _nx ), Spacing( yspace ), Projection(), domain ); +} + +StructuredGrid::grid_t* reduced_gaussian( const std::vector& nx ) { + Grid::Config yspace; + yspace.set( "type", "gaussian" ); + yspace.set( "start", 90.0 ); + yspace.set( "end", -90.0 ); + yspace.set( "N", nx.size() ); + + std::vector _nx( nx.begin(), nx.end() ); + return new StructuredGrid::grid_t( xspace( _nx ), Spacing( yspace ), Projection(), Domain() ); +} + +StructuredGrid::grid_t* reduced_gaussian( const std::vector& nx, const Domain& domain ) { + Grid::Config yspace; + yspace.set( "type", "gaussian" ); + yspace.set( "start", 90.0 ); + yspace.set( "end", -90.0 ); + yspace.set( "N", nx.size() ); + + std::vector _nx( nx.begin(), nx.end() ); + return new StructuredGrid::grid_t( xspace( _nx ), Spacing( yspace ), Projection(), domain ); } template -inline std::vector long_vector( Int nx, long ny ) { - std::vector _nx( ny ); - for ( long j = 0; j < ny; ++j ) { +inline std::vector idx_vector( Int nx, idx_t ny ) { + std::vector _nx( ny ); + for ( idx_t j = 0; j < ny; ++j ) { _nx[j] = nx[j]; } return _nx; @@ -218,11 +254,11 @@ inline std::vector long_vector( Int nx, long ny ) { extern "C" { StructuredGrid::grid_t* atlas__grid__reduced__ReducedGaussian_int( int nx[], long ny ) { - return reduced_gaussian( long_vector( nx, ny ) ); + return reduced_gaussian( idx_vector( nx, ny ) ); } StructuredGrid::grid_t* atlas__grid__reduced__ReducedGaussian_long( long nx[], long ny ) { - return reduced_gaussian( long_vector( nx, ny ) ); + return reduced_gaussian( idx_vector( nx, ny ) ); } } diff --git a/src/atlas/grid/detail/grid/Gaussian.h b/src/atlas/grid/detail/grid/Gaussian.h index 309af4ea6..d287b186d 100644 --- a/src/atlas/grid/detail/grid/Gaussian.h +++ b/src/atlas/grid/detail/grid/Gaussian.h @@ -1,6 +1,16 @@ +/* + * (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 "atlas/grid.h" +#include "atlas/grid/StructuredGrid.h" namespace atlas { namespace grid { @@ -10,6 +20,9 @@ namespace grid { StructuredGrid::grid_t* reduced_gaussian( const std::vector& nx ); StructuredGrid::grid_t* reduced_gaussian( const std::vector& nx, const Domain& domain ); +StructuredGrid::grid_t* reduced_gaussian( const std::vector& nx ); +StructuredGrid::grid_t* reduced_gaussian( const std::vector& nx, const Domain& domain ); + } // namespace grid } // namespace detail } // namespace grid diff --git a/src/atlas/grid/detail/grid/Grid.cc b/src/atlas/grid/detail/grid/Grid.cc index e65a65dc3..3590bd76c 100644 --- a/src/atlas/grid/detail/grid/Grid.cc +++ b/src/atlas/grid/detail/grid/Grid.cc @@ -12,12 +12,14 @@ #include -#include "eckit/memory/Factory.h" #include "eckit/utils/MD5.h" #include "atlas/grid.h" #include "atlas/grid/detail/grid/GridBuilder.h" +#include "atlas/grid/detail/grid/Structured.h" +#include "atlas/grid/detail/grid/Unstructured.h" #include "atlas/mesh/Mesh.h" +#include "atlas/runtime/Exception.h" #include "atlas/runtime/Log.h" namespace atlas { @@ -30,11 +32,7 @@ static void checkSizeOfPoint() { static_assert( sizeof( PointXY ) == 2 * sizeof( double ), "Grid requires size of Point to be 2*double" ); // runtime check - ASSERT( sizeof( PointXY ) == 2 * sizeof( double ) ); -} - -std::string Grid::className() { - return "atlas.Grid"; + ATLAS_ASSERT( sizeof( PointXY ) == 2 * sizeof( double ) ); } const Grid* Grid::create( const Config& config ) { @@ -52,12 +50,16 @@ const Grid* Grid::create( const Config& config ) { if ( name.size() ) { Log::info() << "name provided: " << name << std::endl; } if ( type.size() ) { Log::info() << "type provided: " << type << std::endl; } - if ( name.empty() && type.empty() ) { throw eckit::BadParameter( "no name or type in configuration", Here() ); } + if ( name.empty() && type.empty() ) { throw_Exception( "no name or type in configuration", Here() ); } else { - throw eckit::BadParameter( "name or type in configuration don't exist", Here() ); + throw_Exception( "name or type in configuration don't exist", Here() ); } } +const Grid* Grid::create( const std::string& name ) { + return create( name, util::NoConfig() ); +} + const Grid* Grid::create( const std::string& name, const Grid::Config& config ) { const GridBuilder::Registry& registry = GridBuilder::nameRegistry(); for ( GridBuilder::Registry::const_iterator it = registry.begin(); it != registry.end(); ++it ) { @@ -72,7 +74,7 @@ const Grid* Grid::create( const std::string& name, const Grid::Config& config ) for ( GridBuilder::Registry::const_iterator it = registry.begin(); it != registry.end(); ++it ) { log << " - " << *it->second << "\n"; } - throw eckit::BadParameter( log.str() ); + throw_Exception( log.str() ); // return GridBuilder::createNamed(name); } diff --git a/src/atlas/grid/detail/grid/Grid.h b/src/atlas/grid/detail/grid/Grid.h index 8f15dc2d4..9b19ec7d5 100644 --- a/src/atlas/grid/detail/grid/Grid.h +++ b/src/atlas/grid/detail/grid/Grid.h @@ -13,30 +13,33 @@ #include #include -#include "eckit/memory/Builder.h" -#include "eckit/memory/Owned.h" - #include "atlas/domain/Domain.h" +#include "atlas/library/config.h" #include "atlas/projection/Projection.h" -#include "atlas/util/Config.h" -#include "atlas/util/Point.h" +#include "atlas/util/Object.h" namespace eckit { class Hash; } +namespace atlas { +class PointXY; +class PointLonLat; +namespace util { +class Config; +}; +} // namespace atlas + namespace atlas { namespace grid { namespace detail { namespace grid { -class Grid : public eckit::Owned { +class Grid : public util::Object { public: // types using Projection = atlas::Projection; using Domain = atlas::Domain; using Config = atlas::util::Config; using Spec = atlas::util::Config; - using builder_t = eckit::BuilderT1; - using ARG1 = const Config&; using uid_t = std::string; using hash_t = std::string; @@ -62,11 +65,11 @@ class Grid : public eckit::Owned { }; public: // methods - static std::string className(); - static const Grid* create( const Config& ); - static const Grid* create( const std::string& name, const Config& = Config() ); + static const Grid* create( const std::string& name ); + + static const Grid* create( const std::string& name, const Config& ); static const Grid* create( const Grid&, const Domain& ); @@ -100,7 +103,7 @@ class Grid : public eckit::Owned { /// @return number of grid points /// @note This methods should have constant access time, if necessary derived // classes should compute it at construction - virtual size_t size() const = 0; + virtual idx_t size() const = 0; virtual Spec spec() const = 0; diff --git a/src/atlas/grid/detail/grid/GridBuilder.cc b/src/atlas/grid/detail/grid/GridBuilder.cc index 859ff7ec2..83fe563ab 100644 --- a/src/atlas/grid/detail/grid/GridBuilder.cc +++ b/src/atlas/grid/detail/grid/GridBuilder.cc @@ -14,8 +14,12 @@ #include #include "eckit/parser/Tokenizer.h" +#include "eckit/thread/AutoLock.h" +#include "eckit/thread/Mutex.h" #include "eckit/utils/Translator.h" +#include "atlas/grid/detail/grid/GridFactory.h" +#include "atlas/runtime/Exception.h" #include "atlas/runtime/Log.h" #include "atlas/util/Config.h" @@ -49,7 +53,7 @@ int regex_match_impl( const std::string& string, const std::string& regex, std:: if ( !compiled_ok ) Log::error() << "This regular expression didn't compile: \"" << regex << "\"" << std::endl; - ASSERT( compiled_ok ); + ATLAS_ASSERT( compiled_ok ); int found = !regexec( &re, string.c_str(), matchcount + 1, result, 0 ); if ( found && use_substr ) { @@ -70,7 +74,7 @@ int regex_match_impl( const std::string& string, const std::string& regex, std:: class Regex { public: Regex( const std::string& regex, bool use_case = true ) : regex_( regex ), use_case_( use_case ) {} -/* + /* // unused bool match( const std::string& string ) const { std::vector substr; @@ -81,7 +85,7 @@ class Regex { return regex_match_impl( string, regex_, substr, true, use_case_ ); } -/* + /* // unused operator std::string() const { return regex_; } */ @@ -130,7 +134,7 @@ GridBuilder::GridBuilder( const std::string& type ) : names_(), type_( type ) { pthread_once( &once, init ); eckit::AutoLock lock( local_mutex ); - ASSERT( typed_grids->find( type_ ) == typed_grids->end() ); + ATLAS_ASSERT( typed_grids->find( type_ ) == typed_grids->end() ); ( *typed_grids )[type] = this; } @@ -138,7 +142,7 @@ GridBuilder::GridBuilder( const std::vector& names ) : names_( name pthread_once( &once, init ); eckit::AutoLock lock( local_mutex ); for ( const std::string& name : names_ ) { - ASSERT( named_grids->find( name ) == named_grids->end() ); + ATLAS_ASSERT( named_grids->find( name ) == named_grids->end() ); ( *named_grids )[name] = this; } } @@ -150,11 +154,11 @@ GridBuilder::GridBuilder( const std::string& type, const std::vector lock( local_mutex ); for ( const std::string& name : names_ ) { - ASSERT( named_grids->find( name ) == named_grids->end() ); + ATLAS_ASSERT( named_grids->find( name ) == named_grids->end() ); ( *named_grids )[name] = this; } - ASSERT( typed_grids->find( type_ ) == typed_grids->end() ); + ATLAS_ASSERT( typed_grids->find( type_ ) == typed_grids->end() ); ( *typed_grids )[type] = this; } @@ -163,18 +167,18 @@ GridBuilder::~GridBuilder() { eckit::AutoLock lock( local_mutex ); for ( const std::string& name : names_ ) { - ASSERT( named_grids->find( name ) != named_grids->end() ); + ATLAS_ASSERT( named_grids->find( name ) != named_grids->end() ); ( *named_grids ).erase( name ); } if ( not type_.empty() ) { - ASSERT( typed_grids->find( type_ ) != typed_grids->end() ); + ATLAS_ASSERT( typed_grids->find( type_ ) != typed_grids->end() ); ( *typed_grids ).erase( type_ ); } } const Grid::Implementation* GridBuilder::create( const Grid::Config& config ) const { - eckit::Factory& fact = eckit::Factory::instance(); + //eckit::Factory& fact = eckit::Factory::instance(); std::string name; if ( config.get( "name", name ) ) { // ignore any further configuration @@ -182,13 +186,13 @@ const Grid::Implementation* GridBuilder::create( const Grid::Config& config ) co } std::string type; - if ( config.get( "type", type ) && fact.exists( type ) ) { return fact.get( type ).create( config ); } + if ( config.get( "type", type ) && GridFactory::has( type ) ) { return GridFactory::build( type, config ); } if ( name.size() ) { Log::error() << "name provided: " << name << std::endl; } if ( type.size() ) { Log::error() << "type provided: " << type << std::endl; } - if ( name.empty() && type.empty() ) { throw eckit::BadParameter( "no name or type in configuration", Here() ); } + if ( name.empty() && type.empty() ) { throw_Exception( "no name or type in configuration", Here() ); } else { - throw eckit::BadParameter( "name or type in configuration don't exist", Here() ); + throw_Exception( "name or type in configuration don't exist", Here() ); } } diff --git a/src/atlas/grid/detail/grid/GridBuilder.h b/src/atlas/grid/detail/grid/GridBuilder.h index 1a6677bfa..d1468a779 100644 --- a/src/atlas/grid/detail/grid/GridBuilder.h +++ b/src/atlas/grid/detail/grid/GridBuilder.h @@ -17,6 +17,7 @@ #include #include "atlas/grid/Grid.h" +#include "atlas/util/Config.h" namespace atlas { namespace grid { diff --git a/src/atlas/grid/detail/grid/GridFactory.cc b/src/atlas/grid/detail/grid/GridFactory.cc new file mode 100644 index 000000000..bc0b3ee2b --- /dev/null +++ b/src/atlas/grid/detail/grid/GridFactory.cc @@ -0,0 +1,44 @@ +/* + * (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 "atlas/grid/detail/grid/GridFactory.h" +#include "atlas/grid/detail/grid/Structured.h" +#include "atlas/grid/detail/grid/Unstructured.h" + +namespace atlas { +namespace grid { + +//---------------------------------------------------------------------------------------------------------------------- + +namespace { +void force_link() { + static struct Link { + Link() { + GridFactoryBuilder(); + GridFactoryBuilder(); + } + } link; +} +} // namespace + +//---------------------------------------------------------------------------------------------------------------------- + +const GridImpl* GridFactory::build( const std::string& builder, const util::Config& config ) { + force_link(); + auto factory = get( builder ); + return factory->make( config ); +} + +//---------------------------------------------------------------------------------------------------------------------- + +} // namespace grid +} // namespace atlas diff --git a/src/atlas/grid/detail/grid/GridFactory.h b/src/atlas/grid/detail/grid/GridFactory.h new file mode 100644 index 000000000..b4fa33583 --- /dev/null +++ b/src/atlas/grid/detail/grid/GridFactory.h @@ -0,0 +1,54 @@ +/* + * (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 + +#include "atlas/util/Config.h" +#include "atlas/util/Factory.h" + +namespace atlas { +namespace grid { + +namespace detail { +namespace grid { +class Grid; +} +} // namespace detail +using GridImpl = detail::grid::Grid; + +//---------------------------------------------------------------------------------------------------------------------- + +class GridFactory : public util::Factory { +public: + static std::string className() { return "GridFactory"; } + static const GridImpl* build( const std::string&, const util::Config& ); + using Factory::Factory; + +private: + virtual const GridImpl* make( const util::Config& ) = 0; +}; + +//---------------------------------------------------------------------------------------------------------------------- + +template +class GridFactoryBuilder : public GridFactory { +private: + virtual const GridImpl* make( const util::Config& config ) override { return T::create( config ); } + +public: + using GridFactory::GridFactory; +}; + +//---------------------------------------------------------------------------------------------------------------------- + +} // namespace grid +} // namespace atlas diff --git a/src/atlas/grid/detail/grid/LonLat.cc b/src/atlas/grid/detail/grid/LonLat.cc index 4616aa24d..5b8faebad 100644 --- a/src/atlas/grid/detail/grid/LonLat.cc +++ b/src/atlas/grid/detail/grid/LonLat.cc @@ -1,8 +1,23 @@ +/* + * (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 + #include "LonLat.h" #include "eckit/utils/Translator.h" +#include "atlas/grid/StructuredGrid.h" #include "atlas/grid/detail/grid/GridBuilder.h" +#include "atlas/runtime/Exception.h" namespace atlas { namespace grid { @@ -43,19 +58,21 @@ StructuredGrid::grid_t* create_lonlat( long nlon, long nlat, Shift shift, double start_x = ( shifted_x ? 0.5 : 0.0 ) * 360.0 / double( nlon ); std::array interval_x = {start_x, start_x + 360.}; bool no_endpoint = false; - XSpace xspace( interval_x, std::vector( nlat, nlon ), no_endpoint ); + XSpace xspace( interval_x, std::vector( nlat, nlon ), no_endpoint ); // spacing is uniform in y // If shifted_y, the whole interval is shifted by -dy/2, and last latitude // would be -90-dy/2 (below -90!!!), if endpoint=true. // Instead, we set endpoint=false so that last latitude is -90+dy/2 instead. - Grid::Config config_spacing; - config_spacing.set( "type", "linear" ); - config_spacing.set( "start", 90.0 - ( shifted_y ? 90.0 / double( nlat ) : 0.0 ) ); - config_spacing.set( "end", -90.0 - ( shifted_y ? 90.0 / double( nlat ) : 0.0 ) ); - config_spacing.set( "endpoint", shifted_y ? false : true ); - config_spacing.set( "N", nlat ); - Spacing yspace( config_spacing ); + Spacing yspace( [&] { + Grid::Config config_spacing; + config_spacing.set( "type", "linear" ); + config_spacing.set( "start", 90.0 - ( shifted_y ? 90.0 / double( nlat ) : 0.0 ) ); + config_spacing.set( "end", -90.0 - ( shifted_y ? 90.0 / double( nlat ) : 0.0 ) ); + config_spacing.set( "endpoint", shifted_y ? false : true ); + config_spacing.set( "N", nlat ); + return config_spacing; + }() ); Projection projection; Grid::Config config_projection; @@ -89,7 +106,7 @@ StructuredGrid::grid_t* create_lonlat( const Grid::Config& config, Shift shift ) else if ( config.get( "nx", nx ) && config.get( "ny", ny ) ) { } else { - throw eckit::BadParameter( "Configuration requires either N, or (nx,ny)", Here() ); + throw_Exception( "Configuration requires either N, or (nx,ny)", Here() ); } return create_lonlat( nx, ny, shift, config ); diff --git a/src/atlas/grid/detail/grid/LonLat.h b/src/atlas/grid/detail/grid/LonLat.h index 9d9dd82ff..99d805560 100644 --- a/src/atlas/grid/detail/grid/LonLat.h +++ b/src/atlas/grid/detail/grid/LonLat.h @@ -1 +1,11 @@ +/* + * (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.h" diff --git a/src/atlas/grid/detail/grid/Regional.cc b/src/atlas/grid/detail/grid/Regional.cc index 888fb1088..11473b128 100644 --- a/src/atlas/grid/detail/grid/Regional.cc +++ b/src/atlas/grid/detail/grid/Regional.cc @@ -1,11 +1,23 @@ +/* + * (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 "Regional.h" +#include "atlas/grid/StructuredGrid.h" #include "atlas/grid/detail/grid/GridBuilder.h" +#include "atlas/runtime/Exception.h" #include "atlas/runtime/Log.h" using atlas::grid::LinearSpacing; -using XSpace = atlas::grid::StructuredGrid::XSpace; -using YSpace = atlas::grid::StructuredGrid::YSpace; +using XSpace = atlas::StructuredGrid::XSpace; +using YSpace = atlas::StructuredGrid::YSpace; namespace atlas { namespace grid { @@ -56,7 +68,6 @@ struct Parse_llc_step : ConfigParser { double centre[] = {centre_lonlat[0], centre_lonlat[1]}; p.lonlat2xy( centre ); - ATLAS_DEBUG_VAR( PointXY( centre ) ); double lx = x.step * double( x.N - 1 ); double ly = y.step * double( y.N - 1 ); @@ -98,7 +109,7 @@ struct Parse_bounds_lonlat : ConfigParser { errmsg << "\n" "p.bool() = " << bool( p ); - throw eckit::BadParameter( errmsg.str(), Here() ); + throw_Exception( errmsg.str(), Here() ); } } @@ -190,7 +201,7 @@ static class regional : public GridBuilder { } virtual const Grid::Implementation* create( const std::string& name, const Grid::Config& config ) const { - eckit::NotImplemented( "There are no named regional grids implemented.", Here() ); + throw_NotImplemented( "There are no named regional grids implemented.", Here() ); return nullptr; } @@ -205,13 +216,13 @@ static class regional : public GridBuilder { // Read grid configuration ConfigParser::Parsed x, y; if ( not ConfigParser::parse( projection, config, x, y ) ) { - throw eckit::BadParameter( "Could not parse configuration for RegularRegional grid", Here() ); + throw_Exception( "Could not parse configuration for RegularRegional grid", Here() ); } YSpace yspace( LinearSpacing( y.min, y.max, y.N, y.endpoint ) ); bool with_endpoint = true; - XSpace xspace( {x.min, x.max}, std::vector( y.N, x.N ), with_endpoint ); + XSpace xspace( {x.min, x.max}, std::vector( y.N, x.N ), with_endpoint ); return new StructuredGrid::grid_t( xspace, yspace, projection, domain( config ) ); } @@ -230,7 +241,7 @@ static class zonal_band : public GridBuilder { } virtual const Grid::Implementation* create( const std::string& name, const Grid::Config& config ) const { - eckit::NotImplemented( "There are no named zonal_band grids implemented.", Here() ); + throw_NotImplemented( "There are no named zonal_band grids implemented.", Here() ); return nullptr; } @@ -242,21 +253,19 @@ static class zonal_band : public GridBuilder { if ( config.get( "projection", config_proj ) ) { projection = Projection( config_proj ); } } - ASSERT( projection.units() == "degrees" ); + ATLAS_ASSERT( projection.units() == "degrees" ); // Read grid configuration ConfigParser::Parsed y; long nx; - if ( not config.get( "nx", nx ) ) - throw eckit::BadParameter( "Parameter 'nx' missing in configuration", Here() ); - if ( not config.get( "ny", y.N ) ) - throw eckit::BadParameter( "Parameter 'ny' missing in configuration", Here() ); + if ( not config.get( "nx", nx ) ) throw_Exception( "Parameter 'nx' missing in configuration", Here() ); + if ( not config.get( "ny", y.N ) ) throw_Exception( "Parameter 'ny' missing in configuration", Here() ); if ( not( config.get( "ymin", y.min ) or config.get( "south", y.min ) ) ) y.min = -90.; if ( not( config.get( "ymax", y.max ) or config.get( "north", y.max ) ) ) y.max = 90.; YSpace yspace( LinearSpacing( y.min, y.max, y.N, true ) ); - XSpace xspace( {0., 360.}, std::vector( y.N, nx ), false ); + XSpace xspace( {0., 360.}, std::vector( y.N, nx ), false ); return new StructuredGrid::grid_t( xspace, yspace, projection, domain( config ) ); } diff --git a/src/atlas/grid/detail/grid/Regional.h b/src/atlas/grid/detail/grid/Regional.h index 9d9dd82ff..99d805560 100644 --- a/src/atlas/grid/detail/grid/Regional.h +++ b/src/atlas/grid/detail/grid/Regional.h @@ -1 +1,11 @@ +/* + * (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.h" diff --git a/src/atlas/grid/detail/grid/Structured.cc b/src/atlas/grid/detail/grid/Structured.cc index d491834b5..4250d765e 100644 --- a/src/atlas/grid/detail/grid/Structured.cc +++ b/src/atlas/grid/detail/grid/Structured.cc @@ -11,17 +11,22 @@ #include "Structured.h" #include +#include #include +#include #include "eckit/types/FloatCompare.h" +#include "eckit/utils/Hash.h" #include "atlas/domain/Domain.h" -#include "atlas/grid/Grid.h" +#include "atlas/grid/StructuredGrid.h" #include "atlas/grid/detail/grid/GridBuilder.h" +#include "atlas/grid/detail/grid/GridFactory.h" #include "atlas/grid/detail/spacing/CustomSpacing.h" #include "atlas/grid/detail/spacing/LinearSpacing.h" -#include "atlas/runtime/ErrorHandling.h" +#include "atlas/runtime/Exception.h" #include "atlas/runtime/Log.h" +#include "atlas/util/NormaliseLongitude.h" #include "atlas/util/Point.h" #include "atlas/util/UnitSphere.h" @@ -53,7 +58,7 @@ Structured::Structured( const std::string& name, XSpace xspace, YSpace yspace, P projection_ = Projection(); y_.assign( yspace_.begin(), yspace_.end() ); - size_t ny = y_.size(); + idx_t ny{static_cast( y_.size() )}; if ( xspace_.ny() == 1 && yspace_.size() > 1 ) { nx_.resize( ny, xspace_.nx()[0] ); @@ -68,15 +73,15 @@ Structured::Structured( const std::string& name, XSpace xspace, YSpace yspace, P xmax_ = xspace_.xmax(); } - ASSERT( nx_.size() == ny ); + ATLAS_ASSERT( static_cast( nx_.size() ) == ny ); // Further setup - nxmin_ = nxmax_ = static_cast( nx_.front() ); - for ( size_t j = 1; j < ny; ++j ) { - nxmin_ = std::min( static_cast( nx_[j] ), nxmin_ ); - nxmax_ = std::max( static_cast( nx_[j] ), nxmax_ ); + nxmin_ = nxmax_ = nx_.front(); + for ( idx_t j = 1; j < ny; ++j ) { + nxmin_ = std::min( nx_[j], nxmin_ ); + nxmax_ = std::max( nx_[j], nxmax_ ); } - npts_ = size_t( std::accumulate( nx_.begin(), nx_.end(), 0 ) ); + npts_ = std::accumulate( nx_.begin(), nx_.end(), idx_t{0} ); if ( domain ) { crop( domain ); } @@ -117,8 +122,14 @@ Structured::XSpace::XSpace() : impl_( nullptr ) {} Structured::XSpace::XSpace( const XSpace& xspace ) : impl_( xspace.impl_ ) {} -Structured::XSpace::XSpace( const std::array& interval, const std::vector& N, bool endpoint ) : +template +Structured::XSpace::XSpace( const std::array& interval, const NVector& N, bool endpoint ) : impl_( new Implementation( interval, N, endpoint ) ) {} +template Structured::XSpace::XSpace( const std::array& interval, const std::vector& N, bool endpoint ); +template Structured::XSpace::XSpace( const std::array& interval, const std::vector& N, bool endpoint ); + +Structured::XSpace::XSpace( const std::array& interval, std::initializer_list&& N, bool endpoint ) : + XSpace( interval, std::vector{N}, endpoint ) {} Structured::XSpace::XSpace( const Spacing& spacing ) : impl_( new Implementation( spacing ) ) {} @@ -126,14 +137,18 @@ Structured::XSpace::XSpace( const Config& config ) : impl_( new Implementation( Structured::XSpace::XSpace( const std::vector& config ) : impl_( new Implementation( config ) ) {} +Grid::Spec Structured::XSpace::spec() const { + return impl_->spec(); +} + Structured::XSpace::Implementation::Implementation( const Config& config ) { Config config_xspace( config ); std::string xspace_type; config_xspace.get( "type", xspace_type ); - ASSERT( xspace_type == "linear" ); + ATLAS_ASSERT( xspace_type == "linear" ); - std::vector v_N; + std::vector v_N; std::vector v_start; std::vector v_end; std::vector v_length; @@ -142,19 +157,19 @@ Structured::XSpace::Implementation::Implementation( const Config& config ) { config_xspace.get( "end[]", v_end ); config_xspace.get( "length[]", v_length ); - size_t ny = + idx_t ny = std::max( v_N.size(), std::max( v_start.size(), std::max( v_end.size(), std::max( v_length.size(), 1ul ) ) ) ); reserve( ny ); - if ( not v_N.empty() ) ASSERT( v_N.size() == ny ); - if ( not v_start.empty() ) ASSERT( v_start.size() == ny ); - if ( not v_end.empty() ) ASSERT( v_end.size() == ny ); - if ( not v_length.empty() ) ASSERT( v_length.size() == ny ); + if ( not v_N.empty() ) ATLAS_ASSERT( static_cast( v_N.size() ) == ny ); + if ( not v_start.empty() ) ATLAS_ASSERT( static_cast( v_start.size() ) == ny ); + if ( not v_end.empty() ) ATLAS_ASSERT( static_cast( v_end.size() ) == ny ); + if ( not v_length.empty() ) ATLAS_ASSERT( static_cast( v_length.size() ) == ny ); - nxmin_ = std::numeric_limits::max(); + nxmin_ = std::numeric_limits::max(); nxmax_ = 0; - for ( size_t j = 0; j < ny; ++j ) { + for ( idx_t j = 0; j < ny; ++j ) { if ( not v_N.empty() ) config_xspace.set( "N", v_N[j] ); if ( not v_start.empty() ) config_xspace.set( "start", v_start[j] ); if ( not v_end.empty() ) config_xspace.set( "end", v_end[j] ); @@ -164,32 +179,32 @@ Structured::XSpace::Implementation::Implementation( const Config& config ) { xmax_.push_back( xspace.end ); nx_.push_back( xspace.N ); dx_.push_back( xspace.step ); - nxmin_ = std::min( nxmin_, size_t( nx_[j] ) ); - nxmax_ = std::max( nxmax_, size_t( nx_[j] ) ); + nxmin_ = std::min( nxmin_, nx_[j] ); + nxmax_ = std::max( nxmax_, nx_[j] ); } } Structured::XSpace::Implementation::Implementation( const std::vector& config_list ) { reserve( config_list.size() ); - nxmin_ = std::numeric_limits::max(); + nxmin_ = std::numeric_limits::max(); nxmax_ = 0; std::string xspace_type; - for ( size_t j = 0; j < ny(); ++j ) { + for ( idx_t j = 0; j < ny(); ++j ) { config_list[j].get( "type", xspace_type ); - ASSERT( xspace_type == "linear" ); + ATLAS_ASSERT( xspace_type == "linear" ); spacing::LinearSpacing::Params xspace( config_list[j] ); xmin_.push_back( xspace.start ); xmax_.push_back( xspace.end ); nx_.push_back( xspace.N ); dx_.push_back( xspace.step ); - nxmin_ = std::min( nxmin_, size_t( nx_[j] ) ); - nxmax_ = std::max( nxmax_, size_t( nx_[j] ) ); + nxmin_ = std::min( nxmin_, nx_[j] ); + nxmax_ = std::max( nxmax_, nx_[j] ); } } -void Structured::XSpace::Implementation::Implementation::reserve( long ny ) { +void Structured::XSpace::Implementation::Implementation::reserve( idx_t ny ) { ny_ = ny; nx_.reserve( ny ); xmin_.reserve( ny ); @@ -197,22 +212,32 @@ void Structured::XSpace::Implementation::Implementation::reserve( long ny ) { dx_.reserve( ny ); } -Structured::XSpace::Implementation::Implementation( const std::array& interval, const std::vector& N, +template +Structured::XSpace::Implementation::Implementation( const std::array& interval, const NVector& N, bool endpoint ) : ny_( N.size() ), - nx_( N ), + nx_( N.begin(), N.end() ), xmin_( ny_, interval[0] ), xmax_( ny_, interval[1] ), dx_( ny_ ) { - nxmin_ = std::numeric_limits::max(); + nxmin_ = std::numeric_limits::max(); nxmax_ = 0; double length = interval[1] - interval[0]; - for ( size_t j = 0; j < ny_; ++j ) { - nxmin_ = std::min( nxmin_, size_t( nx_[j] ) ); - nxmax_ = std::max( nxmax_, size_t( nx_[j] ) ); + for ( idx_t j = 0; j < ny_; ++j ) { + nxmin_ = std::min( nxmin_, nx_[j] ); + nxmax_ = std::max( nxmax_, nx_[j] ); dx_[j] = endpoint ? length / double( nx_[j] - 1 ) : length / double( nx_[j] ); } } +template Structured::XSpace::Implementation::Implementation( const std::array& interval, + const std::vector& N, bool endpoint ); +template Structured::XSpace::Implementation::Implementation( const std::array& interval, + const std::vector& N, bool endpoint ); + +Structured::XSpace::Implementation::Implementation( const std::array& interval, + std::initializer_list&& N, bool endpoint ) : + Implementation( interval, std::vector{N}, endpoint ) {} + Structured::XSpace::Implementation::Implementation( const Spacing& spacing ) : ny_( 1 ), @@ -239,16 +264,16 @@ Grid::Spec Structured::XSpace::Implementation::spec() const { double xmin = xmin_[0]; double xmax = xmax_[0]; - long nx = nx_[0]; + idx_t nx = nx_[0]; double dx = dx_[0]; - ASSERT( xmin_.size() == ny_ ); - ASSERT( xmax_.size() == ny_ ); - ASSERT( nx_.size() == ny_ ); + ATLAS_ASSERT( static_cast( xmin_.size() ) == ny_ ); + ATLAS_ASSERT( static_cast( xmax_.size() ) == ny_ ); + ATLAS_ASSERT( static_cast( nx_.size() ) == ny_ ); - for ( size_t j = 1; j < ny_; ++j ) { - same_xmin = same_xmin && ( xmin_[j] == xmin ); - same_xmax = same_xmax && ( xmax_[j] == xmax ); + for ( idx_t j = 1; j < ny_; ++j ) { + same_xmin = same_xmin && ( eckit::types::is_approximately_equal( xmin_[j], xmin ) ); + same_xmax = same_xmax && ( eckit::types::is_approximately_equal( xmax_[j], xmax ) ); same_nx = same_nx && ( nx_[j] == nx ); } @@ -277,34 +302,23 @@ class Normalise { public: Normalise( const RectangularDomain& domain ) : degrees_( domain.units() == "degrees" ), - xmin_( domain.xmin() ), - xmax_( domain.xmax() ), - eps_( 1e-11 ) {} + normalise_( domain.xmin(), domain.xmax() ) {} double operator()( double x ) const { - if ( degrees_ ) { - while ( eckit::types::is_strictly_greater( xmin_, x, eps_ ) ) { - x += 360.; - } - while ( eckit::types::is_strictly_greater( x, xmax_, eps_ ) ) { - x -= 360.; - } - } + if ( degrees_ ) { x = normalise_( x ); } return x; } private: const bool degrees_; - const double xmin_; - const double xmax_; - const double eps_; + NormaliseLongitude normalise_; }; } // namespace void Structured::crop( const Domain& dom ) { if ( dom.global() ) return; - ASSERT( dom.units() == projection().units() ); + ATLAS_ASSERT( dom.units() == projection().units() ); auto zonal_domain = ZonalBandDomain( dom ); auto rect_domain = RectangularDomain( dom ); @@ -313,29 +327,29 @@ void Structured::crop( const Domain& dom ) { const double cropped_ymin = zonal_domain.ymin(); const double cropped_ymax = zonal_domain.ymax(); - size_t jmin = ny(); - size_t jmax = 0; - for ( size_t j = 0; j < ny(); ++j ) { + idx_t jmin = ny(); + idx_t jmax = 0; + for ( idx_t j = 0; j < ny(); ++j ) { if ( zonal_domain.contains_y( y( j ) ) ) { jmin = std::min( j, jmin ); jmax = std::max( j, jmax ); } } - size_t cropped_ny = jmax - jmin + 1; + idx_t cropped_ny = jmax - jmin + 1; std::vector cropped_y( y_.begin() + jmin, y_.begin() + jmin + cropped_ny ); std::vector cropped_xmin( xmin_.begin() + jmin, xmin_.begin() + jmin + cropped_ny ); std::vector cropped_xmax( xmax_.begin() + jmin, xmax_.begin() + jmin + cropped_ny ); std::vector cropped_dx( dx_.begin() + jmin, dx_.begin() + jmin + cropped_ny ); - std::vector cropped_nx( nx_.begin() + jmin, nx_.begin() + jmin + cropped_ny ); - ASSERT( cropped_nx.size() == cropped_ny ); - - size_t cropped_nxmin, cropped_nxmax; - cropped_nxmin = cropped_nxmax = static_cast( cropped_nx.front() ); - for ( size_t j = 1; j < cropped_ny; ++j ) { - cropped_nxmin = std::min( static_cast( cropped_nx[j] ), cropped_nxmin ); - cropped_nxmax = std::max( static_cast( cropped_nx[j] ), cropped_nxmax ); + std::vector cropped_nx( nx_.begin() + jmin, nx_.begin() + jmin + cropped_ny ); + ATLAS_ASSERT( idx_t( cropped_nx.size() ) == cropped_ny ); + + idx_t cropped_nxmin, cropped_nxmax; + cropped_nxmin = cropped_nxmax = cropped_nx.front(); + for ( idx_t j = 1; j < cropped_ny; ++j ) { + cropped_nxmin = std::min( cropped_nx[j], cropped_nxmin ); + cropped_nxmax = std::max( cropped_nx[j], cropped_nxmax ); } - size_t cropped_npts = size_t( std::accumulate( cropped_nx.begin(), cropped_nx.end(), 0 ) ); + idx_t cropped_npts = std::accumulate( cropped_nx.begin(), cropped_nx.end(), idx_t{0} ); Spacing cropped_yspace( new spacing::CustomSpacing( cropped_ny, cropped_y.data(), {cropped_ymin, cropped_ymax} ) ); @@ -359,29 +373,29 @@ void Structured::crop( const Domain& dom ) { const double cropped_ymax = rect_domain.ymax(); // Cropping in Y - size_t jmin = ny(); - size_t jmax = 0; - for ( size_t j = 0; j < ny(); ++j ) { + idx_t jmin = ny(); + idx_t jmax = 0; + for ( idx_t j = 0; j < ny(); ++j ) { if ( rect_domain.contains_y( y( j ) ) ) { jmin = std::min( j, jmin ); jmax = std::max( j, jmax ); } } - ASSERT( jmax >= jmin ); + ATLAS_ASSERT( jmax >= jmin ); - size_t cropped_ny = jmax - jmin + 1; + idx_t cropped_ny = jmax - jmin + 1; std::vector cropped_y( y_.begin() + jmin, y_.begin() + jmin + cropped_ny ); std::vector cropped_dx( dx_.begin() + jmin, dx_.begin() + jmin + cropped_ny ); std::vector cropped_xmin( cropped_ny, std::numeric_limits::max() ); std::vector cropped_xmax( cropped_ny, -std::numeric_limits::max() ); - std::vector cropped_nx( cropped_ny ); + std::vector cropped_nx( cropped_ny ); // Cropping in X Normalise normalise( rect_domain ); - for ( size_t j = jmin, jcropped = 0; j <= jmax; ++j, ++jcropped ) { - size_t n = 0; - for ( size_t i = 0; i < nx( j ); ++i ) { + for ( idx_t j = jmin, jcropped = 0; j <= jmax; ++j, ++jcropped ) { + idx_t n = 0; + for ( idx_t i = 0; i < nx( j ); ++i ) { const double _x = normalise( x( i, j ) ); if ( rect_domain.contains_x( _x ) ) { cropped_xmin[jcropped] = std::min( cropped_xmin[jcropped], _x ); @@ -394,14 +408,14 @@ void Structured::crop( const Domain& dom ) { // Complete structures - size_t cropped_nxmin, cropped_nxmax; - cropped_nxmin = cropped_nxmax = static_cast( cropped_nx.front() ); + idx_t cropped_nxmin, cropped_nxmax; + cropped_nxmin = cropped_nxmax = cropped_nx.front(); - for ( size_t j = 1; j < cropped_ny; ++j ) { - cropped_nxmin = std::min( static_cast( cropped_nx[j] ), cropped_nxmin ); - cropped_nxmax = std::max( static_cast( cropped_nx[j] ), cropped_nxmax ); + for ( idx_t j = 1; j < cropped_ny; ++j ) { + cropped_nxmin = std::min( cropped_nx[j], cropped_nxmin ); + cropped_nxmax = std::max( cropped_nx[j], cropped_nxmax ); } - size_t cropped_npts = size_t( std::accumulate( cropped_nx.begin(), cropped_nx.end(), 0 ) ); + idx_t cropped_npts = std::accumulate( cropped_nx.begin(), cropped_nx.end(), idx_t{0} ); Spacing cropped_yspace( new spacing::CustomSpacing( cropped_ny, cropped_y.data(), {cropped_ymin, cropped_ymax} ) ); @@ -423,7 +437,7 @@ void Structured::crop( const Domain& dom ) { else { std::stringstream errmsg; errmsg << "Cannot crop the grid with domain " << dom; - eckit::BadParameter( errmsg.str(), Here() ); + throw_Exception( errmsg.str(), Here() ); } } @@ -435,8 +449,8 @@ void Structured::computeTruePeriodicity() { else { // domain could be zonal band - size_t j = ny() / 2; - if ( xmin_[j] + ( nx_[j] - 1 ) * dx_[j] == xmax_[j] ) { + idx_t j = ny() / 2; + if ( std::abs( xmin_[j] + ( nx_[j] - 1 ) * dx_[j] - xmax_[j] ) < 1.e-11 ) { periodic_x_ = false; // This would lead to duplicated points } else { @@ -465,7 +479,10 @@ std::string Structured::type() const { void Structured::hash( eckit::Hash& h ) const { h.add( y().data(), sizeof( double ) * y().size() ); - h.add( nx().data(), sizeof( long ) * ny() ); + + // We can use nx() directly, but it could change the hash + std::vector hashed_nx( nx().begin(), nx().end() ); + h.add( hashed_nx.data(), sizeof( long ) * ny() ); // also add lonmin and lonmax h.add( xmin_.data(), sizeof( double ) * xmin_.size() ); @@ -494,8 +511,9 @@ Grid::Spec Structured::spec() const { return grid_spec; } -// -------------------------------------------------------------------- + // -------------------------------------------------------------------- +#if 1 namespace { // anonymous static class structured : public GridBuilder { @@ -511,8 +529,8 @@ static class structured : public GridBuilder { << "Structured grid"; } - virtual const Implementation* create( const std::string& name, const Config& config ) const { - throw eckit::NotImplemented( "Cannot create structured grid from name", Here() ); + virtual const Implementation* create( const std::string& /* name */, const Config& ) const { + throw_NotImplemented( "Cannot create structured grid from name", Here() ); } virtual const Implementation* create( const Config& config ) const { @@ -527,7 +545,7 @@ static class structured : public GridBuilder { if ( config.get( "domain", config_domain ) ) { domain = Domain( config_domain ); } Config config_yspace; - if ( not config.get( "yspace", config_yspace ) ) throw eckit::BadParameter( "yspace missing in configuration" ); + if ( not config.get( "yspace", config_yspace ) ) throw_Exception( "yspace missing in configuration", Here() ); yspace = Spacing( config_yspace ); XSpace xspace; @@ -540,7 +558,7 @@ static class structured : public GridBuilder { xspace = XSpace( config_xspace ); } else { - throw eckit::BadParameter( "xspace missing in configuration" ); + throw_Exception( "xspace missing in configuration", Here() ); } return new StructuredGrid::grid_t( xspace, yspace, projection, domain ); @@ -549,106 +567,134 @@ static class structured : public GridBuilder { } structured_; } // anonymous namespace +#endif // -------------------------------------------------------------------- extern "C" { -long atlas__grid__Structured__ny( Structured* This ) { - ATLAS_ERROR_HANDLING( ASSERT( This ); return This->ny(); ); - return 0; +idx_t atlas__grid__Structured__ny( Structured* This ) { + ATLAS_ASSERT( This != nullptr, "Cannot access uninitialised atlas_StructuredGrid" ); + return This->ny(); } -long atlas__grid__Structured__nx( Structured* This, long jlat ) { - ATLAS_ERROR_HANDLING( ASSERT( This ); return This->nx( jlat ); ); - return 0; +idx_t atlas__grid__Structured__nx( Structured* This, idx_t jlat ) { + ATLAS_ASSERT( This != nullptr, "Cannot access uninitialised atlas_StructuredGrid" ); + return This->nx( jlat ); } -void atlas__grid__Structured__nx_array( Structured* This, const long*& nx_array, size_t& size ) { - ATLAS_ERROR_HANDLING( ASSERT( This ); nx_array = This->nx().data(); size = This->nx().size(); ); +void atlas__grid__Structured__nx_array( Structured* This, const idx_t*& nx_array, idx_t& size ) { + ATLAS_ASSERT( This != nullptr, "Cannot access uninitialised atlas_StructuredGrid" ); + nx_array = This->nx().data(); + size = idx_t( This->nx().size() ); } -long atlas__grid__Structured__nxmax( Structured* This ) { - ATLAS_ERROR_HANDLING( ASSERT( This ); return This->nxmax(); ); - return 0; +idx_t atlas__grid__Structured__nxmax( Structured* This ) { + ATLAS_ASSERT( This != nullptr, "Cannot access uninitialised atlas_StructuredGrid" ); + return This->nxmax(); } -long atlas__grid__Structured__nxmin( Structured* This ) { - ATLAS_ERROR_HANDLING( ASSERT( This ); return This->nxmin(); ); - return 0; +idx_t atlas__grid__Structured__nxmin( Structured* This ) { + ATLAS_ASSERT( This != nullptr, "Cannot access uninitialised atlas_StructuredGrid" ); + return This->nxmin(); } -long atlas__grid__Structured__size( Structured* This ) { - ATLAS_ERROR_HANDLING( ASSERT( This ); return This->size(); ); - return 0; +idx_t atlas__grid__Structured__size( Structured* This ) { + ATLAS_ASSERT( This != nullptr, "Cannot access uninitialised atlas_StructuredGrid" ); + return This->size(); } -double atlas__grid__Structured__y( Structured* This, long j ) { - ATLAS_ERROR_HANDLING( ASSERT( This ); return This->y( j ); ); - return 0.; +double atlas__grid__Structured__y( Structured* This, idx_t j ) { + ATLAS_ASSERT( This != nullptr, "Cannot access uninitialised atlas_StructuredGrid" ); + return This->y( j ); } -double atlas__grid__Structured__x( Structured* This, long i, long j ) { - ATLAS_ERROR_HANDLING( ASSERT( This ); return This->x( i, j ); ); - return 0.; +double atlas__grid__Structured__x( Structured* This, idx_t i, idx_t j ) { + ATLAS_ASSERT( This != nullptr, "Cannot access uninitialised atlas_StructuredGrid" ); + return This->x( i, j ); } -void atlas__grid__Structured__xy( Structured* This, long i, long j, double crd[] ) { - ATLAS_ERROR_HANDLING( ASSERT( This ); This->xy( i, j, crd ); ); +void atlas__grid__Structured__xy( Structured* This, idx_t i, idx_t j, double crd[] ) { + ATLAS_ASSERT( This != nullptr, "Cannot access uninitialised atlas_StructuredGrid" ); + This->xy( i, j, crd ); } -void atlas__grid__Structured__lonlat( Structured* This, long i, long j, double crd[] ) { - ATLAS_ERROR_HANDLING( ASSERT( This ); This->lonlat( i, j, crd ); ); +void atlas__grid__Structured__lonlat( Structured* This, idx_t i, idx_t j, double crd[] ) { + ATLAS_ASSERT( This != nullptr, "Cannot access uninitialised atlas_StructuredGrid" ); + This->lonlat( i, j, crd ); } -void atlas__grid__Structured__y_array( Structured* This, const double*& y_array, size_t& size ) { - ATLAS_ERROR_HANDLING( ASSERT( This ); y_array = This->y().data(); size = This->y().size(); ); +void atlas__grid__Structured__y_array( Structured* This, const double*& y_array, idx_t& size ) { + ATLAS_ASSERT( This != nullptr, "Cannot access uninitialised atlas_StructuredGrid" ); + y_array = This->y().data(); + size = idx_t( This->y().size() ); } int atlas__grid__Structured__reduced( Structured* This ) { - ATLAS_ERROR_HANDLING( ASSERT( This ); return This->reduced(); ); - return 1; + ATLAS_ASSERT( This != nullptr, "Cannot access uninitialised atlas_StructuredGrid" ); + return This->reduced(); } const Structured* atlas__grid__Structured( char* identifier ) { - ATLAS_ERROR_HANDLING( ASSERT( identifier ); const Structured* grid = dynamic_cast( - Grid::create( std::string( identifier ) ) ); - ASSERT( grid ); return grid; ); - return 0; + const Structured* grid = dynamic_cast( Grid::create( std::string( identifier ) ) ); + ATLAS_ASSERT( grid != nullptr ); + return grid; } const Structured* atlas__grid__Structured__config( util::Config* conf ) { - ATLAS_ERROR_HANDLING( ASSERT( conf ); - const Structured* grid = dynamic_cast( Grid::create( *conf ) ); - ASSERT( grid ); return grid; ); - return 0; + ATLAS_ASSERT( conf != nullptr ); + const Structured* grid = dynamic_cast( Grid::create( *conf ) ); + ATLAS_ASSERT( grid != nullptr ); + return grid; } void atlas__grid__Structured__delete( Structured* This ) { - ATLAS_ERROR_HANDLING( ASSERT( This ); ); + ATLAS_ASSERT( This != nullptr, "Cannot access uninitialised atlas_StructuredGrid" ); delete This; } Structured* atlas__grid__regular__RegularGaussian( long N ) { - NOTIMP; + ATLAS_NOTIMPLEMENTED; } Structured* atlas__grid__regular__RegularLonLat( long nlon, long nlat ) { - NOTIMP; + ATLAS_NOTIMPLEMENTED; } Structured* atlas__grid__regular__ShiftedLonLat( long nlon, long nlat ) { - NOTIMP; + ATLAS_NOTIMPLEMENTED; } Structured* atlas__grid__regular__ShiftedLon( long nlon, long nlat ) { - NOTIMP; + ATLAS_NOTIMPLEMENTED; } Structured* atlas__grid__regular__ShiftedLat( long nlon, long nlat ) { - NOTIMP; + ATLAS_NOTIMPLEMENTED; } -long atlas__grid__Gaussian__N( Structured* This ) { - ATLAS_ERROR_HANDLING( ASSERT( This ); GaussianGrid gaussian( This ); ASSERT( gaussian ); return gaussian.N(); ); - return 0; +idx_t atlas__grid__Gaussian__N( Structured* This ) { + ATLAS_ASSERT( This != nullptr, "Cannot access uninitialised atlas_StructuredGrid" ); + GaussianGrid gaussian( This ); + ATLAS_ASSERT( gaussian, "This grid is not a Gaussian grid" ); + return gaussian.N(); +} +} + +namespace { +GridFactoryBuilder __register_Structured( Structured::static_type() ); } + +bool Structured::IteratorXYPredicated::next( PointXY& /*xy*/ ) { + ATLAS_NOTIMPLEMENTED; +#if 0 + if ( j_ < grid_.ny() && i_ < grid_.nx( j_ ) ) { + xy = grid_.xy( i_++, j_ ); + + if ( i_ == grid_.nx( j_ ) ) { + j_++; + i_ = 0; + } + return true; + } + return false; +#endif } } // namespace grid diff --git a/src/atlas/grid/detail/grid/Structured.h b/src/atlas/grid/detail/grid/Structured.h index 4cb402be8..23c0699ba 100644 --- a/src/atlas/grid/detail/grid/Structured.h +++ b/src/atlas/grid/detail/grid/Structured.h @@ -13,12 +13,12 @@ #include #include -#include "eckit/memory/Builder.h" -#include "eckit/utils/Hash.h" - #include "atlas/grid/Spacing.h" #include "atlas/grid/detail/grid/Grid.h" -#include "atlas/util/Config.h" +#include "atlas/library/config.h" +#include "atlas/util/Object.h" +#include "atlas/util/ObjectHandle.h" +#include "atlas/util/Point.h" namespace atlas { namespace grid { @@ -74,8 +74,8 @@ class Structured : public Grid { private: const Structured& grid_; - size_t i_; - size_t j_; + idx_t i_; + idx_t j_; }; class IteratorXYPredicated : public Grid::IteratorXY { @@ -99,21 +99,7 @@ class Structured : public Grid { } } - virtual bool next( PointXY& xy ) { - NOTIMP; -#if 0 - if ( j_ < grid_.ny() && i_ < grid_.nx( j_ ) ) { - xy = grid_.xy( i_++, j_ ); - - if ( i_ == grid_.nx( j_ ) ) { - j_++; - i_ = 0; - } - return true; - } - return false; -#endif - } + virtual bool next( PointXY& xy ); virtual const PointXY operator*() const { return grid_.xy( i_, j_ ); } @@ -143,10 +129,10 @@ class Structured : public Grid { private: const Structured& grid_; Grid::IteratorXY::Predicate p_; - size_t i_; - size_t j_; - size_t n_; - size_t size_; + idx_t i_; + idx_t j_; + idx_t n_; + idx_t size_; }; class IteratorLonLat : public Grid::IteratorLonLat { @@ -192,15 +178,20 @@ class Structured : public Grid { private: const Structured& grid_; - size_t i_; - size_t j_; + idx_t i_; + idx_t j_; }; public: class XSpace { - class Implementation : public eckit::Owned { + class Implementation : public util::Object { public: - Implementation( const std::array& interval, const std::vector& N, bool endpoint = true ); + // Constructor NVector can be either std::vector or std::vector + template + Implementation( const std::array& interval, const NVector& N, bool endpoint = true ); + + Implementation( const std::array& interval, std::initializer_list&& N, + bool endpoint = true ); Implementation( const Spacing& ); @@ -208,16 +199,16 @@ class Structured : public Grid { Implementation( const std::vector& ); - size_t ny() const { return ny_; } + idx_t ny() const { return ny_; } // Minimum number of points across parallels (constant y) - size_t nxmin() const { return nxmin_; } + idx_t nxmin() const { return nxmin_; } // Maximum number of points across parallels (constant y) - size_t nxmax() const { return nxmax_; } + idx_t nxmax() const { return nxmax_; } /// Number of points per latitude - const std::vector& nx() const { return nx_; } + const std::vector& nx() const { return nx_; } /// Value of minimum longitude per latitude [default=0] const std::vector& xmin() const { return xmin_; } @@ -233,13 +224,13 @@ class Structured : public Grid { std::string type() const; private: - void reserve( long ny ); + void reserve( idx_t ny ); private: - size_t ny_; - size_t nxmin_; - size_t nxmax_; - std::vector nx_; + idx_t ny_; + idx_t nxmin_; + idx_t nxmax_; + std::vector nx_; std::vector xmin_; std::vector xmax_; std::vector dx_; @@ -252,22 +243,26 @@ class Structured : public Grid { XSpace( const Spacing& ); - XSpace( const std::array& interval, const std::vector& N, bool endpoint = true ); + // Constructor NVector can be either std::vector or std::vector or initializer list + template + XSpace( const std::array& interval, const NVector& N, bool endpoint = true ); + + XSpace( const std::array& interval, std::initializer_list&& N, bool endpoint = true ); XSpace( const Config& ); XSpace( const std::vector& ); - size_t ny() const { return impl_->ny(); } + idx_t ny() const { return impl_->ny(); } // Minimum number of points across parallels (constant y) - size_t nxmin() const { return impl_->nxmin(); } + idx_t nxmin() const { return impl_->nxmin(); } // Maximum number of points across parallels (constant y) - size_t nxmax() const { return impl_->nxmax(); } + idx_t nxmax() const { return impl_->nxmax(); } /// Number of points per latitude - const std::vector& nx() const { return impl_->nx(); } + const std::vector& nx() const { return impl_->nx(); } /// Value of minimum longitude per latitude [default=0] const std::vector& xmin() const { return impl_->xmin(); } @@ -278,12 +273,12 @@ class Structured : public Grid { /// Value of longitude increment const std::vector& dx() const { return impl_->dx(); } - Spec spec() const { return impl_->spec(); } + Spec spec() const; std::string type() const { return impl_->type(); } private: - eckit::SharedPtr impl_; + util::ObjectHandle impl_; }; using YSpace = Spacing; @@ -296,47 +291,49 @@ class Structured : public Grid { Structured( XSpace, YSpace, Projection, Domain ); Structured( const Structured&, Domain ); - virtual ~Structured(); + virtual ~Structured() override; - virtual size_t size() const { return npts_; } + virtual idx_t size() const override { return npts_; } - virtual Spec spec() const; + virtual Spec spec() const override; /** * Human readable name * Either the name is the one given at construction as a canonical named grid, * or the name "structured" */ - virtual std::string name() const; + virtual std::string name() const override; - virtual std::string type() const; + virtual std::string type() const override; - inline size_t ny() const { return y_.size(); } + inline idx_t ny() const { return static_cast( y_.size() ); } - inline size_t nx( size_t j ) const { return static_cast( nx_[j] ); } + inline idx_t nx( idx_t j ) const { return static_cast( nx_[j] ); } - inline size_t nxmax() const { return nxmax_; } + inline idx_t nxmax() const { return nxmax_; } - inline size_t nxmin() const { return nxmin_; } + inline idx_t nxmin() const { return nxmin_; } - inline const std::vector& nx() const { return nx_; } + inline const std::vector& nx() const { return nx_; } inline const std::vector& y() const { return y_; } - inline double x( size_t i, size_t j ) const { return xmin_[j] + static_cast( i ) * dx_[j]; } + inline double dx( idx_t j ) const { return dx_[j]; } + + inline double x( idx_t i, idx_t j ) const { return xmin_[j] + static_cast( i ) * dx_[j]; } - inline double y( size_t j ) const { return y_[j]; } + inline double y( idx_t j ) const { return y_[j]; } - inline void xy( size_t i, size_t j, double crd[] ) const { + inline void xy( idx_t i, idx_t j, double crd[] ) const { crd[0] = x( i, j ); crd[1] = y( j ); } - PointXY xy( size_t i, size_t j ) const { return PointXY( x( i, j ), y( j ) ); } + PointXY xy( idx_t i, idx_t j ) const { return PointXY( x( i, j ), y( j ) ); } - PointLonLat lonlat( size_t i, size_t j ) const { return projection_.lonlat( xy( i, j ) ); } + PointLonLat lonlat( idx_t i, idx_t j ) const { return projection_.lonlat( xy( i, j ) ); } - void lonlat( size_t i, size_t j, double crd[] ) const { + void lonlat( idx_t i, idx_t j, double crd[] ) const { xy( i, j, crd ); projection_.xy2lonlat( crd ); } @@ -348,22 +345,22 @@ class Structured : public Grid { const XSpace& xspace() const { return xspace_; } const YSpace& yspace() const { return yspace_; } - virtual IteratorXY* xy_begin() const { return new IteratorXY( *this ); } - virtual IteratorXY* xy_end() const { return new IteratorXY( *this, false ); } - virtual IteratorLonLat* lonlat_begin() const { return new IteratorLonLat( *this ); } - virtual IteratorLonLat* lonlat_end() const { return new IteratorLonLat( *this, false ); } + virtual IteratorXY* xy_begin() const override { return new IteratorXY( *this ); } + virtual IteratorXY* xy_end() const override { return new IteratorXY( *this, false ); } + virtual IteratorLonLat* lonlat_begin() const override { return new IteratorLonLat( *this ); } + virtual IteratorLonLat* lonlat_end() const override { return new IteratorLonLat( *this, false ); } - virtual IteratorXYPredicated* xy_begin( IteratorXY::Predicate p ) const { + virtual IteratorXYPredicated* xy_begin( IteratorXY::Predicate p ) const override { return new IteratorXYPredicated( *this, p ); } - virtual IteratorXYPredicated* xy_end( IteratorXY::Predicate p ) const { + virtual IteratorXYPredicated* xy_end( IteratorXY::Predicate p ) const override { return new IteratorXYPredicated( *this, p, false ); } protected: // methods - virtual void print( std::ostream& ) const; + virtual void print( std::ostream& ) const override; - virtual void hash( eckit::Hash& ) const; + virtual void hash( eckit::Hash& ) const override; void computeTruePeriodicity(); @@ -373,19 +370,19 @@ class Structured : public Grid { protected: // Minimum number of points across parallels (constant y) - size_t nxmin_; + idx_t nxmin_; // Maximum number of points across parallels (constant y) - size_t nxmax_; + idx_t nxmax_; /// Total number of unique points in the grid - size_t npts_; + idx_t npts_; /// Latitude values std::vector y_; /// Number of points per latitude - std::vector nx_; + std::vector nx_; /// Value of minimum longitude per latitude [default=0] std::vector xmin_; @@ -418,20 +415,20 @@ Structured* atlas__grid__regular__ShiftedLonLat( long nx, long ny ); Structured* atlas__grid__regular__ShiftedLon( long nx, long ny ); Structured* atlas__grid__regular__ShiftedLat( long nx, long ny ); -void atlas__grid__Structured__nx_array( Structured* This, const long*& nx, size_t& size ); -long atlas__grid__Structured__nx( Structured* This, long j ); -long atlas__grid__Structured__ny( Structured* This ); -long atlas__grid__Structured__nxmin( Structured* This ); -long atlas__grid__Structured__nxmax( Structured* This ); -long atlas__grid__Structured__size( Structured* This ); -double atlas__grid__Structured__y( Structured* This, long j ); -double atlas__grid__Structured__x( Structured* This, long i, long j ); -void atlas__grid__Structured__xy( Structured* This, long i, long j, double crd[] ); -void atlas__grid__Structured__lonlat( Structured* This, long i, long j, double crd[] ); -void atlas__grid__Structured__y_array( Structured* This, const double*& lats, size_t& size ); +void atlas__grid__Structured__nx_array( Structured* This, const idx_t*& nx, idx_t& size ); +idx_t atlas__grid__Structured__nx( Structured* This, idx_t j ); +idx_t atlas__grid__Structured__ny( Structured* This ); +idx_t atlas__grid__Structured__nxmin( Structured* This ); +idx_t atlas__grid__Structured__nxmax( Structured* This ); +idx_t atlas__grid__Structured__size( Structured* This ); +double atlas__grid__Structured__y( Structured* This, idx_t j ); +double atlas__grid__Structured__x( Structured* This, idx_t i, idx_t j ); +void atlas__grid__Structured__xy( Structured* This, idx_t i, idx_t j, double crd[] ); +void atlas__grid__Structured__lonlat( Structured* This, idx_t i, idx_t j, double crd[] ); +void atlas__grid__Structured__y_array( Structured* This, const double*& lats, idx_t& size ); int atlas__grid__Structured__reduced( Structured* This ); -long atlas__grid__Gaussian__N( Structured* This ); +idx_t atlas__grid__Gaussian__N( Structured* This ); } } // namespace grid diff --git a/src/atlas/grid/detail/grid/Unstructured.cc b/src/atlas/grid/detail/grid/Unstructured.cc index e9b867011..64513e77a 100644 --- a/src/atlas/grid/detail/grid/Unstructured.cc +++ b/src/atlas/grid/detail/grid/Unstructured.cc @@ -10,27 +10,36 @@ #include "atlas/grid/detail/grid/Unstructured.h" +#include #include #include -#include "eckit/memory/Builder.h" #include "eckit/types/FloatCompare.h" +#include "eckit/utils/Hash.h" #include "atlas/array/ArrayView.h" #include "atlas/field/Field.h" #include "atlas/grid/Iterator.h" +#include "atlas/grid/detail/grid/GridFactory.h" #include "atlas/mesh/Mesh.h" #include "atlas/mesh/Nodes.h" #include "atlas/option.h" +#include "atlas/runtime/Exception.h" #include "atlas/runtime/Log.h" #include "atlas/util/CoordinateEnums.h" +#include "atlas/util/NormaliseLongitude.h" namespace atlas { namespace grid { namespace detail { namespace grid { -eckit::ConcreteBuilderT1 builder_Unstructured( Unstructured::static_type() ); +//static eckit::ConcreteBuilderT1 builder_Unstructured( Unstructured::static_type() ); + +namespace { +static GridFactoryBuilder __register_Unstructured( Unstructured::static_type() ); +} + Unstructured::Unstructured( const Mesh& m ) : Grid(), points_( new std::vector( m.nodes().size() ) ) { util::Config config_domain; @@ -39,9 +48,9 @@ Unstructured::Unstructured( const Mesh& m ) : Grid(), points_( new std::vector

( m.nodes().xy() ); std::vector& p = *points_; - const size_t npts = p.size(); + const idx_t npts = static_cast( p.size() ); - for ( size_t n = 0; n < npts; ++n ) { + for ( idx_t n = 0; n < npts; ++n ) { p[n].assign( xy( n, XX ), xy( n, YY ) ); } } @@ -52,27 +61,16 @@ class Normalise { public: Normalise( const RectangularDomain& domain ) : degrees_( domain.units() == "degrees" ), - xmin_( domain.xmin() ), - xmax_( domain.xmax() ), - eps_( 1e-11 ) {} + normalise_( domain.xmin(), domain.xmax() ) {} double operator()( double x ) const { - if ( degrees_ ) { - while ( eckit::types::is_strictly_greater( xmin_, x, eps_ ) ) { - x += 360.; - } - while ( eckit::types::is_strictly_greater( x, xmax_, eps_ ) ) { - x -= 360.; - } - } + if ( degrees_ ) { x = normalise_( x ); } return x; } private: const bool degrees_; - const double xmin_; - const double xmax_; - const double eps_; + NormaliseLongitude normalise_; }; } // namespace @@ -104,11 +102,11 @@ Unstructured::Unstructured( const Grid& grid, Domain domain ) : Grid() { points_->shrink_to_fit(); } -Unstructured::Unstructured( const util::Config& p ) : Grid() { +Unstructured::Unstructured( const util::Config& ) : Grid() { util::Config config_domain; config_domain.set( "type", "global" ); domain_ = Domain( config_domain ); - NOTIMP; + ATLAS_NOTIMPLEMENTED; } Unstructured::Unstructured( std::vector* pts ) : Grid(), points_( pts ) { @@ -145,12 +143,12 @@ Grid::uid_t Unstructured::name() const { } void Unstructured::hash( eckit::Hash& h ) const { - ASSERT( points_ ); + ATLAS_ASSERT( points_ != nullptr ); const std::vector& pts = *points_; h.add( &pts[0], sizeof( PointXY ) * pts.size() ); - for ( size_t i = 0; i < pts.size(); i++ ) { + for ( idx_t i = 0, N = static_cast( pts.size() ); i < N; i++ ) { const PointXY& p = pts[i]; h << p.x() << p.y(); } @@ -158,9 +156,9 @@ void Unstructured::hash( eckit::Hash& h ) const { projection().hash( h ); } -size_t Unstructured::size() const { - ASSERT( points_ ); - return points_->size(); +idx_t Unstructured::size() const { + ATLAS_ASSERT( points_ != nullptr ); + return static_cast( points_->size() ); } Grid::Spec Unstructured::spec() const { @@ -175,7 +173,7 @@ Grid::Spec Unstructured::spec() const { std::unique_ptr it( xy_begin() ); std::vector coords( 2 * size() ); - size_t c( 0 ); + idx_t c( 0 ); PointXY xy; while ( it->next( xy ) ) { coords[c++] = xy.x(); @@ -191,6 +189,19 @@ void Unstructured::print( std::ostream& os ) const { os << "Unstructured(Npts:" << size() << ")"; } +bool Unstructured::IteratorXYPredicated::next( PointXY& /*xy*/ ) { + ATLAS_NOTIMPLEMENTED; +#if 0 + if ( n_ != grid_.points_->size() ) { + xy = grid_.xy( n_++ ); + return true; + } + else { + return false; + } +#endif +} + } // namespace grid } // namespace detail } // namespace grid diff --git a/src/atlas/grid/detail/grid/Unstructured.h b/src/atlas/grid/detail/grid/Unstructured.h index 4b985e92b..799f979bf 100644 --- a/src/atlas/grid/detail/grid/Unstructured.h +++ b/src/atlas/grid/detail/grid/Unstructured.h @@ -20,9 +20,8 @@ #include #include -#include "eckit/utils/Hash.h" - #include "atlas/grid/detail/grid/Grid.h" +#include "atlas/util/Point.h" namespace atlas { class Mesh; @@ -39,10 +38,11 @@ class Unstructured : public Grid { public: IteratorXY( const Unstructured& grid, bool begin = true ) : grid_( grid ), - n_( begin ? 0 : grid_.points_->size() ) {} + size_( static_cast( grid_.points_->size() ) ), + n_( begin ? 0 : size_ ) {} virtual bool next( PointXY& xy ) { - if ( n_ != grid_.points_->size() ) { + if ( n_ != size_ ) { xy = grid_.xy( n_++ ); return true; } @@ -68,7 +68,8 @@ class Unstructured : public Grid { private: const Unstructured& grid_; - size_t n_; + idx_t size_; + idx_t n_; }; class IteratorXYPredicated : public Grid::IteratorXY { @@ -76,23 +77,12 @@ class Unstructured : public Grid { IteratorXYPredicated( const Unstructured& grid, Grid::IteratorXY::Predicate p, bool begin = true ) : grid_( grid ), p_( p ), - size_( grid_.points_->size() ), - n_( begin ? 0 : grid_.points_->size() ) { + size_( static_cast( grid_.points_->size() ) ), + n_( begin ? 0 : size_ ) { if ( begin ) {} } - virtual bool next( PointXY& xy ) { - NOTIMP; -#if 0 - if ( n_ != grid_.points_->size() ) { - xy = grid_.xy( n_++ ); - return true; - } - else { - return false; - } -#endif - } + virtual bool next( PointXY& xy ); virtual const PointXY operator*() const { return grid_.xy( n_ ); } @@ -115,18 +105,19 @@ class Unstructured : public Grid { private: const Unstructured& grid_; Grid::IteratorXY::Predicate p_; - size_t size_; - size_t n_; + idx_t size_; + idx_t n_; }; class IteratorLonLat : public Grid::IteratorLonLat { public: IteratorLonLat( const Unstructured& grid, bool begin = true ) : grid_( grid ), - n_( begin ? 0 : grid_.points_->size() ) {} + size_( static_cast( grid_.points_->size() ) ), + n_( begin ? 0 : size_ ) {} virtual bool next( PointLonLat& lonlat ) { - if ( n_ != grid_.points_->size() ) { + if ( n_ != size_ ) { lonlat = grid_.lonlat( n_++ ); return true; } @@ -152,7 +143,8 @@ class Unstructured : public Grid { private: const Unstructured& grid_; - size_t n_; + idx_t size_; + idx_t n_; }; @@ -181,13 +173,13 @@ class Unstructured : public Grid { virtual ~Unstructured(); - virtual size_t size() const; + virtual idx_t size() const; virtual Spec spec() const; - PointXY xy( size_t n ) const { return ( *points_ )[n]; } + PointXY xy( idx_t n ) const { return ( *points_ )[n]; } - PointLonLat lonlat( size_t n ) const { return projection_.lonlat( ( *points_ )[n] ); } + PointLonLat lonlat( idx_t n ) const { return projection_.lonlat( ( *points_ )[n] ); } virtual IteratorXY* xy_begin() const { return new IteratorXY( *this ); } virtual IteratorXY* xy_end() const { return new IteratorXY( *this, false ); } diff --git a/src/atlas/grid/detail/partitioner/CheckerboardPartitioner.cc b/src/atlas/grid/detail/partitioner/CheckerboardPartitioner.cc index 223c0d4ab..edfef30f7 100644 --- a/src/atlas/grid/detail/partitioner/CheckerboardPartitioner.cc +++ b/src/atlas/grid/detail/partitioner/CheckerboardPartitioner.cc @@ -1,4 +1,15 @@ -#include "atlas/grid/detail/partitioner/CheckerboardPartitioner.h" +/* + * (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 "CheckerboardPartitioner.h" #include #include @@ -7,7 +18,9 @@ #include #include -#include "atlas/grid/Grid.h" + +#include "atlas/grid/StructuredGrid.h" +#include "atlas/runtime/Exception.h" #include "atlas/runtime/Log.h" #include "atlas/util/MicroDeg.h" @@ -41,19 +54,19 @@ CheckerboardPartitioner::CheckerboardPartitioner( int N, int nbands, bool checke CheckerboardPartitioner::Checkerboard CheckerboardPartitioner::checkerboard( const Grid& grid ) const { // grid dimensions const RegularGrid rg( grid ); - if ( !rg ) throw eckit::BadValue( "Checkerboard Partitioner only works for Regular grids.", Here() ); + if ( !rg ) throw_Exception( "Checkerboard Partitioner only works for Regular grids.", Here() ); Checkerboard cb; - cb.nx = rg.nx(); - cb.ny = rg.ny(); - size_t nparts = nb_partitions(); + cb.nx = rg.nx(); + cb.ny = rg.ny(); + idx_t nparts = nb_partitions(); if ( nbands_ > 0 ) { cb.nbands = nbands_; } else { // default number of bands double zz = std::sqrt( (double)( nparts * cb.ny ) / cb.nx ); // aim at +/-square regions - cb.nbands = (int)zz + 0.5; + cb.nbands = (idx_t)zz + 0.5; if ( cb.nbands < 1 ) cb.nbands = 1; // at least one band if ( cb.nbands > nparts ) cb.nbands = nparts; // not more bands than procs @@ -64,7 +77,7 @@ CheckerboardPartitioner::Checkerboard CheckerboardPartitioner::checkerboard( con } } if ( checkerboard_ && nparts % cb.nbands != 0 ) - throw eckit::BadValue( "number of bands doesn't divide number of partitions", Here() ); + throw_Exception( "number of bands doesn't divide number of partitions", Here() ); return cb; } @@ -149,7 +162,7 @@ Number of gridpoints per band // for each band, select gridpoints belonging to that band, and sort them // according to X first size_t offset = 0; - size_t jpart = 0; + int jpart = 0; for ( size_t iband = 0; iband < nbands; iband++ ) { // sort according to X first std::sort( nodes + offset, nodes + offset + ngpb[iband], compare_X_Y ); @@ -190,7 +203,7 @@ std::cout << std::endl; void CheckerboardPartitioner::partition( const Grid& grid, int part[] ) const { if ( nb_partitions() == 1 ) // trivial solution, so much faster { - for ( size_t j = 0; j < grid.size(); ++j ) + for ( idx_t j = 0; j < grid.size(); ++j ) part[j] = 0; } else { @@ -199,11 +212,11 @@ void CheckerboardPartitioner::partition( const Grid& grid, int part[] ) const { std::vector nodes( grid.size() ); int n( 0 ); - for ( size_t iy = 0; iy < cb.ny; ++iy ) { - for ( size_t ix = 0; ix < cb.nx; ++ix ) { - nodes[n].x = ix; - nodes[n].y = iy; - nodes[n].n = n; + for ( idx_t iy = 0; iy < cb.ny; ++iy ) { + for ( idx_t ix = 0; ix < cb.nx; ++ix ) { + nodes[n].x = static_cast( ix ); + nodes[n].y = static_cast( iy ); + nodes[n].n = static_cast( n ); ++n; } } diff --git a/src/atlas/grid/detail/partitioner/CheckerboardPartitioner.h b/src/atlas/grid/detail/partitioner/CheckerboardPartitioner.h index e6f981e14..69051a34e 100644 --- a/src/atlas/grid/detail/partitioner/CheckerboardPartitioner.h +++ b/src/atlas/grid/detail/partitioner/CheckerboardPartitioner.h @@ -1,3 +1,13 @@ +/* + * (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 @@ -31,8 +41,8 @@ class CheckerboardPartitioner : public Partitioner { private: struct Checkerboard { - size_t nbands; // number of bands - size_t nx, ny; // grid dimensions + idx_t nbands; // number of bands + idx_t nx, ny; // grid dimensions }; Checkerboard checkerboard( const Grid& ) const; @@ -46,7 +56,7 @@ class CheckerboardPartitioner : public Partitioner { void check() const; private: - size_t nbands_; // number of bands from configuration + idx_t nbands_; // number of bands from configuration bool checkerboard_; // exact (true) or approximate (false) checkerboard }; diff --git a/src/atlas/grid/detail/partitioner/EqualRegionsPartitioner.cc b/src/atlas/grid/detail/partitioner/EqualRegionsPartitioner.cc index c21e8ac73..d5714837a 100644 --- a/src/atlas/grid/detail/partitioner/EqualRegionsPartitioner.cc +++ b/src/atlas/grid/detail/partitioner/EqualRegionsPartitioner.cc @@ -17,9 +17,11 @@ #include #include -#include "atlas/grid/Grid.h" +#include "atlas/grid/Iterator.h" +#include "atlas/grid/StructuredGrid.h" #include "atlas/parallel/mpi/Buffer.h" #include "atlas/parallel/mpi/mpi.h" +#include "atlas/runtime/Exception.h" #include "atlas/runtime/Log.h" #include "atlas/runtime/Trace.h" #include "atlas/util/MicroDeg.h" @@ -528,17 +530,17 @@ void EqualRegionsPartitioner::partition( int nb_nodes, NodeInt nodes[], int part void EqualRegionsPartitioner::partition( const Grid& grid, int part[] ) const { if ( N_ == 1 ) { // trivial solution, so much faster - for ( size_t j = 0; j < grid.size(); ++j ) + for ( idx_t j = 0; j < grid.size(); ++j ) part[j] = 0; } else { ATLAS_TRACE( "EqualRegionsPartitioner::partition" ); - ASSERT( grid.projection().units() == "degrees" ); + ATLAS_ASSERT( grid.projection().units() == "degrees" ); const auto& comm = mpi::comm(); - int mpi_rank = comm.rank(); - int mpi_size = comm.size(); + int mpi_rank = static_cast( comm.rank() ); + int mpi_size = static_cast( comm.size() ); std::vector nodes( grid.size() ); int* nodes_buffer = reinterpret_cast( nodes.data() ); @@ -554,16 +556,16 @@ void EqualRegionsPartitioner::partition( const Grid& grid, int part[] ) const { if ( StructuredGrid( grid ) ) { // The grid comes sorted from north to south and west to east by // construction - // Assert to make sure. + // ATLAS_ASSERT to make sure. StructuredGrid structured_grid( grid ); - ASSERT( structured_grid.y( 1 ) < structured_grid.y( 0 ) ); - ASSERT( structured_grid.x( 1, 0 ) > structured_grid.x( 0, 0 ) ); + ATLAS_ASSERT( structured_grid.y( 1 ) < structured_grid.y( 0 ) ); + ATLAS_ASSERT( structured_grid.x( 1, 0 ) > structured_grid.x( 0, 0 ) ); ATLAS_TRACE( "Take shortcut" ); int n( 0 ); - for ( size_t j = 0; j < structured_grid.ny(); ++j ) { + for ( idx_t j = 0; j < structured_grid.ny(); ++j ) { double y = microdeg( structured_grid.y( j ) ); - for ( size_t i = 0; i < structured_grid.nx( j ); ++i, ++n ) { + for ( idx_t i = 0; i < structured_grid.nx( j ); ++i, ++n ) { nodes[n].x = microdeg( structured_grid.x( i, j ) ); nodes[n].y = y; nodes[n].n = n; @@ -606,8 +608,8 @@ void EqualRegionsPartitioner::partition( const Grid& grid, int part[] ) const { } } else { - int i( 0 ); - int j( 0 ); + idx_t i( 0 ); + idx_t j( 0 ); for ( PointXY point : grid.xy() ) { if ( i >= w_begin && i < w_end ) { w_nodes[j].x = microdeg( point.x() ); diff --git a/src/atlas/grid/detail/partitioner/MatchingMeshPartitioner.cc b/src/atlas/grid/detail/partitioner/MatchingMeshPartitioner.cc new file mode 100644 index 000000000..4492a9759 --- /dev/null +++ b/src/atlas/grid/detail/partitioner/MatchingMeshPartitioner.cc @@ -0,0 +1,34 @@ +/* + * (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/MatchingMeshPartitioner.h" +#include "atlas/runtime/Exception.h" + +namespace atlas { +namespace grid { +namespace detail { +namespace partitioner { + +MatchingMeshPartitioner::MatchingMeshPartitioner() : Partitioner() { + ATLAS_NOTIMPLEMENTED; +} + +MatchingMeshPartitioner::MatchingMeshPartitioner( const idx_t nb_partitions ) : Partitioner( nb_partitions ) { + ATLAS_NOTIMPLEMENTED; +} + +MatchingMeshPartitioner::MatchingMeshPartitioner( const Mesh& mesh ) : + Partitioner( mesh.nb_partitions() ), + prePartitionedMesh_( mesh ) {} + +} // namespace partitioner +} // namespace detail +} // namespace grid +} // namespace atlas diff --git a/src/atlas/grid/detail/partitioner/MatchingMeshPartitioner.h b/src/atlas/grid/detail/partitioner/MatchingMeshPartitioner.h index e18e57d45..be9297b31 100644 --- a/src/atlas/grid/detail/partitioner/MatchingMeshPartitioner.h +++ b/src/atlas/grid/detail/partitioner/MatchingMeshPartitioner.h @@ -12,9 +12,8 @@ #include -#include "eckit/exception/Exceptions.h" - #include "atlas/grid/detail/partitioner/Partitioner.h" +#include "atlas/mesh/Mesh.h" namespace atlas { namespace grid { @@ -23,13 +22,13 @@ namespace partitioner { class MatchingMeshPartitioner : public Partitioner { public: - MatchingMeshPartitioner() : Partitioner() { NOTIMP; } + MatchingMeshPartitioner(); - MatchingMeshPartitioner( const size_t nb_partitions ) : Partitioner( nb_partitions ) { NOTIMP; } + MatchingMeshPartitioner( const idx_t nb_partitions ); - MatchingMeshPartitioner( const Mesh& mesh ) : Partitioner( mesh.nb_partitions() ), prePartitionedMesh_( mesh ) {} + MatchingMeshPartitioner( const Mesh& mesh ); - virtual ~MatchingMeshPartitioner() {} + virtual ~MatchingMeshPartitioner() override {} protected: const Mesh prePartitionedMesh_; diff --git a/src/atlas/grid/detail/partitioner/MatchingMeshPartitionerBruteForce.cc b/src/atlas/grid/detail/partitioner/MatchingMeshPartitionerBruteForce.cc index 594405720..5e0541433 100644 --- a/src/atlas/grid/detail/partitioner/MatchingMeshPartitionerBruteForce.cc +++ b/src/atlas/grid/detail/partitioner/MatchingMeshPartitionerBruteForce.cc @@ -12,9 +12,7 @@ #include -#include "eckit/geometry/Point2.h" #include "eckit/log/ProgressTimer.h" -#include "eckit/mpi/Comm.h" #include "atlas/array/ArrayView.h" #include "atlas/field/Field.h" @@ -22,7 +20,10 @@ #include "atlas/mesh/Elements.h" #include "atlas/mesh/Mesh.h" #include "atlas/mesh/Nodes.h" +#include "atlas/parallel/mpi/mpi.h" +#include "atlas/runtime/Exception.h" #include "atlas/runtime/Log.h" +#include "atlas/runtime/Trace.h" #include "atlas/util/CoordinateEnums.h" namespace atlas { @@ -72,6 +73,9 @@ bool point_in_quadrilateral( const PointLonLat& P, const PointLonLat& A, const P } // namespace void MatchingMeshPartitionerBruteForce::partition( const Grid& grid, int partitioning[] ) const { + ATLAS_TRACE( "MatchingMeshPartitionerBruteForce::partition" ); + + eckit::mpi::Comm& comm = eckit::mpi::comm(); const int mpi_rank = int( comm.rank() ); @@ -81,18 +85,18 @@ void MatchingMeshPartitionerBruteForce::partition( const Grid& grid, int partiti // FIXME: THIS IS A HACK! the coordinates include North/South Pole // (first/last partitions only) - ASSERT( grid.domain().global() ); + ATLAS_ASSERT( grid.domain().global() ); bool includesNorthPole = ( mpi_rank == 0 ); bool includesSouthPole = ( mpi_rank == ( int( comm.size() ) - 1 ) ); - ASSERT( prePartitionedMesh_.nodes().size() ); + ATLAS_ASSERT( prePartitionedMesh_.nodes().size() ); auto lonlat_src = array::make_view( prePartitionedMesh_.nodes().lonlat() ); std::vector coordinates; PointLonLat coordinatesMin = PointLonLat( lonlat_src( 0, LON ), lonlat_src( 0, LAT ) ); PointLonLat coordinatesMax = coordinatesMin; - for ( size_t i = 0; i < lonlat_src.size(); ++i ) { + for ( idx_t i = 0; i < lonlat_src.size(); ++i ) { PointLonLat A( lonlat_src( i, LON ), lonlat_src( i, LAT ) ); coordinatesMin = PointLonLat::componentsMin( coordinatesMin, A ); coordinatesMax = PointLonLat::componentsMax( coordinatesMax, A ); @@ -101,30 +105,30 @@ void MatchingMeshPartitionerBruteForce::partition( const Grid& grid, int partiti { eckit::ProgressTimer timer( "Partitioning target", grid.size(), "point", double( 10 ), atlas::Log::trace() ); - for ( size_t i = 0; i < grid.size(); ++i, ++timer ) { + for ( idx_t i = 0; i < grid.size(); ++i, ++timer ) { partitioning[i] = -1; const PointLonLat& P( coordinates[i] ); if ( coordinatesMin[LON] <= P[LON] && P[LON] <= coordinatesMax[LON] && coordinatesMin[LAT] <= P[LAT] && P[LAT] <= coordinatesMax[LAT] ) { const mesh::Cells& elements_src = prePartitionedMesh_.cells(); - const size_t nb_types = elements_src.nb_types(); + const idx_t nb_types = elements_src.nb_types(); bool found = false; - for ( size_t t = 0; t < nb_types && !found; ++t ) { - size_t idx[4]; + for ( idx_t t = 0; t < nb_types && !found; ++t ) { + idx_t idx[4]; const mesh::Elements& elements = elements_src.elements( t ); const mesh::BlockConnectivity& conn = elements.node_connectivity(); - const size_t nb_nodes = elements.nb_nodes(); - ASSERT( ( nb_nodes == 3 && elements.name() == "Triangle" ) || - ( nb_nodes == 4 && elements.name() == "Quadrilateral" ) ); + const idx_t nb_nodes = elements.nb_nodes(); + ATLAS_ASSERT( ( nb_nodes == 3 && elements.name() == "Triangle" ) || + ( nb_nodes == 4 && elements.name() == "Quadrilateral" ) ); - for ( size_t j = 0; j < elements.size() && !found; ++j ) { - idx[0] = static_cast( conn( j, 0 ) ); - idx[1] = static_cast( conn( j, 1 ) ); - idx[2] = static_cast( conn( j, 2 ) ); - idx[3] = nb_nodes > 3 ? static_cast( conn( j, 3 ) ) : 0; + for ( idx_t j = 0; j < elements.size() && !found; ++j ) { + idx[0] = conn( j, 0 ); + idx[1] = conn( j, 1 ); + idx[2] = conn( j, 2 ); + idx[3] = nb_nodes > 3 ? conn( j, 3 ) : 0; if ( ( elements.name() == "Triangle" && point_in_triangle( P, coordinates[idx[0]], coordinates[idx[1]], @@ -149,7 +153,7 @@ void MatchingMeshPartitionerBruteForce::partition( const Grid& grid, int partiti comm.allReduceInPlace( partitioning, grid.size(), eckit::mpi::Operation::MAX ); const int min = *std::min_element( partitioning, partitioning + grid.size() ); if ( min < 0 ) { - throw eckit::SeriousBug( + throw_Exception( "Could not find partition for target node (source " "mesh does not contain all target grid points)", Here() ); diff --git a/src/atlas/grid/detail/partitioner/MatchingMeshPartitionerBruteForce.h b/src/atlas/grid/detail/partitioner/MatchingMeshPartitionerBruteForce.h index 700ad8b8e..1c3a2406c 100644 --- a/src/atlas/grid/detail/partitioner/MatchingMeshPartitionerBruteForce.h +++ b/src/atlas/grid/detail/partitioner/MatchingMeshPartitionerBruteForce.h @@ -23,7 +23,7 @@ class MatchingMeshPartitionerBruteForce : public MatchingMeshPartitioner { public: MatchingMeshPartitionerBruteForce() : MatchingMeshPartitioner() {} - MatchingMeshPartitionerBruteForce( const size_t nb_partitions ) : MatchingMeshPartitioner( nb_partitions ) {} + MatchingMeshPartitionerBruteForce( const idx_t nb_partitions ) : MatchingMeshPartitioner( nb_partitions ) {} MatchingMeshPartitionerBruteForce( const Mesh& mesh ) : MatchingMeshPartitioner( mesh ) {} virtual void partition( const Grid& grid, int partitioning[] ) const; diff --git a/src/atlas/grid/detail/partitioner/MatchingMeshPartitionerLonLatPolygon.cc b/src/atlas/grid/detail/partitioner/MatchingMeshPartitionerLonLatPolygon.cc index 0fc38d583..945820b8c 100644 --- a/src/atlas/grid/detail/partitioner/MatchingMeshPartitionerLonLatPolygon.cc +++ b/src/atlas/grid/detail/partitioner/MatchingMeshPartitionerLonLatPolygon.cc @@ -16,8 +16,10 @@ #include "eckit/log/ProgressTimer.h" #include "atlas/grid/Grid.h" +#include "atlas/grid/Iterator.h" #include "atlas/mesh/Nodes.h" #include "atlas/parallel/mpi/mpi.h" +#include "atlas/runtime/Exception.h" #include "atlas/runtime/Log.h" #include "atlas/util/LonLatPolygon.h" @@ -35,7 +37,9 @@ void MatchingMeshPartitionerLonLatPolygon::partition( const Grid& grid, int part const int mpi_rank = int( comm.rank() ); const int mpi_size = int( comm.size() ); - ASSERT( grid.domain().global() ); + ATLAS_TRACE( "MatchingMeshPartitionerLonLatPolygon::partition" ); + + ATLAS_ASSERT( grid.domain().global() ); Log::debug() << "MatchingMeshPartitionerLonLatPolygon::partition" << std::endl; @@ -64,7 +68,7 @@ void MatchingMeshPartitionerLonLatPolygon::partition( const Grid& grid, int part comm.allReduceInPlace( partitioning, grid.size(), eckit::mpi::Operation::MAX ); const int min = *std::min_element( partitioning, partitioning + grid.size() ); if ( min < 0 ) { - throw eckit::SeriousBug( + throw_Exception( "Could not find partition for target node (source " "mesh does not contain all target grid points)", Here() ); diff --git a/src/atlas/grid/detail/partitioner/MatchingMeshPartitionerSphericalPolygon.cc b/src/atlas/grid/detail/partitioner/MatchingMeshPartitionerSphericalPolygon.cc index 39d52178f..ff73760e8 100644 --- a/src/atlas/grid/detail/partitioner/MatchingMeshPartitionerSphericalPolygon.cc +++ b/src/atlas/grid/detail/partitioner/MatchingMeshPartitionerSphericalPolygon.cc @@ -15,8 +15,10 @@ #include "eckit/log/ProgressTimer.h" #include "atlas/grid/Grid.h" +#include "atlas/grid/Iterator.h" #include "atlas/mesh/Nodes.h" #include "atlas/parallel/mpi/mpi.h" +#include "atlas/runtime/Exception.h" #include "atlas/runtime/Log.h" #include "atlas/util/SphericalPolygon.h" @@ -34,7 +36,9 @@ void MatchingMeshPartitionerSphericalPolygon::partition( const Grid& grid, int p const int mpi_rank = int( comm.rank() ); const int mpi_size = int( comm.size() ); - ASSERT( grid.domain().global() ); + ATLAS_TRACE( "MatchingMeshPartitionerSphericalPolygon::partition" ); + + ATLAS_ASSERT( grid.domain().global() ); Log::debug() << "MatchingMeshPartitionerSphericalPolygon::partition" << std::endl; @@ -44,6 +48,11 @@ void MatchingMeshPartitionerSphericalPolygon::partition( const Grid& grid, int p bool includesSouthPole = ( mpi_rank == mpi_size - 1 ); const util::SphericalPolygon poly( prePartitionedMesh_.polygon( 0 ), prePartitionedMesh_.nodes().lonlat() ); + const double maxlat = poly.coordinatesMax().lat(); + const double minlat = poly.coordinatesMin().lat(); + auto at_the_pole = [&]( const PointLonLat& P ) { + return ( includesNorthPole && P.lat() >= maxlat ) || ( includesSouthPole && P.lat() < minlat ); + }; { eckit::ProgressTimer timer( "Partitioning", grid.size(), "point", double( 10 ), atlas::Log::trace() ); @@ -51,11 +60,8 @@ void MatchingMeshPartitionerSphericalPolygon::partition( const Grid& grid, int p for ( const PointXY Pxy : grid.xy() ) { ++timer; - const PointLonLat P = grid.projection().lonlat( Pxy ); - const bool atThePole = ( includesNorthPole && P.lat() >= poly.coordinatesMax().lat() ) || - ( includesSouthPole && P.lat() < poly.coordinatesMin().lat() ); - - partitioning[i++] = atThePole || poly.contains( P ) ? mpi_rank : -1; + const PointLonLat P = grid.projection().lonlat( Pxy ); + partitioning[i++] = at_the_pole( P ) || poly.contains( P ) ? mpi_rank : -1; } } @@ -63,7 +69,7 @@ void MatchingMeshPartitionerSphericalPolygon::partition( const Grid& grid, int p comm.allReduceInPlace( partitioning, grid.size(), eckit::mpi::Operation::MAX ); const int min = *std::min_element( partitioning, partitioning + grid.size() ); if ( min < 0 ) { - throw eckit::SeriousBug( + throw_Exception( "Could not find partition for target node (source " "mesh does not contain all target grid points)", Here() ); diff --git a/src/atlas/grid/detail/partitioner/MatchingMeshPartitionerSphericalPolygon.h b/src/atlas/grid/detail/partitioner/MatchingMeshPartitionerSphericalPolygon.h index acabc70ae..c0317d76a 100644 --- a/src/atlas/grid/detail/partitioner/MatchingMeshPartitionerSphericalPolygon.h +++ b/src/atlas/grid/detail/partitioner/MatchingMeshPartitionerSphericalPolygon.h @@ -23,7 +23,7 @@ class MatchingMeshPartitionerSphericalPolygon : public MatchingMeshPartitioner { public: MatchingMeshPartitionerSphericalPolygon() : MatchingMeshPartitioner() {} - MatchingMeshPartitionerSphericalPolygon( const size_t nb_partitions ) : MatchingMeshPartitioner( nb_partitions ) {} + MatchingMeshPartitionerSphericalPolygon( const idx_t nb_partitions ) : MatchingMeshPartitioner( nb_partitions ) {} MatchingMeshPartitionerSphericalPolygon( const Mesh& mesh ) : MatchingMeshPartitioner( mesh ) {} /** diff --git a/src/atlas/grid/detail/partitioner/Partitioner.cc b/src/atlas/grid/detail/partitioner/Partitioner.cc index fad9ee532..b12ec8297 100644 --- a/src/atlas/grid/detail/partitioner/Partitioner.cc +++ b/src/atlas/grid/detail/partitioner/Partitioner.cc @@ -18,6 +18,7 @@ #include "atlas/grid/Distribution.h" #include "atlas/grid/Partitioner.h" +#include "atlas/grid/detail/partitioner/CheckerboardPartitioner.h" #include "atlas/grid/detail/partitioner/EqualRegionsPartitioner.h" #include "atlas/grid/detail/partitioner/MatchingMeshPartitioner.h" #include "atlas/grid/detail/partitioner/MatchingMeshPartitionerBruteForce.h" @@ -25,6 +26,7 @@ #include "atlas/grid/detail/partitioner/MatchingMeshPartitionerSphericalPolygon.h" #include "atlas/library/config.h" #include "atlas/parallel/mpi/mpi.h" +#include "atlas/runtime/Exception.h" #include "atlas/runtime/Log.h" #if ATLAS_HAVE_TRANS @@ -33,8 +35,8 @@ namespace { -static eckit::Mutex* local_mutex = 0; -static std::map* m = 0; +static eckit::Mutex* local_mutex = nullptr; +static std::map* m = nullptr; static pthread_once_t once = PTHREAD_ONCE_INIT; static void init() { @@ -50,11 +52,11 @@ namespace partitioner { Partitioner::Partitioner() : nb_partitions_( mpi::comm().size() ) {} -Partitioner::Partitioner( const size_t nb_partitions ) : nb_partitions_( nb_partitions ) {} +Partitioner::Partitioner( const idx_t nb_partitions ) : nb_partitions_( nb_partitions ) {} Partitioner::~Partitioner() {} -size_t Partitioner::nb_partitions() const { +idx_t Partitioner::nb_partitions() const { return nb_partitions_; } @@ -72,6 +74,7 @@ void load_builder() { struct force_link { force_link() { load_builder(); + load_builder(); #if ATLAS_HAVE_TRANS load_builder(); #endif @@ -85,7 +88,7 @@ PartitionerFactory::PartitionerFactory( const std::string& name ) : name_( name eckit::AutoLock lock( local_mutex ); - ASSERT( m->find( name ) == m->end() ); + ATLAS_ASSERT( m->find( name ) == m->end() ); ( *m )[name] = this; } @@ -134,13 +137,13 @@ Partitioner* PartitionerFactory::build( const std::string& name ) { Log::error() << "PartitionerFactories are:" << '\n'; for ( j = m->begin(); j != m->end(); ++j ) Log::error() << " " << ( *j ).first << '\n'; - throw eckit::SeriousBug( std::string( "No PartitionerFactory called " ) + name ); + throw_Exception( std::string( "No PartitionerFactory called " ) + name ); } return ( *j ).second->make(); } -Partitioner* PartitionerFactory::build( const std::string& name, const size_t nb_partitions ) { +Partitioner* PartitionerFactory::build( const std::string& name, const idx_t nb_partitions ) { pthread_once( &once, init ); eckit::AutoLock lock( local_mutex ); @@ -156,7 +159,7 @@ Partitioner* PartitionerFactory::build( const std::string& name, const size_t nb Log::error() << "PartitionerFactories are:" << '\n'; for ( j = m->begin(); j != m->end(); ++j ) Log::error() << " " << ( *j ).first << '\n'; - throw eckit::SeriousBug( std::string( "No PartitionerFactory called " ) + name ); + throw_Exception( std::string( "No PartitionerFactory called " ) + name ); } return ( *j ).second->make( nb_partitions ); @@ -179,7 +182,7 @@ grid::detail::partitioner::Partitioner* MatchedPartitionerFactory::build( const return new MatchingMeshPartitionerBruteForce( partitioned ); } else { - NOTIMP; + ATLAS_NOTIMPLEMENTED; } } diff --git a/src/atlas/grid/detail/partitioner/Partitioner.h b/src/atlas/grid/detail/partitioner/Partitioner.h index 663dfeb0f..159e36792 100644 --- a/src/atlas/grid/detail/partitioner/Partitioner.h +++ b/src/atlas/grid/detail/partitioner/Partitioner.h @@ -10,36 +10,44 @@ #pragma once -#include "eckit/memory/Owned.h" +#include -#include "atlas/grid/Distribution.h" -#include "atlas/grid/Grid.h" -#include "atlas/mesh/Mesh.h" +#include "atlas/util/Object.h" + +#include "atlas/library/config.h" + +namespace atlas { +class Grid; +class Mesh; +namespace grid { +class Distribution; +} // namespace grid +} // namespace atlas namespace atlas { namespace grid { namespace detail { namespace partitioner { -class Partitioner : public eckit::Owned { +class Partitioner : public util::Object { public: using Grid = atlas::Grid; public: Partitioner(); - Partitioner( const size_t nb_partitions ); + Partitioner( const idx_t nb_partitions ); virtual ~Partitioner(); virtual void partition( const Grid& grid, int part[] ) const = 0; Distribution partition( const Grid& grid ) const; - size_t nb_partitions() const; + idx_t nb_partitions() const; virtual std::string type() const = 0; private: - size_t nb_partitions_; + idx_t nb_partitions_; }; // ------------------------------------------------------------------ @@ -54,7 +62,7 @@ class PartitionerFactory { * \return Partitioner */ static Partitioner* build( const std::string& ); - static Partitioner* build( const std::string&, const size_t nb_partitions ); + static Partitioner* build( const std::string&, const idx_t nb_partitions ); /*! * \brief list all registered partioner builders @@ -64,8 +72,8 @@ class PartitionerFactory { private: std::string name_; - virtual Partitioner* make() = 0; - virtual Partitioner* make( const size_t nb_partitions ) = 0; + virtual Partitioner* make() = 0; + virtual Partitioner* make( const idx_t nb_partitions ) = 0; protected: PartitionerFactory( const std::string& ); @@ -78,7 +86,7 @@ template class PartitionerBuilder : public PartitionerFactory { virtual Partitioner* make() { return new T(); } - virtual Partitioner* make( const size_t nb_partitions ) { return new T( nb_partitions ); } + virtual Partitioner* make( const idx_t nb_partitions ) { return new T( nb_partitions ); } public: PartitionerBuilder( const std::string& name ) : PartitionerFactory( name ) {} diff --git a/src/atlas/grid/detail/partitioner/TransPartitioner.cc b/src/atlas/grid/detail/partitioner/TransPartitioner.cc index 059205211..510af0385 100644 --- a/src/atlas/grid/detail/partitioner/TransPartitioner.cc +++ b/src/atlas/grid/detail/partitioner/TransPartitioner.cc @@ -8,13 +8,14 @@ * nor does it submit to any jurisdiction. */ -#include "eckit/exception/Exceptions.h" +#include #include "atlas/array.h" #include "atlas/grid/Grid.h" #include "atlas/grid/detail/partitioner/EqualRegionsPartitioner.h" #include "atlas/grid/detail/partitioner/TransPartitioner.h" #include "atlas/parallel/mpi/mpi.h" +#include "atlas/runtime/Exception.h" #include "atlas/runtime/Trace.h" #include "atlas/trans/ifs/TransIFS.h" @@ -32,7 +33,7 @@ TransPartitioner::TransPartitioner() : Partitioner() { } } -TransPartitioner::TransPartitioner( const size_t N ) : Partitioner( N ) { +TransPartitioner::TransPartitioner( const idx_t N ) : Partitioner( N ) { EqualRegionsPartitioner eqreg( nb_partitions() ); nbands_ = eqreg.nb_bands(); nregions_.resize( nbands_ ); @@ -47,11 +48,10 @@ void TransPartitioner::partition( const Grid& grid, int part[] ) const { ATLAS_TRACE( "TransPartitioner::partition" ); StructuredGrid g( grid ); - if ( not g ) - throw eckit::BadCast( "Grid is not a grid::Structured type. Cannot partition using IFS trans", Here() ); + if ( not g ) throw_Exception( "Grid is not a grid::Structured type. Cannot partition using IFS trans", Here() ); trans::TransIFS t( grid ); - if ( nb_partitions() != size_t( t.nproc() ) ) { + if ( nb_partitions() != idx_t( t.nproc() ) ) { std::stringstream msg; msg << "Requested to partition grid with TransPartitioner in " << nb_partitions() << " partitions, but " @@ -59,7 +59,7 @@ void TransPartitioner::partition( const Grid& grid, int part[] ) const { << t.nproc() << " partitions " "(equal to number of MPI tasks in communicator)."; - throw eckit::BadParameter( msg.str(), Here() ); + throw_Exception( msg.str(), Here() ); } int nlonmax = g.nxmax(); @@ -89,8 +89,8 @@ void TransPartitioner::partition( const Grid& grid, int part[] ) const { for ( int jgl = nfrstlat( ja ) - 1; jgl < nlstlat( ja ); ++jgl ) { int igl = nptrfrstlat( ja ) + jgl - nfrstlat( ja ); for ( int jl = nsta( jb, igl ) - 1; jl < nsta( jb, igl ) + nonl( jb, igl ) - 1; ++jl ) { - size_t ind = iglobal[jgl * nlonmax + jl] - 1; - if ( ind >= grid.size() ) throw eckit::OutOfRange( ind, grid.size(), Here() ); + idx_t ind = iglobal[jgl * nlonmax + jl] - 1; + if ( ind >= grid.size() ) throw_OutOfRange( "part", ind, grid.size(), Here() ); part[ind] = iproc; } } diff --git a/src/atlas/grid/detail/partitioner/TransPartitioner.h b/src/atlas/grid/detail/partitioner/TransPartitioner.h index 1cfcb8b17..4d1ccb5c1 100644 --- a/src/atlas/grid/detail/partitioner/TransPartitioner.h +++ b/src/atlas/grid/detail/partitioner/TransPartitioner.h @@ -30,7 +30,7 @@ class TransPartitioner : public Partitioner { /// @brief Constructor TransPartitioner(); - TransPartitioner( const size_t nb_partitions ); + TransPartitioner( const idx_t nb_partitions ); virtual ~TransPartitioner(); diff --git a/src/atlas/grid/detail/pl/classic_gaussian/N.cc b/src/atlas/grid/detail/pl/classic_gaussian/N.cc index 6bc286c79..5aaf77b66 100644 --- a/src/atlas/grid/detail/pl/classic_gaussian/N.cc +++ b/src/atlas/grid/detail/pl/classic_gaussian/N.cc @@ -13,18 +13,22 @@ #include "N.h" +#include "atlas/runtime/Exception.h" + namespace atlas { namespace grid { namespace detail { namespace pl { namespace classic_gaussian { -std::string PointsPerLatitude::className() { - return "atlas.grid.reduced.pl.classic_gaussian.PointsPerLatitude"; +void PointsPerLatitude::assign( long nlon[], const size_t size ) const { + ATLAS_ASSERT( size >= nlon_.size() ); + for ( size_t jlat = 0; jlat < nlon_.size(); ++jlat ) + nlon[jlat] = nlon_[jlat]; } -void PointsPerLatitude::assign( long nlon[], const size_t size ) const { - ASSERT( size >= nlon_.size() ); +void PointsPerLatitude::assign( int nlon[], const size_t size ) const { + ATLAS_ASSERT( size >= nlon_.size() ); for ( size_t jlat = 0; jlat < nlon_.size(); ++jlat ) nlon[jlat] = nlon_[jlat]; } @@ -33,9 +37,13 @@ void PointsPerLatitude::assign( std::vector& nlon ) const { nlon = nlon_; } +void PointsPerLatitude::assign( std::vector& nlon ) const { + nlon.assign( nlon_.begin(), nlon_.end() ); +} + template void load() { - eckit::ConcreteBuilderT0 builder( "tmp" ); + PointsPerLatitudeBuilder(); } void regist() { diff --git a/src/atlas/grid/detail/pl/classic_gaussian/N.h b/src/atlas/grid/detail/pl/classic_gaussian/N.h index f0bdf2c64..ceb7b304a 100644 --- a/src/atlas/grid/detail/pl/classic_gaussian/N.h +++ b/src/atlas/grid/detail/pl/classic_gaussian/N.h @@ -13,8 +13,10 @@ #pragma once -#include "eckit/memory/Builder.h" -#include "eckit/memory/Owned.h" +#include +#include + +#include "atlas/util/Factory.h" namespace atlas { namespace grid { @@ -22,25 +24,49 @@ namespace detail { namespace pl { namespace classic_gaussian { -class PointsPerLatitude : public eckit::Owned { +class PointsPerLatitude { public: - typedef eckit::BuilderT0 builder_t; - - static std::string className(); - /// @pre nlats has enough allocated memory to store the latitudes /// @param size of lats vector void assign( long nlon[], const size_t size ) const; + /// @pre nlats has enough allocated memory to store the latitudes + /// @param size of lats vector + void assign( int nlon[], const size_t size ) const; + /// @post resizes the vector to the number of latitutes void assign( std::vector& nlon ) const; + /// @post resizes the vector to the number of latitutes + void assign( std::vector& nlon ) const; + size_t N() const { return nlon_.size(); } protected: std::vector nlon_; }; + +class PointsPerLatitudeFactory : public util::Factory { +public: + static std::string className() { return "PointsPerLatitudeFactory"; } + static const PointsPerLatitude* build( const std::string& builder ) { return get( builder )->make(); } + using Factory::Factory; + +private: + virtual const PointsPerLatitude* make() const = 0; +}; + +template +class PointsPerLatitudeBuilder : public PointsPerLatitudeFactory { +public: + using PointsPerLatitudeFactory::PointsPerLatitudeFactory; + +private: + virtual const PointsPerLatitude* make() const override { return new T(); } +}; + + #define DECLARE_POINTS_PER_LATITUDE( NUMBER ) \ class N##NUMBER : public PointsPerLatitude { \ public: \ @@ -48,15 +74,17 @@ class PointsPerLatitude : public eckit::Owned { }; #define LIST( ... ) __VA_ARGS__ -#define DEFINE_POINTS_PER_LATITUDE( NUMBER, NLON ) \ - eckit::ConcreteBuilderT0 builder_N##NUMBER( #NUMBER ); \ - \ - N##NUMBER::N##NUMBER() { \ - size_t N = NUMBER; \ - long nlon[] = {NLON}; \ - nlon_.assign( nlon, nlon + N ); \ +#define DEFINE_POINTS_PER_LATITUDE( NUMBER, NLON ) \ + N##NUMBER::N##NUMBER() { \ + size_t N = NUMBER; \ + long nlon[] = {NLON}; \ + nlon_.assign( nlon, nlon + N ); \ + } \ + namespace { \ + static PointsPerLatitudeBuilder builder_N##NUMBER( #NUMBER ); \ } + DECLARE_POINTS_PER_LATITUDE( 16 ); DECLARE_POINTS_PER_LATITUDE( 24 ); DECLARE_POINTS_PER_LATITUDE( 32 ); diff --git a/src/atlas/grid/detail/pl/classic_gaussian/N1024.cc b/src/atlas/grid/detail/pl/classic_gaussian/N1024.cc index b825c9e60..15d6fe319 100644 --- a/src/atlas/grid/detail/pl/classic_gaussian/N1024.cc +++ b/src/atlas/grid/detail/pl/classic_gaussian/N1024.cc @@ -1,3 +1,13 @@ +/* + * (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. + */ + // TL2047 #include "N.h" diff --git a/src/atlas/grid/detail/pl/classic_gaussian/N128.cc b/src/atlas/grid/detail/pl/classic_gaussian/N128.cc index 247e52dde..d8a2822b0 100644 --- a/src/atlas/grid/detail/pl/classic_gaussian/N128.cc +++ b/src/atlas/grid/detail/pl/classic_gaussian/N128.cc @@ -1,3 +1,13 @@ +/* + * (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. + */ + // TL255 #include "N.h" diff --git a/src/atlas/grid/detail/pl/classic_gaussian/N1280.cc b/src/atlas/grid/detail/pl/classic_gaussian/N1280.cc index 7d2280053..550267302 100644 --- a/src/atlas/grid/detail/pl/classic_gaussian/N1280.cc +++ b/src/atlas/grid/detail/pl/classic_gaussian/N1280.cc @@ -1,3 +1,13 @@ +/* + * (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. + */ + // TL2559 #include "N.h" diff --git a/src/atlas/grid/detail/pl/classic_gaussian/N16.cc b/src/atlas/grid/detail/pl/classic_gaussian/N16.cc index c3435033f..2ee8ccca9 100644 --- a/src/atlas/grid/detail/pl/classic_gaussian/N16.cc +++ b/src/atlas/grid/detail/pl/classic_gaussian/N16.cc @@ -1,3 +1,13 @@ +/* + * (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. + */ + // TL31 #include "N.h" diff --git a/src/atlas/grid/detail/pl/classic_gaussian/N160.cc b/src/atlas/grid/detail/pl/classic_gaussian/N160.cc index 1be4c0472..54fd65d25 100644 --- a/src/atlas/grid/detail/pl/classic_gaussian/N160.cc +++ b/src/atlas/grid/detail/pl/classic_gaussian/N160.cc @@ -1,3 +1,13 @@ +/* + * (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. + */ + // TL319 #include "N.h" diff --git a/src/atlas/grid/detail/pl/classic_gaussian/N1600.cc b/src/atlas/grid/detail/pl/classic_gaussian/N1600.cc index b993438c2..f0f72e864 100644 --- a/src/atlas/grid/detail/pl/classic_gaussian/N1600.cc +++ b/src/atlas/grid/detail/pl/classic_gaussian/N1600.cc @@ -1,3 +1,13 @@ +/* + * (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. + */ + // TL3199 #include "N.h" diff --git a/src/atlas/grid/detail/pl/classic_gaussian/N200.cc b/src/atlas/grid/detail/pl/classic_gaussian/N200.cc index 124b2c7ea..7953bab1b 100644 --- a/src/atlas/grid/detail/pl/classic_gaussian/N200.cc +++ b/src/atlas/grid/detail/pl/classic_gaussian/N200.cc @@ -1,3 +1,13 @@ +/* + * (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. + */ + // TL399 #include "N.h" diff --git a/src/atlas/grid/detail/pl/classic_gaussian/N2000.cc b/src/atlas/grid/detail/pl/classic_gaussian/N2000.cc index b16b0aafa..c4dcd175e 100644 --- a/src/atlas/grid/detail/pl/classic_gaussian/N2000.cc +++ b/src/atlas/grid/detail/pl/classic_gaussian/N2000.cc @@ -1,3 +1,13 @@ +/* + * (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. + */ + // TL3999 #include "N.h" diff --git a/src/atlas/grid/detail/pl/classic_gaussian/N24.cc b/src/atlas/grid/detail/pl/classic_gaussian/N24.cc index 7d31437e9..d42788541 100644 --- a/src/atlas/grid/detail/pl/classic_gaussian/N24.cc +++ b/src/atlas/grid/detail/pl/classic_gaussian/N24.cc @@ -1,3 +1,13 @@ +/* + * (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. + */ + // TL47 #include "N.h" diff --git a/src/atlas/grid/detail/pl/classic_gaussian/N256.cc b/src/atlas/grid/detail/pl/classic_gaussian/N256.cc index 20b6fadb5..68ea82418 100644 --- a/src/atlas/grid/detail/pl/classic_gaussian/N256.cc +++ b/src/atlas/grid/detail/pl/classic_gaussian/N256.cc @@ -1,3 +1,13 @@ +/* + * (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. + */ + // TL511 #include "N.h" diff --git a/src/atlas/grid/detail/pl/classic_gaussian/N32.cc b/src/atlas/grid/detail/pl/classic_gaussian/N32.cc index 76f872d5d..56d5c0e23 100644 --- a/src/atlas/grid/detail/pl/classic_gaussian/N32.cc +++ b/src/atlas/grid/detail/pl/classic_gaussian/N32.cc @@ -1,3 +1,13 @@ +/* + * (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. + */ + // TL63 #include "N.h" diff --git a/src/atlas/grid/detail/pl/classic_gaussian/N320.cc b/src/atlas/grid/detail/pl/classic_gaussian/N320.cc index 3494bbd64..172c23546 100644 --- a/src/atlas/grid/detail/pl/classic_gaussian/N320.cc +++ b/src/atlas/grid/detail/pl/classic_gaussian/N320.cc @@ -1,3 +1,13 @@ +/* + * (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. + */ + // TL639 #include "N.h" diff --git a/src/atlas/grid/detail/pl/classic_gaussian/N400.cc b/src/atlas/grid/detail/pl/classic_gaussian/N400.cc index 334e7d49f..219e602ba 100644 --- a/src/atlas/grid/detail/pl/classic_gaussian/N400.cc +++ b/src/atlas/grid/detail/pl/classic_gaussian/N400.cc @@ -1,3 +1,13 @@ +/* + * (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. + */ + // TL799 #include "N.h" diff --git a/src/atlas/grid/detail/pl/classic_gaussian/N4000.cc b/src/atlas/grid/detail/pl/classic_gaussian/N4000.cc index 8d5269344..23ecf2615 100644 --- a/src/atlas/grid/detail/pl/classic_gaussian/N4000.cc +++ b/src/atlas/grid/detail/pl/classic_gaussian/N4000.cc @@ -1,3 +1,13 @@ +/* + * (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. + */ + // TL7999 #include "N.h" diff --git a/src/atlas/grid/detail/pl/classic_gaussian/N48.cc b/src/atlas/grid/detail/pl/classic_gaussian/N48.cc index 7e0e6ea59..ed73d5c9f 100644 --- a/src/atlas/grid/detail/pl/classic_gaussian/N48.cc +++ b/src/atlas/grid/detail/pl/classic_gaussian/N48.cc @@ -1,3 +1,13 @@ +/* + * (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. + */ + // TL95 #include "N.h" diff --git a/src/atlas/grid/detail/pl/classic_gaussian/N512.cc b/src/atlas/grid/detail/pl/classic_gaussian/N512.cc index ba7cd62a6..6ff27f5f9 100644 --- a/src/atlas/grid/detail/pl/classic_gaussian/N512.cc +++ b/src/atlas/grid/detail/pl/classic_gaussian/N512.cc @@ -1,3 +1,13 @@ +/* + * (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. + */ + // TL1023 #include "N.h" diff --git a/src/atlas/grid/detail/pl/classic_gaussian/N576.cc b/src/atlas/grid/detail/pl/classic_gaussian/N576.cc index 05d473d0e..155dc524c 100644 --- a/src/atlas/grid/detail/pl/classic_gaussian/N576.cc +++ b/src/atlas/grid/detail/pl/classic_gaussian/N576.cc @@ -1,3 +1,13 @@ +/* + * (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. + */ + // TL1151 #include "N.h" diff --git a/src/atlas/grid/detail/pl/classic_gaussian/N64.cc b/src/atlas/grid/detail/pl/classic_gaussian/N64.cc index 71bab123a..109250467 100644 --- a/src/atlas/grid/detail/pl/classic_gaussian/N64.cc +++ b/src/atlas/grid/detail/pl/classic_gaussian/N64.cc @@ -1,3 +1,13 @@ +/* + * (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. + */ + // TL127 #include "N.h" diff --git a/src/atlas/grid/detail/pl/classic_gaussian/N640.cc b/src/atlas/grid/detail/pl/classic_gaussian/N640.cc index 96634d2f6..a96ad0ab1 100644 --- a/src/atlas/grid/detail/pl/classic_gaussian/N640.cc +++ b/src/atlas/grid/detail/pl/classic_gaussian/N640.cc @@ -1,3 +1,13 @@ +/* + * (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. + */ + // TL1279 #include "N.h" diff --git a/src/atlas/grid/detail/pl/classic_gaussian/N80.cc b/src/atlas/grid/detail/pl/classic_gaussian/N80.cc index 1137f61f7..6168768b3 100644 --- a/src/atlas/grid/detail/pl/classic_gaussian/N80.cc +++ b/src/atlas/grid/detail/pl/classic_gaussian/N80.cc @@ -1,3 +1,13 @@ +/* + * (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. + */ + // TL159 #include "N.h" diff --git a/src/atlas/grid/detail/pl/classic_gaussian/N800.cc b/src/atlas/grid/detail/pl/classic_gaussian/N800.cc index 580681bcf..2982070c9 100644 --- a/src/atlas/grid/detail/pl/classic_gaussian/N800.cc +++ b/src/atlas/grid/detail/pl/classic_gaussian/N800.cc @@ -1,3 +1,13 @@ +/* + * (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. + */ + // TL1599 #include "N.h" diff --git a/src/atlas/grid/detail/pl/classic_gaussian/N8000.cc b/src/atlas/grid/detail/pl/classic_gaussian/N8000.cc index 062f413f6..dcddc1473 100644 --- a/src/atlas/grid/detail/pl/classic_gaussian/N8000.cc +++ b/src/atlas/grid/detail/pl/classic_gaussian/N8000.cc @@ -1,3 +1,13 @@ +/* + * (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. + */ + // TL15999 #include "N.h" diff --git a/src/atlas/grid/detail/pl/classic_gaussian/N96.cc b/src/atlas/grid/detail/pl/classic_gaussian/N96.cc index 6f8a5aa4f..967f76c32 100644 --- a/src/atlas/grid/detail/pl/classic_gaussian/N96.cc +++ b/src/atlas/grid/detail/pl/classic_gaussian/N96.cc @@ -1,3 +1,13 @@ +/* + * (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. + */ + // TL191 #include "N.h" diff --git a/src/atlas/grid/detail/pl/classic_gaussian/PointsPerLatitude.cc b/src/atlas/grid/detail/pl/classic_gaussian/PointsPerLatitude.cc index 38cd8c7ff..d2d6820fd 100644 --- a/src/atlas/grid/detail/pl/classic_gaussian/PointsPerLatitude.cc +++ b/src/atlas/grid/detail/pl/classic_gaussian/PointsPerLatitude.cc @@ -13,12 +13,12 @@ #include "PointsPerLatitude.h" -#include "eckit/memory/ScopedPtr.h" +#include +#include #include "atlas/grid/detail/pl/classic_gaussian/N.h" +#include "atlas/runtime/Exception.h" -using eckit::Factory; -using eckit::ScopedPtr; namespace atlas { namespace grid { @@ -28,22 +28,24 @@ namespace classic_gaussian { //----------------------------------------------------------------------------- -void points_per_latitude_npole_equator( const size_t N, long nlon[] ) { +template +void points_per_latitude_npole_equator_impl( const size_t N, Int nlon[] ) { std::stringstream Nstream; Nstream << N; std::string Nstr = Nstream.str(); - if ( Factory::instance().exists( Nstr ) ) { - ScopedPtr pl( Factory::instance().get( Nstr ).create() ); + if ( PointsPerLatitudeFactory::has( Nstr ) ) { + std::unique_ptr pl( PointsPerLatitudeFactory::build( Nstr ) ); pl->assign( nlon, N ); } else { - throw eckit::BadParameter( "gaussian::classic::PointsPerLatitude not available for N" + Nstr, Here() ); + throw_Exception( "gaussian::classic::PointsPerLatitude not available for N" + Nstr, Here() ); } } //----------------------------------------------------------------------------- -void points_per_latitude_npole_spole( const size_t N, long nlon[] ) { +template +void points_per_latitude_npole_spole_impl( const size_t N, Int nlon[] ) { points_per_latitude_npole_equator( N, nlon ); size_t end = 2 * N - 1; for ( size_t jlat = 0; jlat < N; ++jlat ) { @@ -53,6 +55,24 @@ void points_per_latitude_npole_spole( const size_t N, long nlon[] ) { //----------------------------------------------------------------------------- +void points_per_latitude_npole_equator( const size_t N, long nlon[] ) { + points_per_latitude_npole_equator_impl( N, nlon ); +} +void points_per_latitude_npole_equator( const size_t N, int nlon[] ) { + points_per_latitude_npole_equator_impl( N, nlon ); +} + +//----------------------------------------------------------------------------- + +void points_per_latitude_npole_spole( const size_t N, long nlon[] ) { + points_per_latitude_npole_spole_impl( N, nlon ); +} +void points_per_latitude_npole_spole( const size_t N, int nlon[] ) { + points_per_latitude_npole_spole_impl( N, nlon ); +} + +//----------------------------------------------------------------------------- + } // namespace classic_gaussian } // namespace pl } // namespace detail diff --git a/src/atlas/grid/detail/pl/classic_gaussian/PointsPerLatitude.h b/src/atlas/grid/detail/pl/classic_gaussian/PointsPerLatitude.h index c3b63516b..fc547afdd 100644 --- a/src/atlas/grid/detail/pl/classic_gaussian/PointsPerLatitude.h +++ b/src/atlas/grid/detail/pl/classic_gaussian/PointsPerLatitude.h @@ -29,6 +29,14 @@ namespace classic_gaussian { */ void points_per_latitude_npole_equator( const size_t N, long nlon[] ); +/** + * @brief Compute points per latitude between North pole and equator + * @param N [in] Number of latitudes between pole and equator (Gaussian N + * number) + * @param nlon [out] points per latitude + */ +void points_per_latitude_npole_equator( const size_t N, int nlon[] ); + /** * @brief Compute points per latitude between North pole and South pole * @param N [in] Number of latitudes between pole and equator (Gaussian N @@ -37,6 +45,14 @@ void points_per_latitude_npole_equator( const size_t N, long nlon[] ); */ void points_per_latitude_npole_spole( const size_t N, long nlon[] ); +/** + * @brief Compute points per latitude between North pole and South pole + * @param N [in] Number of latitudes between pole and equator (Gaussian N + * number) + * @param nlon [out] points per latitude (size 2*N) + */ +void points_per_latitude_npole_spole( const size_t N, int nlon[] ); + } // namespace classic_gaussian } // namespace pl } // namespace detail diff --git a/src/atlas/grid/detail/spacing/CustomSpacing.cc b/src/atlas/grid/detail/spacing/CustomSpacing.cc index 7115a36fd..f668a4c80 100644 --- a/src/atlas/grid/detail/spacing/CustomSpacing.cc +++ b/src/atlas/grid/detail/spacing/CustomSpacing.cc @@ -13,7 +13,9 @@ #include #include "eckit/config/Parametrisation.h" -#include "eckit/exception/Exceptions.h" + +#include "atlas/grid/detail/spacing/SpacingFactory.h" +#include "atlas/runtime/Exception.h" namespace atlas { namespace grid { @@ -29,7 +31,7 @@ CustomSpacing::CustomSpacing( const eckit::Parametrisation& params ) { params.get( "values", x_ ); size_t N; - if ( params.get( "N", N ) ) { ASSERT( x_.size() == N ); } + if ( params.get( "N", N ) ) { ATLAS_ASSERT( x_.size() == N ); } N = x_.size(); std::vector interval; @@ -55,7 +57,9 @@ CustomSpacing::Spec CustomSpacing::spec() const { return spacing_specs; } -register_BuilderT1( Spacing, CustomSpacing, CustomSpacing::static_type() ); +namespace { +static SpacingBuilder __builder( CustomSpacing::static_type() ); +} } // namespace spacing } // namespace grid diff --git a/src/atlas/grid/detail/spacing/CustomSpacing.h b/src/atlas/grid/detail/spacing/CustomSpacing.h index 6907bc807..31a2eadbc 100644 --- a/src/atlas/grid/detail/spacing/CustomSpacing.h +++ b/src/atlas/grid/detail/spacing/CustomSpacing.h @@ -11,6 +11,7 @@ #pragma once #include +#include #include "atlas/grid/detail/spacing/Spacing.h" @@ -18,29 +19,29 @@ namespace atlas { namespace grid { namespace spacing { + +// clang-format off + /// @brief Custom spacing in interval /// -/// There are N points, by default in the open interval (90, -90). +/// There are N points, by default in the open interval (90, -90). The interval is used to +/// determine if a grid's domain contains poles. /// /// Using the constructor CustomSpacing( N, x[], {min,max} ) we can create /// -/// CustomSpacing( 4, {75,25,-25,-75} ) --> { 75 , 25 , -25 -/// , -75 } -/// CustomSpacing( 4, {75,25,-25,-75}, {-90,90} ) --> { 75 , 25 , -25 -/// , -75 } +/// CustomSpacing( 4, {75,25,-25,-75} ) --> { 75 , 25 , -25, -75 } +/// CustomSpacing( 4, {75,25,-25,-75}, {-90,90} ) --> { 75 , 25 , -25, -75 } /// -/// The optional argument {min,max} serves as purpose to indicate that the -/// points -/// lie in the open interval (min,max). If not specified, the default values are -/// taken +/// The optional argument {min,max} serves as purpose to indicate that the points +/// lie in the open interval (min,max). If not specified, the default values are taken /// to be the North and South pole's latitudes. /// /// Configuration parameters can be passed as well with following keys: /// -/// {"N":4, "values":[75,25,-25,75] } --> { 75 , 25 , -/// -25 , -75 } -/// {"N":4, "values":[75,25,-25,75], "interval":[-90,90] } --> { 75 , 25 , -/// -25 , -75 } +/// {"N":4, "values":[75,25,-25,75] } --> { 75 , 25 , -25 , -75 } +/// {"N":4, "values":[75,25,-25,75], "interval":[-90,90] } --> { 75 , 25 , -25 , -75 } + +// clang-format on class CustomSpacing : public Spacing { private: diff --git a/src/atlas/grid/detail/spacing/FocusSpacing.cc b/src/atlas/grid/detail/spacing/FocusSpacing.cc index 0873ce17c..d2179f477 100644 --- a/src/atlas/grid/detail/spacing/FocusSpacing.cc +++ b/src/atlas/grid/detail/spacing/FocusSpacing.cc @@ -11,9 +11,10 @@ #include #include "eckit/config/Parametrisation.h" -#include "eckit/exception/Exceptions.h" #include "atlas/grid/detail/spacing/FocusSpacing.h" +#include "atlas/grid/detail/spacing/SpacingFactory.h" +#include "atlas/runtime/Exception.h" namespace atlas { namespace grid { @@ -25,13 +26,12 @@ FocusSpacing::FocusSpacing( const eckit::Parametrisation& params ) { long N; // retrieve xmin, xmax and N from params - if ( !params.get( "start", xmin ) ) throw eckit::BadParameter( "start missing in Params", Here() ); - if ( !params.get( "end", xmax ) ) throw eckit::BadParameter( "end missing in Params", Here() ); - if ( !params.get( "N", N ) ) throw eckit::BadParameter( "N missing in Params", Here() ); + if ( !params.get( "start", xmin ) ) throw_Exception( "start missing in Params", Here() ); + if ( !params.get( "end", xmax ) ) throw_Exception( "end missing in Params", Here() ); + if ( !params.get( "N", N ) ) throw_Exception( "N missing in Params", Here() ); // additional parameters for focus spacing - if ( !params.get( "focus_factor", focus_factor_ ) ) - throw eckit::BadParameter( "focus_factor missing in Params", Here() ); + if ( !params.get( "focus_factor", focus_factor_ ) ) throw_Exception( "focus_factor missing in Params", Here() ); x_.resize( N ); if ( N == 1 ) { x_[0] = 0.5 * ( xmin + xmax ); } @@ -64,7 +64,9 @@ FocusSpacing::Spec FocusSpacing::spec() const { return spacing_specs; } -register_BuilderT1( Spacing, FocusSpacing, FocusSpacing::static_type() ); +namespace { +static SpacingBuilder __builder( FocusSpacing::static_type() ); +} } // namespace spacing } // namespace grid diff --git a/src/atlas/grid/detail/spacing/FocusSpacing.h b/src/atlas/grid/detail/spacing/FocusSpacing.h index 9c032f9a4..bc2ad7fc2 100644 --- a/src/atlas/grid/detail/spacing/FocusSpacing.h +++ b/src/atlas/grid/detail/spacing/FocusSpacing.h @@ -10,6 +10,8 @@ #pragma once +#include + #include "atlas/grid/detail/spacing/Spacing.h" namespace atlas { diff --git a/src/atlas/grid/detail/spacing/GaussianSpacing.cc b/src/atlas/grid/detail/spacing/GaussianSpacing.cc index d2c5d408f..a081d845a 100644 --- a/src/atlas/grid/detail/spacing/GaussianSpacing.cc +++ b/src/atlas/grid/detail/spacing/GaussianSpacing.cc @@ -9,10 +9,11 @@ */ #include "eckit/config/Parametrisation.h" -#include "eckit/exception/Exceptions.h" #include "atlas/grid/detail/spacing/GaussianSpacing.h" +#include "atlas/grid/detail/spacing/SpacingFactory.h" #include "atlas/grid/detail/spacing/gaussian/Latitudes.h" +#include "atlas/runtime/Exception.h" namespace atlas { namespace grid { @@ -20,7 +21,7 @@ namespace spacing { GaussianSpacing::GaussianSpacing( long N ) { // perform checks - ASSERT( N % 2 == 0 ); + ATLAS_ASSERT( N % 2 == 0 ); // initialize latitudes during setup, to avoid repeating it. x_.resize( N ); @@ -33,10 +34,10 @@ GaussianSpacing::GaussianSpacing( long N ) { GaussianSpacing::GaussianSpacing( const eckit::Parametrisation& params ) { // retrieve N from params long N; - if ( !params.get( "N", N ) ) throw eckit::BadParameter( "N missing in Params", Here() ); + if ( !params.get( "N", N ) ) throw_Exception( "N missing in Params", Here() ); // perform checks - ASSERT( N % 2 == 0 ); + ATLAS_ASSERT( N % 2 == 0 ); // initialize latitudes during setup, to avoid repeating it. x_.resize( N ); @@ -54,7 +55,7 @@ GaussianSpacing::GaussianSpacing( const eckit::Parametrisation& params ) { start = interval[0]; end = interval[1]; } - if ( start != 90. && end != -90. ) { NOTIMP; } + if ( start != 90. && end != -90. ) { ATLAS_NOTIMPLEMENTED; } min_ = std::min( start, end ); max_ = std::max( start, end ); @@ -67,7 +68,9 @@ GaussianSpacing::Spec GaussianSpacing::spec() const { return spacing_specs; } -register_BuilderT1( Spacing, GaussianSpacing, GaussianSpacing::static_type() ); +namespace { +static SpacingBuilder __builder( GaussianSpacing::static_type() ); +} } // namespace spacing } // namespace grid diff --git a/src/atlas/grid/detail/spacing/GaussianSpacing.h b/src/atlas/grid/detail/spacing/GaussianSpacing.h index bf4aff6d6..a6b37f8cc 100644 --- a/src/atlas/grid/detail/spacing/GaussianSpacing.h +++ b/src/atlas/grid/detail/spacing/GaussianSpacing.h @@ -10,32 +10,34 @@ #pragma once +#include + #include "atlas/grid/detail/spacing/Spacing.h" namespace atlas { namespace grid { namespace spacing { +// clang-format off + /// @brief Gaussian spacing in interval /// /// There are N Gaussian spaced points in the open interval (90, -90) /// /// Using the constructor GaussianSpacing( N ) we can create /// -/// Gaussian( 4 ) --> { 59.44... , 19.87... , -/// -19.87... , -59.44... } +/// GaussianSpacing( 4 ) --> { 59.44... , 19.87... , -19.87... , -59.44... } /// /// Configuration parameters can be passed as well with following keys: /// -/// {"N":4 } --> { 59.44... , 19.87... , -/// -19.87... , -59.44... } +/// {"N":4 } --> { 59.44... , 19.87... , -19.87... , -59.44... } /// /// To reverse the orientation of points to go from negative to positive -/// instead, pass also -/// the start and end keys: +/// instead, pass also the start and end keys: /// -/// {"N":4, "start":-90, "end":90 } --> { -59.44... , -19.87... , -/// 19.87... , 59.44... } +/// {"N":4, "start":-90, "end":90 } --> { -59.44... , -19.87... , 19.87... , 59.44... } + +// clang-format on class GaussianSpacing : public Spacing { public: diff --git a/src/atlas/grid/detail/spacing/LinearSpacing.cc b/src/atlas/grid/detail/spacing/LinearSpacing.cc index 7a45bb5f0..54641fb2e 100644 --- a/src/atlas/grid/detail/spacing/LinearSpacing.cc +++ b/src/atlas/grid/detail/spacing/LinearSpacing.cc @@ -11,9 +11,12 @@ #include "atlas/grid/detail/spacing/LinearSpacing.h" #include +#include #include "eckit/config/Parametrisation.h" -#include "eckit/exception/Exceptions.h" + +#include "atlas/grid/detail/spacing/SpacingFactory.h" +#include "atlas/runtime/Exception.h" namespace atlas { namespace grid { @@ -34,7 +37,7 @@ LinearSpacing::Params::Params( const eckit::Parametrisation& params ) { // end = endpoint ? start + step * double(N-1) : // start + step * double(N); // } else { - // throw eckit::BadParameter("Invalid combination of parameters",Here()); + // throw_Exception("Invalid combination of parameters",Here()); // } // } // else @@ -51,11 +54,11 @@ LinearSpacing::Params::Params( const eckit::Parametrisation& params ) { end = start + length; } else { - throw eckit::BadParameter( "Invalid combination of parameters", Here() ); + throw_Exception( "Invalid combination of parameters", Here() ); } } else { - throw eckit::BadParameter( "Invalid combination of parameters", Here() ); + throw_Exception( "Invalid combination of parameters", Here() ); } length = end - start; @@ -130,7 +133,9 @@ LinearSpacing::Spec LinearSpacing::spec() const { return spacing_specs; } -register_BuilderT1( Spacing, LinearSpacing, LinearSpacing::static_type() ); +namespace { +static SpacingBuilder __builder( LinearSpacing::static_type() ); +} } // namespace spacing } // namespace grid diff --git a/src/atlas/grid/detail/spacing/LinearSpacing.h b/src/atlas/grid/detail/spacing/LinearSpacing.h index 3014aa74f..58a1001b9 100644 --- a/src/atlas/grid/detail/spacing/LinearSpacing.h +++ b/src/atlas/grid/detail/spacing/LinearSpacing.h @@ -11,6 +11,7 @@ #pragma once #include +#include #include "atlas/grid/detail/spacing/Spacing.h" @@ -18,34 +19,28 @@ namespace atlas { namespace grid { namespace spacing { +// clang-format off + /// @brief Linear spacing in interval /// -/// There are N equally spaced points in the closed interval [start, stop] or -/// the -/// half-open interval [start, stop) (depending on whether endpoint is True or -/// False) +/// There are N equally spaced points in the closed interval [start, stop] or the +/// half-open interval [start, stop) (depending on whether endpoint is True or False) /// /// Using the constructor LinearSpacing( start, end, N, endpoint ) we can create -/// -/// LinearSpacing( 2, 3, 5, true ) --> { 2.0 , 2.25 , -/// 2.5 , 2.75 , 3.0 } -/// LinearSpacing( 2, 3, 5, false ) --> { 2.0 , 2.2 , -/// 2.4 , 2.6 , 2.8 } +/// LinearSpacing( 2, 3, 5, true ) --> { 2.0 , 2.25 , 2.5 , 2.75 , 3.0 } +/// LinearSpacing( 2, 3, 5, false ) --> { 2.0 , 2.2 , 2.4 , 2.6 , 2.8 } /// /// Configuration parameters can be passed as well with following keys: /// -/// {"start":2 , "end":3, "N":5, "endpoint":true } --> { 2.0 , 2.25 , 2.5 -/// , 2.75 , 3.0 } -/// {"start":2 , "end":3, "N":5, "endpoint":false} --> { 2.0 , 2.2 , 2.4 -/// , 2.6 , 2.8 } +/// {"start":2 , "end":3, "N":5, "endpoint":true } --> { 2.0 , 2.25 , 2.5 , 2.75 , 3.0 } +/// {"start":2 , "end":3, "N":5, "endpoint":false} --> { 2.0 , 2.2 , 2.4 , 2.6 , 2.8 } /// -/// Instead of the "end" key, you can provide the "length" key, to achieve the -/// same results: +/// Instead of the "end" key, you can provide the "length" key, to achieve the same results: /// -/// {"start":2 , "length":1, "N":5, "endpoint":true } --> { 2.0 , 2.25 , 2.5 -/// , 2.75 , 3.0 } -/// {"start":2 , "length":1, "N":5, "endpoint":false} --> { 2.0 , 2.2 , 2.4 -/// , 2.6 , 2.8 } +/// {"start":2 , "length":1, "N":5, "endpoint":true } --> { 2.0 , 2.25 , 2.5 , 2.75 , 3.0 } +/// {"start":2 , "length":1, "N":5, "endpoint":false} --> { 2.0 , 2.2 , 2.4 , 2.6 , 2.8 } + +// clang-format on class LinearSpacing : public Spacing { public: diff --git a/src/atlas/grid/detail/spacing/Spacing.cc b/src/atlas/grid/detail/spacing/Spacing.cc index 77de0e4af..5ae41fc6f 100644 --- a/src/atlas/grid/detail/spacing/Spacing.cc +++ b/src/atlas/grid/detail/spacing/Spacing.cc @@ -9,20 +9,19 @@ */ #include "eckit/config/Parametrisation.h" -#include "eckit/exception/Exceptions.h" #include "atlas/grid/detail/spacing/Spacing.h" +#include "atlas/grid/detail/spacing/SpacingFactory.h" +#include "atlas/runtime/Exception.h" namespace atlas { namespace grid { namespace spacing { -Spacing* Spacing::create( const eckit::Parametrisation& params ) { +const Spacing* Spacing::create( const eckit::Parametrisation& params ) { std::string spacingType; - if ( not params.get( "type", spacingType ) ) { - throw eckit::BadParameter( "type missing in configuration", Here() ); - } - return eckit::Factory::instance().get( spacingType ).create( params ); + if ( not params.get( "type", spacingType ) ) { throw_Exception( "type missing in configuration", Here() ); } + return SpacingFactory::build( spacingType, params ); } } // namespace spacing diff --git a/src/atlas/grid/detail/spacing/Spacing.h b/src/atlas/grid/detail/spacing/Spacing.h index baef8c07d..efe664f15 100644 --- a/src/atlas/grid/detail/spacing/Spacing.h +++ b/src/atlas/grid/detail/spacing/Spacing.h @@ -13,31 +13,30 @@ #include #include -#include "eckit/memory/Builder.h" -#include "eckit/memory/Owned.h" - -#include "atlas/util/Config.h" +#include "atlas/util/Object.h" namespace eckit { class Parametrisation; } +namespace atlas { +namespace util { +class Config; +} +} // namespace atlas + namespace atlas { namespace grid { namespace spacing { -class Spacing : public eckit::Owned { +class Spacing : public util::Object { public: using const_iterator = std::vector::const_iterator; using Interval = std::array; using Spec = atlas::util::Config; - using ARG1 = const eckit::Parametrisation&; - using builder_t = eckit::BuilderT1; - static std::string className() { return "atlas.Spacing"; } - public: - static Spacing* create( const eckit::Parametrisation& params ); + static const Spacing* create( const eckit::Parametrisation& params ); virtual std::string type() const = 0; diff --git a/src/atlas/grid/detail/spacing/SpacingFactory.cc b/src/atlas/grid/detail/spacing/SpacingFactory.cc new file mode 100644 index 000000000..a50a0d2c3 --- /dev/null +++ b/src/atlas/grid/detail/spacing/SpacingFactory.cc @@ -0,0 +1,46 @@ +/* + * (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 "atlas/grid/detail/spacing/SpacingFactory.h" + +namespace atlas { +namespace grid { +namespace spacing { + +//---------------------------------------------------------------------------------------------------------------------- + +void force_link() { + static struct Link { + Link() { + //SpacingBuilder(); + //SpacingBuilder(); + } + } link; +} + +//---------------------------------------------------------------------------------------------------------------------- + +const Spacing* SpacingFactory::build( const std::string& builder ) { + return build( builder, util::NoConfig() ); +} + +const Spacing* SpacingFactory::build( const std::string& builder, const eckit::Parametrisation& param ) { + force_link(); + auto factory = get( builder ); + return factory->make( param ); +} + +//---------------------------------------------------------------------------------------------------------------------- + +} // namespace spacing +} // namespace grid +} // namespace atlas diff --git a/src/atlas/grid/detail/spacing/SpacingFactory.h b/src/atlas/grid/detail/spacing/SpacingFactory.h new file mode 100644 index 000000000..fe5b16231 --- /dev/null +++ b/src/atlas/grid/detail/spacing/SpacingFactory.h @@ -0,0 +1,51 @@ +/* + * (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 + +#include "atlas/util/Config.h" +#include "atlas/util/Factory.h" + +namespace atlas { +namespace grid { +namespace spacing { + +//---------------------------------------------------------------------------------------------------------------------- + +class Spacing; +class SpacingFactory : public util::Factory { +public: + static std::string className() { return "SpacingFactory"; } + static const Spacing* build( const std::string& ); + static const Spacing* build( const std::string&, const eckit::Parametrisation& ); + using Factory::Factory; + +private: + virtual const Spacing* make( const eckit::Parametrisation& ) = 0; +}; + +//---------------------------------------------------------------------------------------------------------------------- + +template +class SpacingBuilder : public SpacingFactory { +private: + virtual const Spacing* make( const eckit::Parametrisation& param ) { return new T( param ); } + +public: + using SpacingFactory::SpacingFactory; +}; + +//---------------------------------------------------------------------------------------------------------------------- + +} // namespace spacing +} // namespace grid +} // namespace atlas diff --git a/src/atlas/grid/detail/spacing/gaussian/Latitudes.cc b/src/atlas/grid/detail/spacing/gaussian/Latitudes.cc index 37233dd62..145d60e21 100644 --- a/src/atlas/grid/detail/spacing/gaussian/Latitudes.cc +++ b/src/atlas/grid/detail/spacing/gaussian/Latitudes.cc @@ -12,21 +12,19 @@ /// @date Jan 2014 #include - -#include "eckit/memory/ScopedPtr.h" +#include #include "atlas/array.h" -#include "atlas/array/MakeView.h" #include "atlas/grid/detail/spacing/gaussian/Latitudes.h" #include "atlas/grid/detail/spacing/gaussian/N.h" #include "atlas/library/config.h" +#include "atlas/runtime/Exception.h" #include "atlas/runtime/Log.h" #include "atlas/util/Constants.h" #include "atlas/util/CoordinateEnums.h" -using eckit::ConcreteBuilderT0; -using eckit::Factory; -using eckit::ScopedPtr; +//using eckit::ConcreteBuilderT0; +//using eckit::Factory; using atlas::array::Array; using atlas::array::ArrayView; @@ -47,10 +45,14 @@ void gaussian_latitudes_npole_equator( const size_t N, double lats[] ) { std::stringstream Nstream; Nstream << N; std::string Nstr = Nstream.str(); - if ( Factory::instance().exists( Nstr ) ) { - ScopedPtr gl( Factory::instance().get( Nstr ).create() ); + if ( GaussianLatitudesFactory::has( Nstr ) ) { + std::unique_ptr gl( GaussianLatitudesFactory::build( Nstr ) ); gl->assign( lats, N ); } + // if ( Factory::instance().exists( Nstr ) ) { + // std::unique_ptr gl( Factory::instance().get( Nstr ).create() ); + // gl->assign( lats, N ); + // } else { std::vector weights( N ); compute_gaussian_quadrature_npole_equator( N, lats, weights.data() ); @@ -218,7 +220,7 @@ void legpol_quadrature( const int kn, const double pfn[], double& pl, double& pw std::stringstream s; s << "Could not converge gaussian latitude to accuracy [" << zeps * 1000 << "]\n"; s << "after " << itemax << " iterations. Consequently also failed to compute quadrature weight."; - throw eckit::Exception( s.str(), Here() ); + throw_Exception( s.str(), Here() ); } pl = zxn; diff --git a/src/atlas/grid/detail/spacing/gaussian/N.cc b/src/atlas/grid/detail/spacing/gaussian/N.cc index e2af7f0f5..db147506a 100644 --- a/src/atlas/grid/detail/spacing/gaussian/N.cc +++ b/src/atlas/grid/detail/spacing/gaussian/N.cc @@ -11,19 +11,23 @@ /// @author Willem Deconinck /// @date Jan 2015 + #include "atlas/grid/detail/spacing/gaussian/N.h" +#include "atlas/runtime/Exception.h" namespace atlas { namespace grid { namespace spacing { namespace gaussian { -std::string GaussianLatitudes::className() { - return "GaussianLatitudes"; +#if 0 +std ::string GaussianLatitudes::className() { +return "GaussianLatitudes"; } +#endif void GaussianLatitudes::assign( double lats[], const size_t size ) const { - ASSERT( size >= lats_.size() ); + ATLAS_ASSERT( size >= lats_.size() ); for ( size_t jlat = 0; jlat < lats_.size(); ++jlat ) lats[jlat] = lats_[jlat]; } @@ -34,7 +38,8 @@ void GaussianLatitudes::assign( std::vector& lats ) const { template void load() { - eckit::ConcreteBuilderT0 builder( "tmp" ); + // eckit::ConcreteBuilderT0 builder( "tmp" ); + GaussianLatitudesBuilder(); } void regist() { diff --git a/src/atlas/grid/detail/spacing/gaussian/N.h b/src/atlas/grid/detail/spacing/gaussian/N.h index 2c40cadfe..32a7c8d18 100644 --- a/src/atlas/grid/detail/spacing/gaussian/N.h +++ b/src/atlas/grid/detail/spacing/gaussian/N.h @@ -13,20 +13,18 @@ #pragma once -#include "eckit/memory/Builder.h" -#include "eckit/memory/Owned.h" +#include +#include + +#include "atlas/util/Factory.h" namespace atlas { namespace grid { namespace spacing { namespace gaussian { -class GaussianLatitudes : public eckit::Owned { +class GaussianLatitudes { public: - typedef eckit::BuilderT0 builder_t; - - static std::string className(); - /// @pre nlats has enough allocated memory to store the latitudes /// @param size of lats vector void assign( double lats[], const size_t size ) const; @@ -40,6 +38,25 @@ class GaussianLatitudes : public eckit::Owned { std::vector lats_; }; +class GaussianLatitudesFactory : public util::Factory { +public: + static std::string className() { return "GaussianLatitudesFactory"; } + static const GaussianLatitudes* build( const std::string& builder ) { return get( builder )->make(); } + using Factory::Factory; + +private: + virtual const GaussianLatitudes* make() const = 0; +}; + +template +class GaussianLatitudesBuilder : public GaussianLatitudesFactory { +public: + using GaussianLatitudesFactory::GaussianLatitudesFactory; + +private: + virtual const GaussianLatitudes* make() const override { return new T(); } +}; + #define DECLARE_GAUSSIAN_LATITUDES( NUMBER ) \ class N##NUMBER : public GaussianLatitudes { \ public: \ @@ -47,15 +64,17 @@ class GaussianLatitudes : public eckit::Owned { }; #define LIST( ... ) __VA_ARGS__ -#define DEFINE_GAUSSIAN_LATITUDES( NUMBER, LATS ) \ - eckit::ConcreteBuilderT0 builder_N##NUMBER( #NUMBER ); \ - \ - N##NUMBER::N##NUMBER() { \ - size_t N = NUMBER; \ - double lat[] = {LATS}; \ - lats_.assign( lat, lat + N ); \ +#define DEFINE_GAUSSIAN_LATITUDES( NUMBER, LATS ) \ + N##NUMBER::N##NUMBER() { \ + size_t N = NUMBER; \ + double lat[] = {LATS}; \ + lats_.assign( lat, lat + N ); \ + } \ + namespace { \ + static GaussianLatitudesBuilder builder_N##NUMBER( #NUMBER ); \ } + DECLARE_GAUSSIAN_LATITUDES( 16 ); DECLARE_GAUSSIAN_LATITUDES( 24 ); DECLARE_GAUSSIAN_LATITUDES( 32 ); diff --git a/src/atlas/grid/detail/spacing/gaussian/N1024.cc b/src/atlas/grid/detail/spacing/gaussian/N1024.cc index bc2ba3366..0e8c698b6 100644 --- a/src/atlas/grid/detail/spacing/gaussian/N1024.cc +++ b/src/atlas/grid/detail/spacing/gaussian/N1024.cc @@ -1,3 +1,13 @@ +/* + * (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. + */ + // TL2047 #include "atlas/grid/detail/spacing/gaussian/N.h" diff --git a/src/atlas/grid/detail/spacing/gaussian/N128.cc b/src/atlas/grid/detail/spacing/gaussian/N128.cc index eaf60c8e7..8e28b58b6 100644 --- a/src/atlas/grid/detail/spacing/gaussian/N128.cc +++ b/src/atlas/grid/detail/spacing/gaussian/N128.cc @@ -1,3 +1,13 @@ +/* + * (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. + */ + // TL255 #include "atlas/grid/detail/spacing/gaussian/N.h" diff --git a/src/atlas/grid/detail/spacing/gaussian/N1280.cc b/src/atlas/grid/detail/spacing/gaussian/N1280.cc index 72fac78bd..15983f0a7 100644 --- a/src/atlas/grid/detail/spacing/gaussian/N1280.cc +++ b/src/atlas/grid/detail/spacing/gaussian/N1280.cc @@ -1,3 +1,13 @@ +/* + * (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. + */ + // TL2559 #include "atlas/grid/detail/spacing/gaussian/N.h" diff --git a/src/atlas/grid/detail/spacing/gaussian/N16.cc b/src/atlas/grid/detail/spacing/gaussian/N16.cc index 5bb5fdaa0..bcaf903b6 100644 --- a/src/atlas/grid/detail/spacing/gaussian/N16.cc +++ b/src/atlas/grid/detail/spacing/gaussian/N16.cc @@ -1,3 +1,13 @@ +/* + * (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. + */ + // TL31 #include "atlas/grid/detail/spacing/gaussian/N.h" diff --git a/src/atlas/grid/detail/spacing/gaussian/N160.cc b/src/atlas/grid/detail/spacing/gaussian/N160.cc index ce185f4d9..a2587d518 100644 --- a/src/atlas/grid/detail/spacing/gaussian/N160.cc +++ b/src/atlas/grid/detail/spacing/gaussian/N160.cc @@ -1,3 +1,13 @@ +/* + * (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. + */ + // TL319 #include "atlas/grid/detail/spacing/gaussian/N.h" diff --git a/src/atlas/grid/detail/spacing/gaussian/N1600.cc b/src/atlas/grid/detail/spacing/gaussian/N1600.cc index 8ace5abcc..6684ae750 100644 --- a/src/atlas/grid/detail/spacing/gaussian/N1600.cc +++ b/src/atlas/grid/detail/spacing/gaussian/N1600.cc @@ -1,3 +1,13 @@ +/* + * (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. + */ + // TL3199 #include "atlas/grid/detail/spacing/gaussian/N.h" diff --git a/src/atlas/grid/detail/spacing/gaussian/N200.cc b/src/atlas/grid/detail/spacing/gaussian/N200.cc index a6aa53cba..9886b4455 100644 --- a/src/atlas/grid/detail/spacing/gaussian/N200.cc +++ b/src/atlas/grid/detail/spacing/gaussian/N200.cc @@ -1,3 +1,13 @@ +/* + * (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. + */ + // TL399 #include "atlas/grid/detail/spacing/gaussian/N.h" diff --git a/src/atlas/grid/detail/spacing/gaussian/N2000.cc b/src/atlas/grid/detail/spacing/gaussian/N2000.cc index 123df8f13..07f6c50ea 100644 --- a/src/atlas/grid/detail/spacing/gaussian/N2000.cc +++ b/src/atlas/grid/detail/spacing/gaussian/N2000.cc @@ -1,3 +1,13 @@ +/* + * (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. + */ + // TL3999 #include "atlas/grid/detail/spacing/gaussian/N.h" diff --git a/src/atlas/grid/detail/spacing/gaussian/N24.cc b/src/atlas/grid/detail/spacing/gaussian/N24.cc index 2935d6cf5..2b48fc1ea 100644 --- a/src/atlas/grid/detail/spacing/gaussian/N24.cc +++ b/src/atlas/grid/detail/spacing/gaussian/N24.cc @@ -1,3 +1,13 @@ +/* + * (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. + */ + // TL47 #include "atlas/grid/detail/spacing/gaussian/N.h" diff --git a/src/atlas/grid/detail/spacing/gaussian/N256.cc b/src/atlas/grid/detail/spacing/gaussian/N256.cc index fa73bc930..bd4f63b33 100644 --- a/src/atlas/grid/detail/spacing/gaussian/N256.cc +++ b/src/atlas/grid/detail/spacing/gaussian/N256.cc @@ -1,3 +1,13 @@ +/* + * (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. + */ + // TL511 #include "atlas/grid/detail/spacing/gaussian/N.h" diff --git a/src/atlas/grid/detail/spacing/gaussian/N32.cc b/src/atlas/grid/detail/spacing/gaussian/N32.cc index cc886f7b7..ef354d5da 100644 --- a/src/atlas/grid/detail/spacing/gaussian/N32.cc +++ b/src/atlas/grid/detail/spacing/gaussian/N32.cc @@ -1,3 +1,13 @@ +/* + * (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. + */ + // TL63 #include "atlas/grid/detail/spacing/gaussian/N.h" diff --git a/src/atlas/grid/detail/spacing/gaussian/N320.cc b/src/atlas/grid/detail/spacing/gaussian/N320.cc index 93921bc8a..72443953a 100644 --- a/src/atlas/grid/detail/spacing/gaussian/N320.cc +++ b/src/atlas/grid/detail/spacing/gaussian/N320.cc @@ -1,3 +1,13 @@ +/* + * (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. + */ + // TL639 #include "atlas/grid/detail/spacing/gaussian/N.h" diff --git a/src/atlas/grid/detail/spacing/gaussian/N400.cc b/src/atlas/grid/detail/spacing/gaussian/N400.cc index e31f90664..e26379b13 100644 --- a/src/atlas/grid/detail/spacing/gaussian/N400.cc +++ b/src/atlas/grid/detail/spacing/gaussian/N400.cc @@ -1,3 +1,13 @@ +/* + * (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. + */ + // TL799 #include "atlas/grid/detail/spacing/gaussian/N.h" diff --git a/src/atlas/grid/detail/spacing/gaussian/N4000.cc b/src/atlas/grid/detail/spacing/gaussian/N4000.cc index 7f707d18b..4a83faa38 100644 --- a/src/atlas/grid/detail/spacing/gaussian/N4000.cc +++ b/src/atlas/grid/detail/spacing/gaussian/N4000.cc @@ -1,3 +1,13 @@ +/* + * (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. + */ + // TL7999 #include "atlas/grid/detail/spacing/gaussian/N.h" diff --git a/src/atlas/grid/detail/spacing/gaussian/N48.cc b/src/atlas/grid/detail/spacing/gaussian/N48.cc index 273e49e0f..d7cc6fb65 100644 --- a/src/atlas/grid/detail/spacing/gaussian/N48.cc +++ b/src/atlas/grid/detail/spacing/gaussian/N48.cc @@ -1,3 +1,13 @@ +/* + * (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. + */ + // TL95 #include "atlas/grid/detail/spacing/gaussian/N.h" diff --git a/src/atlas/grid/detail/spacing/gaussian/N512.cc b/src/atlas/grid/detail/spacing/gaussian/N512.cc index 2df73e9cf..d04361f5c 100644 --- a/src/atlas/grid/detail/spacing/gaussian/N512.cc +++ b/src/atlas/grid/detail/spacing/gaussian/N512.cc @@ -1,3 +1,13 @@ +/* + * (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. + */ + // TL1023 #include "atlas/grid/detail/spacing/gaussian/N.h" diff --git a/src/atlas/grid/detail/spacing/gaussian/N576.cc b/src/atlas/grid/detail/spacing/gaussian/N576.cc index 57c5a5b1a..eefa89b94 100644 --- a/src/atlas/grid/detail/spacing/gaussian/N576.cc +++ b/src/atlas/grid/detail/spacing/gaussian/N576.cc @@ -1,3 +1,13 @@ +/* + * (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. + */ + // TL1151 #include "atlas/grid/detail/spacing/gaussian/N.h" diff --git a/src/atlas/grid/detail/spacing/gaussian/N64.cc b/src/atlas/grid/detail/spacing/gaussian/N64.cc index 4d43b3628..f6e2bbfe9 100644 --- a/src/atlas/grid/detail/spacing/gaussian/N64.cc +++ b/src/atlas/grid/detail/spacing/gaussian/N64.cc @@ -1,3 +1,13 @@ +/* + * (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. + */ + // TL127 #include "atlas/grid/detail/spacing/gaussian/N.h" diff --git a/src/atlas/grid/detail/spacing/gaussian/N640.cc b/src/atlas/grid/detail/spacing/gaussian/N640.cc index db04e8554..43ff7fd28 100644 --- a/src/atlas/grid/detail/spacing/gaussian/N640.cc +++ b/src/atlas/grid/detail/spacing/gaussian/N640.cc @@ -1,3 +1,13 @@ +/* + * (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. + */ + // TL1279 #include "atlas/grid/detail/spacing/gaussian/N.h" diff --git a/src/atlas/grid/detail/spacing/gaussian/N80.cc b/src/atlas/grid/detail/spacing/gaussian/N80.cc index 7ca4b5d55..e18342bce 100644 --- a/src/atlas/grid/detail/spacing/gaussian/N80.cc +++ b/src/atlas/grid/detail/spacing/gaussian/N80.cc @@ -1,3 +1,13 @@ +/* + * (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. + */ + // TL159 #include "atlas/grid/detail/spacing/gaussian/N.h" diff --git a/src/atlas/grid/detail/spacing/gaussian/N800.cc b/src/atlas/grid/detail/spacing/gaussian/N800.cc index 00ade7469..5380285b8 100644 --- a/src/atlas/grid/detail/spacing/gaussian/N800.cc +++ b/src/atlas/grid/detail/spacing/gaussian/N800.cc @@ -1,3 +1,13 @@ +/* + * (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. + */ + // TL1599 #include "atlas/grid/detail/spacing/gaussian/N.h" diff --git a/src/atlas/grid/detail/spacing/gaussian/N8000.cc b/src/atlas/grid/detail/spacing/gaussian/N8000.cc index f4d552a9a..fbf59fc0b 100644 --- a/src/atlas/grid/detail/spacing/gaussian/N8000.cc +++ b/src/atlas/grid/detail/spacing/gaussian/N8000.cc @@ -1,3 +1,13 @@ +/* + * (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. + */ + // TL15999 #include "atlas/grid/detail/spacing/gaussian/N.h" diff --git a/src/atlas/grid/detail/spacing/gaussian/N96.cc b/src/atlas/grid/detail/spacing/gaussian/N96.cc index 2aa15b282..36d6eb5c9 100644 --- a/src/atlas/grid/detail/spacing/gaussian/N96.cc +++ b/src/atlas/grid/detail/spacing/gaussian/N96.cc @@ -1,3 +1,13 @@ +/* + * (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. + */ + // TL191 #include "atlas/grid/detail/spacing/gaussian/N.h" diff --git a/src/atlas/grid/detail/vertical/VerticalInterface.cc b/src/atlas/grid/detail/vertical/VerticalInterface.cc new file mode 100644 index 000000000..3a8ef5722 --- /dev/null +++ b/src/atlas/grid/detail/vertical/VerticalInterface.cc @@ -0,0 +1,27 @@ +/* + * (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 "VerticalInterface.h" +#include "atlas/grid/Vertical.h" + +namespace atlas { + +Vertical* atlas__Vertical__new( idx_t levels, const double z[] ) { + std::vector zvec( z, z + levels ); + return new Vertical( levels, zvec ); +} + +void atlas__Vertical__delete( Vertical* This ) { + delete This; +} + +} // namespace atlas diff --git a/src/atlas/grid/detail/vertical/VerticalInterface.h b/src/atlas/grid/detail/vertical/VerticalInterface.h new file mode 100644 index 000000000..c0e9ba085 --- /dev/null +++ b/src/atlas/grid/detail/vertical/VerticalInterface.h @@ -0,0 +1,30 @@ +/* + * (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 + +//#include "atlas/util/Object.h" + +#include "atlas/library/config.h" + +namespace atlas { +class Vertical; +} // namespace atlas + +namespace atlas { + +extern "C" { +Vertical* atlas__Vertical__new( idx_t levels, const double z[] ); +void atlas__Vertical__delete( Vertical* This ); +} + +} // namespace atlas diff --git a/src/atlas/interpolation/Interpolation.cc b/src/atlas/interpolation/Interpolation.cc index 04defbd1e..f5c43b2e4 100644 --- a/src/atlas/interpolation/Interpolation.cc +++ b/src/atlas/interpolation/Interpolation.cc @@ -8,19 +8,21 @@ * nor does it submit to any jurisdiction. */ -#include "eckit/exception/Exceptions.h" +#include #include "atlas/field/Field.h" #include "atlas/field/FieldSet.h" #include "atlas/functionspace/FunctionSpace.h" #include "atlas/interpolation/Interpolation.h" +#include "atlas/interpolation/method/MethodFactory.h" +#include "atlas/runtime/Exception.h" namespace atlas { Interpolation::Interpolation( const Config& config, const FunctionSpace& source, const FunctionSpace& target ) : - implementation_( [&]() -> Implementation* { + Handle( [&]() -> Implementation* { std::string type; - config.get( "type", type ); + ATLAS_ASSERT( config.get( "type", type ) ); Implementation* impl = interpolation::MethodFactory::build( type, config ); impl->setup( source, target ); return impl; @@ -32,7 +34,71 @@ Interpolation::Interpolation( const Config& config, const FunctionSpace& source, } } -Interpolation::Interpolation( const Interpolation& other ) : implementation_( other.implementation_ ) {} +Interpolation::Interpolation( const Config& config, const Grid& source, const Grid& target ) : + Handle( [&]() -> Implementation* { + std::string type; + ATLAS_ASSERT( config.get( "type", type ) ); + Implementation* impl = interpolation::MethodFactory::build( type, config ); + impl->setup( source, target ); + return impl; + }() ) { + std::string path; + if ( config.get( "output", path ) ) { + std::ofstream file( path ); + print( file ); + } +} + +Interpolation::Interpolation( const Config& config, const FunctionSpace& source, const Field& target ) : + Handle( [&]() -> Implementation* { + std::string type; + ATLAS_ASSERT( config.get( "type", type ) ); + Implementation* impl = interpolation::MethodFactory::build( type, config ); + impl->setup( source, target ); + return impl; + }() ) { + std::string path; + if ( config.get( "output", path ) ) { + std::ofstream file( path ); + print( file ); + } +} + +Interpolation::Interpolation( const Interpolation::Config& config, const FunctionSpace& source, + const FieldSet& target ) : + Handle( [&]() -> Implementation* { + std::string type; + ATLAS_ASSERT( config.get( "type", type ) ); + Implementation* impl = interpolation::MethodFactory::build( type, config ); + impl->setup( source, target ); + return impl; + }() ) { + std::string path; + if ( config.get( "output", path ) ) { + std::ofstream file( path ); + print( file ); + } +} + +void Interpolation::execute( const FieldSet& source, FieldSet& target ) const { + get()->execute( source, target ); +} + +void Interpolation::execute( const Field& source, Field& target ) const { + get()->execute( source, target ); +} + +void Interpolation::print( std::ostream& out ) const { + get()->print( out ); +} + +const FunctionSpace& Interpolation::source() const { + return get()->source(); +} + +const FunctionSpace& Interpolation::target() const { + return get()->target(); +} extern "C" { Interpolation::Implementation* atlas__Interpolation__new( const eckit::Parametrisation* config, @@ -48,6 +114,32 @@ Interpolation::Implementation* atlas__Interpolation__new( const eckit::Parametri return interpolator; } +Interpolation::Implementation* atlas__Interpolation__new_tgt_field( const eckit::Parametrisation* config, + const functionspace::FunctionSpaceImpl* source, + const field::FieldImpl* target ) { + Interpolation::Implementation* interpolator; + { + Interpolation im( *config, FunctionSpace( source ), Field( target ) ); + interpolator = const_cast( im.get() ); + interpolator->attach(); + } + interpolator->detach(); + return interpolator; +} + +Interpolation::Implementation* atlas__Interpolation__new_tgt_fieldset( const eckit::Parametrisation* config, + const functionspace::FunctionSpaceImpl* source, + const field::FieldSetImpl* target ) { + Interpolation::Implementation* interpolator; + { + Interpolation im( *config, FunctionSpace( source ), FieldSet( target ) ); + interpolator = const_cast( im.get() ); + interpolator->attach(); + } + interpolator->detach(); + return interpolator; +} + void atlas__Interpolation__delete( Interpolation::Implementation* This ) { delete This; } diff --git a/src/atlas/interpolation/Interpolation.h b/src/atlas/interpolation/Interpolation.h index 2e9468c8f..a5aae026b 100644 --- a/src/atlas/interpolation/Interpolation.h +++ b/src/atlas/interpolation/Interpolation.h @@ -10,39 +10,52 @@ #pragma once -#include "eckit/config/Configuration.h" -#include "eckit/memory/SharedPtr.h" - #include "atlas/interpolation/method/Method.h" +#include "atlas/util/ObjectHandle.h" + +namespace eckit { +class Parametrisation; +} namespace atlas { class Field; class FieldSet; class FunctionSpace; +class Grid; +namespace interpolation { +class Method; +} } // namespace atlas namespace atlas { -class Interpolation { +class Interpolation : public util::ObjectHandle { public: - using Implementation = interpolation::Method; - using Config = Implementation::Config; + using Config = eckit::Parametrisation; + + using Handle::Handle; + Interpolation() = default; - Interpolation() {} - Interpolation( const Interpolation& ); + // Setup Interpolation from source to target function space Interpolation( const Config&, const FunctionSpace& source, const FunctionSpace& target ); - void execute( const FieldSet& source, FieldSet& target ) const { get()->execute( source, target ); } - void execute( const Field& source, Field& target ) const { get()->execute( source, target ); } + // Setup Interpolation from source to coordinates given in a field with multiple components + Interpolation( const Config&, const FunctionSpace& source, const Field& target ); - const Implementation* get() const { return implementation_.get(); } + // Setup Interpolation from source to coordinates given by separate fields for each component + Interpolation( const Config&, const FunctionSpace& source, const FieldSet& target ); - operator bool() const { return implementation_; } + // Setup Interpolation from source grid to target grid + Interpolation( const Config&, const Grid& source, const Grid& target ); - void print( std::ostream& out ) const { implementation_->print( out ); } + void execute( const FieldSet& source, FieldSet& target ) const; -private: - eckit::SharedPtr implementation_; + void execute( const Field& source, Field& target ) const; + + void print( std::ostream& out ) const; + + const FunctionSpace& source() const; + const FunctionSpace& target() const; }; /// C-interface @@ -60,6 +73,15 @@ extern "C" { Interpolation::Implementation* atlas__Interpolation__new( const eckit::Parametrisation* config, const functionspace::FunctionSpaceImpl* source, const functionspace::FunctionSpaceImpl* target ); + +Interpolation::Implementation* atlas__Interpolation__new_tgt_field( const eckit::Parametrisation* config, + const functionspace::FunctionSpaceImpl* source, + const field::FieldImpl* target ); + +Interpolation::Implementation* atlas__Interpolation__new_tgt_fieldset( const eckit::Parametrisation* config, + const functionspace::FunctionSpaceImpl* source, + const field::FieldSetImpl* target ); + void atlas__Interpolation__delete( Interpolation::Implementation* This ); void atlas__Interpolation__execute_field( Interpolation::Implementation* This, const field::FieldImpl* source, field::FieldImpl* target ); diff --git a/src/atlas/interpolation/Vector2D.cc b/src/atlas/interpolation/Vector2D.cc new file mode 100644 index 000000000..e88262e16 --- /dev/null +++ b/src/atlas/interpolation/Vector2D.cc @@ -0,0 +1,26 @@ +/* + * (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 "Vector2D.h" + +#if !ATLAS_HAVE_EIGEN + +#include + +namespace atlas { +namespace interpolation { + +void Vector2D::print( std::ostream& s ) const { + s << "[" << x() << "," << y() << "]"; +} + +} // namespace interpolation +} // namespace atlas +#endif diff --git a/src/atlas/interpolation/Vector2D.h b/src/atlas/interpolation/Vector2D.h index 5d20215a5..fffb65e06 100644 --- a/src/atlas/interpolation/Vector2D.h +++ b/src/atlas/interpolation/Vector2D.h @@ -10,9 +10,6 @@ #pragma once -#include -#include - #include "atlas/library/config.h" #if ATLAS_HAVE_EIGEN @@ -24,6 +21,11 @@ #include #include +#else + +#include +#include + #endif namespace atlas { @@ -75,7 +77,7 @@ class Vector2D { double cross( const Vector2D& other ) const { return x() * other.y() - y() * other.x(); } - void print( std::ostream& s ) const { s << "[" << x() << "," << y() << "]"; } + void print( std::ostream& s ) const; friend std::ostream& operator<<( std::ostream& s, const Vector2D& p ) { p.print( s ); diff --git a/src/atlas/interpolation/Vector3D.cc b/src/atlas/interpolation/Vector3D.cc new file mode 100644 index 000000000..1fb5b807e --- /dev/null +++ b/src/atlas/interpolation/Vector3D.cc @@ -0,0 +1,26 @@ +/* + * (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 "Vector3D.h" + +#if !ATLAS_HAVE_EIGEN + +#include + +namespace atlas { +namespace interpolation { + +void Vector3D::print( std::ostream& s ) const { + s << "[" << x() << "," << y() << "," << z() << "]"; +} + +} // namespace interpolation +} // namespace atlas +#endif diff --git a/src/atlas/interpolation/Vector3D.h b/src/atlas/interpolation/Vector3D.h index 2dc1594ee..f09163b31 100644 --- a/src/atlas/interpolation/Vector3D.h +++ b/src/atlas/interpolation/Vector3D.h @@ -10,9 +10,6 @@ #pragma once -#include -#include - #include "atlas/library/config.h" #if ATLAS_HAVE_EIGEN @@ -24,6 +21,11 @@ #include #include +#else + +#include +#include + #endif namespace atlas { @@ -72,7 +74,11 @@ class Vector3D { Vector3D operator-() const { return Vector3D( -x(), -y(), -z() ); } - double norm() const { return sqrt( squaredNorm() ); } + Vector3D operator/( double a ) const { return Vector3D( x() / a, y() / a, z() / a ); } + + Vector3D operator*( double a ) const { return Vector3D( x() * a, y() * a, z() * a ); } + + double norm() const { return std::sqrt( squaredNorm() ); } double squaredNorm() const { return x() * x() + y() * y() + z() * z(); } @@ -83,7 +89,7 @@ class Vector3D { x() * other.y() - y() * other.x() ); } - void print( std::ostream& s ) const { s << "[" << x() << "," << y() << "," << z() << "]"; } + void print( std::ostream& s ) const; friend std::ostream& operator<<( std::ostream& s, const Vector3D& p ) { p.print( s ); diff --git a/src/atlas/interpolation/element/Quad3D.cc b/src/atlas/interpolation/element/Quad3D.cc index f1703f034..e946cb41e 100644 --- a/src/atlas/interpolation/element/Quad3D.cc +++ b/src/atlas/interpolation/element/Quad3D.cc @@ -9,8 +9,7 @@ */ #include - -#include "eckit/exception/Exceptions.h" +#include #include "atlas/interpolation/element/Quad3D.h" #include "atlas/interpolation/element/Triag3D.h" @@ -90,6 +89,11 @@ double Quad3D::area() const { return T013.area() + T231.area(); } +void Quad3D::print( std::ostream& s ) const { + s << "Quad3D[v00=" << v00 << ",v10=" << v10 << ",v11=" << v11 << ",v01=" << v01 << "]"; +} + + //---------------------------------------------------------------------------------------------------------------------- } // namespace element diff --git a/src/atlas/interpolation/element/Quad3D.h b/src/atlas/interpolation/element/Quad3D.h index f0d4a2b92..abd304914 100644 --- a/src/atlas/interpolation/element/Quad3D.h +++ b/src/atlas/interpolation/element/Quad3D.h @@ -10,10 +10,12 @@ #pragma once +#include #include #include "atlas/interpolation/Vector3D.h" #include "atlas/interpolation/method/Intersect.h" +#include "atlas/runtime/Exception.h" #include "atlas/util/Point.h" namespace atlas { @@ -43,9 +45,7 @@ class Quad3D { double area() const; - void print( std::ostream& s ) const { - s << "Quad3D[v00=" << v00 << ",v10=" << v10 << ",v11=" << v11 << ",v01=" << v01 << "]"; - } + void print( std::ostream& ) const; friend std::ostream& operator<<( std::ostream& s, const Quad3D& p ) { p.print( s ); @@ -57,7 +57,7 @@ class Quad3D { if ( i == 1 ) return v10; if ( i == 2 ) return v11; if ( i == 3 ) return v01; - throw eckit::OutOfRange(i,4,Here()); + throw_OutOfRange( "Quad3D::p(i)", i, 4, Here() ); } private: // members diff --git a/src/atlas/interpolation/element/Triag3D.cc b/src/atlas/interpolation/element/Triag3D.cc index afc245004..2b90b01cf 100644 --- a/src/atlas/interpolation/element/Triag3D.cc +++ b/src/atlas/interpolation/element/Triag3D.cc @@ -9,6 +9,7 @@ */ #include +#include #include "atlas/interpolation/element/Triag3D.h" #include "atlas/interpolation/method/Intersect.h" @@ -93,6 +94,12 @@ double Triag3D::area() const { return 0.5 * cross.norm(); } +void Triag3D::print( std::ostream& s ) const { + s << "Triag3D[" + << "v0=(" << v0[0] << ", " << v0[1] << ", " << v0[2] << "), v1=(" << v1[0] << ", " << v1[1] << ", " << v1[2] + << "), v2=(" << v2[0] << ", " << v2[1] << ", " << v2[2] << ")]"; +} + //---------------------------------------------------------------------------------------------------------------------- } // namespace element diff --git a/src/atlas/interpolation/element/Triag3D.h b/src/atlas/interpolation/element/Triag3D.h index f4da50450..fa4c6769c 100644 --- a/src/atlas/interpolation/element/Triag3D.h +++ b/src/atlas/interpolation/element/Triag3D.h @@ -10,11 +10,12 @@ #pragma once +#include #include -#include "eckit/exception/Exceptions.h" #include "atlas/interpolation/Vector3D.h" #include "atlas/interpolation/method/Intersect.h" +#include "atlas/runtime/Exception.h" #include "atlas/util/Point.h" namespace atlas { @@ -45,11 +46,7 @@ class Triag3D { double area() const; - void print( std::ostream& s ) const { - s << "Triag3D[" - << "v0=(" << v0[0] << ", " << v0[1] << ", " << v0[2] << "), v1=(" << v1[0] << ", " << v1[1] << ", " << v1[2] - << "), v2=(" << v2[0] << ", " << v2[1] << ", " << v2[2] << ")]"; - } + void print( std::ostream& s ) const; friend std::ostream& operator<<( std::ostream& s, const Triag3D& p ) { p.print( s ); @@ -60,7 +57,7 @@ class Triag3D { if ( i == 0 ) return v0; if ( i == 1 ) return v1; if ( i == 2 ) return v2; - throw eckit::OutOfRange(i,3,Here()); + throw_OutOfRange( "Triag3D::p(i)", i, 3, Here() ); } private: // members diff --git a/src/atlas/interpolation/method/Method.cc b/src/atlas/interpolation/method/Method.cc index f51c31134..b5f6920d7 100644 --- a/src/atlas/interpolation/method/Method.cc +++ b/src/atlas/interpolation/method/Method.cc @@ -10,9 +10,6 @@ #include "atlas/interpolation/method/Method.h" -#include - -#include "eckit/exception/Exceptions.h" #include "eckit/linalg/LinearAlgebra.h" #include "eckit/linalg/Vector.h" #include "eckit/log/Timer.h" @@ -20,108 +17,162 @@ #include "eckit/thread/Mutex.h" #include "eckit/thread/Once.h" +#include "atlas/array.h" #include "atlas/field/Field.h" #include "atlas/field/FieldSet.h" #include "atlas/functionspace/NodeColumns.h" #include "atlas/mesh/Nodes.h" +#include "atlas/runtime/Exception.h" #include "atlas/runtime/Log.h" #include "atlas/runtime/Trace.h" -// for static linking -#include "FiniteElement.h" -#include "KNearestNeighbours.h" -#include "NearestNeighbour.h" - namespace atlas { namespace interpolation { -namespace { +void Method::check_compatibility( const Field& src, const Field& tgt ) const { + ATLAS_ASSERT( src.datatype() == tgt.datatype() ); + ATLAS_ASSERT( src.rank() == tgt.rank() ); + ATLAS_ASSERT( src.levels() == tgt.levels() ); + ATLAS_ASSERT( src.variables() == tgt.variables() ); -typedef std::map MethodFactoryMap_t; -static MethodFactoryMap_t* m = 0; -static eckit::Mutex* local_mutex = 0; -static pthread_once_t once = PTHREAD_ONCE_INIT; - -static void init() { - local_mutex = new eckit::Mutex(); - m = new MethodFactoryMap_t(); + ATLAS_ASSERT( !matrix_.empty() ); + ATLAS_ASSERT( tgt.shape( 0 ) == static_cast( matrix_.rows() ) ); + ATLAS_ASSERT( src.shape( 0 ) == static_cast( matrix_.cols() ) ); } -template -void load_builder() { - MethodBuilder( "tmp" ); +template +void Method::interpolate_field( const Field& src, Field& tgt ) const { + check_compatibility( src, tgt ); + if ( src.rank() == 1 ) { interpolate_field_rank1( src, tgt ); } + if ( src.rank() == 2 ) { interpolate_field_rank2( src, tgt ); } + if ( src.rank() == 3 ) { interpolate_field_rank3( src, tgt ); } } -struct force_link { - force_link() { - load_builder(); - load_builder(); - load_builder(); +template +void Method::interpolate_field_rank1( const Field& src, Field& tgt ) const { + const auto outer = matrix_.outer(); + const auto index = matrix_.inner(); + const auto weight = matrix_.data(); + idx_t rows = static_cast( matrix_.rows() ); + + if ( use_eckit_linalg_spmv_ ) { + if ( src.datatype() != array::make_datatype() ) { + throw_NotImplemented( "Only double precision interpolation is currently implemented with eckit backend", + Here() ); + } + ATLAS_ASSERT( src.array().contiguous() ); + ATLAS_ASSERT( tgt.array().contiguous() ); + + eckit::linalg::Vector v_src( array::make_view( src ).data(), src.shape( 0 ) ); + eckit::linalg::Vector v_tgt( array::make_view( tgt ).data(), tgt.shape( 0 ) ); + eckit::linalg::LinearAlgebra::backend().spmv( matrix_, v_src, v_tgt ); + } + else { + auto v_src = array::make_view( src ); + auto v_tgt = array::make_view( tgt ); + + atlas_omp_parallel_for( idx_t r = 0; r < rows; ++r ) { + v_tgt( r ) = 0.; + for ( idx_t c = outer[r]; c < outer[r + 1]; ++c ) { + idx_t n = index[c]; + Value w = static_cast( weight[c] ); + v_tgt( r ) += w * v_src( n ); + } + } } -}; +} -} // namespace +template +void Method::interpolate_field_rank2( const Field& src, Field& tgt ) const { + const auto outer = matrix_.outer(); + const auto index = matrix_.inner(); + const auto weight = matrix_.data(); + idx_t rows = static_cast( matrix_.rows() ); -MethodFactory::MethodFactory( const std::string& name ) : name_( name ) { - pthread_once( &once, init ); - eckit::AutoLock lock( local_mutex ); + auto v_src = array::make_view( src ); + auto v_tgt = array::make_view( tgt ); - if ( m->find( name ) != m->end() ) { throw eckit::SeriousBug( "MethodFactory duplicate '" + name + "'" ); } + idx_t Nk = src.shape( 1 ); - ASSERT( m->find( name ) == m->end() ); - ( *m )[name] = this; + atlas_omp_parallel_for( idx_t r = 0; r < rows; ++r ) { + for ( idx_t k = 0; k < Nk; ++k ) { + v_tgt( r, k ) = 0.; + } + for ( idx_t c = outer[r]; c < outer[r + 1]; ++c ) { + idx_t n = index[c]; + Value w = static_cast( weight[c] ); + for ( idx_t k = 0; k < Nk; ++k ) + v_tgt( r, k ) += w * v_src( n, k ); + } + } } -MethodFactory::~MethodFactory() { - eckit::AutoLock lock( local_mutex ); - m->erase( name_ ); -} -Method* MethodFactory::build( const std::string& name, const Method::Config& config ) { - pthread_once( &once, init ); - eckit::AutoLock lock( local_mutex ); +template +void Method::interpolate_field_rank3( const Field& src, Field& tgt ) const { + const auto outer = matrix_.outer(); + const auto index = matrix_.inner(); + const auto weight = matrix_.data(); + idx_t rows = static_cast( matrix_.rows() ); + + auto v_src = array::make_view( src ); + auto v_tgt = array::make_view( tgt ); - force_link(); + idx_t Nk = src.shape( 1 ); + idx_t Nl = src.shape( 2 ); - MethodFactoryMap_t::const_iterator j = m->find( name ); - if ( j == m->end() ) { - eckit::Log::error() << "MethodFactory '" << name << "' not found." << std::endl; - eckit::Log::error() << "MethodFactories are:" << std::endl; - for ( j = m->begin(); j != m->end(); ++j ) { - eckit::Log::error() << '\t' << ( *j ).first << std::endl; + atlas_omp_parallel_for( idx_t r = 0; r < rows; ++r ) { + for ( idx_t k = 0; k < Nk; ++k ) { + for ( idx_t l = 0; l < Nl; ++l ) { + v_tgt( r, k, l ) = 0.; + } + } + for ( idx_t c = outer[r]; c < outer[r + 1]; ++c ) { + idx_t n = index[c]; + Value w = static_cast( weight[c] ); + for ( idx_t k = 0; k < Nk; ++k ) + for ( idx_t l = 0; l < Nl; ++l ) + v_tgt( r, k, l ) += w * v_src( n, k, l ); } - throw eckit::SeriousBug( "MethodFactory '" + name + "' not found." ); } +} + + +Method::Method( const Method::Config& config ) { + std::string spmv = ""; + config.get( "spmv", spmv ); + use_eckit_linalg_spmv_ = ( spmv == "eckit" ); +} - return ( *j ).second->make( config ); +void Method::setup( const FunctionSpace& /*source*/, const Field& /*target*/ ) { + ATLAS_NOTIMPLEMENTED; +} + +void Method::setup( const FunctionSpace& /*source*/, const FieldSet& /*target*/ ) { + ATLAS_NOTIMPLEMENTED; } void Method::execute( const FieldSet& fieldsSource, FieldSet& fieldsTarget ) const { ATLAS_TRACE( "atlas::interpolation::method::Method::execute()" ); - const size_t N = fieldsSource.size(); - ASSERT( N == fieldsTarget.size() ); + const idx_t N = fieldsSource.size(); + ATLAS_ASSERT( N == fieldsTarget.size() ); - for ( size_t i = 0; i < fieldsSource.size(); ++i ) { + for ( idx_t i = 0; i < fieldsSource.size(); ++i ) { Log::debug() << "Method::execute() on field " << ( i + 1 ) << '/' << N << "..." << std::endl; - - const Field& src = fieldsSource[i]; - Field& tgt = fieldsTarget[i]; - - eckit::linalg::Vector v_src( const_cast( src.data() ), src.shape( 0 ) ); - eckit::linalg::Vector v_tgt( tgt.data(), tgt.shape( 0 ) ); - - eckit::linalg::LinearAlgebra::backend().spmv( matrix_, v_src, v_tgt ); + Method::execute( fieldsSource[i], fieldsTarget[i] ); } } -void Method::execute( const Field& fieldSource, Field& fieldTarget ) const { +void Method::execute( const Field& src, Field& tgt ) const { + haloExchange( src ); + ATLAS_TRACE( "atlas::interpolation::method::Method::execute()" ); - eckit::linalg::Vector v_src( const_cast( fieldSource ).data(), fieldSource.shape( 0 ) ), - v_tgt( fieldTarget.data(), fieldTarget.shape( 0 ) ); + if ( src.datatype().kind() == array::DataType::KIND_REAL64 ) { interpolate_field( src, tgt ); } + if ( src.datatype().kind() == array::DataType::KIND_REAL32 ) { interpolate_field( src, tgt ); } - eckit::linalg::LinearAlgebra::backend().spmv( matrix_, v_src, v_tgt ); + tgt.set_dirty(); } void Method::normalise( Triplets& triplets ) { @@ -139,5 +190,14 @@ void Method::normalise( Triplets& triplets ) { } } +void Method::haloExchange( const FieldSet& fields ) const { + for ( auto& field : fields ) { + haloExchange( field ); + } +} +void Method::haloExchange( const Field& field ) const { + if ( field.dirty() ) source().haloExchange( field ); +} + } // namespace interpolation } // namespace atlas diff --git a/src/atlas/interpolation/method/Method.h b/src/atlas/interpolation/method/Method.h index 0f57609f5..65d430d8b 100644 --- a/src/atlas/interpolation/method/Method.h +++ b/src/atlas/interpolation/method/Method.h @@ -14,25 +14,25 @@ #include #include +#include "atlas/util/Object.h" #include "eckit/config/Configuration.h" #include "eckit/linalg/SparseMatrix.h" -#include "eckit/memory/Owned.h" -#include "eckit/memory/SharedPtr.h" namespace atlas { class Field; class FieldSet; class FunctionSpace; +class Grid; } // namespace atlas namespace atlas { namespace interpolation { -class Method : public eckit::Owned { +class Method : public util::Object { public: typedef eckit::Parametrisation Config; - Method( const Config& config ) : config_( config ) {} + Method( const Config& ); virtual ~Method() {} /** @@ -41,12 +41,18 @@ class Method : public eckit::Owned { * @param target functionspace containing target points */ virtual void setup( const FunctionSpace& source, const FunctionSpace& target ) = 0; + virtual void setup( const Grid& source, const Grid& target ) = 0; + virtual void setup( const FunctionSpace& source, const Field& target ); + virtual void setup( const FunctionSpace& source, const FieldSet& target ); virtual void execute( const FieldSet& source, FieldSet& target ) const; virtual void execute( const Field& source, Field& target ) const; virtual void print( std::ostream& ) const = 0; + virtual const FunctionSpace& source() const = 0; + virtual const FunctionSpace& target() const = 0; + protected: using Triplet = eckit::linalg::Triplet; using Triplets = std::vector; @@ -54,32 +60,33 @@ class Method : public eckit::Owned { static void normalise( Triplets& triplets ); - const Config& config_; + void haloExchange( const FieldSet& ) const; + void haloExchange( const Field& ) const; + + //const Config& config_; // NOTE : Matrix-free or non-linear interpolation operators do not have // matrices, // so do not expose here, even though only linear operators are now // implemented. Matrix matrix_; -}; -struct MethodFactory { - static Method* build( const std::string& name, const Method::Config& ); + bool use_eckit_linalg_spmv_; -protected: - std::string name_; - virtual Method* make( const Method::Config& ) = 0; +private: + template + void interpolate_field( const Field& src, Field& tgt ) const; - MethodFactory( const std::string& ); - virtual ~MethodFactory(); -}; + template + void interpolate_field_rank1( const Field& src, Field& tgt ) const; -template -struct MethodBuilder : public MethodFactory { - MethodBuilder( const std::string& name ) : MethodFactory( name ) {} + template + void interpolate_field_rank2( const Field& src, Field& tgt ) const; -private: - virtual Method* make( const Method::Config& config ) { return new T( config ); } + template + void interpolate_field_rank3( const Field& src, Field& tgt ) const; + + void check_compatibility( const Field& src, const Field& tgt ) const; }; } // namespace interpolation diff --git a/src/atlas/interpolation/method/MethodFactory.cc b/src/atlas/interpolation/method/MethodFactory.cc new file mode 100644 index 000000000..2f9337d89 --- /dev/null +++ b/src/atlas/interpolation/method/MethodFactory.cc @@ -0,0 +1,55 @@ +/* + * (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 "MethodFactory.h" + +// for static linking +#include "fe/FiniteElement.h" +#include "knn/KNearestNeighbours.h" +#include "knn/NearestNeighbour.h" +#include "structured/Cubic2D.h" +#include "structured/Cubic3D.h" +#include "structured/Linear2D.h" +#include "structured/Linear3D.h" +#include "structured/QuasiCubic2D.h" +#include "structured/QuasiCubic3D.h" + + +namespace atlas { +namespace interpolation { + +namespace { + +void force_link() { + static struct Link { + Link() { + MethodBuilder(); + MethodBuilder(); + MethodBuilder(); + MethodBuilder(); + MethodBuilder(); + MethodBuilder(); + MethodBuilder(); + MethodBuilder(); + MethodBuilder(); + } + } link; +} + +} // namespace + +Method* MethodFactory::build( const std::string& name, const Method::Config& config ) { + force_link(); + auto factory = get( name ); + return factory->make( config ); +} + +} // namespace interpolation +} // namespace atlas diff --git a/src/atlas/interpolation/method/MethodFactory.h b/src/atlas/interpolation/method/MethodFactory.h new file mode 100644 index 000000000..a210855e6 --- /dev/null +++ b/src/atlas/interpolation/method/MethodFactory.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 + +#include +#include +#include + +#include "atlas/interpolation/method/Method.h" +#include "atlas/util/Factory.h" +#include "atlas/util/Object.h" + +#include "eckit/config/Configuration.h" + +namespace atlas { +class Field; +class FieldSet; +class FunctionSpace; +class Grid; +} // namespace atlas + +namespace atlas { +namespace interpolation { + +struct MethodFactory : public util::Factory { +public: + static std::string className() { return "MethodFactory"; } + static Method* build( const std::string& name, const Method::Config& ); + +protected: + virtual Method* make( const Method::Config& ) = 0; + using Factory::Factory; +}; + +template +struct MethodBuilder : public MethodFactory { + using MethodFactory::MethodFactory; + +private: + virtual Method* make( const Method::Config& config ) { return new T( config ); } +}; + +} // namespace interpolation +} // namespace atlas diff --git a/src/atlas/interpolation/method/PointIndex3.cc b/src/atlas/interpolation/method/PointIndex3.cc index 8fbe18d27..8dc3a1b38 100644 --- a/src/atlas/interpolation/method/PointIndex3.cc +++ b/src/atlas/interpolation/method/PointIndex3.cc @@ -15,12 +15,14 @@ #include "atlas/array/MakeView.h" #include "atlas/interpolation/method/PointIndex3.h" #include "atlas/mesh/HybridElements.h" +#include "atlas/runtime/Trace.h" namespace atlas { namespace interpolation { namespace method { ElemIndex3* create_element_kdtree( const Field& field_centres ) { + ATLAS_TRACE(); const array::ArrayView centres = array::make_view( field_centres ); static bool fastBuildKDTrees = eckit::Resource( "$ATLAS_FAST_BUILD_KDTREES", true ); @@ -33,8 +35,8 @@ ElemIndex3* create_element_kdtree( const Field& field_centres ) { p.reserve( nb_cells ); for ( size_t j = 0; j < nb_cells; ++j ) { - p.push_back( ElemIndex3::Value( ElemIndex3::Point( centres( j, XX ), centres( j, YY ), centres( j, ZZ ) ), - ElemIndex3::Payload( j ) ) ); + p.emplace_back( ElemIndex3::Point( centres( j, XX ), centres( j, YY ), centres( j, ZZ ) ), + ElemIndex3::Payload( j ) ); } tree->build( p.begin(), p.end() ); diff --git a/src/atlas/interpolation/method/PointSet.cc b/src/atlas/interpolation/method/PointSet.cc index 753172880..22b814719 100644 --- a/src/atlas/interpolation/method/PointSet.cc +++ b/src/atlas/interpolation/method/PointSet.cc @@ -16,6 +16,7 @@ #include "atlas/interpolation/method/PointSet.h" #include "atlas/mesh/Mesh.h" #include "atlas/mesh/Nodes.h" +#include "atlas/runtime/Exception.h" using namespace eckit; @@ -34,9 +35,9 @@ PointSet::PointSet( Mesh& mesh ) { npts_ = nodes.size(); - ASSERT( npts_ > 0 ); + ATLAS_ASSERT( npts_ > 0 ); - ASSERT( nodes.has_field( "xyz" ) ); + ATLAS_ASSERT( nodes.has_field( "xyz" ) ); array::ArrayView coords = array::make_view( nodes.field( "xyz" ) ); static bool fastBuildKDTrees = eckit::Resource( "$ATLAS_FAST_BUILD_KDTREES", true ); diff --git a/src/atlas/interpolation/method/PointSet.h b/src/atlas/interpolation/method/PointSet.h index a12a1992b..e01edf447 100644 --- a/src/atlas/interpolation/method/PointSet.h +++ b/src/atlas/interpolation/method/PointSet.h @@ -23,6 +23,7 @@ #include "atlas/interpolation/method/PointIndex3.h" #include "atlas/mesh/Mesh.h" +#include "atlas/runtime/Exception.h" #include "atlas/runtime/Trace.h" namespace atlas { @@ -50,7 +51,7 @@ class PointSet { void list_unique_points( std::vector& opts ) { ATLAS_TRACE( "Finding unique points" ); - ASSERT( opts.empty() ); + ATLAS_ASSERT( opts.empty() ); opts.reserve( npts_ ); diff --git a/src/atlas/interpolation/method/FiniteElement.cc b/src/atlas/interpolation/method/fe/FiniteElement.cc similarity index 69% rename from src/atlas/interpolation/method/FiniteElement.cc rename to src/atlas/interpolation/method/fe/FiniteElement.cc index 3fd23a242..d93d0bb42 100644 --- a/src/atlas/interpolation/method/FiniteElement.cc +++ b/src/atlas/interpolation/method/fe/FiniteElement.cc @@ -9,28 +9,31 @@ */ #include +#include #include -#include "atlas/interpolation/method/FiniteElement.h" +#include "FiniteElement.h" -#include "eckit/exception/Exceptions.h" -#include "eckit/geometry/Point3.h" #include "eckit/log/Plural.h" #include "eckit/log/ProgressTimer.h" #include "eckit/log/Seconds.h" -#include "eckit/mpi/Comm.h" #include "atlas/functionspace/NodeColumns.h" #include "atlas/functionspace/PointCloud.h" +#include "atlas/grid.h" #include "atlas/interpolation/element/Quad3D.h" #include "atlas/interpolation/element/Triag3D.h" +#include "atlas/interpolation/method/MethodFactory.h" #include "atlas/interpolation/method/Ray.h" #include "atlas/mesh/ElementType.h" #include "atlas/mesh/Nodes.h" #include "atlas/mesh/actions/BuildCellCentres.h" #include "atlas/mesh/actions/BuildXYZField.h" +#include "atlas/meshgenerator.h" #include "atlas/parallel/GatherScatter.h" #include "atlas/parallel/mpi/Buffer.h" +#include "atlas/parallel/mpi/mpi.h" +#include "atlas/runtime/Exception.h" #include "atlas/runtime/Log.h" #include "atlas/runtime/Trace.h" #include "atlas/util/CoordinateEnums.h" @@ -51,36 +54,57 @@ static const double parametricEpsilon = 1e-15; } // namespace + +void FiniteElement::setup( const Grid& source, const Grid& target ) { + if ( mpi::comm().size() > 1 ) { ATLAS_NOTIMPLEMENTED; } + auto functionspace = []( const Grid& grid ) { + Mesh mesh; + if ( StructuredGrid{grid} ) { + mesh = MeshGenerator( "structured", util::Config( "three_dimensional", true ) ).generate( grid ); + } + else { + mesh = MeshGenerator( "delaunay" ).generate( grid ); + } + return functionspace::NodeColumns( mesh ); + }; + + setup( functionspace( source ), functionspace( target ) ); +} + void FiniteElement::setup( const FunctionSpace& source, const FunctionSpace& target ) { ATLAS_TRACE( "atlas::interpolation::method::FiniteElement::setup()" ); source_ = source; target_ = target; - if ( functionspace::NodeColumns tgt = target ) { - Mesh meshTarget = tgt.mesh(); + ATLAS_TRACE_SCOPE( "Setup target" ) { + if ( functionspace::NodeColumns tgt = target ) { + Mesh meshTarget = tgt.mesh(); - // generate 3D point coordinates - target_xyz_ = mesh::actions::BuildXYZField( "xyz" )( meshTarget ); - target_ghost_ = meshTarget.nodes().ghost(); - } - else if ( functionspace::PointCloud tgt = target ) { - const size_t N = tgt.size(); - target_xyz_ = Field( "xyz", array::make_datatype(), array::make_shape( N, 3 ) ); - target_ghost_ = tgt.ghost(); - array::ArrayView lonlat = array::make_view( tgt.lonlat() ); - array::ArrayView xyz = array::make_view( target_xyz_ ); - PointXYZ p2; - for ( size_t n = 0; n < N; ++n ) { - const PointLonLat p1( lonlat( n, 0 ), lonlat( n, 1 ) ); - util::Earth::convertSphericalToCartesian( p1, p2 ); - xyz( n, 0 ) = p2.x(); - xyz( n, 1 ) = p2.y(); - xyz( n, 2 ) = p2.z(); + // generate 3D point coordinates + target_xyz_ = mesh::actions::BuildXYZField( "xyz" )( meshTarget ); + target_ghost_ = meshTarget.nodes().ghost(); + target_lonlat_ = meshTarget.nodes().lonlat(); + } + else if ( functionspace::PointCloud tgt = target ) { + const idx_t N = tgt.size(); + target_xyz_ = Field( "xyz", array::make_datatype(), array::make_shape( N, 3 ) ); + target_ghost_ = tgt.ghost(); + target_lonlat_ = tgt.lonlat(); + array::ArrayView lonlat = array::make_view( tgt.lonlat() ); + array::ArrayView xyz = array::make_view( target_xyz_ ); + PointXYZ p2; + for ( idx_t n = 0; n < N; ++n ) { + const PointLonLat p1( lonlat( n, 0 ), lonlat( n, 1 ) ); + util::Earth::convertSphericalToCartesian( p1, p2 ); + xyz( n, 0 ) = p2.x(); + xyz( n, 1 ) = p2.y(); + xyz( n, 2 ) = p2.z(); + } + } + else { + ATLAS_NOTIMPLEMENTED; } - } - else { - NOTIMP; } setup( source ); @@ -91,31 +115,15 @@ struct Stencil { { max_stencil_size = 4 }; - Stencil() { - g = -1; - size = 0; - } - void add( gidx_t tgt, gidx_t src, double weight ) { - if ( g >= 0 ) { ASSERT( tgt == g ); } - g = tgt; - size_t i = size; - source[i] = src; - weights[i] = weight; - ++size; - } - gidx_t g; - std::array source; - std::array weights; - size_t size; }; void FiniteElement::print( std::ostream& out ) const { functionspace::NodeColumns src( source_ ); functionspace::NodeColumns tgt( target_ ); - if ( not tgt ) NOTIMP; + if ( not tgt ) ATLAS_NOTIMPLEMENTED; auto gidx_src = array::make_view( src.nodes().global_index() ); - ASSERT( tgt.nodes().size() == matrix_.rows() ); + ATLAS_ASSERT( tgt.nodes().size() == idx_t( matrix_.rows() ) ); auto field_stencil_points_loc = tgt.createField( option::variables( Stencil::max_stencil_size ) ); @@ -128,15 +136,15 @@ void FiniteElement::print( std::ostream& out ) const { stencil_size_loc.assign( 0 ); for ( Matrix::const_iterator it = matrix_.begin(); it != matrix_.end(); ++it ) { - int p = it.row(); - int& i = stencil_size_loc( p ); + idx_t p = idx_t( it.row() ); + idx_t& i = stencil_size_loc( p ); stencil_points_loc( p, i ) = gidx_src( it.col() ); stencil_weights_loc( p, i ) = *it; ++i; } - size_t global_size = tgt.gather().glb_dof(); + gidx_t global_size = tgt.gather().glb_dof(); auto field_stencil_points_glb = tgt.createField( option::variables( Stencil::max_stencil_size ) | option::global( 0 ) ); @@ -174,10 +182,13 @@ void FiniteElement::print( std::ostream& out ) const { void FiniteElement::setup( const FunctionSpace& source ) { const functionspace::NodeColumns src = source; - ASSERT( src ); + ATLAS_ASSERT( src ); Mesh meshSource = src.mesh(); + + auto trace_setup_source = atlas::Trace{Here(), "Setup source"}; + // generate 3D point coordinates Field source_xyz = mesh::actions::BuildXYZField( "xyz" )( meshSource ); @@ -189,43 +200,47 @@ void FiniteElement::setup( const FunctionSpace& source ) { eckit::ScopedPtr eTree( create_element_kdtree( cell_centres ) ); - const mesh::Nodes& i_nodes = meshSource.nodes(); + trace_setup_source.stop(); + icoords_.reset( new array::ArrayView( array::make_view( source_xyz ) ) ); ocoords_.reset( new array::ArrayView( array::make_view( target_xyz_ ) ) ); igidx_.reset( new array::ArrayView( array::make_view( src.nodes().global_index() ) ) ); + connectivity_ = &meshSource.cells().node_connectivity(); + const mesh::Nodes& i_nodes = meshSource.nodes(); - connectivity_ = &meshSource.cells().node_connectivity(); - size_t inp_npts = i_nodes.size(); - size_t out_npts = ocoords_->shape( 0 ); + idx_t inp_npts = i_nodes.size(); + idx_t out_npts = ocoords_->shape( 0 ); array::ArrayView out_ghosts = array::make_view( target_ghost_ ); - size_t Nelements = meshSource.cells().size(); + array::ArrayView out_lonlat = array::make_view( target_lonlat_ ); + + idx_t Nelements = meshSource.cells().size(); const double maxFractionElemsToTry = 0.2; // weights -- one per vertex of element, triangles (3) or quads (4) - std::vector weights_triplets; // structure to fill-in sparse matrix - weights_triplets.reserve( out_npts * 4 ); // preallocate space as if all elements where quads + Triplets weights_triplets; // structure to fill-in sparse matrix + weights_triplets.reserve( out_npts * 4 ); // preallocate space as if all elements where quads // search nearest k cell centres - const size_t maxNbElemsToTry = std::max( 64, size_t( Nelements * maxFractionElemsToTry ) ); - size_t max_neighbours = 0; + const idx_t maxNbElemsToTry = std::max( 64, idx_t( Nelements * maxFractionElemsToTry ) ); + idx_t max_neighbours = 0; std::vector failures; - { + ATLAS_TRACE_SCOPE( "Computing interpolation matrix" ) { eckit::ProgressTimer progress( "Computing interpolation weights", out_npts, "point", double( 5 ), Log::debug() ); - for ( size_t ip = 0; ip < out_npts; ++ip, ++progress ) { + for ( idx_t ip = 0; ip < out_npts; ++ip, ++progress ) { if ( out_ghosts( ip ) ) { continue; } PointXYZ p{( *ocoords_ )( ip, 0 ), ( *ocoords_ )( ip, 1 ), ( *ocoords_ )( ip, 2 )}; // lookup point - size_t kpts = 1; + idx_t kpts = 1; bool success = false; std::ostringstream failures_log; @@ -246,9 +261,7 @@ void FiniteElement::setup( const FunctionSpace& source ) { failures.push_back( ip ); Log::debug() << "------------------------------------------------------" "---------------------\n"; - PointLonLat pll; - util::Earth::convertCartesianToSpherical( p, pll ); - if ( pll.lon() < 0 ) pll.lon() += 360.; + const PointLonLat pll{out_lonlat( ip, 0 ), out_lonlat( ip, 1 )}; Log::debug() << "Failed to project point (lon,lat)=" << pll << '\n'; Log::debug() << failures_log.str(); } @@ -262,15 +275,12 @@ void FiniteElement::setup( const FunctionSpace& source ) { std::ostringstream msg; msg << "Rank " << eckit::mpi::comm().rank() << " failed to project points:\n"; for ( std::vector::const_iterator i = failures.begin(); i != failures.end(); ++i ) { - const PointXYZ p{( *ocoords_ )( *i, 0 ), ( *ocoords_ )( *i, 1 ), ( *ocoords_ )( *i, 2 )}; // lookup point - PointLonLat pll; - util::Earth::convertCartesianToSpherical( p, pll ); - if ( pll.lon() < 0 ) pll.lon() += 360.; + const PointLonLat pll{out_lonlat( *i, 0 ), out_lonlat( *i, 1 )}; // lookup point msg << "\t(lon,lat) = " << pll << "\n"; } Log::error() << msg.str() << std::endl; - throw eckit::SeriousBug( msg.str() ); + throw_Exception( msg.str() ); } // fill sparse matrix and return @@ -288,46 +298,50 @@ struct ElementEdge { }; Method::Triplets FiniteElement::projectPointToElements( size_t ip, const ElemIndex3::NodeList& elems, - std::ostream& failures_log ) const { - ASSERT( elems.begin() != elems.end() ); + std::ostream& /* failures_log */ ) const { + ATLAS_ASSERT( elems.begin() != elems.end() ); const size_t inp_points = icoords_->shape( 0 ); std::array idx; std::array w; Triplets triplets; + triplets.reserve( 4 ); Ray ray( PointXYZ{( *ocoords_ )( ip, 0 ), ( *ocoords_ )( ip, 1 ), ( *ocoords_ )( ip, 2 )} ); - Vector3D p{( *ocoords_ )( ip, 0 ), ( *ocoords_ )( ip, 1 ), ( *ocoords_ )( ip, 2 )}; + const Vector3D p{( *ocoords_ )( ip, 0 ), ( *ocoords_ )( ip, 1 ), ( *ocoords_ )( ip, 2 )}; ElementEdge edge; idx_t single_point; for ( ElemIndex3::NodeList::const_iterator itc = elems.begin(); itc != elems.end(); ++itc ) { - const size_t elem_id = ( *itc ).value().payload(); - ASSERT( elem_id < connectivity_->rows() ); + const idx_t elem_id = idx_t( ( *itc ).value().payload() ); + ATLAS_ASSERT( elem_id < connectivity_->rows() ); - const size_t nb_cols = connectivity_->cols( elem_id ); - ASSERT( nb_cols == 3 || nb_cols == 4 ); + const idx_t nb_cols = connectivity_->cols( elem_id ); + ATLAS_ASSERT( nb_cols == 3 || nb_cols == 4 ); - for ( size_t i = 0; i < nb_cols; ++i ) { - idx[i] = size_t( ( *connectivity_ )( elem_id, i ) ); - ASSERT( idx[i] < inp_points ); + for ( idx_t i = 0; i < nb_cols; ++i ) { + idx[i] = ( *connectivity_ )( elem_id, i ); + ATLAS_ASSERT( idx[i] < inp_points ); } - const double tolerance = 1.e-12; + constexpr double tolerance = 1.e-12; auto on_triag_edge = [&]() { if ( w[0] < tolerance ) { edge.idx[0] = 1; edge.idx[1] = 2; + w[0] = 0.; return true; } if ( w[1] < tolerance ) { edge.idx[0] = 0; edge.idx[1] = 2; + w[1] = 0.; return true; } if ( w[2] < tolerance ) { edge.idx[0] = 0; edge.idx[1] = 1; + w[2] = 0.; return true; } return false; @@ -337,21 +351,29 @@ Method::Triplets FiniteElement::projectPointToElements( size_t ip, const ElemInd if ( w[0] < tolerance && w[1] < tolerance ) { edge.idx[0] = 2; edge.idx[1] = 3; + w[0] = 0.; + w[1] = 0.; return true; } if ( w[1] < tolerance && w[2] < tolerance ) { edge.idx[0] = 0; edge.idx[1] = 3; + w[1] = 0.; + w[2] = 0.; return true; } if ( w[2] < tolerance && w[3] < tolerance ) { edge.idx[0] = 0; edge.idx[1] = 1; + w[2] = 0.; + w[3] = 0.; return true; } if ( w[3] < tolerance && w[0] < tolerance ) { edge.idx[0] = 1; edge.idx[1] = 2; + w[3] = 0.; + w[0] = 0.; return true; } return false; @@ -359,20 +381,36 @@ Method::Triplets FiniteElement::projectPointToElements( size_t ip, const ElemInd auto on_single_point = [&]() { if ( w[edge.idx[0]] < tolerance ) { - single_point = edge.idx[1]; + single_point = edge.idx[1]; + w[edge.idx[0]] = 0.; return true; } if ( w[edge.idx[1]] < tolerance ) { - single_point = edge.idx[0]; + single_point = edge.idx[0]; + w[edge.idx[1]] = 0.; return true; } return false; }; auto interpolate_edge = [&]( const Vector3D& p0, const Vector3D& p1 ) { - double t = ( p - p0 ).squaredNorm() / ( p1 - p0 ).squaredNorm(); - w[edge.idx[0]] = t; - w[edge.idx[1]] = 1. - t; + /* + * Given points p0,p1 defining the edge, and point p, find projected point pt + * on edge to compute interpolation weights. + * p + * |`. + * | `.v + * | `. + * p1--------------pt-----p0 + * <--d---- + */ + Vector3D d = ( p1 - p0 ) / ( p1 - p0 ).norm(); + Vector3D v = p - p0; + double t = v.dot( d ); + Vector3D pt = p0 + d * t; + t = ( pt - p0 ).norm() / ( p1 - p0 ).norm(); + w[edge.idx[0]] = 1. - t; + w[edge.idx[1]] = t; }; if ( nb_cols == 3 ) { @@ -385,7 +423,7 @@ Method::Triplets FiniteElement::projectPointToElements( size_t ip, const ElemInd // pick an epsilon based on a characteristic length (sqrt(area)) // (this scales linearly so it better compares with linear weights u,v,w) const double edgeEpsilon = parametricEpsilon * std::sqrt( triag.area() ); - ASSERT( edgeEpsilon >= 0 ); + ATLAS_ASSERT( edgeEpsilon >= 0 ); Intersect is = triag.intersects( ray, edgeEpsilon ); @@ -397,20 +435,18 @@ Method::Triplets FiniteElement::projectPointToElements( size_t ip, const ElemInd w[2] = is.v; if ( on_triag_edge() ) { - if ( on_single_point() ) { - triplets.push_back( Triplet( ip, idx[single_point], w[single_point] ) ); - } + if ( on_single_point() ) { triplets.emplace_back( ip, idx[single_point], w[single_point] ); } else { if ( ( *igidx_ )( idx[edge.idx[1]] ) < ( *igidx_ )( idx[edge.idx[0]] ) ) { edge.swap(); } interpolate_edge( triag.p( edge.idx[0] ), triag.p( edge.idx[1] ) ); for ( size_t i = 0; i < 2; ++i ) { - triplets.push_back( Triplet( ip, idx[edge.idx[i]], w[edge.idx[i]] ) ); + triplets.emplace_back( ip, idx[edge.idx[i]], w[edge.idx[i]] ); } } } else { for ( size_t i = 0; i < 3; ++i ) { - triplets.push_back( Triplet( ip, idx[i], w[i] ) ); + triplets.emplace_back( ip, idx[i], w[i] ); } } @@ -428,7 +464,7 @@ Method::Triplets FiniteElement::projectPointToElements( size_t ip, const ElemInd // pick an epsilon based on a characteristic length (sqrt(area)) // (this scales linearly so it better compares with linear weights u,v,w) const double edgeEpsilon = parametricEpsilon * std::sqrt( quad.area() ); - ASSERT( edgeEpsilon >= 0 ); + ATLAS_ASSERT( edgeEpsilon >= 0 ); Intersect is = quad.intersects( ray, edgeEpsilon ); @@ -440,20 +476,18 @@ Method::Triplets FiniteElement::projectPointToElements( size_t ip, const ElemInd w[3] = ( 1. - is.u ) * is.v; if ( on_quad_edge() ) { - if ( on_single_point() ) { - triplets.push_back( Triplet( ip, idx[single_point], w[single_point] ) ); - } + if ( on_single_point() ) { triplets.emplace_back( ip, idx[single_point], w[single_point] ); } else { if ( ( *igidx_ )( idx[edge.idx[1]] ) < ( *igidx_ )( idx[edge.idx[0]] ) ) { edge.swap(); } interpolate_edge( quad.p( edge.idx[0] ), quad.p( edge.idx[1] ) ); for ( size_t i = 0; i < 2; ++i ) { - triplets.push_back( Triplet( ip, idx[edge.idx[i]], w[edge.idx[i]] ) ); + triplets.emplace_back( ip, idx[edge.idx[i]], w[edge.idx[i]] ); } } } else { for ( size_t i = 0; i < 4; ++i ) { - triplets.push_back( Triplet( ip, idx[i], w[i] ) ); + triplets.emplace_back( ip, idx[i], w[i] ); } } break; // stop looking for elements diff --git a/src/atlas/interpolation/method/FiniteElement.h b/src/atlas/interpolation/method/fe/FiniteElement.h similarity index 86% rename from src/atlas/interpolation/method/FiniteElement.h rename to src/atlas/interpolation/method/fe/FiniteElement.h index 7d0c8b4b2..347da6db4 100644 --- a/src/atlas/interpolation/method/FiniteElement.h +++ b/src/atlas/interpolation/method/fe/FiniteElement.h @@ -18,6 +18,7 @@ #include "eckit/memory/NonCopyable.h" #include "atlas/array/ArrayView.h" +#include "atlas/functionspace/FunctionSpace.h" #include "atlas/interpolation/method/PointIndex3.h" #include "atlas/mesh/Elements.h" @@ -29,10 +30,12 @@ class FiniteElement : public Method { public: FiniteElement( const Config& config ) : Method( config ) {} - virtual ~FiniteElement() {} + virtual ~FiniteElement() override {} virtual void setup( const FunctionSpace& source, const FunctionSpace& target ) override; + virtual void setup( const Grid& source, const Grid& target ) override; + virtual void print( std::ostream& ) const override; protected: @@ -57,12 +60,16 @@ class FiniteElement : public Method { */ Triplets projectPointToElements( size_t ip, const ElemIndex3::NodeList& elems, std::ostream& failures_log ) const; + virtual const FunctionSpace& source() const override { return source_; } + virtual const FunctionSpace& target() const override { return target_; } + protected: mesh::MultiBlockConnectivity* connectivity_; std::unique_ptr> icoords_; std::unique_ptr> ocoords_; std::unique_ptr> igidx_; + Field target_lonlat_; Field target_xyz_; Field target_ghost_; diff --git a/src/atlas/interpolation/method/KNearestNeighbours.cc b/src/atlas/interpolation/method/knn/KNearestNeighbours.cc similarity index 72% rename from src/atlas/interpolation/method/KNearestNeighbours.cc rename to src/atlas/interpolation/method/knn/KNearestNeighbours.cc index afc405c3d..b6d2c3dbb 100644 --- a/src/atlas/interpolation/method/KNearestNeighbours.cc +++ b/src/atlas/interpolation/method/knn/KNearestNeighbours.cc @@ -8,14 +8,21 @@ * nor does it submit to any jurisdiction. */ -#include "atlas/interpolation/method/KNearestNeighbours.h" +#include "atlas/interpolation/method/knn/KNearestNeighbours.h" #include "eckit/log/Plural.h" #include "eckit/log/Timer.h" +#include "atlas/array.h" #include "atlas/functionspace/NodeColumns.h" +#include "atlas/grid/Grid.h" +#include "atlas/grid/StructuredGrid.h" +#include "atlas/interpolation/method/MethodFactory.h" #include "atlas/mesh/Nodes.h" #include "atlas/mesh/actions/BuildXYZField.h" +#include "atlas/meshgenerator.h" +#include "atlas/parallel/mpi/mpi.h" +#include "atlas/runtime/Exception.h" #include "atlas/runtime/Log.h" #include "atlas/runtime/Trace.h" @@ -32,21 +39,39 @@ MethodBuilder __builder( "k-nearest-neighbours" ); KNearestNeighbours::KNearestNeighbours( const Method::Config& config ) : KNearestNeighboursBase( config ) { k_ = 1; config.get( "k-nearest-neighbours", k_ ); - ASSERT( k_ ); + ATLAS_ASSERT( k_ ); +} + +void KNearestNeighbours::setup( const Grid& source, const Grid& target ) { + if ( mpi::comm().size() > 1 ) { ATLAS_NOTIMPLEMENTED; } + auto functionspace = []( const Grid& grid ) -> FunctionSpace { + Mesh mesh; + if ( StructuredGrid( grid ) ) { + mesh = MeshGenerator( "structured", util::Config( "three_dimensional", true ) ).generate( grid ); + } + else { + mesh = MeshGenerator( "delaunay" ).generate( grid ); + } + return functionspace::NodeColumns( mesh ); + }; + + setup( functionspace( source ), functionspace( target ) ); } void KNearestNeighbours::setup( const FunctionSpace& source, const FunctionSpace& target ) { + source_ = source; + target_ = target; functionspace::NodeColumns src = source; functionspace::NodeColumns tgt = target; - ASSERT( src ); - ASSERT( tgt ); + ATLAS_ASSERT( src ); + ATLAS_ASSERT( tgt ); Mesh meshSource = src.mesh(); Mesh meshTarget = tgt.mesh(); // build point-search tree buildPointSearchTree( meshSource ); - ASSERT( pTree_ ); + ATLAS_ASSERT( pTree_ != nullptr ); // generate 3D point coordinates mesh::actions::BuildXYZField( "xyz" )( meshTarget ); @@ -76,7 +101,7 @@ void KNearestNeighbours::setup( const FunctionSpace& source, const FunctionSpace // calculate weights (individual and total, to normalise) using distance // squared const size_t npts = nn.size(); - ASSERT( npts ); + ATLAS_ASSERT( npts ); weights.resize( npts, 0 ); double sum = 0; @@ -87,12 +112,12 @@ void KNearestNeighbours::setup( const FunctionSpace& source, const FunctionSpace weights[j] = 1. / ( 1. + d2 ); sum += weights[j]; } - ASSERT( sum > 0 ); + ATLAS_ASSERT( sum > 0 ); // insert weights into the matrix for ( size_t j = 0; j < npts; ++j ) { size_t jp = nn[j].payload(); - ASSERT( jp < inp_npts ); + ATLAS_ASSERT( jp < inp_npts ); weights_triplets.push_back( Triplet( ip, jp, weights[j] / sum ) ); } } diff --git a/src/atlas/interpolation/method/KNearestNeighbours.h b/src/atlas/interpolation/method/knn/KNearestNeighbours.h similarity index 70% rename from src/atlas/interpolation/method/KNearestNeighbours.h rename to src/atlas/interpolation/method/knn/KNearestNeighbours.h index ab20d5779..4e8c8919f 100644 --- a/src/atlas/interpolation/method/KNearestNeighbours.h +++ b/src/atlas/interpolation/method/knn/KNearestNeighbours.h @@ -10,7 +10,8 @@ #pragma once -#include "atlas/interpolation/method/KNearestNeighboursBase.h" +#include "atlas/functionspace/FunctionSpace.h" +#include "atlas/interpolation/method/knn/KNearestNeighboursBase.h" namespace atlas { namespace interpolation { @@ -19,7 +20,7 @@ namespace method { class KNearestNeighbours : public KNearestNeighboursBase { public: KNearestNeighbours( const Config& config ); - virtual ~KNearestNeighbours() {} + virtual ~KNearestNeighbours() override {} /** * @brief Create an interpolant sparse matrix relating two (pre-partitioned) @@ -32,7 +33,15 @@ class KNearestNeighbours : public KNearestNeighboursBase { virtual void print( std::ostream& ) const override {} -protected: + virtual void setup( const Grid& source, const Grid& target ) override; + + virtual const FunctionSpace& source() const override { return source_; } + virtual const FunctionSpace& target() const override { return target_; } + +private: + FunctionSpace source_; + FunctionSpace target_; + size_t k_; }; diff --git a/src/atlas/interpolation/method/KNearestNeighboursBase.cc b/src/atlas/interpolation/method/knn/KNearestNeighboursBase.cc similarity index 87% rename from src/atlas/interpolation/method/KNearestNeighboursBase.cc rename to src/atlas/interpolation/method/knn/KNearestNeighboursBase.cc index 3a25cd091..9c1e16000 100644 --- a/src/atlas/interpolation/method/KNearestNeighboursBase.cc +++ b/src/atlas/interpolation/method/knn/KNearestNeighboursBase.cc @@ -9,8 +9,10 @@ */ #include "eckit/config/Resource.h" +#include "eckit/log/TraceTimer.h" -#include "atlas/interpolation/method/KNearestNeighboursBase.h" +#include "atlas/array.h" +#include "atlas/interpolation/method/knn/KNearestNeighboursBase.h" #include "atlas/library/Library.h" #include "atlas/mesh/Nodes.h" #include "atlas/mesh/actions/BuildXYZField.h" @@ -36,14 +38,14 @@ void KNearestNeighboursBase::buildPointSearchTree( Mesh& meshSource ) { if ( fastBuildKDTrees ) { std::vector pidx; pidx.reserve( meshSource.nodes().size() ); - for ( size_t ip = 0; ip < meshSource.nodes().size(); ++ip ) { + for ( idx_t ip = 0; ip < meshSource.nodes().size(); ++ip ) { PointIndex3::Point p{coords( ip, 0 ), coords( ip, 1 ), coords( ip, 2 )}; pidx.push_back( PointIndex3::Value( p, ip ) ); } pTree_->build( pidx.begin(), pidx.end() ); } else { - for ( size_t ip = 0; ip < meshSource.nodes().size(); ++ip ) { + for ( idx_t ip = 0; ip < meshSource.nodes().size(); ++ip ) { PointIndex3::Point p{coords( ip, 0 ), coords( ip, 1 ), coords( ip, 2 )}; pTree_->insert( PointIndex3::Value( p, ip ) ); } diff --git a/src/atlas/interpolation/method/KNearestNeighboursBase.h b/src/atlas/interpolation/method/knn/KNearestNeighboursBase.h similarity index 87% rename from src/atlas/interpolation/method/KNearestNeighboursBase.h rename to src/atlas/interpolation/method/knn/KNearestNeighboursBase.h index aca15cd33..0e92070ff 100644 --- a/src/atlas/interpolation/method/KNearestNeighboursBase.h +++ b/src/atlas/interpolation/method/knn/KNearestNeighboursBase.h @@ -10,7 +10,7 @@ #pragma once -#include "eckit/memory/ScopedPtr.h" +#include #include "atlas/interpolation/method/Method.h" #include "atlas/interpolation/method/PointIndex3.h" @@ -22,12 +22,12 @@ namespace method { class KNearestNeighboursBase : public Method { public: KNearestNeighboursBase( const Config& config ) : Method( config ) {} - virtual ~KNearestNeighboursBase() {} + virtual ~KNearestNeighboursBase() override {} protected: void buildPointSearchTree( Mesh& meshSource ); - eckit::ScopedPtr pTree_; + std::unique_ptr pTree_; }; } // namespace method diff --git a/src/atlas/interpolation/method/NearestNeighbour.cc b/src/atlas/interpolation/method/knn/NearestNeighbour.cc similarity index 69% rename from src/atlas/interpolation/method/NearestNeighbour.cc rename to src/atlas/interpolation/method/knn/NearestNeighbour.cc index 14f76eefc..6beae9844 100644 --- a/src/atlas/interpolation/method/NearestNeighbour.cc +++ b/src/atlas/interpolation/method/knn/NearestNeighbour.cc @@ -10,10 +10,16 @@ #include "eckit/log/Plural.h" +#include "atlas/array.h" #include "atlas/functionspace/NodeColumns.h" -#include "atlas/interpolation/method/NearestNeighbour.h" +#include "atlas/grid.h" +#include "atlas/interpolation/method/MethodFactory.h" +#include "atlas/interpolation/method/knn/NearestNeighbour.h" #include "atlas/mesh/Nodes.h" #include "atlas/mesh/actions/BuildXYZField.h" +#include "atlas/meshgenerator.h" +#include "atlas/parallel/mpi/mpi.h" +#include "atlas/runtime/Exception.h" #include "atlas/runtime/Log.h" #include "atlas/runtime/Trace.h" @@ -27,18 +33,36 @@ MethodBuilder __builder( "nearest-neighbour" ); } // namespace +void NearestNeighbour::setup( const Grid& source, const Grid& target ) { + if ( mpi::comm().size() > 1 ) { ATLAS_NOTIMPLEMENTED; } + auto functionspace = []( const Grid& grid ) -> FunctionSpace { + Mesh mesh; + if ( StructuredGrid( grid ) ) { + mesh = MeshGenerator( "structured", util::Config( "three_dimensional" ) ).generate( grid ); + } + else { + mesh = MeshGenerator( "delaunay" ).generate( grid ); + } + return functionspace::NodeColumns( mesh ); + }; + + setup( functionspace( source ), functionspace( target ) ); +} + void NearestNeighbour::setup( const FunctionSpace& source, const FunctionSpace& target ) { + source_ = source; + target_ = target; functionspace::NodeColumns src = source; functionspace::NodeColumns tgt = target; - ASSERT( src ); - ASSERT( tgt ); + ATLAS_ASSERT( src ); + ATLAS_ASSERT( tgt ); Mesh meshSource = src.mesh(); Mesh meshTarget = tgt.mesh(); // build point-search tree buildPointSearchTree( meshSource ); - ASSERT( pTree_ ); + ATLAS_ASSERT( pTree_ != nullptr ); // generate 3D point coordinates mesh::actions::BuildXYZField( "xyz" )( meshTarget ); @@ -64,7 +88,7 @@ void NearestNeighbour::setup( const FunctionSpace& source, const FunctionSpace& size_t jp = nn.payload(); // insert the weights into the interpolant matrix - ASSERT( jp < inp_npts ); + ATLAS_ASSERT( jp < inp_npts ); weights_triplets.push_back( Triplet( ip, jp, 1 ) ); } } diff --git a/src/atlas/interpolation/method/NearestNeighbour.h b/src/atlas/interpolation/method/knn/NearestNeighbour.h similarity index 71% rename from src/atlas/interpolation/method/NearestNeighbour.h rename to src/atlas/interpolation/method/knn/NearestNeighbour.h index 829e8647a..85ba2c3a7 100644 --- a/src/atlas/interpolation/method/NearestNeighbour.h +++ b/src/atlas/interpolation/method/knn/NearestNeighbour.h @@ -10,7 +10,8 @@ #pragma once -#include "atlas/interpolation/method/KNearestNeighboursBase.h" +#include "atlas/functionspace/FunctionSpace.h" +#include "atlas/interpolation/method/knn/KNearestNeighboursBase.h" namespace atlas { namespace interpolation { @@ -19,7 +20,7 @@ namespace method { class NearestNeighbour : public KNearestNeighboursBase { public: NearestNeighbour( const Config& config ) : KNearestNeighboursBase( config ) {} - virtual ~NearestNeighbour() {} + virtual ~NearestNeighbour() override {} virtual void print( std::ostream& ) const override {} @@ -32,6 +33,15 @@ class NearestNeighbour : public KNearestNeighboursBase { * @param target functionspace containing target points */ virtual void setup( const FunctionSpace& source, const FunctionSpace& target ) override; + + virtual void setup( const Grid& source, const Grid& target ) override; + + virtual const FunctionSpace& source() const override { return source_; } + virtual const FunctionSpace& target() const override { return target_; } + +private: + FunctionSpace source_; + FunctionSpace target_; }; } // namespace method diff --git a/src/atlas/interpolation/method/structured/Cubic2D.cc b/src/atlas/interpolation/method/structured/Cubic2D.cc new file mode 100644 index 000000000..52c543242 --- /dev/null +++ b/src/atlas/interpolation/method/structured/Cubic2D.cc @@ -0,0 +1,32 @@ +/* + * (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. and Interpolation + */ + +#include "Cubic2D.h" + +#include "atlas/interpolation/method/MethodFactory.h" + +namespace atlas { +namespace interpolation { +namespace method { + +namespace { + +MethodBuilder __builder1( "structured-cubic2D" ); +MethodBuilder __builder2( "cubic2D" ); +MethodBuilder __builder3( "structured-bicubic" ); +MethodBuilder __builder4( "bicubic" ); + +} // namespace + +Cubic2D::Cubic2D( const Config& config ) : StructuredInterpolation2D( config ) {} + +} // namespace method +} // namespace interpolation +} // namespace atlas diff --git a/src/atlas/interpolation/method/structured/Cubic2D.h b/src/atlas/interpolation/method/structured/Cubic2D.h new file mode 100644 index 000000000..437e195d4 --- /dev/null +++ b/src/atlas/interpolation/method/structured/Cubic2D.h @@ -0,0 +1,27 @@ +/* + * (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. and Interpolation + */ + +#pragma once + +#include "StructuredInterpolation2D.h" +#include "kernels/CubicHorizontalKernel.h" + +namespace atlas { +namespace interpolation { +namespace method { + +class Cubic2D : public StructuredInterpolation2D { +public: + Cubic2D( const Config& ); +}; + +} // namespace method +} // namespace interpolation +} // namespace atlas diff --git a/src/atlas/interpolation/method/structured/Cubic3D.cc b/src/atlas/interpolation/method/structured/Cubic3D.cc new file mode 100644 index 000000000..d9ae2c2d3 --- /dev/null +++ b/src/atlas/interpolation/method/structured/Cubic3D.cc @@ -0,0 +1,32 @@ +/* + * (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. and Interpolation + */ + +#include "Cubic3D.h" + +#include "atlas/interpolation/method/MethodFactory.h" + +namespace atlas { +namespace interpolation { +namespace method { + +namespace { + +MethodBuilder __builder1( "structured-cubic3D" ); +MethodBuilder __builder2( "cubic3D" ); +MethodBuilder __builder3( "structured-tricubic" ); +MethodBuilder __builder4( "tricubic" ); + +} // namespace + +Cubic3D::Cubic3D( const Config& config ) : StructuredInterpolation3D( config ) {} + +} // namespace method +} // namespace interpolation +} // namespace atlas diff --git a/src/atlas/interpolation/method/structured/Cubic3D.h b/src/atlas/interpolation/method/structured/Cubic3D.h new file mode 100644 index 000000000..ca61769a2 --- /dev/null +++ b/src/atlas/interpolation/method/structured/Cubic3D.h @@ -0,0 +1,27 @@ +/* + * (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. and Interpolation + */ + +#pragma once + +#include "StructuredInterpolation3D.h" +#include "kernels/Cubic3DKernel.h" + +namespace atlas { +namespace interpolation { +namespace method { + +class Cubic3D : public StructuredInterpolation3D { +public: + Cubic3D( const Config& ); +}; + +} // namespace method +} // namespace interpolation +} // namespace atlas diff --git a/src/atlas/interpolation/method/structured/Linear2D.cc b/src/atlas/interpolation/method/structured/Linear2D.cc new file mode 100644 index 000000000..13628952f --- /dev/null +++ b/src/atlas/interpolation/method/structured/Linear2D.cc @@ -0,0 +1,32 @@ +/* + * (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. and Interpolation + */ + +#include "Linear2D.h" + +#include "atlas/interpolation/method/MethodFactory.h" + +namespace atlas { +namespace interpolation { +namespace method { + +namespace { + +MethodBuilder __builder1( "structured-linear2D" ); +MethodBuilder __builder2( "linear2D" ); +MethodBuilder __builder3( "structured-bilinear" ); +MethodBuilder __builder4( "bilinear" ); + +} // namespace + +Linear2D::Linear2D( const Config& config ) : StructuredInterpolation2D( config ) {} + +} // namespace method +} // namespace interpolation +} // namespace atlas diff --git a/src/atlas/interpolation/method/structured/Linear2D.h b/src/atlas/interpolation/method/structured/Linear2D.h new file mode 100644 index 000000000..056fee305 --- /dev/null +++ b/src/atlas/interpolation/method/structured/Linear2D.h @@ -0,0 +1,27 @@ +/* + * (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. and Interpolation + */ + +#pragma once + +#include "StructuredInterpolation2D.h" +#include "kernels/LinearHorizontalKernel.h" + +namespace atlas { +namespace interpolation { +namespace method { + +class Linear2D : public StructuredInterpolation2D { +public: + Linear2D( const Config& ); +}; + +} // namespace method +} // namespace interpolation +} // namespace atlas diff --git a/src/atlas/interpolation/method/structured/Linear3D.cc b/src/atlas/interpolation/method/structured/Linear3D.cc new file mode 100644 index 000000000..c462ba6c5 --- /dev/null +++ b/src/atlas/interpolation/method/structured/Linear3D.cc @@ -0,0 +1,32 @@ +/* + * (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. and Interpolation + */ + +#include "Linear3D.h" + +#include "atlas/interpolation/method/MethodFactory.h" + +namespace atlas { +namespace interpolation { +namespace method { + +namespace { + +MethodBuilder __builder1( "structured-linear3D" ); +MethodBuilder __builder2( "linear3D" ); +MethodBuilder __builder3( "structured-trilinear" ); +MethodBuilder __builder4( "trilinear" ); + +} // namespace + +Linear3D::Linear3D( const Config& config ) : StructuredInterpolation3D( config ) {} + +} // namespace method +} // namespace interpolation +} // namespace atlas diff --git a/src/atlas/interpolation/method/structured/Linear3D.h b/src/atlas/interpolation/method/structured/Linear3D.h new file mode 100644 index 000000000..65b58b886 --- /dev/null +++ b/src/atlas/interpolation/method/structured/Linear3D.h @@ -0,0 +1,27 @@ +/* + * (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. and Interpolation + */ + +#pragma once + +#include "StructuredInterpolation3D.h" +#include "kernels/Linear3DKernel.h" + +namespace atlas { +namespace interpolation { +namespace method { + +class Linear3D : public StructuredInterpolation3D { +public: + Linear3D( const Config& ); +}; + +} // namespace method +} // namespace interpolation +} // namespace atlas diff --git a/src/atlas/interpolation/method/structured/QuasiCubic2D.cc b/src/atlas/interpolation/method/structured/QuasiCubic2D.cc new file mode 100644 index 000000000..8d4f8c636 --- /dev/null +++ b/src/atlas/interpolation/method/structured/QuasiCubic2D.cc @@ -0,0 +1,32 @@ +/* + * (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. and Interpolation + */ + +#include "QuasiCubic2D.h" + +#include "atlas/interpolation/method/MethodFactory.h" + +namespace atlas { +namespace interpolation { +namespace method { + +namespace { + +MethodBuilder __builder1( "structured-quasicubic2D" ); +MethodBuilder __builder2( "quasicubic2D" ); +MethodBuilder __builder3( "structured-biquasicubic" ); +MethodBuilder __builder4( "biquasicubic" ); + +} // namespace + +QuasiCubic2D::QuasiCubic2D( const Config& config ) : StructuredInterpolation2D( config ) {} + +} // namespace method +} // namespace interpolation +} // namespace atlas diff --git a/src/atlas/interpolation/method/structured/QuasiCubic2D.h b/src/atlas/interpolation/method/structured/QuasiCubic2D.h new file mode 100644 index 000000000..8551fc9cb --- /dev/null +++ b/src/atlas/interpolation/method/structured/QuasiCubic2D.h @@ -0,0 +1,27 @@ +/* + * (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. and Interpolation + */ + +#pragma once + +#include "StructuredInterpolation2D.h" +#include "kernels/QuasiCubicHorizontalKernel.h" + +namespace atlas { +namespace interpolation { +namespace method { + +class QuasiCubic2D : public StructuredInterpolation2D { +public: + QuasiCubic2D( const Config& ); +}; + +} // namespace method +} // namespace interpolation +} // namespace atlas diff --git a/src/atlas/interpolation/method/structured/QuasiCubic3D.cc b/src/atlas/interpolation/method/structured/QuasiCubic3D.cc new file mode 100644 index 000000000..d448f02b5 --- /dev/null +++ b/src/atlas/interpolation/method/structured/QuasiCubic3D.cc @@ -0,0 +1,32 @@ +/* + * (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. and Interpolation + */ + +#include "QuasiCubic3D.h" + +#include "atlas/interpolation/method/MethodFactory.h" + +namespace atlas { +namespace interpolation { +namespace method { + +namespace { + +MethodBuilder __builder1( "structured-quasicubic3D" ); +MethodBuilder __builder2( "quasicubic3D" ); +MethodBuilder __builder3( "structured-triquasicubic" ); +MethodBuilder __builder4( "triquasicubic" ); + +} // namespace + +QuasiCubic3D::QuasiCubic3D( const Config& config ) : StructuredInterpolation3D( config ) {} + +} // namespace method +} // namespace interpolation +} // namespace atlas diff --git a/src/atlas/interpolation/method/structured/QuasiCubic3D.h b/src/atlas/interpolation/method/structured/QuasiCubic3D.h new file mode 100644 index 000000000..435d4ec05 --- /dev/null +++ b/src/atlas/interpolation/method/structured/QuasiCubic3D.h @@ -0,0 +1,27 @@ +/* + * (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. and Interpolation + */ + +#pragma once + +#include "StructuredInterpolation3D.h" +#include "kernels/QuasiCubic3DKernel.h" + +namespace atlas { +namespace interpolation { +namespace method { + +class QuasiCubic3D : public StructuredInterpolation3D { +public: + QuasiCubic3D( const Config& ); +}; + +} // namespace method +} // namespace interpolation +} // namespace atlas diff --git a/src/atlas/interpolation/method/structured/StructuredInterpolation2D.h b/src/atlas/interpolation/method/structured/StructuredInterpolation2D.h new file mode 100644 index 000000000..870990168 --- /dev/null +++ b/src/atlas/interpolation/method/structured/StructuredInterpolation2D.h @@ -0,0 +1,87 @@ +/* + * (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/interpolation/method/Method.h" + +#include + +#include "atlas/field/Field.h" +#include "atlas/field/FieldSet.h" +#include "atlas/functionspace/FunctionSpace.h" + +namespace atlas { +namespace interpolation { +namespace method { + +/** + * @class StructuredInterpolation2D + * + * Horizontal interpolation making use of Structure of grid + * Multiple (vertical) levels can be interpolated as well but + * assumes that input and output levels are the same. + */ + +template +class StructuredInterpolation2D : public Method { +public: + StructuredInterpolation2D( const Config& config ); + + virtual ~StructuredInterpolation2D() override {} + + virtual void setup( const Grid& source, const Grid& target ) override; + + virtual void setup( const FunctionSpace& source, const FunctionSpace& target ) override; + + virtual void setup( const FunctionSpace& source, const Field& target ) override; + + virtual void setup( const FunctionSpace& source, const FieldSet& target ) override; + + virtual void print( std::ostream& ) const override; + + virtual void execute( const Field& src, Field& tgt ) const override; + + virtual void execute( const FieldSet& src, FieldSet& tgt ) const override; + + +protected: + void setup( const FunctionSpace& source ); + + virtual const FunctionSpace& source() const override { return source_; } + + virtual const FunctionSpace& target() const override { return target_; } + +private: + template + void execute_impl( const Kernel& kernel, const FieldSet& src, FieldSet& tgt ) const; + + static double convert_units_multiplier( const Field& field ); + +protected: + Field target_lonlat_; + Field target_ghost_; + + FieldSet target_lonlat_fields_; + + FunctionSpace source_; + FunctionSpace target_; + + bool matrix_free_; + + std::unique_ptr kernel_; +}; + + +} // namespace method +} // namespace interpolation +} // namespace atlas + +#include "StructuredInterpolation2D.tcc" diff --git a/src/atlas/interpolation/method/structured/StructuredInterpolation2D.tcc b/src/atlas/interpolation/method/structured/StructuredInterpolation2D.tcc new file mode 100644 index 000000000..80470e1f8 --- /dev/null +++ b/src/atlas/interpolation/method/structured/StructuredInterpolation2D.tcc @@ -0,0 +1,295 @@ +/* + * (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. and Interpolation + */ + +#pragma once + +#include "StructuredInterpolation2D.h" + + +#include "atlas/array/ArrayView.h" +#include "atlas/field/Field.h" +#include "atlas/field/FieldSet.h" +#include "atlas/functionspace/NodeColumns.h" +#include "atlas/functionspace/PointCloud.h" +#include "atlas/functionspace/StructuredColumns.h" +#include "atlas/grid/Grid.h" +#include "atlas/grid/StructuredGrid.h" +#include "atlas/mesh/Nodes.h" +#include "atlas/parallel/mpi/mpi.h" +#include "atlas/parallel/omp/omp.h" +#include "atlas/runtime/Exception.h" +#include "atlas/runtime/Log.h" +#include "atlas/runtime/Trace.h" +#include "atlas/util/CoordinateEnums.h" +#include "atlas/util/NormaliseLongitude.h" +#include "atlas/util/Point.h" + +namespace atlas { +namespace interpolation { +namespace method { + +template +double StructuredInterpolation2D::convert_units_multiplier( const Field& field ) { + std::string units = field.metadata().getString( "units", "degrees" ); + if ( units == "degrees" ) { return 1.; } + if ( units == "radians" ) { return 180. / M_PI; } + ATLAS_NOTIMPLEMENTED; +} + +template +StructuredInterpolation2D::StructuredInterpolation2D( const Method::Config& config ) : + Method( config ), + matrix_free_{false} { + config.get( "matrix_free", matrix_free_ ); +} + + +template +void StructuredInterpolation2D::setup( const Grid& source, const Grid& target ) { + if ( mpi::comm().size() > 1 ) { ATLAS_NOTIMPLEMENTED; } + + + ATLAS_ASSERT( StructuredGrid( source ) ); + FunctionSpace source_fs = + functionspace::StructuredColumns( source, option::halo( std::max( kernel_->stencil_halo(), 1 ) ) ); + // guarantee "1" halo for pole treatment! + FunctionSpace target_fs = functionspace::PointCloud( target ); + + setup( source_fs, target_fs ); +} + + +template +void StructuredInterpolation2D::setup( const FunctionSpace& source, const FunctionSpace& target ) { + ATLAS_TRACE( "atlas::interpolation::method::StructuredInterpolation::setup()" ); + + source_ = source; + target_ = target; + + if ( functionspace::NodeColumns tgt = target ) { + target_lonlat_ = tgt.mesh().nodes().lonlat(); + target_ghost_ = tgt.mesh().nodes().ghost(); + } + else if ( functionspace::PointCloud tgt = target ) { + target_lonlat_ = tgt.lonlat(); + target_ghost_ = tgt.ghost(); + } + else { + ATLAS_NOTIMPLEMENTED; + } + + setup( source ); +} + +template +void StructuredInterpolation2D::setup( const FunctionSpace& source, const Field& target ) { + ATLAS_TRACE( "StructuredInterpolation<" + Kernel::className() + ">::setup(FunctionSpace source, Field target)" ); + + source_ = source; + + if ( target.functionspace() ) { target_ = target.functionspace(); } + + target_lonlat_ = target; + + setup( source ); +} + +template +void StructuredInterpolation2D::setup( const FunctionSpace& source, const FieldSet& target ) { + ATLAS_TRACE( "StructuredInterpolation<" + Kernel::className() + ">::setup(FunctionSpace source,FieldSet target)" ); + + source_ = source; + + ATLAS_ASSERT( target.size() >= 2 ); + if ( target[0].functionspace() ) { target_ = target[0].functionspace(); } + + target_lonlat_fields_ = target; + + setup( source ); +} + +template +void StructuredInterpolation2D::print( std::ostream& ) const { + ATLAS_NOTIMPLEMENTED; +} + + +template +void StructuredInterpolation2D::setup( const FunctionSpace& source ) { + kernel_.reset( new Kernel( source ) ); + + if ( functionspace::StructuredColumns( source ).halo() < 1 ) { + throw_Exception( "The source functionspace must have (halo >= 1) for pole treatment" ); + } + + if ( not matrix_free_ ) { + idx_t inp_npts = source.size(); + idx_t out_npts = target_lonlat_.shape( 0 ); + + auto ghost = array::make_view( target_ghost_ ); + auto lonlat = array::make_view( target_lonlat_ ); + + double convert_units = convert_units_multiplier( target_lonlat_ ); + + auto triplets = kernel_->allocate_triplets( out_npts ); + + constexpr NormaliseLongitude normalise; + //auto normalise = []( double x ) { return x; }; + ATLAS_TRACE_SCOPE( "Precomputing interpolation matrix" ) { + atlas_omp_parallel { + typename Kernel::WorkSpace workspace; + atlas_omp_for( idx_t n = 0; n < out_npts; ++n ) { + if ( not ghost( n ) ) { + PointLonLat p{normalise( lonlat( n, LON ) ) * convert_units, lonlat( n, LAT ) * convert_units}; + kernel_->insert_triplets( n, p, triplets, workspace ); + } + } + } + // fill sparse matrix and return + Matrix A( out_npts, inp_npts, triplets ); + matrix_.swap( A ); + } + } +} + + +template +void StructuredInterpolation2D::execute( const Field& src_field, Field& tgt_field ) const { + FieldSet tgt( tgt_field ); + execute( FieldSet( src_field ), tgt ); +} + + +template +void StructuredInterpolation2D::execute( const FieldSet& src_fields, FieldSet& tgt_fields ) const { + if ( not matrix_free_ ) { + Method::execute( src_fields, tgt_fields ); + return; + } + + ATLAS_TRACE( "StructuredInterpolation<" + Kernel::className() + ">::execute()" ); + + const idx_t N = src_fields.size(); + ATLAS_ASSERT( N == tgt_fields.size() ); + + if ( N == 0 ) return; + + haloExchange( src_fields ); + + array::DataType datatype = src_fields[0].datatype(); + int rank = src_fields[0].rank(); + + for ( idx_t i = 0; i < N; ++i ) { + ATLAS_ASSERT( src_fields[i].datatype() == datatype ); + ATLAS_ASSERT( src_fields[i].rank() == rank ); + ATLAS_ASSERT( tgt_fields[i].datatype() == datatype ); + ATLAS_ASSERT( tgt_fields[i].rank() == rank ); + } + + if ( datatype.kind() == array::DataType::KIND_REAL64 && rank == 1 ) { + execute_impl( *kernel_, src_fields, tgt_fields ); + } + if ( datatype.kind() == array::DataType::KIND_REAL32 && rank == 1 ) { + execute_impl( *kernel_, src_fields, tgt_fields ); + } + if ( datatype.kind() == array::DataType::KIND_REAL64 && rank == 2 ) { + execute_impl( *kernel_, src_fields, tgt_fields ); + } + if ( datatype.kind() == array::DataType::KIND_REAL32 && rank == 2 ) { + execute_impl( *kernel_, src_fields, tgt_fields ); + } + + tgt_fields.set_dirty(); +} + + +template +template +void StructuredInterpolation2D::execute_impl( const Kernel& kernel, const FieldSet& src_fields, + FieldSet& tgt_fields ) const { + const idx_t N = src_fields.size(); + + std::vector > src_view; + std::vector > tgt_view; + src_view.reserve( N ); + tgt_view.reserve( N ); + + for ( idx_t i = 0; i < N; ++i ) { + src_view.emplace_back( array::make_view( src_fields[i] ) ); + tgt_view.emplace_back( array::make_view( tgt_fields[i] ) ); + } + if ( target_lonlat_ ) { + double convert_units = convert_units_multiplier( target_lonlat_ ); + + if ( target_ghost_ ) { + idx_t out_npts = target_lonlat_.shape( 0 ); + const auto ghost = array::make_view( target_ghost_ ); + const auto lonlat = array::make_view( target_lonlat_ ); + + atlas_omp_parallel { + typename Kernel::Stencil stencil; + typename Kernel::Weights weights; + atlas_omp_for( idx_t n = 0; n < out_npts; ++n ) { + if ( not ghost( n ) ) { + PointLonLat p{lonlat( n, LON ) * convert_units, lonlat( n, LAT ) * convert_units}; + kernel.compute_stencil( p.lon(), p.lat(), stencil ); + kernel.compute_weights( p.lon(), p.lat(), stencil, weights ); + for ( idx_t i = 0; i < N; ++i ) { + kernel.interpolate( stencil, weights, src_view[i], tgt_view[i], n ); + } + } + } + } + } + else { + idx_t out_npts = target_lonlat_.shape( 0 ); + const auto lonlat = array::make_view( target_lonlat_ ); + + atlas_omp_parallel { + typename Kernel::Stencil stencil; + typename Kernel::Weights weights; + atlas_omp_for( idx_t n = 0; n < out_npts; ++n ) { + PointLonLat p{lonlat( n, LON ) * convert_units, lonlat( n, LAT ) * convert_units}; + kernel.compute_stencil( p.lon(), p.lat(), stencil ); + kernel.compute_weights( p.lon(), p.lat(), stencil, weights ); + for ( idx_t i = 0; i < N; ++i ) { + kernel.interpolate( stencil, weights, src_view[i], tgt_view[i], n ); + } + } + } + } + } + else if ( not target_lonlat_fields_.empty() ) { + idx_t out_npts = target_lonlat_fields_[0].shape( 0 ); + const auto lon = array::make_view( target_lonlat_fields_[LON] ); + const auto lat = array::make_view( target_lonlat_fields_[LAT] ); + double convert_units = convert_units_multiplier( target_lonlat_fields_[LON] ); + + atlas_omp_parallel { + typename Kernel::Stencil stencil; + typename Kernel::Weights weights; + atlas_omp_for( idx_t n = 0; n < out_npts; ++n ) { + PointLonLat p{lon( n ) * convert_units, lat( n ) * convert_units}; + kernel.compute_stencil( p.lon(), p.lat(), stencil ); + kernel.compute_weights( p.lon(), p.lat(), stencil, weights ); + for ( idx_t i = 0; i < N; ++i ) { + kernel.interpolate( stencil, weights, src_view[i], tgt_view[i], n ); + } + } + } + } + else { + ATLAS_NOTIMPLEMENTED; + } +} + +} // namespace method +} // namespace interpolation +} // namespace atlas diff --git a/src/atlas/interpolation/method/structured/StructuredInterpolation3D.h b/src/atlas/interpolation/method/structured/StructuredInterpolation3D.h new file mode 100644 index 000000000..374b1b2ed --- /dev/null +++ b/src/atlas/interpolation/method/structured/StructuredInterpolation3D.h @@ -0,0 +1,90 @@ +/* + * (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/interpolation/method/Method.h" + +#include + +#include "atlas/field/Field.h" +#include "atlas/field/FieldSet.h" +#include "atlas/functionspace/FunctionSpace.h" +#include "atlas/grid/Vertical.h" + +namespace atlas { +namespace interpolation { +namespace method { + +/** + * @class StructuredInterpolation3D + * + * Three-dimensional interpolation making use of Structure of grid. + */ + +template +class StructuredInterpolation3D : public Method { +public: + StructuredInterpolation3D( const Config& config ); + + virtual ~StructuredInterpolation3D() override {} + + virtual void setup( const Grid& source, const Grid& target ) override; + + virtual void setup( const FunctionSpace& source, const FunctionSpace& target ) override; + + virtual void setup( const FunctionSpace& source, const Field& target ) override; + + virtual void setup( const FunctionSpace& source, const FieldSet& target ) override; + + virtual void print( std::ostream& ) const override; + + virtual void execute( const Field& src, Field& tgt ) const override; + + virtual void execute( const FieldSet& src, FieldSet& tgt ) const override; + + +protected: + void setup( const FunctionSpace& source ); + + virtual const FunctionSpace& source() const override { return source_; } + + virtual const FunctionSpace& target() const override { return target_; } + +private: + template + void execute_impl( const Kernel& kernel, const FieldSet& src, FieldSet& tgt ) const; + + static double convert_units_multiplier( const Field& field ); + +protected: + Field target_ghost_; + Field target_lonlat_; + Field target_vertical_; + + Field target_3d_; + + FieldSet target_xyz_; + + FunctionSpace source_; + FunctionSpace target_; + + bool matrix_free_; + bool limiter_; + + std::unique_ptr kernel_; +}; + + +} // namespace method +} // namespace interpolation +} // namespace atlas + +#include "StructuredInterpolation3D.tcc" diff --git a/src/atlas/interpolation/method/structured/StructuredInterpolation3D.tcc b/src/atlas/interpolation/method/structured/StructuredInterpolation3D.tcc new file mode 100644 index 000000000..28089806b --- /dev/null +++ b/src/atlas/interpolation/method/structured/StructuredInterpolation3D.tcc @@ -0,0 +1,331 @@ +/* + * (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. and Interpolation + */ + +#pragma once + +#include "StructuredInterpolation3D.h" + +#include "atlas/array/ArrayView.h" +#include "atlas/field/Field.h" +#include "atlas/field/FieldSet.h" +#include "atlas/functionspace/NodeColumns.h" +#include "atlas/functionspace/PointCloud.h" +#include "atlas/functionspace/StructuredColumns.h" +#include "atlas/grid/StructuredGrid.h" +#include "atlas/mesh/Nodes.h" +#include "atlas/parallel/mpi/mpi.h" +#include "atlas/parallel/omp/omp.h" +#include "atlas/runtime/Exception.h" +#include "atlas/runtime/Log.h" +#include "atlas/runtime/Trace.h" +#include "atlas/util/CoordinateEnums.h" +#include "atlas/util/Point.h" + +namespace atlas { +namespace interpolation { +namespace method { + +template +double StructuredInterpolation3D::convert_units_multiplier( const Field& field ) { + std::string units = field.metadata().getString( "units", "degrees" ); + if ( units == "degrees" ) { return 1.; } + if ( units == "radians" ) { return 180. / M_PI; } + ATLAS_NOTIMPLEMENTED; +} + +template +StructuredInterpolation3D::StructuredInterpolation3D( const Method::Config& config ) : + Method( config ), + matrix_free_{false}, + limiter_{false} { + config.get( "matrix_free", matrix_free_ ); + config.get( "limiter", limiter_ ); + + if ( not matrix_free_ ) { throw_NotImplemented( "Matrix-free StructuredInterpolation3D not implemented", Here() ); } +} + + +template +void StructuredInterpolation3D::setup( const Grid& source, const Grid& target ) { + if ( mpi::comm().size() > 1 ) { ATLAS_NOTIMPLEMENTED; } + + + ATLAS_ASSERT( StructuredGrid( source ) ); + FunctionSpace source_fs = functionspace::StructuredColumns( source, option::halo( kernel_->stencil_halo() ) ); + FunctionSpace target_fs = functionspace::PointCloud( target ); + + setup( source_fs, target_fs ); +} + + +template +void StructuredInterpolation3D::setup( const FunctionSpace& source, const FunctionSpace& target ) { + ATLAS_TRACE( "StructuredInterpolation<" + Kernel::className() + ">::setup()" ); + + source_ = source; + target_ = target; + + if ( functionspace::PointCloud tgt = target ) { + target_lonlat_ = tgt.lonlat(); + target_vertical_ = tgt.vertical(); + target_ghost_ = tgt.ghost(); + } + else { + ATLAS_NOTIMPLEMENTED; + } + + setup( source ); +} + +template +void StructuredInterpolation3D::setup( const FunctionSpace& source, const Field& target ) { + ATLAS_TRACE( "StructuredInterpolation<" + Kernel::className() + ">::setup(FunctionSpace source, Field target)" ); + + source_ = source; + + if ( target.functionspace() ) { target_ = target.functionspace(); } + ATLAS_ASSERT( target.levels() ); + + target_3d_ = target; + + setup( source ); +} + +template +void StructuredInterpolation3D::setup( const FunctionSpace& source, const FieldSet& target ) { + ATLAS_TRACE( "StructuredInterpolation<" + Kernel::className() + ">::setup(FunctionSpace source,FieldSet target)" ); + + source_ = source; + + ATLAS_ASSERT( target.size() >= 3 ); + if ( target[0].functionspace() ) { target_ = target[0].functionspace(); } + ATLAS_ASSERT( target[0].levels() ); + + target_xyz_ = target; + + setup( source ); +} + +template +void StructuredInterpolation3D::print( std::ostream& ) const { + ATLAS_NOTIMPLEMENTED; +} + + +template +void StructuredInterpolation3D::setup( const FunctionSpace& source ) { + kernel_.reset( new Kernel( source, util::Config( "limiter", limiter_ ) ) ); +} + + +template +void StructuredInterpolation3D::execute( const Field& src_field, Field& tgt_field ) const { + FieldSet tgt( tgt_field ); + execute( FieldSet( src_field ), tgt ); +} + + +template +void StructuredInterpolation3D::execute( const FieldSet& src_fields, FieldSet& tgt_fields ) const { + if ( not matrix_free_ ) { + Method::execute( src_fields, tgt_fields ); + return; + } + + ATLAS_TRACE( "StructuredInterpolation<" + Kernel::className() + ">::execute()" ); + + const idx_t N = src_fields.size(); + ATLAS_ASSERT( N == tgt_fields.size() ); + + if ( N == 0 ) return; + + haloExchange( src_fields ); + + array::DataType datatype = src_fields[0].datatype(); + int rank = src_fields[0].rank(); + + ATLAS_ASSERT( rank > 1 ); + + for ( idx_t i = 0; i < N; ++i ) { + ATLAS_ASSERT( src_fields[i].datatype() == datatype ); + ATLAS_ASSERT( src_fields[i].rank() == rank ); + ATLAS_ASSERT( tgt_fields[i].datatype() == datatype ); + } + + if ( datatype.kind() == array::DataType::KIND_REAL64 && rank == 2 ) { + execute_impl( *kernel_, src_fields, tgt_fields ); + } + if ( datatype.kind() == array::DataType::KIND_REAL32 && rank == 2 ) { + execute_impl( *kernel_, src_fields, tgt_fields ); + } + if ( datatype.kind() == array::DataType::KIND_REAL64 && rank == 3 ) { + execute_impl( *kernel_, src_fields, tgt_fields ); + } + if ( datatype.kind() == array::DataType::KIND_REAL32 && rank == 3 ) { + execute_impl( *kernel_, src_fields, tgt_fields ); + } + + tgt_fields.set_dirty(); +} + + +template +template +void StructuredInterpolation3D::execute_impl( const Kernel& kernel, const FieldSet& src_fields, + FieldSet& tgt_fields ) const { + const idx_t N = src_fields.size(); + + auto make_src_view = [&]( const FieldSet& src_fields ) { + std::vector > src_view; + src_view.reserve( N ); + for ( idx_t i = 0; i < N; ++i ) { + src_view.emplace_back( array::make_view( src_fields[i] ) ); + } + return src_view; + }; + + // Assertions + ATLAS_ASSERT( tgt_fields.size() == src_fields.size() ); + idx_t tgt_rank = -1; + for ( auto& f : tgt_fields ) { + if ( tgt_rank == -1 ) tgt_rank = f.rank(); + if ( f.rank() != tgt_rank ) { throw_Exception( "target fields don't all have the same rank!", Here() ); } + } + + if ( functionspace::PointCloud( target() ) && tgt_rank == 1 ) { + const idx_t out_npts = target_lonlat_.shape( 0 ); + + const auto ghost = array::make_view( target_ghost_ ); + const auto lonlat = array::make_view( target_lonlat_ ); + const auto vertical = array::make_view( target_vertical_ ); + + const auto src_view = make_src_view( src_fields ); + + constexpr int TargetRank = 1; + std::vector > tgt_view; + tgt_view.reserve( N ); + for ( idx_t i = 0; i < N; ++i ) { + tgt_view.emplace_back( array::make_view( tgt_fields[i] ) ); + } + + const double convert_units = convert_units_multiplier( target_lonlat_ ); + atlas_omp_parallel { + typename Kernel::Stencil stencil; + typename Kernel::Weights weights; + atlas_omp_for( idx_t n = 0; n < out_npts; ++n ) { + if ( not ghost( n ) ) { + double x = lonlat( n, LON ) * convert_units; + double y = lonlat( n, LAT ) * convert_units; + double z = vertical( n ); + kernel.compute_stencil( x, y, z, stencil ); + kernel.compute_weights( x, y, z, stencil, weights ); + for ( idx_t i = 0; i < N; ++i ) { + kernel.interpolate( stencil, weights, src_view[i], tgt_view[i], n ); + } + } + } + } + } + else if ( target_3d_ && tgt_rank == Rank ) { + const idx_t out_npts = target_3d_.shape( 0 ); + const idx_t out_nlev = target_3d_.shape( 1 ); + + const auto coords = array::make_view( target_3d_ ); + const auto src_view = make_src_view( src_fields ); + + constexpr int TargetRank = Rank; + std::vector > tgt_view; + tgt_view.reserve( N ); + + for ( idx_t i = 0; i < N; ++i ) { + tgt_view.emplace_back( array::make_view( tgt_fields[i] ) ); + + if ( Rank == 3 && + ( src_fields[i].stride( Rank - 1 ) != 1 || tgt_fields[i].stride( TargetRank - 1 ) != 1 ) ) { + throw_Exception( + "Something will go seriously wrong if we continue from here as " + "the implementation assumes stride=1 for fastest moving index (variables).", + Here() ); + } + } + + const double convert_units = convert_units_multiplier( target_3d_ ); + + atlas_omp_parallel { + typename Kernel::Stencil stencil; + typename Kernel::Weights weights; + atlas_omp_for( idx_t n = 0; n < out_npts; ++n ) { + for ( idx_t k = 0; k < out_nlev; ++k ) { + double x = coords( n, k, LON ) * convert_units; + double y = coords( n, k, LAT ) * convert_units; + double z = coords( n, k, ZZ ); + + kernel.compute_stencil( x, y, z, stencil ); + kernel.compute_weights( x, y, z, stencil, weights ); + for ( idx_t i = 0; i < N; ++i ) { + kernel.interpolate( stencil, weights, src_view[i], tgt_view[i], n, k ); + } + } + } + } + } + else if ( not target_xyz_.empty() && tgt_rank == Rank ) { + const idx_t out_npts = target_xyz_[0].shape( 0 ); + const idx_t out_nlev = target_xyz_[0].shape( 1 ); + + const auto xcoords = array::make_view( target_xyz_[LON] ); + const auto ycoords = array::make_view( target_xyz_[LAT] ); + const auto zcoords = array::make_view( target_xyz_[ZZ] ); + const auto src_view = make_src_view( src_fields ); + + constexpr int TargetRank = Rank; + std::vector > tgt_view; + tgt_view.reserve( N ); + + for ( idx_t i = 0; i < N; ++i ) { + tgt_view.emplace_back( array::make_view( tgt_fields[i] ) ); + + if ( Rank == 3 && + ( src_fields[i].stride( Rank - 1 ) != 1 || tgt_fields[i].stride( TargetRank - 1 ) != 1 ) ) { + throw_Exception( + "Something will go seriously wrong if we continue from here as " + "the implementation assumes stride=1 for fastest moving index (variables).", + Here() ); + } + } + + const double convert_units = convert_units_multiplier( target_xyz_[LON] ); + + atlas_omp_parallel { + typename Kernel::Stencil stencil; + typename Kernel::Weights weights; + atlas_omp_for( idx_t n = 0; n < out_npts; ++n ) { + for ( idx_t k = 0; k < out_nlev; ++k ) { + const double x = xcoords( n, k ) * convert_units; + const double y = ycoords( n, k ) * convert_units; + const double z = zcoords( n, k ); + kernel.compute_stencil( x, y, z, stencil ); + kernel.compute_weights( x, y, z, stencil, weights ); + for ( idx_t i = 0; i < N; ++i ) { + kernel.interpolate( stencil, weights, src_view[i], tgt_view[i], n, k ); + } + } + } + } + } + + else { + ATLAS_NOTIMPLEMENTED; + } +} + +} // namespace method +} // namespace interpolation +} // namespace atlas diff --git a/src/atlas/interpolation/method/structured/kernels/Cubic3DKernel.h b/src/atlas/interpolation/method/structured/kernels/Cubic3DKernel.h new file mode 100644 index 000000000..bb60058ad --- /dev/null +++ b/src/atlas/interpolation/method/structured/kernels/Cubic3DKernel.h @@ -0,0 +1,321 @@ +/* + * (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. and Interpolation + */ + +#pragma once + +#include +#include + +#include "atlas/array/ArrayView.h" +#include "atlas/functionspace/StructuredColumns.h" +#include "atlas/grid/Stencil.h" +#include "atlas/grid/StencilComputer.h" +#include "atlas/runtime/Exception.h" +#include "atlas/util/CoordinateEnums.h" +#include "atlas/util/Point.h" + +#include "CubicHorizontalKernel.h" +#include "CubicVerticalKernel.h" + +namespace atlas { +namespace interpolation { +namespace method { + +class Cubic3DKernel { +public: + Cubic3DKernel( const functionspace::StructuredColumns& fs, const util::Config& config = util::NoConfig() ) { + src_ = fs; + ATLAS_ASSERT( src_ ); + ATLAS_ASSERT( src_.halo() >= 2 ); + ATLAS_ASSERT( src_.vertical().size() ); + horizontal_interpolation_ = CubicHorizontalKernel( src_, config ); + vertical_interpolation_ = CubicVerticalKernel( fs.vertical(), config ); + limiter_ = config.getBool( "limiter", false ); + } + +private: + functionspace::StructuredColumns src_; + CubicHorizontalKernel horizontal_interpolation_; + CubicVerticalKernel vertical_interpolation_; + bool limiter_{false}; + +public: + static std::string className() { return "Cubic3DKernel"; } + static constexpr idx_t stencil_width() { return 4; } + static constexpr idx_t stencil_size() { return stencil_width() * stencil_width() * stencil_width(); } + static constexpr idx_t stencil_halo() { + return static_cast( static_cast( stencil_width() ) / 2. + 0.5 ); + } + +public: + using Stencil = Stencil3D<4>; + struct Weights { + std::array, 4> weights_i; + std::array weights_j; + std::array weights_k; + }; + +public: + struct WorkSpace { + Stencil stencil; + Weights weights; + }; + + template + void compute_stencil( const double x, const double y, const double z, stencil_t& stencil ) const { + horizontal_interpolation_.compute_stencil( x, y, stencil ); + vertical_interpolation_.compute_stencil( z, stencil ); + } + + template + void compute_weights( const double x, const double y, const double z, weights_t& weights ) const { + Stencil stencil; + compute_stencil( x, y, z, stencil ); + compute_weights( x, y, z, stencil, weights ); + } + + + template + void compute_weights( const double x, const double y, const double z, const stencil_t& stencil, + weights_t& weights ) const { + horizontal_interpolation_.compute_weights( x, y, stencil, weights ); + vertical_interpolation_.compute_weights( z, stencil, weights ); + } + + template + typename std::enable_if<( array_t::RANK == 2 ), typename array_t::value_type>::type interpolate( + const stencil_t& stencil, const weights_t& weights, const array_t& input ) const { + using Value = typename array_t::value_type; + + std::array, stencil_width()> index; + const auto& wj = weights.weights_j; + const auto& wk = weights.weights_k; + + Value output = 0.; + for ( idx_t j = 0; j < stencil_width(); ++j ) { + const auto& wi = weights.weights_i[j]; + for ( idx_t i = 0; i < stencil_width(); ++i ) { + idx_t n = src_.index( stencil.i( i, j ), stencil.j( j ) ); + Value wij = wi[i] * wj[j]; + for ( idx_t k = 0; k < stencil_width(); ++k ) { + Value w = wij * wk[k]; + output += w * input( n, stencil.k( k ) ); + } + index[j][i] = n; + } + } + + if ( limiter_ ) { limit_scalar( output, index, stencil, input ); } + return output; + } + + template + typename std::enable_if<( array_t::RANK == 2 ), void>::type limit_scalar( + typename array_t::value_type& output, const std::array, 4>& index, + const stencil_t& stencil, const array_t& input ) const { + using Scalar = typename array_t::value_type; + // Limit output to max/min of values in stencil marked by '*' + // x x x x + // x *-----* x + // / P | + // x *------ * x + // x x x x + idx_t k = stencil.k_interval(); + idx_t k1, k2; + if ( k < 0 ) { k1 = k2 = 0; } + else if ( k > 2 ) { + k1 = k2 = 3; + } + else { + k1 = k; + k2 = k + 1; + } + + Scalar maxval = std::numeric_limits::lowest(); + Scalar minval = std::numeric_limits::max(); + for ( idx_t j = 1; j < 3; ++j ) { + for ( idx_t i = 1; i < 3; ++i ) { + idx_t n = index[j][i]; + + Scalar f1 = input( n, stencil.k( k1 ) ); + Scalar f2 = input( n, stencil.k( k2 ) ); + + maxval = std::max( maxval, f1 ); + maxval = std::max( maxval, f2 ); + minval = std::min( minval, f1 ); + minval = std::min( minval, f2 ); + } + } + if ( output < minval ) { output = minval; } + else if ( output > maxval ) { + output = maxval; + } + } + + template + struct OutputView1D { + template + Value& operator()( Int v ) { + return data_[v]; + } + template + Value& operator[]( Int v ) { + return data_[v]; + } + static constexpr int RANK{1}; + OutputView1D( Value* data ) : data_( data ) {} + using value_type = Value; + + Value* data_; + }; + + template + OutputView1D make_outputview( Value* data ) const { + return OutputView1D( data ); + } + + template + typename std::enable_if<( InputArray::RANK == 3 ), void>::type interpolate_vars( const stencil_t& stencil, + const weights_t& weights, + const InputArray& input, + OutputArray& output, + const idx_t nvar ) const { + using Value = typename InputArray::value_type; + + std::array, stencil_width()> index; + const auto& wj = weights.weights_j; + const auto& wk = weights.weights_k; + + const Value* _input_; + + for ( idx_t v = 0; v < nvar; ++v ) { + output[v] = 0.; + } + + for ( idx_t j = 0; j < stencil_width(); ++j ) { + const auto& wi = weights.weights_i[j]; + for ( idx_t i = 0; i < stencil_width(); ++i ) { + const idx_t n = src_.index( stencil.i( i, j ), stencil.j( j ) ); + const Value wij = wi[i] * wj[j]; + for ( idx_t k = 0; k < stencil_width(); ++k ) { + const Value w = wij * wk[k]; + const idx_t kk = stencil.k( k ); + _input_ = &( input( n, kk, 0 ) ); // Assumption that input.stride(2) == 1 + for ( idx_t v = 0; v < nvar; ++v ) { + output[v] += w * _input_[v]; + } + } + index[j][i] = n; + } + } + + if ( limiter_ ) { limit_vars( index, stencil, input, output, nvar ); } + } + + template + typename std::enable_if<( InputArray::RANK == 3 ), void>::type limit_vars( + const std::array, 4>& index, const stencil_t& stencil, const InputArray& input, + OutputArray& output, const idx_t nvar ) const { + // Limit output to max/min of values in stencil marked by '*' + // x x x x + // x *-----* x + // / P | + // x *------ * x + // x x x x + + using Value = typename InputArray::value_type; + + const idx_t k = stencil.k_interval(); + idx_t k1, k2; + if ( k < 0 ) { k1 = k2 = stencil.k( 0 ); } + else if ( k > 2 ) { + k1 = k2 = stencil.k( 3 ); + } + else { + k1 = stencil.k( k ); + k2 = k1 + 1; + } + + for ( idx_t v = 0; v < nvar; ++v ) { + Value limited = output[v]; + Value maxval = std::numeric_limits::lowest(); + Value minval = std::numeric_limits::max(); + for ( idx_t j = 1; j < 3; ++j ) { + for ( idx_t i = 1; i < 3; ++i ) { + idx_t n = index[j][i]; + + Value f1 = input( n, k1, v ); + Value f2 = input( n, k2, v ); + + maxval = std::max( maxval, f1 ); + maxval = std::max( maxval, f2 ); + minval = std::min( minval, f1 ); + minval = std::min( minval, f2 ); + } + } + if ( limited < minval ) { limited = minval; } + else if ( limited > maxval ) { + limited = maxval; + } + output[v] = limited; + } + } + + + template + typename std::enable_if<( InputArray::RANK == 2 && OutputArray::RANK == 1 ), void>::type interpolate( + const stencil_t& stencil, const weights_t& weights, const InputArray& input, OutputArray& output, + idx_t r ) const { + output( r ) = interpolate( stencil, weights, input ); + } + + template + typename std::enable_if<( InputArray::RANK == 2 && OutputArray::RANK == 2 ), void>::type interpolate( + const stencil_t& stencil, const weights_t& weights, const InputArray& input, OutputArray& output, idx_t r, + idx_t k ) const { + output( r, k ) = interpolate( stencil, weights, input ); + } + + template + typename std::enable_if<( InputArray::RANK == 3 && OutputArray::RANK == 3 ), void>::type interpolate( + const stencil_t& stencil, const weights_t& weights, const InputArray& input, OutputArray& output, idx_t r, + idx_t k ) const { + auto output_vars = make_outputview( &output( r, k, 0 ) ); + interpolate_vars( stencil, weights, input, output_vars, output.shape( 2 ) ); + } + + template + typename std::enable_if<( InputArray::RANK == 2 && OutputArray::RANK == 3 ), void>::type interpolate( + const stencil_t&, const weights_t&, const InputArray&, OutputArray&, idx_t /*r*/, idx_t /*k*/ ) const { + ATLAS_NOTIMPLEMENTED; + } + + template + typename std::enable_if<( InputArray::RANK == 3 && OutputArray::RANK == 1 ), void>::type interpolate( + const stencil_t&, const weights_t&, const InputArray&, OutputArray&, idx_t /*r*/ ) const { + ATLAS_NOTIMPLEMENTED; + } + + template + typename std::enable_if<( InputArray::RANK == 3 && OutputArray::RANK == 1 ), void>::type interpolate( + const stencil_t&, const weights_t&, const InputArray&, OutputArray&, idx_t /*r*/, idx_t /*k*/ ) const { + ATLAS_NOTIMPLEMENTED; + } + + template + typename std::enable_if<( InputArray::RANK == 3 && OutputArray::RANK == 2 ), void>::type interpolate( + const stencil_t&, const weights_t&, const InputArray&, OutputArray&, idx_t /*r*/, idx_t /*k*/ ) const { + ATLAS_NOTIMPLEMENTED; + } +}; + +} // namespace method +} // namespace interpolation +} // namespace atlas diff --git a/src/atlas/interpolation/method/structured/kernels/CubicHorizontalKernel.h b/src/atlas/interpolation/method/structured/kernels/CubicHorizontalKernel.h new file mode 100644 index 000000000..270508517 --- /dev/null +++ b/src/atlas/interpolation/method/structured/kernels/CubicHorizontalKernel.h @@ -0,0 +1,332 @@ +/* + * (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. and Interpolation + */ + +#pragma once + +#include +#include + +#include "eckit/linalg/Triplet.h" + +#include "atlas/array/ArrayView.h" +#include "atlas/functionspace/StructuredColumns.h" +#include "atlas/grid/Stencil.h" +#include "atlas/grid/StencilComputer.h" +#include "atlas/runtime/Exception.h" +#include "atlas/util/CoordinateEnums.h" +#include "atlas/util/NormaliseLongitude.h" +#include "atlas/util/Point.h" + +namespace atlas { +namespace interpolation { +namespace method { + +class CubicHorizontalKernel { + using Triplet = eckit::linalg::Triplet; + using Triplets = std::vector; + +public: + CubicHorizontalKernel() = default; + + CubicHorizontalKernel( const functionspace::StructuredColumns& fs, const util::Config& config = util::NoConfig() ) { + src_ = fs; + ATLAS_ASSERT( src_ ); + ATLAS_ASSERT( src_.halo() >= 2 ); + compute_horizontal_stencil_ = ComputeHorizontalStencil( src_.grid(), stencil_width() ); + limiter_ = config.getBool( "limiter", false ); + } + +protected: + functionspace::StructuredColumns src_; + ComputeHorizontalStencil compute_horizontal_stencil_; + bool limiter_{false}; + +public: + static std::string className() { return "CubicHorizontalKernel"; } + static constexpr idx_t stencil_width() { return 4; } + static constexpr idx_t stencil_size() { return stencil_width() * stencil_width(); } + static constexpr idx_t stencil_halo() { + return static_cast( static_cast( stencil_width() ) / 2. + 0.5 ); + } + +public: + using Stencil = HorizontalStencil<4>; + struct Weights { + std::array, 4> weights_i; + std::array weights_j; + }; + +public: + struct WorkSpace { + Stencil stencil; + Weights weights; + }; + + template + void compute_stencil( const double x, const double y, stencil_t& stencil ) const { + compute_horizontal_stencil_( x, y, stencil ); + } + + template + void compute_weights( const double x, const double y, weights_t& weights ) const { + Stencil stencil; + compute_stencil( x, y, stencil ); + compute_weights( x, y, stencil, weights ); + } + + + template + void compute_weights( const double x, const double y, const stencil_t& stencil, weights_t& weights ) const { + PointXY P1, P2; + std::array yvec; + for ( idx_t j = 0; j < stencil_width(); ++j ) { + auto& weights_i = weights.weights_i[j]; + src_.compute_xy( stencil.i( 1, j ), stencil.j( j ), P1 ); + src_.compute_xy( stencil.i( 2, j ), stencil.j( j ), P2 ); + const double alpha = ( P2.x() - x ) / ( P2.x() - P1.x() ); + const double alpha_sqr = alpha * alpha; + const double two_minus_alpha = 2. - alpha; + const double one_minus_alpha_sqr = 1. - alpha_sqr; + weights_i[0] = -alpha * one_minus_alpha_sqr / 6.; + weights_i[1] = 0.5 * alpha * ( 1. + alpha ) * two_minus_alpha; + weights_i[2] = 0.5 * one_minus_alpha_sqr * two_minus_alpha; + weights_i[3] = 1. - weights_i[0] - weights_i[1] - weights_i[2]; + yvec[j] = P1.y(); + } + const double dl12 = yvec[0] - yvec[1]; + const double dl13 = yvec[0] - yvec[2]; + const double dl14 = yvec[0] - yvec[3]; + const double dl23 = yvec[1] - yvec[2]; + const double dl24 = yvec[1] - yvec[3]; + const double dl34 = yvec[2] - yvec[3]; + const double dcl1 = dl12 * dl13 * dl14; + const double dcl2 = -dl12 * dl23 * dl24; + const double dcl3 = dl13 * dl23 * dl34; + + const double dl1 = y - yvec[0]; + const double dl2 = y - yvec[1]; + const double dl3 = y - yvec[2]; + const double dl4 = y - yvec[3]; + + auto& weights_j = weights.weights_j; + weights_j[0] = ( dl2 * dl3 * dl4 ) / dcl1; + weights_j[1] = ( dl1 * dl3 * dl4 ) / dcl2; + weights_j[2] = ( dl1 * dl2 * dl4 ) / dcl3; + weights_j[3] = 1. - weights_j[0] - weights_j[1] - weights_j[2]; + } + + template + typename array_t::value_type interpolate( const stencil_t& stencil, const weights_t& weights, + const array_t& input ) const { + using Value = typename array_t::value_type; + + std::array, stencil_width()> index; + const auto& weights_j = weights.weights_j; + Value output = 0.; + for ( idx_t j = 0; j < stencil_width(); ++j ) { + const auto& weights_i = weights.weights_i[j]; + for ( idx_t i = 0; i < stencil_width(); ++i ) { + idx_t n = src_.index( stencil.i( i, j ), stencil.j( j ) ); + Value w = weights_i[i] * weights_j[j]; + output += w * input[n]; + index[j][i] = n; + } + } + + if ( limiter_ ) { limit( output, index, input ); } + return output; + } + + template + void limit( typename array_t::value_type& output, const std::array, 4>& index, + const array_t& input ) const { + using Scalar = typename array_t::value_type; + // Limit output to max/min of values in stencil marked by '*' + // x x x x + // x *-----* x + // / P | + // x *------ * x + // x x x x + Scalar maxval = std::numeric_limits::lowest(); + Scalar minval = std::numeric_limits::max(); + for ( idx_t j = 1; j < 3; ++j ) { + for ( idx_t i = 1; i < 3; ++i ) { + idx_t n = index[j][i]; + Scalar val = input[n]; + maxval = std::max( maxval, val ); + minval = std::min( minval, val ); + } + } + if ( output < minval ) { output = minval; } + else if ( output > maxval ) { + output = maxval; + } + } + + + template + typename std::enable_if<( Rank == 1 ), void>::type interpolate( const stencil_t& stencil, const weights_t& weights, + const array::ArrayView& input, + array::ArrayView& output, + idx_t r ) const { + std::array, stencil_width()> index; + const auto& weights_j = weights.weights_j; + output( r ) = 0.; + for ( idx_t j = 0; j < stencil_width(); ++j ) { + const auto& weights_i = weights.weights_i[j]; + for ( idx_t i = 0; i < stencil_width(); ++i ) { + idx_t n = src_.index( stencil.i( i, j ), stencil.j( j ) ); + Value w = static_cast( weights_i[i] * weights_j[j] ); + output( r ) += w * input[n]; + index[j][i] = n; + } + } + + if ( limiter_ ) { limit( index, input, output, r ); } + } + + template + typename std::enable_if<( Rank == 1 ), void>::type limit( const std::array, 4>& index, + const array::ArrayView& input, + array::ArrayView& output, idx_t r ) const { + // Limit output to max/min of values in stencil marked by '*' + // x x x x + // x *-----* x + // / P | + // x *------ * x + // x x x x + Value maxval = std::numeric_limits::lowest(); + Value minval = std::numeric_limits::max(); + for ( idx_t j = 1; j < 3; ++j ) { + for ( idx_t i = 1; i < 3; ++i ) { + idx_t n = index[j][i]; + Value val = input[n]; + maxval = std::max( maxval, val ); + minval = std::min( minval, val ); + } + } + if ( output( r ) < minval ) { output( r ) = minval; } + else if ( output( r ) > maxval ) { + output( r ) = maxval; + } + } + + + template + typename std::enable_if<( Rank == 2 ), void>::type interpolate( const stencil_t& stencil, const weights_t& weights, + const array::ArrayView& input, + array::ArrayView& output, + idx_t r ) const { + std::array, stencil_width()> index; + const auto& weights_j = weights.weights_j; + const idx_t Nk = output.shape( 1 ); + for ( idx_t k = 0; k < Nk; ++k ) { + output( r, k ) = 0.; + } + for ( idx_t j = 0; j < stencil_width(); ++j ) { + const auto& weights_i = weights.weights_i[j]; + for ( idx_t i = 0; i < stencil_width(); ++i ) { + idx_t n = src_.index( stencil.i( i, j ), stencil.j( j ) ); + Value w = static_cast( weights_i[i] * weights_j[j] ); + for ( idx_t k = 0; k < Nk; ++k ) { + output( r, k ) += w * input( n, k ); + } + index[j][i] = n; + } + } + + if ( limiter_ ) { limit( index, input, output, r ); } + } + + template + typename std::enable_if<( Rank == 2 ), void>::type limit( const std::array, 4>& index, + const array::ArrayView& input, + array::ArrayView& output, idx_t r ) const { + // Limit output to max/min of values in stencil marked by '*' + // x x x x + // x *-----* x + // / P | + // x *------ * x + // x x x x + for ( idx_t k = 0; k < output.shape( 1 ); ++k ) { + Value maxval = std::numeric_limits::lowest(); + Value minval = std::numeric_limits::max(); + for ( idx_t j = 1; j < 3; ++j ) { + for ( idx_t i = 1; i < 3; ++i ) { + idx_t n = index[j][i]; + Value val = input( n, k ); + maxval = std::max( maxval, val ); + minval = std::min( minval, val ); + } + } + if ( output( r, k ) < minval ) { output( r, k ) = minval; } + else if ( output( r, k ) > maxval ) { + output( r, k ) = maxval; + } + } + } + + + template + typename array_t::value_type operator()( const double x, const double y, const array_t& input ) const { + Stencil stencil; + compute_stencil( x, y, stencil ); + Weights weights; + compute_weights( x, y, stencil, weights ); + return interpolate( stencil, weights, input ); + } + + template + typename array_t::value_type interpolate( const PointLonLat& p, const array_t& input, WorkSpace& ws ) const { + compute_stencil( p.lon(), p.lat(), ws.stencil ); + compute_weights( p.lon(), p.lat(), ws.stencil, ws.weights ); + return interpolate( ws.stencil, ws.weights, input ); + } + + // Thread private workspace + Triplets compute_triplets( const idx_t row, const double x, const double y, WorkSpace& ws ) const { + Triplets triplets; + triplets.reserve( stencil_size() ); + insert_triplets( row, x, y, triplets, ws ); + return triplets; + } + + Triplets reserve_triplets( size_t N ) { + Triplets triplets; + triplets.reserve( N * stencil_size() ); + return triplets; + } + + Triplets allocate_triplets( size_t N ) { return Triplets( N * stencil_size() ); } + + void insert_triplets( const idx_t row, const PointXY& p, Triplets& triplets, WorkSpace& ws ) const { + insert_triplets( row, p.x(), p.y(), triplets, ws ); + } + + void insert_triplets( const idx_t row, const double x, const double y, Triplets& triplets, WorkSpace& ws ) const { + compute_horizontal_stencil_( x, y, ws.stencil ); + compute_weights( x, y, ws.stencil, ws.weights ); + const auto& wj = ws.weights.weights_j; + + idx_t pos = row * stencil_size(); + for ( idx_t j = 0; j < stencil_width(); ++j ) { + const auto& wi = ws.weights.weights_i[j]; + for ( idx_t i = 0; i < stencil_width(); ++i ) { + idx_t col = src_.index( ws.stencil.i( i, j ), ws.stencil.j( j ) ); + double w = wi[i] * wj[j]; + triplets[pos++] = Triplet( row, col, w ); + } + } + } +}; + +} // namespace method +} // namespace interpolation +} // namespace atlas diff --git a/src/atlas/interpolation/method/structured/kernels/CubicVerticalKernel.h b/src/atlas/interpolation/method/structured/kernels/CubicVerticalKernel.h new file mode 100644 index 000000000..291f9d153 --- /dev/null +++ b/src/atlas/interpolation/method/structured/kernels/CubicVerticalKernel.h @@ -0,0 +1,182 @@ +/* + * (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. and Interpolation + */ + +#pragma once +#include + +#include "atlas/grid/Stencil.h" +#include "atlas/grid/StencilComputer.h" +#include "atlas/grid/Vertical.h" +#include "atlas/util/Point.h" + +namespace atlas { +namespace interpolation { +namespace method { + +class CubicVerticalKernel { + ComputeVerticalStencil compute_vertical_stencil_; + Vertical vertical_; + static constexpr idx_t stencil_width() { return 4; } + static constexpr idx_t stencil_size() { return stencil_width() * stencil_width(); } + idx_t first_level_; + idx_t last_level_; + bool limiter_; + +public: + CubicVerticalKernel() = default; + + CubicVerticalKernel( const Vertical& vertical, const eckit::Configuration& config = util::NoConfig() ) : + compute_vertical_stencil_( vertical, stencil_width() ), + vertical_( vertical ), + first_level_( vertical_.k_begin() ), + last_level_( vertical_.k_end() - 1 ) { + limiter_ = config.getBool( "limiter", false ); + } + struct Weights { + std::array weights_k; + }; + using Stencil = VerticalStencil<4>; + + template + void compute_stencil( const double z, stencil_t& stencil ) const { + compute_vertical_stencil_( z, stencil ); + } + + template + void compute_weights( const double z, const stencil_t& stencil, weights_t& weights ) const { + auto& w = weights.weights_k; + + std::array zvec; + for ( idx_t k = 0; k < 4; ++k ) { + zvec[k] = vertical_( stencil.k( k ) ); + } + + // auto quadratic_interpolation = [z]( const double zvec[], double w[] ) { + // double d01 = zvec[0] - zvec[1]; + // double d02 = zvec[0] - zvec[2]; + // double d12 = zvec[1] - zvec[2]; + // double dc0 = d01 * d02; + // double dc1 = -d01 * d12; + // double d0 = z - zvec[0]; + // double d1 = z - zvec[1]; + // double d2 = z - zvec[2]; + // w[0] = ( d1 * d2 ) / dc0; + // w[1] = ( d0 * d2 ) / dc1; + // w[2] = 1. - w[0] - w[1]; + // }; + + if ( stencil.k_interval() == -1 ) { + // constant extrapolation + // lev0 lev1 lev2 lev3 + // + |------X------X------X + // w=1 w=0 w=0 w=0 + w[0] = 1.; + w[1] = 0.; + w[2] = 0.; + w[3] = 0.; + return; + } + else if ( stencil.k_interval() == 3 ) { + // constant extrapolation + // lev(n-4) lev(n-3) lev(n-2) lev(n-1) + // X---------X---------X---------| + + // w=0 w=0 w=0 w=1 + w[0] = 0.; + w[1] = 0.; + w[2] = 0.; + w[3] = 1.; + return; + } + // else if ( stencil.k_interval() == 0 ) { + // // quadratic interpolation + // // lev0 lev1 lev2 lev3 + // // | + | | | + // // w=0 + // quadratic_interpolation( zvec.data(), w.data() ); + // w[3] = 0.; + // return; + // } + // else if ( stencil.k_interval() == 2 ) { + // // quadratic interpolation + // // lev(n-4) lev(n-3) lev(n-2) lev(n-1) + // // | | | + | + // // w=0 + // quadratic_interpolation( zvec.data() + 1, w.data() + 1 ); + // w[0] = 0.; + // return; + // } + + // cubic interpolation + // lev(k+0) lev(k+1) lev(k+2) lev(k+3) + // | | x | | + double d01 = zvec[0] - zvec[1]; + double d02 = zvec[0] - zvec[2]; + double d03 = zvec[0] - zvec[3]; + double d12 = zvec[1] - zvec[2]; + double d13 = zvec[1] - zvec[3]; + double d23 = zvec[2] - zvec[3]; + double dc0 = d01 * d02 * d03; + double dc1 = -d01 * d12 * d13; + double dc2 = d02 * d12 * d23; + + double d0 = z - zvec[0]; + double d1 = z - zvec[1]; + double d2 = z - zvec[2]; + double d3 = z - zvec[3]; + + w[0] = ( d1 * d2 * d3 ) / dc0; + w[1] = ( d0 * d2 * d3 ) / dc1; + w[2] = ( d0 * d1 * d3 ) / dc2; + w[3] = 1. - w[0] - w[1] - w[2]; + } + + template + void interpolate( const stencil_t& stencil, const weights_t& weights, const array_t& input, double& output ) const { + output = 0.; + const auto& w = weights.weights_k; + for ( idx_t k = 0; k < stencil_width(); ++k ) { + output += w[k] * input[stencil.k( k )]; + } + + + if ( limiter_ ) { + idx_t k = stencil.k_interval(); + idx_t k1, k2; + if ( k < 0 ) { k1 = k2 = 0; } + else if ( k > 2 ) { + k1 = k2 = 3; + } + else { + k1 = k; + k2 = k + 1; + } + double f1 = input[stencil.k( k1 )]; + double f2 = input[stencil.k( k2 )]; + double maxval = std::max( f1, f2 ); + double minval = std::min( f1, f2 ); + output = std::min( maxval, std::max( minval, output ) ); + } + } + + template + double operator()( const double z, const array_t& input ) const { + VerticalStencil stencil; + compute_vertical_stencil_( z, stencil ); + Weights weights; + compute_weights( z, stencil, weights ); + double output; + interpolate( stencil, weights, input, output ); + return output; + } +}; + +} // namespace method +} // namespace interpolation +} // namespace atlas diff --git a/src/atlas/interpolation/method/structured/kernels/Linear3DKernel.h b/src/atlas/interpolation/method/structured/kernels/Linear3DKernel.h new file mode 100644 index 000000000..a5d537b58 --- /dev/null +++ b/src/atlas/interpolation/method/structured/kernels/Linear3DKernel.h @@ -0,0 +1,220 @@ +/* + * (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. and Interpolation + */ + +#pragma once + +#include +#include + +#include "atlas/array/ArrayView.h" +#include "atlas/functionspace/StructuredColumns.h" +#include "atlas/grid/Stencil.h" +#include "atlas/grid/StencilComputer.h" +#include "atlas/runtime/Exception.h" +#include "atlas/util/CoordinateEnums.h" +#include "atlas/util/Point.h" + +#include "LinearHorizontalKernel.h" +#include "LinearVerticalKernel.h" + +namespace atlas { +namespace interpolation { +namespace method { + +class Linear3DKernel { +public: + Linear3DKernel( const functionspace::StructuredColumns& fs, const util::Config& config = util::NoConfig() ) { + src_ = fs; + ATLAS_ASSERT( src_ ); + ATLAS_ASSERT( src_.halo() >= 0 ); + ATLAS_ASSERT( src_.vertical().size() ); + horizontal_interpolation_ = LinearHorizontalKernel( src_, config ); + vertical_interpolation_ = LinearVerticalKernel( fs.vertical(), config ); + } + +private: + functionspace::StructuredColumns src_; + LinearHorizontalKernel horizontal_interpolation_; + LinearVerticalKernel vertical_interpolation_; + +public: + static std::string className() { return "Linear3DKernel"; } + static constexpr idx_t stencil_width() { return 2; } + static constexpr idx_t stencil_size() { return stencil_width() * stencil_width() * stencil_width(); } + static constexpr idx_t stencil_halo() { return 0; } + +public: + using Stencil = Stencil3D<2>; + struct Weights { + std::array, 2> weights_i; + std::array weights_j; + std::array weights_k; + }; + +public: + struct WorkSpace { + Stencil stencil; + Weights weights; + }; + + template + void compute_stencil( const double x, const double y, const double z, stencil_t& stencil ) const { + horizontal_interpolation_.compute_stencil( x, y, stencil ); + vertical_interpolation_.compute_stencil( z, stencil ); + } + + template + void compute_weights( const double x, const double y, const double z, weights_t& weights ) const { + Stencil stencil; + compute_stencil( x, y, z, stencil ); + compute_weights( x, y, z, stencil, weights ); + } + + + template + void compute_weights( const double x, const double y, const double z, const stencil_t& stencil, + weights_t& weights ) const { + horizontal_interpolation_.compute_weights( x, y, stencil, weights ); + vertical_interpolation_.compute_weights( z, stencil, weights ); + } + + template + typename std::enable_if<( array_t::RANK == 2 ), typename array_t::value_type>::type interpolate( + const stencil_t& stencil, const weights_t& weights, const array_t& input ) const { + using Value = typename array_t::value_type; + + std::array, stencil_width()> index; + const auto& wj = weights.weights_j; + const auto& wk = weights.weights_k; + + Value output = 0.; + for ( idx_t j = 0; j < stencil_width(); ++j ) { + const auto& wi = weights.weights_i[j]; + for ( idx_t i = 0; i < stencil_width(); ++i ) { + idx_t n = src_.index( stencil.i( i, j ), stencil.j( j ) ); + Value wij = wi[i] * wj[j]; + for ( idx_t k = 0; k < stencil_width(); ++k ) { + Value w = wij * wk[k]; + output += w * input( n, stencil.k( k ) ); + } + index[j][i] = n; + } + } + return output; + } + + template + struct OutputView1D { + template + Value& operator()( Int v ) { + return data_[v]; + } + template + Value& operator[]( Int v ) { + return data_[v]; + } + static constexpr int RANK{1}; + OutputView1D( Value* data ) : data_( data ) {} + using value_type = Value; + + Value* data_; + }; + + template + OutputView1D make_outputview( Value* data ) const { + return OutputView1D( data ); + } + + template + typename std::enable_if<( InputArray::RANK == 3 ), void>::type interpolate_vars( const stencil_t& stencil, + const weights_t& weights, + const InputArray& input, + OutputArray& output, + const idx_t nvar ) const { + using Value = typename InputArray::value_type; + + std::array, stencil_width()> index; + const auto& wj = weights.weights_j; + const auto& wk = weights.weights_k; + + const Value* _input_; + + for ( idx_t v = 0; v < nvar; ++v ) { + output[v] = 0.; + } + + for ( idx_t j = 0; j < stencil_width(); ++j ) { + const auto& wi = weights.weights_i[j]; + for ( idx_t i = 0; i < stencil_width(); ++i ) { + const idx_t n = src_.index( stencil.i( i, j ), stencil.j( j ) ); + const Value wij = wi[i] * wj[j]; + for ( idx_t k = 0; k < stencil_width(); ++k ) { + const Value w = wij * wk[k]; + const idx_t kk = stencil.k( k ); + _input_ = &( input( n, kk, 0 ) ); // Assumption that input.stride(2) == 1 + for ( idx_t v = 0; v < nvar; ++v ) { + output[v] += w * _input_[v]; + } + } + index[j][i] = n; + } + } + } + + template + typename std::enable_if<( InputArray::RANK == 2 && OutputArray::RANK == 1 ), void>::type interpolate( + const stencil_t& stencil, const weights_t& weights, const InputArray& input, OutputArray& output, + idx_t r ) const { + output( r ) = interpolate( stencil, weights, input ); + } + + template + typename std::enable_if<( InputArray::RANK == 2 && OutputArray::RANK == 2 ), void>::type interpolate( + const stencil_t& stencil, const weights_t& weights, const InputArray& input, OutputArray& output, idx_t r, + idx_t k ) const { + output( r, k ) = interpolate( stencil, weights, input ); + } + + template + typename std::enable_if<( InputArray::RANK == 3 && OutputArray::RANK == 3 ), void>::type interpolate( + const stencil_t& stencil, const weights_t& weights, const InputArray& input, OutputArray& output, idx_t r, + idx_t k ) const { + auto output_vars = make_outputview( &output( r, k, 0 ) ); + interpolate_vars( stencil, weights, input, output_vars, output.shape( 2 ) ); + } + + template + typename std::enable_if<( InputArray::RANK == 2 && OutputArray::RANK == 3 ), void>::type interpolate( + const stencil_t&, const weights_t&, const InputArray&, OutputArray&, idx_t /*r*/, idx_t /*k*/ ) const { + ATLAS_NOTIMPLEMENTED; + } + + template + typename std::enable_if<( InputArray::RANK == 3 && OutputArray::RANK == 1 ), void>::type interpolate( + const stencil_t&, const weights_t&, const InputArray&, OutputArray&, idx_t /*r*/ ) const { + ATLAS_NOTIMPLEMENTED; + } + + template + typename std::enable_if<( InputArray::RANK == 3 && OutputArray::RANK == 1 ), void>::type interpolate( + const stencil_t&, const weights_t&, const InputArray&, OutputArray&, idx_t /*r*/, idx_t /*k*/ ) const { + ATLAS_NOTIMPLEMENTED; + } + + template + typename std::enable_if<( InputArray::RANK == 3 && OutputArray::RANK == 2 ), void>::type interpolate( + const stencil_t&, const weights_t&, const InputArray&, OutputArray&, idx_t /*r*/, idx_t /*k*/ ) const { + ATLAS_NOTIMPLEMENTED; + } +}; + +} // namespace method +} // namespace interpolation +} // namespace atlas diff --git a/src/atlas/interpolation/method/structured/kernels/LinearHorizontalKernel.h b/src/atlas/interpolation/method/structured/kernels/LinearHorizontalKernel.h new file mode 100644 index 000000000..edbe4f8a2 --- /dev/null +++ b/src/atlas/interpolation/method/structured/kernels/LinearHorizontalKernel.h @@ -0,0 +1,216 @@ +/* + * (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. and Interpolation + */ + +#pragma once + +#include +#include + +#include "eckit/linalg/Triplet.h" + +#include "atlas/array/ArrayView.h" +#include "atlas/functionspace/StructuredColumns.h" +#include "atlas/grid/Stencil.h" +#include "atlas/grid/StencilComputer.h" +#include "atlas/runtime/Exception.h" +#include "atlas/util/CoordinateEnums.h" +#include "atlas/util/NormaliseLongitude.h" +#include "atlas/util/Point.h" + +namespace atlas { +namespace interpolation { +namespace method { + +class LinearHorizontalKernel { + using Triplet = eckit::linalg::Triplet; + using Triplets = std::vector; + +public: + LinearHorizontalKernel() = default; + + LinearHorizontalKernel( const functionspace::StructuredColumns& fs, const util::Config& = util::NoConfig() ) { + src_ = fs; + ATLAS_ASSERT( src_ ); + compute_horizontal_stencil_ = ComputeHorizontalStencil( src_.grid(), stencil_width() ); + } + +private: + functionspace::StructuredColumns src_; + ComputeHorizontalStencil compute_horizontal_stencil_; + +public: + static std::string className() { return "LinearHorizontalKernel"; } + static constexpr idx_t stencil_width() { return 2; } + static constexpr idx_t stencil_size() { return stencil_width() * stencil_width(); } + static constexpr idx_t stencil_halo() { return 0; } + +public: + using Stencil = HorizontalStencil<2>; + struct Weights { + std::array, 2> weights_i; + std::array weights_j; + }; + +public: + struct WorkSpace { + Stencil stencil; + Weights weights; + }; + + template + void compute_stencil( const double x, const double y, stencil_t& stencil ) const { + compute_horizontal_stencil_( x, y, stencil ); + } + + template + void compute_weights( const double x, const double y, weights_t& weights ) const { + Stencil stencil; + compute_stencil( x, y, stencil ); + compute_weights( x, y, stencil, weights ); + } + + + template + void compute_weights( const double x, const double y, const stencil_t& stencil, weights_t& weights ) const { + PointXY P1, P2; + std::array yvec; + // Compute weights for each constant-Y + for ( idx_t j = 0; j < stencil_width(); ++j ) { + auto& weights_i = weights.weights_i[j]; + src_.compute_xy( stencil.i( 0, j ), stencil.j( j ), P1 ); + src_.compute_xy( stencil.i( 1, j ), stencil.j( j ), P2 ); + const double alpha = ( P2.x() - x ) / ( P2.x() - P1.x() ); + weights_i[0] = alpha; + weights_i[1] = 1. - alpha; + yvec[j] = P1.y(); + } + // Compute weights in y-direction + { + auto& weights_j = weights.weights_j; + const double alpha = ( yvec[1] - y ) / ( yvec[1] - yvec[0] ); + weights_j[0] = alpha; + weights_j[1] = 1. - alpha; + } + } + + template + typename array_t::value_type interpolate( const stencil_t& stencil, const weights_t& weights, + const array_t& input ) const { + using Value = typename array_t::value_type; + + const auto& weights_j = weights.weights_j; + Value output = 0.; + for ( idx_t j = 0; j < stencil_width(); ++j ) { + const auto& weights_i = weights.weights_i[j]; + for ( idx_t i = 0; i < stencil_width(); ++i ) { + idx_t n = src_.index( stencil.i( i, j ), stencil.j( j ) ); + Value w = weights_i[i] * weights_j[j]; + output += w * input[n]; + } + } + + return output; + } + + template + typename std::enable_if<( Rank == 1 ), void>::type interpolate( const stencil_t& stencil, const weights_t& weights, + const array::ArrayView& input, + array::ArrayView& output, + idx_t r ) const { + const auto& weights_j = weights.weights_j; + output( r ) = 0.; + for ( idx_t j = 0; j < stencil_width(); ++j ) { + const auto& weights_i = weights.weights_i[j]; + for ( idx_t i = 0; i < stencil_width(); ++i ) { + idx_t n = src_.index( stencil.i( i, j ), stencil.j( j ) ); + Value w = static_cast( weights_i[i] * weights_j[j] ); + output( r ) += w * input[n]; + } + } + } + + template + typename std::enable_if<( Rank == 2 ), void>::type interpolate( const stencil_t& stencil, const weights_t& weights, + const array::ArrayView& input, + array::ArrayView& output, + idx_t r ) const { + const auto& weights_j = weights.weights_j; + const idx_t Nk = output.shape( 1 ); + for ( idx_t k = 0; k < Nk; ++k ) { + output( r, k ) = 0.; + } + for ( idx_t j = 0; j < stencil_width(); ++j ) { + const auto& weights_i = weights.weights_i[j]; + for ( idx_t i = 0; i < stencil_width(); ++i ) { + idx_t n = src_.index( stencil.i( i, j ), stencil.j( j ) ); + Value w = static_cast( weights_i[i] * weights_j[j] ); + for ( idx_t k = 0; k < Nk; ++k ) { + output( r, k ) += w * input( n, k ); + } + } + } + } + + template + typename array_t::value_type operator()( const double x, const double y, const array_t& input ) const { + Stencil stencil; + compute_stencil( x, y, stencil ); + Weights weights; + compute_weights( x, y, stencil, weights ); + return interpolate( stencil, weights, input ); + } + + template + typename array_t::value_type interpolate( const PointLonLat& p, const array_t& input, WorkSpace& ws ) const { + compute_stencil( p.lon(), p.lat(), ws.stencil ); + compute_weights( p.lon(), p.lat(), ws.stencil, ws.weights ); + return interpolate( ws.stencil, ws.weights, input ); + } + + // Thread private workspace + Triplets compute_triplets( const idx_t row, const double x, const double y, WorkSpace& ws ) const { + Triplets triplets; + triplets.reserve( stencil_size() ); + insert_triplets( row, x, y, triplets, ws ); + return triplets; + } + + Triplets reserve_triplets( size_t N ) { + Triplets triplets; + triplets.reserve( N * stencil_size() ); + return triplets; + } + + Triplets allocate_triplets( size_t N ) { return Triplets( N * stencil_size() ); } + + void insert_triplets( const idx_t row, const PointXY& p, Triplets& triplets, WorkSpace& ws ) const { + insert_triplets( row, p.x(), p.y(), triplets, ws ); + } + + void insert_triplets( const idx_t row, const double x, const double y, Triplets& triplets, WorkSpace& ws ) const { + compute_horizontal_stencil_( x, y, ws.stencil ); + compute_weights( x, y, ws.stencil, ws.weights ); + const auto& wj = ws.weights.weights_j; + + idx_t pos = row * stencil_size(); + for ( idx_t j = 0; j < stencil_width(); ++j ) { + const auto& wi = ws.weights.weights_i[j]; + for ( idx_t i = 0; i < stencil_width(); ++i ) { + idx_t col = src_.index( ws.stencil.i( i, j ), ws.stencil.j( j ) ); + double w = wi[i] * wj[j]; + triplets[pos++] = Triplet( row, col, w ); + } + } + } +}; + +} // namespace method +} // namespace interpolation +} // namespace atlas diff --git a/src/atlas/interpolation/method/structured/kernels/LinearVerticalKernel.h b/src/atlas/interpolation/method/structured/kernels/LinearVerticalKernel.h new file mode 100644 index 000000000..db8eba2c4 --- /dev/null +++ b/src/atlas/interpolation/method/structured/kernels/LinearVerticalKernel.h @@ -0,0 +1,109 @@ +/* + * (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. and Interpolation + */ + +#pragma once + +#include + +#include "atlas/grid/Stencil.h" +#include "atlas/grid/StencilComputer.h" +#include "atlas/grid/Vertical.h" +#include "atlas/util/Point.h" + +namespace atlas { +namespace interpolation { +namespace method { + +class LinearVerticalKernel { + ComputeVerticalStencil compute_vertical_stencil_; + Vertical vertical_; + static constexpr idx_t stencil_width() { return 2; } + static constexpr idx_t stencil_size() { return stencil_width() * stencil_width(); } + idx_t first_level_; + idx_t last_level_; + +public: + LinearVerticalKernel() = default; + + LinearVerticalKernel( const Vertical& vertical, const eckit::Configuration& ) : + compute_vertical_stencil_( vertical, stencil_width() ), + vertical_( vertical ), + first_level_( vertical_.k_begin() ), + last_level_( vertical_.k_end() - 1 ) {} + struct Weights { + std::array weights_k; + }; + using Stencil = VerticalStencil<2>; + + template + void compute_stencil( const double z, stencil_t& stencil ) const { + compute_vertical_stencil_( z, stencil ); + } + + template + void compute_weights( const double z, const stencil_t& stencil, weights_t& weights ) const { + auto& w = weights.weights_k; + + std::array zvec; + for ( idx_t k = 0; k < stencil_width(); ++k ) { + zvec[k] = vertical_( stencil.k( k ) ); + } + + if ( stencil.k_interval() == -1 ) { + // constant extrapolation + // lev0 lev1 + // + |------X + // w=1 w=0 + w[0] = 1.; + w[1] = 0.; + return; + } + else if ( stencil.k_interval() == 1 ) { + // constant extrapolation + // lev(n-2) lev(n-1) + // X---------| + + // w=0 w=1 + w[0] = 0.; + w[1] = 1.; + return; + } + + // Linear interpolation + // lev(k+0) lev(k+1) + // | x | + const double alpha = ( zvec[1] - z ) / ( zvec[1] - zvec[0] ); + w[0] = alpha; + w[1] = 1. - alpha; + } + + template + void interpolate( const stencil_t& stencil, const weights_t& weights, const array_t& input, double& output ) const { + output = 0.; + const auto& w = weights.weights_k; + for ( idx_t k = 0; k < stencil_width(); ++k ) { + output += w[k] * input[stencil.k( k )]; + } + } + + template + double operator()( const double z, const array_t& input ) const { + Stencil stencil; + compute_vertical_stencil_( z, stencil ); + Weights weights; + compute_weights( z, stencil, weights ); + double output; + interpolate( stencil, weights, input, output ); + return output; + } +}; + +} // namespace method +} // namespace interpolation +} // namespace atlas diff --git a/src/atlas/interpolation/method/structured/kernels/QuasiCubic3DKernel.cc b/src/atlas/interpolation/method/structured/kernels/QuasiCubic3DKernel.cc new file mode 100644 index 000000000..a2ebbe443 --- /dev/null +++ b/src/atlas/interpolation/method/structured/kernels/QuasiCubic3DKernel.cc @@ -0,0 +1,26 @@ +/* + * (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. and Interpolation + */ + +#include "QuasiCubic3DKernel.h" + +namespace atlas { +namespace interpolation { +namespace method { + +// Note: Following symbols should no longer be necessary from C++17 onwards +constexpr std::array QuasiCubicLinearPoints::j; +constexpr std::array QuasiCubicLinearPoints::jj; +constexpr std::array QuasiCubicLinearPoints::jw; +constexpr std::array QuasiCubicLinearPoints::i; +constexpr std::array QuasiCubicLinearPoints::ii; + +} // namespace method +} // namespace interpolation +} // namespace atlas diff --git a/src/atlas/interpolation/method/structured/kernels/QuasiCubic3DKernel.h b/src/atlas/interpolation/method/structured/kernels/QuasiCubic3DKernel.h new file mode 100644 index 000000000..140e93a36 --- /dev/null +++ b/src/atlas/interpolation/method/structured/kernels/QuasiCubic3DKernel.h @@ -0,0 +1,455 @@ +/* + * (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. and Interpolation + */ + +#pragma once + +#include +#include + +#include "atlas/array/ArrayView.h" +#include "atlas/functionspace/StructuredColumns.h" +#include "atlas/grid/Stencil.h" +#include "atlas/grid/StencilComputer.h" +#include "atlas/runtime/Exception.h" +#include "atlas/util/CoordinateEnums.h" +#include "atlas/util/Point.h" + +#include "CubicVerticalKernel.h" +#include "LinearHorizontalKernel.h" +#include "QuasiCubicHorizontalKernel.h" + +namespace atlas { +namespace interpolation { +namespace method { + +struct QuasiCubicLinearPoints { + constexpr QuasiCubicLinearPoints() {} + static constexpr std::array j{{1, 2}}; + static constexpr std::array jj{{0, 3}}; + static constexpr std::array jw{{4, 5}}; + static constexpr std::array i{{1, 2}}; + static constexpr std::array ii{{0, 3}}; +}; + +class QuasiCubic3DKernel { +public: + QuasiCubic3DKernel( const functionspace::StructuredColumns& fs, const util::Config& config = util::NoConfig() ) { + src_ = fs; + ATLAS_ASSERT( src_ ); + ATLAS_ASSERT( src_.halo() >= 2 ); + ATLAS_ASSERT( src_.vertical().size() ); + quasi_cubic_horizontal_interpolation_ = QuasiCubicHorizontalKernel( src_, config ); + linear_horizontal_interpolation_ = LinearHorizontalKernel( src_, config ); + vertical_interpolation_ = CubicVerticalKernel( fs.vertical(), config ); + limiter_ = config.getBool( "limiter", false ); + } + +private: + functionspace::StructuredColumns src_; + QuasiCubicHorizontalKernel quasi_cubic_horizontal_interpolation_; + LinearHorizontalKernel linear_horizontal_interpolation_; + CubicVerticalKernel vertical_interpolation_; + bool limiter_{false}; + +public: + static std::string className() { return "QuasiCubic3DKernel"; } + static constexpr idx_t stencil_width() { return 4; } + static constexpr idx_t stencil_size() { return 32; } + static constexpr idx_t stencil_halo() { + return static_cast( static_cast( stencil_width() ) / 2. + 0.5 ); + } + +public: + using Stencil = Stencil3D<4>; + struct Weights { + std::array, 4> weights_i; + std::array weights_j; + std::array weights_k; + struct LinearWeights { + std::array, 2> weights_i; + std::array weights_j; + } linear; + }; + + +public: + struct WorkSpace { + Stencil stencil; + Weights weights; + }; + + template + void compute_stencil( const double x, const double y, const double z, stencil_t& stencil ) const { + quasi_cubic_horizontal_interpolation_.compute_stencil( x, y, stencil ); + vertical_interpolation_.compute_stencil( z, stencil ); + } + + template + void compute_weights( const double x, const double y, const double z, weights_t& weights ) const { + Stencil stencil; + compute_stencil( x, y, z, stencil ); + compute_weights( x, y, z, stencil, weights ); + } + + + template + void compute_weights( const double x, const double y, const double z, const stencil_t& stencil, + weights_t& weights ) const { + quasi_cubic_horizontal_interpolation_.compute_weights( x, y, stencil, weights ); + + + // Insert more linear weights in available slots (weights_i[0], weights_i[3], weights_j[4], weights_j[5]) + { + PointXY P1, P2; + std::array yvec; + constexpr QuasiCubicLinearPoints pts{}; + // Top and bottom row x-direction + for ( idx_t l = 0; l < 2; ++l ) { + idx_t j = pts.j[l]; // index in stencil + idx_t jj = pts.jj[l]; // row index in weights_i + auto& weights_i = weights.weights_i[jj]; + src_.compute_xy( stencil.i( pts.i[0], j ), stencil.j( j ), P1 ); + src_.compute_xy( stencil.i( pts.i[1], j ), stencil.j( j ), P2 ); + const double alpha = ( P2.x() - x ) / ( P2.x() - P1.x() ); + weights_i[pts.ii[0]] = alpha; + weights_i[pts.ii[1]] = 1. - alpha; + yvec[l] = P1.y(); + } + // Compute weights in y-direction + { + auto& weights_j = weights.weights_j; + const double alpha = ( yvec[1] - y ) / ( yvec[1] - yvec[0] ); + weights_j[4] = alpha; + weights_j[5] = 1. - alpha; + } + } + + vertical_interpolation_.compute_weights( z, stencil, weights ); + } + + template + typename std::enable_if<( array_t::RANK == 2 ), typename array_t::value_type>::type interpolate( + const stencil_t& stencil, const weights_t& weights, const array_t& input ) const { + using Value = typename array_t::value_type; + + std::array, stencil_width()> index; + const auto& wk = weights.weights_k; + + Value output = 0.; + + // Horizontally quasi-cubic part for inner levels ( k = {1,2} ) + { + // Inner levels, inner rows (cubic in i, cubic in j) --> 16 points + const auto& wj = weights.weights_j; + for ( idx_t j = 1; j < 3; ++j ) { // j = {1,2} + const auto& wi = weights.weights_i[j]; + for ( idx_t i = 0; i < 4; ++i ) { // i = {0,1,2,3} + idx_t n = src_.index( stencil.i( i, j ), stencil.j( j ) ); + Value wij = wi[i] * wj[j]; + for ( idx_t k = 1; k < 3; ++k ) { // k = {1,2} + Value w = wij * wk[k]; + output += w * input( n, stencil.k( k ) ); + } + index[j][i] = n; + } + } + // Inner levels, outer rows: (linear in i, cubic in j) --> 8 points + for ( idx_t j = 0; j < 4; j += 3 ) { // j = {0,3} + const auto& wi = weights.weights_i[j]; + for ( idx_t i = 1; i < 3; ++i ) { // i = {1,2} + idx_t n = src_.index( stencil.i( i, j ), stencil.j( j ) ); + Value wij = wi[i] * wj[j]; + for ( idx_t k = 1; k < 3; ++k ) { // k = {1,2} + Value w = wij * wk[k]; + output += w * input( n, stencil.k( k ) ); + } + index[j][i] = n; + } + } + } + // Horizontally Linear part for outer levels ( k = {0,3} ) + { + constexpr QuasiCubicLinearPoints pts{}; + // Outer levels: (linear in i, linear in j) -- > 8 points + for ( idx_t m = 0; m < 2; ++m ) { + idx_t j = pts.j[m]; // index in stencil ( j = {1,2} ) + idx_t jj = pts.jj[m]; // row index in weights_i ( jj = {0,3} ) + idx_t jw = pts.jw[m]; // jw = {4,5}; + const auto& wi = weights.weights_i[jj]; + const double wj = weights.weights_j[jw]; + for ( idx_t l = 0; l < 2; ++l ) { + idx_t i = pts.i[l]; // i = {1,2} + idx_t ii = pts.ii[l]; // ii = {0,3} + idx_t n = src_.index( stencil.i( i, j ), stencil.j( j ) ); + Value wij = wi[ii] * wj; + for ( idx_t k = 0; k < 4; k += 3 ) { // k = {0,3} + Value w = wij * wk[k]; + output += w * input( n, stencil.k( k ) ); + } + } + } + } + + + if ( limiter_ ) { limit_scalar( output, index, stencil, input ); } + return output; + } + + template + typename std::enable_if<( array_t::RANK == 2 ), void>::type limit_scalar( + typename array_t::value_type& output, const std::array, 4>& index, + const stencil_t& stencil, const array_t& input ) const { + using Scalar = typename array_t::value_type; + // Limit output to max/min of values in stencil marked by '*' + // x x x x + // x *-----* x + // / P | + // x *------ * x + // x x x x + idx_t k = stencil.k_interval(); + idx_t k1, k2; + if ( k < 0 ) { k1 = k2 = 0; } + else if ( k > 2 ) { + k1 = k2 = 3; + } + else { + k1 = k; + k2 = k + 1; + } + + Scalar maxval = std::numeric_limits::lowest(); + Scalar minval = std::numeric_limits::max(); + for ( idx_t j = 1; j < 3; ++j ) { + for ( idx_t i = 1; i < 3; ++i ) { + idx_t n = index[j][i]; + + Scalar f1 = input( n, stencil.k( k1 ) ); + Scalar f2 = input( n, stencil.k( k2 ) ); + + maxval = std::max( maxval, f1 ); + maxval = std::max( maxval, f2 ); + minval = std::min( minval, f1 ); + minval = std::min( minval, f2 ); + } + } + if ( output < minval ) { output = minval; } + else if ( output > maxval ) { + output = maxval; + } + } + + template + struct OutputView1D { + template + Value& operator()( Int v ) { + return data_[v]; + } + template + Value& operator[]( Int v ) { + return data_[v]; + } + static constexpr int RANK{1}; + OutputView1D( Value* data ) : data_( data ) {} + using value_type = Value; + + Value* data_; + }; + + template + OutputView1D make_outputview( Value* data ) const { + return OutputView1D( data ); + } + + template + typename std::enable_if<( InputArray::RANK == 3 ), void>::type interpolate_vars( const stencil_t& stencil, + const weights_t& weights, + const InputArray& input, + OutputArray& output, + const idx_t nvar ) const { + using Value = typename InputArray::value_type; + + std::array, stencil_width()> index; + const auto& wk = weights.weights_k; + + const Value* _input_; + + for ( idx_t v = 0; v < nvar; ++v ) { + output[v] = 0.; + } + + // Horizontally quasi-cubic part for inner levels ( k = {1,2} ) + { + // Inner levels, inner rows (cubic in i, cubic in j) --> 16 points + const auto& wj = weights.weights_j; + for ( idx_t j = 1; j < 3; ++j ) { // j = {1,2} + const auto& wi = weights.weights_i[j]; + for ( idx_t i = 0; i < 4; ++i ) { // i = {0,1,2,3} + idx_t n = src_.index( stencil.i( i, j ), stencil.j( j ) ); + Value wij = wi[i] * wj[j]; + for ( idx_t k = 1; k < 3; ++k ) { // k = {1,2} + Value w = wij * wk[k]; + const idx_t kk = stencil.k( k ); + _input_ = &( input( n, kk, 0 ) ); // Assumption that input.stride(2) == 1 + for ( idx_t v = 0; v < nvar; ++v ) { + output[v] += w * _input_[v]; + } + } + index[j][i] = n; + } + } + // Inner levels, outer rows: (linear in i, cubic in j) --> 8 points + for ( idx_t j = 0; j < 4; j += 3 ) { // j = {0,3} + const auto& wi = weights.weights_i[j]; + for ( idx_t i = 1; i < 3; ++i ) { // i = {1,2} + idx_t n = src_.index( stencil.i( i, j ), stencil.j( j ) ); + Value wij = wi[i] * wj[j]; + for ( idx_t k = 1; k < 3; ++k ) { // k = {1,2} + Value w = wij * wk[k]; + const idx_t kk = stencil.k( k ); + _input_ = &( input( n, kk, 0 ) ); // Assumption that input.stride(2) == 1 + for ( idx_t v = 0; v < nvar; ++v ) { + output[v] += w * _input_[v]; + } + } + index[j][i] = n; + } + } + } + // Horizontally Linear part for outer levels ( k = {0,3} ) + { + constexpr QuasiCubicLinearPoints pts{}; + // Outer levels: (linear in i, linear in j) -- > 8 points + for ( idx_t m = 0; m < 2; ++m ) { + idx_t j = pts.j[m]; // index in stencil ( j = {1,2} ) + idx_t jj = pts.jj[m]; // row index in weights_i ( jj = {0,3} ) + idx_t jw = pts.jw[m]; // jw = {4,5}; + const auto& wi = weights.weights_i[jj]; + const double wj = weights.weights_j[jw]; + for ( idx_t l = 0; l < 2; ++l ) { + idx_t i = pts.i[l]; // i = {1,2} + idx_t ii = pts.ii[l]; // ii = {0,3} + idx_t n = src_.index( stencil.i( i, j ), stencil.j( j ) ); + Value wij = wi[ii] * wj; + for ( idx_t k = 0; k < 4; k += 3 ) { // k = {0,3} + Value w = wij * wk[k]; + const idx_t kk = stencil.k( k ); + _input_ = &( input( n, kk, 0 ) ); // Assumption that input.stride(2) == 1 + for ( idx_t v = 0; v < nvar; ++v ) { + output[v] += w * _input_[v]; + } + } + } + } + } + + + if ( limiter_ ) { limit_vars( index, stencil, input, output, nvar ); } + } + + template + typename std::enable_if<( InputArray::RANK == 3 ), void>::type limit_vars( + const std::array, 4>& index, const stencil_t& stencil, const InputArray& input, + OutputArray& output, const idx_t nvar ) const { + // Limit output to max/min of values in stencil marked by '*' + // x x x x + // x *-----* x + // / P | + // x *------ * x + // x x x x + + using Value = typename InputArray::value_type; + + const idx_t k = stencil.k_interval(); + idx_t k1, k2; + if ( k < 0 ) { k1 = k2 = stencil.k( 0 ); } + else if ( k > 2 ) { + k1 = k2 = stencil.k( 3 ); + } + else { + k1 = stencil.k( k ); + k2 = k1 + 1; + } + + for ( idx_t v = 0; v < nvar; ++v ) { + Value limited = output[v]; + Value maxval = std::numeric_limits::lowest(); + Value minval = std::numeric_limits::max(); + for ( idx_t j = 1; j < 3; ++j ) { + for ( idx_t i = 1; i < 3; ++i ) { + idx_t n = index[j][i]; + + Value f1 = input( n, k1, v ); + Value f2 = input( n, k2, v ); + + maxval = std::max( maxval, f1 ); + maxval = std::max( maxval, f2 ); + minval = std::min( minval, f1 ); + minval = std::min( minval, f2 ); + } + } + if ( limited < minval ) { limited = minval; } + else if ( limited > maxval ) { + limited = maxval; + } + output[v] = limited; + } + } + + + template + typename std::enable_if<( InputArray::RANK == 2 && OutputArray::RANK == 1 ), void>::type interpolate( + const stencil_t& stencil, const weights_t& weights, const InputArray& input, OutputArray& output, + idx_t r ) const { + output( r ) = interpolate( stencil, weights, input ); + } + + template + typename std::enable_if<( InputArray::RANK == 2 && OutputArray::RANK == 2 ), void>::type interpolate( + const stencil_t& stencil, const weights_t& weights, const InputArray& input, OutputArray& output, idx_t r, + idx_t k ) const { + output( r, k ) = interpolate( stencil, weights, input ); + } + + template + typename std::enable_if<( InputArray::RANK == 3 && OutputArray::RANK == 3 ), void>::type interpolate( + const stencil_t& stencil, const weights_t& weights, const InputArray& input, OutputArray& output, idx_t r, + idx_t k ) const { + auto output_vars = make_outputview( &output( r, k, 0 ) ); + interpolate_vars( stencil, weights, input, output_vars, output.shape( 2 ) ); + } + + template + typename std::enable_if<( InputArray::RANK == 2 && OutputArray::RANK == 3 ), void>::type interpolate( + const stencil_t&, const weights_t&, const InputArray&, OutputArray&, idx_t /*r*/, idx_t /*k*/ ) const { + ATLAS_NOTIMPLEMENTED; + } + + template + typename std::enable_if<( InputArray::RANK == 3 && OutputArray::RANK == 1 ), void>::type interpolate( + const stencil_t&, const weights_t&, const InputArray&, OutputArray&, idx_t /*r*/ ) const { + ATLAS_NOTIMPLEMENTED; + } + + template + typename std::enable_if<( InputArray::RANK == 3 && OutputArray::RANK == 1 ), void>::type interpolate( + const stencil_t&, const weights_t&, const InputArray&, OutputArray&, idx_t /*r*/, idx_t /*k*/ ) const { + ATLAS_NOTIMPLEMENTED; + } + + template + typename std::enable_if<( InputArray::RANK == 3 && OutputArray::RANK == 2 ), void>::type interpolate( + const stencil_t&, const weights_t&, const InputArray&, OutputArray&, idx_t /*r*/, idx_t /*k*/ ) const { + ATLAS_NOTIMPLEMENTED; + } +}; // namespace method + +} // namespace method +} // namespace interpolation +} // namespace atlas diff --git a/src/atlas/interpolation/method/structured/kernels/QuasiCubicHorizontalKernel.h b/src/atlas/interpolation/method/structured/kernels/QuasiCubicHorizontalKernel.h new file mode 100644 index 000000000..d4b081a16 --- /dev/null +++ b/src/atlas/interpolation/method/structured/kernels/QuasiCubicHorizontalKernel.h @@ -0,0 +1,395 @@ +/* + * (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. and Interpolation + */ + +#pragma once + +#include +#include + +#include "eckit/linalg/Triplet.h" + +#include "atlas/array/ArrayView.h" +#include "atlas/functionspace/StructuredColumns.h" +#include "atlas/grid/Stencil.h" +#include "atlas/grid/StencilComputer.h" +#include "atlas/runtime/Exception.h" +#include "atlas/util/CoordinateEnums.h" +#include "atlas/util/NormaliseLongitude.h" +#include "atlas/util/Point.h" + +namespace atlas { +namespace interpolation { +namespace method { + +class QuasiCubicHorizontalKernel { + using Triplet = eckit::linalg::Triplet; + using Triplets = std::vector; + +public: + QuasiCubicHorizontalKernel() = default; + + QuasiCubicHorizontalKernel( const functionspace::StructuredColumns& fs, + const util::Config& config = util::NoConfig() ) { + src_ = fs; + ATLAS_ASSERT( src_ ); + ATLAS_ASSERT( src_.halo() >= 2 ); + compute_horizontal_stencil_ = ComputeHorizontalStencil( src_.grid(), stencil_width() ); + limiter_ = config.getBool( "limiter", false ); + } + +protected: + functionspace::StructuredColumns src_; + ComputeHorizontalStencil compute_horizontal_stencil_; + bool limiter_{false}; + +public: + static std::string className() { return "CubicHorizontalKernel"; } + static constexpr idx_t stencil_width() { return 4; } + static constexpr idx_t stencil_size() { return 12; } + static constexpr idx_t stencil_halo() { + return static_cast( static_cast( stencil_width() ) / 2. + 0.5 ); + } + +public: + using Stencil = HorizontalStencil<4>; + struct Weights { + std::array, 4> weights_i; + std::array weights_j; + }; + +public: + struct WorkSpace { + Stencil stencil; + Weights weights; + }; + + template + void compute_stencil( const double x, const double y, stencil_t& stencil ) const { + compute_horizontal_stencil_( x, y, stencil ); + } + + template + void compute_weights( const double x, const double y, weights_t& weights ) const { + Stencil stencil; + compute_stencil( x, y, stencil ); + compute_weights( x, y, stencil, weights ); + } + + template + void compute_weights( const double x, const double y, const stencil_t& stencil, weights_t& weights ) const { + PointXY P1, P2; + std::array yvec; + + // Compute x-direction weights LINEAR for outer rows ( j = {0,3} ) + for ( idx_t j = 0; j < 4; j += 3 ) { + auto& weights_i = weights.weights_i[j]; + src_.compute_xy( stencil.i( 1, j ), stencil.j( j ), P1 ); + src_.compute_xy( stencil.i( 2, j ), stencil.j( j ), P2 ); + const double alpha = ( P2.x() - x ) / ( P2.x() - P1.x() ); + weights_i[1] = alpha; + weights_i[2] = 1. - alpha; + yvec[j] = P1.y(); + } + + // Compute x-direction weights CUBIC for inner rows ( j = {1,2} ) + for ( idx_t j = 1; j < 3; ++j ) { + auto& weights_i = weights.weights_i[j]; + src_.compute_xy( stencil.i( 1, j ), stencil.j( j ), P1 ); + src_.compute_xy( stencil.i( 2, j ), stencil.j( j ), P2 ); + const double alpha = ( P2.x() - x ) / ( P2.x() - P1.x() ); + const double alpha_sqr = alpha * alpha; + const double two_minus_alpha = 2. - alpha; + const double one_minus_alpha_sqr = 1. - alpha_sqr; + weights_i[0] = -alpha * one_minus_alpha_sqr / 6.; + weights_i[1] = 0.5 * alpha * ( 1. + alpha ) * two_minus_alpha; + weights_i[2] = 0.5 * one_minus_alpha_sqr * two_minus_alpha; + weights_i[3] = 1. - weights_i[0] - weights_i[1] - weights_i[2]; + yvec[j] = P1.y(); + } + + // Compute weights in y-direction + const double dl12 = yvec[0] - yvec[1]; + const double dl13 = yvec[0] - yvec[2]; + const double dl14 = yvec[0] - yvec[3]; + const double dl23 = yvec[1] - yvec[2]; + const double dl24 = yvec[1] - yvec[3]; + const double dl34 = yvec[2] - yvec[3]; + const double dcl1 = dl12 * dl13 * dl14; + const double dcl2 = -dl12 * dl23 * dl24; + const double dcl3 = dl13 * dl23 * dl34; + + const double dl1 = y - yvec[0]; + const double dl2 = y - yvec[1]; + const double dl3 = y - yvec[2]; + const double dl4 = y - yvec[3]; + + auto& weights_j = weights.weights_j; + weights_j[0] = ( dl2 * dl3 * dl4 ) / dcl1; + weights_j[1] = ( dl1 * dl3 * dl4 ) / dcl2; + weights_j[2] = ( dl1 * dl2 * dl4 ) / dcl3; + weights_j[3] = 1. - weights_j[0] - weights_j[1] - weights_j[2]; + } + + template + typename array_t::value_type interpolate( const stencil_t& stencil, const weights_t& weights, + const array_t& input ) const { + using Value = typename array_t::value_type; + + std::array, stencil_width()> index; + const auto& weights_j = weights.weights_j; + Value output = 0.; + // LINEAR for outer rows ( j = {0,3} ) + for ( idx_t j = 0; j < 4; j += 3 ) { + const auto& weights_i = weights.weights_i[j]; + for ( idx_t i : {1, 2} ) { + idx_t n = src_.index( stencil.i( i, j ), stencil.j( j ) ); + Value w = weights_i[i] * weights_j[j]; + output += w * input[n]; + index[j][i] = n; + } + } + // CUBIC for inner rows ( j = {1,2} ) + for ( idx_t j = 1; j < 3; ++j ) { + const auto& weights_i = weights.weights_i[j]; + for ( idx_t i = 0; i < stencil_width(); ++i ) { + idx_t n = src_.index( stencil.i( i, j ), stencil.j( j ) ); + Value w = weights_i[i] * weights_j[j]; + output += w * input[n]; + index[j][i] = n; + } + } + + if ( limiter_ ) { limit( output, index, input ); } + return output; + } + + template + void limit( typename array_t::value_type& output, const std::array, 4>& index, + const array_t& input ) const { + using Scalar = typename array_t::value_type; + // Limit output to max/min of values in stencil marked by '*' + // x x x x + // x *-----* x + // / P | + // x *------ * x + // x x x x + Scalar maxval = std::numeric_limits::lowest(); + Scalar minval = std::numeric_limits::max(); + for ( idx_t j = 1; j < 3; ++j ) { + for ( idx_t i = 1; i < 3; ++i ) { + idx_t n = index[j][i]; + Scalar val = input[n]; + maxval = std::max( maxval, val ); + minval = std::min( minval, val ); + } + } + if ( output < minval ) { output = minval; } + else if ( output > maxval ) { + output = maxval; + } + } + + + template + typename std::enable_if<( Rank == 1 ), void>::type interpolate( const stencil_t& stencil, const weights_t& weights, + const array::ArrayView& input, + array::ArrayView& output, + idx_t r ) const { + std::array, stencil_width()> index; + const auto& weights_j = weights.weights_j; + output( r ) = 0.; + + // LINEAR for outer rows ( j = {0,3} ) + for ( idx_t j = 0; j < 4; j += 3 ) { + const auto& weights_i = weights.weights_i[j]; + for ( idx_t i = 1; i < 3; ++i ) { // i = {1,2} + idx_t n = src_.index( stencil.i( i, j ), stencil.j( j ) ); + Value w = weights_i[i] * weights_j[j]; + output( r ) += w * input[n]; + index[j][i] = n; + } + } + // CUBIC for inner rows ( j = {1,2} ) + for ( idx_t j = 1; j < 3; ++j ) { + const auto& weights_i = weights.weights_i[j]; + for ( idx_t i = 0; i < stencil_width(); ++i ) { + idx_t n = src_.index( stencil.i( i, j ), stencil.j( j ) ); + Value w = weights_i[i] * weights_j[j]; + output( r ) += w * input[n]; + index[j][i] = n; + } + } + + if ( limiter_ ) { limit( index, input, output, r ); } + } + + template + typename std::enable_if<( Rank == 1 ), void>::type limit( const std::array, 4>& index, + const array::ArrayView& input, + array::ArrayView& output, idx_t r ) const { + // Limit output to max/min of values in stencil marked by '*' + // x x x x + // x *-----* x + // / P | + // x *------ * x + // x x x x + Value maxval = std::numeric_limits::lowest(); + Value minval = std::numeric_limits::max(); + for ( idx_t j = 1; j < 3; ++j ) { + for ( idx_t i = 1; i < 3; ++i ) { + idx_t n = index[j][i]; + Value val = input[n]; + maxval = std::max( maxval, val ); + minval = std::min( minval, val ); + } + } + if ( output( r ) < minval ) { output( r ) = minval; } + else if ( output( r ) > maxval ) { + output( r ) = maxval; + } + } + + template + typename std::enable_if<( Rank == 2 ), void>::type interpolate( const stencil_t& stencil, const weights_t& weights, + const array::ArrayView& input, + array::ArrayView& output, + idx_t r ) const { + std::array, stencil_width()> index; + const auto& weights_j = weights.weights_j; + const idx_t Nk = output.shape( 1 ); + for ( idx_t k = 0; k < Nk; ++k ) { + output( r, k ) = 0.; + } + + // LINEAR for outer rows ( j = {0,3} ) + for ( idx_t j = 0; j < 4; j += 3 ) { + const auto& weights_i = weights.weights_i[j]; + for ( idx_t i = 1; i < 3; ++i ) { // i = {1,2} + idx_t n = src_.index( stencil.i( i, j ), stencil.j( j ) ); + Value w = weights_i[i] * weights_j[j]; + for ( idx_t k = 0; k < Nk; ++k ) { + output( r, k ) += w * input( n, k ); + } + index[j][i] = n; + } + } + // CUBIC for inner rows ( j = {1,2} ) + for ( idx_t j = 1; j < 3; ++j ) { + const auto& weights_i = weights.weights_i[j]; + for ( idx_t i = 0; i < stencil_width(); ++i ) { + idx_t n = src_.index( stencil.i( i, j ), stencil.j( j ) ); + Value w = weights_i[i] * weights_j[j]; + for ( idx_t k = 0; k < Nk; ++k ) { + output( r, k ) += w * input( n, k ); + } + index[j][i] = n; + } + } + + if ( limiter_ ) { limit( index, input, output, r ); } + } + + template + typename std::enable_if<( Rank == 2 ), void>::type limit( const std::array, 4>& index, + const array::ArrayView& input, + array::ArrayView& output, idx_t r ) const { + // Limit output to max/min of values in stencil marked by '*' + // x x x x + // x *-----* x + // / P | + // x *------ * x + // x x x x + for ( idx_t k = 0; k < output.shape( 1 ); ++k ) { + Value maxval = std::numeric_limits::lowest(); + Value minval = std::numeric_limits::max(); + for ( idx_t j = 1; j < 3; ++j ) { + for ( idx_t i = 1; i < 3; ++i ) { + idx_t n = index[j][i]; + Value val = input( n, k ); + maxval = std::max( maxval, val ); + minval = std::min( minval, val ); + } + } + if ( output( r, k ) < minval ) { output( r, k ) = minval; } + else if ( output( r, k ) > maxval ) { + output( r, k ) = maxval; + } + } + } + + + template + typename array_t::value_type operator()( const double x, const double y, const array_t& input ) const { + Stencil stencil; + compute_stencil( x, y, stencil ); + Weights weights; + compute_weights( x, y, stencil, weights ); + return interpolate( stencil, weights, input ); + } + + template + typename array_t::value_type interpolate( const PointLonLat& p, const array_t& input, WorkSpace& ws ) const { + compute_stencil( p.lon(), p.lat(), ws.stencil ); + compute_weights( p.lon(), p.lat(), ws.stencil, ws.weights ); + return interpolate( ws.stencil, ws.weights, input ); + } + + // Thread private workspace + Triplets compute_triplets( const idx_t row, const double x, const double y, WorkSpace& ws ) const { + Triplets triplets; + triplets.reserve( stencil_size() ); + insert_triplets( row, x, y, triplets, ws ); + return triplets; + } + + Triplets reserve_triplets( size_t N ) { + Triplets triplets; + triplets.reserve( N * stencil_size() ); + return triplets; + } + + Triplets allocate_triplets( size_t N ) { return Triplets( N * stencil_size() ); } + + void insert_triplets( const idx_t row, const PointXY& p, Triplets& triplets, WorkSpace& ws ) const { + insert_triplets( row, p.x(), p.y(), triplets, ws ); + } + + void insert_triplets( const idx_t row, const double x, const double y, Triplets& triplets, WorkSpace& ws ) const { + compute_horizontal_stencil_( x, y, ws.stencil ); + compute_weights( x, y, ws.stencil, ws.weights ); + const auto& wj = ws.weights.weights_j; + + idx_t pos = row * stencil_size(); + + // LINEAR for outer rows ( j = {0,3} ) + for ( idx_t j = 0; j < 4; j += 3 ) { + const auto& wi = ws.weights.weights_i[j]; + for ( idx_t i = 1; i < 3; ++i ) { // i = {1,2} + idx_t col = src_.index( ws.stencil.i( i, j ), ws.stencil.j( j ) ); + double w = wi[i] * wj[j]; + triplets[pos++] = Triplet( row, col, w ); + } + } + + // CUBIC for inner rows ( j = {1,2} ) + for ( idx_t j = 1; j < 3; ++j ) { + const auto& wi = ws.weights.weights_i[j]; + for ( idx_t i = 0; i < stencil_width(); ++i ) { + idx_t col = src_.index( ws.stencil.i( i, j ), ws.stencil.j( j ) ); + double w = wi[i] * wj[j]; + triplets[pos++] = Triplet( row, col, w ); + } + } + } +}; + +} // namespace method +} // namespace interpolation +} // namespace atlas diff --git a/src/atlas/library/Library.cc b/src/atlas/library/Library.cc index 92e99b845..5d705eec9 100644 --- a/src/atlas/library/Library.cc +++ b/src/atlas/library/Library.cc @@ -8,8 +8,10 @@ * nor does it submit to any jurisdiction. */ +#include +#include -#include "eckit/eckit_config.h" +#include "eckit/eckit.h" #include "eckit/filesystem/LocalPathName.h" #include "eckit/filesystem/PathName.h" #include "eckit/log/Log.h" @@ -73,8 +75,8 @@ Library::Library() : debug_( eckit::system::Library::debug() ), info_( getEnv( "ATLAS_INFO", true ) ), trace_( getEnv( "ATLAS_TRACE", false ) ), - trace_report_( getEnv( "ATLAS_TRACE_REPORT", false ) ), - trace_barriers_( getEnv( "ATLAS_TRACE_BARRIERS", false ) ) {} + trace_barriers_( getEnv( "ATLAS_TRACE_BARRIERS", false ) ), + trace_report_( getEnv( "ATLAS_TRACE_REPORT", false ) ) {} Library& Library::instance() { return libatlas; @@ -103,9 +105,10 @@ void Library::initialise( int argc, char** argv ) { atlas::Log::debug().reset(); } Log::debug() << "Atlas initialised eckit::Main.\n"; - if ( eckit::mpi::comm( "world" ).size() > 1 ) + if ( eckit::mpi::comm( "world" ).size() > 1 ) { Log::debug() << "--> Only MPI rank 0 is logging. Please initialise eckit::Main \n" " before to avoid this behaviour.\n"; + } } initialise(); } @@ -126,7 +129,7 @@ void Library::initialise( const eckit::Parametrisation& config ) { if ( not info_ ) info_channel_.reset(); // Summary - if ( getEnv( "ATLAS_LOG_RANK", 0 ) == mpi::comm().rank() ) { + if ( getEnv( "ATLAS_LOG_RANK", 0 ) == int( mpi::comm().rank() ) ) { std::ostream& out = Log::debug(); out << "Executable [" << Main::instance().name() << "]\n"; out << " \n"; @@ -155,6 +158,11 @@ void Library::initialise() { void Library::finalise() { if ( ATLAS_HAVE_TRACE && trace_report_ ) { Log::info() << atlas::Trace::report() << std::endl; } + if ( getEnv( "ATLAS_FINALISES_MPI", false ) ) { + Log::debug() << "ATLAS_FINALISES_MPI is set: calling eckit::mpi::finaliseAllComms()" << std::endl; + eckit::mpi::finaliseAllComms(); + } + // Make sure that these specialised channels that wrap Log::info() are // destroyed before eckit::Log::info gets destroyed. // Just in case someone still tries to log, we reset to empty channels. @@ -252,6 +260,7 @@ void Library::Information::print( std::ostream& out ) const { << " MKL : " << str( feature_MKL ) << '\n' << " Tesselation : " << str( feature_Tesselation ) << '\n' << " ArrayDataStore : " << array_data_store << '\n' + << " idx_t : " << ATLAS_BITS_LOCAL << " bit integer" << '\n' << " gidx_t : " << ATLAS_BITS_GLOBAL << " bit integer" << '\n' << " \n"; diff --git a/src/atlas/library/Library.h b/src/atlas/library/Library.h index 0478d4397..373a540fc 100644 --- a/src/atlas/library/Library.h +++ b/src/atlas/library/Library.h @@ -60,9 +60,9 @@ class Library : public eckit::system::Library { protected: virtual const void* addr() const override; + bool debug_{false}; bool info_{true}; bool trace_{false}; - bool debug_{false}; bool trace_barriers_{false}; bool trace_report_{false}; mutable std::unique_ptr info_channel_; diff --git a/src/atlas/library/config.h b/src/atlas/library/config.h index 68793efeb..71502e9f0 100644 --- a/src/atlas/library/config.h +++ b/src/atlas/library/config.h @@ -1,8 +1,18 @@ +/* + * (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 -#include "eckit/eckit_config.h" +#include "eckit/eckit.h" #include "atlas/atlas_ecbuild_config.h" #include "atlas/library/defines.h" @@ -21,9 +31,13 @@ typedef long gidx_t; /// @typedef idx_t /// Integer type for indices in connectivity tables +#if ( ATLAS_BITS_LOCAL == 32 ) typedef int idx_t; +#else +typedef long idx_t; +#endif /// @typedef uidx_t /// Integer type for unique indices -typedef long uidx_t; -} +typedef gidx_t uidx_t; +} // namespace atlas diff --git a/src/atlas/library/defines.h.in b/src/atlas/library/defines.h.in index e8050e1fe..3d1848bf6 100644 --- a/src/atlas/library/defines.h.in +++ b/src/atlas/library/defines.h.in @@ -1,3 +1,16 @@ +#if 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. + */ +// clang-format off +#endif + #ifndef atlas_library_defines_h #define atlas_library_defines_h @@ -30,5 +43,6 @@ #define ATLAS_HOST #endif +#define ATLAS_BITS_LOCAL @ATLAS_BITS_LOCAL@ #endif diff --git a/src/atlas/library/git_sha1.h.in b/src/atlas/library/git_sha1.h.in index 5ef047dc5..402fbdfb6 100644 --- a/src/atlas/library/git_sha1.h.in +++ b/src/atlas/library/git_sha1.h.in @@ -1,19 +1,27 @@ +/* + * (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 #define ATLAS_GIT_SHA1 "@ATLAS_GIT_SHA1@" -#include #include +#include namespace atlas { namespace library { -inline const char* git_sha1(unsigned int chars=7) { - static std::string sha1(ATLAS_GIT_SHA1); - if(sha1.empty()) { - return "not available"; - } - sha1 = sha1.substr(0, std::min(chars,40u)); +inline const char* git_sha1( unsigned int chars = 7 ) { + static std::string sha1( ATLAS_GIT_SHA1 ); + if ( sha1.empty() ) { return "not available"; } + sha1 = sha1.substr( 0, std::min( chars, 40u ) ); return sha1.c_str(); } -} -} \ No newline at end of file +} // namespace library +} // namespace atlas diff --git a/src/atlas/library/version.h.in b/src/atlas/library/version.h.in index 8452089f3..f4fbba80c 100644 --- a/src/atlas/library/version.h.in +++ b/src/atlas/library/version.h.in @@ -1,3 +1,13 @@ +/* + * (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 #define ATLAS_VERSION_STR "@ATLAS_VERSION_STR@" diff --git a/src/atlas/mesh/Connectivity.cc b/src/atlas/mesh/Connectivity.cc index 91a6177fb..983527fd6 100644 --- a/src/atlas/mesh/Connectivity.cc +++ b/src/atlas/mesh/Connectivity.cc @@ -8,15 +8,16 @@ * nor does it submit to any jurisdiction. */ +#include #include #include "atlas/array.h" #include "atlas/array/DataType.h" #include "atlas/array/MakeView.h" #include "atlas/array/Vector.h" -#include "atlas/library/defines.h" +#include "atlas/library/config.h" #include "atlas/mesh/Connectivity.h" -#include "atlas/runtime/ErrorHandling.h" +#include "atlas/runtime/Exception.h" #if ATLAS_HAVE_FORTRAN #define FORTRAN_BASE 1 @@ -32,30 +33,26 @@ namespace mesh { IrregularConnectivityImpl::IrregularConnectivityImpl( const std::string& name ) : owns_( true ), - data_{array::Array::create( 0 ), // values - array::Array::create( 1 ), // displs - array::Array::create( 1 )}, // counts - values_view_( array::make_host_view( *( data_[_values_] ) ) ), - displs_view_( array::make_host_view( *( data_[_displs_] ) ) ), - counts_view_( array::make_host_view( *( data_[_counts_] ) ) ), + values_( 0 ), + displs_( 1 ), + counts_( 1 ), missing_value_( std::numeric_limits::is_signed ? -1 : std::numeric_limits::max() ), rows_( 0 ), maxcols_( 0 ), - mincols_( std::numeric_limits::max() ), - ctxt_( 0 ), - callback_update_( 0 ), - callback_delete_( 0 ), - gpu_clone_( this ) { + mincols_( std::numeric_limits::max() ), + ctxt_( nullptr ), + callback_update_( nullptr ), + callback_delete_( nullptr ) { rename( name ); - displs_view_( 0 ) = 0; - counts_view_( 0 ) = 0; + displs_[0] = 0; + counts_[0] = 0; } // ----------------------------------------------------------------------------- -size_t get_total_size_counts( size_t rows, size_t counts[] ) { - size_t total_size = 0; - for ( size_t j = 0; j < rows; ++j ) { +idx_t get_total_size_counts( idx_t rows, idx_t counts[] ) { + idx_t total_size = 0; + for ( idx_t j = 0; j < rows; ++j ) { total_size += counts[j]; } return total_size; @@ -63,23 +60,20 @@ size_t get_total_size_counts( size_t rows, size_t counts[] ) { // ----------------------------------------------------------------------------- -IrregularConnectivityImpl::IrregularConnectivityImpl( idx_t values[], size_t rows, size_t displs[], size_t counts[] ) : +IrregularConnectivityImpl::IrregularConnectivityImpl( idx_t values[], idx_t rows, idx_t displs[], idx_t counts[] ) : owns_( false ), - data_{array::Array::wrap( values, array::ArrayShape{get_total_size_counts( rows, counts )} ), - array::Array::wrap( displs, array::ArrayShape{rows} ), - array::Array::wrap( counts, array::ArrayShape{rows} )}, - values_view_( array::make_view( *( data_[_values_] ) ) ), - displs_view_( array::make_view( *( data_[_displs_] ) ) ), - counts_view_( array::make_view( *( data_[_counts_] ) ) ), + //TODO need to create clone if pointers are not cuda managed + values_( values, get_total_size_counts( rows, counts ) ), + displs_( displs, rows ), + counts_( counts, rows ), missing_value_( std::numeric_limits::is_signed ? -1 : std::numeric_limits::max() ), rows_( rows ), - ctxt_( 0 ), - callback_update_( 0 ), - callback_delete_( 0 ), - gpu_clone_( this ) { + ctxt_( nullptr ), + callback_update_( nullptr ), + callback_delete_( nullptr ) { maxcols_ = 0; - mincols_ = std::numeric_limits::max(); - for ( size_t j = 0; j < rows; ++j ) { + mincols_ = std::numeric_limits::max(); + for ( idx_t j = 0; j < rows; ++j ) { maxcols_ = std::max( maxcols_, counts[j] ); mincols_ = std::min( mincols_, counts[j] ); } @@ -87,51 +81,43 @@ IrregularConnectivityImpl::IrregularConnectivityImpl( idx_t values[], size_t row IrregularConnectivityImpl::IrregularConnectivityImpl( const IrregularConnectivityImpl& other ) : owns_( false ), - data_{other.data_[0], other.data_[1], other.data_[2]}, - values_view_( other.values_view_ ), - displs_view_( other.displs_view_ ), - counts_view_( other.counts_view_ ), + values_( other.values_ ), + displs_( other.displs_ ), + counts_( other.counts_ ), missing_value_( other.missing_value_ ), rows_( other.rows_ ), maxcols_( other.maxcols_ ), mincols_( other.mincols_ ), - ctxt_( 0 ), - gpu_clone_( this ) {} + ctxt_( nullptr ) {} //------------------------------------------------------------------------------------------------------ IrregularConnectivityImpl::~IrregularConnectivityImpl() { on_delete(); - - if ( owns_ ) { - std::for_each( data_.begin(), data_.end(), []( array::Array* a ) { - assert( a ); - delete a; - a = 0; - } ); - } + //TODO owns is unsed ? } //------------------------------------------------------------------------------------------------------ void IrregularConnectivityImpl::clear() { + //TODO clean this if ( owns() ) { - data_[_values_]->resize( 0 ); - data_[_displs_]->resize( 1 ); - data_[_counts_]->resize( 1 ); - displs_view_ = array::make_view( *( data_[_displs_] ) ); - counts_view_ = array::make_view( *( data_[_counts_] ) ); - displs_view_( 0 ) = 0; - counts_view_( 0 ) = 0; + values_.resize( 0 ); + displs_.resize( 1 ); + counts_.resize( 1 ); + displs_( 0 ) = 0; + counts_( 0 ) = 0; } else { - data_[_values_] = nullptr; - data_[_displs_] = nullptr; - data_[_counts_] = nullptr; + //TODO what to do here + // data_[_values_] = nullptr; + // data_[_displs_] = nullptr; + // data_[_counts_] = nullptr; // std::for_each(data_.begin(), data_.end(), [](array::Array* a){ a=0;}); } + rows_ = 0; maxcols_ = 0; - mincols_ = std::numeric_limits::max(); + mincols_ = std::numeric_limits::max(); on_update(); } @@ -147,44 +133,42 @@ void IrregularConnectivityImpl::on_update() { if ( ctxt_ && callback_update_ ) callback_update_( ctxt_ ); } -void IrregularConnectivityImpl::resize( size_t old_size, size_t new_size, bool initialize, const idx_t values[], +void IrregularConnectivityImpl::resize( idx_t old_size, idx_t new_size, bool initialize, const idx_t values[], bool fortran_array ) { - data_[_values_]->resize( new_size ); - values_view_ = array::make_view( *( data_[_values_] ) ); - // TODO WILLEM isnt this if the other way around? + values_.resize( new_size ); + idx_t add_base = fortran_array ? 0 : FORTRAN_BASE; if ( initialize ) { - for ( size_t j = 0, c = old_size; c < new_size; ++c, ++j ) { - values_view_( c ) = values[j] + add_base; + for ( idx_t j = 0, c = old_size; c < new_size; ++c, ++j ) { + values_[c] = values[j] + add_base; } } else { - for ( size_t j = old_size; j < new_size; ++j ) { - values_view_( j ) = missing_value() TO_FORTRAN; + for ( idx_t j = old_size; j < new_size; ++j ) { + values_[j] = missing_value() TO_FORTRAN; } } } //------------------------------------------------------------------------------------------------------ -void IrregularConnectivityImpl::add( size_t rows, size_t cols, const idx_t values[], bool fortran_array ) { - if ( !owns_ ) throw eckit::AssertionFailed( "HybridConnectivity must be owned to be resized directly" ); - size_t old_size = data_[_values_]->size(); +void IrregularConnectivityImpl::add( idx_t rows, idx_t cols, const idx_t values[], bool fortran_array ) { + ATLAS_ASSERT( owns_, "Connectivity must be owned to be resized directly" ); + idx_t old_size = values_.size(); if ( rows_ == 0 ) old_size = 0; - size_t new_size = old_size + rows * cols; - size_t new_rows = rows_ + rows; + idx_t new_size = old_size + rows * cols; + idx_t new_rows = rows_ + rows; - ASSERT( data_[_displs_] != 0 ); - ASSERT( data_[_counts_] != 0 ); - data_[_displs_]->resize( new_rows + 1 ); - data_[_counts_]->resize( new_rows + 1 ); - displs_view_ = array::make_view( *( data_[_displs_] ) ); - counts_view_ = array::make_view( *( data_[_counts_] ) ); + //TODO what to do here + // ATLAS_ASSERT( displs_] != nullptr ); + // ATLAS_ASSERT( data_[_counts_] != nullptr ); + displs_.resize( new_rows + 1 ); + counts_.resize( new_rows + 1 ); - for ( size_t j = 0; rows_ < new_rows; ++rows_, ++j ) { - displs_view_( rows_ + 1 ) = displs_view_( rows_ ) + cols; - counts_view_( rows_ ) = cols; + for ( idx_t j = 0; rows_ < new_rows; ++rows_, ++j ) { + displs_[rows_ + 1] = displs_[rows_] + cols; + counts_[rows_] = cols; } maxcols_ = std::max( maxcols_, cols ); @@ -198,82 +182,66 @@ void IrregularConnectivityImpl::add( size_t rows, size_t cols, const idx_t value //------------------------------------------------------------------------------------------------------ void IrregularConnectivityImpl::add( const BlockConnectivityImpl& block ) { - if ( !owns_ ) throw eckit::AssertionFailed( "HybridConnectivity must be owned to be resized directly" ); + ATLAS_ASSERT( owns_, "Connectivity must be owned to be resized directly" ); bool fortran_array = FORTRAN_BASE; - const size_t rows = block.rows(); - const size_t cols = block.cols(); + const idx_t rows = block.rows(); + const idx_t cols = block.cols(); const idx_t* values = block.data(); - std::vector values_vector; - if ( !block.values_view_.contiguous() ) { - values_vector.resize( rows * cols ); - values = values_vector.data(); - for ( int i = 0, c = 0; i < rows; ++i ) { - for ( int j = 0; j < cols; ++j ) { - values_vector[c++] = block( i, j ); - } - } - fortran_array = false; - } - add( rows, cols, values, fortran_array ); } //------------------------------------------------------------------------------------------------------ -void IrregularConnectivityImpl::add( size_t rows, const size_t cols[] ) { - if ( !owns_ ) throw eckit::AssertionFailed( "HybridConnectivity must be owned to be resized directly" ); - size_t old_size = data_[_values_]->size(); - size_t new_size = old_size; - for ( size_t j = 0; j < rows; ++j ) +void IrregularConnectivityImpl::add( idx_t rows, const idx_t cols[] ) { + ATLAS_ASSERT( owns_, "Connectivity must be owned to be resized directly" ); + idx_t old_size = values_.size(); + idx_t new_size = old_size; + for ( idx_t j = 0; j < rows; ++j ) new_size += cols[j]; - size_t new_rows = rows_ + rows; - data_[_displs_]->resize( new_rows + 1 ); - data_[_counts_]->resize( new_rows + 1 ); - displs_view_ = array::make_view( *( data_[_displs_] ) ); - counts_view_ = array::make_view( *( data_[_counts_] ) ); - - for ( size_t j = 0; rows_ < new_rows; ++rows_, ++j ) { - // TODO isnt this a bug ? I dont understand - displs_view_( rows_ + 1 ) = displs_view_( rows_ ) + cols[j]; - counts_view_( rows_ ) = cols[j]; - maxcols_ = std::max( maxcols_, cols[j] ); - mincols_ = std::min( mincols_, cols[j] ); + idx_t new_rows = rows_ + rows; + displs_.resize( new_rows + 1 ); + counts_.resize( new_rows + 1 ); + + for ( idx_t j = 0; rows_ < new_rows; ++rows_, ++j ) { + displs_[rows_ + 1] = displs_[rows_] + cols[j]; + counts_[rows_] = cols[j]; + maxcols_ = std::max( maxcols_, cols[j] ); + mincols_ = std::min( mincols_, cols[j] ); } - resize( old_size, new_size, false, NULL, false ); + resize( old_size, new_size, false, nullptr, false ); on_update(); } //------------------------------------------------------------------------------------------------------ -void IrregularConnectivityImpl::add( size_t rows, size_t cols ) { - if ( !owns_ ) throw eckit::AssertionFailed( "HybridConnectivity must be owned to be resized directly" ); - size_t old_size = data_[_values_]->size(); +void IrregularConnectivityImpl::add( idx_t rows, idx_t cols ) { + ATLAS_ASSERT( owns_, "Connectivity must be owned to be resized directly" ); + idx_t old_size = values_.size(); if ( rows_ == 0 ) old_size = 0; - size_t new_size = old_size + rows * cols; - size_t new_rows = rows_ + rows; + idx_t new_size = old_size + rows * cols; + idx_t new_rows = rows_ + rows; - ASSERT( data_[_displs_] != 0 ); - ASSERT( data_[_counts_] != 0 ); - data_[_displs_]->resize( new_rows + 1 ); - data_[_counts_]->resize( new_rows + 1 ); - displs_view_ = array::make_view( *( data_[_displs_] ) ); - counts_view_ = array::make_view( *( data_[_counts_] ) ); + //TODO + // ATLAS_ASSERT( data_[_displs_] != nullptr ); + // ATLAS_ASSERT( data_[_counts_] != nullptr ); + displs_.resize( new_rows + 1 ); + counts_.resize( new_rows + 1 ); - for ( size_t j = 0; rows_ < new_rows; ++rows_, ++j ) { - displs_view_( rows_ + 1 ) = displs_view_( rows_ ) + cols; - counts_view_( rows_ ) = cols; + for ( idx_t j = 0; rows_ < new_rows; ++rows_, ++j ) { + displs_[rows_ + 1] = displs_[rows_] + cols; + counts_[rows_] = cols; } maxcols_ = std::max( maxcols_, cols ); mincols_ = std::min( mincols_, cols ); const bool dummy_arg_fortran_array = false; - const idx_t* dummy_arg_values = NULL; + const idx_t* dummy_arg_values = nullptr; resize( old_size, new_size, false, dummy_arg_values, dummy_arg_fortran_array ); on_update(); @@ -281,37 +249,34 @@ void IrregularConnectivityImpl::add( size_t rows, size_t cols ) { //------------------------------------------------------------------------------------------------------ -void IrregularConnectivityImpl::insert( size_t position, size_t rows, size_t cols, const idx_t values[], +void IrregularConnectivityImpl::insert( idx_t position, idx_t rows, idx_t cols, const idx_t values[], bool fortran_array ) { - if ( !owns_ ) throw eckit::AssertionFailed( "HybridConnectivity must be owned to be resized directly" ); - size_t position_displs = displs_view_( position ); - data_[_displs_]->insert( position, rows ); - data_[_counts_]->insert( position, rows ); - displs_view_ = array::make_view( *( data_[_displs_] ) ); - counts_view_ = array::make_view( *( data_[_counts_] ) ); - - displs_view_( position ) = position_displs; - for ( size_t jrow = position; jrow < position + rows; ++jrow ) { - counts_view_( jrow ) = cols; + ATLAS_ASSERT( owns_, "Connectivity must be owned to be resized directly" ); + idx_t position_displs = displs_[position]; + displs_.insert( position, rows ); + counts_.insert( position, rows ); + + displs_[position] = position_displs; + for ( idx_t jrow = position; jrow < position + rows; ++jrow ) { + counts_[jrow] = cols; } - for ( size_t jrow = position; jrow < displs_view_.size() - 1; ++jrow ) { - displs_view_( jrow + 1 ) = displs_view_( jrow ) + counts_view_( jrow ); + for ( idx_t jrow = position; jrow < displs_.size() - 1; ++jrow ) { + displs_[jrow + 1] = displs_[jrow] + counts_[jrow]; } maxcols_ = std::max( maxcols_, cols ); mincols_ = std::min( mincols_, cols ); - data_[_values_]->insert( position_displs, rows * cols ); - values_view_ = array::make_view( *( data_[_values_] ) ); + values_.insert( position_displs, rows * cols ); - if ( values == NULL ) { - for ( size_t c = position_displs; c < position_displs + rows * cols; ++c ) { - values_view_( c ) = missing_value() TO_FORTRAN; + if ( values == nullptr ) { + for ( idx_t c = position_displs; c < position_displs + rows * cols; ++c ) { + values_[c] = missing_value() TO_FORTRAN; } } else { idx_t add_base = fortran_array ? 0 : FORTRAN_BASE; - for ( size_t c = position_displs; c < position_displs + rows * cols; ++c ) { - values_view_( c ) = values[c - position_displs] + add_base; + for ( idx_t c = position_displs; c < position_displs + rows * cols; ++c ) { + values_[c] = values[c - position_displs] + add_base; } } rows_ += rows; @@ -321,94 +286,61 @@ void IrregularConnectivityImpl::insert( size_t position, size_t rows, size_t col //------------------------------------------------------------------------------------------------------ -void IrregularConnectivityImpl::insert( size_t position, size_t rows, size_t cols ) { - IrregularConnectivityImpl::insert( position, rows, cols, NULL, false ); +void IrregularConnectivityImpl::insert( idx_t position, idx_t rows, idx_t cols ) { + IrregularConnectivityImpl::insert( position, rows, cols, nullptr, false ); } //------------------------------------------------------------------------------------------------------ -void IrregularConnectivityImpl::insert( size_t position, size_t rows, const size_t cols[] ) { - if ( !owns_ ) throw eckit::AssertionFailed( "HybridConnectivity must be owned to be resized directly" ); - size_t position_displs = displs_view_( position ); +void IrregularConnectivityImpl::insert( idx_t position, idx_t rows, const idx_t cols[] ) { + ATLAS_ASSERT( owns_, "Connectivity must be owned to be resized directly" ); + idx_t position_displs = displs_[position]; if ( rows_ == 0 ) { if ( position > 1 ) { - data_[_displs_]->insert( position - 1, rows ); - data_[_counts_]->insert( position - 1, rows ); + displs_.insert( position - 1, rows ); + counts_.insert( position - 1, rows ); } } else { - data_[_displs_]->insert( position, rows ); - data_[_counts_]->insert( position, rows ); + displs_.insert( position, rows ); + counts_.insert( position, rows ); } - displs_view_ = array::make_view( *( data_[_displs_] ) ); - counts_view_ = array::make_view( *( data_[_counts_] ) ); - - displs_view_( position ) = position_displs; - for ( size_t jrow = position; jrow < position + rows; ++jrow ) { - counts_view_( jrow ) = cols[jrow - position]; - maxcols_ = std::max( maxcols_, counts_view_( jrow ) ); - mincols_ = std::min( mincols_, counts_view_( jrow ) ); + + displs_[position] = position_displs; + for ( idx_t jrow = position; jrow < position + rows; ++jrow ) { + counts_[jrow] = cols[jrow - position]; + maxcols_ = std::max( maxcols_, counts_[jrow] ); + mincols_ = std::min( mincols_, counts_[jrow] ); } - for ( size_t jrow = position; jrow < displs_view_.size() - 1; ++jrow ) { - displs_view_( jrow + 1 ) = displs_view_( jrow ) + counts_view_( jrow ); + for ( idx_t jrow = position; jrow < displs_.size() - 1; ++jrow ) { + displs_[jrow + 1] = displs_[jrow] + counts_[jrow]; } - size_t insert_size( 0 ); - for ( size_t j = 0; j < rows; ++j ) + idx_t insert_size( 0 ); + for ( idx_t j = 0; j < rows; ++j ) insert_size += cols[j]; - data_[_values_]->insert( position_displs, insert_size ); - values_view_ = array::make_view( *( data_[_values_] ) ); + values_.insert( position_displs, insert_size ); - for ( size_t c = position_displs; c < position_displs + insert_size; ++c ) { - values_view_( c ) = missing_value() TO_FORTRAN; + for ( idx_t c = position_displs; c < position_displs + insert_size; ++c ) { + values_[c] = missing_value() TO_FORTRAN; } rows_ += rows; on_update(); } -void IrregularConnectivityImpl::cloneToDevice() { - std::for_each( data_.begin(), data_.end(), []( array::Array* a ) { a->cloneToDevice(); } ); - values_view_ = array::make_device_view( *( data_[_values_] ) ); - displs_view_ = array::make_device_view( *( data_[_displs_] ) ); - counts_view_ = array::make_device_view( *( data_[_counts_] ) ); - gpu_clone_.cloneToDevice(); -} -void IrregularConnectivityImpl::cloneFromDevice() { - std::for_each( data_.begin(), data_.end(), []( array::Array* a ) { a->cloneFromDevice(); } ); - values_view_ = array::make_host_view( *( data_[_values_] ) ); - displs_view_ = array::make_host_view( *( data_[_displs_] ) ); - counts_view_ = array::make_host_view( *( data_[_counts_] ) ); -} -void IrregularConnectivityImpl::syncHostDevice() const { - std::for_each( data_.begin(), data_.end(), []( array::Array* a ) { a->syncHostDevice(); } ); -} -bool IrregularConnectivityImpl::valid() const { - bool res = true; - std::for_each( data_.begin(), data_.end(), [&]( array::Array* a ) { res &= a->valid(); } ); - return res; -} -bool IrregularConnectivityImpl::hostNeedsUpdate() const { - bool res = true; - std::for_each( data_.begin(), data_.end(), [&]( array::Array* a ) { res &= a->hostNeedsUpdate(); } ); - return res; -} -bool IrregularConnectivityImpl::deviceNeedsUpdate() const { - bool res = true; - std::for_each( data_.begin(), data_.end(), [&]( array::Array* a ) { res &= a->deviceNeedsUpdate(); } ); - return res; -} - size_t IrregularConnectivityImpl::footprint() const { size_t size = sizeof( *this ); - std::for_each( data_.begin(), data_.end(), [&]( array::Array* a ) { size += a->footprint(); } ); + size += values_.footprint(); + size += displs_.footprint(); + size += counts_.footprint(); return size; } void IrregularConnectivityImpl::dump( std::ostream& os ) const { - array::make_host_view( *( data_[_values_] ) ).dump( os ); + //TODO dump } //------------------------------------------------------------------------------------------------------ @@ -417,18 +349,18 @@ void IrregularConnectivityImpl::dump( std::ostream& os ) const { //------------------------------------------------------------------------------------------------------ -MultiBlockConnectivity::MultiBlockConnectivity( idx_t values[], size_t rows, -size_t displs[], size_t counts[], size_t blocks, size_t block_displs[], size_t +MultiBlockConnectivity::MultiBlockConnectivity( idx_t values[], idx_t rows, +idx_t displs[], idx_t counts[], idx_t blocks, idx_t block_displs[], idx_t block_cols[] ) : IrregularConnectivity(values,rows,displs,counts), blocks_(blocks), - block_displs_(array::Array::wrap(block_displs, + block_displs_(array::Array::wrap(block_displs, array::ArrayShape{blocks})), - block_cols_(array::Array::wrap(block_cols, + block_cols_(array::Array::wrap(block_cols, array::ArrayShape{blocks})), block_(blocks), - block_displs_view_(array::make_view(*block_displs_)), - block_cols_view_(array::make_view(*block_cols_)) + block_displs_view_(array::make_view(*block_displs_)), + block_cols_view_(array::make_view(*block_cols_)) { rebuild_block_connectivity(); } @@ -438,98 +370,42 @@ array::ArrayShape{blocks})), MultiBlockConnectivityImpl::MultiBlockConnectivityImpl( const std::string& name ) : IrregularConnectivityImpl( name ), blocks_( 0 ), - block_displs_( array::Array::create( 1 ) ), - block_cols_( array::Array::create( 1 ) ), - block_displs_view_( array::make_view( *block_displs_ ) ), - block_cols_view_( array::make_view( *block_cols_ ) ), - block_( 0 ), - block_view_( make_host_vector_view( block_ ) ), - gpu_clone_( this ) { - block_displs_view_( 0 ) = 0; + block_displs_( 1 ), + block_cols_( 1 ), + block_( 0 ) { + block_displs_( 0 ) = 0; } //------------------------------------------------------------------------------------------------------ -MultiBlockConnectivityImpl::~MultiBlockConnectivityImpl() { - if ( block_displs_ ) delete block_displs_; - if ( block_cols_ ) delete block_cols_; -} +MultiBlockConnectivityImpl::~MultiBlockConnectivityImpl() {} //------------------------------------------------------------------------------------------------------ void MultiBlockConnectivityImpl::clear() { - // TODO - // IrregularConnectivity::clear(); - // if( owns() ) - // { - // block_displs_.resize(1); - // block_displs_[0]=0ul; - // block_cols_.clear(); - // } - // blocks_ = 0; - // block_displs_ = 0; - // block_cols_ = 0; - // block_.clear(); -} - -void MultiBlockConnectivityImpl::cloneToDevice() { - IrregularConnectivityImpl::cloneToDevice(); - block_displs_->cloneToDevice(); - block_cols_->cloneToDevice(); - block_displs_view_ = array::make_device_view( *( block_displs_ ) ); - block_cols_view_ = array::make_device_view( *( block_cols_ ) ); - - block_.cloneToDevice(); - block_view_ = make_device_vector_view( block_ ); - - gpu_clone_.cloneToDevice(); -} - -void MultiBlockConnectivityImpl::cloneFromDevice() { - IrregularConnectivityImpl::cloneFromDevice(); - block_displs_->cloneFromDevice(); - block_cols_->cloneFromDevice(); - block_displs_view_ = array::make_host_view( *( block_displs_ ) ); - block_cols_view_ = array::make_host_view( *( block_cols_ ) ); - - block_.cloneFromDevice(); - block_view_ = make_host_vector_view( block_ ); -} - -void MultiBlockConnectivityImpl::syncHostDevice() const { - IrregularConnectivityImpl::syncHostDevice(); - block_displs_->syncHostDevice(); - block_cols_->syncHostDevice(); -} - -bool MultiBlockConnectivityImpl::valid() const { - return IrregularConnectivityImpl::valid() && block_displs_->valid() && block_cols_->valid(); -} - -bool MultiBlockConnectivityImpl::hostNeedsUpdate() const { - return IrregularConnectivityImpl::hostNeedsUpdate() && block_displs_->hostNeedsUpdate() && - block_cols_->hostNeedsUpdate(); -} - -bool MultiBlockConnectivityImpl::deviceNeedsUpdate() const { - return IrregularConnectivityImpl::deviceNeedsUpdate() && block_displs_->deviceNeedsUpdate() && - block_cols_->deviceNeedsUpdate(); + IrregularConnectivityImpl::clear(); + if ( owns() ) { + block_displs_.resize( 1 ); + block_cols_.resize( 1 ); + block_displs_( 0 ) = 0ul; + } + blocks_ = 0; + block_ = array::SVector( 0 ); } //------------------------------------------------------------------------------------------------------ -void MultiBlockConnectivityImpl::add( size_t rows, size_t cols, const idx_t values[], bool fortran_array ) { - if ( !owns() ) throw eckit::AssertionFailed( "MultiBlockConnectivity must be owned to be resized directly" ); - size_t old_rows = this->rows(); +void MultiBlockConnectivityImpl::add( idx_t rows, idx_t cols, const idx_t values[], bool fortran_array ) { + ATLAS_ASSERT( owns(), "MultiBlockConnectivity must be owned to be resized directly" ); + idx_t old_rows = this->rows(); IrregularConnectivityImpl::add( rows, cols, values, fortran_array ); - block_displs_->insert( block_displs_->size(), 1 ); - block_cols_->insert( block_cols_->size(), 1 ); - block_displs_view_ = array::make_view( *block_displs_ ); - block_cols_view_ = array::make_view( *block_cols_ ); + block_displs_.insert( block_displs_.size(), 1 ); + block_cols_.insert( block_cols_.size(), 1 ); + blocks_++; - block_displs_view_( block_displs_view_.size() - 1 ) = old_rows + rows; - block_cols_view_( block_cols_view_.size() - 2 ) = cols; + block_displs_[block_displs_.size() - 1] = old_rows + rows; + block_cols_[block_cols_.size() - 2] = cols; rebuild_block_connectivity(); } @@ -537,76 +413,70 @@ void MultiBlockConnectivityImpl::add( size_t rows, size_t cols, const idx_t valu //------------------------------------------------------------------------------------------------------ void MultiBlockConnectivityImpl::add( const BlockConnectivityImpl& block ) { - if ( !owns() ) throw eckit::AssertionFailed( "MultiBlockConnectivity must be owned to be resized directly" ); + ATLAS_ASSERT( owns(), "MultiBlockConnectivity must be owned to be resized directly" ); IrregularConnectivityImpl::add( block ); - - block_view_ = make_host_vector_view( block_ ); } //------------------------------------------------------------------------------------------------------ -void MultiBlockConnectivityImpl::add( size_t rows, size_t cols ) { - if ( !owns() ) throw eckit::AssertionFailed( "MultiBlockConnectivity must be owned to be resized directly" ); - size_t old_rows = this->rows(); +void MultiBlockConnectivityImpl::add( idx_t rows, idx_t cols ) { + ATLAS_ASSERT( owns(), "MultiBlockConnectivity must be owned to be resized directly" ); + idx_t old_rows = this->rows(); IrregularConnectivityImpl::add( rows, cols ); - block_displs_->insert( block_displs_->size(), 1 ); - block_cols_->insert( block_cols_->size(), 1 ); - block_displs_view_ = array::make_view( *block_displs_ ); - block_cols_view_ = array::make_view( *block_cols_ ); + block_displs_.insert( block_displs_.size(), 1 ); + block_cols_.insert( block_cols_.size(), 1 ); blocks_++; - block_displs_view_( block_displs_view_.size() - 1 ) = old_rows + rows; - block_cols_view_( block_cols_view_.size() - 2 ) = cols; + + block_displs_[block_displs_.size() - 1] = old_rows + rows; + block_cols_[block_cols_.size() - 2] = cols; rebuild_block_connectivity(); } //------------------------------------------------------------------------------------------------------ -void MultiBlockConnectivityImpl::add( size_t rows, const size_t cols[] ) { - if ( !owns() ) throw eckit::AssertionFailed( "MultiBlockConnectivity must be owned to be resized directly" ); - size_t min = std::numeric_limits::max(); - size_t max = 0; - size_t old_rows = this->rows(); +void MultiBlockConnectivityImpl::add( idx_t rows, const idx_t cols[] ) { + ATLAS_ASSERT( owns(), "MultiBlockConnectivity must be owned to be resized directly" ); + idx_t min = std::numeric_limits::max(); + idx_t max = 0; + idx_t old_rows = this->rows(); - for ( size_t j = 0; j < rows; ++j ) { + for ( idx_t j = 0; j < rows; ++j ) { min = std::min( min, cols[j] ); max = std::min( max, cols[j] ); } - if ( min != max ) - throw eckit::AssertionFailed( - "MultiBlockConnectivity::add(rows,cols[]): " - "all elements of cols[] must be identical" ); + ATLAS_ASSERT( min == max, + "MultiBlockConnectivity::add(rows,cols[]): " + "all elements of cols[] must be identical" ); IrregularConnectivityImpl::add( rows, cols ); - block_displs_->insert( block_displs_->size(), 1 ); - block_cols_->insert( block_cols_->size(), 1 ); - block_displs_view_ = array::make_view( *block_displs_ ); - block_cols_view_ = array::make_view( *block_cols_ ); + block_displs_.insert( block_displs_.size(), 1 ); + block_cols_.insert( block_cols_.size(), 1 ); blocks_++; - block_displs_view_( block_displs_view_.size() - 1 ) = old_rows; - block_cols_view_( block_cols_view_.size() - 2 ) = max; + block_displs_( block_displs_.size() - 1 ) = old_rows; + block_cols_[block_cols_.size() - 2] = max; rebuild_block_connectivity(); } //------------------------------------------------------------------------------------------------------ -void MultiBlockConnectivityImpl::insert( size_t position, size_t rows, size_t cols, const idx_t values[], +void MultiBlockConnectivityImpl::insert( idx_t position, idx_t rows, idx_t cols, const idx_t values[], bool fortran_array ) { - if ( !owns() ) throw eckit::AssertionFailed( "MultiBlockConnectivity must be owned to be resized directly" ); + ATLAS_ASSERT( owns(), "MultiBlockConnectivity must be owned to be resized directly" ); - ASSERT( blocks_ ); + ATLAS_ASSERT( blocks_ ); long blk_idx = blocks_; do { blk_idx--; - } while ( blk_idx >= 0l && block_displs_view_( blk_idx ) >= position && cols != block_cols_view_( blk_idx ) ); - ASSERT( blk_idx >= 0l ); - ASSERT( cols == block( blk_idx ).cols() ); + } while ( blk_idx >= 0l && block_displs_[blk_idx] >= position && cols != block_cols_[blk_idx] ); + ATLAS_ASSERT( blk_idx >= 0l ); + ATLAS_ASSERT( cols == block( blk_idx ).cols() ); - for ( size_t jblk = blk_idx; jblk < blocks_; ++jblk ) - block_displs_view_( jblk + 1 ) += rows; + for ( idx_t jblk = blk_idx; jblk < blocks_; ++jblk ) + block_displs_[jblk + 1] += rows; IrregularConnectivityImpl::insert( position, rows, cols, values, fortran_array ); rebuild_block_connectivity(); @@ -614,70 +484,61 @@ void MultiBlockConnectivityImpl::insert( size_t position, size_t rows, size_t co //------------------------------------------------------------------------------------------------------ -void MultiBlockConnectivityImpl::insert( size_t position, size_t rows, size_t cols ) { - if ( !owns() ) throw eckit::AssertionFailed( "MultiBlockConnectivity must be owned to be resized directly" ); +void MultiBlockConnectivityImpl::insert( idx_t position, idx_t rows, idx_t cols ) { + ATLAS_ASSERT( owns(), "MultiBlockConnectivity must be owned to be resized directly" ); long blk_idx = blocks_; do { blk_idx--; - } while ( blk_idx >= 0l && block_displs_view_( blk_idx ) >= position && cols != block_cols_view_( blk_idx ) ); + } while ( blk_idx >= 0l && block_displs_[blk_idx] >= position && cols != block_cols_[blk_idx] ); - ASSERT( blk_idx >= 0l ); + ATLAS_ASSERT( blk_idx >= 0l ); IrregularConnectivityImpl::insert( position, rows, cols ); - for ( size_t jblk = blk_idx; jblk < blocks_; ++jblk ) - block_displs_view_( jblk + 1 ) += rows; + for ( idx_t jblk = blk_idx; jblk < blocks_; ++jblk ) + block_displs_[jblk + 1] += rows; rebuild_block_connectivity(); } //------------------------------------------------------------------------------------------------------ -void MultiBlockConnectivityImpl::insert( size_t position, size_t rows, const size_t cols[] ) { - if ( !owns() ) throw eckit::AssertionFailed( "MultiBlockConnectivity must be owned to be resized directly" ); - size_t min = std::numeric_limits::max(); - size_t max = 0; - for ( size_t j = 0; j < rows; ++j ) { +void MultiBlockConnectivityImpl::insert( idx_t position, idx_t rows, const idx_t cols[] ) { + ATLAS_ASSERT( owns(), "MultiBlockConnectivity must be owned to be resized directly" ); + + idx_t min = std::numeric_limits::max(); + idx_t max = 0; + for ( idx_t j = 0; j < rows; ++j ) { min = std::min( min, cols[j] ); max = std::min( max, cols[j] ); } - if ( min != max ) - throw eckit::AssertionFailed( - "MultiBlockConnectivity::add(rows,cols[]): " - "all elements of cls[] must be identical" ); + ATLAS_ASSERT( min == max, + "MultiBlockConnectivity::add(rows,cols[]): " + "all elements of cls[] must be identical" ); long blk_idx = blocks_; do { blk_idx--; - } while ( blk_idx >= 0l && block_displs_view_( blk_idx ) >= position && max != block_cols_view_( blk_idx ) ); + } while ( blk_idx >= 0l && block_displs_[blk_idx] >= position && max != block_cols_[blk_idx] ); - ASSERT( blk_idx >= 0l ); + ATLAS_ASSERT( blk_idx >= 0l ); IrregularConnectivityImpl::insert( position, rows, cols ); - for ( size_t jblk = blk_idx; jblk < blocks_; ++jblk ) - block_displs_view_( jblk + 1 ) += rows; + for ( idx_t jblk = blk_idx; jblk < blocks_; ++jblk ) + block_displs_[jblk + 1] += rows; rebuild_block_connectivity(); } //------------------------------------------------------------------------------------------------------ void MultiBlockConnectivityImpl::rebuild_block_connectivity() { - block_.resize( blocks_, 0 ); - block_view_ = make_host_vector_view( block_ ); - - for ( size_t b = 0; b < blocks_; ++b ) { - if ( block_view_[b] ) { - block_view_[b]->rebuild( block_displs_view_( b + 1 ) - block_displs_view_( b ), // rows - block_cols_view_( b ), // cols - data() + displs( block_displs_view_( b ) ) ); - } - else { - block_view_[b] = new BlockConnectivityImpl( block_displs_view_( b + 1 ) - block_displs_view_( b ), // rows - block_cols_view_( b ), // cols - data() + displs( block_displs_view_( b ) ), - /*own = */ false ); - } + block_.resize( blocks_, std::move( BlockConnectivityImpl() ) ); + + for ( idx_t b = 0; b < blocks_; ++b ) { + block_[b].rebuild( block_displs_[b + 1] - block_displs_[b], // rows + block_cols_[b], // cols + values_.data() + displs( block_displs_[b] ) ); } } @@ -685,11 +546,11 @@ void MultiBlockConnectivityImpl::rebuild_block_connectivity() { size_t MultiBlockConnectivityImpl::footprint() const { size_t size = IrregularConnectivityImpl::footprint(); - size += block_displs_->footprint(); - size += block_cols_->footprint(); + size += block_displs_.footprint(); + size += block_cols_.footprint(); - for ( size_t j = 0; j < block_.size(); ++j ) { - size += block_view_[j]->footprint(); + for ( idx_t j = 0; j < block_.size(); ++j ) { + size += block_[j].footprint(); } return size; } @@ -698,55 +559,43 @@ size_t MultiBlockConnectivityImpl::footprint() const { BlockConnectivityImpl::BlockConnectivityImpl() : owns_( true ), - values_( array::Array::create( 1, 1 ) ), - values_view_( array::make_view( *values_ ) ), + values_( 0 ), rows_( 0 ), cols_( 0 ), - missing_value_( std::numeric_limits::is_signed ? -1 : std::numeric_limits::max() ), - gpu_clone_( this ) {} + missing_value_( std::numeric_limits::is_signed ? -1 : std::numeric_limits::max() ) {} //------------------------------------------------------------------------------------------------------ -BlockConnectivityImpl::BlockConnectivityImpl( size_t rows, size_t cols, const std::initializer_list& values ) : +BlockConnectivityImpl::BlockConnectivityImpl( idx_t rows, idx_t cols, const std::initializer_list& values ) : owns_( true ), - values_( array::Array::create( 1, 1 ) ), - values_view_( array::make_view( *values_ ) ), + values_( rows * cols ), rows_( rows ), cols_( cols ), - missing_value_( std::numeric_limits::is_signed ? -1 : std::numeric_limits::max() ), - gpu_clone_( this ) { - delete values_; - values_ = array::Array::create( rows_, cols_ ); - values_view_ = array::make_view( *values_ ); + missing_value_( std::numeric_limits::is_signed ? -1 : std::numeric_limits::max() ) { idx_t add_base = FORTRAN_BASE; auto v = values.begin(); - for ( size_t i = 0; i < rows_; ++i ) { - for ( size_t j = 0; j < cols_; ++j ) { - values_view_( i, j ) = *( v++ ) + add_base; + for ( idx_t i = 0; i < rows_; ++i ) { + for ( idx_t j = 0; j < cols_; ++j ) { + values_[index( i, j )] = *( v++ ) + add_base; } } - ASSERT( v == values.end() ); + ATLAS_ASSERT( v == values.end() ); } //------------------------------------------------------------------------------------------------------ -BlockConnectivityImpl::BlockConnectivityImpl( size_t rows, size_t cols, idx_t values[] ) : +BlockConnectivityImpl::BlockConnectivityImpl( idx_t rows, idx_t cols, idx_t values[] ) : owns_( true ), - values_( array::Array::create( 1, 1 ) ), - values_view_( array::make_view( *values_ ) ), + values_( rows * cols ), rows_( rows ), cols_( cols ), - missing_value_( std::numeric_limits::is_signed ? -1 : std::numeric_limits::max() ), - gpu_clone_( this ) { - delete values_; - values_ = array::Array::create( rows_, cols_ ); - values_view_ = array::make_view( *values_ ); - if ( values_->size() ) { + missing_value_( std::numeric_limits::is_signed ? -1 : std::numeric_limits::max() ) { + if ( values_.size() ) { idx_t add_base = FORTRAN_BASE; idx_t* v = &values[0]; - for ( size_t i = 0; i < rows_; ++i ) { - for ( size_t j = 0; j < cols_; ++j ) { - values_view_( i, j ) = *( v++ ) + add_base; + for ( idx_t i = 0; i < rows_; ++i ) { + for ( idx_t j = 0; j < cols_; ++j ) { + values_[index( i, j )] = *( v++ ) + add_base; } } } @@ -754,91 +603,59 @@ BlockConnectivityImpl::BlockConnectivityImpl( size_t rows, size_t cols, idx_t va //------------------------------------------------------------------------------------------------------ -BlockConnectivityImpl::BlockConnectivityImpl( size_t rows, size_t cols, idx_t values[], bool dummy ) : +BlockConnectivityImpl::BlockConnectivityImpl( idx_t rows, idx_t cols, idx_t values[], bool /*dummy*/ ) : owns_( false ), - values_( array::Array::wrap( values, array::ArrayShape{rows, cols} ) ), - values_view_( array::make_view( *values_ ) ), + values_( values, rows * cols ), rows_( rows ), cols_( cols ), - missing_value_( std::numeric_limits::is_signed ? -1 : std::numeric_limits::max() ), - gpu_clone_( this ) {} + missing_value_( std::numeric_limits::is_signed ? -1 : std::numeric_limits::max() ) {} //------------------------------------------------------------------------------------------------------ BlockConnectivityImpl::~BlockConnectivityImpl() { - if ( owns_ ) { - assert( values_ ); - delete values_; - } + //TODO owns_ not used ? } //------------------------------------------------------------------------------------------------------ -void BlockConnectivityImpl::rebuild( size_t rows, size_t cols, idx_t values[] ) { - ASSERT( not owns_ ); - rows_ = rows; - cols_ = cols; - assert( values_ ); - delete values_; - values_ = array::Array::wrap( values, array::ArrayShape{rows, cols} ); - values_view_ = array::make_view( *values_ ); +void BlockConnectivityImpl::rebuild( idx_t rows, idx_t cols, idx_t values[] ) { + rows_ = rows; + cols_ = cols; + values_ = array::SVector( values, rows * cols ); } //------------------------------------------------------------------------------------------------------ -void BlockConnectivityImpl::add( size_t rows, size_t cols, const idx_t values[], bool fortran_array ) { - if ( !owns_ ) throw eckit::AssertionFailed( "BlockConnectivity must be owned to be resized directly" ); - if ( cols_ != 0 && cols_ != cols ) - throw eckit::AssertionFailed( - "Cannot add values with different cols than " - "already existing in BlockConnectivity" ); +void BlockConnectivityImpl::add( idx_t rows, idx_t cols, const idx_t values[], bool fortran_array ) { + ATLAS_ASSERT( owns(), "BlockConnectivity must be owned to be resized directly" ); + if ( cols_ != 0 && cols_ != cols ) { + ATLAS_ASSERT( false, + "Cannot add values with different cols than " + "already existing in BlockConnectivity" ); + } - values_->resize( rows_ + rows, cols ); - values_view_ = array::make_view( *values_ ); + values_.resize( ( rows_ + rows ) * cols ); + const idx_t oldrows = rows_; + idx_t add_base = fortran_array ? 0 : FORTRAN_BASE; - idx_t add_base = fortran_array ? 0 : FORTRAN_BASE; + rows_ += rows; + cols_ = cols; - for ( size_t i = 0, i_old = rows_; i < rows; ++i, ++i_old ) { - for ( size_t j = 0; j < cols; ++j ) { - values_view_( i_old, j ) = values[i * cols + j] + add_base; + for ( idx_t i = 0; i < rows; ++i ) { + for ( idx_t j = 0; j < cols; ++j ) { + values_[index( i + oldrows, j )] = values[i * cols + j] + add_base; } } - - rows_ += rows; - cols_ = cols; } //------------------------------------------------------------------------------------------------------ size_t BlockConnectivityImpl::footprint() const { size_t size = sizeof( *this ); - if ( owns() ) size += values_->footprint(); + if ( owns() ) size += values_.footprint(); return size; } -void BlockConnectivityImpl::cloneToDevice() { - values_->cloneToDevice(); - values_view_ = array::make_device_view( *values_ ); - gpu_clone_.cloneToDevice(); -} - -void BlockConnectivityImpl::cloneFromDevice() { - values_->cloneFromDevice(); - values_view_ = array::make_host_view( *values_ ); -} - -bool BlockConnectivityImpl::valid() const { - return values_->valid(); -} - -bool BlockConnectivityImpl::hostNeedsUpdate() const { - return values_->hostNeedsUpdate(); -} - -bool BlockConnectivityImpl::deviceNeedsUpdate() const { - return values_->deviceNeedsUpdate(); -} - //------------------------------------------------------------------------------------------------------ class ConnectivityPrivateAccess { @@ -852,11 +669,9 @@ class ConnectivityPrivateAccess { callback_t& callback_update() { return connectivity_.callback_update_; } callback_t& callback_delete() { return connectivity_.callback_delete_; } - // TODO : For now return host-view raw data to Fortran, but this should be - // reviewed to also possibly return device-view data - int* values() { return array::make_view( *connectivity_.data_[Connectivity::_values_] ).data(); } - size_t* displs() { return array::make_view( *connectivity_.data_[Connectivity::_displs_] ).data(); } - size_t* counts() { return array::make_view( *connectivity_.data_[Connectivity::_counts_] ).data(); } + idx_t* values() { return connectivity_.values_.data(); } + idx_t* displs() { return connectivity_.displs_.data(); } + idx_t* counts() { return connectivity_.counts_.data(); } const char* name() { return connectivity_.name_; } @@ -868,12 +683,12 @@ class ConnectivityPrivateAccess { extern "C" { Connectivity* atlas__Connectivity__create() { - Connectivity* connectivity = 0; - ATLAS_ERROR_HANDLING( connectivity = new Connectivity(); ); + Connectivity* connectivity = nullptr; + connectivity = new Connectivity(); return connectivity; } void atlas__Connectivity__delete( Connectivity* This ) { - ATLAS_ERROR_HANDLING( delete This ); + delete This; } void atlas__connectivity__register_ctxt( Connectivity* This, Connectivity::ctxt_t ctxt ) { @@ -897,90 +712,91 @@ void atlas__connectivity__register_delete( Connectivity* This, Connectivity::cal access.callback_delete() = callback; } -void atlas__Connectivity__displs( Connectivity* This, size_t*& displs, size_t& size ) { +void atlas__Connectivity__displs( Connectivity* This, idx_t*& displs, idx_t& size ) { ConnectivityPrivateAccess access( *This ); displs = access.displs(); size = This->rows() + 1; } -void atlas__Connectivity__counts( Connectivity* This, size_t*& counts, size_t& size ) { +void atlas__Connectivity__counts( Connectivity* This, idx_t*& counts, idx_t& size ) { ConnectivityPrivateAccess access( *This ); counts = access.counts(); size = This->rows(); } -void atlas__Connectivity__values( Connectivity* This, int*& values, size_t& size ) { +void atlas__Connectivity__values( Connectivity* This, idx_t*& values, idx_t& size ) { ConnectivityPrivateAccess access( *This ); values = access.values(); size = This->rows() ? access.displs()[This->rows()] + 1 : 0; } -void atlas__Connectivity__add_values( Connectivity* This, size_t rows, size_t cols, int values[] ) { +void atlas__Connectivity__add_values( Connectivity* This, idx_t rows, idx_t cols, idx_t values[] ) { This->add( rows, cols, values, true ); } -void atlas__Connectivity__add_missing( Connectivity* This, size_t rows, size_t cols ) { +void atlas__Connectivity__add_missing( Connectivity* This, idx_t rows, idx_t cols ) { This->add( rows, cols ); } -size_t atlas__Connectivity__rows( const Connectivity* This ) { +idx_t atlas__Connectivity__rows( const Connectivity* This ) { return This->rows(); } -int atlas__Connectivity__missing_value( const Connectivity* This ) { +idx_t atlas__Connectivity__missing_value( const Connectivity* This ) { return This->missing_value() TO_FORTRAN; } MultiBlockConnectivity* atlas__MultiBlockConnectivity__create() { - MultiBlockConnectivity* connectivity = 0; - ATLAS_ERROR_HANDLING( connectivity = new MultiBlockConnectivity(); ); + MultiBlockConnectivity* connectivity = nullptr; + connectivity = new MultiBlockConnectivity(); return connectivity; } -size_t atlas__MultiBlockConnectivity__blocks( const MultiBlockConnectivity* This ) { +idx_t atlas__MultiBlockConnectivity__blocks( const MultiBlockConnectivity* This ) { return This->blocks(); } -BlockConnectivityImpl* atlas__MultiBlockConnectivity__block( MultiBlockConnectivity* This, size_t block_idx ) { - ATLAS_ERROR_HANDLING( ASSERT( This != 0 ) ); +BlockConnectivityImpl* atlas__MultiBlockConnectivity__block( MultiBlockConnectivity* This, idx_t block_idx ) { + ATLAS_ASSERT( This != nullptr ); BlockConnectivityImpl* block = &This->block( block_idx ); - ASSERT( block != 0 ); + ATLAS_ASSERT( block != nullptr ); return block; } void atlas__BlockConnectivity__delete( BlockConnectivityImpl* This ) { - ATLAS_ERROR_HANDLING( delete This ); + delete This; } -size_t atlas__BlockConnectivity__rows( const BlockConnectivityImpl* This ) { - ATLAS_ERROR_HANDLING( ASSERT( This != 0 ) ); +idx_t atlas__BlockConnectivity__rows( const BlockConnectivityImpl* This ) { + ATLAS_ASSERT( This != nullptr ); return This->rows(); } -size_t atlas__BlockConnectivity__cols( const BlockConnectivityImpl* This ) { - ATLAS_ERROR_HANDLING( ASSERT( This != 0 ) ); +idx_t atlas__BlockConnectivity__cols( const BlockConnectivityImpl* This ) { + ATLAS_ASSERT( This != nullptr ); return This->cols(); } -int atlas__BlockConnectivity__missing_value( const BlockConnectivityImpl* This ) { - ATLAS_ERROR_HANDLING( ASSERT( This != 0 ) ); +idx_t atlas__BlockConnectivity__missing_value( const BlockConnectivityImpl* This ) { + ATLAS_ASSERT( This != nullptr ); return This->missing_value(); } -void atlas__BlockConnectivity__data( BlockConnectivityImpl* This, int*& data, size_t& rows, size_t& cols ) { - ATLAS_ERROR_HANDLING( ASSERT( This != 0 ) ); +void atlas__BlockConnectivity__data( BlockConnectivityImpl* This, idx_t*& data, idx_t& rows, idx_t& cols ) { + ATLAS_ASSERT( This != nullptr ); data = This->data(); rows = This->rows(); cols = This->cols(); } const char* atlas__Connectivity__name( Connectivity* This ) { - ATLAS_ERROR_HANDLING( ASSERT( This ); return ConnectivityPrivateAccess( *This ).name(); ); - return 0; + ATLAS_ASSERT( This ); + return ConnectivityPrivateAccess( *This ).name(); } void atlas__Connectivity__rename( Connectivity* This, const char* name ) { - ATLAS_ERROR_HANDLING( ASSERT( This ); This->rename( std::string( name ) ); ); + ATLAS_ASSERT( This ); + This->rename( std::string( name ) ); } } diff --git a/src/atlas/mesh/Connectivity.h b/src/atlas/mesh/Connectivity.h index a611c94de..5e2be057a 100644 --- a/src/atlas/mesh/Connectivity.h +++ b/src/atlas/mesh/Connectivity.h @@ -24,27 +24,31 @@ #pragma once #include +#include +#include -#include "eckit/memory/Owned.h" +#include "atlas/util/Object.h" #include "atlas/array.h" #include "atlas/array/ArrayView.h" #include "atlas/array/DataType.h" #include "atlas/array/IndexView.h" +#include "atlas/array/SVector.h" #include "atlas/array/Vector.h" -#include "atlas/array/gridtools/GPUClonable.h" #include "atlas/array_fwd.h" #include "atlas/library/config.h" namespace atlas { namespace mesh { -#define MAX_STRING_SIZE 60 +constexpr size_t MAX_STRING_SIZE() { + return 60; +} template -class ConnectivityInterface : public eckit::Owned, public ConnectivityImpl { +class ConnectivityInterface : public util::Object, public ConnectivityImpl { using ConnectivityImpl::ConnectivityImpl; - using eckit::Owned::Owned; + using util::Object::Object; }; // Classes defined in this file: @@ -99,14 +103,11 @@ class ConnectivityIndex { }; public: + ATLAS_HOST_DEVICE ConnectivityIndex( const ConnectivityIndex& other ) { set( other.get() ); } ATLAS_HOST_DEVICE ConnectivityIndex( idx_t* idx ) : idx_( idx ) {} ATLAS_HOST_DEVICE void set( const idx_t& value ) { *( idx_ ) = value + BASE; } ATLAS_HOST_DEVICE idx_t get() const { return *(idx_)-BASE; } - ATLAS_HOST_DEVICE void operator =( const idx_t& value ) { set( value ); } - ATLAS_HOST_DEVICE ConnectivityIndex& operator=( const ConnectivityIndex& other ) { - set( other.get() ); - return *this; - } + ATLAS_HOST_DEVICE void operator=( const idx_t& value ) { set( value ); } ATLAS_HOST_DEVICE ConnectivityIndex& operator+( const idx_t& value ) { *( idx_ ) += value; return *this; @@ -141,30 +142,30 @@ class ConnectivityRow { public: ATLAS_HOST_DEVICE - ConnectivityRow( idx_t* data, size_t size ) : data_( data ), size_( size ) {} + ConnectivityRow( idx_t* data, idx_t size ) : data_( data ), size_( size ) {} - ATLAS_HOST_DEVICE - idx_t operator()( size_t i ) const { return data_[i] FROM_FORTRAN; } + template + ATLAS_HOST_DEVICE idx_t operator()( Int i ) const { + return data_[i] FROM_FORTRAN; + } - ATLAS_HOST_DEVICE - Index operator()( size_t i ) { return INDEX_REF( data_ + i ); } + template + ATLAS_HOST_DEVICE Index operator()( Int i ) { + return INDEX_REF( data_ + i ); + } ATLAS_HOST_DEVICE - size_t size() const { return size_; } + idx_t size() const { return size_; } private: idx_t* data_; - size_t size_; + idx_t size_; }; class IrregularConnectivityImpl { public: typedef ConnectivityRow Row; - static constexpr unsigned short _values_ = 0; - static constexpr unsigned short _displs_ = 1; - static constexpr unsigned short _counts_ = 2; - public: //-- Constructors @@ -174,7 +175,7 @@ class IrregularConnectivityImpl { /// @brief Construct connectivity table wrapping existing raw data. /// No resizing can be performed as data is not owned. - IrregularConnectivityImpl( idx_t values[], size_t rows, size_t displs[], size_t counts[] ); + IrregularConnectivityImpl( idx_t values[], idx_t rows, idx_t displs[], idx_t counts[] ); /// @brief Copy ctr (only to be used when calling a cuda kernel) // This ctr has to be defined in the header, since __CUDACC__ will identify @@ -196,122 +197,111 @@ class IrregularConnectivityImpl { /// @brief Rename this Connectivity void rename( const std::string& name ) { - strncpy( name_, name.c_str(), std::max( name.size(), size_t( MAX_STRING_SIZE ) ) ); + strncpy( name_, name.c_str(), std::max( name.size(), MAX_STRING_SIZE() ) ); } /// @brief Number of rows in the connectivity table ATLAS_HOST_DEVICE - size_t rows() const { return rows_; } + idx_t rows() const { return rows_; } /// @brief Number of columns for specified row in the connectivity table ATLAS_HOST_DEVICE - size_t cols( size_t row_idx ) const { return counts_view_( row_idx ); } + idx_t cols( idx_t row_idx ) const { return counts_[row_idx]; } /// @brief Maximum value for number of columns over all rows ATLAS_HOST_DEVICE - size_t maxcols() const { return maxcols_; } + idx_t maxcols() const { return maxcols_; } /// @brief Minimum value for number of columns over all rows ATLAS_HOST_DEVICE - size_t mincols() const { return mincols_; } + idx_t mincols() const { return mincols_; } /// @brief Access to connectivity table elements for given row and column /// The returned index has base 0 regardless if ATLAS_HAVE_FORTRAN is defined. ATLAS_HOST_DEVICE - idx_t operator()( size_t row_idx, size_t col_idx ) const; + idx_t operator()( idx_t row_idx, idx_t col_idx ) const; - /// @brief Access to raw data. - /// Note that the connectivity base is 1 in case ATLAS_HAVE_FORTRAN is - /// defined. - const idx_t* data() const { return values_view_.data(); } - idx_t* data() { return values_view_.data(); } - - size_t size() const { return values_view_.size(); } + idx_t size() const { return values_.size(); } ATLAS_HOST_DEVICE idx_t missing_value() const { return missing_value_; } ATLAS_HOST_DEVICE - Row row( size_t row_idx ) const; + Row row( idx_t row_idx ) const; ///-- Modifiers /// @brief Modify row with given values. Values must be given with base 0 - void set( size_t row_idx, const idx_t column_values[] ); + void set( idx_t row_idx, const idx_t column_values[] ); /// @brief Modify (row,col) with given value. Value must be given with base 0 - void set( size_t row_idx, size_t col_idx, const idx_t value ); + void set( idx_t row_idx, idx_t col_idx, const idx_t value ); /// @brief Resize connectivity /// @note Can only be used when data is owned. - virtual void resize( size_t old_size, size_t size, bool initialize, const idx_t values[], bool fortran_array ); + virtual void resize( idx_t old_size, idx_t size, bool initialize, const idx_t values[], bool fortran_array ); /// @brief Resize connectivity, and add given rows /// @note Can only be used when data is owned. - virtual void add( size_t rows, size_t cols, const idx_t values[], bool fortran_array = false ); + virtual void add( idx_t rows, idx_t cols, const idx_t values[], bool fortran_array = false ); /// @brief Resize connectivity, and add given rows with missing values /// @note Can only be used when data is owned. - virtual void add( size_t rows, size_t cols ); + virtual void add( idx_t rows, idx_t cols ); /// @brief Resize connectivity, and add given rows with missing values /// @note Can only be used when data is owned. - virtual void add( size_t rows, const size_t cols[] ); + virtual void add( idx_t rows, const idx_t cols[] ); /// @brief Resize connectivity, and copy from a BlockConnectivity virtual void add( const BlockConnectivityImpl& block ); /// @brief Resize connectivity, and insert given rows /// @note Can only be used when data is owned. - virtual void insert( size_t position, size_t rows, size_t cols, const idx_t values[], bool fortran_array = false ); + virtual void insert( idx_t position, idx_t rows, idx_t cols, const idx_t values[], bool fortran_array = false ); /// @brief Resize connectivity, and insert given rows with missing values /// @note Can only be used when data is owned. - virtual void insert( size_t position, size_t rows, size_t cols ); + virtual void insert( idx_t position, idx_t rows, idx_t cols ); /// @brief Resize connectivity, and insert given rows with missing values /// @note Can only be used when data is owned. - virtual void insert( size_t position, size_t rows, const size_t cols[] ); + virtual void insert( idx_t position, idx_t rows, const idx_t cols[] ); virtual void clear(); virtual size_t footprint() const; - size_t displs( const size_t row ) const { return displs_view_( row ); } - - virtual void cloneToDevice(); - virtual void cloneFromDevice(); - virtual void syncHostDevice() const; - virtual bool valid() const; - virtual bool hostNeedsUpdate() const; - virtual bool deviceNeedsUpdate() const; + idx_t displs( const idx_t row ) const { return displs_[row]; } - IrregularConnectivityImpl* gpu_object_ptr() { return gpu_clone_.gpu_object_ptr(); } void dump( std::ostream& os ) const; + friend std::ostream& operator<<( std::ostream& os, const IrregularConnectivityImpl& p ) { + p.dump( os ); + return os; + } protected: bool owns() { return owns_; } - const size_t* displs() const { return displs_view_.data(); } - const size_t* counts() const { return counts_view_.data(); } + const idx_t* displs() const { return displs_.data(); } + const idx_t* counts() const { return counts_.data(); } private: void on_delete(); void on_update(); private: - char name_[MAX_STRING_SIZE]; - + char name_[MAX_STRING_SIZE()]; bool owns_; - std::array data_; - array::ArrayView values_view_; - array::ArrayView displs_view_; - array::ArrayView counts_view_; +protected: + array::SVector values_; + array::SVector displs_; + array::SVector counts_; idx_t missing_value_; - size_t rows_; - size_t maxcols_; - size_t mincols_; + idx_t rows_; + idx_t maxcols_; + idx_t mincols_; public: typedef void* ctxt_t; @@ -322,7 +312,6 @@ class IrregularConnectivityImpl { ctxt_t ctxt_; callback_t callback_update_; callback_t callback_delete_; - array::gridtools::GPUClonable gpu_clone_; }; // ---------------------------------------------------------------------------------------------- @@ -367,51 +356,37 @@ class MultiBlockConnectivityImpl : public IrregularConnectivityImpl { /// Data is owned MultiBlockConnectivityImpl( const std::string& name = "" ); - /* -/// @brief Construct connectivity table wrapping existing raw data. -/// No resizing can be performed as data is not owned. -MultiBlockConnectivity( - idx_t values[], - size_t rows, - size_t displs[], - size_t counts[], - size_t blocks, size_t block_displs[], - size_t block_cols[] ); -*/ virtual ~MultiBlockConnectivityImpl(); //-- Accessors /// @brief Number of blocks ATLAS_HOST_DEVICE - size_t blocks() const { return blocks_; } + idx_t blocks() const { return blocks_; } /// @brief Access to a block connectivity ATLAS_HOST_DEVICE - const BlockConnectivityImpl& block( size_t block_idx ) const { return *( block_view_[block_idx] ); } + const BlockConnectivityImpl& block( idx_t block_idx ) const { return block_[block_idx]; } ATLAS_HOST_DEVICE - BlockConnectivityImpl& block( size_t block_idx ) { return *( block_view_[block_idx] ); } - - // ATLAS_HOST_DEVICE - // BlockConnectivityImpl* base() { return block_.base();} + BlockConnectivityImpl& block( idx_t block_idx ) { return block_[block_idx]; } /// @brief Access to connectivity table elements for given row and column /// The row_idx counts up from 0, from block 0, as in IrregularConnectivity /// The returned index has base 0 regardless if ATLAS_HAVE_FORTRAN is defined. ATLAS_HOST_DEVICE - idx_t operator()( size_t row_idx, size_t col_idx ) const; + idx_t operator()( idx_t row_idx, idx_t col_idx ) const; /// @brief Access to connectivity table elements for given row and column /// The block_row_idx counts up from zero for every block_idx. /// The returned index has base 0 regardless if ATLAS_HAVE_FORTRAN is defined. ATLAS_HOST_DEVICE - idx_t operator()( size_t block_idx, size_t block_row_idx, size_t block_col_idx ) const; + idx_t operator()( idx_t block_idx, idx_t block_row_idx, idx_t block_col_idx ) const; ///-- Modifiers /// @brief Resize connectivity, and add given rows as a new block /// @note Can only be used when data is owned. - virtual void add( size_t rows, size_t cols, const idx_t values[], bool fortran_array = false ); + virtual void add( idx_t rows, idx_t cols, const idx_t values[], bool fortran_array = false ); /// @brief Resize connectivity, and copy from a BlockConnectivity to a new /// block @@ -420,51 +395,37 @@ MultiBlockConnectivity( /// @brief Resize connectivity, and add given rows with missing values /// @note Can only be used when data is owned. - virtual void add( size_t rows, size_t cols ); + virtual void add( idx_t rows, idx_t cols ); /// @brief Resize connectivity, and add given rows with missing values /// @note Can only be used when data is owned. - virtual void add( size_t rows, const size_t cols[] ); + virtual void add( idx_t rows, const idx_t cols[] ); /// @brief Resize connectivity, and insert given rows /// @note Can only be used when data is owned. - virtual void insert( size_t position, size_t rows, size_t cols, const idx_t values[], bool fortran_array = false ); + virtual void insert( idx_t position, idx_t rows, idx_t cols, const idx_t values[], bool fortran_array = false ); /// @brief Resize connectivity, and insert given rows with missing values /// @note Can only be used when data is owned. - virtual void insert( size_t position, size_t rows, size_t cols ); + virtual void insert( idx_t position, idx_t rows, idx_t cols ); /// @brief Resize connectivity, and insert given rows with missing values /// @note Can only be used when data is owned. - virtual void insert( size_t position, size_t rows, const size_t cols[] ); + virtual void insert( idx_t position, idx_t rows, const idx_t cols[] ); virtual void clear(); virtual size_t footprint() const; - virtual void cloneToDevice(); - virtual void cloneFromDevice(); - virtual void syncHostDevice() const; - virtual bool valid() const; - virtual bool hostNeedsUpdate() const; - virtual bool deviceNeedsUpdate() const; - - MultiBlockConnectivityImpl* gpu_object_ptr() { return gpu_clone_.gpu_object_ptr(); } - private: void rebuild_block_connectivity(); private: - size_t blocks_; - array::Array* block_displs_; - array::Array* block_cols_; - - array::ArrayView block_displs_view_; - array::ArrayView block_cols_view_; - array::Vector block_; - array::VectorView block_view_; + idx_t blocks_; + array::SVector block_displs_; + array::SVector block_cols_; - array::gridtools::GPUClonable gpu_clone_; + array::SVector block_; }; // ----------------------------------------------------------------------------------------------------- @@ -489,7 +450,7 @@ class BlockConnectivityImpl { private: friend class IrregularConnectivityImpl; friend class MultiBlockConnectivityImpl; - BlockConnectivityImpl( size_t rows, size_t cols, idx_t values[], bool dummy ); + BlockConnectivityImpl( idx_t rows, idx_t cols, idx_t values[], bool dummy ); public: //-- Constructors @@ -497,11 +458,11 @@ class BlockConnectivityImpl { /// @brief Construct connectivity table that needs resizing a-posteriori /// Data is owned BlockConnectivityImpl(); - BlockConnectivityImpl( size_t rows, size_t cols, const std::initializer_list& ); + BlockConnectivityImpl( idx_t rows, idx_t cols, const std::initializer_list& ); /// @brief Construct connectivity table wrapping existing raw data. /// No resizing can be performed as data is not owned. - BlockConnectivityImpl( size_t rows, size_t cols, idx_t values[] ); + BlockConnectivityImpl( idx_t rows, idx_t cols, idx_t values[] ); /// @brief Copy ctr (only to be used when calling a cuda kernel) // This ctr has to be defined in the header, since __CUDACC__ will identify @@ -509,40 +470,44 @@ class BlockConnectivityImpl { // it is compiled it for a GPU kernel BlockConnectivityImpl( const BlockConnectivityImpl& other ) : owns_( false ), - values_( 0 ), - values_view_( other.values_view_ ), + values_( other.values_ ), rows_( other.rows_ ), cols_( other.cols_ ), - missing_value_( other.missing_value_ ), - gpu_clone_( this ) {} + missing_value_( other.missing_value_ ) {} + + BlockConnectivityImpl( BlockConnectivityImpl&& ) = default; + BlockConnectivityImpl& operator=( const BlockConnectivityImpl& other ) = default; /// @brief Destructor ~BlockConnectivityImpl(); - void rebuild( size_t rows, size_t cols, idx_t values[] ); + ATLAS_HOST_DEVICE + idx_t index( idx_t i, idx_t j ) const; + + void rebuild( idx_t rows, idx_t cols, idx_t values[] ); //-- Accessors /// @brief Access to connectivity table elements for given row and column /// The returned index has base 0 regardless if ATLAS_HAVE_FORTRAN is defined. ATLAS_HOST_DEVICE - idx_t operator()( size_t row_idx, size_t col_idx ) const; + idx_t operator()( idx_t row_idx, idx_t col_idx ) const; /// @brief Number of rows ATLAS_HOST_DEVICE - size_t rows() const { return rows_; } + idx_t rows() const { return rows_; } /// @brief Number of columns ATLAS_HOST_DEVICE - size_t cols() const { return cols_; } + idx_t cols() const { return cols_; } /// @brief Access to raw data. /// Note that the connectivity base is 1 in case ATLAS_HAVE_FORTRAN is /// defined. ATLAS_HOST_DEVICE - const idx_t* data() const { return values_view_.data(); } + const idx_t* data() const { return values_.data(); } ATLAS_HOST_DEVICE - idx_t* data() { return values_view_.data(); } + idx_t* data() { return values_.data(); } ATLAS_HOST_DEVICE idx_t missing_value() const { return missing_value_; } @@ -553,92 +518,84 @@ class BlockConnectivityImpl { /// @brief Modify row with given values. Values must be given with base 0 ATLAS_HOST_DEVICE - void set( size_t row_idx, const idx_t column_values[] ); + void set( idx_t row_idx, const idx_t column_values[] ); /// @brief Modify (row,col) with given value. Value must be given with base 0 ATLAS_HOST_DEVICE - void set( size_t row_idx, size_t col_idx, const idx_t value ); + void set( idx_t row_idx, idx_t col_idx, const idx_t value ); /// @brief Resize connectivity, and add given rows /// @note Can only be used when data is owned. - void add( size_t rows, size_t cols, const idx_t values[], bool fortran_array = false ); - - void cloneToDevice(); - void cloneFromDevice(); - void syncHostDevice() const; - bool valid() const; - bool hostNeedsUpdate() const; - bool deviceNeedsUpdate() const; + void add( idx_t rows, idx_t cols, const idx_t values[], bool fortran_array = false ); bool owns() const { return owns_; } - BlockConnectivityImpl* gpu_object_ptr() { return gpu_clone_.gpu_object_ptr(); } private: bool owns_; - array::Array* values_; - array::ArrayView values_view_; + array::SVector values_; - size_t rows_; - size_t cols_; + idx_t rows_; + idx_t cols_; idx_t missing_value_; - array::gridtools::GPUClonable gpu_clone_; }; -typedef ConnectivityInterface IrregularConnectivity; -typedef ConnectivityInterface MultiBlockConnectivity; -typedef BlockConnectivityImpl BlockConnectivity; - -typedef IrregularConnectivity Connectivity; +using IrregularConnectivity = ConnectivityInterface; +using MultiBlockConnectivity = ConnectivityInterface; +using BlockConnectivity = BlockConnectivityImpl; +using Connectivity = IrregularConnectivity; // ----------------------------------------------------------------------------------------------------- -inline idx_t IrregularConnectivityImpl::operator()( size_t row_idx, size_t col_idx ) const { - assert( counts_view_( row_idx ) > ( col_idx ) ); - return values_view_( displs_view_( row_idx ) + col_idx ) FROM_FORTRAN; +inline idx_t IrregularConnectivityImpl::operator()( idx_t row_idx, idx_t col_idx ) const { + assert( counts_[row_idx] > ( col_idx ) ); + return values_[displs_[row_idx] + col_idx] FROM_FORTRAN; } -inline void IrregularConnectivityImpl::set( size_t row_idx, const idx_t column_values[] ) { - const size_t N = counts_view_( row_idx ); - for ( size_t n = 0; n < N; ++n ) { - values_view_( displs_view_( row_idx ) + n ) = column_values[n] TO_FORTRAN; +inline void IrregularConnectivityImpl::set( idx_t row_idx, const idx_t column_values[] ) { + const idx_t N = counts_[row_idx]; + for ( idx_t n = 0; n < N; ++n ) { + values_[displs_[row_idx] + n] = column_values[n] TO_FORTRAN; } } -inline void IrregularConnectivityImpl::set( size_t row_idx, size_t col_idx, const idx_t value ) { - assert( col_idx < counts_view_( row_idx ) ); - values_view_( displs_view_( row_idx ) + col_idx ) = value TO_FORTRAN; +inline void IrregularConnectivityImpl::set( idx_t row_idx, idx_t col_idx, const idx_t value ) { + assert( col_idx < counts_[row_idx] ); + values_[displs_[row_idx] + col_idx] = value TO_FORTRAN; } -inline IrregularConnectivityImpl::Row IrregularConnectivityImpl::row( size_t row_idx ) const { - return IrregularConnectivityImpl::Row( const_cast( values_view_.data() ) + displs_view_( row_idx ), - counts_view_( row_idx ) ); +inline IrregularConnectivityImpl::Row IrregularConnectivityImpl::row( idx_t row_idx ) const { + return IrregularConnectivityImpl::Row( const_cast( values_.data() ) + displs_( row_idx ), + counts_( row_idx ) ); } // ----------------------------------------------------------------------------------------------------- -inline idx_t MultiBlockConnectivityImpl::operator()( size_t row_idx, size_t col_idx ) const { +inline idx_t MultiBlockConnectivityImpl::operator()( idx_t row_idx, idx_t col_idx ) const { return IrregularConnectivityImpl::operator()( row_idx, col_idx ); } -inline idx_t MultiBlockConnectivityImpl::operator()( size_t block_idx, size_t block_row_idx, - size_t block_col_idx ) const { +inline idx_t MultiBlockConnectivityImpl::operator()( idx_t block_idx, idx_t block_row_idx, idx_t block_col_idx ) const { return block( block_idx )( block_row_idx, block_col_idx ); } // ----------------------------------------------------------------------------------------------------- -inline idx_t BlockConnectivityImpl::operator()( size_t row_idx, size_t col_idx ) const { - return values_view_( row_idx, col_idx ) FROM_FORTRAN; +inline idx_t BlockConnectivityImpl::operator()( idx_t row_idx, idx_t col_idx ) const { + return values_[index( row_idx, col_idx )] FROM_FORTRAN; } -inline void BlockConnectivityImpl::set( size_t row_idx, const idx_t column_values[] ) { - for ( size_t n = 0; n < cols_; ++n ) { - values_view_( row_idx, n ) = column_values[n] TO_FORTRAN; +inline void BlockConnectivityImpl::set( idx_t row_idx, const idx_t column_values[] ) { + for ( idx_t n = 0; n < cols_; ++n ) { + values_[index( row_idx, n )] = column_values[n] TO_FORTRAN; } } -inline void BlockConnectivityImpl::set( size_t row_idx, size_t col_idx, const idx_t value ) { - values_view_( row_idx, col_idx ) = value TO_FORTRAN; +inline void BlockConnectivityImpl::set( idx_t row_idx, idx_t col_idx, const idx_t value ) { + values_[index( row_idx, col_idx )] = value TO_FORTRAN; +} + +inline idx_t BlockConnectivityImpl::index( idx_t i, idx_t j ) const { + return i * cols_ + j; } // ------------------------------------------------------------------------------------------------------ @@ -649,21 +606,21 @@ MultiBlockConnectivity* atlas__MultiBlockConnectivity__create(); const char* atlas__Connectivity__name( Connectivity* This ); void atlas__Connectivity__rename( Connectivity* This, const char* name ); void atlas__Connectivity__delete( Connectivity* This ); -void atlas__Connectivity__displs( Connectivity* This, size_t*& displs, size_t& size ); -void atlas__Connectivity__counts( Connectivity* This, size_t*& counts, size_t& size ); -void atlas__Connectivity__values( Connectivity* This, int*& values, size_t& size ); -size_t atlas__Connectivity__rows( const Connectivity* This ); -void atlas__Connectivity__add_values( Connectivity* This, size_t rows, size_t cols, int values[] ); -void atlas__Connectivity__add_missing( Connectivity* This, size_t rows, size_t cols ); -int atlas__Connectivity__missing_value( const Connectivity* This ); - -size_t atlas__MultiBlockConnectivity__blocks( const MultiBlockConnectivity* This ); -BlockConnectivityImpl* atlas__MultiBlockConnectivity__block( MultiBlockConnectivity* This, size_t block_idx ); - -size_t atlas__BlockConnectivity__rows( const BlockConnectivityImpl* This ); -size_t atlas__BlockConnectivity__cols( const BlockConnectivityImpl* This ); -int atlas__BlockConnectivity__missing_value( const BlockConnectivityImpl* This ); -void atlas__BlockConnectivity__data( BlockConnectivityImpl* This, int*& data, size_t& rows, size_t& cols ); +void atlas__Connectivity__displs( Connectivity* This, idx_t*& displs, idx_t& size ); +void atlas__Connectivity__counts( Connectivity* This, idx_t*& counts, idx_t& size ); +void atlas__Connectivity__values( Connectivity* This, idx_t*& values, idx_t& size ); +idx_t atlas__Connectivity__rows( const Connectivity* This ); +void atlas__Connectivity__add_values( Connectivity* This, idx_t rows, idx_t cols, idx_t values[] ); +void atlas__Connectivity__add_missing( Connectivity* This, idx_t rows, idx_t cols ); +idx_t atlas__Connectivity__missing_value( const Connectivity* This ); + +idx_t atlas__MultiBlockConnectivity__blocks( const MultiBlockConnectivity* This ); +BlockConnectivityImpl* atlas__MultiBlockConnectivity__block( MultiBlockConnectivity* This, idx_t block_idx ); + +idx_t atlas__BlockConnectivity__rows( const BlockConnectivityImpl* This ); +idx_t atlas__BlockConnectivity__cols( const BlockConnectivityImpl* This ); +idx_t atlas__BlockConnectivity__missing_value( const BlockConnectivityImpl* This ); +void atlas__BlockConnectivity__data( BlockConnectivityImpl* This, idx_t*& data, idx_t& rows, idx_t& cols ); void atlas__BlockConnectivity__delete( BlockConnectivityImpl* This ); } diff --git a/src/atlas/mesh/ElementType.cc b/src/atlas/mesh/ElementType.cc index 09407a8c0..fb1bdcb0e 100644 --- a/src/atlas/mesh/ElementType.cc +++ b/src/atlas/mesh/ElementType.cc @@ -9,7 +9,7 @@ */ #include "atlas/mesh/ElementType.h" -#include "atlas/runtime/ErrorHandling.h" +#include "atlas/runtime/Exception.h" #include "atlas/util/CoordinateEnums.h" namespace atlas { @@ -18,7 +18,7 @@ namespace mesh { //------------------------------------------------------------------------------ ElementType* ElementType::create( const std::string& ) { - NOTIMP; + ATLAS_NOTIMPLEMENTED; } ElementType::ElementType() {} @@ -28,7 +28,7 @@ ElementType::~ElementType() {} extern "C" { void atlas__mesh__ElementType__delete( ElementType* This ) { - ATLAS_ERROR_HANDLING( delete This ); + delete This; } ElementType* atlas__mesh__Triangle__create() { return new temporary::Triangle(); @@ -41,23 +41,23 @@ ElementType* atlas__mesh__Line__create() { } const char* atlas__mesh__ElementType__name( const ElementType* This ) { - ATLAS_ERROR_HANDLING( ASSERT( This ); return This->name().c_str(); ); - return 0; + ATLAS_ASSERT( This ); + return This->name().c_str(); } -size_t atlas__mesh__ElementType__nb_nodes( const ElementType* This ) { - ATLAS_ERROR_HANDLING( ASSERT( This ); return This->nb_nodes() ); - return 0; +idx_t atlas__mesh__ElementType__nb_nodes( const ElementType* This ) { + ATLAS_ASSERT( This ); + return This->nb_nodes(); } -size_t atlas__mesh__ElementType__nb_edges( const ElementType* This ) { - ATLAS_ERROR_HANDLING( ASSERT( This ); return This->nb_edges() ); - return 0; +idx_t atlas__mesh__ElementType__nb_edges( const ElementType* This ) { + ATLAS_ASSERT( This ); + return This->nb_edges(); } int atlas__mesh__ElementType__parametric( const ElementType* This ) { - ATLAS_ERROR_HANDLING( ASSERT( This ); return This->parametric() ); - return 0; + ATLAS_ASSERT( This ); + return This->parametric(); } } diff --git a/src/atlas/mesh/ElementType.h b/src/atlas/mesh/ElementType.h index c4bc151bb..c7f8f3ba5 100644 --- a/src/atlas/mesh/ElementType.h +++ b/src/atlas/mesh/ElementType.h @@ -13,7 +13,10 @@ #pragma once -#include "eckit/memory/Owned.h" +#include + +#include "atlas/library/config.h" +#include "atlas/util/Object.h" namespace atlas { namespace mesh { @@ -22,7 +25,7 @@ namespace mesh { * \brief ElementType class (abstract) that provides access to geometric * information of an element */ -class ElementType : public eckit::Owned { +class ElementType : public util::Object { public: // methods static ElementType* create( const std::string& ); @@ -34,13 +37,13 @@ class ElementType : public eckit::Owned { //-- Accessors virtual const std::string& name() const = 0; - // virtual size_t dimensionality() const = 0; + // virtual idx_t dimensionality() const = 0; - // virtual size_t nb_vertices() const = 0; - virtual size_t nb_edges() const = 0; - // virtual size_t nb_faces() const = 0; + // virtual idx_t nb_vertices() const = 0; + virtual idx_t nb_edges() const = 0; + // virtual idx_t nb_faces() const = 0; - virtual size_t nb_nodes() const = 0; + virtual idx_t nb_nodes() const = 0; virtual bool parametric() const = 0; }; @@ -65,7 +68,7 @@ class Face : public ElementType { { FACES = 1 }; - virtual size_t nb_faces() const { return FACES; } + virtual idx_t nb_faces() const { return FACES; } }; class Edge : public ElementType { @@ -82,8 +85,8 @@ class Edge : public ElementType { { EDGES = 1 }; - virtual size_t nb_faces() const { return FACES; } - virtual size_t nb_edges() const { return EDGES; } + virtual idx_t nb_faces() const { return FACES; } + virtual idx_t nb_edges() const { return EDGES; } }; class Vertex : public ElementType { @@ -104,9 +107,9 @@ class Vertex : public ElementType { { VERTICES = 1 }; - virtual size_t nb_faces() const { return FACES; } - virtual size_t nb_edges() const { return EDGES; } - virtual size_t nb_vertices() const { return VERTICES; } + virtual idx_t nb_faces() const { return FACES; } + virtual idx_t nb_edges() const { return EDGES; } + virtual idx_t nb_vertices() const { return VERTICES; } }; class Quadrilateral : public Face { @@ -129,11 +132,11 @@ class Quadrilateral : public Face { }; virtual ~Quadrilateral() {} virtual bool parametric() const { return true; } - virtual size_t nb_vertices() const { return VERTICES; } - virtual size_t nb_edges() const { return EDGES; } - virtual size_t nb_nodes() const { return VERTICES; } - virtual size_t nb_facets() const { return FACETS; } - virtual size_t nb_ridges() const { return RIDGES; } + virtual idx_t nb_vertices() const { return VERTICES; } + virtual idx_t nb_edges() const { return EDGES; } + virtual idx_t nb_nodes() const { return VERTICES; } + virtual idx_t nb_facets() const { return FACETS; } + virtual idx_t nb_ridges() const { return RIDGES; } virtual const std::string& name() const { static std::string s( "Quadrilateral" ); return s; @@ -160,11 +163,11 @@ class Triangle : public Face { }; virtual ~Triangle() {} virtual bool parametric() const { return true; } - virtual size_t nb_vertices() const { return VERTICES; } - virtual size_t nb_edges() const { return EDGES; } - virtual size_t nb_nodes() const { return VERTICES; } - virtual size_t nb_facets() const { return FACETS; } - virtual size_t nb_ridges() const { return RIDGES; } + virtual idx_t nb_vertices() const { return VERTICES; } + virtual idx_t nb_edges() const { return EDGES; } + virtual idx_t nb_nodes() const { return VERTICES; } + virtual idx_t nb_facets() const { return FACETS; } + virtual idx_t nb_ridges() const { return RIDGES; } virtual const std::string& name() const { static std::string s( "Triangle" ); return s; @@ -187,10 +190,10 @@ class Line : public Edge { }; virtual ~Line() {} virtual bool parametric() const { return true; } - virtual size_t nb_vertices() const { return VERTICES; } - virtual size_t nb_edges() const { return EDGES; } - virtual size_t nb_nodes() const { return VERTICES; } - virtual size_t nb_facets() const { return FACETS; } + virtual idx_t nb_vertices() const { return VERTICES; } + virtual idx_t nb_edges() const { return EDGES; } + virtual idx_t nb_nodes() const { return VERTICES; } + virtual idx_t nb_facets() const { return FACETS; } virtual const std::string& name() const { static std::string s( "Line" ); return s; @@ -204,8 +207,8 @@ ElementType* atlas__mesh__Quadrilateral__create(); ElementType* atlas__mesh__Line__create(); void atlas__mesh__ElementType__delete( ElementType* This ); -size_t atlas__mesh__ElementType__nb_nodes( const ElementType* This ); -size_t atlas__mesh__ElementType__nb_edges( const ElementType* This ); +idx_t atlas__mesh__ElementType__nb_nodes( const ElementType* This ); +idx_t atlas__mesh__ElementType__nb_edges( const ElementType* This ); int atlas__mesh__ElementType__parametric( const ElementType* This ); const char* atlas__mesh__ElementType__name( const ElementType* This ); } diff --git a/src/atlas/mesh/Elements.cc b/src/atlas/mesh/Elements.cc index 27e1da0fd..dcd309512 100644 --- a/src/atlas/mesh/Elements.cc +++ b/src/atlas/mesh/Elements.cc @@ -13,7 +13,7 @@ #include "atlas/field/Field.h" #include "atlas/library/config.h" #include "atlas/mesh/ElementType.h" -#include "atlas/runtime/ErrorHandling.h" +#include "atlas/runtime/Exception.h" namespace atlas { namespace mesh { @@ -28,21 +28,21 @@ void Elements::rebuild() { end_ = hybrid_elements_->elements_begin_[type_idx_ + 1]; } -Elements::Elements( HybridElements& elements, size_t type_idx ) : +Elements::Elements( HybridElements& elements, idx_t type_idx ) : owns_( false ), hybrid_elements_( &elements ), type_idx_( type_idx ) { rebuild(); } -Elements::Elements( ElementType* element_type, size_t nb_elements, const std::vector& node_connectivity ) : +Elements::Elements( ElementType* element_type, idx_t nb_elements, const std::vector& node_connectivity ) : owns_( true ) { hybrid_elements_ = new HybridElements(); type_idx_ = hybrid_elements_->add( element_type, nb_elements, node_connectivity.data() ); rebuild(); } -Elements::Elements( ElementType* element_type, size_t nb_elements, const idx_t node_connectivity[], +Elements::Elements( ElementType* element_type, idx_t nb_elements, const idx_t node_connectivity[], bool fortran_array ) : owns_( true ) { hybrid_elements_ = new HybridElements(); @@ -156,8 +156,8 @@ array::LocalView Elements::view( Field& field array::Range{begin(), begin() + size()}, array::Range::all() ); } -size_t Elements::add( const size_t nb_elements ) { - size_t position = size(); +idx_t Elements::add( const idx_t nb_elements ) { + idx_t position = size(); hybrid_elements_->insert( type_idx_, end(), nb_elements ); return position; } @@ -167,96 +167,87 @@ size_t Elements::add( const size_t nb_elements ) { extern "C" { void atlas__mesh__Elements__delete( Elements* This ) { - ATLAS_ERROR_HANDLING( delete This ); + delete This; } -size_t atlas__mesh__Elements__size( const Elements* This ) { - ATLAS_ERROR_HANDLING( ASSERT( This != 0 ) ); +idx_t atlas__mesh__Elements__size( const Elements* This ) { + ATLAS_ASSERT( This != nullptr, "Cannot access uninitialised atlas_Elements" ); return This->size(); } -size_t atlas__mesh__Elements__begin( const Elements* This ) { - ATLAS_ERROR_HANDLING( ASSERT( This != 0 ) ); +idx_t atlas__mesh__Elements__begin( const Elements* This ) { + ATLAS_ASSERT( This != nullptr, "Cannot access uninitialised atlas_Elements" ); return This->begin(); } -size_t atlas__mesh__Elements__end( const Elements* This ) { - ATLAS_ERROR_HANDLING( ASSERT( This != 0 ) ); +idx_t atlas__mesh__Elements__end( const Elements* This ) { + ATLAS_ASSERT( This != nullptr, "Cannot access uninitialised atlas_Elements" ); return This->end(); } BlockConnectivity* atlas__mesh__Elements__node_connectivity( Elements* This ) { - BlockConnectivity* connectivity( 0 ); - ATLAS_ERROR_HANDLING( connectivity = &This->node_connectivity() ); - return connectivity; + ATLAS_ASSERT( This != nullptr, "Cannot access uninitialised atlas_Elements" ); + return &This->node_connectivity(); } BlockConnectivity* atlas__mesh__Elements__edge_connectivity( Elements* This ) { - BlockConnectivity* connectivity( 0 ); - ATLAS_ERROR_HANDLING( connectivity = &This->edge_connectivity() ); - return connectivity; + ATLAS_ASSERT( This != nullptr, "Cannot access uninitialised atlas_Elements" ); + return &This->edge_connectivity(); } BlockConnectivity* atlas__mesh__Elements__cell_connectivity( Elements* This ) { - BlockConnectivity* connectivity( 0 ); - ATLAS_ERROR_HANDLING( connectivity = &This->cell_connectivity() ); - return connectivity; + ATLAS_ASSERT( This != nullptr, "Cannot access uninitialised atlas_Elements" ); + return &This->cell_connectivity(); } int atlas__mesh__Elements__has_field( const Elements* This, char* name ) { - ATLAS_ERROR_HANDLING( ASSERT( This != 0 ) ); + ATLAS_ASSERT( This != nullptr, "Cannot access uninitialised atlas_Elements" ); return This->has_field( std::string( name ) ); } int atlas__mesh__Elements__nb_fields( const Elements* This ) { - ATLAS_ERROR_HANDLING( ASSERT( This != 0 ) ); + ATLAS_ASSERT( This != nullptr, "Cannot access uninitialised atlas_Elements" ); return This->nb_fields(); } -field::FieldImpl* atlas__mesh__Elements__field_by_idx( Elements* This, size_t idx ) { - field::FieldImpl* field( 0 ); - ATLAS_ERROR_HANDLING( ASSERT( This != 0 ); field = This->field( idx ).get(); ); - return field; +field::FieldImpl* atlas__mesh__Elements__field_by_idx( Elements* This, idx_t idx ) { + ATLAS_ASSERT( This != nullptr, "Cannot access uninitialised atlas_Elements" ); + return This->field( idx ).get(); } field::FieldImpl* atlas__mesh__Elements__field_by_name( Elements* This, char* name ) { - field::FieldImpl* field( 0 ); - ATLAS_ERROR_HANDLING( ASSERT( This != 0 ); field = This->field( std::string( name ) ).get(); ); - return field; + ATLAS_ASSERT( This != nullptr, "Cannot access uninitialised atlas_Elements" ); + return This->field( std::string( name ) ).get(); } field::FieldImpl* atlas__mesh__Elements__global_index( Elements* This ) { - field::FieldImpl* field( 0 ); - ATLAS_ERROR_HANDLING( ASSERT( This != 0 ); field = This->global_index().get(); ); - return field; + ATLAS_ASSERT( This != nullptr, "Cannot access uninitialised atlas_Elements" ); + return This->global_index().get(); } field::FieldImpl* atlas__mesh__Elements__remote_index( Elements* This ) { - field::FieldImpl* field( 0 ); - ATLAS_ERROR_HANDLING( ASSERT( This != 0 ); field = This->remote_index().get(); ); - return field; + ATLAS_ASSERT( This != nullptr, "Cannot access uninitialised atlas_Elements" ); + return This->remote_index().get(); } field::FieldImpl* atlas__mesh__Elements__partition( Elements* This ) { - field::FieldImpl* field( 0 ); - ATLAS_ERROR_HANDLING( ASSERT( This != 0 ); field = This->partition().get(); ); - return field; + ATLAS_ASSERT( This != nullptr, "Cannot access uninitialised atlas_Elements" ); + return This->partition().get(); } field::FieldImpl* atlas__mesh__Elements__halo( Elements* This ) { - field::FieldImpl* field( 0 ); - ATLAS_ERROR_HANDLING( ASSERT( This != 0 ); field = This->halo().get(); ); - return field; + ATLAS_ASSERT( This != nullptr, "Cannot access uninitialised atlas_Elements" ); + return This->halo().get(); } const ElementType* atlas__mesh__Elements__element_type( const Elements* This ) { - const ElementType* element_type( 0 ); - ATLAS_ERROR_HANDLING( ASSERT( This != 0 ); element_type = &This->element_type(); ); - return element_type; + ATLAS_ASSERT( This != nullptr, "Cannot access uninitialised atlas_Elements" ); + return &This->element_type(); } -void atlas__mesh__Elements__add( Elements* This, size_t nb_elements ) { - ATLAS_ERROR_HANDLING( ASSERT( This != 0 ); This->add( nb_elements ); ); +void atlas__mesh__Elements__add( Elements* This, idx_t nb_elements ) { + ATLAS_ASSERT( This != nullptr, "Cannot access uninitialised atlas_Elements" ); + This->add( nb_elements ); } } diff --git a/src/atlas/mesh/Elements.h b/src/atlas/mesh/Elements.h index b765f00ea..912ca88b5 100644 --- a/src/atlas/mesh/Elements.h +++ b/src/atlas/mesh/Elements.h @@ -16,11 +16,10 @@ #pragma once -#include "eckit/memory/Owned.h" - #include "atlas/array/ArrayView.h" #include "atlas/mesh/Connectivity.h" #include "atlas/mesh/HybridElements.h" +#include "atlas/util/Object.h" namespace atlas { namespace mesh { @@ -34,22 +33,22 @@ namespace mesh { // ------------------------------------------------------------------------------------------------------ /// @brief Describe elements of a single type -class Elements : public eckit::Owned { +class Elements : public util::Object { public: // typedef atlas::mesh::BlockConnectivity Connectivity; public: //-- Constructors /// @brief Constructor that treats elements as sub-elements in HybridElements - Elements( HybridElements& elements, size_t type_idx ); + Elements( HybridElements& elements, idx_t type_idx ); /// @brief Constructor that internally creates a HybridElements that owns the /// data - Elements( ElementType*, size_t nb_elements, const std::vector& node_connectivity ); + Elements( ElementType*, idx_t nb_elements, const std::vector& node_connectivity ); /// @brief Constructor that internally creates a HybridElements that owns the /// data - Elements( ElementType*, size_t nb_elements, const idx_t node_connectivity[], bool fortran_array = false ); + Elements( ElementType*, idx_t nb_elements, const idx_t node_connectivity[], bool fortran_array = false ); /// @brief Destructor virtual ~Elements(); @@ -57,16 +56,16 @@ class Elements : public eckit::Owned { //-- Accessors /// @brief Number of elements - size_t size() const; + idx_t size() const; /// @brief Name of this element type const std::string& name() const; /// @brief Number of nodes for each element type - size_t nb_nodes() const; + idx_t nb_nodes() const; /// @brief Number of edges for each element type - size_t nb_edges() const; + idx_t nb_edges() const; /// @brief Element to Node connectivity table const BlockConnectivity& node_connectivity() const; @@ -88,21 +87,21 @@ class Elements : public eckit::Owned { // const HybridElements& hybrid_elements() const; /// @brief Index of Elements in hybrid_elements - // size_t type_idx() const; + // idx_t type_idx() const; /// @brief Begin of elements in hybrid_elements - size_t begin() const; + idx_t begin() const; /// @brief End of elements in hybrid_elements - size_t end() const; + idx_t end() const; const Field& field( const std::string& name ) const { return hybrid_elements_->field( name ); } Field& field( const std::string& name ) { return hybrid_elements_->field( name ); } bool has_field( const std::string& name ) const { return hybrid_elements_->has_field( name ); } - const Field& field( size_t idx ) const { return hybrid_elements_->field( idx ); } - Field& field( size_t idx ) { return hybrid_elements_->field( idx ); } - size_t nb_fields() const { return hybrid_elements_->nb_fields(); } + const Field& field( idx_t idx ) const { return hybrid_elements_->field( idx ); } + Field& field( idx_t idx ) { return hybrid_elements_->field( idx ); } + idx_t nb_fields() const { return hybrid_elements_->nb_fields(); } const Field& global_index() const { return hybrid_elements_->global_index(); } Field& global_index() { return hybrid_elements_->global_index(); } @@ -125,7 +124,7 @@ class Elements : public eckit::Owned { template array::LocalView view( Field& ) const; - size_t add( const size_t nb_elements ); + idx_t add( const idx_t nb_elements ); private: friend class HybridElements; @@ -134,29 +133,29 @@ class Elements : public eckit::Owned { private: bool owns_; HybridElements* hybrid_elements_; - size_t size_; - size_t begin_; - size_t end_; - size_t type_idx_; - size_t nb_nodes_; - size_t nb_edges_; + idx_t size_; + idx_t begin_; + idx_t end_; + idx_t type_idx_; + idx_t nb_nodes_; + idx_t nb_edges_; }; // ------------------------------------------------------------------------------------------------------ -inline size_t Elements::size() const { +inline idx_t Elements::size() const { return size_; } -inline size_t Elements::nb_nodes() const { +inline idx_t Elements::nb_nodes() const { return nb_nodes_; } -inline size_t Elements::nb_edges() const { +inline idx_t Elements::nb_edges() const { return nb_edges_; } -// inline size_t Elements::type_idx() const +// inline idx_t Elements::type_idx() const //{ // return type_idx_; //} @@ -230,11 +229,11 @@ inline const ElementType& Elements::element_type() const { return hybrid_elements_->element_type( type_idx_ ); } -inline size_t Elements::begin() const { +inline idx_t Elements::begin() const { return begin_; } -inline size_t Elements::end() const { +inline idx_t Elements::end() const { return end_; } @@ -242,22 +241,22 @@ inline size_t Elements::end() const { extern "C" { void atlas__mesh__Elements__delete( Elements* This ); -size_t atlas__mesh__Elements__size( const Elements* This ); -size_t atlas__mesh__Elements__begin( const Elements* This ); -size_t atlas__mesh__Elements__end( const Elements* This ); +idx_t atlas__mesh__Elements__size( const Elements* This ); +idx_t atlas__mesh__Elements__begin( const Elements* This ); +idx_t atlas__mesh__Elements__end( const Elements* This ); BlockConnectivity* atlas__mesh__Elements__node_connectivity( Elements* This ); BlockConnectivity* atlas__mesh__Elements__edge_connectivity( Elements* This ); BlockConnectivity* atlas__mesh__Elements__cell_connectivity( Elements* This ); int atlas__mesh__Elements__has_field( const Elements* This, char* name ); int atlas__mesh__Elements__nb_fields( const Elements* This ); -field::FieldImpl* atlas__mesh__Elements__field_by_idx( Elements* This, size_t idx ); +field::FieldImpl* atlas__mesh__Elements__field_by_idx( Elements* This, idx_t idx ); field::FieldImpl* atlas__mesh__Elements__field_by_name( Elements* This, char* name ); field::FieldImpl* atlas__mesh__Elements__global_index( Elements* This ); field::FieldImpl* atlas__mesh__Elements__remote_index( Elements* This ); field::FieldImpl* atlas__mesh__Elements__partition( Elements* This ); field::FieldImpl* atlas__mesh__Elements__halo( Elements* This ); const ElementType* atlas__mesh__Elements__element_type( const Elements* This ); -void atlas__mesh__Elements__add( Elements* This, size_t nb_elements ); +void atlas__mesh__Elements__add( Elements* This, idx_t nb_elements ); } //------------------------------------------------------------------------------------------------------ diff --git a/src/atlas/mesh/Halo.cc b/src/atlas/mesh/Halo.cc index 498742e72..802a60cc4 100644 --- a/src/atlas/mesh/Halo.cc +++ b/src/atlas/mesh/Halo.cc @@ -8,10 +8,9 @@ * nor does it submit to any jurisdiction. */ -#include "eckit/exception/Exceptions.h" - #include "atlas/mesh/Halo.h" #include "atlas/mesh/Mesh.h" +#include "atlas/runtime/Exception.h" #include "atlas/util/Metadata.h" namespace atlas { @@ -27,8 +26,8 @@ Halo::Halo( const detail::MeshImpl& mesh ) { mesh.metadata().get( "halo", size_ ); } -long Halo::size() const { - ASSERT( size_ >= 0 ); +int Halo::size() const { + ATLAS_ASSERT( size_ >= 0 ); return size_; } diff --git a/src/atlas/mesh/Halo.h b/src/atlas/mesh/Halo.h index af523a7da..9c205bed2 100644 --- a/src/atlas/mesh/Halo.h +++ b/src/atlas/mesh/Halo.h @@ -31,11 +31,11 @@ class Halo { Halo() {} Halo( const Mesh& mesh ); Halo( const detail::MeshImpl& mesh ); - Halo( const long size ) : size_( size ) {} - long size() const; + Halo( const int size ) : size_( size ) {} + int size() const; private: - long size_{-1}; + int size_{-1}; }; } // namespace mesh diff --git a/src/atlas/mesh/HybridElements.cc b/src/atlas/mesh/HybridElements.cc index d663321d2..32393e029 100644 --- a/src/atlas/mesh/HybridElements.cc +++ b/src/atlas/mesh/HybridElements.cc @@ -11,7 +11,6 @@ #include #include "eckit/log/Bytes.h" -#include "eckit/memory/SharedPtr.h" #include "atlas/array/MakeView.h" #include "atlas/field/Field.h" @@ -20,7 +19,7 @@ #include "atlas/mesh/Elements.h" #include "atlas/mesh/HybridElements.h" #include "atlas/mesh/Mesh.h" -#include "atlas/runtime/ErrorHandling.h" +#include "atlas/runtime/Exception.h" #include "atlas/runtime/Log.h" #if ATLAS_HAVE_FORTRAN @@ -44,14 +43,14 @@ namespace mesh { namespace { -static void set_uninitialized_fields_to_zero( HybridElements& elems, size_t begin ) { +static void set_uninitialized_fields_to_zero( HybridElements& elems, idx_t begin ) { ArrayView global_index = make_view( elems.global_index() ); - IndexView remote_index = make_indexview( elems.remote_index() ); + IndexView remote_index = make_indexview( elems.remote_index() ); ArrayView partition = make_view( elems.partition() ); ArrayView halo = make_view( elems.halo() ); ArrayView flags = make_view( elems.flags() ); - for ( size_t j = begin; j < elems.size(); ++j ) { + for ( idx_t j = begin; j < elems.size(); ++j ) { global_index( j ) = 0; remote_index( j ) = 0; partition( j ) = 0; @@ -65,7 +64,7 @@ static void set_uninitialized_fields_to_zero( HybridElements& elems, size_t begi HybridElements::HybridElements() : size_( 0 ), elements_size_(), elements_begin_( 1, 0ul ), type_idx_() { add( Field( "glb_idx", make_datatype(), make_shape( size() ) ) ); - add( Field( "remote_idx", make_datatype(), make_shape( size() ) ) ); + add( Field( "remote_idx", make_datatype(), make_shape( size() ) ) ); add( Field( "partition", make_datatype(), make_shape( size() ) ) ); add( Field( "halo", make_datatype(), make_shape( size() ) ) ); add( Field( "flags", make_datatype(), make_shape( size() ) ) ); @@ -79,23 +78,23 @@ HybridElements::HybridElements() : size_( 0 ), elements_size_(), elements_begin_ HybridElements::~HybridElements() {} Field HybridElements::add( const Field& field ) { - ASSERT( field ); - ASSERT( !field.name().empty() ); + ATLAS_ASSERT( field ); + ATLAS_ASSERT( !field.name().empty() ); if ( has_field( field.name() ) ) { std::stringstream msg; msg << "Trying to add field '" << field.name() << "' to HybridElements, but HybridElements already has a field with " "this name."; - throw eckit::Exception( msg.str(), Here() ); + throw_Exception( msg.str(), Here() ); } fields_[field.name()] = field; return field; } -void HybridElements::resize( size_t size ) { - size_t old_size = size_; - size_ = size; +void HybridElements::resize( idx_t size ) { + idx_t old_size = size_; + size_ = size; for ( FieldMap::iterator it = fields_.begin(); it != fields_.end(); ++it ) { Field& field = it->second; array::ArrayShape shape = field.shape(); @@ -109,8 +108,9 @@ void HybridElements::resize( size_t size ) { void HybridElements::remove_field( const std::string& name ) { if ( !has_field( name ) ) { std::stringstream msg; - msg << "Trying to remove field `" << name << "' in Nodes, but no field with this name is present in Nodes."; - throw eckit::Exception( msg.str(), Here() ); + msg << "Trying to remove field `" << name + << "' in HybridElements, but no field with this name is present in HybridElements."; + throw_Exception( msg.str(), Here() ); } fields_.erase( name ); } @@ -118,8 +118,9 @@ void HybridElements::remove_field( const std::string& name ) { const Field& HybridElements::field( const std::string& name ) const { if ( !has_field( name ) ) { std::stringstream msg; - msg << "Trying to access field `" << name << "' in Nodes, but no field with this name is present in Nodes."; - throw eckit::Exception( msg.str(), Here() ); + msg << "Trying to access field `" << name + << "' in HybridElements, but no field with this name is present in HybridElements."; + throw_Exception( msg.str(), Here() ); } return fields_.find( name )->second; } @@ -128,9 +129,9 @@ Field& HybridElements::field( const std::string& name ) { return const_cast( static_cast( this )->field( name ) ); } -const Field& HybridElements::field( size_t idx ) const { - ASSERT( idx < nb_fields() ); - size_t c( 0 ); +const Field& HybridElements::field( idx_t idx ) const { + ATLAS_ASSERT( idx < nb_fields() ); + idx_t c( 0 ); for ( FieldMap::const_iterator it = fields_.begin(); it != fields_.end(); ++it ) { if ( idx == c ) { const Field& field = it->second; @@ -138,10 +139,10 @@ const Field& HybridElements::field( size_t idx ) const { } c++; } - throw eckit::SeriousBug( "Should not be here!", Here() ); + throw_Exception( "Should not be here!", Here() ); } -Field& HybridElements::field( size_t idx ) { +Field& HybridElements::field( idx_t idx ) { return const_cast( static_cast( this )->field( idx ) ); } @@ -150,27 +151,27 @@ HybridElements::Connectivity& HybridElements::add( Connectivity* connectivity ) return *connectivity; } -size_t HybridElements::add( const ElementType* element_type, size_t nb_elements, - const std::vector& connectivity ) { +idx_t HybridElements::add( const ElementType* element_type, idx_t nb_elements, + const std::vector& connectivity ) { return add( element_type, nb_elements, connectivity.data() ); } -size_t HybridElements::add( const ElementType* element_type, size_t nb_elements, const idx_t connectivity[] ) { +idx_t HybridElements::add( const ElementType* element_type, idx_t nb_elements, const idx_t connectivity[] ) { return add( element_type, nb_elements, connectivity, false ); } -size_t HybridElements::add( const ElementType* element_type, size_t nb_elements, const idx_t connectivity[], - bool fortran_array ) { - eckit::SharedPtr etype( element_type ); +idx_t HybridElements::add( const ElementType* element_type, idx_t nb_elements, const idx_t connectivity[], + bool fortran_array ) { + util::ObjectHandle etype( element_type ); - size_t old_size = size(); - size_t new_size = old_size + nb_elements; + idx_t old_size = size(); + idx_t new_size = old_size + nb_elements; - size_t nb_nodes = etype->nb_nodes(); + idx_t nb_nodes = etype->nb_nodes(); type_idx_.resize( new_size ); - for ( size_t e = old_size; e < new_size; ++e ) { + for ( idx_t e = old_size; e < new_size; ++e ) { type_idx_[e] = element_types_.size(); } @@ -179,38 +180,30 @@ size_t HybridElements::add( const ElementType* element_type, size_t nb_elements, element_types_.push_back( etype ); elements_.resize( element_types_.size() ); - for ( size_t t = 0; t < nb_types(); ++t ) { + for ( idx_t t = 0; t < nb_types(); ++t ) { if ( elements_[t] ) elements_[t]->rebuild(); else - elements_[t].reset( new Elements( *this, t ) ); + elements_[t] = util::ObjectHandle( new Elements( *this, t ) ); } - // for( size_t t=0; trebuild(); - // } - // element_types_.push_back( etype ); - // elements_.push_back( eckit::SharedPtr(new - // Elements(*this,type_idx_.back())) ); - node_connectivity_->add( nb_elements, nb_nodes, connectivity, fortran_array ); resize( new_size ); return element_types_.size() - 1; } -size_t HybridElements::add( const ElementType* element_type, size_t nb_elements ) { - eckit::SharedPtr etype( element_type ); +idx_t HybridElements::add( const ElementType* element_type, idx_t nb_elements ) { + util::ObjectHandle etype( element_type ); - size_t old_size = size(); - size_t new_size = old_size + nb_elements; + idx_t old_size = size(); + idx_t new_size = old_size + nb_elements; - size_t nb_nodes = etype->nb_nodes(); + idx_t nb_nodes = etype->nb_nodes(); type_idx_.resize( new_size ); - for ( size_t e = old_size; e < new_size; ++e ) { + for ( idx_t e = old_size; e < new_size; ++e ) { type_idx_[e] = element_types_.size(); } @@ -219,8 +212,8 @@ size_t HybridElements::add( const ElementType* element_type, size_t nb_elements element_types_.push_back( etype ); elements_.resize( element_types_.size() ); - for ( size_t t = 0; t < nb_types(); ++t ) { - elements_[t].reset( new Elements( *this, t ) ); + for ( idx_t t = 0; t < nb_types(); ++t ) { + elements_[t] = util::ObjectHandle( new Elements( *this, t ) ); } node_connectivity_->add( nb_elements, nb_nodes ); @@ -228,29 +221,29 @@ size_t HybridElements::add( const ElementType* element_type, size_t nb_elements return element_types_.size() - 1; } -size_t HybridElements::add( const Elements& elems ) { +idx_t HybridElements::add( const Elements& elems ) { bool fortran_array = true; return add( &elems.element_type(), elems.size(), elems.node_connectivity().data(), fortran_array ); } -const std::string& HybridElements::name( size_t elem_idx ) const { +const std::string& HybridElements::name( idx_t elem_idx ) const { return element_types_[type_idx_[elem_idx]]->name(); } -size_t HybridElements::elemtype_nb_nodes( size_t elem_idx ) const { +idx_t HybridElements::elemtype_nb_nodes( idx_t elem_idx ) const { return element_type( type_idx( elem_idx ) ).nb_nodes(); } -size_t HybridElements::elemtype_nb_edges( size_t elem_idx ) const { +idx_t HybridElements::elemtype_nb_edges( idx_t elem_idx ) const { return element_type( type_idx( elem_idx ) ).nb_edges(); } -void HybridElements::insert( size_t type_idx, size_t position, size_t nb_elements ) { +void HybridElements::insert( idx_t type_idx, idx_t position, idx_t nb_elements ) { type_idx_.insert( type_idx_.begin() + position, nb_elements, type_idx ); elements_size_[type_idx] += nb_elements; - for ( size_t jtype = type_idx + 1; jtype < nb_types() + 1; ++jtype ) + for ( idx_t jtype = type_idx + 1; jtype < nb_types() + 1; ++jtype ) elements_begin_[jtype] += nb_elements; - for ( size_t t = 0; t < nb_types(); ++t ) { + for ( idx_t t = 0; t < nb_types(); ++t ) { elements_[t]->rebuild(); } node_connectivity_->insert( position, nb_elements, element_types_[type_idx]->nb_nodes() ); @@ -282,21 +275,15 @@ void HybridElements::clear() { void HybridElements::cloneToDevice() const { std::for_each( fields_.begin(), fields_.end(), []( const FieldMap::value_type& v ) { v.second.cloneToDevice(); } ); - std::for_each( connectivities_.begin(), connectivities_.end(), - []( const ConnectivityMap::value_type& v ) { v.second->cloneToDevice(); } ); } void HybridElements::cloneFromDevice() const { std::for_each( fields_.begin(), fields_.end(), []( const FieldMap::value_type& v ) { v.second.cloneFromDevice(); } ); - std::for_each( connectivities_.begin(), connectivities_.end(), - []( const ConnectivityMap::value_type& v ) { v.second->cloneFromDevice(); } ); } void HybridElements::syncHostDevice() const { std::for_each( fields_.begin(), fields_.end(), []( const FieldMap::value_type& v ) { v.second.syncHostDevice(); } ); - std::for_each( connectivities_.begin(), connectivities_.end(), - []( const ConnectivityMap::value_type& v ) { v.second->syncHostDevice(); } ); } size_t HybridElements::footprint() const { @@ -307,8 +294,8 @@ size_t HybridElements::footprint() const { for ( ConnectivityMap::const_iterator it = connectivities_.begin(); it != connectivities_.end(); ++it ) { size += ( *it ).second->footprint(); } - size += elements_size_.capacity() * sizeof( size_t ); - size += elements_begin_.capacity() * sizeof( size_t ); + size += elements_size_.capacity() * sizeof( idx_t ); + size += elements_begin_.capacity() * sizeof( idx_t ); size += metadata_.footprint(); @@ -319,106 +306,100 @@ size_t HybridElements::footprint() const { extern "C" { HybridElements* atlas__mesh__HybridElements__create() { - HybridElements* This = 0; - ATLAS_ERROR_HANDLING( This = new HybridElements() ); - return This; + return new HybridElements(); } void atlas__mesh__HybridElements__delete( HybridElements* This ) { - ATLAS_ERROR_HANDLING( delete This ); + ATLAS_ASSERT( This != nullptr, "Cannot access uninitialised atlas_mesh_HybridElements" ); + delete This; } MultiBlockConnectivity* atlas__mesh__HybridElements__node_connectivity( HybridElements* This ) { - MultiBlockConnectivity* connectivity( 0 ); - ATLAS_ERROR_HANDLING( connectivity = &This->node_connectivity() ); - return connectivity; + ATLAS_ASSERT( This != nullptr, "Cannot access uninitialised atlas_mesh_HybridElements" ); + return &This->node_connectivity(); } MultiBlockConnectivity* atlas__mesh__HybridElements__edge_connectivity( HybridElements* This ) { - MultiBlockConnectivity* connectivity( 0 ); - ATLAS_ERROR_HANDLING( connectivity = &This->edge_connectivity() ); - return connectivity; + ATLAS_ASSERT( This != nullptr, "Cannot access uninitialised atlas_mesh_HybridElements" ); + return &This->edge_connectivity(); } MultiBlockConnectivity* atlas__mesh__HybridElements__cell_connectivity( HybridElements* This ) { - MultiBlockConnectivity* connectivity( 0 ); - ATLAS_ERROR_HANDLING( connectivity = &This->cell_connectivity() ); - return connectivity; + ATLAS_ASSERT( This != nullptr, "Cannot access uninitialised atlas_mesh_HybridElements" ); + return &This->cell_connectivity(); } -size_t atlas__mesh__HybridElements__size( const HybridElements* This ) { +idx_t atlas__mesh__HybridElements__size( const HybridElements* This ) { + ATLAS_ASSERT( This != nullptr, "Cannot access uninitialised atlas_mesh_HybridElements" ); return This->size(); } -void atlas__mesh__HybridElements__add_elements( HybridElements* This, ElementType* elementtype, size_t nb_elements ) { +void atlas__mesh__HybridElements__add_elements( HybridElements* This, ElementType* elementtype, idx_t nb_elements ) { + ATLAS_ASSERT( This != nullptr, "Cannot access uninitialised atlas_mesh_HybridElements" ); This->add( elementtype, nb_elements ); } void atlas__mesh__HybridElements__add_elements_with_nodes( HybridElements* This, ElementType* elementtype, - size_t nb_elements, int node_connectivity[], + idx_t nb_elements, idx_t node_connectivity[], int fortran_array ) { + ATLAS_ASSERT( This != nullptr, "Cannot access uninitialised atlas_mesh_HybridElements" ); + ATLAS_ASSERT( elementtype != nullptr, "Cannot access uninitialised atlas_mesh_ElementType" ); This->add( elementtype, nb_elements, node_connectivity, fortran_array ); } int atlas__mesh__HybridElements__has_field( const HybridElements* This, char* name ) { - ATLAS_ERROR_HANDLING( ASSERT( This != 0 ) ); + ATLAS_ASSERT( This != nullptr, "Cannot access uninitialised atlas_mesh_HybridElements" ); return This->has_field( std::string( name ) ); } int atlas__mesh__HybridElements__nb_fields( const HybridElements* This ) { - ATLAS_ERROR_HANDLING( ASSERT( This != 0 ) ); + ATLAS_ASSERT( This != nullptr, "Cannot access uninitialised atlas_mesh_HybridElements" ); return This->nb_fields(); } int atlas__mesh__HybridElements__nb_types( const HybridElements* This ) { - ATLAS_ERROR_HANDLING( ASSERT( This != 0 ) ); + ATLAS_ASSERT( This != nullptr, "Cannot access uninitialised atlas_mesh_HybridElements" ); return This->nb_types(); } -field::FieldImpl* atlas__mesh__HybridElements__field_by_idx( HybridElements* This, size_t idx ) { - field::FieldImpl* field( 0 ); - ATLAS_ERROR_HANDLING( ASSERT( This != 0 ); field = This->field( idx ).get(); ); - return field; +field::FieldImpl* atlas__mesh__HybridElements__field_by_idx( HybridElements* This, idx_t idx ) { + ATLAS_ASSERT( This != nullptr, "Cannot access uninitialised atlas_mesh_HybridElements" ); + return This->field( idx ).get(); } field::FieldImpl* atlas__mesh__HybridElements__field_by_name( HybridElements* This, char* name ) { - field::FieldImpl* field( 0 ); - ATLAS_ERROR_HANDLING( ASSERT( This != 0 ); field = This->field( std::string( name ) ).get(); ); - return field; + ATLAS_ASSERT( This != nullptr, "Cannot access uninitialised atlas_mesh_HybridElements" ); + return This->field( std::string( name ) ).get(); } field::FieldImpl* atlas__mesh__HybridElements__global_index( HybridElements* This ) { - field::FieldImpl* field( 0 ); - ATLAS_ERROR_HANDLING( ASSERT( This != 0 ); field = This->global_index().get(); ); - return field; + ATLAS_ASSERT( This != nullptr, "Cannot access uninitialised atlas_mesh_HybridElements" ); + return This->global_index().get(); } field::FieldImpl* atlas__mesh__HybridElements__remote_index( HybridElements* This ) { - field::FieldImpl* field( 0 ); - ATLAS_ERROR_HANDLING( ASSERT( This != 0 ); field = This->remote_index().get(); ); - return field; + ATLAS_ASSERT( This != nullptr, "Cannot access uninitialised atlas_mesh_HybridElements" ); + return This->remote_index().get(); } field::FieldImpl* atlas__mesh__HybridElements__partition( HybridElements* This ) { - field::FieldImpl* field( 0 ); - ATLAS_ERROR_HANDLING( ASSERT( This != 0 ); field = This->partition().get(); ); - return field; + ATLAS_ASSERT( This != nullptr, "Cannot access uninitialised atlas_mesh_HybridElements" ); + return This->partition().get(); } field::FieldImpl* atlas__mesh__HybridElements__halo( HybridElements* This ) { - field::FieldImpl* field( 0 ); - ATLAS_ERROR_HANDLING( ASSERT( This != 0 ); field = This->halo().get(); ); - return field; + ATLAS_ASSERT( This != nullptr, "Cannot access uninitialised atlas_mesh_HybridElements" ); + return This->halo().get(); } -Elements* atlas__mesh__HybridElements__elements( HybridElements* This, size_t idx ) { - Elements* elements( 0 ); - ATLAS_ERROR_HANDLING( ASSERT( This != 0 ); elements = &This->elements( idx ); ); - return elements; +Elements* atlas__mesh__HybridElements__elements( HybridElements* This, idx_t idx ) { + ATLAS_ASSERT( This != nullptr, "Cannot access uninitialised atlas_mesh_HybridElements" ); + return &This->elements( idx ); } void atlas__mesh__HybridElements__add_field( HybridElements* This, field::FieldImpl* field ) { - ATLAS_ERROR_HANDLING( ASSERT( This ); This->add( field ); ); + ATLAS_ASSERT( This != nullptr, "Cannot access uninitialised atlas_mesh_HybridElements" ); + This->add( field ); } } diff --git a/src/atlas/mesh/HybridElements.h b/src/atlas/mesh/HybridElements.h index 3e5f9b5f9..e95dbeb8e 100644 --- a/src/atlas/mesh/HybridElements.h +++ b/src/atlas/mesh/HybridElements.h @@ -16,14 +16,21 @@ #pragma once -#include "eckit/memory/Owned.h" -#include "eckit/memory/SharedPtr.h" +#include + +#include "atlas/util/Object.h" +#include "atlas/util/ObjectHandle.h" #include "atlas/field/Field.h" -#include "atlas/mesh/Connectivity.h" #include "atlas/util/Metadata.h" -#include "atlas/field/detail/FieldImpl.h" // only included for Fortran interface +#include "atlas/mesh/Connectivity.h" + +namespace atlas { +namespace field { +class FieldImpl; +} +} // namespace atlas namespace atlas { class Mesh; @@ -39,13 +46,22 @@ class Elements; } } // namespace atlas +namespace atlas { +namespace mesh { +template +class ConnectivityInterface; +class MultiBlockConnectivityImpl; +using MultiBlockConnectivity = ConnectivityInterface; +} // namespace mesh +} // namespace atlas + namespace atlas { namespace mesh { // ------------------------------------------------------------------------------- /// @brief HybridElements class that describes elements of different types -class HybridElements : public eckit::Owned { +class HybridElements : public util::Object { friend class Elements; public: @@ -59,19 +75,19 @@ class HybridElements : public eckit::Owned { //-- Accessors /// @brief Number of elements - size_t size() const; + idx_t size() const; /// @brief Number of nodes for given element - size_t nb_nodes( size_t elem_idx ) const; + idx_t nb_nodes( idx_t elem_idx ) const; /// @brief Number of edges for given element - size_t nb_edges( size_t elem_idx ) const; + idx_t nb_edges( idx_t elem_idx ) const; /// @brief Element type index for given element - size_t type_idx( size_t elem_idx ) const; + idx_t type_idx( idx_t elem_idx ) const; /// @brief Element type name for given element - const std::string& name( size_t elem_idx ) const; + const std::string& name( idx_t elem_idx ) const; /// @brief Element to Node connectivity table const HybridElements::Connectivity& node_connectivity() const; @@ -86,23 +102,23 @@ class HybridElements : public eckit::Owned { HybridElements::Connectivity& cell_connectivity(); /// @brief Number of types present in HybridElements - size_t nb_types() const; + idx_t nb_types() const; /// @brief The element_type description for given type - const ElementType& element_type( size_t type_idx ) const; + const ElementType& element_type( idx_t type_idx ) const; /// @brief Sub-elements convenience class for given type /// This allows optimized access to connectivities and loops. - const Elements& elements( size_t type_idx ) const; - Elements& elements( size_t type_idx ); + const Elements& elements( idx_t type_idx ) const; + Elements& elements( idx_t type_idx ); const Field& field( const std::string& name ) const; Field& field( const std::string& name ); bool has_field( const std::string& name ) const { return ( fields_.find( name ) != fields_.end() ); } - const Field& field( size_t ) const; - Field& field( size_t ); - size_t nb_fields() const { return fields_.size(); } + const Field& field( idx_t ) const; + Field& field( idx_t ); + idx_t nb_fields() const { return static_cast( fields_.size() ); } const util::Metadata& metadata() const { return metadata_; } util::Metadata& metadata() { return metadata_; } @@ -126,33 +142,33 @@ class HybridElements : public eckit::Owned { /// @brief Add a new element type with given number of elements /// @return type_idx of the added element type - size_t add( const ElementType*, size_t nb_elements ); + idx_t add( const ElementType*, idx_t nb_elements ); /// @brief Add a new element type with given number of elements and /// node-connectivity /// @return type_idx of the added element type - size_t add( const ElementType*, size_t nb_elements, const std::vector& node_connectivity ); + idx_t add( const ElementType*, idx_t nb_elements, const std::vector& node_connectivity ); /// @brief Add a new element type with given number of elements and /// node-connectivity /// @return type_idx of the added element type - size_t add( const ElementType*, size_t nb_elements, const idx_t node_connectivity[] ); + idx_t add( const ElementType*, idx_t nb_elements, const idx_t node_connectivity[] ); /// @brief Add a new element type with given number of elements and /// node-connectivity /// @return type_idx of the added element type - size_t add( const ElementType*, size_t nb_elements, const idx_t node_connectivity[], bool fortran_array ); + idx_t add( const ElementType*, idx_t nb_elements, const idx_t node_connectivity[], bool fortran_array ); /// @brief Add a new element type from existing Elements. /// Data will be copied. /// @return type_idx of the added element type - size_t add( const Elements& ); + idx_t add( const Elements& ); Field add( const Field& field ); void remove_field( const std::string& name ); - void insert( size_t type_idx, size_t position, size_t nb_elements = 1 ); + void insert( idx_t type_idx, idx_t position, idx_t nb_elements = 1 ); void cloneToDevice() const; @@ -167,30 +183,30 @@ class HybridElements : public eckit::Owned { private: // -- types typedef std::map FieldMap; - typedef std::map> ConnectivityMap; + typedef std::map> ConnectivityMap; private: // -- methods - void resize( size_t size ); + void resize( idx_t size ); - size_t elemtype_nb_nodes( size_t elem_idx ) const; - size_t elemtype_nb_edges( size_t elem_idx ) const; + idx_t elemtype_nb_nodes( idx_t elem_idx ) const; + idx_t elemtype_nb_edges( idx_t elem_idx ) const; Connectivity& add( Connectivity* ); private: // -- Data // -- Total number of elements - size_t size_; + idx_t size_; // -- Data: one value per type - std::vector elements_size_; - std::vector elements_begin_; - std::vector> element_types_; + std::vector elements_size_; + std::vector elements_begin_; + std::vector> element_types_; // -- Data: one value per element - std::vector type_idx_; + std::vector type_idx_; // -- Sub elements - std::vector> elements_; + std::vector> elements_; // -- Fields and connectivities FieldMap fields_; @@ -207,15 +223,15 @@ class HybridElements : public eckit::Owned { // ----------------------------------------------------------------------------------------------------- -inline size_t HybridElements::size() const { +inline idx_t HybridElements::size() const { return size_; } -inline size_t HybridElements::nb_types() const { - return element_types_.size(); +inline idx_t HybridElements::nb_types() const { + return static_cast( element_types_.size() ); } -inline const ElementType& HybridElements::element_type( size_t type_idx ) const { +inline const ElementType& HybridElements::element_type( idx_t type_idx ) const { return *element_types_[type_idx].get(); } @@ -243,23 +259,23 @@ inline HybridElements::Connectivity& HybridElements::cell_connectivity() { return *cell_connectivity_; } -inline const Elements& HybridElements::elements( size_t type_idx ) const { +inline const Elements& HybridElements::elements( idx_t type_idx ) const { return *elements_[type_idx].get(); } -inline Elements& HybridElements::elements( size_t type_idx ) { +inline Elements& HybridElements::elements( idx_t type_idx ) { return *elements_[type_idx].get(); } -inline size_t HybridElements::nb_nodes( size_t elem_idx ) const { +inline idx_t HybridElements::nb_nodes( idx_t elem_idx ) const { return node_connectivity_->rows() ? node_connectivity_->cols( elem_idx ) : elemtype_nb_nodes( elem_idx ); } -inline size_t HybridElements::nb_edges( size_t elem_idx ) const { +inline idx_t HybridElements::nb_edges( idx_t elem_idx ) const { return edge_connectivity_->rows() ? edge_connectivity_->cols( elem_idx ) : elemtype_nb_edges( elem_idx ); } -inline size_t HybridElements::type_idx( size_t elem_idx ) const { +inline idx_t HybridElements::type_idx( idx_t elem_idx ) const { return type_idx_[elem_idx]; } @@ -272,23 +288,23 @@ MultiBlockConnectivity* atlas__mesh__HybridElements__node_connectivity( HybridEl MultiBlockConnectivity* atlas__mesh__HybridElements__edge_connectivity( HybridElements* This ); MultiBlockConnectivity* atlas__mesh__HybridElements__cell_connectivity( HybridElements* This ); -size_t atlas__mesh__HybridElements__size( const HybridElements* This ); -void atlas__mesh__HybridElements__add_elements( HybridElements* This, ElementType* elementtype, size_t nb_elements ); +idx_t atlas__mesh__HybridElements__size( const HybridElements* This ); +void atlas__mesh__HybridElements__add_elements( HybridElements* This, ElementType* elementtype, idx_t nb_elements ); void atlas__mesh__HybridElements__add_elements_with_nodes( HybridElements* This, ElementType* elementtype, - size_t nb_elements, int node_connectivity[], + idx_t nb_elements, idx_t node_connectivity[], int fortran_array ); void atlas__mesh__HybridElements__add_field( HybridElements* This, field::FieldImpl* field ); int atlas__mesh__HybridElements__has_field( const HybridElements* This, char* name ); int atlas__mesh__HybridElements__nb_fields( const HybridElements* This ); int atlas__mesh__HybridElements__nb_types( const HybridElements* This ); field::FieldImpl* atlas__mesh__HybridElements__field_by_name( HybridElements* This, char* name ); -field::FieldImpl* atlas__mesh__HybridElements__field_by_idx( HybridElements* This, size_t idx ); +field::FieldImpl* atlas__mesh__HybridElements__field_by_idx( HybridElements* This, idx_t idx ); field::FieldImpl* atlas__mesh__HybridElements__global_index( HybridElements* This ); field::FieldImpl* atlas__mesh__HybridElements__remote_index( HybridElements* This ); field::FieldImpl* atlas__mesh__HybridElements__partition( HybridElements* This ); field::FieldImpl* atlas__mesh__HybridElements__halo( HybridElements* This ); -Elements* atlas__mesh__HybridElements__elements( HybridElements* This, size_t idx ); +Elements* atlas__mesh__HybridElements__elements( HybridElements* This, idx_t idx ); } } // namespace mesh diff --git a/src/atlas/mesh/IsGhostNode.h b/src/atlas/mesh/IsGhostNode.h index 874564709..8e17b929d 100644 --- a/src/atlas/mesh/IsGhostNode.h +++ b/src/atlas/mesh/IsGhostNode.h @@ -22,10 +22,10 @@ namespace mesh { class IsGhostNode { public: IsGhostNode( const mesh::Nodes& nodes ) : - flags_( array::make_view( nodes.field( "flags" ) ) ), + flags_( array::make_view( nodes.flags() ) ), ghost_( array::make_view( nodes.ghost() ) ) {} - bool operator()( size_t idx ) const { return Nodes::Topology::check( flags_( idx ), Nodes::Topology::GHOST ); } + bool operator()( idx_t idx ) const { return Nodes::Topology::check( flags_( idx ), Nodes::Topology::GHOST ); } private: array::ArrayView flags_; diff --git a/src/atlas/mesh/Mesh.cc b/src/atlas/mesh/Mesh.cc index 46b154770..ecac60573 100644 --- a/src/atlas/mesh/Mesh.cc +++ b/src/atlas/mesh/Mesh.cc @@ -14,13 +14,9 @@ namespace atlas { //---------------------------------------------------------------------------------------------------------------------- -Mesh::Mesh() : impl_( new Implementation() ) {} +Mesh::Mesh() : Handle( new Implementation() ) {} -Mesh::Mesh( const Mesh& mesh ) : impl_( mesh.impl_ ) {} - -Mesh::Mesh( const Implementation* impl ) : impl_( const_cast( impl ) ) {} - -Mesh::Mesh( eckit::Stream& stream ) : impl_( new Implementation( stream ) ) {} +Mesh::Mesh( eckit::Stream& stream ) : Handle( new Implementation( stream ) ) {} //---------------------------------------------------------------------------------------------------------------------- diff --git a/src/atlas/mesh/Mesh.h b/src/atlas/mesh/Mesh.h index 20481065d..0f5f2f233 100644 --- a/src/atlas/mesh/Mesh.h +++ b/src/atlas/mesh/Mesh.h @@ -12,9 +12,8 @@ #include -#include "eckit/memory/SharedPtr.h" - #include "atlas/mesh/detail/MeshImpl.h" +#include "atlas/util/ObjectHandle.h" //---------------------------------------------------------------------------------------------------------------------- // Forward declarations @@ -50,9 +49,8 @@ namespace atlas { //---------------------------------------------------------------------------------------------------------------------- -class Mesh { +class Mesh : public util::ObjectHandle { public: - using Implementation = mesh::detail::MeshImpl; using Nodes = mesh::Nodes; using Cells = mesh::Cells; using Edges = mesh::Edges; @@ -61,71 +59,65 @@ class Mesh { using Polygon = mesh::PartitionPolygon; public: + using Handle::Handle; Mesh(); - Mesh( const Mesh& ); - Mesh( const Implementation* ); /// @brief Construct a mesh from a Stream (serialization) explicit Mesh( eckit::Stream& ); /// @brief Serialization to Stream - void encode( eckit::Stream& s ) const { return impl_->encode( s ); } + void encode( eckit::Stream& s ) const { return get()->encode( s ); } - void print( std::ostream& out ) const { impl_->print( out ); } + void print( std::ostream& out ) const { get()->print( out ); } - const util::Metadata& metadata() const { return impl_->metadata(); } - util::Metadata& metadata() { return impl_->metadata(); } + const util::Metadata& metadata() const { return get()->metadata(); } + util::Metadata& metadata() { return get()->metadata(); } - const Nodes& nodes() const { return impl_->nodes(); } - Nodes& nodes() { return impl_->nodes(); } + const Nodes& nodes() const { return get()->nodes(); } + Nodes& nodes() { return get()->nodes(); } - const Cells& cells() const { return impl_->cells(); } + const Cells& cells() const { return get()->cells(); } Cells& cells() { - return impl_->cells(); + return get()->cells(); ; } - const Edges& edges() const { return impl_->edges(); } - Edges& edges() { return impl_->edges(); } + const Edges& edges() const { return get()->edges(); } + Edges& edges() { return get()->edges(); } - const HybridElements& facets() const { return impl_->facets(); } - HybridElements& facets() { return impl_->facets(); } + const HybridElements& facets() const { return get()->facets(); } + HybridElements& facets() { return get()->facets(); } - const HybridElements& ridges() const { return impl_->ridges(); } - HybridElements& ridges() { return impl_->ridges(); } + const HybridElements& ridges() const { return get()->ridges(); } + HybridElements& ridges() { return get()->ridges(); } - const HybridElements& peaks() const { return impl_->peaks(); } - HybridElements& peaks() { return impl_->peaks(); } + const HybridElements& peaks() const { return get()->peaks(); } + HybridElements& peaks() { return get()->peaks(); } - bool generated() const { return impl_->generated(); } + bool generated() const { return get()->generated(); } /// @brief Return the memory footprint of the mesh - size_t footprint() const { return impl_->footprint(); } - - size_t partition() const { return impl_->partition(); } + size_t footprint() const { return get()->footprint(); } - size_t nb_partitions() const { return impl_->nb_partitions(); } + idx_t partition() const { return get()->partition(); } - void cloneToDevice() const { impl_->cloneToDevice(); } + idx_t nb_partitions() const { return get()->nb_partitions(); } - void cloneFromDevice() const { impl_->cloneFromDevice(); } + void cloneToDevice() const { get()->cloneToDevice(); } - void syncHostDevice() const { impl_->syncHostDevice(); } + void cloneFromDevice() const { get()->cloneFromDevice(); } - const Projection& projection() const { return impl_->projection(); } + void syncHostDevice() const { get()->syncHostDevice(); } - const PartitionGraph& partitionGraph() const { return impl_->partitionGraph(); } + const Projection& projection() const { return get()->projection(); } - PartitionGraph::Neighbours nearestNeighbourPartitions() const { return impl_->nearestNeighbourPartitions(); } + const PartitionGraph& partitionGraph() const { return get()->partitionGraph(); } - const Implementation* get() const { return impl_.get(); } - Implementation* get() { return impl_.get(); } + PartitionGraph::Neighbours nearestNeighbourPartitions() const { return get()->nearestNeighbourPartitions(); } - const Polygon& polygon( size_t halo = 0 ) const { return impl_->polygon( halo ); } + const Polygon& polygon( idx_t halo = 0 ) const { return get()->polygon( halo ); } - const Grid& grid() const { return impl_->grid(); } - - operator bool() const { return impl_; } + const Grid& grid() const { return get()->grid(); } private: // methods friend std::ostream& operator<<( std::ostream& s, const Mesh& p ) { @@ -134,11 +126,8 @@ class Mesh { } friend class meshgenerator::MeshGeneratorImpl; - void setProjection( const Projection& p ) { impl_->setProjection( p ); } - void setGrid( const Grid& p ) { impl_->setGrid( p ); } - -private: - eckit::SharedPtr impl_; + void setProjection( const Projection& p ) { get()->setProjection( p ); } + void setGrid( const Grid& p ) { get()->setGrid( p ); } }; //---------------------------------------------------------------------------------------------------------------------- diff --git a/src/atlas/mesh/Nodes.cc b/src/atlas/mesh/Nodes.cc index 2e167868e..76d72f433 100644 --- a/src/atlas/mesh/Nodes.cc +++ b/src/atlas/mesh/Nodes.cc @@ -8,11 +8,14 @@ * nor does it submit to any jurisdiction. */ -#include "atlas/mesh/Nodes.h" -#include "atlas/array/MakeView.h" +#include + +#include "atlas/array.h" #include "atlas/field/Field.h" +#include "atlas/mesh/Connectivity.h" +#include "atlas/mesh/Nodes.h" #include "atlas/parallel/mpi/mpi.h" -#include "atlas/runtime/ErrorHandling.h" +#include "atlas/runtime/Exception.h" #include "atlas/runtime/Log.h" #include "atlas/util/CoordinateEnums.h" @@ -26,28 +29,18 @@ namespace mesh { Nodes::Nodes() : size_( 0 ) { global_index_ = add( Field( "glb_idx", make_datatype(), make_shape( size() ) ) ); - remote_index_ = add( Field( "remote_idx", make_datatype(), make_shape( size() ) ) ); + remote_index_ = add( Field( "remote_idx", make_datatype(), make_shape( size() ) ) ); partition_ = add( Field( "partition", make_datatype(), make_shape( size() ) ) ); xy_ = add( Field( "xy", make_datatype(), make_shape( size(), 2 ) ) ); xy_.set_variables( 2 ); lonlat_ = add( Field( "lonlat", make_datatype(), make_shape( size(), 2 ) ) ); lonlat_.set_variables( 2 ); ghost_ = add( Field( "ghost", make_datatype(), make_shape( size() ) ) ); + flags_ = add( Field( "flags", make_datatype(), make_shape( size() ) ) ); + halo_ = add( Field( "halo", make_datatype(), make_shape( size() ) ) ); edge_connectivity_ = &add( new Connectivity( "edge" ) ); cell_connectivity_ = &add( new Connectivity( "cell" ) ); - - add( Field( "flags", make_datatype(), make_shape( size() ) ) ); - - array::ArrayView glb_idx = array::make_view( global_index() ); - array::ArrayView part = array::make_view( partition() ); - array::ArrayView flags = array::make_view( field( "flags" ) ); - - for ( size_t n = 0; n < size(); ++n ) { - glb_idx( n ) = 1 + n; - part( n ) = mpi::comm().rank(); - flags( n ) = 0; - } } Nodes::Connectivity& Nodes::add( Connectivity* connectivity ) { @@ -56,13 +49,13 @@ Nodes::Connectivity& Nodes::add( Connectivity* connectivity ) { } Field Nodes::add( const Field& field ) { - ASSERT( field ); - ASSERT( !field.name().empty() ); + ATLAS_ASSERT( field ); + ATLAS_ASSERT( !field.name().empty() ); if ( has_field( field.name() ) ) { std::stringstream msg; msg << "Trying to add field '" << field.name() << "' to Nodes, but Nodes already has a field with this name."; - throw eckit::Exception( msg.str(), Here() ); + throw_Exception( msg.str(), Here() ); } fields_[field.name()] = field; return field; @@ -72,7 +65,7 @@ void Nodes::remove_field( const std::string& name ) { if ( !has_field( name ) ) { std::stringstream msg; msg << "Trying to remove field `" << name << "' in Nodes, but no field with this name is present in Nodes."; - throw eckit::Exception( msg.str(), Here() ); + throw_Exception( msg.str(), Here() ); } fields_.erase( name ); } @@ -81,7 +74,7 @@ const Field& Nodes::field( const std::string& name ) const { if ( !has_field( name ) ) { std::stringstream msg; msg << "Trying to access field `" << name << "' in Nodes, but no field with this name is present in Nodes."; - throw eckit::Exception( msg.str(), Here() ); + throw_Exception( msg.str(), Here() ); } return fields_.find( name )->second; } @@ -90,32 +83,35 @@ Field& Nodes::field( const std::string& name ) { return const_cast( static_cast( this )->field( name ) ); } -void Nodes::resize( size_t size ) { - size_t previous_size = size_; - size_ = size; - for ( FieldMap::iterator it = fields_.begin(); it != fields_.end(); ++it ) { - Field& field = it->second; - array::ArrayShape shape = field.shape(); - shape[0] = size_; - field.resize( shape ); - } - - array::ArrayView glb_idx = array::make_view( global_index() ); - array::ArrayView part = array::make_view( partition() ); - array::ArrayView flags = array::make_view( field( "flags" ) ); +void Nodes::resize( idx_t size ) { + if ( size != size_ ) { + idx_t previous_size = size_; + size_ = size; + for ( FieldMap::iterator it = fields_.begin(); it != fields_.end(); ++it ) { + Field& field = it->second; + array::ArrayShape shape = field.shape(); + shape[0] = size_; + field.resize( shape ); + } - const int mpi_rank = mpi::comm().rank(); - for ( size_t n = previous_size; n < size_; ++n ) { - glb_idx( n ) = 1 + n; - part( n ) = mpi_rank; - ; - flags( n ) = 0; + auto glb_idx = array::make_view( global_index() ); + auto part = array::make_view( partition() ); + auto flag = array::make_view( flags() ); + auto _halo = array::make_view( halo() ); + + const int mpi_rank = static_cast( mpi::comm().rank() ); + for ( idx_t n = previous_size; n < size_; ++n ) { + glb_idx( n ) = 1 + n; + part( n ) = mpi_rank; + flag( n ) = 0; + _halo( n ) = std::numeric_limits::max(); + } } } -const Field& Nodes::field( size_t idx ) const { - ASSERT( idx < nb_fields() ); - size_t c( 0 ); +const Field& Nodes::field( idx_t idx ) const { + ATLAS_ASSERT( idx < nb_fields() ); + idx_t c( 0 ); for ( FieldMap::const_iterator it = fields_.begin(); it != fields_.end(); ++it ) { if ( idx == c ) { const Field& field = it->second; @@ -123,11 +119,11 @@ const Field& Nodes::field( size_t idx ) const { } c++; } - eckit::SeriousBug( "Should not be here!", Here() ); + throw_Exception( "Should not be here!", Here() ); static Field f; return f; } -Field& Nodes::field( size_t idx ) { +Field& Nodes::field( idx_t idx ) { return const_cast( static_cast( this )->field( idx ) ); } @@ -135,7 +131,7 @@ void Nodes::print( std::ostream& os ) const { os << "Nodes[\n"; os << "\t size=" << size() << ",\n"; os << "\t fields=\n"; - for ( size_t i = 0; i < nb_fields(); ++i ) { + for ( idx_t i = 0; i < nb_fields(); ++i ) { os << "\t\t" << field( i ); if ( i != nb_fields() - 1 ) os << ","; os << "\n"; @@ -161,7 +157,7 @@ const IrregularConnectivity& Nodes::connectivity( const std::string& name ) cons msg << "Trying to access connectivity `" << name << "' in Nodes, but no connectivity with this name is present in " "Nodes."; - throw eckit::Exception( msg.str(), Here() ); + throw_Exception( msg.str(), Here() ); } return *connectivities_.find( name )->second; } @@ -171,28 +167,22 @@ IrregularConnectivity& Nodes::connectivity( const std::string& name ) { msg << "Trying to access connectivity `" << name << "' in Nodes, but no connectivity with this name is present in " "Nodes."; - throw eckit::Exception( msg.str(), Here() ); + throw_Exception( msg.str(), Here() ); } return *connectivities_.find( name )->second; } void Nodes::cloneToDevice() const { std::for_each( fields_.begin(), fields_.end(), []( const FieldMap::value_type& v ) { v.second.cloneToDevice(); } ); - std::for_each( connectivities_.begin(), connectivities_.end(), - []( const ConnectivityMap::value_type& v ) { v.second->cloneToDevice(); } ); } void Nodes::cloneFromDevice() const { std::for_each( fields_.begin(), fields_.end(), []( const FieldMap::value_type& v ) { v.second.cloneFromDevice(); } ); - std::for_each( connectivities_.begin(), connectivities_.end(), - []( const ConnectivityMap::value_type& v ) { v.second->cloneFromDevice(); } ); } void Nodes::syncHostDevice() const { std::for_each( fields_.begin(), fields_.end(), []( const FieldMap::value_type& v ) { v.second.syncHostDevice(); } ); - std::for_each( connectivities_.begin(), connectivities_.end(), - []( const ConnectivityMap::value_type& v ) { v.second->syncHostDevice(); } ); } //----------------------------------------------------------------------------- @@ -200,115 +190,116 @@ void Nodes::syncHostDevice() const { extern "C" { Nodes* atlas__mesh__Nodes__create() { - Nodes* nodes( 0 ); - ATLAS_ERROR_HANDLING( nodes = new Nodes() ); - return nodes; + return new Nodes(); } void atlas__mesh__Nodes__delete( Nodes* This ) { - ATLAS_ERROR_HANDLING( delete This ); + ATLAS_ASSERT( This != nullptr ); } -size_t atlas__mesh__Nodes__size( Nodes* This ) { - ATLAS_ERROR_HANDLING( ASSERT( This ); return This->size(); ); - return 0; +idx_t atlas__mesh__Nodes__size( Nodes* This ) { + ATLAS_ASSERT( This != nullptr ); + return This->size(); } -void atlas__mesh__Nodes__resize( Nodes* This, size_t size ) { - ATLAS_ERROR_HANDLING( ASSERT( This ); This->resize( size ); ); +void atlas__mesh__Nodes__resize( Nodes* This, idx_t size ) { + ATLAS_ASSERT( This != nullptr ); + This->resize( size ); } -size_t atlas__mesh__Nodes__nb_fields( Nodes* This ) { - ATLAS_ERROR_HANDLING( ASSERT( This ); return This->nb_fields(); ); - return 0; +idx_t atlas__mesh__Nodes__nb_fields( Nodes* This ) { + ATLAS_ASSERT( This != nullptr ); + return This->nb_fields(); } void atlas__mesh__Nodes__add_field( Nodes* This, field::FieldImpl* field ) { - ATLAS_ERROR_HANDLING( ASSERT( This ); ASSERT( field ); This->add( field ); ); + ATLAS_ASSERT( This != nullptr ); + ATLAS_ASSERT( field != nullptr ); + This->add( field ); } void atlas__mesh__Nodes__remove_field( Nodes* This, char* name ) { - ATLAS_ERROR_HANDLING( ASSERT( This ); This->remove_field( std::string( name ) ); ); + ATLAS_ASSERT( This != nullptr ); + This->remove_field( std::string( name ) ); } int atlas__mesh__Nodes__has_field( Nodes* This, char* name ) { - ATLAS_ERROR_HANDLING( ASSERT( This ); return This->has_field( std::string( name ) ); ); - return 0; + ATLAS_ASSERT( This != nullptr ); + return This->has_field( std::string( name ) ); } field::FieldImpl* atlas__mesh__Nodes__field_by_name( Nodes* This, char* name ) { - ATLAS_ERROR_HANDLING( ASSERT( This ); return This->field( std::string( name ) ).get(); ); - return 0; + ATLAS_ASSERT( This != nullptr ); + return This->field( std::string( name ) ).get(); } -field::FieldImpl* atlas__mesh__Nodes__field_by_idx( Nodes* This, size_t idx ) { - ATLAS_ERROR_HANDLING( ASSERT( This ); return This->field( idx ).get(); ); - return 0; +field::FieldImpl* atlas__mesh__Nodes__field_by_idx( Nodes* This, idx_t idx ) { + ATLAS_ASSERT( This != nullptr ); + return This->field( idx ).get(); } util::Metadata* atlas__mesh__Nodes__metadata( Nodes* This ) { - ATLAS_ERROR_HANDLING( ASSERT( This ); return &This->metadata(); ); - return 0; + ATLAS_ASSERT( This != nullptr ); + return &This->metadata(); } void atlas__mesh__Nodes__str( Nodes* This, char*& str, int& size ) { - ATLAS_ERROR_HANDLING( std::stringstream ss; ss << *This; std::string s = ss.str(); size = s.size(); - str = new char[size + 1]; strcpy( str, s.c_str() ); ); + ATLAS_ASSERT( This != nullptr ); + std::stringstream ss; + ss << *This; + std::string s = ss.str(); + size = static_cast( s.size() ); + str = new char[size + 1]; + strcpy( str, s.c_str() ); } IrregularConnectivity* atlas__mesh__Nodes__edge_connectivity( Nodes* This ) { - IrregularConnectivity* connectivity( 0 ); - ATLAS_ERROR_HANDLING( connectivity = &This->edge_connectivity() ); - return connectivity; + ATLAS_ASSERT( This != nullptr ); + return &This->edge_connectivity(); } IrregularConnectivity* atlas__mesh__Nodes__cell_connectivity( Nodes* This ) { - IrregularConnectivity* connectivity( 0 ); - ATLAS_ERROR_HANDLING( connectivity = &This->cell_connectivity() ); - return connectivity; + ATLAS_ASSERT( This != nullptr ); + return &This->cell_connectivity(); } IrregularConnectivity* atlas__mesh__Nodes__connectivity( Nodes* This, char* name ) { - ATLAS_ERROR_HANDLING( ASSERT( This ); return &This->connectivity( std::string( name ) ); ); - return 0; + ATLAS_ASSERT( This != nullptr ); + return &This->connectivity( std::string( name ) ); } void atlas__mesh__Nodes__add_connectivity( Nodes* This, IrregularConnectivity* connectivity ) { - ATLAS_ERROR_HANDLING( ASSERT( This ); ASSERT( connectivity ); This->add( connectivity ); ); + ATLAS_ASSERT( This != nullptr ); + ATLAS_ASSERT( connectivity != nullptr ); + This->add( connectivity ); } field::FieldImpl* atlas__mesh__Nodes__xy( Nodes* This ) { - field::FieldImpl* field( 0 ); - ATLAS_ERROR_HANDLING( ASSERT( This != 0 ); field = This->xy().get(); ); - return field; + ATLAS_ASSERT( This != nullptr ); + return This->xy().get(); } field::FieldImpl* atlas__mesh__Nodes__lonlat( Nodes* This ) { - field::FieldImpl* field( 0 ); - ATLAS_ERROR_HANDLING( ASSERT( This != 0 ); field = This->lonlat().get(); ); - return field; + ATLAS_ASSERT( This != nullptr ); + return This->lonlat().get(); } field::FieldImpl* atlas__mesh__Nodes__global_index( Nodes* This ) { - field::FieldImpl* field( 0 ); - ATLAS_ERROR_HANDLING( ASSERT( This != 0 ); field = This->global_index().get(); ); - return field; + ATLAS_ASSERT( This != nullptr ); + return This->global_index().get(); } field::FieldImpl* atlas__mesh__Nodes__remote_index( Nodes* This ) { - field::FieldImpl* field( 0 ); - ATLAS_ERROR_HANDLING( ASSERT( This != 0 ); field = This->remote_index().get(); ); - return field; + ATLAS_ASSERT( This != nullptr ); + return This->remote_index().get(); } field::FieldImpl* atlas__mesh__Nodes__partition( Nodes* This ) { - field::FieldImpl* field( 0 ); - ATLAS_ERROR_HANDLING( ASSERT( This != 0 ); field = This->partition().get(); ); - return field; + ATLAS_ASSERT( This != nullptr ); + return This->partition().get(); } field::FieldImpl* atlas__mesh__Nodes__ghost( Nodes* This ) { - field::FieldImpl* field( 0 ); - ATLAS_ERROR_HANDLING( ASSERT( This != 0 ); field = This->ghost().get(); ); - return field; + ATLAS_ASSERT( This != nullptr ); + return This->ghost().get(); } } diff --git a/src/atlas/mesh/Nodes.h b/src/atlas/mesh/Nodes.h index 46e0d4abb..8410551db 100644 --- a/src/atlas/mesh/Nodes.h +++ b/src/atlas/mesh/Nodes.h @@ -16,15 +16,22 @@ #include #include -#include "eckit/exception/Exceptions.h" -#include "eckit/memory/Owned.h" -#include "eckit/memory/SharedPtr.h" +#include "atlas/util/Object.h" +#include "atlas/util/ObjectHandle.h" #include "atlas/field/Field.h" -#include "atlas/mesh/Connectivity.h" #include "atlas/util/Bitflags.h" #include "atlas/util/Metadata.h" +namespace atlas { +namespace mesh { +template +class ConnectivityInterface; +class IrregularConnectivityImpl; +using IrregularConnectivity = ConnectivityInterface; +} // namespace mesh +} // namespace atlas + namespace atlas { namespace mesh { @@ -32,9 +39,9 @@ namespace mesh { * \brief Nodes class that owns a collection of fields defined in nodes of the * mesh */ -class Nodes : public eckit::Owned { +class Nodes : public util::Object { public: - typedef IrregularConnectivity Connectivity; + using Connectivity = IrregularConnectivity; class Topology : public util::Bitflags { public: @@ -48,7 +55,8 @@ class Nodes : public eckit::Owned { EAST = ( 1 << 5 ), NORTH = ( 1 << 6 ), SOUTH = ( 1 << 7 ), - PATCH = ( 1 << 8 ) + PATCH = ( 1 << 8 ), + POLE = ( 1 << 9 ) }; }; @@ -56,7 +64,7 @@ class Nodes : public eckit::Owned { //-- Constructors /// @brief Construct "size" nodes Nodes(); - // Nodes(size_t size); + // Nodes(idx_t size); //-- Accessors @@ -64,9 +72,9 @@ class Nodes : public eckit::Owned { Field& field( const std::string& name ); bool has_field( const std::string& name ) const { return ( fields_.find( name ) != fields_.end() ); } - const Field& field( size_t ) const; - Field& field( size_t ); - size_t nb_fields() const { return fields_.size(); } + const Field& field( idx_t ) const; + Field& field( idx_t ); + idx_t nb_fields() const { return static_cast( fields_.size() ); } const util::Metadata& metadata() const { return metadata_; } util::Metadata& metadata() { return metadata_; } @@ -89,6 +97,12 @@ class Nodes : public eckit::Owned { const Field& ghost() const { return ghost_; } Field& ghost() { return ghost_; } + const Field& flags() const { return flags_; } + Field& flags() { return flags_; } + + const Field& halo() const { return halo_; } + Field& halo() { return halo_; } + /// @brief Node to Edge connectivity table const Connectivity& edge_connectivity() const; Connectivity& edge_connectivity(); @@ -102,17 +116,17 @@ class Nodes : public eckit::Owned { bool has_connectivity( std::string name ) const { return connectivities_.count( name ); } - size_t size() const { return size_; } + idx_t size() const { return size_; } // -- Modifiers Field add( const Field& ); - void resize( size_t ); + void resize( idx_t ); void remove_field( const std::string& name ); - Connectivity& add( mesh::Connectivity* ); + Connectivity& add( Connectivity* ); /// @brief Return the memory footprint of the Nodes size_t footprint() const; @@ -133,10 +147,10 @@ class Nodes : public eckit::Owned { private: typedef std::map FieldMap; - typedef std::map> ConnectivityMap; + typedef std::map> ConnectivityMap; private: - size_t size_; + idx_t size_; FieldMap fields_; ConnectivityMap connectivities_; @@ -149,6 +163,8 @@ class Nodes : public eckit::Owned { Field xy_; Field lonlat_; Field ghost_; + Field flags_; + Field halo_; // Cached shortcuts to specific connectivities in connectivities_ Connectivity* edge_connectivity_; @@ -174,14 +190,14 @@ inline Nodes::Connectivity& Nodes::cell_connectivity() { extern "C" { Nodes* atlas__mesh__Nodes__create(); void atlas__mesh__Nodes__delete( Nodes* This ); -size_t atlas__mesh__Nodes__size( Nodes* This ); -void atlas__mesh__Nodes__resize( Nodes* This, size_t size ); -size_t atlas__mesh__Nodes__nb_fields( Nodes* This ); +idx_t atlas__mesh__Nodes__size( Nodes* This ); +void atlas__mesh__Nodes__resize( Nodes* This, idx_t size ); +idx_t atlas__mesh__Nodes__nb_fields( Nodes* This ); void atlas__mesh__Nodes__add_field( Nodes* This, field::FieldImpl* field ); void atlas__mesh__Nodes__remove_field( Nodes* This, char* name ); int atlas__mesh__Nodes__has_field( Nodes* This, char* name ); field::FieldImpl* atlas__mesh__Nodes__field_by_name( Nodes* This, char* name ); -field::FieldImpl* atlas__mesh__Nodes__field_by_idx( Nodes* This, size_t idx ); +field::FieldImpl* atlas__mesh__Nodes__field_by_idx( Nodes* This, idx_t idx ); util::Metadata* atlas__mesh__Nodes__metadata( Nodes* This ); void atlas__mesh__Nodes__str( Nodes* This, char*& str, int& size ); IrregularConnectivity* atlas__mesh__Nodes__edge_connectivity( Nodes* This ); diff --git a/src/atlas/mesh/PartitionPolygon.cc b/src/atlas/mesh/PartitionPolygon.cc index c18c3ebe7..b42b5447b 100644 --- a/src/atlas/mesh/PartitionPolygon.cc +++ b/src/atlas/mesh/PartitionPolygon.cc @@ -8,38 +8,42 @@ * nor does it submit to any jurisdiction. */ -#include "atlas/mesh/PartitionPolygon.h" +#include + #include "atlas/array/MakeView.h" #include "atlas/field/Field.h" #include "atlas/mesh.h" +#include "atlas/mesh/PartitionPolygon.h" #include "atlas/parallel/mpi/mpi.h" +#include "atlas/runtime/Trace.h" #include "atlas/util/CoordinateEnums.h" namespace atlas { namespace mesh { namespace { -util::Polygon::edge_set_t compute_edges( const detail::MeshImpl& mesh, size_t halo ) { +util::Polygon::edge_set_t compute_edges( const detail::MeshImpl& mesh, idx_t halo ) { + ATLAS_TRACE( "PartitionPolygon" ); // extract partition boundary edges by always attempting first to` // remove a reversed edge from a neighbouring element, if any util::Polygon::edge_set_t edges; - for ( size_t t = 0; t < mesh.cells().nb_types(); ++t ) { + for ( idx_t t = 0; t < mesh.cells().nb_types(); ++t ) { const Elements& elements = mesh.cells().elements( t ); const BlockConnectivity& conn = elements.node_connectivity(); auto field_flags = elements.view( elements.flags() ); auto field_halo = elements.view( elements.halo() ); - auto patch = [&field_flags]( size_t e ) { + auto patch = [&field_flags]( idx_t e ) { using Topology = atlas::mesh::Nodes::Topology; return Topology::check( field_flags( e ), Topology::PATCH ); }; - const size_t nb_nodes = elements.nb_nodes(); + const idx_t nb_nodes = elements.nb_nodes(); - for ( size_t j = 0; j < elements.size(); ++j ) { + for ( idx_t j = 0; j < elements.size(); ++j ) { if ( patch( j ) == 0 && field_halo( j ) <= halo ) { - for ( size_t k = 0; k < nb_nodes; ++k ) { + for ( idx_t k = 0; k < nb_nodes; ++k ) { util::Polygon::edge_t edge( conn( j, k ), conn( j, ( k + 1 ) % nb_nodes ) ); if ( !edges.erase( edge.reverse() ) ) { edges.insert( edge ); } } @@ -50,7 +54,7 @@ util::Polygon::edge_set_t compute_edges( const detail::MeshImpl& mesh, size_t ha } } // namespace -PartitionPolygon::PartitionPolygon( const detail::MeshImpl& mesh, size_t halo ) : +PartitionPolygon::PartitionPolygon( const detail::MeshImpl& mesh, idx_t halo ) : util::Polygon( compute_edges( mesh, halo ) ), mesh_( mesh ), halo_( halo ) {} @@ -77,8 +81,8 @@ void PartitionPolygon::outputPythonScript( const eckit::PathName& filepath, cons comm.allReduceInPlace( xmin, eckit::mpi::min() ); comm.allReduceInPlace( xmax, eckit::mpi::max() ); - size_t count = mesh_.nodes().size(); - size_t count_all = count; + idx_t count = mesh_.nodes().size(); + idx_t count_all = count; comm.allReduceInPlace( count_all, eckit::mpi::sum() ); for ( int r = 0; r < mpi_size; ++r ) { @@ -149,9 +153,9 @@ void PartitionPolygon::outputPythonScript( const eckit::PathName& filepath, cons << r << " = " << count_all << "\n" "" - //"\n" "x_" << r << " = ["; for (size_t i=0; i -#include "eckit/memory/Owned.h" +#include "atlas/util/Object.h" #include "atlas/library/config.h" #include "atlas/util/Config.h" @@ -36,16 +36,16 @@ namespace mesh { /** * @brief Polygon class that holds the boundary of a mesh partition */ -class PartitionPolygon : public util::Polygon, public eckit::Owned { +class PartitionPolygon : public util::Polygon, public util::Object { public: // methods //-- Constructors /// @brief Construct "size" polygon - PartitionPolygon( const detail::MeshImpl& mesh, size_t halo ); + PartitionPolygon( const detail::MeshImpl& mesh, idx_t halo ); //-- Accessors - size_t halo() const { return halo_; } + idx_t halo() const { return halo_; } /// @brief Return the memory footprint of the Polygon size_t footprint() const; @@ -62,7 +62,7 @@ class PartitionPolygon : public util::Polygon, public eckit::Owned { private: const detail::MeshImpl& mesh_; - size_t halo_; + idx_t halo_; }; //------------------------------------------------------------------------------------------------------ diff --git a/src/atlas/mesh/actions/BuildCellCentres.cc b/src/atlas/mesh/actions/BuildCellCentres.cc index 2d23c36e9..59bdd99f2 100644 --- a/src/atlas/mesh/actions/BuildCellCentres.cc +++ b/src/atlas/mesh/actions/BuildCellCentres.cc @@ -18,6 +18,7 @@ #include "atlas/mesh/Mesh.h" #include "atlas/mesh/Nodes.h" #include "atlas/mesh/actions/BuildCellCentres.h" +#include "atlas/runtime/Trace.h" #include "atlas/util/CoordinateEnums.h" namespace atlas { @@ -44,32 +45,33 @@ Field& BuildCellCentres::operator()( Mesh& mesh ) const { recompute = true; } if ( recompute ) { + ATLAS_TRACE( "BuildCellCentres" ); mesh::Nodes& nodes = mesh.nodes(); array::ArrayView coords = array::make_view( nodes.field( "xyz" ) ); - size_t firstVirtualPoint = std::numeric_limits::max(); - if ( nodes.metadata().has( "NbRealPts" ) ) { firstVirtualPoint = nodes.metadata().get( "NbRealPts" ); } + idx_t firstVirtualPoint = std::numeric_limits::max(); + if ( nodes.metadata().has( "NbRealPts" ) ) { firstVirtualPoint = nodes.metadata().get( "NbRealPts" ); } - size_t nb_cells = mesh.cells().size(); - auto centroids = array::make_view( mesh.cells().field( field_name_ ) ); + idx_t nb_cells = mesh.cells().size(); + auto centroids = array::make_view( mesh.cells().field( field_name_ ) ); const mesh::HybridElements::Connectivity& cell_node_connectivity = mesh.cells().node_connectivity(); - for ( size_t e = 0; e < nb_cells; ++e ) { + for ( idx_t e = 0; e < nb_cells; ++e ) { centroids( e, XX ) = 0.; centroids( e, YY ) = 0.; centroids( e, ZZ ) = 0.; - const size_t nb_cell_nodes = cell_node_connectivity.cols( e ); + const idx_t nb_cell_nodes = cell_node_connectivity.cols( e ); // check for degenerate elements (less than three unique nodes) // NOTE: this is not a proper check but it is very robust eckit::types::CompareApproximatelyEqual approx( 1.e-9 ); - int nb_equal_nodes = 0; - for ( size_t ni = 0; ni < nb_cell_nodes - 1; ++ni ) { + idx_t nb_equal_nodes = 0; + for ( idx_t ni = 0; ni < nb_cell_nodes - 1; ++ni ) { idx_t i = cell_node_connectivity( e, ni ); Point3 Pi( coords( i, XX ), coords( i, YY ), coords( i, ZZ ) ); - for ( size_t nj = ni + 1; nj < nb_cell_nodes; ++nj ) { + for ( idx_t nj = ni + 1; nj < nb_cell_nodes; ++nj ) { idx_t j = cell_node_connectivity( e, nj ); Point3 Pj( coords( j, XX ), coords( j, YY ), coords( j, ZZ ) ); if ( approx( Pi[XX], Pj[XX] ) && approx( Pi[YY], Pj[YY] ) && approx( Pi[ZZ], Pj[ZZ] ) ) { @@ -78,14 +80,14 @@ Field& BuildCellCentres::operator()( Mesh& mesh ) const { } } - int nb_unique_nodes = int( nb_cell_nodes ) - nb_equal_nodes; + idx_t nb_unique_nodes = idx_t( nb_cell_nodes ) - nb_equal_nodes; if ( nb_unique_nodes < 3 ) { continue; } if ( flatten_virtual_elements_ ) { // calculate centroid by averaging coordinates (uses only "real" nodes) - size_t nb_real_nodes = 0; - for ( size_t n = 0; n < nb_cell_nodes; ++n ) { - const size_t i = size_t( cell_node_connectivity( e, n ) ); + idx_t nb_real_nodes = 0; + for ( idx_t n = 0; n < nb_cell_nodes; ++n ) { + const idx_t i = cell_node_connectivity( e, n ); if ( i < firstVirtualPoint ) { ++nb_real_nodes; centroids( e, XX ) += coords( i, XX ); @@ -103,9 +105,9 @@ Field& BuildCellCentres::operator()( Mesh& mesh ) const { } else { const double average_coefficient = 1. / static_cast( nb_cell_nodes ); - for ( size_t n = 0; n < nb_cell_nodes; ++n ) { - const size_t i = size_t( cell_node_connectivity( e, n ) ); - for ( size_t d = 0; d < 3; ++d ) { + for ( idx_t n = 0; n < nb_cell_nodes; ++n ) { + const idx_t i = cell_node_connectivity( e, n ); + for ( idx_t d = 0; d < 3; ++d ) { centroids( e, d ) += coords( i, d ) * average_coefficient; } } diff --git a/src/atlas/mesh/actions/BuildConvexHull3D.cc b/src/atlas/mesh/actions/BuildConvexHull3D.cc index c90745504..ee4cbee3c 100644 --- a/src/atlas/mesh/actions/BuildConvexHull3D.cc +++ b/src/atlas/mesh/actions/BuildConvexHull3D.cc @@ -13,7 +13,6 @@ #include #include #include "eckit/log/BigNum.h" -#include "eckit/memory/ScopedPtr.h" #include "atlas/library/config.h" @@ -50,10 +49,10 @@ const Point_3 origin = Point_3( CGAL::ORIGIN ); #include "atlas/mesh/Mesh.h" #include "atlas/mesh/Nodes.h" #include "atlas/mesh/actions/BuildConvexHull3D.h" +#include "atlas/runtime/Log.h" #include "atlas/runtime/Trace.h" #include "atlas/util/CoordinateEnums.h" -using namespace eckit; using namespace eckit::geometry; using atlas::interpolation::method::PointIndex3; @@ -75,7 +74,7 @@ static Polyhedron_3* create_convex_hull_from_points( const std::vector& // insertion from a vector : std::vector vertices( pts.size() ); - for ( size_t i = 0; i < vertices.size(); ++i ) + for ( idx_t i = 0, size = vertices.size(); i < size; ++i ) vertices[i] = Point_3( pts[i]( XX ), pts[i]( YY ), pts[i]( ZZ ) ); // compute convex hull of non-collinear points @@ -92,15 +91,15 @@ static void cgal_polyhedron_to_atlas_mesh( Mesh& mesh, Polyhedron_3& poly, Point mesh::Nodes& nodes = mesh.nodes(); - ASSERT( points.size() == nodes.size() ); + ATLAS_ASSERT( points.size() == size_t( nodes.size() ) ); const idx_t nb_nodes = idx_t( points.size() ); - ASSERT( mesh.cells().size() == 0 ); + ATLAS_ASSERT( mesh.cells().size() == 0 ); /* triangles */ - const size_t nb_triags = poly.size_of_facets(); + const idx_t nb_triags = poly.size_of_facets(); mesh.cells().add( new mesh::temporary::Triangle(), nb_triags ); mesh::HybridElements::Connectivity& triag_nodes = mesh.cells().node_connectivity(); array::ArrayView triag_gidx = array::make_view( mesh.cells().global_index() ); @@ -112,11 +111,11 @@ static void cgal_polyhedron_to_atlas_mesh( Mesh& mesh, Polyhedron_3& poly, Point Log::debug() << "Inserting triags (" << eckit::BigNum( nb_triags ) << ")" << std::endl; - size_t tidx = 0; + idx_t tidx = 0; for ( Polyhedron_3::Facet_const_iterator f = poly.facets_begin(); f != poly.facets_end(); ++f ) { // loop over half-edges and take each vertex() - size_t iedge = 0; + idx_t iedge = 0; Polyhedron_3::Halfedge_around_facet_const_circulator edge = f->facet_begin(); do { Polyhedron_3::Vertex_const_handle vh = edge->vertex(); @@ -126,7 +125,7 @@ static void cgal_polyhedron_to_atlas_mesh( Mesh& mesh, Polyhedron_3& poly, Point idx[iedge] = points.unique( pt ); - ASSERT( idx[iedge] < nb_nodes ); + ATLAS_ASSERT( idx[iedge] < nb_nodes ); vts[iedge] = vh; @@ -134,7 +133,7 @@ static void cgal_polyhedron_to_atlas_mesh( Mesh& mesh, Polyhedron_3& poly, Point ++edge; } while ( edge != f->facet_begin() && iedge < 3 ); - ASSERT( iedge == 3 ); + ATLAS_ASSERT( iedge == 3 ); if ( ensure_outward_normals ) /* ensure outward pointing normal */ { @@ -158,21 +157,21 @@ static void cgal_polyhedron_to_atlas_mesh( Mesh& mesh, Polyhedron_3& poly, Point ++tidx; } - ASSERT( tidx == nb_triags ); + ATLAS_ASSERT( tidx == nb_triags ); } #else struct Polyhedron_3 { - size_t size_of_vertices() const { return 0; } + idx_t size_of_vertices() const { return 0; } }; static Polyhedron_3* create_convex_hull_from_points( const std::vector& pts ) { - throw NotImplemented( "CGAL package not found -- Delaunay triangulation is disabled", Here() ); + throw_NotImplemented( "CGAL package not found -- Delaunay triangulation is disabled", Here() ); } static void cgal_polyhedron_to_atlas_mesh( Mesh& mesh, Polyhedron_3& poly, PointSet& points ) { - throw NotImplemented( "CGAL package not found -- Delaunay triangulation is disabled", Here() ); + throw_NotImplemented( "CGAL package not found -- Delaunay triangulation is disabled", Here() ); } #endif @@ -198,12 +197,12 @@ void BuildConvexHull3D::operator()( Mesh& mesh ) const { // define polyhedron to hold convex hull - eckit::ScopedPtr poly( create_convex_hull_from_points( ipts ) ); + std::unique_ptr poly( create_convex_hull_from_points( ipts ) ); // std::cout << "convex hull " << poly->size_of_vertices() << " vertices" // << std::endl; - ASSERT( poly->size_of_vertices() == ipts.size() ); + ATLAS_ASSERT( poly->size_of_vertices() == ipts.size() ); cgal_polyhedron_to_atlas_mesh( mesh, *poly, points ); } diff --git a/src/atlas/mesh/actions/BuildDualMesh.cc b/src/atlas/mesh/actions/BuildDualMesh.cc index af13bb413..b13f88adb 100644 --- a/src/atlas/mesh/actions/BuildDualMesh.cc +++ b/src/atlas/mesh/actions/BuildDualMesh.cc @@ -20,14 +20,14 @@ #include "atlas/field/Field.h" #include "atlas/functionspace/EdgeColumns.h" #include "atlas/functionspace/NodeColumns.h" -#include "atlas/grid/Grid.h" +#include "atlas/grid/StructuredGrid.h" #include "atlas/library/config.h" #include "atlas/mesh/HybridElements.h" #include "atlas/mesh/Mesh.h" #include "atlas/mesh/Nodes.h" #include "atlas/mesh/actions/BuildDualMesh.h" #include "atlas/parallel/Checksum.h" -#include "atlas/runtime/ErrorHandling.h" +#include "atlas/runtime/Exception.h" #include "atlas/runtime/Trace.h" #include "atlas/util/CoordinateEnums.h" #include "atlas/util/Unique.h" @@ -123,7 +123,7 @@ void build_median_dual_mesh( Mesh& mesh ) { nodes_fs.haloExchange( nodes.field( "dual_volumes" ) ); } - functionspace::EdgeColumns edges_fs( mesh, Halo( mesh ) ); + functionspace::EdgeColumns edges_fs( mesh ); { ATLAS_TRACE( "halo-exchange dual_normals" ); edges_fs.haloExchange( edges.field( "dual_normals" ) ); @@ -135,14 +135,14 @@ array::Array* build_centroids_xy( const mesh::HybridElements& elements, const Fi const array::ArrayView xy = array::make_view( field_xy ); array::Array* array_centroids = array::Array::create( array::make_shape( elements.size(), 2 ) ); array::ArrayView centroids = array::make_view( *array_centroids ); - size_t nb_elems = elements.size(); + idx_t nb_elems = elements.size(); const mesh::HybridElements::Connectivity& elem_nodes = elements.node_connectivity(); - for ( size_t e = 0; e < nb_elems; ++e ) { + for ( idx_t e = 0; e < nb_elems; ++e ) { centroids( e, XX ) = 0.; centroids( e, YY ) = 0.; - const size_t nb_nodes_per_elem = elem_nodes.cols( e ); + const idx_t nb_nodes_per_elem = elem_nodes.cols( e ); const double average_coefficient = 1. / static_cast( nb_nodes_per_elem ); - for ( size_t n = 0; n < nb_nodes_per_elem; ++n ) { + for ( idx_t n = 0; n < nb_nodes_per_elem; ++n ) { centroids( e, XX ) += xy( elem_nodes( e, n ), XX ); centroids( e, YY ) += xy( elem_nodes( e, n ), YY ); } @@ -165,30 +165,30 @@ void add_median_dual_volume_contribution_cells( const mesh::HybridElements& cell const mesh::HybridElements::Connectivity& edge_node_connectivity = edges.node_connectivity(); auto field_flags = array::make_view( cells.flags() ); - auto patch = [&field_flags]( size_t e ) { + auto patch = [&field_flags]( idx_t e ) { using Topology = atlas::mesh::Nodes::Topology; return Topology::check( field_flags( e ), Topology::PATCH ); }; // special ordering for bit-identical results - size_t nb_cells = cells.size(); + idx_t nb_cells = cells.size(); std::vector ordering( nb_cells ); - for ( size_t jcell = 0; jcell < nb_cells; ++jcell ) + for ( idx_t jcell = 0; jcell < nb_cells; ++jcell ) ordering[jcell] = Node( util::unique_lonlat( cell_centroids( jcell, XX ), cell_centroids( jcell, YY ) ), jcell ); std::sort( ordering.data(), ordering.data() + nb_cells ); - for ( size_t jcell = 0; jcell < nb_cells; ++jcell ) { + for ( idx_t jcell = 0; jcell < nb_cells; ++jcell ) { idx_t icell = ordering[jcell].i; if ( patch( icell ) ) continue; double x0 = cell_centroids( icell, XX ); double y0 = cell_centroids( icell, YY ); - for ( size_t jedge = 0; jedge < cell_edge_connectivity.cols( icell ); ++jedge ) { + for ( idx_t jedge = 0; jedge < cell_edge_connectivity.cols( icell ); ++jedge ) { idx_t iedge = cell_edge_connectivity( icell, jedge ); double x1 = edge_centroids( iedge, XX ); double y1 = edge_centroids( iedge, YY ); - for ( size_t jnode = 0; jnode < 2; ++jnode ) { + for ( idx_t jnode = 0; jnode < 2; ++jnode ) { idx_t inode = edge_node_connectivity( iedge, jnode ); double x2 = xy( inode, XX ); double y2 = xy( inode, YY ); @@ -209,9 +209,9 @@ void add_median_dual_volume_contribution_poles( const mesh::HybridElements& edge const mesh::HybridElements::Connectivity& edge_node_connectivity = edges.node_connectivity(); const mesh::HybridElements::Connectivity& edge_cell_connectivity = edges.cell_connectivity(); - const size_t nb_edges = edges.size(); + const idx_t nb_edges = edges.size(); std::map> node_to_bdry_edge; - for ( size_t jedge = 0; jedge < nb_edges; ++jedge ) { + for ( idx_t jedge = 0; jedge < nb_edges; ++jedge ) { if ( edge_cell_connectivity( jedge, 0 ) != edge_cell_connectivity.missing_value() && edge_cell_connectivity( jedge, 1 ) == edge_cell_connectivity.missing_value() ) { node_to_bdry_edge[edge_node_connectivity( jedge, 0 )].push_back( jedge ); @@ -225,15 +225,15 @@ void add_median_dual_volume_contribution_poles( const mesh::HybridElements& edge std::map>::iterator it; for ( it = node_to_bdry_edge.begin(); it != node_to_bdry_edge.end(); ++it ) { - const size_t jnode = ( *it ).first; + const idx_t jnode = ( *it ).first; std::vector& bdry_edges = ( *it ).second; const double x0 = xy( jnode, XX ); const double y0 = xy( jnode, YY ); double x1, y1, y2; - for ( size_t jedge = 0; jedge < bdry_edges.size(); ++jedge ) { - const size_t iedge = bdry_edges[jedge]; - x1 = edge_centroids( iedge, XX ); - y1 = edge_centroids( iedge, YY ); + for ( idx_t jedge = 0; jedge < static_cast( bdry_edges.size() ); ++jedge ) { + const idx_t iedge = bdry_edges[jedge]; + x1 = edge_centroids( iedge, XX ); + y1 = edge_centroids( iedge, YY ); y2 = 0.; if ( std::abs( y1 - max[YY] ) < tol ) @@ -256,7 +256,7 @@ void build_dual_normals( Mesh& mesh ) { mesh::Nodes& nodes = mesh.nodes(); mesh::HybridElements& edges = mesh.edges(); - const size_t nb_edges = edges.size(); + const idx_t nb_edges = edges.size(); array::ArrayView node_xy = array::make_view( nodes.xy() ); double min[2], max[2]; @@ -272,7 +272,7 @@ void build_dual_normals( Mesh& mesh ) { const mesh::HybridElements::Connectivity& edge_cell_connectivity = edges.cell_connectivity(); std::map> node_to_bdry_edge; - for ( size_t jedge = 0; jedge < nb_edges; ++jedge ) { + for ( idx_t jedge = 0; jedge < nb_edges; ++jedge ) { if ( edge_cell_connectivity( jedge, 0 ) != edge_cell_connectivity.missing_value() && edge_cell_connectivity( jedge, 1 ) == edge_cell_connectivity.missing_value() ) { node_to_bdry_edge[edge_node_connectivity( jedge, 0 )].push_back( jedge ); @@ -280,16 +280,17 @@ void build_dual_normals( Mesh& mesh ) { } } - for ( size_t edge = 0; edge < nb_edges; ++edge ) { + for ( idx_t edge = 0; edge < nb_edges; ++edge ) { if ( edge_cell_connectivity( edge, 0 ) == edge_cell_connectivity.missing_value() ) { // this is a pole edge // only compute for one node - for ( size_t n = 0; n < 2; ++n ) { + for ( idx_t n = 0; n < 2; ++n ) { idx_t node = edge_node_connectivity( edge, n ); std::vector& bdry_edges = node_to_bdry_edge[node]; double x[2]; - size_t cnt = 0; - for ( size_t jedge = 0; jedge < bdry_edges.size(); ++jedge ) { + idx_t cnt = 0; + const idx_t nb_bdry_edges = static_cast( bdry_edges.size() ); + for ( idx_t jedge = 0; jedge < nb_bdry_edges; ++jedge ) { idx_t bdry_edge = bdry_edges[jedge]; if ( std::abs( edge_centroids( bdry_edge, YY ) - max[YY] ) < tol ) { edge_centroids( edge, YY ) = 90.; @@ -349,15 +350,15 @@ void make_dual_normals_outward( Mesh& mesh ) { const mesh::HybridElements::Connectivity& edge_cell_connectivity = edges.cell_connectivity(); const mesh::HybridElements::Connectivity& edge_node_connectivity = edges.node_connectivity(); array::ArrayView dual_normals = array::make_view( edges.field( "dual_normals" ) ); - const size_t nb_edges = edges.size(); + const idx_t nb_edges = edges.size(); - for ( size_t edge = 0; edge < nb_edges; ++edge ) { + for ( idx_t edge = 0; edge < nb_edges; ++edge ) { if ( edge_cell_connectivity( edge, 0 ) != edge_cell_connectivity.missing_value() ) { // Make normal point from node 1 to node 2 - const size_t ip1 = edge_node_connectivity( edge, 0 ); - const size_t ip2 = edge_node_connectivity( edge, 1 ); - double dx = node_xy( ip2, XX ) - node_xy( ip1, XX ); - double dy = node_xy( ip2, YY ) - node_xy( ip1, YY ); + const idx_t ip1 = edge_node_connectivity( edge, 0 ); + const idx_t ip2 = edge_node_connectivity( edge, 1 ); + double dx = node_xy( ip2, XX ) - node_xy( ip1, XX ); + double dy = node_xy( ip2, YY ) - node_xy( ip1, YY ); if ( dx * dual_normals( edge, XX ) + dy * dual_normals( edge, YY ) < 0 ) { dual_normals( edge, XX ) = -dual_normals( edge, XX ); dual_normals( edge, YY ) = -dual_normals( edge, YY ); @@ -367,10 +368,9 @@ void make_dual_normals_outward( Mesh& mesh ) { } void build_brick_dual_mesh( const Grid& grid, Mesh& mesh ) { - auto g = grid::StructuredGrid( grid ); + auto g = StructuredGrid( grid ); if ( g ) { - if ( mpi::comm().size() != 1 ) - throw eckit::UserError( "Cannot build_brick_dual_mesh with more than 1 task", Here() ); + if ( mpi::comm().size() != 1 ) throw_Exception( "Cannot build_brick_dual_mesh with more than 1 task", Here() ); mesh::Nodes& nodes = mesh.nodes(); array::ArrayView xy = array::make_view( nodes.xy() ); @@ -380,18 +380,18 @@ void build_brick_dual_mesh( const Grid& grid, Mesh& mesh ) { int c = 0; int n = 0; - for ( size_t jlat = 0; jlat < g.ny(); ++jlat ) { + for ( idx_t jlat = 0; jlat < g.ny(); ++jlat ) { double lat = g.y( jlat ); double latN = ( jlat == 0 ) ? 90. : 0.5 * ( lat + g.y( jlat - 1 ) ); double latS = ( jlat == g.ny() - 1 ) ? -90. : 0.5 * ( lat + g.y( jlat + 1 ) ); double dlat = ( latN - latS ); double dlon = 360. / static_cast( g.nx( jlat ) ); - for ( size_t jlon = 0; jlon < g.nx( jlat ); ++jlon ) { + for ( idx_t jlon = 0; jlon < g.nx( jlat ); ++jlon ) { while ( gidx( c ) != n + 1 ) c++; - ASSERT( xy( c, XX ) == g.x( jlon, jlat ) ); - ASSERT( xy( c, YY ) == lat ); + ATLAS_ASSERT( xy( c, XX ) == g.x( jlon, jlat ) ); + ATLAS_ASSERT( xy( c, YY ) == lat ); dual_volumes( c ) = dlon * dlat; ++n; } @@ -401,12 +401,12 @@ void build_brick_dual_mesh( const Grid& grid, Mesh& mesh ) { nodes_fs.haloExchange( nodes.field( "dual_volumes" ) ); } else { - throw eckit::BadCast( "Cannot build_brick_dual_mesh with mesh provided grid type", Here() ); + throw_Exception( "Cannot build_brick_dual_mesh with mesh provided grid type", Here() ); } } -void build_centroid_dual_mesh( Mesh& mesh ) { - NOTIMP; +void build_centroid_dual_mesh( Mesh& ) { + ATLAS_NOTIMPLEMENTED; // This requires code below which has not been ported yet } @@ -414,11 +414,15 @@ void build_centroid_dual_mesh( Mesh& mesh ) { // C wrapper interfaces to C++ routines void atlas__build_median_dual_mesh( Mesh::Implementation* mesh ) { - ATLAS_ERROR_HANDLING( Mesh m( mesh ); build_median_dual_mesh( m ); ); + ATLAS_ASSERT( mesh != nullptr, "Cannot access uninitialised atlas_Mesh" ); + Mesh m( mesh ); + build_median_dual_mesh( m ); } void atlas__build_centroid_dual_mesh( Mesh::Implementation* mesh ) { - ATLAS_ERROR_HANDLING( Mesh m( mesh ); build_centroid_dual_mesh( m ); ); + ATLAS_ASSERT( mesh != nullptr, "Cannot access uninitialised atlas_Mesh" ); + Mesh m( mesh ); + build_centroid_dual_mesh( m ); } // ------------------------------------------------------------------ diff --git a/src/atlas/mesh/actions/BuildEdges.cc b/src/atlas/mesh/actions/BuildEdges.cc index 5a6067ce2..b114b1f86 100644 --- a/src/atlas/mesh/actions/BuildEdges.cc +++ b/src/atlas/mesh/actions/BuildEdges.cc @@ -18,7 +18,9 @@ #include "atlas/array.h" #include "atlas/array/ArrayView.h" #include "atlas/array/IndexView.h" +#include "atlas/domain.h" #include "atlas/field/Field.h" +#include "atlas/grid/StructuredGrid.h" #include "atlas/library/config.h" #include "atlas/mesh/ElementType.h" #include "atlas/mesh/Elements.h" @@ -27,13 +29,14 @@ #include "atlas/mesh/Nodes.h" #include "atlas/mesh/detail/AccumulateFacets.h" #include "atlas/parallel/mpi/mpi.h" -#include "atlas/runtime/ErrorHandling.h" +#include "atlas/runtime/Exception.h" +#include "atlas/runtime/Log.h" #include "atlas/util/CoordinateEnums.h" #include "atlas/util/LonLatMicroDeg.h" #include "atlas/util/MicroDeg.h" #include "atlas/util/Unique.h" -using atlas::mesh::detail::accumulate_facets; +using atlas::mesh::detail::accumulate_facets_ordered_by_halo; using Topology = atlas::mesh::Nodes::Topology; using atlas::util::UniqueLonLat; using atlas::util::microdeg; @@ -47,12 +50,12 @@ namespace actions { namespace { // anonymous struct Sort { Sort() {} - Sort( gidx_t gid, int idx ) { + Sort( gidx_t gid, idx_t idx ) { g = gid; i = idx; } gidx_t g; - int i; + idx_t i; bool operator<( const Sort& other ) const { return ( g < other.g ); } }; } // anonymous namespace @@ -63,25 +66,20 @@ void build_element_to_edge_connectivity( Mesh& mesh ) { cell_edge_connectivity.clear(); // Allocate cell_edge_connectivity - for ( size_t t = 0; t < mesh.cells().nb_types(); ++t ) { - size_t nb_elements = mesh.cells().elements( t ).size(); - size_t nb_edges_per_elem = mesh.cells().element_type( t ).nb_edges(); + for ( idx_t t = 0; t < mesh.cells().nb_types(); ++t ) { + idx_t nb_elements = mesh.cells().elements( t ).size(); + idx_t nb_edges_per_elem = mesh.cells().element_type( t ).nb_edges(); std::vector init( mesh.cells().elements( t ).size() * nb_edges_per_elem, cell_edge_connectivity.missing_value() ); cell_edge_connectivity.add( nb_elements, nb_edges_per_elem, init.data() ); } - size_t nb_edges = mesh.edges().size(); - mesh::HybridElements::Connectivity& edge_cell_connectivity = mesh.edges().cell_connectivity(); - mesh::HybridElements::Connectivity& edge_node_connectivity = mesh.edges().node_connectivity(); + idx_t nb_edges = mesh.edges().size(); + const mesh::HybridElements::Connectivity& edge_cell_connectivity = mesh.edges().cell_connectivity(); + const mesh::HybridElements::Connectivity& edge_node_connectivity = mesh.edges().node_connectivity(); - bool has_pole_edges( false ); - std::shared_ptr> is_pole_edge; - if ( mesh.edges().has_field( "is_pole_edge" ) ) { - has_pole_edges = true; - is_pole_edge = std::shared_ptr>( - new array::ArrayView( array::make_view( mesh.edges().field( "is_pole_edge" ) ) ) ); - } + auto edge_flags = array::make_view( mesh.edges().flags() ); + auto is_pole_edge = [&]( idx_t e ) { return Topology::check( edge_flags( e ), Topology::POLE ); }; // Sort edges for bit-reproducibility std::vector edge_sort; @@ -89,25 +87,34 @@ void build_element_to_edge_connectivity( Mesh& mesh ) { { UniqueLonLat compute_uid( mesh ); - for ( size_t jedge = 0; jedge < nb_edges; ++jedge ) + for ( idx_t jedge = 0; jedge < nb_edges; ++jedge ) edge_sort.emplace_back( Sort( compute_uid( edge_node_connectivity.row( jedge ) ), jedge ) ); std::sort( edge_sort.data(), edge_sort.data() + nb_edges ); } // Fill in cell_edge_connectivity - std::vector edge_cnt( mesh.cells().size() ); - for ( size_t jedge = 0; jedge < nb_edges; ++jedge ) { + std::vector edge_cnt( mesh.cells().size() ); + for ( idx_t jedge = 0; jedge < nb_edges; ++jedge ) { int iedge = edge_sort[jedge].i; - for ( size_t j = 0; j < 2; ++j ) { + for ( idx_t j = 0; j < 2; ++j ) { idx_t elem = edge_cell_connectivity( iedge, j ); if ( elem != edge_cell_connectivity.missing_value() ) { + ATLAS_ASSERT( edge_cnt[elem] < cell_edge_connectivity.cols( elem ) ); cell_edge_connectivity.set( elem, edge_cnt[elem]++, iedge ); } else { - if ( !( has_pole_edges && ( *is_pole_edge )( iedge ) ) ) { - if ( j == 0 ) throw eckit::SeriousBug( "edge has no element connected", Here() ); + if ( not is_pole_edge( iedge ) ) { + if ( j == 0 ) { + auto node_gidx = array::make_view( mesh.nodes().global_index() ); + std::stringstream ss; + ss << "Edge [" << node_gidx( edge_node_connectivity( jedge, 0 ) ) << ", " + << node_gidx( edge_node_connectivity( jedge, 1 ) ) << "] " + << "has no element connected."; + Log::error() << ss.str() << std::endl; + throw_Exception( ss.str(), Here() ); + } } } } @@ -116,80 +123,177 @@ void build_element_to_edge_connectivity( Mesh& mesh ) { // Verify that all edges have been found auto field_flags = array::make_view( mesh.cells().flags() ); - auto patch = [&field_flags]( size_t e ) { + auto patch = [&field_flags]( idx_t e ) { using Topology = atlas::mesh::Nodes::Topology; return Topology::check( field_flags( e ), Topology::PATCH ); }; - for ( size_t jcell = 0; jcell < mesh.cells().size(); ++jcell ) { + for ( idx_t jcell = 0; jcell < mesh.cells().size(); ++jcell ) { if ( patch( jcell ) ) continue; - for ( size_t jcol = 0; jcol < cell_edge_connectivity.cols( jcell ); ++jcol ) { + for ( idx_t jcol = 0; jcol < cell_edge_connectivity.cols( jcell ); ++jcol ) { if ( cell_edge_connectivity( jcell, jcol ) == cell_edge_connectivity.missing_value() ) { const array::ArrayView gidx = array::make_view( mesh.nodes().global_index() ); std::stringstream msg; msg << "Could not find edge " << jcol << " for " << mesh.cells().name( jcell ) << " elem " << jcell << " with nodes ( "; - for ( size_t jnode = 0; jnode < mesh.cells().node_connectivity().cols( jcell ); ++jnode ) { + for ( idx_t jnode = 0; jnode < mesh.cells().node_connectivity().cols( jcell ); ++jnode ) { msg << gidx( mesh.cells().node_connectivity()( jcell, jnode ) ) << " "; } msg << ")"; - throw eckit::SeriousBug( msg.str(), Here() ); + throw_Exception( msg.str(), Here() ); } } } } void build_node_to_edge_connectivity( Mesh& mesh ) { - mesh::Nodes& nodes = mesh.nodes(); - const size_t nb_edges = mesh.edges().size(); + mesh::Nodes& nodes = mesh.nodes(); + const idx_t nb_edges = mesh.edges().size(); + + mesh::Nodes::Connectivity& node_to_edge = nodes.edge_connectivity(); + node_to_edge.clear(); - mesh::HybridElements::Connectivity& edge_node_connectivity = mesh.edges().node_connectivity(); + const mesh::HybridElements::Connectivity& edge_node_connectivity = mesh.edges().node_connectivity(); - std::vector to_edge_size( nodes.size(), 0 ); - for ( size_t jedge = 0; jedge < nb_edges; ++jedge ) { - for ( int j = 0; j < 2; ++j ) { + std::vector to_edge_size( nodes.size(), 0 ); + for ( idx_t jedge = 0; jedge < nb_edges; ++jedge ) { + for ( idx_t j = 0; j < 2; ++j ) { ++to_edge_size[edge_node_connectivity( jedge, j )]; } } - mesh::Nodes::Connectivity& node_to_edge = nodes.edge_connectivity(); node_to_edge.add( nodes.size(), to_edge_size.data() ); - for ( size_t jnode = 0; jnode < nodes.size(); ++jnode ) + + for ( idx_t jnode = 0; jnode < nodes.size(); ++jnode ) to_edge_size[jnode] = 0; UniqueLonLat compute_uid( mesh ); std::vector edge_sort( nb_edges ); - for ( size_t jedge = 0; jedge < nb_edges; ++jedge ) + for ( idx_t jedge = 0; jedge < nb_edges; ++jedge ) edge_sort[jedge] = Sort( compute_uid( edge_node_connectivity.row( jedge ) ), jedge ); std::stable_sort( edge_sort.data(), edge_sort.data() + nb_edges ); - for ( size_t jedge = 0; jedge < nb_edges; ++jedge ) { - size_t iedge = edge_sort[jedge].i; - for ( size_t j = 0; j < 2; ++j ) { + for ( idx_t jedge = 0; jedge < nb_edges; ++jedge ) { + idx_t iedge = edge_sort[jedge].i; + ATLAS_ASSERT( iedge < nb_edges ); + for ( idx_t j = 0; j < 2; ++j ) { idx_t node = edge_node_connectivity( iedge, j ); node_to_edge.set( node, to_edge_size[node]++, iedge ); } } } -void accumulate_pole_edges( mesh::Nodes& nodes, std::vector& pole_edge_nodes, size_t& nb_pole_edges ) { +class AccumulatePoleEdges { + enum + { + NORTH = 0, + SOUTH = 1 + }; + const array::ArrayView xy; + const array::ArrayView flags; + const array::ArrayView part; + const array::ArrayView halo; + const idx_t nb_nodes; + std::vector> pole_nodes; + +public: + AccumulatePoleEdges( mesh::Nodes& nodes ) : + xy( array::make_view( nodes.xy() ) ), + flags( array::make_view( nodes.flags() ) ), + part( array::make_view( nodes.partition() ) ), + halo( array::make_view( nodes.halo() ) ), + nb_nodes( nodes.size() ), + pole_nodes( 2 ) { + double min[2], max[2]; + min[XX] = std::numeric_limits::max(); + min[YY] = std::numeric_limits::max(); + max[XX] = -std::numeric_limits::max(); + max[YY] = -std::numeric_limits::max(); + for ( idx_t node = 0; node < nb_nodes; ++node ) { + min[XX] = std::min( min[XX], xy( node, XX ) ); + min[YY] = std::min( min[YY], xy( node, YY ) ); + max[XX] = std::max( max[XX], xy( node, XX ) ); + max[YY] = std::max( max[YY], xy( node, YY ) ); + } + + ATLAS_TRACE_MPI( ALLREDUCE ) { + mpi::comm().allReduceInPlace( min, 2, eckit::mpi::min() ); + mpi::comm().allReduceInPlace( max, 2, eckit::mpi::max() ); + } + + double tol = 1e-6; + + // Collect all nodes closest to poles + for ( idx_t node = 0; node < nb_nodes; ++node ) { + if ( std::abs( xy( node, YY ) - max[YY] ) < tol ) { pole_nodes[NORTH].insert( node ); } + else if ( std::abs( xy( node, YY ) - min[YY] ) < tol ) { + pole_nodes[SOUTH].insert( node ); + } + } + + // Sanity check + { + for ( idx_t NS = 0; NS < 2; ++NS ) { + int npart = -1; + for ( std::set::iterator it = pole_nodes[NS].begin(); it != pole_nodes[NS].end(); ++it ) { + int node = *it; + if ( npart == -1 ) + npart = part( node ); + else if ( part( node ) != npart ) { + // Not implemented yet, when pole-lattitude is split. + std::stringstream msg; + msg << "Split pole-latitude is not supported yet... node " << node << "[p" << part( node ) + << "] should belong to part " << npart; + throw_NotImplemented( msg.str(), Here() ); + } + } + } + } + } + void compute_pole_edges( int _halo, std::vector& pole_edge_nodes, idx_t& nb_pole_edges ) { + // Create connections over the poles and store in pole_edge_nodes + nb_pole_edges = 0; + for ( idx_t NS = 0; NS < 2; ++NS ) { + for ( std::set::iterator it = pole_nodes[NS].begin(); it != pole_nodes[NS].end(); ++it ) { + int node = *it; + if ( !Topology::check( flags( node ), Topology::PERIODIC | Topology::GHOST ) ) { + int x2 = microdeg( xy( node, XX ) + 180. ); + for ( std::set::iterator itr = pole_nodes[NS].begin(); itr != pole_nodes[NS].end(); ++itr ) { + int other_node = *itr; + if ( microdeg( xy( other_node, XX ) ) == x2 ) { + if ( !Topology::check( flags( other_node ), Topology::PERIODIC ) ) { + if ( halo( node ) == _halo && halo( other_node ) == _halo ) { + pole_edge_nodes.push_back( node ); + pole_edge_nodes.push_back( other_node ); + ++nb_pole_edges; + } + } + } + } + } + } + } + } +}; + +void accumulate_pole_edges( mesh::Nodes& nodes, std::vector& pole_edge_nodes, idx_t& nb_pole_edges ) { enum { NORTH = 0, SOUTH = 1 }; - array::ArrayView xy = array::make_view( nodes.xy() ); - array::ArrayView flags = array::make_view( nodes.field( "flags" ) ); - array::ArrayView part = array::make_view( nodes.partition() ); - const size_t nb_nodes = nodes.size(); + const auto xy = array::make_view( nodes.xy() ); + const auto flags = array::make_view( nodes.flags() ); + const auto part = array::make_view( nodes.partition() ); + const idx_t nb_nodes = nodes.size(); double min[2], max[2]; min[XX] = std::numeric_limits::max(); min[YY] = std::numeric_limits::max(); max[XX] = -std::numeric_limits::max(); max[YY] = -std::numeric_limits::max(); - for ( size_t node = 0; node < nb_nodes; ++node ) { + for ( idx_t node = 0; node < nb_nodes; ++node ) { min[XX] = std::min( min[XX], xy( node, XX ) ); min[YY] = std::min( min[YY], xy( node, YY ) ); max[XX] = std::max( max[XX], xy( node, XX ) ); @@ -205,7 +309,7 @@ void accumulate_pole_edges( mesh::Nodes& nodes, std::vector& pole_edge_no // Collect all nodes closest to poles std::vector> pole_nodes( 2 ); - for ( size_t node = 0; node < nb_nodes; ++node ) { + for ( idx_t node = 0; node < nb_nodes; ++node ) { if ( std::abs( xy( node, YY ) - max[YY] ) < tol ) { pole_nodes[NORTH].insert( node ); } else if ( std::abs( xy( node, YY ) - min[YY] ) < tol ) { pole_nodes[SOUTH].insert( node ); @@ -214,7 +318,7 @@ void accumulate_pole_edges( mesh::Nodes& nodes, std::vector& pole_edge_no // Sanity check { - for ( size_t NS = 0; NS < 2; ++NS ) { + for ( idx_t NS = 0; NS < 2; ++NS ) { int npart = -1; for ( std::set::iterator it = pole_nodes[NS].begin(); it != pole_nodes[NS].end(); ++it ) { int node = *it; @@ -225,7 +329,7 @@ void accumulate_pole_edges( mesh::Nodes& nodes, std::vector& pole_edge_no std::stringstream msg; msg << "Split pole-latitude is not supported yet... node " << node << "[p" << part( node ) << "] should belong to part " << npart; - throw eckit::NotImplemented( msg.str(), Here() ); + throw_NotImplemented( msg.str(), Here() ); } } } @@ -233,7 +337,7 @@ void accumulate_pole_edges( mesh::Nodes& nodes, std::vector& pole_edge_no // Create connections over the poles and store in pole_edge_nodes nb_pole_edges = 0; - for ( size_t NS = 0; NS < 2; ++NS ) { + for ( idx_t NS = 0; NS < 2; ++NS ) { for ( std::set::iterator it = pole_nodes[NS].begin(); it != pole_nodes[NS].end(); ++it ) { int node = *it; if ( !Topology::check( flags( node ), Topology::PERIODIC | Topology::GHOST ) ) { @@ -262,7 +366,7 @@ struct ComputeUniquePoleEdgeIndex { double centroid[2]; centroid[XX] = 0.; centroid[YY] = 0.; - for ( size_t jnode = 0; jnode < 2; ++jnode ) { + for ( idx_t jnode = 0; jnode < 2; ++jnode ) { centroid[XX] += xy( edge_nodes( jnode ), XX ); centroid[YY] += xy( edge_nodes( jnode ), YY ); } @@ -281,119 +385,235 @@ struct ComputeUniquePoleEdgeIndex { }; void build_edges( Mesh& mesh ) { - mesh::Nodes& nodes = mesh.nodes(); - array::ArrayView part = array::make_view( nodes.partition() ); + build_edges( mesh, util::NoConfig() ); +} + +void build_edges( Mesh& mesh, const eckit::Configuration& config ) { + ATLAS_TRACE( "BuildEdges" ); + + int mesh_halo( 0 ); + mesh.metadata().get( "halo", mesh_halo ); + + if ( mesh.metadata().has( "built_edges_for_halo" ) ) { + int edges_halo = mesh.metadata().getInt( "built_edges_for_halo" ); + if ( edges_halo == mesh_halo ) { + // Nothing to be done here + return; + } + } + + bool pole_edges{false}; + if ( StructuredGrid grid = mesh.grid() ) { + if ( Domain domain = grid.domain() ) { pole_edges = domain.global(); } + } + config.get( "pole_edges", pole_edges ); + + + mesh::Nodes& nodes = mesh.nodes(); + auto node_part = array::make_view( nodes.partition() ); - size_t nb_nodes = nodes.size(); + idx_t nb_nodes = nodes.size(); + + mesh.edges().clear(); + + idx_t edge_start{0}; + idx_t edge_end{0}; // storage for edge-to-node-connectivity shape=(nb_edges,2) std::vector edge_nodes_data; std::vector edge_to_elem_data; - size_t nb_edges; - size_t nb_inner_edges; + std::vector edge_halo_offsets; + idx_t nb_edges; + idx_t nb_inner_edges; idx_t missing_value; - accumulate_facets( mesh.cells(), mesh.nodes(), edge_nodes_data, edge_to_elem_data, nb_edges, nb_inner_edges, - missing_value ); - // Build edges - mesh.edges().add( new mesh::temporary::Line(), nb_edges, edge_nodes_data.data() ); - mesh::HybridElements::Connectivity& edge_nodes = mesh.edges().node_connectivity(); - mesh::HybridElements::Connectivity& cell_nodes = mesh.cells().node_connectivity(); + accumulate_facets_ordered_by_halo( mesh.cells(), mesh.nodes(), edge_nodes_data, edge_to_elem_data, nb_edges, + nb_inner_edges, missing_value, edge_halo_offsets ); - UniqueLonLat compute_uid( mesh ); + std::shared_ptr pole_edge_accumulator; + if ( pole_edges ) { pole_edge_accumulator = std::make_shared( nodes ); } - array::IndexView edge_ridx = array::make_indexview( mesh.edges().remote_index() ); - array::ArrayView edge_part = array::make_view( mesh.edges().partition() ); - array::ArrayView edge_glb_idx = array::make_view( mesh.edges().global_index() ); - - ASSERT( cell_nodes.missing_value() == missing_value ); - for ( size_t edge = 0; edge < nb_edges; ++edge ) { - const int ip1 = edge_nodes( edge, 0 ); - const int ip2 = edge_nodes( edge, 1 ); - if ( compute_uid( ip1 ) > compute_uid( ip2 ) ) { - idx_t swapped[2] = {ip2, ip1}; - edge_nodes.set( edge, swapped ); - } + for ( int halo = 0; halo <= mesh_halo; ++halo ) { + edge_start = edge_end; + edge_end += ( edge_halo_offsets[halo + 1] - edge_halo_offsets[halo] ); - ASSERT( size_t( edge_nodes( edge, 0 ) ) < nb_nodes ); - ASSERT( size_t( edge_nodes( edge, 1 ) ) < nb_nodes ); - edge_glb_idx( edge ) = compute_uid( edge_nodes.row( edge ) ); - edge_part( edge ) = std::min( part( edge_nodes( edge, 0 ) ), part( edge_nodes( edge, 1 ) ) ); - edge_ridx( edge ) = edge; + // Build edges + mesh.edges().add( new mesh::temporary::Line(), ( edge_end - edge_start ), + edge_nodes_data.data() + edge_halo_offsets[halo] * 2 ); + auto& edge_nodes = mesh.edges().node_connectivity(); + const auto& cell_nodes = mesh.cells().node_connectivity(); - const idx_t e1 = edge_to_elem_data[2 * edge + 0]; - const idx_t e2 = edge_to_elem_data[2 * edge + 1]; + UniqueLonLat compute_uid( mesh ); - ASSERT( e1 != cell_nodes.missing_value() ); - if ( e2 == cell_nodes.missing_value() ) { - // do nothing - } - else if ( compute_uid( cell_nodes.row( e1 ) ) > compute_uid( cell_nodes.row( e2 ) ) ) { - edge_to_elem_data[edge * 2 + 0] = e2; - edge_to_elem_data[edge * 2 + 1] = e1; + auto edge_ridx = array::make_indexview( mesh.edges().remote_index() ); + auto edge_part = array::make_view( mesh.edges().partition() ); + auto edge_glb_idx = array::make_view( mesh.edges().global_index() ); + auto edge_halo = array::make_view( mesh.edges().halo() ); + auto edge_flags = array::make_view( mesh.edges().flags() ); + + ATLAS_ASSERT( cell_nodes.missing_value() == missing_value ); + for ( idx_t edge = edge_start; edge < edge_end; ++edge ) { + const idx_t iedge = edge_halo_offsets[halo] + ( edge - edge_start ); + const int ip1 = edge_nodes( edge, 0 ); + const int ip2 = edge_nodes( edge, 1 ); + if ( compute_uid( ip1 ) > compute_uid( ip2 ) ) { + idx_t swapped[2] = {ip2, ip1}; + edge_nodes.set( edge, swapped ); + } + + ATLAS_ASSERT( idx_t( edge_nodes( edge, 0 ) ) < nb_nodes ); + ATLAS_ASSERT( idx_t( edge_nodes( edge, 1 ) ) < nb_nodes ); + edge_glb_idx( edge ) = compute_uid( edge_nodes.row( edge ) ); + edge_part( edge ) = std::min( node_part( edge_nodes( edge, 0 ) ), node_part( edge_nodes( edge, 1 ) ) ); + edge_ridx( edge ) = edge; + edge_halo( edge ) = halo; + edge_flags( edge ) = 0; + + const idx_t e1 = edge_to_elem_data[2 * iedge + 0]; + const idx_t e2 = edge_to_elem_data[2 * iedge + 1]; + + ATLAS_ASSERT( e1 != cell_nodes.missing_value() ); + if ( e2 == cell_nodes.missing_value() ) { + // do nothing + } + else if ( compute_uid( cell_nodes.row( e1 ) ) > compute_uid( cell_nodes.row( e2 ) ) ) { + edge_to_elem_data[iedge * 2 + 0] = e2; + edge_to_elem_data[iedge * 2 + 1] = e1; + } } - } - mesh.edges().cell_connectivity().add( nb_edges, 2, edge_to_elem_data.data() ); + mesh.edges().cell_connectivity().add( ( edge_end - edge_start ), 2, + edge_to_elem_data.data() + edge_halo_offsets[halo] * 2 ); - build_element_to_edge_connectivity( mesh ); -} + if ( pole_edges ) { + idx_t nb_pole_edges; + std::vector pole_edge_nodes; -void build_pole_edges( Mesh& mesh ) { - mesh::Nodes& nodes = mesh.nodes(); - mesh::HybridElements& edges = mesh.edges(); + pole_edge_accumulator->compute_pole_edges( halo, pole_edge_nodes, nb_pole_edges ); - size_t nb_cell_edges = edges.size(); + if ( nb_pole_edges ) { + edge_start = edge_end; + edge_end += nb_pole_edges; - size_t nb_pole_edges; - std::vector pole_edge_nodes; - accumulate_pole_edges( nodes, pole_edge_nodes, nb_pole_edges ); + mesh.edges().add( new mesh::temporary::Line(), nb_pole_edges, pole_edge_nodes.data() ); - edges.add( new mesh::temporary::Line(), nb_pole_edges, pole_edge_nodes.data() ); + auto edge_ridx = array::make_indexview( mesh.edges().remote_index() ); + auto edge_part = array::make_view( mesh.edges().partition() ); + auto edge_glb_idx = array::make_view( mesh.edges().global_index() ); + auto edge_halo = array::make_view( mesh.edges().halo() ); + auto edge_flags = array::make_view( mesh.edges().flags() ); - if ( !edges.has_field( "is_pole_edge" ) ) - edges.add( Field( "is_pole_edge", array::make_datatype(), array::make_shape( edges.size() ) ) ); + auto set_pole_edge = [&edge_flags]( idx_t e ) { Topology::set( edge_flags( e ), Topology::POLE ); }; - array::ArrayView node_part = array::make_view( nodes.partition() ); + auto& edge_nodes = mesh.edges().node_connectivity(); - array::ArrayView edge_glb_idx = array::make_view( edges.global_index() ); - array::ArrayView edge_part = array::make_view( edges.partition() ); - array::IndexView edge_ridx = array::make_indexview( edges.remote_index() ); - array::ArrayView is_pole_edge = array::make_view( edges.field( "is_pole_edge" ) ); + mesh.edges().cell_connectivity().add( nb_pole_edges, 2 ); - mesh::HybridElements::Connectivity& edge_nodes = edges.node_connectivity(); - MultiBlockConnectivity& edge_to_elem = edges.cell_connectivity(); - edge_to_elem.add( nb_pole_edges, 2 ); + idx_t cnt = 0; + ComputeUniquePoleEdgeIndex compute_uid( nodes ); + for ( idx_t edge = edge_start; edge < edge_end; ++edge ) { + idx_t ip1 = pole_edge_nodes[cnt++]; + idx_t ip2 = pole_edge_nodes[cnt++]; + std::array enodes{ip1, ip2}; + edge_nodes.set( edge, enodes.data() ); + edge_glb_idx( edge ) = compute_uid( edge_nodes.row( edge ) ); + edge_part( edge ) = + std::min( node_part( edge_nodes( edge, 0 ) ), node_part( edge_nodes( edge, 1 ) ) ); + edge_ridx( edge ) = edge; + edge_halo( edge ) = halo; + set_pole_edge( edge ); + } + } + } + } + + mesh.edges().metadata().set( "pole_edges", pole_edges ); - for ( size_t edge = 0; edge < nb_cell_edges; ++edge ) { - is_pole_edge( edge ) = 0; + + build_element_to_edge_connectivity( mesh ); + + mesh::HybridElements::Connectivity& cell_edges = mesh.cells().edge_connectivity(); + auto cell_halo = array::make_view( mesh.cells().halo() ); + auto cell_flags = array::make_view( mesh.cells().flags() ); + auto cell_patch = [&cell_flags]( idx_t e ) { + using Topology = atlas::mesh::Nodes::Topology; + return Topology::check( cell_flags( e ), Topology::PATCH ); + }; + auto edge_halo = array::make_view( mesh.edges().halo() ); + int max_halo = 0; + for ( idx_t jcell = 0; jcell < mesh.cells().size(); ++jcell ) { + if ( not cell_patch( jcell ) ) { + int halo = cell_halo( jcell ); + max_halo = std::max( halo, max_halo ); + for ( idx_t jedge = 0; jedge < cell_edges.cols( jcell ); ++jedge ) { + auto iedge = cell_edges( jcell, jedge ); + ATLAS_ASSERT( edge_halo( iedge ) <= halo ); + } + } } - size_t cnt = 0; - ComputeUniquePoleEdgeIndex compute_uid( nodes ); - for ( size_t edge = nb_cell_edges; edge < nb_cell_edges + nb_pole_edges; ++edge ) { - idx_t ip1 = pole_edge_nodes[cnt++]; - idx_t ip2 = pole_edge_nodes[cnt++]; - idx_t enodes[] = {ip1, ip2}; - edge_nodes.set( edge, enodes ); - edge_glb_idx( edge ) = compute_uid( edge_nodes.row( edge ) ); - edge_part( edge ) = std::min( node_part( edge_nodes( edge, 0 ) ), node_part( edge_nodes( edge, 1 ) ) ); - edge_ridx( edge ) = edge; - is_pole_edge( edge ) = 1; + std::vector nb_edges_including_halo( max_halo + 1 ); + + { + int nb_edges = mesh.edges().size(); + for ( int jedge = 0; jedge < nb_edges; ++jedge ) { + nb_edges_including_halo[edge_halo( jedge )] = jedge + 1; + if ( jedge > 0 ) ATLAS_ASSERT( edge_halo( jedge ) >= edge_halo( jedge - 1 ) ); + } + } + + for ( int i = 0; i <= max_halo; ++i ) { + if ( i > 0 ) ATLAS_ASSERT( nb_edges_including_halo[i] > nb_edges_including_halo[i - 1] ); + std::stringstream ss; + ss << "nb_edges_including_halo[" << i << "]"; + mesh.metadata().set( ss.str(), nb_edges_including_halo[i] ); + } + + mesh.metadata().set( "built_edges_for_halo", mesh_halo ); + + // Backwards compatibility for code that reads "is_pole_edge" field instead of checking the flags, only Fortran would do it + { + if ( pole_edges ) { + if ( !mesh.edges().has_field( "is_pole_edge" ) ) { + mesh.edges().add( + Field( "is_pole_edge", array::make_datatype(), array::make_shape( mesh.edges().size() ) ) ); + } + auto edge_flags = array::make_view( mesh.edges().flags() ); + auto is_pole_edge = array::make_view( mesh.edges().field( "is_pole_edge" ) ); + int nb_edges = mesh.edges().size(); + for ( int jedge = 0; jedge < nb_edges; ++jedge ) { + is_pole_edge( jedge ) = Topology::check( edge_flags( jedge ), Topology::POLE ); + } + } } } +void build_pole_edges( Mesh& ) { + ATLAS_TRACE(); + Log::info() << "ATLAS_WARNING: Deprecation warning: build_pole_edges is no longer required.\n" + << "It is automatically inferred within atlas_build_edges" << std::endl; + Log::info() << "The 'build_pole_edges' function will be removed in a future version" << std::endl; +} + //---------------------------------------------------------------------------------------------------------------------- // C wrapper interfaces to C++ routines +extern "C" { void atlas__build_edges( Mesh::Implementation* mesh ) { - ATLAS_ERROR_HANDLING( Mesh m( mesh ); build_edges( m ); ); + ATLAS_ASSERT( mesh != nullptr, "Cannot access uninitialised atlas_Mesh" ); + Mesh m( mesh ); + build_edges( m ); } -void atlas__build_pole_edges( Mesh::Implementation* mesh ) { - ATLAS_ERROR_HANDLING( Mesh m( mesh ); build_pole_edges( m ); ); +void atlas__build_pole_edges( Mesh::Implementation* ) { + Log::info() << "ATLAS_WARNING: Deprecation warning: atlas_build_pole_edges is no longer required.\n" + << "It is automatically inferred within atlas_build_edges" << std::endl; + Log::info() << "The 'atlas_build_pole_edges' function will be removed in a future version" << std::endl; } void atlas__build_node_to_edge_connectivity( Mesh::Implementation* mesh ) { - ATLAS_ERROR_HANDLING( Mesh m( mesh ); build_node_to_edge_connectivity( m ); ); + ATLAS_ASSERT( mesh != nullptr, "Cannot access uninitialised atlas_Mesh" ); + Mesh m( mesh ); + build_node_to_edge_connectivity( m ); +} } //---------------------------------------------------------------------------------------------------------------------- diff --git a/src/atlas/mesh/actions/BuildEdges.h b/src/atlas/mesh/actions/BuildEdges.h index d2dcab7a1..17e360283 100644 --- a/src/atlas/mesh/actions/BuildEdges.h +++ b/src/atlas/mesh/actions/BuildEdges.h @@ -10,15 +10,11 @@ #pragma once -#include - +namespace eckit { +class Configuration; +} // namespace eckit namespace atlas { class Mesh; -namespace mesh { -namespace detail { -class MeshImpl; -} -} // namespace mesh } // namespace atlas namespace atlas { @@ -26,19 +22,33 @@ namespace mesh { namespace actions { void build_edges( Mesh& mesh ); +void build_edges( Mesh& mesh, const eckit::Configuration& ); void build_pole_edges( Mesh& mesh ); void build_element_to_edge_connectivity( Mesh& mesh ); void build_node_to_edge_connectivity( Mesh& mesh ); -// ------------------------------------------------------------------ -// C wrapper interfaces to C++ routines -extern "C" { -void atlas__build_edges( mesh::detail::MeshImpl* mesh ); -void atlas__build_pole_edges( mesh::detail::MeshImpl* mesh ); -void atlas__build_node_to_edge_connectivity( mesh::detail::MeshImpl* mesh ); -} // ------------------------------------------------------------------ } // namespace actions } // namespace mesh } // namespace atlas + +// ------------------------------------------------------------------ + +namespace atlas { +namespace mesh { +namespace detail { +class MeshImpl; +} // namespace detail +} // namespace mesh +} // namespace atlas + + +// C wrapper interfaces to C++ routines +extern "C" { +void atlas__build_edges( atlas::mesh::detail::MeshImpl* mesh ); +void atlas__build_pole_edges( atlas::mesh::detail::MeshImpl* mesh ); +void atlas__build_node_to_edge_connectivity( atlas::mesh::detail::MeshImpl* mesh ); +} + +// ------------------------------------------------------------------ diff --git a/src/atlas/mesh/actions/BuildHalo.cc b/src/atlas/mesh/actions/BuildHalo.cc index deaefea4a..6c5568d3f 100644 --- a/src/atlas/mesh/actions/BuildHalo.cc +++ b/src/atlas/mesh/actions/BuildHalo.cc @@ -9,8 +9,10 @@ */ #include +#include #include #include +#include #include #include "atlas/array.h" @@ -24,15 +26,15 @@ #include "atlas/mesh/actions/BuildHalo.h" #include "atlas/mesh/actions/BuildParallelFields.h" #include "atlas/mesh/detail/AccumulateFacets.h" -#include "atlas/mesh/detail/PeriodicTransform.h" #include "atlas/parallel/mpi/Buffer.h" #include "atlas/parallel/mpi/mpi.h" -#include "atlas/runtime/ErrorHandling.h" +#include "atlas/runtime/Exception.h" #include "atlas/runtime/Log.h" #include "atlas/runtime/Trace.h" #include "atlas/util/CoordinateEnums.h" #include "atlas/util/LonLatMicroDeg.h" #include "atlas/util/MicroDeg.h" +#include "atlas/util/PeriodicTransform.h" #include "atlas/util/Unique.h" //#define DEBUG_OUTPUT @@ -45,9 +47,9 @@ // #define ATLAS_103 // #define ATLAS_103_SORT -using atlas::mesh::detail::PeriodicTransform; using atlas::mesh::detail::accumulate_facets; using atlas::util::LonLatMicroDeg; +using atlas::util::PeriodicTransform; using atlas::util::UniqueLonLat; using atlas::util::microdeg; using Topology = atlas::mesh::Nodes::Topology; @@ -57,12 +59,12 @@ namespace mesh { namespace actions { struct Entity { - Entity( gidx_t gid, int idx ) { + Entity( gidx_t gid, idx_t idx ) { g = gid; i = idx; } gidx_t g; - gidx_t i; + idx_t i; bool operator<( const Entity& other ) const { return ( g < other.g ); } }; @@ -75,8 +77,8 @@ void make_nodes_global_index_human_readable( const mesh::actions::BuildHalo& bui // and could receive different gidx for different tasks // unused // int mypart = mpi::comm().rank(); - int nparts = mpi::comm().size(); - size_t root = 0; + int nparts = static_cast( mpi::comm().size() ); + idx_t root = 0; array::ArrayView nodes_glb_idx = array::make_view( nodes.global_index() ); // nodes_glb_idx.dump( Log::info() ); @@ -90,7 +92,7 @@ void make_nodes_global_index_human_readable( const mesh::actions::BuildHalo& bui if ( do_all ) { points_to_edit.resize( nodes_glb_idx.size() ); - for ( size_t i = 0; i < nodes_glb_idx.size(); ++i ) + for ( idx_t i = 0; i < nodes_glb_idx.size(); ++i ) points_to_edit[i] = i; } else { @@ -101,8 +103,8 @@ void make_nodes_global_index_human_readable( const mesh::actions::BuildHalo& bui } std::vector glb_idx( points_to_edit.size() ); - int nb_nodes = glb_idx.size(); - for ( size_t i = 0; i < nb_nodes; ++i ) + idx_t nb_nodes = static_cast( glb_idx.size() ); + for ( idx_t i = 0; i < nb_nodes; ++i ) glb_idx[i] = nodes_glb_idx( points_to_edit[i] ); // ATLAS_DEBUG_VAR( points_to_edit ); @@ -146,14 +148,16 @@ void make_nodes_global_index_human_readable( const mesh::actions::BuildHalo& bui // 2) Sort all global indices, and renumber from 1 to glb_nb_edges std::vector node_sort; node_sort.reserve( glb_nb_nodes ); - for ( size_t jnode = 0; jnode < glb_idx_gathered.size(); ++jnode ) { + const idx_t nb_glb_idx_gathered = static_cast( glb_idx_gathered.size() ); + for ( idx_t jnode = 0; jnode < nb_glb_idx_gathered; ++jnode ) { node_sort.push_back( Entity( glb_idx_gathered[jnode], jnode ) ); } ATLAS_TRACE_SCOPE( "sort on rank 0" ) { std::sort( node_sort.begin(), node_sort.end() ); } - gidx_t gid = glb_idx_max + 1; - for ( size_t jnode = 0; jnode < node_sort.size(); ++jnode ) { + gidx_t gid = glb_idx_max + 1; + const idx_t nb_node_sort = static_cast( node_sort.size() ); + for ( idx_t jnode = 0; jnode < nb_node_sort; ++jnode ) { if ( jnode > 0 && node_sort[jnode].g != node_sort[jnode - 1].g ) { ++gid; } int inode = node_sort[jnode].i; glb_idx_gathered[inode] = gid; @@ -162,7 +166,7 @@ void make_nodes_global_index_human_readable( const mesh::actions::BuildHalo& bui // 3) Scatter renumbered back ATLAS_TRACE_MPI( SCATTER ) { mpi::comm().scatterv( glb_idx_gathered.data(), recvcounts.data(), recvdispls.data(), glb_idx.data(), - glb_idx.size(), root ); + static_cast( glb_idx.size() ), root ); } for ( int jnode = 0; jnode < nb_nodes; ++jnode ) { @@ -180,8 +184,8 @@ void make_cells_global_index_human_readable( const mesh::actions::BuildHalo& bui bool do_all ) { ATLAS_TRACE(); - int nparts = mpi::comm().size(); - size_t root = 0; + int nparts = static_cast( mpi::comm().size() ); + idx_t root = 0; array::ArrayView cells_glb_idx = array::make_view( cells.global_index() ); // ATLAS_DEBUG( "min = " << cells.global_index().metadata().getLong("min") ); @@ -194,12 +198,12 @@ void make_cells_global_index_human_readable( const mesh::actions::BuildHalo& bui if ( do_all ) { cells_to_edit.resize( cells_glb_idx.size() ); - for ( size_t i = 0; i < cells_glb_idx.size(); ++i ) { + for ( idx_t i = 0; i < cells_glb_idx.size(); ++i ) { cells_to_edit[i] = i; } } else { - size_t nb_cells_to_edit( 0 ); + idx_t nb_cells_to_edit( 0 ); for ( const auto& new_cells : build_halo.periodic_cells_local_index_ ) { nb_cells_to_edit += new_cells.size(); } @@ -216,8 +220,8 @@ void make_cells_global_index_human_readable( const mesh::actions::BuildHalo& bui } std::vector glb_idx( cells_to_edit.size() ); - int nb_cells = glb_idx.size(); - for ( size_t i = 0; i < nb_cells; ++i ) + const idx_t nb_cells = static_cast( glb_idx.size() ); + for ( idx_t i = 0; i < nb_cells; ++i ) glb_idx[i] = cells_glb_idx( cells_to_edit[i] ); // 1) Gather all global indices, together with location @@ -226,7 +230,7 @@ void make_cells_global_index_human_readable( const mesh::actions::BuildHalo& bui std::vector recvdispls( mpi::comm().size() ); ATLAS_TRACE_MPI( GATHER ) { mpi::comm().gather( nb_cells, recvcounts, root ); } - int glb_nb_cells = std::accumulate( recvcounts.begin(), recvcounts.end(), 0 ); + idx_t glb_nb_cells = std::accumulate( recvcounts.begin(), recvcounts.end(), 0 ); recvdispls[0] = 0; for ( int jpart = 1; jpart < nparts; ++jpart ) { // start at 1 @@ -242,23 +246,23 @@ void make_cells_global_index_human_readable( const mesh::actions::BuildHalo& bui // 2) Sort all global indices, and renumber from 1 to glb_nb_edges std::vector cell_sort; cell_sort.reserve( glb_nb_cells ); - for ( size_t jnode = 0; jnode < glb_idx_gathered.size(); ++jnode ) { - cell_sort.push_back( Entity( glb_idx_gathered[jnode], jnode ) ); + for ( idx_t jcell = 0; jcell < glb_nb_cells; ++jcell ) { + cell_sort.push_back( Entity( glb_idx_gathered[jcell], jcell ) ); } ATLAS_TRACE_SCOPE( "sort on rank 0" ) { std::sort( cell_sort.begin(), cell_sort.end() ); } gidx_t gid = glb_idx_max + 1; - for ( size_t jcell = 0; jcell < cell_sort.size(); ++jcell ) { + for ( idx_t jcell = 0; jcell < glb_nb_cells; ++jcell ) { if ( jcell > 0 && cell_sort[jcell].g != cell_sort[jcell - 1].g ) { ++gid; } - int icell = cell_sort[jcell].i; + idx_t icell = cell_sort[jcell].i; glb_idx_gathered[icell] = gid; } // 3) Scatter renumbered back ATLAS_TRACE_MPI( SCATTER ) { mpi::comm().scatterv( glb_idx_gathered.data(), recvcounts.data(), recvdispls.data(), glb_idx.data(), - glb_idx.size(), root ); + static_cast( glb_idx.size() ), root ); } for ( int jcell = 0; jcell < nb_cells; ++jcell ) { @@ -280,12 +284,12 @@ class BuildHaloHelper; void increase_halo( Mesh& mesh ); void increase_halo_interior( BuildHaloHelper& ); -class EastWest : public PeriodicTransform { +class EastWest : public util::PeriodicTransform { public: EastWest() { x_translation_ = -360.; } }; -class WestEast : public PeriodicTransform { +class WestEast : public util::PeriodicTransform { public: WestEast() { x_translation_ = 360.; } }; @@ -295,28 +299,25 @@ typedef std::vector> Node2Elem; void build_lookup_node2elem( const Mesh& mesh, Node2Elem& node2elem ) { ATLAS_TRACE(); - auto cell_gidx = array::make_view( mesh.cells().global_index() ); - auto node_gidx = array::make_view( mesh.nodes().global_index() ); - const mesh::Nodes& nodes = mesh.nodes(); node2elem.resize( nodes.size() ); - for ( size_t jnode = 0; jnode < node2elem.size(); ++jnode ) { + for ( idx_t jnode = 0; jnode < nodes.size(); ++jnode ) { node2elem[jnode].clear(); node2elem[jnode].reserve( 12 ); } const mesh::HybridElements::Connectivity& elem_nodes = mesh.cells().node_connectivity(); auto field_flags = array::make_view( mesh.cells().flags() ); - auto patched = [&field_flags]( size_t e ) { + auto patched = [&field_flags]( idx_t e ) { using Topology = atlas::mesh::Nodes::Topology; return Topology::check( field_flags( e ), Topology::PATCH ); }; - size_t nb_elems = mesh.cells().size(); - for ( size_t elem = 0; elem < nb_elems; ++elem ) { + idx_t nb_elems = mesh.cells().size(); + for ( idx_t elem = 0; elem < nb_elems; ++elem ) { if ( not patched( elem ) ) { - for ( size_t n = 0; n < elem_nodes.cols( elem ); ++n ) { + for ( idx_t n = 0; n < elem_nodes.cols( elem ); ++n ) { int node = elem_nodes( elem, n ); node2elem[node].push_back( elem ); } @@ -335,8 +336,8 @@ void accumulate_partition_bdry_nodes_old( Mesh& mesh, std::vector& bdry_nod facet_nodes.reserve( mesh.nodes().size() * 4 ); connectivity_facet_to_elem.reserve( facet_nodes.capacity() * 2 ); - size_t nb_facets( 0 ); - size_t nb_inner_facets( 0 ); + idx_t nb_facets( 0 ); + idx_t nb_inner_facets( 0 ); idx_t missing_value; accumulate_facets( /*in*/ mesh.cells(), @@ -347,9 +348,9 @@ void accumulate_partition_bdry_nodes_old( Mesh& mesh, std::vector& bdry_nod /*out*/ nb_inner_facets, /*out*/ missing_value ); - for ( size_t jface = 0; jface < nb_facets; ++jface ) { + for ( idx_t jface = 0; jface < nb_facets; ++jface ) { if ( connectivity_facet_to_elem[jface * 2 + 1] == missing_value ) { - for ( size_t jnode = 0; jnode < 2; ++jnode ) // 2 nodes per face + for ( idx_t jnode = 0; jnode < 2; ++jnode ) // 2 nodes per face { bdry_nodes_set.insert( facet_nodes[jface * 2 + jnode] ); } @@ -358,7 +359,7 @@ void accumulate_partition_bdry_nodes_old( Mesh& mesh, std::vector& bdry_nod bdry_nodes = std::vector( bdry_nodes_set.begin(), bdry_nodes_set.end() ); } -void accumulate_partition_bdry_nodes( Mesh& mesh, size_t halo, std::vector& bdry_nodes ) { +void accumulate_partition_bdry_nodes( Mesh& mesh, idx_t halo, std::vector& bdry_nodes ) { #ifndef ATLAS_103 /* deprecated */ accumulate_partition_bdry_nodes_old( mesh, bdry_nodes ); @@ -415,19 +416,19 @@ class Notification { std::vector notes; }; -typedef std::map Uid2Node; +typedef std::map Uid2Node; void build_lookup_uid2node( Mesh& mesh, Uid2Node& uid2node ) { ATLAS_TRACE(); Notification notes; mesh::Nodes& nodes = mesh.nodes(); array::ArrayView xy = array::make_view( nodes.xy() ); array::ArrayView glb_idx = array::make_view( nodes.global_index() ); - size_t nb_nodes = nodes.size(); + idx_t nb_nodes = nodes.size(); UniqueLonLat compute_uid( mesh ); uid2node.clear(); - for ( size_t jnode = 0; jnode < nb_nodes; ++jnode ) { + for ( idx_t jnode = 0; jnode < nb_nodes; ++jnode ) { uid_t uid = compute_uid( jnode ); bool inserted = uid2node.insert( std::make_pair( uid, jnode ) ).second; if ( not inserted ) { @@ -439,7 +440,7 @@ void build_lookup_uid2node( Mesh& mesh, Uid2Node& uid2node ) { notes.add_error( msg.str() ); } } - if ( notes.error() ) throw eckit::SeriousBug( notes.str(), Here() ); + if ( notes.error() ) throw_Exception( notes.str(), Here() ); } void accumulate_elements( const Mesh& mesh, const mpi::BufferView& request_node_uid, const Uid2Node& uid2node, @@ -449,22 +450,22 @@ void accumulate_elements( const Mesh& mesh, const mpi::BufferView& reques const mesh::HybridElements::Connectivity& elem_nodes = mesh.cells().node_connectivity(); const auto elem_part = array::make_view( mesh.cells().partition() ); - size_t nb_nodes = request_node_uid.size(); - const size_t mpi_rank = mpi::comm().rank(); + const idx_t nb_nodes = mesh.nodes().size(); + const idx_t nb_request_nodes = static_cast( request_node_uid.size() ); + const int mpi_rank = static_cast( mpi::comm().rank() ); std::set found_elements_set; - for ( size_t jnode = 0; jnode < nb_nodes; ++jnode ) { + for ( idx_t jnode = 0; jnode < nb_request_nodes; ++jnode ) { uid_t uid = request_node_uid( jnode ); - int inode = -1; + idx_t inode = -1; // search and get node index for uid Uid2Node::const_iterator found = uid2node.find( uid ); if ( found != uid2node.end() ) { inode = found->second; } - if ( inode != -1 && size_t( inode ) < node2elem.size() ) { - for ( size_t jelem = 0; jelem < node2elem[inode].size(); ++jelem ) { - idx_t e = node2elem[inode][jelem]; - if ( size_t( elem_part( e ) ) == mpi_rank ) { found_elements_set.insert( e ); } + if ( inode != -1 && inode < nb_nodes ) { + for ( const idx_t e : node2elem[inode] ) { + if ( elem_part( e ) == mpi_rank ) { found_elements_set.insert( e ); } } } } @@ -476,17 +477,15 @@ void accumulate_elements( const Mesh& mesh, const mpi::BufferView& reques // Collect all nodes new_nodes_uid.clear(); - for ( size_t jelem = 0; jelem < found_elements.size(); ++jelem ) { - idx_t e = found_elements[jelem]; - - size_t nb_elem_nodes = elem_nodes.cols( e ); - for ( size_t n = 0; n < nb_elem_nodes; ++n ) { + for ( const idx_t e : found_elements ) { + idx_t nb_elem_nodes = elem_nodes.cols( e ); + for ( idx_t n = 0; n < nb_elem_nodes; ++n ) { new_nodes_uid.insert( compute_uid( elem_nodes( e, n ) ) ); } } // Remove nodes we already have in the request-buffer - for ( size_t jnode = 0; jnode < nb_nodes; ++jnode ) { + for ( idx_t jnode = 0; jnode < nb_request_nodes; ++jnode ) { new_nodes_uid.erase( request_node_uid( jnode ) ); } } @@ -516,8 +515,8 @@ class BuildHaloHelper { std::vector> elem_type; - Buffers( Mesh& mesh ) { - const size_t mpi_size = mpi::comm().size(); + Buffers( Mesh& ) { + const idx_t mpi_size = static_cast( mpi::comm().size() ); node_part.resize( mpi_size ); node_ridx.resize( mpi_size ); @@ -533,21 +532,22 @@ class BuildHaloHelper { } void print( std::ostream& os ) const { - const size_t mpi_size = mpi::comm().size(); + const idx_t mpi_size = static_cast( mpi::comm().size() ); os << "Nodes\n" << "-----\n"; - size_t n( 0 ); - for ( size_t jpart = 0; jpart < mpi_size; ++jpart ) { - for ( size_t jnode = 0; jnode < node_glb_idx[jpart].size(); ++jnode ) { - os << std::setw( 4 ) << n++ << " : " << node_glb_idx[jpart][jnode] << "\n"; + idx_t n( 0 ); + for ( idx_t jpart = 0; jpart < mpi_size; ++jpart ) { + for ( auto g : node_glb_idx[jpart] ) { + os << std::setw( 4 ) << n++ << " : " << g << "\n"; } } os << std::flush; os << "Cells\n" << "-----\n"; - size_t e( 0 ); - for ( size_t jpart = 0; jpart < mpi_size; ++jpart ) { - for ( size_t jelem = 0; jelem < elem_glb_idx[jpart].size(); ++jelem ) { + idx_t e( 0 ); + for ( idx_t jpart = 0; jpart < mpi_size; ++jpart ) { + const idx_t nb_elem = static_cast( elem_glb_idx[jpart].size() ); + for ( idx_t jelem = 0; jelem < nb_elem; ++jelem ) { os << std::setw( 4 ) << e++ << " : [ t" << elem_type[jpart][jelem] << " -- p" << elem_part[jpart][jelem] << "] " << elem_glb_idx[jpart][jelem] << "\n"; } @@ -591,8 +591,9 @@ class BuildHaloHelper { array::ArrayView lonlat; array::ArrayView glb_idx; array::ArrayView part; - array::IndexView ridx; + array::IndexView ridx; array::ArrayView flags; + array::ArrayView halo; array::ArrayView ghost; mesh::HybridElements::Connectivity* elem_nodes; array::ArrayView elem_part; @@ -603,7 +604,7 @@ class BuildHaloHelper { Node2Elem node_to_elem; Uid2Node uid2node; UniqueLonLat compute_uid; - size_t halo; + idx_t halosize; public: BuildHaloHelper( BuildHalo& builder, Mesh& _mesh ) : @@ -613,16 +614,17 @@ class BuildHaloHelper { lonlat( array::make_view( mesh.nodes().lonlat() ) ), glb_idx( array::make_view( mesh.nodes().global_index() ) ), part( array::make_view( mesh.nodes().partition() ) ), - ridx( array::make_indexview( mesh.nodes().remote_index() ) ), - flags( array::make_view( mesh.nodes().field( "flags" ) ) ), + ridx( array::make_indexview( mesh.nodes().remote_index() ) ), + flags( array::make_view( mesh.nodes().flags() ) ), + halo( array::make_view( mesh.nodes().halo() ) ), ghost( array::make_view( mesh.nodes().ghost() ) ), elem_nodes( &mesh.cells().node_connectivity() ), elem_part( array::make_view( mesh.cells().partition() ) ), elem_flags( array::make_view( mesh.cells().flags() ) ), elem_glb_idx( array::make_view( mesh.cells().global_index() ) ), compute_uid( mesh ) { - halo = 0; - mesh.metadata().get( "halo", halo ); + halosize = 0; + mesh.metadata().get( "halo", halosize ); // update(); } @@ -633,9 +635,10 @@ class BuildHaloHelper { lonlat = array::make_view( nodes.lonlat() ); glb_idx = array::make_view( nodes.global_index() ); part = array::make_view( nodes.partition() ); - ridx = array::make_indexview( nodes.remote_index() ); - flags = array::make_view( nodes.field( "flags" ) ); + ridx = array::make_indexview( nodes.remote_index() ); + flags = array::make_view( nodes.flags() ); ghost = array::make_view( nodes.ghost() ); + halo = array::make_view( nodes.halo() ); elem_nodes = &mesh.cells().node_connectivity(); elem_part = array::make_view( mesh.cells().partition() ); @@ -647,14 +650,14 @@ class BuildHaloHelper { void fill_sendbuffer( Buffers& buf, const NodeContainer& nodes_uid, const ElementContainer& elems, const int p ) { // ATLAS_TRACE(); - int nb_nodes = nodes_uid.size(); + idx_t nb_nodes = static_cast( nodes_uid.size() ); buf.node_glb_idx[p].resize( nb_nodes ); buf.node_part[p].resize( nb_nodes ); buf.node_ridx[p].resize( nb_nodes ); buf.node_flags[p].resize( nb_nodes, Topology::NONE ); buf.node_xy[p].resize( 2 * nb_nodes ); - int jnode = 0; + idx_t jnode = 0; typename NodeContainer::iterator it; for ( it = nodes_uid.begin(); it != nodes_uid.end(); ++it, ++jnode ) { uid_t uid = *it; @@ -662,7 +665,7 @@ class BuildHaloHelper { Uid2Node::iterator found = uid2node.find( uid ); if ( found != uid2node.end() ) // Point exists inside domain { - int node = found->second; + idx_t node = found->second; buf.node_glb_idx[p][jnode] = glb_idx( node ); buf.node_part[p][jnode] = part( node ); buf.node_ridx[p][jnode] = ridx( node ); @@ -673,15 +676,15 @@ class BuildHaloHelper { else { Log::warning() << "Node with uid " << uid << " needed by [" << p << "] was not found in [" << mpi::comm().rank() << "]." << std::endl; - ASSERT( false ); + ATLAS_ASSERT( false ); } } - size_t nb_elems = elems.size(); + idx_t nb_elems = static_cast( elems.size() ); - size_t nb_elem_nodes( 0 ); - for ( size_t jelem = 0; jelem < nb_elems; ++jelem ) { - size_t ielem = elems[jelem]; + idx_t nb_elem_nodes( 0 ); + for ( idx_t jelem = 0; jelem < nb_elems; ++jelem ) { + idx_t ielem = elems[jelem]; nb_elem_nodes += elem_nodes->cols( ielem ); } @@ -691,26 +694,26 @@ class BuildHaloHelper { buf.elem_type[p].resize( nb_elems ); buf.elem_nodes_id[p].resize( nb_elem_nodes ); buf.elem_nodes_displs[p].resize( nb_elems ); - size_t jelemnode( 0 ); - for ( size_t jelem = 0; jelem < nb_elems; ++jelem ) { + idx_t jelemnode( 0 ); + for ( idx_t jelem = 0; jelem < nb_elems; ++jelem ) { buf.elem_nodes_displs[p][jelem] = jelemnode; - size_t ielem = elems[jelem]; + idx_t ielem = elems[jelem]; buf.elem_glb_idx[p][jelem] = elem_glb_idx( ielem ); buf.elem_part[p][jelem] = elem_part( ielem ); Topology::set( buf.elem_flags[p][jelem], elem_flags( ielem ) ); buf.elem_type[p][jelem] = mesh.cells().type_idx( ielem ); - for ( size_t jnode = 0; jnode < elem_nodes->cols( ielem ); ++jnode ) + for ( idx_t jnode = 0; jnode < elem_nodes->cols( ielem ); ++jnode ) buf.elem_nodes_id[p][jelemnode++] = compute_uid( ( *elem_nodes )( ielem, jnode ) ); } } template void fill_sendbuffer( Buffers& buf, const NodeContainer& nodes_uid, const ElementContainer& elems, - const PeriodicTransform& transform, int newflags, const int p ) { + const util::PeriodicTransform& transform, int newflags, const int p ) { // ATLAS_TRACE(); - int nb_nodes = nodes_uid.size(); + idx_t nb_nodes = static_cast( nodes_uid.size() ); buf.node_glb_idx[p].resize( nb_nodes ); buf.node_part[p].resize( nb_nodes ); buf.node_ridx[p].resize( nb_nodes ); @@ -738,15 +741,15 @@ class BuildHaloHelper { else { Log::warning() << "Node with uid " << uid << " needed by [" << p << "] was not found in [" << mpi::comm().rank() << "]." << std::endl; - ASSERT( false ); + ATLAS_ASSERT( false ); } } - size_t nb_elems = elems.size(); + idx_t nb_elems = static_cast( elems.size() ); - size_t nb_elem_nodes( 0 ); - for ( size_t jelem = 0; jelem < nb_elems; ++jelem ) { - size_t ielem = elems[jelem]; + idx_t nb_elem_nodes( 0 ); + for ( idx_t jelem = 0; jelem < nb_elems; ++jelem ) { + idx_t ielem = elems[jelem]; nb_elem_nodes += elem_nodes->cols( ielem ); } @@ -756,15 +759,15 @@ class BuildHaloHelper { buf.elem_type[p].resize( nb_elems ); buf.elem_nodes_id[p].resize( nb_elem_nodes ); buf.elem_nodes_displs[p].resize( nb_elems ); - size_t jelemnode( 0 ); - for ( size_t jelem = 0; jelem < nb_elems; ++jelem ) { + idx_t jelemnode( 0 ); + for ( idx_t jelem = 0; jelem < nb_elems; ++jelem ) { buf.elem_nodes_displs[p][jelem] = jelemnode; - size_t ielem = elems[jelem]; + idx_t ielem = elems[jelem]; buf.elem_part[p][jelem] = elem_part( ielem ); Topology::set( buf.elem_flags[p][jelem], elem_flags( ielem ) | newflags ); buf.elem_type[p][jelem] = mesh.cells().type_idx( ielem ); std::vector crds( elem_nodes->cols( ielem ) * 2 ); - for ( size_t jnode = 0; jnode < elem_nodes->cols( ielem ); ++jnode ) { + for ( idx_t jnode = 0; jnode < elem_nodes->cols( ielem ); ++jnode ) { double crd[] = {xy( ( *elem_nodes )( ielem, jnode ), XX ), xy( ( *elem_nodes )( ielem, jnode ), YY )}; transform( crd, -1 ); buf.elem_nodes_id[p][jelemnode++] = util::unique_lonlat( crd ); @@ -780,7 +783,7 @@ class BuildHaloHelper { void add_nodes( Buffers& buf ) { ATLAS_TRACE(); - const size_t mpi_size = mpi::comm().size(); + const idx_t mpi_size = static_cast( mpi::comm().size() ); mesh::Nodes& nodes = mesh.nodes(); int nb_nodes = nodes.size(); @@ -809,13 +812,14 @@ class BuildHaloHelper { }; std::vector> rfn_idx( mpi_size ); - for ( size_t jpart = 0; jpart < mpi_size; ++jpart ) { + for ( idx_t jpart = 0; jpart < mpi_size; ++jpart ) { rfn_idx[jpart].reserve( buf.node_glb_idx[jpart].size() ); } int nb_new_nodes = 0; - for ( size_t jpart = 0; jpart < mpi_size; ++jpart ) { - for ( size_t n = 0; n < buf.node_glb_idx[jpart].size(); ++n ) { + for ( idx_t jpart = 0; jpart < mpi_size; ++jpart ) { + const idx_t nb_nodes_on_part = static_cast( buf.node_glb_idx[jpart].size() ); + for ( idx_t n = 0; n < nb_nodes_on_part; ++n ) { double crd[] = {buf.node_xy[jpart][n * 2 + XX], buf.node_xy[jpart][n * 2 + YY]}; if ( not node_already_exists( util::unique_lonlat( crd ) ) ) { rfn_idx[jpart].push_back( n ); } } @@ -825,10 +829,11 @@ class BuildHaloHelper { // Resize nodes // ------------ nodes.resize( nb_nodes + nb_new_nodes ); - flags = array::make_view( nodes.field( "flags" ) ); + flags = array::make_view( nodes.flags() ); + halo = array::make_view( nodes.halo() ); glb_idx = array::make_view( nodes.global_index() ); part = array::make_view( nodes.partition() ); - ridx = array::make_indexview( nodes.remote_index() ); + ridx = array::make_indexview( nodes.remote_index() ); xy = array::make_view( nodes.xy() ); lonlat = array::make_view( nodes.lonlat() ); ghost = array::make_view( nodes.ghost() ); @@ -838,9 +843,10 @@ class BuildHaloHelper { // Add new nodes // ------------- int new_node = 0; - for ( size_t jpart = 0; jpart < mpi_size; ++jpart ) { + for ( idx_t jpart = 0; jpart < mpi_size; ++jpart ) { for ( size_t n = 0; n < rfn_idx[jpart].size(); ++n ) { - int loc_idx = nb_nodes + new_node; + int loc_idx = nb_nodes + new_node; + halo( loc_idx ) = halosize + 1; Topology::reset( flags( loc_idx ), buf.node_flags[jpart][rfn_idx[jpart][n]] ); ghost( loc_idx ) = Topology::check( flags( loc_idx ), Topology::GHOST ); glb_idx( loc_idx ) = buf.node_glb_idx[jpart][rfn_idx[jpart][n]]; @@ -869,7 +875,7 @@ class BuildHaloHelper { << glb_idx( loc_idx ) << "(" << xy( loc_idx, XX ) << "," << xy( loc_idx, YY ) << ")\n"; msg << "Existing already loc " << other << " : " << glb_idx( other ) << "(" << xy( other, XX ) << "," << xy( other, YY ) << ")\n"; - throw eckit::SeriousBug( msg.str(), Here() ); + throw_Exception( msg.str(), Here() ); } uid2node[uid] = nb_nodes + new_node; } @@ -881,8 +887,8 @@ class BuildHaloHelper { void add_elements( Buffers& buf ) { ATLAS_TRACE(); - const size_t mpi_size = mpi::comm().size(); - auto cell_gidx = array::make_view( mesh.cells().global_index() ); + const idx_t mpi_size = static_cast( mpi::comm().size() ); + auto cell_gidx = array::make_view( mesh.cells().global_index() ); // Elements might be duplicated from different Tasks. We need to identify // unique entries int nb_elems = mesh.cells().size(); @@ -912,14 +918,15 @@ class BuildHaloHelper { if ( not status.new_periodic_ghost_cells.size() ) status.new_periodic_ghost_cells.resize( mesh.cells().nb_types() ); - std::vector> received_new_elems( mpi_size ); - for ( size_t jpart = 0; jpart < mpi_size; ++jpart ) { + std::vector> received_new_elems( mpi_size ); + for ( idx_t jpart = 0; jpart < mpi_size; ++jpart ) { received_new_elems[jpart].reserve( buf.elem_glb_idx[jpart].size() ); } - size_t nb_new_elems( 0 ); - for ( size_t jpart = 0; jpart < mpi_size; ++jpart ) { - for ( size_t e = 0; e < buf.elem_glb_idx[jpart].size(); ++e ) { + idx_t nb_new_elems( 0 ); + for ( idx_t jpart = 0; jpart < mpi_size; ++jpart ) { + const idx_t nb_elems_from_part = static_cast( buf.elem_glb_idx[jpart].size() ); + for ( idx_t e = 0; e < nb_elems_from_part; ++e ) { if ( element_already_exists( buf.elem_glb_idx[jpart][e] ) == false ) { received_new_elems[jpart].push_back( e ); } @@ -929,17 +936,16 @@ class BuildHaloHelper { std::vector>> elements_of_type( mesh.cells().nb_types(), std::vector>( mpi_size ) ); - std::vector nb_elements_of_type( mesh.cells().nb_types(), 0 ); + std::vector nb_elements_of_type( mesh.cells().nb_types(), 0 ); - for ( size_t jpart = 0; jpart < mpi_size; ++jpart ) { - for ( size_t jelem = 0; jelem < received_new_elems[jpart].size(); ++jelem ) { - int ielem = received_new_elems[jpart][jelem]; + for ( idx_t jpart = 0; jpart < mpi_size; ++jpart ) { + for ( const idx_t ielem : received_new_elems[jpart] ) { elements_of_type[buf.elem_type[jpart][ielem]][jpart].push_back( ielem ); ++nb_elements_of_type[buf.elem_type[jpart][ielem]]; } } - for ( size_t t = 0; t < mesh.cells().nb_types(); ++t ) { + for ( idx_t t = 0; t < mesh.cells().nb_types(); ++t ) { const std::vector>& elems = elements_of_type[t]; mesh::Elements& elements = mesh.cells().elements( t ); @@ -947,8 +953,8 @@ class BuildHaloHelper { BlockConnectivity& node_connectivity = elements.node_connectivity(); if ( nb_elements_of_type[t] == 0 ) continue; - size_t old_size = elements.size(); - size_t new_elems_pos = elements.add( nb_elements_of_type[t] ); + idx_t old_size = elements.size(); + idx_t new_elems_pos = elements.add( nb_elements_of_type[t] ); auto elem_type_glb_idx = elements.view( mesh.cells().global_index() ); auto elem_type_part = elements.view( mesh.cells().partition() ); @@ -956,16 +962,15 @@ class BuildHaloHelper { auto elem_type_flags = elements.view( mesh.cells().flags() ); // Copy information in new elements - size_t new_elem( 0 ); - for ( size_t jpart = 0; jpart < mpi_size; ++jpart ) { - for ( size_t e = 0; e < elems[jpart].size(); ++e ) { - size_t jelem = elems[jpart][e]; + idx_t new_elem( 0 ); + for ( idx_t jpart = 0; jpart < mpi_size; ++jpart ) { + for ( const idx_t jelem : elems[jpart] ) { int loc_idx = new_elems_pos + new_elem; elem_type_glb_idx( loc_idx ) = std::abs( buf.elem_glb_idx[jpart][jelem] ); elem_type_part( loc_idx ) = buf.elem_part[jpart][jelem]; - elem_type_halo( loc_idx ) = halo + 1; + elem_type_halo( loc_idx ) = halosize + 1; elem_type_flags( loc_idx ) = buf.elem_flags[jpart][jelem]; - for ( size_t n = 0; n < node_connectivity.cols(); ++n ) { + for ( idx_t n = 0; n < node_connectivity.cols(); ++n ) { node_connectivity.set( loc_idx, n, uid2node[buf.elem_nodes_id[jpart][buf.elem_nodes_displs[jpart][jelem] + n]] ); } @@ -1002,13 +1007,13 @@ void gather_bdry_nodes( const BuildHaloHelper& helper, const std::vector& Mesh::PartitionGraph::Neighbours neighbours = helper.mesh.nearestNeighbourPartitions(); if ( periodic ) { // add own rank to neighbours to allow periodicity with self (pole caps) - size_t rank = comm.rank(); + idx_t rank = comm.rank(); neighbours.insert( std::upper_bound( neighbours.begin(), neighbours.end(), rank ), rank ); } - const size_t mpi_size = comm.size(); - const int counts_tag = 0; - const int buffer_tag = 1; + const idx_t mpi_size = comm.size(); + const int counts_tag = 0; + const int buffer_tag = 1; std::vector counts_requests; counts_requests.reserve( neighbours.size() ); @@ -1017,7 +1022,7 @@ void gather_bdry_nodes( const BuildHaloHelper& helper, const std::vector& int sendcnt = send.size(); ATLAS_TRACE_MPI( ISEND ) { - for ( size_t to : neighbours ) { + for ( idx_t to : neighbours ) { counts_requests.push_back( comm.iSend( sendcnt, to, counts_tag ) ); } } @@ -1025,13 +1030,13 @@ void gather_bdry_nodes( const BuildHaloHelper& helper, const std::vector& recv.counts.assign( 0, mpi_size ); ATLAS_TRACE_MPI( IRECEIVE ) { - for ( size_t from : neighbours ) { + for ( idx_t from : neighbours ) { counts_requests.push_back( comm.iReceive( recv.counts[from], from, counts_tag ) ); } } ATLAS_TRACE_MPI( ISEND ) { - for ( size_t to : neighbours ) { + for ( idx_t to : neighbours ) { buffer_requests.push_back( comm.iSend( send.data(), send.size(), to, buffer_tag ) ); } } @@ -1044,14 +1049,14 @@ void gather_bdry_nodes( const BuildHaloHelper& helper, const std::vector& recv.displs[0] = 0; recv.cnt = recv.counts[0]; - for ( size_t jpart = 1; jpart < mpi_size; ++jpart ) { + for ( idx_t jpart = 1; jpart < mpi_size; ++jpart ) { recv.displs[jpart] = recv.displs[jpart - 1] + recv.counts[jpart - 1]; recv.cnt += recv.counts[jpart]; } recv.buffer.resize( recv.cnt ); ATLAS_TRACE_MPI( IRECEIVE ) { - for ( size_t from : neighbours ) { + for ( idx_t from : neighbours ) { buffer_requests.push_back( comm.iReceive( recv.buffer.data() + recv.displs[from], recv.counts[from], from, buffer_tag ) ); } @@ -1078,26 +1083,27 @@ void increase_halo_interior( BuildHaloHelper& helper ) { // 1) Find boundary nodes of this partition: - accumulate_partition_bdry_nodes( helper.mesh, helper.halo, helper.bdry_nodes ); + accumulate_partition_bdry_nodes( helper.mesh, helper.halosize, helper.bdry_nodes ); const std::vector& bdry_nodes = helper.bdry_nodes; + const idx_t nb_bdry_nodes = static_cast( bdry_nodes.size() ); // 2) Communicate uid of these boundary nodes to other partitions std::vector send_bdry_nodes_uid( bdry_nodes.size() ); - for ( size_t jnode = 0; jnode < bdry_nodes.size(); ++jnode ) + for ( idx_t jnode = 0; jnode < nb_bdry_nodes; ++jnode ) send_bdry_nodes_uid[jnode] = helper.compute_uid( bdry_nodes[jnode] ); - size_t mpi_size = mpi::comm().size(); + idx_t mpi_size = static_cast( mpi::comm().size() ); atlas::mpi::Buffer recv_bdry_nodes_uid_from_parts( mpi_size ); gather_bdry_nodes( helper, send_bdry_nodes_uid, recv_bdry_nodes_uid_from_parts ); #ifndef ATLAS_103 /* deprecated */ - for ( size_t jpart = 0; jpart < mpi_size; ++jpart ) + for ( idx_t jpart = 0; jpart < mpi_size; ++jpart ) #else const Mesh::PartitionGraph::Neighbours neighbours = helper.mesh.nearestNeighbourPartitions(); - for ( size_t jpart : neighbours ) + for ( idx_t jpart : neighbours ) #endif { @@ -1128,8 +1134,7 @@ void increase_halo_interior( BuildHaloHelper& helper ) { class PeriodicPoints { public: - PeriodicPoints( Mesh& mesh, int flag, size_t N ) : - flags_( array::make_view( mesh.nodes().field( "flags" ) ) ) { + PeriodicPoints( Mesh& mesh, int flag, idx_t N ) : flags_( array::make_view( mesh.nodes().flags() ) ) { flag_ = flag; N_ = N; } @@ -1147,7 +1152,7 @@ class PeriodicPoints { friend std::ostream& operator<<( std::ostream& os, const PeriodicPoints& periodic_points ) { os << "["; - for ( size_t j = 0; j < periodic_points.flags_.shape( 0 ); ++j ) { + for ( idx_t j = 0; j < periodic_points.flags_.shape( 0 ); ++j ) { if ( periodic_points( j ) ) os << " " << j + 1; } os << " ]"; @@ -1156,7 +1161,7 @@ class PeriodicPoints { }; void increase_halo_periodic( BuildHaloHelper& helper, const PeriodicPoints& periodic_points, - const PeriodicTransform& transform, int newflags ) { + const util::PeriodicTransform& transform, int newflags ) { helper.update(); // if (helper.node_to_elem.size() == 0 ) !!! NOT ALLOWED !!! (atlas_test_halo // will fail) @@ -1172,15 +1177,16 @@ void increase_halo_periodic( BuildHaloHelper& helper, const PeriodicPoints& peri // 1) Find boundary nodes of this partition: - if ( !helper.bdry_nodes.size() ) accumulate_partition_bdry_nodes( helper.mesh, helper.halo, helper.bdry_nodes ); + if ( !helper.bdry_nodes.size() ) accumulate_partition_bdry_nodes( helper.mesh, helper.halosize, helper.bdry_nodes ); - std::vector bdry_nodes = filter_nodes( helper.bdry_nodes, periodic_points ); + std::vector bdry_nodes = filter_nodes( helper.bdry_nodes, periodic_points ); + const idx_t nb_bdry_nodes = static_cast( bdry_nodes.size() ); // 2) Compute transformed uid of these boundary nodes and send to other // partitions - std::vector send_bdry_nodes_uid( bdry_nodes.size() ); - for ( size_t jnode = 0; jnode < bdry_nodes.size(); ++jnode ) { + std::vector send_bdry_nodes_uid( nb_bdry_nodes ); + for ( idx_t jnode = 0; jnode < nb_bdry_nodes; ++jnode ) { double crd[] = {helper.xy( bdry_nodes[jnode], XX ), helper.xy( bdry_nodes[jnode], YY )}; transform( crd, +1 ); // Log::info() << " crd " << crd[0] << " " << crd[1] << " uid " << @@ -1188,7 +1194,7 @@ void increase_halo_periodic( BuildHaloHelper& helper, const PeriodicPoints& peri send_bdry_nodes_uid[jnode] = util::unique_lonlat( crd ); } - size_t mpi_size = mpi::comm().size(); + idx_t mpi_size = mpi::comm().size(); atlas::mpi::Buffer recv_bdry_nodes_uid_from_parts( mpi_size ); gather_bdry_nodes( helper, send_bdry_nodes_uid, recv_bdry_nodes_uid_from_parts, @@ -1196,13 +1202,13 @@ void increase_halo_periodic( BuildHaloHelper& helper, const PeriodicPoints& peri #ifndef ATLAS_103 /* deprecated */ - for ( size_t jpart = 0; jpart < mpi_size; ++jpart ) + for ( idx_t jpart = 0; jpart < mpi_size; ++jpart ) #else Mesh::PartitionGraph::Neighbours neighbours = helper.mesh.nearestNeighbourPartitions(); // add own rank to neighbours to allow periodicity with self (pole caps) - size_t rank = mpi::comm().rank(); + idx_t rank = mpi::comm().rank(); neighbours.insert( std::upper_bound( neighbours.begin(), neighbours.end(), rank ), rank ); - for ( size_t jpart : neighbours ) + for ( idx_t jpart : neighbours ) #endif { // 3) Find elements and nodes completing these elements in @@ -1210,7 +1216,7 @@ void increase_halo_periodic( BuildHaloHelper& helper, const PeriodicPoints& peri atlas::mpi::BufferView recv_bdry_nodes_uid = recv_bdry_nodes_uid_from_parts[jpart]; - std::vector found_bdry_elems; + std::vector found_bdry_elems; std::set found_bdry_nodes_uid; accumulate_elements( helper.mesh, recv_bdry_nodes_uid, helper.uid2node, helper.node_to_elem, found_bdry_elems, @@ -1244,7 +1250,7 @@ void BuildHalo::operator()( int nb_elems ) { for ( int jhalo = halo; jhalo < nb_elems; ++jhalo ) { Log::debug() << "Increase halo " << jhalo + 1 << std::endl; - size_t nb_nodes_before_halo_increase = mesh_.nodes().size(); + idx_t nb_nodes_before_halo_increase = mesh_.nodes().size(); BuildHaloHelper helper( *this, mesh_ ); @@ -1309,9 +1315,9 @@ void BuildHalo::operator()( int nb_elems ) { // C wrapper interfaces to C++ routines void atlas__build_halo( Mesh::Implementation* mesh, int nb_elems ) { - // #undef ATLAS_ERROR_HANDLING - // #define ATLAS_ERROR_HANDLING(x) x - ATLAS_ERROR_HANDLING( Mesh m( mesh ); build_halo( m, nb_elems ); ); + ATLAS_ASSERT( mesh != nullptr, "Cannot access uninitialised atlas_Mesh" ); + Mesh m( mesh ); + build_halo( m, nb_elems ); } // ------------------------------------------------------------------ diff --git a/src/atlas/mesh/actions/BuildHalo.h b/src/atlas/mesh/actions/BuildHalo.h index 542af321f..4ecfddb8e 100644 --- a/src/atlas/mesh/actions/BuildHalo.h +++ b/src/atlas/mesh/actions/BuildHalo.h @@ -26,12 +26,12 @@ class BuildHalo { BuildHalo( Mesh& mesh ); void operator()( int nb_elems ); +private: + Mesh& mesh_; + public: std::vector periodic_points_local_index_; std::vector> periodic_cells_local_index_; - -private: - Mesh& mesh_; }; /// @brief Enlarge each partition of the mesh with a halo of elements diff --git a/src/atlas/mesh/actions/BuildParallelFields.cc b/src/atlas/mesh/actions/BuildParallelFields.cc index be297b962..c6a80acc2 100644 --- a/src/atlas/mesh/actions/BuildParallelFields.cc +++ b/src/atlas/mesh/actions/BuildParallelFields.cc @@ -13,8 +13,6 @@ #include #include -#include "eckit/exception/Exceptions.h" - #include "atlas/array.h" #include "atlas/array/ArrayView.h" #include "atlas/array/IndexView.h" @@ -23,42 +21,43 @@ #include "atlas/mesh/Mesh.h" #include "atlas/mesh/Nodes.h" #include "atlas/mesh/actions/BuildParallelFields.h" -#include "atlas/mesh/detail/PeriodicTransform.h" #include "atlas/parallel/GatherScatter.h" #include "atlas/parallel/mpi/Buffer.h" #include "atlas/parallel/mpi/mpi.h" -#include "atlas/runtime/ErrorHandling.h" +#include "atlas/runtime/Exception.h" #include "atlas/runtime/Log.h" #include "atlas/runtime/Trace.h" #include "atlas/util/CoordinateEnums.h" +#include "atlas/util/PeriodicTransform.h" #include "atlas/util/Unique.h" #define EDGE( jedge ) \ "Edge(" << node_gidx( edge_nodes( jedge, 0 ) ) << "[p" << node_part( edge_nodes( jedge, 0 ) ) << "] " \ << node_gidx( edge_nodes( jedge, 1 ) ) << "[p" << node_part( edge_nodes( jedge, 1 ) ) << "])" +//#define DEBUGGING_PARFIELDS #ifdef DEBUGGING_PARFIELDS #define own1 2419089 #define own2 2423185 -#define OWNED_EDGE( jedge ) \ - ( ( gidx( edge_nodes( jedge, 0 ) ) == own1 && gidx( edge_nodes( jedge, 1 ) ) == own2 ) || \ - ( gidx( edge_nodes( jedge, 0 ) ) == own2 && gidx( edge_nodes( jedge, 1 ) ) == own1 ) ) +#define OWNED_EDGE( jedge ) \ + ( ( node_gidx( edge_nodes( jedge, 0 ) ) == own1 && node_gidx( edge_nodes( jedge, 1 ) ) == own2 ) || \ + ( node_gidx( edge_nodes( jedge, 0 ) ) == own2 && node_gidx( edge_nodes( jedge, 1 ) ) == own1 ) ) #define per1 -1 #define per2 -1 -#define PERIODIC_EDGE( jedge ) \ - ( ( gidx( edge_nodes( jedge, 0 ) ) == per1 && gidx( edge_nodes( jedge, 1 ) ) == per2 ) || \ - ( gidx( edge_nodes( jedge, 0 ) ) == per2 && gidx( edge_nodes( jedge, 1 ) ) == per1 ) ) -#define find1 -12 -#define find2 -17 -#define FIND_EDGE( jedge ) \ - ( ( gidx( edge_nodes( jedge, 0 ) ) == find1 && gidx( edge_nodes( jedge, 1 ) ) == find2 ) || \ - ( gidx( edge_nodes( jedge, 0 ) ) == find2 && gidx( edge_nodes( jedge, 1 ) ) == find1 ) ) -#define ownuid 547124520 -#define OWNED_UID( UID ) ( UID == ownuid ) +#define PERIODIC_EDGE( jedge ) \ + ( ( node_gidx( edge_nodes( jedge, 0 ) ) == per1 && node_gidx( edge_nodes( jedge, 1 ) ) == per2 ) || \ + ( node_gidx( edge_nodes( jedge, 0 ) ) == per2 && node_gidx( edge_nodes( jedge, 1 ) ) == per1 ) ) +#define find1 39 // 1697 +#define find2 41 // 1698 +#define FIND_EDGE( jedge ) \ + ( ( node_gidx( edge_nodes( jedge, 0 ) ) == find1 && node_gidx( edge_nodes( jedge, 1 ) ) == find2 ) || \ + ( node_gidx( edge_nodes( jedge, 0 ) ) == find2 && node_gidx( edge_nodes( jedge, 1 ) ) == find1 ) ) +#define find_gidx 689849552510167040 +#define FIND_GIDX( UID ) ( ( UID ) == find_gidx ) #endif using Topology = atlas::mesh::Nodes::Topology; -using atlas::mesh::detail::PeriodicTransform; +using atlas::util::PeriodicTransform; using atlas::util::UniqueLonLat; namespace atlas { @@ -79,12 +78,12 @@ typedef gidx_t uid_t; namespace { struct Node { - Node( gidx_t gid, int idx ) { + Node( gidx_t gid, idx_t idx ) { g = gid; i = idx; } gidx_t g; - gidx_t i; + idx_t i; bool operator<( const Node& other ) const { return ( g < other.g ); } }; @@ -134,7 +133,7 @@ Field& build_nodes_global_idx( mesh::Nodes& nodes ) { UniqueLonLat compute_uid( nodes ); - for ( size_t jnode = 0; jnode < glb_idx.shape( 0 ); ++jnode ) { + for ( idx_t jnode = 0; jnode < glb_idx.shape( 0 ); ++jnode ) { if ( glb_idx( jnode ) <= 0 ) { glb_idx( jnode ) = compute_uid( jnode ); } } return nodes.global_index(); @@ -158,8 +157,8 @@ void renumber_nodes_glb_idx( mesh::Nodes& nodes ) { UniqueLonLat compute_uid( nodes ); // unused // int mypart = mpi::comm().rank(); - int nparts = mpi::comm().size(); - size_t root = 0; + int nparts = mpi::comm().size(); + idx_t root = 0; array::ArrayView glb_idx = array::make_view( nodes.global_index() ); @@ -204,20 +203,21 @@ void renumber_nodes_glb_idx( mesh::Nodes& nodes ) { std::vector node_sort; node_sort.reserve( glb_nb_nodes ); ATLAS_TRACE_SCOPE( "sort global indices" ) { - for ( size_t jnode = 0; jnode < glb_id.shape( 0 ); ++jnode ) { + for ( idx_t jnode = 0; jnode < glb_id.shape( 0 ); ++jnode ) { node_sort.push_back( Node( glb_id( jnode ), jnode ) ); } std::sort( node_sort.begin(), node_sort.end() ); } // Assume edge gid start - uid_t gid = 0; - for ( size_t jnode = 0; jnode < node_sort.size(); ++jnode ) { + uid_t gid = 0; + const idx_t nb_sorted_nodes = static_cast( node_sort.size() ); + for ( idx_t jnode = 0; jnode < nb_sorted_nodes; ++jnode ) { if ( jnode == 0 ) { ++gid; } else if ( node_sort[jnode].g != node_sort[jnode - 1].g ) { ++gid; } - int inode = node_sort[jnode].i; + idx_t inode = node_sort[jnode].i; glb_id( inode ) = gid; } @@ -236,47 +236,46 @@ void renumber_nodes_glb_idx( mesh::Nodes& nodes ) { Field& build_nodes_remote_idx( mesh::Nodes& nodes ) { ATLAS_TRACE(); - size_t mypart = mpi::comm().rank(); - size_t nparts = mpi::comm().size(); + idx_t mypart = static_cast( mpi::comm().rank() ); + idx_t nparts = static_cast( mpi::comm().size() ); UniqueLonLat compute_uid( nodes ); // This piece should be somewhere central ... could be NPROMA ? // ----------> - std::vector proc( nparts ); - for ( size_t jpart = 0; jpart < nparts; ++jpart ) + std::vector proc( nparts ); + for ( idx_t jpart = 0; jpart < nparts; ++jpart ) proc[jpart] = jpart; // <--------- - auto ridx = array::make_indexview( nodes.remote_index() ); - auto part = array::make_view( nodes.partition() ); - auto gidx = array::make_view( nodes.global_index() ); - size_t nb_nodes = nodes.size(); + auto ridx = array::make_indexview( nodes.remote_index() ); + auto part = array::make_view( nodes.partition() ); + idx_t nb_nodes = nodes.size(); - int varsize = 2; + idx_t varsize = 2; std::vector> send_needed( mpi::comm().size() ); std::vector> recv_needed( mpi::comm().size() ); int sendcnt = 0; std::map lookup; - for ( size_t jnode = 0; jnode < nb_nodes; ++jnode ) { + for ( idx_t jnode = 0; jnode < nb_nodes; ++jnode ) { uid_t uid = compute_uid( jnode ); - if ( size_t( part( jnode ) ) == mypart ) { + if ( idx_t( part( jnode ) ) == mypart ) { lookup[uid] = jnode; ridx( jnode ) = jnode; } else { - ASSERT( jnode < part.shape( 0 ) ); - if ( part( jnode ) >= (int)proc.size() ) { + ATLAS_ASSERT( jnode < part.shape( 0 ) ); + if ( part( jnode ) >= static_cast( proc.size() ) ) { std::stringstream msg; msg << "Assertion [part(" << jnode << ") < proc.size()] failed\n" << "part(" << jnode << ") = " << part( jnode ) << "\n" << "proc.size() = " << proc.size(); - eckit::AssertionFailed( msg.str(), Here() ); + throw_AssertionFailed( msg.str(), Here() ); } - ASSERT( part( jnode ) < (int)proc.size() ); - ASSERT( (size_t)proc[part( jnode )] < send_needed.size() ); + ATLAS_ASSERT( part( jnode ) < (idx_t)proc.size() ); + ATLAS_ASSERT( (size_t)proc[part( jnode )] < send_needed.size() ); send_needed[proc[part( jnode )]].push_back( uid ); send_needed[proc[part( jnode )]].push_back( jnode ); sendcnt++; @@ -288,14 +287,14 @@ Field& build_nodes_remote_idx( mesh::Nodes& nodes ) { std::vector> send_found( mpi::comm().size() ); std::vector> recv_found( mpi::comm().size() ); - for ( size_t jpart = 0; jpart < nparts; ++jpart ) { + for ( idx_t jpart = 0; jpart < nparts; ++jpart ) { const std::vector& recv_node = recv_needed[proc[jpart]]; - const size_t nb_recv_nodes = recv_node.size() / varsize; + const idx_t nb_recv_nodes = idx_t( recv_node.size() ) / varsize; // array::ArrayView recv_node( make_view( Array::wrap(shape, // recv_needed[ proc[jpart] ].data()) ), // array::make_shape(recv_needed[ proc[jpart] ].size()/varsize,varsize) // ); - for ( size_t jnode = 0; jnode < nb_recv_nodes; ++jnode ) { + for ( idx_t jnode = 0; jnode < nb_recv_nodes; ++jnode ) { uid_t uid = recv_node[jnode * varsize + 0]; int inode = recv_node[jnode * varsize + 1]; if ( lookup.count( uid ) ) { @@ -307,19 +306,19 @@ Field& build_nodes_remote_idx( mesh::Nodes& nodes ) { msg << "[" << mpi::comm().rank() << "] " << "Node requested by rank [" << jpart << "] with uid [" << uid << "] that should be owned is not found"; - throw eckit::SeriousBug( msg.str(), Here() ); + throw_Exception( msg.str(), Here() ); } } } ATLAS_TRACE_MPI( ALLTOALL ) { mpi::comm().allToAll( send_found, recv_found ); } - for ( size_t jpart = 0; jpart < nparts; ++jpart ) { + for ( idx_t jpart = 0; jpart < nparts; ++jpart ) { const std::vector& recv_node = recv_found[proc[jpart]]; - const size_t nb_recv_nodes = recv_node.size() / 2; + const idx_t nb_recv_nodes = recv_node.size() / 2; // array::ArrayView recv_node( recv_found[ proc[jpart] ].data(), // array::make_shape(recv_found[ proc[jpart] ].size()/2,2) ); - for ( size_t jnode = 0; jnode < nb_recv_nodes; ++jnode ) { + for ( idx_t jnode = 0; jnode < nb_recv_nodes; ++jnode ) { ridx( recv_node[jnode * 2 + 0] ) = recv_node[jnode * 2 + 1]; } } @@ -340,25 +339,23 @@ Field& build_edges_partition( Mesh& mesh ) { const mesh::Nodes& nodes = mesh.nodes(); - UniqueLonLat compute_uid( mesh ); - - size_t mypart = mpi::comm().rank(); - size_t nparts = mpi::comm().size(); + idx_t mypart = static_cast( mpi::comm().rank() ); - mesh::HybridElements& edges = mesh.edges(); - array::ArrayView edge_part = array::make_view( edges.partition() ); - array::ArrayView edge_glb_idx = array::make_view( edges.global_index() ); + mesh::HybridElements& edges = mesh.edges(); + auto edge_part = array::make_view( edges.partition() ); + //const auto edge_glb_idx = array::make_view( edges.global_index() ); - const mesh::HybridElements::Connectivity& edge_nodes = edges.node_connectivity(); - const mesh::HybridElements::Connectivity& edge_to_elem = edges.cell_connectivity(); + const auto& edge_nodes = edges.node_connectivity(); + const auto& edge_to_elem = edges.cell_connectivity(); - array::ArrayView node_part = array::make_view( nodes.partition() ); - array::ArrayView xy = array::make_view( nodes.xy() ); - array::ArrayView flags = array::make_view( nodes.field( "flags" ) ); - array::ArrayView node_gidx = array::make_view( nodes.global_index() ); + const auto node_part = array::make_view( nodes.partition() ); + const auto xy = array::make_view( nodes.xy() ); + const auto flags = array::make_view( nodes.flags() ); + const auto node_gidx = array::make_view( nodes.global_index() ); - array::ArrayView elem_part = array::make_view( mesh.cells().partition() ); - array::ArrayView elem_halo = array::make_view( mesh.cells().halo() ); + const auto elem_gidx = array::make_view( mesh.cells().global_index() ); + const auto elem_part = array::make_view( mesh.cells().partition() ); + //const auto elem_halo = array::make_view( mesh.cells().halo() ); auto check_flags = [&]( idx_t jedge, int flag ) { idx_t ip1 = edge_nodes( jedge, 0 ); @@ -368,29 +365,84 @@ Field& build_edges_partition( Mesh& mesh ) { auto domain_bdry = [&]( idx_t jedge ) { if ( check_flags( jedge, Topology::BC | Topology::NORTH ) ) { return true; } if ( check_flags( jedge, Topology::BC | Topology::SOUTH ) ) { return true; } + if ( check_flags( jedge, Topology::BC | Topology::WEST ) ) { return true; } + if ( check_flags( jedge, Topology::BC | Topology::EAST ) ) { return true; } + return false; + }; + auto periodic_east = [&]( idx_t jedge ) { + if ( check_flags( jedge, Topology::PERIODIC | Topology::EAST ) ) { return true; } + return false; + }; + auto periodic_west = [&]( idx_t jedge ) { + if ( check_flags( jedge, Topology::PERIODIC | Topology::WEST ) ) { return true; } return false; }; - PeriodicTransform transform; + auto periodic_west_bdry = [&]( idx_t jedge ) { + if ( check_flags( jedge, Topology::PERIODIC | Topology::WEST | Topology::BC ) ) { return true; } + return false; + }; - size_t nb_edges = edges.size(); - std::vector periodic( nb_edges ); + idx_t nb_edges = edges.size(); std::vector bdry_edges; bdry_edges.reserve( nb_edges ); - std::map global_to_local; - - for ( size_t jedge = 0; jedge < nb_edges; ++jedge ) { - global_to_local[edge_glb_idx( jedge )] = jedge; - - periodic[jedge] = 0; - idx_t ip1 = edge_nodes( jedge, 0 ); - idx_t ip2 = edge_nodes( jedge, 1 ); - int pn1 = node_part( ip1 ); - int pn2 = node_part( ip2 ); - int y1 = util::microdeg( xy( ip1, YY ) ); - int y2 = util::microdeg( xy( ip2, YY ) ); + std::map global_to_local; + + + PeriodicTransform transform_periodic_east( -360. ); + PeriodicTransform transform_periodic_west( +360. ); + UniqueLonLat _compute_uid( mesh ); + auto compute_uid = [&]( idx_t jedge ) -> gidx_t { + if ( periodic_east( jedge ) ) { return -_compute_uid( edge_nodes.row( jedge ), transform_periodic_east ); } + else if ( periodic_west_bdry( jedge ) ) { + return _compute_uid( edge_nodes.row( jedge ) ); + } + else if ( periodic_west( jedge ) ) { + return -_compute_uid( edge_nodes.row( jedge ), transform_periodic_west ); + } + else { + return _compute_uid( edge_nodes.row( jedge ) ); + } + }; + + + // should be unit-test + { + ATLAS_ASSERT( util::unique_lonlat( 360., 0., transform_periodic_east ) == util::unique_lonlat( 0., 0. ) ); + ATLAS_ASSERT( util::unique_lonlat( 0., 0., transform_periodic_west ) == util::unique_lonlat( 360., 0. ) ); + } + + + for ( idx_t jedge = 0; jedge < nb_edges; ++jedge ) { + gidx_t edge_gidx = compute_uid( jedge ); + global_to_local[edge_gidx] = jedge; + +#ifdef DEBUGGING_PARFIELDS + if ( FIND_EDGE( jedge ) ) { + std::cout << "[" << mypart << "] " << EDGE( jedge ) << " has gidx " << edge_gidx << std::endl; + if ( periodic_east( jedge ) ) { + std::cout << "[" << mypart << "] " << EDGE( jedge ) << " is periodic_east " << std::endl; + } + else if ( periodic_west( jedge ) ) { + std::cout << "[" << mypart << "] " << EDGE( jedge ) << " is periodic_west " << std::endl; + } + else { + std::cout << "[" << mypart << "] " << EDGE( jedge ) << " is not periodic" << std::endl; + } + } + if ( FIND_GIDX( edge_gidx ) ) + std::cout << "[" << mypart << "] " + << "has " << EDGE( jedge ) << " with gidx " << edge_gidx << std::endl; +#endif + + idx_t ip1 = edge_nodes( jedge, 0 ); + idx_t ip2 = edge_nodes( jedge, 1 ); + int pn1 = node_part( ip1 ); + int pn2 = node_part( ip2 ); + int y1 = util::microdeg( xy( ip1, YY ) ); + int y2 = util::microdeg( xy( ip2, YY ) ); int p; if ( y1 == y2 ) { int x1 = util::microdeg( xy( ip1, XX ) ); @@ -401,20 +453,55 @@ Field& build_edges_partition( Mesh& mesh ) { p = ( y1 > y2 ) ? pn1 : pn2; } - idx_t elem1 = edge_to_elem( jedge, 0 ); - idx_t elem2 = edge_to_elem( jedge, 1 ); - if ( elem1 == edge_to_elem.missing_value() ) { - bdry_edges.push_back( edge_glb_idx( jedge ) ); - p = pn1; - // Log::error() << EDGE(jedge) << " is a pole edge with part " << p << - // std::endl; + idx_t elem1 = edge_to_elem( jedge, 0 ); + idx_t elem2 = edge_to_elem( jedge, 1 ); + idx_t missing = edge_to_elem.missing_value(); + if ( elem1 == missing && elem2 == missing ) { + // Don't attempt to change p } - else if ( elem2 == edge_to_elem.missing_value() ) { - // if( not domain_bdry(jedge) ) { - bdry_edges.push_back( edge_glb_idx( jedge ) ); - p = elem_part( elem1 ); - if ( pn1 != p && pn2 == pn1 && elem_halo( elem1 ) > 0 ) { p = pn1; } - // } + else if ( elem1 == missing ) { + ATLAS_NOTIMPLEMENTED; + } + else if ( elem2 == missing ) { + if ( pn1 == pn2 ) { p = pn1; } + else if ( periodic_east( jedge ) ) { +#ifdef DEBUGGING_PARFIELDS + if ( FIND_EDGE( jedge ) ) + std::cout << "[" << mypart << "] " + << "periodic_east" << std::endl; +#endif + bdry_edges.push_back( edge_gidx ); + p = -1; + } + else if ( periodic_west_bdry( jedge ) ) { +#ifdef DEBUGGING_PARFIELDS + if ( FIND_EDGE( jedge ) ) + std::cout << "[" << mypart << "] " + << "periodic_west_bdry" << std::endl; +#endif + p = elem_part( elem1 ); + } + else if ( periodic_west( jedge ) ) { +#ifdef DEBUGGING_PARFIELDS + if ( FIND_EDGE( jedge ) ) + std::cout << "[" << mypart << "] " + << "periodic_west" << std::endl; +#endif + bdry_edges.push_back( edge_gidx ); + p = -1; + } + else if ( domain_bdry( jedge ) ) { +#ifdef DEBUGGING_PARFIELDS + if ( FIND_EDGE( jedge ) ) + std::cout << "[" << mypart << "] " + << "domain_bdry" << std::endl; +#endif + p = elem_part( elem1 ); + } + else { + bdry_edges.push_back( edge_gidx ); + p = -1; + } } else if ( p != elem_part( elem1 ) && p != elem_part( elem2 ) ) { p = ( p == pn1 ) ? pn2 : pn1; @@ -424,7 +511,7 @@ Field& build_edges_partition( Mesh& mesh ) { msg << "[" << eckit::mpi::comm().rank() << "] " << EDGE( jedge ) << " has nodes and elements of different rank: elem1[p" << elem_part( elem1 ) << "] elem2[p" << elem_part( elem2 ) << "]"; - throw eckit::SeriousBug( msg.str(), Here() ); + throw_Exception( msg.str(), Here() ); } } edge_part( jedge ) = p; @@ -440,30 +527,51 @@ Field& build_edges_partition( Mesh& mesh ) { mpi::Buffer recv_bdry_edges_from_parts( mpi_size ); std::vector> send_gidx( mpi_size ); std::vector> send_part( mpi_size ); - std::vector> recv_gidx( mpi_size ); - std::vector> recv_part( mpi_size ); + std::vector> send_bdry_gidx( mpi_size ); + std::vector> send_bdry_elem_part( mpi_size ); + std::vector> send_bdry_elem_gidx( mpi_size ); mpi::comm().allGatherv( bdry_edges.begin(), bdry_edges.end(), recv_bdry_edges_from_parts ); for ( int p = 0; p < mpi_size; ++p ) { auto view = recv_bdry_edges_from_parts[p]; - for ( int j = 0; j < view.size(); ++j ) { - gidx_t gidx = view[j]; - if ( global_to_local.count( gidx ) ) { - if ( not is_bdry_edge( gidx ) ) { - int iedge = global_to_local[gidx]; + for ( size_t j = 0; j < view.size(); ++j ) { + gidx_t gidx = view[j]; + gidx_t master_gidx = std::abs( gidx ); + if ( global_to_local.count( master_gidx ) ) { + idx_t iedge = global_to_local[master_gidx]; +#ifdef DEBUGGING_PARFIELDS + if ( FIND_GIDX( master_gidx ) ) std::cout << "[" << mypart << "] found " << EDGE( iedge ) << std::endl; +#endif + if ( not is_bdry_edge( master_gidx ) ) { send_gidx[p].push_back( gidx ); send_part[p].push_back( edge_part( iedge ) ); +#ifdef DEBUGGING_PARFIELDS + if ( FIND_EDGE( iedge ) ) { + std::cout << "[" << mypart << "] found " << EDGE( iedge ) " for part " << p << std::endl; + } +#endif + } + else { // boundary edge with nodes of different rank + idx_t ielem = + ( edge_to_elem( iedge, 0 ) != edge_to_elem.missing_value() ? edge_to_elem( iedge, 0 ) + : edge_to_elem( iedge, 1 ) ); + send_bdry_gidx[p].push_back( gidx ); + send_bdry_elem_part[p].push_back( elem_part( ielem ) ); + send_bdry_elem_gidx[p].push_back( elem_gidx( ielem ) ); } } } } + std::vector> recv_gidx( mpi_size ); + std::vector> recv_part( mpi_size ); + mpi::comm().allToAll( send_gidx, recv_gidx ); mpi::comm().allToAll( send_part, recv_part ); for ( int p = 0; p < mpi_size; ++p ) { const auto& recv_gidx_p = recv_gidx[p]; const auto& recv_part_p = recv_part[p]; - for ( int j = 0; j < recv_gidx_p.size(); ++j ) { - idx_t iedge = global_to_local[recv_gidx_p[j]]; - int prev = edge_part( iedge ); + for ( size_t j = 0; j < recv_gidx_p.size(); ++j ) { + idx_t iedge = global_to_local[recv_gidx_p[j]]; + // int prev = edge_part( iedge ); edge_part( iedge ) = recv_part_p[j]; // if( edge_part(iedge) != prev ) // Log::error() << EDGE(iedge) << " part " << prev << " --> " << @@ -471,16 +579,59 @@ Field& build_edges_partition( Mesh& mesh ) { } } + std::vector> recv_bdry_gidx( mpi_size ); + std::vector> recv_bdry_elem_part( mpi_size ); + std::vector> recv_bdry_elem_gidx( mpi_size ); + mpi::comm().allToAll( send_bdry_gidx, recv_bdry_gidx ); + mpi::comm().allToAll( send_bdry_elem_part, recv_bdry_elem_part ); + mpi::comm().allToAll( send_bdry_elem_gidx, recv_bdry_elem_gidx ); + for ( int p = 0; p < mpi_size; ++p ) { + const auto& recv_bdry_gidx_p = recv_bdry_gidx[p]; + const auto& recv_bdry_elem_part_p = recv_bdry_elem_part[p]; + const auto& recv_bdry_elem_gidx_p = recv_bdry_elem_gidx[p]; + for ( size_t j = 0; j < recv_bdry_gidx_p.size(); ++j ) { + idx_t iedge = global_to_local[recv_bdry_gidx_p[j]]; + idx_t e1 = ( edge_to_elem( iedge, 0 ) != edge_to_elem.missing_value() ? edge_to_elem( iedge, 0 ) + : edge_to_elem( iedge, 1 ) ); + if ( elem_gidx( e1 ) != recv_bdry_elem_gidx_p[j] ) { + idx_t ip1 = edge_nodes( iedge, 0 ); + idx_t ip2 = edge_nodes( iedge, 1 ); + int pn1 = node_part( ip1 ); + int pn2 = node_part( ip2 ); + int y1 = util::microdeg( xy( ip1, YY ) ); + int y2 = util::microdeg( xy( ip2, YY ) ); + int ped; + if ( y1 == y2 ) { + int x1 = util::microdeg( xy( ip1, XX ) ); + int x2 = util::microdeg( xy( ip2, XX ) ); + ped = ( x1 < x2 ) ? pn1 : pn2; + } + else { + ped = ( y1 > y2 ) ? pn1 : pn2; + } + int pe1 = elem_part( e1 ); + int pe2 = recv_bdry_elem_part_p[j]; + if ( ped != pe1 && ped != pe2 ) { + ped = ( ped == pn1 ) ? pn2 : pn1; + if ( ped != pe1 && p != pe2 ) { + std::stringstream msg; + msg << "[" << eckit::mpi::comm().rank() << "] " << EDGE( iedge ) + << " has nodes and elements of different rank: elem1[p" << pe1 << "] elem2[p" << pe2 << "]"; + throw_Exception( msg.str(), Here() ); + } + } + edge_part( iedge ) = ped; + } + } + } + // Sanity check - std::shared_ptr> is_pole_edge; + auto edge_flags = array::make_view( edges.flags() ); + auto is_pole_edge = [&]( idx_t e ) { return Topology::check( edge_flags( e ), Topology::POLE ); }; bool has_pole_edges = false; - if ( edges.has_field( "is_pole_edge" ) ) { - has_pole_edges = true; - is_pole_edge = std::shared_ptr>( - new array::ArrayView( array::make_view( edges.field( "is_pole_edge" ) ) ) ); - } + mesh.edges().metadata().get( "pole_edges", has_pole_edges ); int insane = 0; - for ( size_t jedge = 0; jedge < nb_edges; ++jedge ) { + for ( idx_t jedge = 0; jedge < nb_edges; ++jedge ) { idx_t ip1 = edge_nodes( jedge, 0 ); idx_t ip2 = edge_nodes( jedge, 1 ); idx_t elem1 = edge_to_elem( jedge, 0 ); @@ -488,7 +639,7 @@ Field& build_edges_partition( Mesh& mesh ) { int p = edge_part( jedge ); int pn1 = node_part( ip1 ); int pn2 = node_part( ip2 ); - if ( has_pole_edges && ( *is_pole_edge )( jedge ) ) { + if ( has_pole_edges && is_pole_edge( jedge ) ) { if ( p != pn1 || p != pn2 ) { Log::error() << "pole edge " << EDGE( jedge ) << " [p" << p << "] is not correct" << std::endl; insane = 1; @@ -505,13 +656,17 @@ Field& build_edges_partition( Mesh& mesh ) { bool edge_partition_is_same_as_one_of_nodes = ( p == pn1 || p == pn2 ); if ( edge_is_partition_boundary ) { if ( not edge_partition_is_same_as_one_of_nodes ) { + gidx_t edge_gidx = compute_uid( jedge ); + if ( elem1 != edge_to_elem.missing_value() ) { - Log::error() << "[" << mypart << "] " << EDGE( jedge ) << " [p" << p << "] is not correct elem1[p" - << elem_part( elem1 ) << "]" << std::endl; + Log::error() << "[" << mypart << "] " << EDGE( jedge ) << " " << edge_gidx << " [p" << p + << "] at partition_boundary is not correct. elem1[p" << elem_part( elem1 ) << "]" + << std::endl; } else { - Log::error() << "[" << mypart << "] " << EDGE( jedge ) << " [p" << p << "] is not correct elem2[p" - << elem_part( elem2 ) << "]" << std::endl; + Log::error() << "[" << mypart << "] " << EDGE( jedge ) << " " << edge_gidx << " [p" << p + << "] at partition_boundary is not correct elem2[p" << elem_part( elem2 ) << "]" + << std::endl; } insane = 1; } @@ -528,7 +683,7 @@ Field& build_edges_partition( Mesh& mesh ) { } } mpi::comm().allReduceInPlace( insane, eckit::mpi::max() ); - if ( insane && eckit::mpi::comm().rank() == 0 ) throw eckit::Exception( "Sanity check failed", Here() ); + if ( insane && eckit::mpi::comm().rank() == 0 ) throw_Exception( "Sanity check failed", Here() ); //#ifdef DEBUGGING_PARFIELDS // if( OWNED_EDGE(jedge) ) @@ -550,30 +705,27 @@ Field& build_edges_remote_idx( Mesh& mesh ) { const mesh::Nodes& nodes = mesh.nodes(); UniqueLonLat compute_uid( mesh ); - size_t mypart = mpi::comm().rank(); - size_t nparts = mpi::comm().size(); + idx_t mypart = mpi::comm().rank(); + idx_t nparts = mpi::comm().size(); mesh::HybridElements& edges = mesh.edges(); - array::IndexView edge_ridx = array::make_indexview( edges.remote_index() ); + auto edge_ridx = array::make_indexview( edges.remote_index() ); const array::ArrayView edge_part = array::make_view( edges.partition() ); const mesh::HybridElements::Connectivity& edge_nodes = edges.node_connectivity(); array::ArrayView xy = array::make_view( nodes.xy() ); - array::ArrayView flags = array::make_view( nodes.field( "flags" ) ); + array::ArrayView flags = array::make_view( nodes.flags() ); #ifdef DEBUGGING_PARFIELDS array::ArrayView node_gidx = array::make_view( nodes.global_index() ); array::ArrayView node_part = array::make_view( nodes.partition() ); #endif - std::shared_ptr> is_pole_edge; + auto edge_flags = array::make_view( edges.flags() ); + auto is_pole_edge = [&]( idx_t e ) { return Topology::check( edge_flags( e ), Topology::POLE ); }; bool has_pole_edges = false; - if ( edges.has_field( "is_pole_edge" ) ) { - has_pole_edges = true; - is_pole_edge = std::shared_ptr>( - new array::ArrayView( array::make_view( edges.field( "is_pole_edge" ) ) ) ); - } + mesh.edges().metadata().get( "pole_edges", has_pole_edges ); const int nb_edges = edges.size(); @@ -590,7 +742,7 @@ Field& build_edges_remote_idx( Mesh& mesh ) { int ip2 = edge_nodes( jedge, 1 ); centroid[XX] = 0.5 * ( xy( ip1, XX ) + xy( ip2, XX ) ); centroid[YY] = 0.5 * ( xy( ip1, YY ) + xy( ip2, YY ) ); - if ( has_pole_edges && ( *is_pole_edge )( jedge ) ) { centroid[YY] = centroid[YY] > 0 ? 90. : -90.; } + if ( has_pole_edges && is_pole_edge( jedge ) ) { centroid[YY] = centroid[YY] > 0 ? 90. : -90.; } bool needed( false ); @@ -612,13 +764,13 @@ Field& build_edges_remote_idx( Mesh& mesh ) { } uid_t uid = util::unique_lonlat( centroid ); - if ( size_t( edge_part( jedge ) ) == mypart && !needed ) // All interior edges fall here + if ( idx_t( edge_part( jedge ) ) == mypart && !needed ) // All interior edges fall here { lookup[uid] = jedge; edge_ridx( jedge ) = jedge; #ifdef DEBUGGING_PARFIELDS - if ( FIND_EDGE( jedge ) ) { DEBUG( "Found " << EDGE( jedge ) ); } + if ( FIND_EDGE( jedge ) ) { ATLAS_DEBUG( "Found " << EDGE( jedge ) ); } #endif } else // All ghost edges PLUS the periodic edges identified edges above @@ -636,7 +788,7 @@ Field& build_edges_remote_idx( Mesh& mesh ) { } } - int varsize = 2; + idx_t varsize = 2; #ifdef DEBUGGING_PARFIELDS varsize = 6; #endif @@ -647,12 +799,12 @@ Field& build_edges_remote_idx( Mesh& mesh ) { std::vector> recv_found( mpi::comm().size() ); std::map::iterator found; - for ( size_t jpart = 0; jpart < nparts; ++jpart ) { + for ( idx_t jpart = 0; jpart < nparts; ++jpart ) { const std::vector& recv_edge = recv_needed[jpart]; - const size_t nb_recv_edges = recv_edge.size() / varsize; + const idx_t nb_recv_edges = idx_t( recv_edge.size() ) / varsize; // array::ArrayView recv_edge( recv_needed[ jpart ].data(), // array::make_shape(recv_needed[ jpart ].size()/varsize,varsize) ); - for ( size_t jedge = 0; jedge < nb_recv_edges; ++jedge ) { + for ( idx_t jedge = 0; jedge < nb_recv_edges; ++jedge ) { uid_t recv_uid = recv_edge[jedge * varsize + 0]; int recv_idx = recv_edge[jedge * varsize + 1]; found = lookup.find( recv_uid ); @@ -672,7 +824,7 @@ Field& build_edges_remote_idx( Mesh& mesh ) { msg << " that should be owned by " << mpi::comm().rank() << " is not found. This could be because no " "halo was built."; - // throw eckit::SeriousBug(msg.str(),Here()); + // throw_Exception(msg.str(),Here()); Log::warning() << msg.str() << " @ " << Here() << std::endl; } } @@ -680,12 +832,12 @@ Field& build_edges_remote_idx( Mesh& mesh ) { ATLAS_TRACE_MPI( ALLTOALL ) { mpi::comm().allToAll( send_found, recv_found ); } - for ( size_t jpart = 0; jpart < nparts; ++jpart ) { + for ( idx_t jpart = 0; jpart < nparts; ++jpart ) { const std::vector& recv_edge = recv_found[jpart]; - const size_t nb_recv_edges = recv_edge.size() / 2; + const idx_t nb_recv_edges = recv_edge.size() / 2; // array::ArrayView recv_edge( recv_found[ jpart ].data(), // array::make_shape(recv_found[ jpart ].size()/2,2) ); - for ( size_t jedge = 0; jedge < nb_recv_edges; ++jedge ) { + for ( idx_t jedge = 0; jedge < nb_recv_edges; ++jedge ) { edge_ridx( recv_edge[jedge * 2 + 0] ) = recv_edge[jedge * 2 + 1]; } } @@ -697,8 +849,8 @@ Field& build_edges_global_idx( Mesh& mesh ) { UniqueLonLat compute_uid( mesh ); - int nparts = mpi::comm().size(); - size_t root = 0; + int nparts = mpi::comm().size(); + idx_t root = 0; mesh::HybridElements& edges = mesh.edges(); @@ -707,13 +859,10 @@ Field& build_edges_global_idx( Mesh& mesh ) { const mesh::HybridElements::Connectivity& edge_nodes = edges.node_connectivity(); array::ArrayView xy = array::make_view( mesh.nodes().xy() ); - std::shared_ptr> is_pole_edge; + auto edge_flags = array::make_view( edges.flags() ); + auto is_pole_edge = [&]( idx_t e ) { return Topology::check( edge_flags( e ), Topology::POLE ); }; bool has_pole_edges = false; - if ( edges.has_field( "is_pole_edge" ) ) { - has_pole_edges = true; - is_pole_edge = std::shared_ptr>( - new array::ArrayView( array::make_view( edges.field( "is_pole_edge" ) ) ) ); - } + mesh.edges().metadata().get( "pole_edges", has_pole_edges ); /* * Sorting following edge_gidx will define global order of @@ -727,7 +876,7 @@ Field& build_edges_global_idx( Mesh& mesh ) { if ( edge_gidx( jedge ) <= 0 ) { centroid[XX] = 0.5 * ( xy( edge_nodes( jedge, 0 ), XX ) + xy( edge_nodes( jedge, 1 ), XX ) ); centroid[YY] = 0.5 * ( xy( edge_nodes( jedge, 0 ), YY ) + xy( edge_nodes( jedge, 1 ), YY ) ); - if ( has_pole_edges && ( *is_pole_edge )( jedge ) ) { centroid[YY] = centroid[YY] > 0 ? 90. : -90.; } + if ( has_pole_edges && is_pole_edge( jedge ) ) { centroid[YY] = centroid[YY] > 0 ? 90. : -90.; } edge_gidx( jedge ) = util::unique_lonlat( centroid ); } } @@ -767,7 +916,7 @@ Field& build_edges_global_idx( Mesh& mesh ) { // 2) Sort all global indices, and renumber from 1 to glb_nb_edges std::vector edge_sort; edge_sort.reserve( glb_nb_edges ); - for ( size_t jedge = 0; jedge < glb_edge_id.shape( 0 ); ++jedge ) { + for ( idx_t jedge = 0; jedge < glb_edge_id.shape( 0 ); ++jedge ) { edge_sort.emplace_back( Node( glb_edge_id( jedge ), jedge ) ); } std::sort( edge_sort.begin(), edge_sort.end() ); @@ -800,18 +949,24 @@ Field& build_edges_global_idx( Mesh& mesh ) { // C wrapper interfaces to C++ routines void atlas__build_parallel_fields( Mesh::Implementation* mesh ) { - ATLAS_ERROR_HANDLING( Mesh m( mesh ); build_parallel_fields( m ); ); + ATLAS_ASSERT( mesh != nullptr, "Cannot access uninitialised atlas_Mesh" ); + Mesh m( mesh ); + build_parallel_fields( m ); } void atlas__build_nodes_parallel_fields( mesh::Nodes* nodes ) { - ATLAS_ERROR_HANDLING( build_nodes_parallel_fields( *nodes ) ); + ATLAS_ASSERT( nodes != nullptr, "Cannot access uninitialised atlas_mesh_Nodes" ); + build_nodes_parallel_fields( *nodes ); } void atlas__build_edges_parallel_fields( Mesh::Implementation* mesh ) { - ATLAS_ERROR_HANDLING( Mesh m( mesh ); build_edges_parallel_fields( m ); ); + ATLAS_ASSERT( mesh != nullptr, "Cannot access uninitialised atlas_Mesh" ); + Mesh m( mesh ); + build_edges_parallel_fields( m ); } void atlas__renumber_nodes_glb_idx( mesh::Nodes* nodes ) { - ATLAS_ERROR_HANDLING( renumber_nodes_glb_idx( *nodes ) ); + ATLAS_ASSERT( nodes != nullptr, "Cannot access uninitialised atlas_mesh_Nodes" ); + renumber_nodes_glb_idx( *nodes ); } //---------------------------------------------------------------------------------------------------------------------- diff --git a/src/atlas/mesh/actions/BuildPeriodicBoundaries.cc b/src/atlas/mesh/actions/BuildPeriodicBoundaries.cc index 90ac6811a..1594e8b68 100644 --- a/src/atlas/mesh/actions/BuildPeriodicBoundaries.cc +++ b/src/atlas/mesh/actions/BuildPeriodicBoundaries.cc @@ -17,16 +17,16 @@ #include "atlas/mesh/Mesh.h" #include "atlas/mesh/Nodes.h" #include "atlas/mesh/actions/BuildPeriodicBoundaries.h" -#include "atlas/mesh/detail/PeriodicTransform.h" #include "atlas/parallel/mpi/Statistics.h" #include "atlas/parallel/mpi/mpi.h" -#include "atlas/runtime/ErrorHandling.h" +#include "atlas/runtime/Exception.h" #include "atlas/util/CoordinateEnums.h" #include "atlas/util/LonLatMicroDeg.h" +#include "atlas/util/PeriodicTransform.h" using Topology = atlas::mesh::Nodes::Topology; -using atlas::mesh::detail::PeriodicTransform; using atlas::util::LonLatMicroDeg; +using atlas::util::PeriodicTransform; namespace atlas { namespace mesh { @@ -35,21 +35,24 @@ namespace actions { typedef gidx_t uid_t; void build_periodic_boundaries( Mesh& mesh ) { + ATLAS_TRACE(); bool periodic = false; mesh.metadata().get( "periodic", periodic ); - if ( !periodic ) { - int mypart = mpi::comm().rank(); + auto mpi_size = static_cast( mpi::comm().size() ); + auto mypart = static_cast( mpi::comm().rank() ); + + if ( !periodic ) { mesh::Nodes& nodes = mesh.nodes(); - array::ArrayView flags = array::make_view( nodes.field( "flags" ) ); - array::IndexView ridx = array::make_indexview( nodes.remote_index() ); - array::ArrayView part = array::make_view( nodes.partition() ); - array::ArrayView ghost = array::make_view( nodes.ghost() ); + auto flags = array::make_view( nodes.flags() ); + auto ridx = array::make_indexview( nodes.remote_index() ); + auto part = array::make_view( nodes.partition() ); + auto ghost = array::make_view( nodes.ghost() ); int nb_nodes = nodes.size(); - array::ArrayView xy = array::make_view( nodes.xy() ); + auto xy = array::make_view( nodes.xy() ); // Identify my master and slave nodes on own partition // master nodes are at x=0, slave nodes are at x=2pi @@ -60,7 +63,7 @@ void build_periodic_boundaries( Mesh& mesh ) { std::vector slave_nodes; slave_nodes.reserve( 3 * nb_nodes ); - for ( size_t jnode = 0; jnode < nodes.size(); ++jnode ) { + for ( idx_t jnode = 0; jnode < nodes.size(); ++jnode ) { if ( Topology::check_all( flags( jnode ), Topology::BC | Topology::WEST ) ) { Topology::set( flags( jnode ), Topology::PERIODIC ); if ( part( jnode ) == mypart ) { @@ -84,20 +87,20 @@ void build_periodic_boundaries( Mesh& mesh ) { } } - std::vector> found_master( mpi::comm().size() ); - std::vector> send_slave_idx( mpi::comm().size() ); + std::vector> found_master( mpi_size ); + std::vector> send_slave_idx( mpi_size ); // Find masters on other tasks to send to me { int sendcnt = slave_nodes.size(); - std::vector recvcounts( mpi::comm().size() ); + std::vector recvcounts( mpi_size ); ATLAS_TRACE_MPI( ALLGATHER ) { mpi::comm().allGather( sendcnt, recvcounts.begin(), recvcounts.end() ); } - std::vector recvdispls( mpi::comm().size() ); + std::vector recvdispls( mpi_size ); recvdispls[0] = 0; int recvcnt = recvcounts[0]; - for ( size_t jproc = 1; jproc < mpi::comm().size(); ++jproc ) { + for ( idx_t jproc = 1; jproc < mpi_size; ++jproc ) { recvdispls[jproc] = recvdispls[jproc - 1] + recvcounts[jproc - 1]; recvcnt += recvcounts[jproc]; } @@ -109,12 +112,12 @@ void build_periodic_boundaries( Mesh& mesh ) { } PeriodicTransform transform; - for ( size_t jproc = 0; jproc < mpi::comm().size(); ++jproc ) { + for ( idx_t jproc = 0; jproc < mpi_size; ++jproc ) { found_master.reserve( master_nodes.size() ); send_slave_idx.reserve( master_nodes.size() ); array::LocalView recv_slave( recvbuf.data() + recvdispls[jproc], array::make_shape( recvcounts[jproc] / 3, 3 ) ); - for ( size_t jnode = 0; jnode < recv_slave.shape( 0 ); ++jnode ) { + for ( idx_t jnode = 0; jnode < recv_slave.shape( 0 ); ++jnode ) { LonLatMicroDeg slave( recv_slave( jnode, LON ), recv_slave( jnode, LAT ) ); transform( slave, -1 ); uid_t slave_uid = slave.unique(); @@ -129,11 +132,11 @@ void build_periodic_boundaries( Mesh& mesh ) { } // Fill in data to communicate - std::vector> recv_slave_idx( mpi::comm().size() ); - std::vector> send_master_part( mpi::comm().size() ); - std::vector> recv_master_part( mpi::comm().size() ); - std::vector> send_master_ridx( mpi::comm().size() ); - std::vector> recv_master_ridx( mpi::comm().size() ); + std::vector> recv_slave_idx( mpi_size ); + std::vector> send_master_part( mpi_size ); + std::vector> recv_master_part( mpi_size ); + std::vector> send_master_ridx( mpi_size ); + std::vector> recv_master_ridx( mpi_size ); // std::vector< std::vector > send_slave_part( mpi::comm().size() ); // std::vector< std::vector > recv_slave_part( mpi::comm().size() ); @@ -141,11 +144,11 @@ void build_periodic_boundaries( Mesh& mesh ) { // std::vector< std::vector > recv_slave_ridx( mpi::comm().size() ); { - for ( size_t jproc = 0; jproc < mpi::comm().size(); ++jproc ) { - int nb_found_master = found_master[jproc].size(); + for ( idx_t jproc = 0; jproc < mpi_size; ++jproc ) { + idx_t nb_found_master = static_cast( found_master[jproc].size() ); send_master_part[jproc].resize( nb_found_master ); send_master_ridx[jproc].resize( nb_found_master ); - for ( int jnode = 0; jnode < nb_found_master; ++jnode ) { + for ( idx_t jnode = 0; jnode < nb_found_master; ++jnode ) { int loc_idx = found_master[jproc][jnode]; send_master_part[jproc][jnode] = part( loc_idx ); send_master_ridx[jproc][jnode] = loc_idx; @@ -176,10 +179,10 @@ void build_periodic_boundaries( Mesh& mesh ) { // Fill in periodic // unused // int nb_recv_master = 0; - for ( size_t jproc = 0; jproc < mpi::comm().size(); ++jproc ) { - size_t nb_recv = recv_slave_idx[jproc].size(); - for ( size_t jnode = 0; jnode < nb_recv; ++jnode ) { - int slave_idx = recv_slave_idx[jproc][jnode]; + for ( idx_t jproc = 0; jproc < mpi_size; ++jproc ) { + idx_t nb_recv = static_cast( recv_slave_idx[jproc].size() ); + for ( idx_t jnode = 0; jnode < nb_recv; ++jnode ) { + idx_t slave_idx = recv_slave_idx[jproc][jnode]; part( slave_idx ) = recv_master_part[jproc][jnode]; ridx( slave_idx ) = recv_master_ridx[jproc][jnode]; } @@ -192,7 +195,9 @@ void build_periodic_boundaries( Mesh& mesh ) { // C wrapper interfaces to C++ routines void atlas__build_periodic_boundaries( Mesh::Implementation* mesh ) { - ATLAS_ERROR_HANDLING( Mesh m( mesh ); build_periodic_boundaries( m ); ); + ATLAS_ASSERT( mesh != nullptr, "Cannot access uninitialised atlas_Mesh" ); + Mesh m( mesh ); + build_periodic_boundaries( m ); } // ------------------------------------------------------------------ diff --git a/src/atlas/mesh/actions/BuildStatistics.cc b/src/atlas/mesh/actions/BuildStatistics.cc index 02e45ef32..bf3a87955 100644 --- a/src/atlas/mesh/actions/BuildStatistics.cc +++ b/src/atlas/mesh/actions/BuildStatistics.cc @@ -10,6 +10,8 @@ #include #include +#include +#include #include #include #include @@ -28,7 +30,7 @@ #include "atlas/mesh/Nodes.h" #include "atlas/mesh/actions/BuildDualMesh.h" #include "atlas/parallel/Checksum.h" -#include "atlas/runtime/ErrorHandling.h" +#include "atlas/runtime/Exception.h" #include "atlas/util/Constants.h" #include "atlas/util/CoordinateEnums.h" #include "atlas/util/Earth.h" @@ -152,17 +154,17 @@ void build_statistics( Mesh& mesh ) { array::ArrayView eta = array::make_view( mesh.cells().add( Field( "stats_eta", array::make_datatype(), array::make_shape( mesh.cells().size() ) ) ) ); - for ( size_t jtype = 0; jtype < mesh.cells().nb_types(); ++jtype ) { + for ( idx_t jtype = 0; jtype < mesh.cells().nb_types(); ++jtype ) { const mesh::Elements& elements = mesh.cells().elements( jtype ); const BlockConnectivity& elem_nodes = elements.node_connectivity(); - const size_t nb_elems = elements.size(); + const idx_t nb_elems = elements.size(); if ( elements.element_type().name() == "Triangle" ) { - for ( size_t jelem = 0; jelem < nb_elems; ++jelem ) { - size_t ielem = elements.begin() + jelem; - size_t ip1 = elem_nodes( jelem, 0 ); - size_t ip2 = elem_nodes( jelem, 1 ); - size_t ip3 = elem_nodes( jelem, 2 ); + for ( idx_t jelem = 0; jelem < nb_elems; ++jelem ) { + idx_t ielem = elements.begin() + jelem; + idx_t ip1 = elem_nodes( jelem, 0 ); + idx_t ip2 = elem_nodes( jelem, 1 ); + idx_t ip3 = elem_nodes( jelem, 2 ); PointLonLat p1( lonlat( ip1, LON ), lonlat( ip1, LAT ) ); PointLonLat p2( lonlat( ip2, LON ), lonlat( ip2, LAT ) ); PointLonLat p3( lonlat( ip3, LON ), lonlat( ip3, LAT ) ); @@ -175,12 +177,12 @@ void build_statistics( Mesh& mesh ) { } } if ( elements.element_type().name() == "Quadrilateral" ) { - for ( size_t jelem = 0; jelem < nb_elems; ++jelem ) { - size_t ielem = elements.begin() + jelem; - size_t ip1 = elem_nodes( jelem, 0 ); - size_t ip2 = elem_nodes( jelem, 1 ); - size_t ip3 = elem_nodes( jelem, 2 ); - size_t ip4 = elem_nodes( jelem, 3 ); + for ( idx_t jelem = 0; jelem < nb_elems; ++jelem ) { + idx_t ielem = elements.begin() + jelem; + idx_t ip1 = elem_nodes( jelem, 0 ); + idx_t ip2 = elem_nodes( jelem, 1 ); + idx_t ip3 = elem_nodes( jelem, 2 ); + idx_t ip4 = elem_nodes( jelem, 3 ); PointLonLat p1( lonlat( ip1, LON ), lonlat( ip1, LAT ) ); PointLonLat p2( lonlat( ip2, LON ), lonlat( ip2, LAT ) ); @@ -211,7 +213,7 @@ void build_statistics( Mesh& mesh ) { array::ArrayView dual_delta_sph = array::make_view( nodes.add( Field( "dual_delta_sph", array::make_datatype(), array::make_shape( nodes.size(), 1 ) ) ) ); - for ( size_t jnode = 0; jnode < nodes.size(); ++jnode ) { + for ( idx_t jnode = 0; jnode < nodes.size(); ++jnode ) { const double lat = util::Constants::degreesToRadians() * lonlat( jnode, LAT ); const double hx = util::Constants::degreesToRadians() * util::Earth::radius() * std::cos( lat ); const double hy = util::Constants::degreesToRadians() * util::Earth::radius(); @@ -219,7 +221,7 @@ void build_statistics( Mesh& mesh ) { } if ( mpi::comm().size() == 1 ) { - for ( size_t jnode = 0; jnode < nodes.size(); ++jnode ) { + for ( idx_t jnode = 0; jnode < nodes.size(); ++jnode ) { ofs << std::setw( idt ) << dual_delta_sph( jnode ) << "\n"; } } @@ -231,7 +233,9 @@ void build_statistics( Mesh& mesh ) { // C wrapper interfaces to C++ routines void atlas__build_statistics( Mesh::Implementation* mesh ) { - ATLAS_ERROR_HANDLING( Mesh m( mesh ); build_statistics( m ); ); + ATLAS_ASSERT( mesh != nullptr, "Cannot access uninitialised atlas_Mesh" ); + Mesh m( mesh ); + build_statistics( m ); } // ------------------------------------------------------------------ diff --git a/src/atlas/mesh/actions/BuildTorusXYZField.cc b/src/atlas/mesh/actions/BuildTorusXYZField.cc index 3c2a042a7..9cdbe9333 100644 --- a/src/atlas/mesh/actions/BuildTorusXYZField.cc +++ b/src/atlas/mesh/actions/BuildTorusXYZField.cc @@ -17,6 +17,7 @@ #include "atlas/mesh/Mesh.h" #include "atlas/mesh/Nodes.h" #include "atlas/mesh/actions/BuildTorusXYZField.h" +#include "atlas/runtime/Exception.h" namespace atlas { namespace mesh { @@ -26,24 +27,24 @@ namespace actions { BuildTorusXYZField::BuildTorusXYZField( const std::string& name ) : name_( name ) {} -Field& BuildTorusXYZField::operator()( Mesh& mesh, const Domain& dom, double r0, double r1, int nx, int ny ) const { +Field& BuildTorusXYZField::operator()( Mesh& mesh, const Domain& dom, double r0, double r1, idx_t nx, idx_t ny ) const { return operator()( mesh.nodes(), dom, r0, r1, nx, ny ); } -Field& BuildTorusXYZField::operator()( mesh::Nodes& nodes, const Domain& dom, double r0, double r1, int nx, - int ny ) const { +Field& BuildTorusXYZField::operator()( mesh::Nodes& nodes, const Domain& dom, double r0, double r1, idx_t nx, + idx_t ny ) const { // fill xyz with torus coordinates. r0 and r1 are large and small radii, // respectively. auto domain = RectangularDomain( dom ); - ASSERT( domain ); + ATLAS_ASSERT( domain ); const double xmin = domain.xmin(); const double xmax = domain.xmax(); const double ymin = domain.ymin(); const double ymax = domain.ymax(); if ( !nodes.has_field( name_ ) ) { - const size_t npts = nodes.size(); + const idx_t npts = nodes.size(); const array::ArrayView lonlat = array::make_view( nodes.xy() ); array::ArrayView xyz = array::make_view( nodes.add( Field( name_, array::make_datatype(), array::make_shape( npts, 3 ) ) ) ); @@ -51,7 +52,7 @@ Field& BuildTorusXYZField::operator()( mesh::Nodes& nodes, const Domain& dom, do const double pi = M_PI; const double c1 = 2. * pi / double( nx ) * ( nx - 1 ) / ( xmax - xmin ); const double c2 = 2. * pi / double( ny ) * ( ny - 1 ) / ( ymax - ymin ); - for ( size_t n = 0; n < npts; ++n ) { + for ( idx_t n = 0; n < npts; ++n ) { double lon = -pi + c1 * ( lonlat( n, 0 ) - xmin ); double lat = -pi + c2 * ( lonlat( n, 1 ) - ymin ); diff --git a/src/atlas/mesh/actions/BuildTorusXYZField.h b/src/atlas/mesh/actions/BuildTorusXYZField.h index 93f34e9a8..2b5903583 100644 --- a/src/atlas/mesh/actions/BuildTorusXYZField.h +++ b/src/atlas/mesh/actions/BuildTorusXYZField.h @@ -14,6 +14,7 @@ #include "atlas/domain/Domain.h" #include "atlas/domain/detail/RectangularDomain.h" +#include "atlas/library/config.h" namespace atlas { class Field; @@ -37,8 +38,8 @@ class BuildTorusXYZField { public: explicit BuildTorusXYZField( const std::string& name = "xyz" ); - Field& operator()( Mesh&, const atlas::Domain&, double r0, double r1, int nx, int ny ) const; - Field& operator()( mesh::Nodes&, const atlas::Domain&, double r0, double r1, int nx, int ny ) const; + Field& operator()( Mesh&, const atlas::Domain&, double r0, double r1, idx_t nx, idx_t ny ) const; + Field& operator()( mesh::Nodes&, const atlas::Domain&, double r0, double r1, idx_t nx, idx_t ny ) const; private: std::string name_; diff --git a/src/atlas/mesh/actions/BuildXYZField.cc b/src/atlas/mesh/actions/BuildXYZField.cc index 30a71553b..4c5831b88 100644 --- a/src/atlas/mesh/actions/BuildXYZField.cc +++ b/src/atlas/mesh/actions/BuildXYZField.cc @@ -14,6 +14,7 @@ #include "atlas/field/Field.h" #include "atlas/mesh/Mesh.h" #include "atlas/mesh/Nodes.h" +#include "atlas/runtime/Trace.h" #include "atlas/util/Earth.h" #include "atlas/util/Point.h" @@ -38,11 +39,12 @@ Field& BuildXYZField::operator()( mesh::Nodes& nodes ) const { recompute = true; } if ( recompute ) { + ATLAS_TRACE( "BuildXYZField" ); array::ArrayView lonlat = array::make_view( nodes.lonlat() ); array::ArrayView xyz = array::make_view( nodes.field( name_ ) ); PointXYZ p2; - for ( size_t n = 0; n < nodes.size(); ++n ) { + for ( idx_t n = 0; n < nodes.size(); ++n ) { const PointLonLat p1( lonlat( n, 0 ), lonlat( n, 1 ) ); util::Earth::convertSphericalToCartesian( p1, p2 ); xyz( n, 0 ) = p2.x(); diff --git a/src/atlas/mesh/actions/ExtendNodesGlobal.cc b/src/atlas/mesh/actions/ExtendNodesGlobal.cc index 0d5d596de..eeb556825 100644 --- a/src/atlas/mesh/actions/ExtendNodesGlobal.cc +++ b/src/atlas/mesh/actions/ExtendNodesGlobal.cc @@ -10,13 +10,15 @@ #include "atlas/mesh/actions/ExtendNodesGlobal.h" +#include "atlas/array.h" #include "atlas/field/Field.h" #include "atlas/grid/Grid.h" +#include "atlas/grid/Iterator.h" #include "atlas/mesh/Mesh.h" #include "atlas/mesh/Nodes.h" +#include "atlas/runtime/Exception.h" #include "atlas/util/CoordinateEnums.h" #include "atlas/util/Earth.h" -#include "eckit/exception/Exceptions.h" namespace atlas { namespace mesh { @@ -42,27 +44,27 @@ void ExtendNodesGlobal::operator()( const Grid& grid, Mesh& mesh ) const { mesh::Nodes& nodes = mesh.nodes(); - const size_t nb_real_pts = nodes.size(); - const size_t nb_extension_pts = extended_pts.size(); + const idx_t nb_real_pts = nodes.size(); + const idx_t nb_extension_pts = extended_pts.size(); - size_t new_size = nodes.size() + extended_pts.size(); + idx_t new_size = nodes.size() + extended_pts.size(); nodes.resize( new_size ); // resizes the fields - const size_t nb_total_pts = nodes.size(); + const idx_t nb_total_pts = nodes.size(); - ASSERT( nb_total_pts == nb_real_pts + nb_extension_pts ); + ATLAS_ASSERT( nb_total_pts == nb_real_pts + nb_extension_pts ); - nodes.metadata().set( "NbRealPts", nb_real_pts ); - nodes.metadata().set( "NbVirtualPts", nb_extension_pts ); + nodes.metadata().set( "NbRealPts", nb_real_pts ); + nodes.metadata().set( "NbVirtualPts", nb_extension_pts ); array::ArrayView xyz = array::make_view( nodes.field( "xyz" ) ); array::ArrayView xy = array::make_view( nodes.xy() ); array::ArrayView lonlat = array::make_view( nodes.lonlat() ); array::ArrayView gidx = array::make_view( nodes.global_index() ); - for ( size_t i = 0; i < nb_extension_pts; ++i ) { - const size_t n = nb_real_pts + i; + for ( idx_t i = 0; i < nb_extension_pts; ++i ) { + const idx_t n = nb_real_pts + i; const PointLonLat pLL = grid.projection().lonlat( extended_pts[i] ); PointXYZ pXYZ; diff --git a/src/atlas/mesh/actions/WriteLoadBalanceReport.cc b/src/atlas/mesh/actions/WriteLoadBalanceReport.cc index d20f477ce..838d0f7e7 100644 --- a/src/atlas/mesh/actions/WriteLoadBalanceReport.cc +++ b/src/atlas/mesh/actions/WriteLoadBalanceReport.cc @@ -10,6 +10,7 @@ #include #include +#include #include "eckit/filesystem/PathName.h" @@ -19,7 +20,7 @@ #include "atlas/mesh/Nodes.h" #include "atlas/mesh/actions/WriteLoadBalanceReport.h" #include "atlas/parallel/mpi/mpi.h" -#include "atlas/runtime/ErrorHandling.h" +#include "atlas/runtime/Exception.h" using atlas::mesh::IsGhostNode; @@ -40,26 +41,26 @@ void write_load_balance_report( const Mesh& mesh, const std::string& filename ) } void write_load_balance_report( const Mesh& mesh, std::ostream& ofs ) { - size_t npart = mpi::comm().size(); - size_t root = 0; + idx_t npart = mpi::comm().size(); + idx_t root = 0; - std::vector nb_total_nodes( npart, 0 ); - std::vector nb_owned_nodes( npart, 0 ); - std::vector nb_ghost_nodes( npart, 0 ); + std::vector nb_total_nodes( npart, 0 ); + std::vector nb_owned_nodes( npart, 0 ); + std::vector nb_ghost_nodes( npart, 0 ); std::vector ghost_ratio_nodes( npart, 0 ); - std::vector nb_total_edges( npart, 0 ); - std::vector nb_owned_edges( npart, 0 ); - std::vector nb_ghost_edges( npart, 0 ); + std::vector nb_total_edges( npart, 0 ); + std::vector nb_owned_edges( npart, 0 ); + std::vector nb_ghost_edges( npart, 0 ); std::vector nb_ghost_ratio_edges( npart, 0 ); { const mesh::Nodes& nodes = mesh.nodes(); IsGhostNode is_ghost( nodes ); - size_t nb_nodes = nodes.size(); - int nowned( 0 ); - int nghost( 0 ); - for ( size_t n = 0; n < nb_nodes; ++n ) { + idx_t nb_nodes = nodes.size(); + idx_t nowned( 0 ); + idx_t nghost( 0 ); + for ( idx_t n = 0; n < nb_nodes; ++n ) { if ( is_ghost( n ) ) ++nghost; else @@ -75,7 +76,7 @@ void write_load_balance_report( const Mesh& mesh, std::ostream& ofs ) { mpi::comm().gather( nghost, nb_ghost_nodes, root ); } - for ( size_t p = 0; p < npart; ++p ) { + for ( idx_t p = 0; p < npart; ++p ) { if ( nb_owned_nodes[p] ) { ghost_ratio_nodes[p] = static_cast( nb_ghost_nodes[p] ) / static_cast( nb_owned_nodes[p] ); @@ -92,10 +93,10 @@ void write_load_balance_report( const Mesh& mesh, std::ostream& ofs ) { const mesh::Nodes& nodes = mesh.nodes(); IsGhostNode is_ghost( nodes ); const mesh::HybridElements::Connectivity& edge_nodes = mesh.edges().node_connectivity(); - size_t nb_edges = mesh.edges().size(); - int nowned( 0 ); - int nghost( 0 ); - for ( size_t j = 0; j < nb_edges; ++j ) { + idx_t nb_edges = mesh.edges().size(); + idx_t nowned( 0 ); + idx_t nghost( 0 ); + for ( idx_t j = 0; j < nb_edges; ++j ) { if ( is_ghost( edge_nodes( j, 0 ) ) ) ++nghost; else @@ -188,7 +189,7 @@ void write_load_balance_report( const Mesh& mesh, std::ostream& ofs ) { ofs << std::setw( idt ) << "gedges"; } ofs << "\n"; - for ( size_t jpart = 0; jpart < npart; ++jpart ) { + for ( idx_t jpart = 0; jpart < npart; ++jpart ) { ofs << std::setw( 6 ) << jpart; ofs << std::setw( idt ) << nb_total_nodes[jpart]; ofs << std::setw( idt ) << nb_owned_nodes[jpart]; @@ -208,7 +209,9 @@ void write_load_balance_report( const Mesh& mesh, std::ostream& ofs ) { // C wrapper interfaces to C++ routines void atlas__write_load_balance_report( Mesh::Implementation* mesh, char* filename ) { - ATLAS_ERROR_HANDLING( Mesh m( mesh ); write_load_balance_report( m, std::string( filename ) ); ); + ATLAS_ASSERT( mesh != nullptr, "Cannot access uninitialised atlas_Mesh" ); + Mesh m( mesh ); + write_load_balance_report( m, std::string( filename ) ); } // ------------------------------------------------------------------ diff --git a/src/atlas/mesh/detail/AccumulateFacets.cc b/src/atlas/mesh/detail/AccumulateFacets.cc index 5262377ca..6ad19c8c6 100644 --- a/src/atlas/mesh/detail/AccumulateFacets.cc +++ b/src/atlas/mesh/detail/AccumulateFacets.cc @@ -8,12 +8,11 @@ * nor does it submit to any jurisdiction. */ -#include "eckit/exception/Exceptions.h" - +#include "atlas/mesh/detail/AccumulateFacets.h" #include "atlas/mesh/Elements.h" #include "atlas/mesh/HybridElements.h" #include "atlas/mesh/Nodes.h" -#include "atlas/mesh/detail/AccumulateFacets.h" +#include "atlas/runtime/Exception.h" #include "atlas/runtime/Trace.h" namespace atlas { @@ -22,33 +21,33 @@ namespace detail { void accumulate_facets( const mesh::HybridElements& cells, const mesh::Nodes& nodes, std::vector& facet_nodes_data, // shape(nb_facets,nb_nodes_per_facet) - std::vector& connectivity_facet_to_elem, size_t& nb_facets, size_t& nb_inner_facets, + std::vector& connectivity_facet_to_elem, idx_t& nb_facets, idx_t& nb_inner_facets, idx_t& missing_value ) { ATLAS_TRACE(); missing_value = -1; std::vector> node_to_facet( nodes.size() ); - for ( size_t j = 0; j < node_to_facet.size(); ++j ) { - node_to_facet[j].reserve( 6 ); + for ( auto& facet : node_to_facet ) { + facet.reserve( 6 ); } nb_facets = 0; nb_inner_facets = 0; if ( connectivity_facet_to_elem.size() == 0 ) { connectivity_facet_to_elem.reserve( 6 * cells.size() ); } if ( facet_nodes_data.size() == 0 ) { facet_nodes_data.reserve( 6 * cells.size() ); } - for ( size_t t = 0; t < cells.nb_types(); ++t ) { + for ( idx_t t = 0; t < cells.nb_types(); ++t ) { const mesh::Elements& elements = cells.elements( t ); const mesh::BlockConnectivity& elem_nodes = elements.node_connectivity(); auto elem_flags = elements.view( elements.flags() ); - auto patch = [&elem_flags]( size_t e ) { + auto patch = [&elem_flags]( idx_t e ) { using Topology = atlas::mesh::Nodes::Topology; return Topology::check( elem_flags( e ), Topology::PATCH ); }; - size_t nb_elems = elements.size(); - size_t nb_nodes_in_facet = 2; + idx_t nb_elems = elements.size(); + idx_t nb_nodes_in_facet = 2; std::vector> facet_node_numbering; - size_t nb_facets_in_elem; + idx_t nb_facets_in_elem; if ( elements.name() == "Quadrilateral" ) { nb_facets_in_elem = 4; facet_node_numbering.resize( nb_facets_in_elem, std::vector( nb_nodes_in_facet ) ); @@ -72,30 +71,131 @@ void accumulate_facets( const mesh::HybridElements& cells, const mesh::Nodes& no facet_node_numbering[2][1] = 0; } else { - throw eckit::BadParameter( elements.name() + " is not \"Quadrilateral\" or \"Triangle\"", Here() ); + throw_Exception( elements.name() + " is not \"Quadrilateral\" or \"Triangle\"", Here() ); } std::vector facet_nodes( nb_nodes_in_facet ); - for ( size_t e = 0; e < nb_elems; ++e ) { + for ( idx_t e = 0; e < nb_elems; ++e ) { if ( patch( e ) ) continue; - for ( size_t f = 0; f < nb_facets_in_elem; ++f ) { + for ( idx_t f = 0; f < nb_facets_in_elem; ++f ) { bool found_face = false; - for ( size_t jnode = 0; jnode < nb_nodes_in_facet; ++jnode ) { + for ( idx_t jnode = 0; jnode < nb_nodes_in_facet; ++jnode ) { + facet_nodes[jnode] = elem_nodes( e, facet_node_numbering[f][jnode] ); + } + + idx_t node = facet_nodes[0]; + for ( const idx_t face : node_to_facet[node] ) { + idx_t nb_matched_nodes = 0; + if ( nb_nodes_in_facet > 1 ) // 2D or 3D + { + for ( idx_t jnode = 0; jnode < nb_nodes_in_facet; ++jnode ) { + idx_t other_node = facet_nodes[jnode]; + for ( const idx_t other_face : node_to_facet[other_node] ) { + if ( other_face == face ) { + ++nb_matched_nodes; + break; + } + } + } + if ( nb_matched_nodes == nb_nodes_in_facet ) { + connectivity_facet_to_elem[2 * face + 1] = e + elements.begin(); + ++nb_inner_facets; + found_face = true; + break; + } + } + } + + if ( found_face == false ) { + connectivity_facet_to_elem.emplace_back( elements.begin() + e ); + // if 2nd element stays missing_value, it is a bdry face + connectivity_facet_to_elem.emplace_back( missing_value ); + for ( idx_t n = 0; n < nb_nodes_in_facet; ++n ) { + node_to_facet[facet_nodes[n]].emplace_back( nb_facets ); + facet_nodes_data.emplace_back( facet_nodes[n] ); + } + ++nb_facets; + } + } + } + } +} + +void accumulate_facets_in_range( std::vector& range, const mesh::HybridElements& cells, + const mesh::Nodes& /*nodes*/, + std::vector& facet_nodes_data, // shape(nb_facets,nb_nodes_per_facet) + std::vector& connectivity_facet_to_elem, idx_t& nb_facets, + idx_t& nb_inner_facets, idx_t& missing_value, + std::vector>& node_to_facet ) { + ATLAS_TRACE(); + if ( connectivity_facet_to_elem.size() == 0 ) { connectivity_facet_to_elem.reserve( 6 * cells.size() ); } + if ( facet_nodes_data.size() == 0 ) { facet_nodes_data.reserve( 6 * cells.size() ); } + for ( idx_t t = 0; t < cells.nb_types(); ++t ) { + const mesh::Elements& elements = cells.elements( t ); + const mesh::BlockConnectivity& elem_nodes = elements.node_connectivity(); + auto elem_flags = elements.view( elements.flags() ); + + auto patch = [&elem_flags]( idx_t e ) { + using Topology = atlas::mesh::Nodes::Topology; + return Topology::check( elem_flags( e ), Topology::PATCH ); + }; + + idx_t nb_nodes_in_facet = 2; + + std::vector> facet_node_numbering; + idx_t nb_facets_in_elem; + if ( elements.name() == "Quadrilateral" ) { + nb_facets_in_elem = 4; + facet_node_numbering.resize( nb_facets_in_elem, std::vector( nb_nodes_in_facet ) ); + facet_node_numbering[0][0] = 0; + facet_node_numbering[0][1] = 1; + facet_node_numbering[1][0] = 1; + facet_node_numbering[1][1] = 2; + facet_node_numbering[2][0] = 2; + facet_node_numbering[2][1] = 3; + facet_node_numbering[3][0] = 3; + facet_node_numbering[3][1] = 0; + } + else if ( elements.name() == "Triangle" ) { + nb_facets_in_elem = 3; + facet_node_numbering.resize( nb_facets_in_elem, std::vector( nb_nodes_in_facet ) ); + facet_node_numbering[0][0] = 0; + facet_node_numbering[0][1] = 1; + facet_node_numbering[1][0] = 1; + facet_node_numbering[1][1] = 2; + facet_node_numbering[2][0] = 2; + facet_node_numbering[2][1] = 0; + } + else { + throw_Exception( elements.name() + " is not \"Quadrilateral\" or \"Triangle\"", Here() ); + } + + std::vector facet_nodes( nb_nodes_in_facet ); + + const idx_t e_start = range[t].start(); + const idx_t e_end = range[t].end(); + + for ( idx_t e = e_start; e < e_end; ++e ) { + if ( patch( e ) ) continue; + + for ( idx_t f = 0; f < nb_facets_in_elem; ++f ) { + bool found_face = false; + + for ( idx_t jnode = 0; jnode < nb_nodes_in_facet; ++jnode ) { facet_nodes[jnode] = elem_nodes( e, facet_node_numbering[f][jnode] ); } int node = facet_nodes[0]; - for ( size_t jface = 0; jface < node_to_facet[node].size(); ++jface ) { - int face = node_to_facet[node][jface]; - size_t nb_matched_nodes = 0; + for ( idx_t face : node_to_facet[node] ) { + idx_t nb_matched_nodes = 0; if ( nb_nodes_in_facet > 1 ) // 2D or 3D { - for ( size_t jnode = 0; jnode < nb_nodes_in_facet; ++jnode ) { - size_t other_node = facet_nodes[jnode]; - for ( size_t iface = 0; iface < node_to_facet[other_node].size(); ++iface ) { - if ( node_to_facet[facet_nodes[jnode]][iface] == face ) { + for ( idx_t jnode = 0; jnode < nb_nodes_in_facet; ++jnode ) { + idx_t other_node = facet_nodes[jnode]; + for ( idx_t other_face : node_to_facet[other_node] ) { + if ( other_face == face ) { ++nb_matched_nodes; break; } @@ -114,7 +214,7 @@ void accumulate_facets( const mesh::HybridElements& cells, const mesh::Nodes& no connectivity_facet_to_elem.emplace_back( elements.begin() + e ); // if 2nd element stays missing_value, it is a bdry face connectivity_facet_to_elem.emplace_back( missing_value ); - for ( size_t n = 0; n < nb_nodes_in_facet; ++n ) { + for ( idx_t n = 0; n < nb_nodes_in_facet; ++n ) { node_to_facet[facet_nodes[n]].emplace_back( nb_facets ); facet_nodes_data.emplace_back( facet_nodes[n] ); } @@ -125,6 +225,58 @@ void accumulate_facets( const mesh::HybridElements& cells, const mesh::Nodes& no } } +void accumulate_facets_ordered_by_halo( const mesh::HybridElements& cells, const mesh::Nodes& nodes, + std::vector& facet_nodes_data, // shape(nb_facets,nb_nodes_per_facet) + std::vector& connectivity_facet_to_elem, idx_t& nb_facets, + idx_t& nb_inner_facets, idx_t& missing_value, + std::vector& halo_offsets ) { + ATLAS_TRACE(); + + static int MAXHALO = 50; + std::vector> ranges( MAXHALO, std::vector( cells.nb_types() ) ); + + int maxhalo{0}; + for ( idx_t t = 0; t < cells.nb_types(); ++t ) { + const mesh::Elements& elements = cells.elements( t ); + auto elem_halo = elements.view( elements.halo() ); + idx_t nb_elems = elements.size(); + + int halo{0}; + int begin{0}; + int end{0}; + for ( idx_t e = 0; e < nb_elems; ++e ) { + ATLAS_ASSERT( elem_halo( e ) >= halo ); + if ( elem_halo( e ) > halo ) { + end = e; + ranges[halo][t] = array::Range{begin, end}; + begin = end; + ++halo; + } + } + end = nb_elems; + ranges[halo][t] = array::Range{begin, end}; + maxhalo = std::max( halo, maxhalo ); + } + + + missing_value = -1; + std::vector> node_to_facet( nodes.size() ); + for ( auto& facets : node_to_facet ) { + facets.reserve( 6 ); + } + nb_facets = 0; + nb_inner_facets = 0; + + + halo_offsets = std::vector{0}; + for ( int h = 0; h <= maxhalo; ++h ) { + accumulate_facets_in_range( ranges[h], cells, nodes, facet_nodes_data, connectivity_facet_to_elem, nb_facets, + nb_inner_facets, missing_value, node_to_facet ); + halo_offsets.emplace_back( nb_facets ); + } +} + + } // namespace detail } // namespace mesh } // namespace atlas diff --git a/src/atlas/mesh/detail/AccumulateFacets.h b/src/atlas/mesh/detail/AccumulateFacets.h index ebbfa2fbd..e5b40b43e 100644 --- a/src/atlas/mesh/detail/AccumulateFacets.h +++ b/src/atlas/mesh/detail/AccumulateFacets.h @@ -32,9 +32,16 @@ namespace detail { // currently only supports 2D meshes. Little work needed for 3D. void accumulate_facets( const mesh::HybridElements& cells, const mesh::Nodes& nodes, std::vector& facet_nodes_data, // shape(nb_facets,nb_nodes_per_facet) - std::vector& connectivity_facet_to_elem, size_t& nb_facets, size_t& nb_inner_facets, + std::vector& connectivity_facet_to_elem, idx_t& nb_facets, idx_t& nb_inner_facets, idx_t& missing_value ); +// currently only supports 2D meshes. Little work needed for 3D. +void accumulate_facets_ordered_by_halo( const mesh::HybridElements& cells, const mesh::Nodes& nodes, + std::vector& facet_nodes_data, // shape(nb_facets,nb_nodes_per_facet) + std::vector& connectivity_facet_to_elem, idx_t& nb_facets, + idx_t& nb_inner_facets, idx_t& missing_value, + std::vector& halo_offsets ); + } // namespace detail } // namespace mesh } // namespace atlas diff --git a/src/atlas/mesh/detail/MeshImpl.cc b/src/atlas/mesh/detail/MeshImpl.cc index 30c6696ce..85813234d 100644 --- a/src/atlas/mesh/detail/MeshImpl.cc +++ b/src/atlas/mesh/detail/MeshImpl.cc @@ -10,7 +10,6 @@ #include -#include "eckit/exception/Exceptions.h" #include "eckit/types/FloatCompare.h" #include "atlas/grid/Grid.h" @@ -20,6 +19,7 @@ #include "atlas/mesh/Nodes.h" #include "atlas/mesh/detail/MeshImpl.h" #include "atlas/parallel/mpi/mpi.h" +#include "atlas/runtime/Exception.h" using atlas::Grid; using atlas::Projection; @@ -30,16 +30,15 @@ namespace detail { //---------------------------------------------------------------------------------------------------------------------- -MeshImpl::MeshImpl( eckit::Stream& s ) { - NOTIMP; +MeshImpl::MeshImpl( eckit::Stream& ) { + ATLAS_NOTIMPLEMENTED; } -void MeshImpl::encode( eckit::Stream& s ) const { - NOTIMP; +void MeshImpl::encode( eckit::Stream& ) const { + ATLAS_NOTIMPLEMENTED; } -MeshImpl::MeshImpl() : dimensionality_( 2 ) { - nodes_.reset( new mesh::Nodes() ); +MeshImpl::MeshImpl() : nodes_( new mesh::Nodes() ), dimensionality_( 2 ) { createElements(); } @@ -49,7 +48,7 @@ MeshImpl::~MeshImpl() { } } -void MeshImpl::print( std::ostream& os ) const {} +void MeshImpl::print( std::ostream& ) const {} size_t MeshImpl::footprint() const { size_t size = sizeof( *this ); @@ -78,9 +77,9 @@ void MeshImpl::createElements() { else if ( dimensionality_ == 3 ) edges_ = ridges_; else - throw eckit::Exception( "Invalid Mesh dimensionality", Here() ); + throw_Exception( "Invalid Mesh dimensionality", Here() ); - ASSERT( edges_.owners() == 2 ); + ATLAS_ASSERT( edges_.owners() == 2 ); } bool MeshImpl::generated() const { @@ -96,11 +95,11 @@ void MeshImpl::setGrid( const Grid& grid ) { if ( not projection_ ) projection_ = grid_->projection(); } -size_t MeshImpl::nb_partitions() const { +idx_t MeshImpl::nb_partitions() const { return mpi::comm().size(); } -size_t MeshImpl::partition() const { +idx_t MeshImpl::partition() const { return mpi::comm().rank(); } @@ -137,13 +136,13 @@ PartitionGraph::Neighbours MeshImpl::nearestNeighbourPartitions() const { return partitionGraph().nearestNeighbours( partition() ); } -const PartitionPolygon& MeshImpl::polygon( size_t halo ) const { - if ( halo >= polygons_.size() ) { polygons_.resize( halo + 1 ); } +const PartitionPolygon& MeshImpl::polygon( idx_t halo ) const { + if ( halo >= static_cast( polygons_.size() ) ) { polygons_.resize( halo + 1 ); } if ( not polygons_[halo] ) { int mesh_halo = 0; metadata().get( "halo", mesh_halo ); if ( halo > mesh_halo ) { - throw eckit::Exception( "Mesh does not contain a halo of size " + std::to_string( halo ) + ".", Here() ); + throw_Exception( "Mesh does not contain a halo of size " + std::to_string( halo ) + ".", Here() ); } polygons_[halo].reset( new PartitionPolygon( *this, halo ) ); diff --git a/src/atlas/mesh/detail/MeshImpl.h b/src/atlas/mesh/detail/MeshImpl.h index b395a145c..f4dd3468c 100644 --- a/src/atlas/mesh/detail/MeshImpl.h +++ b/src/atlas/mesh/detail/MeshImpl.h @@ -11,17 +11,21 @@ #pragma once #include - -#include "eckit/memory/Owned.h" -#include "eckit/memory/SharedPtr.h" +#include #include "atlas/mesh/PartitionPolygon.h" #include "atlas/mesh/detail/PartitionGraph.h" #include "atlas/projection/Projection.h" #include "atlas/util/Metadata.h" +#include "atlas/util/Object.h" +#include "atlas/util/ObjectHandle.h" //---------------------------------------------------------------------------------------------------------------------- +namespace eckit { +class Stream; +} + namespace atlas { class Grid; class Mesh; @@ -44,7 +48,7 @@ namespace detail { class MeshObserver; -class MeshImpl : public eckit::Owned { +class MeshImpl : public util::Object { public: // methods /// @brief Construct a empty MeshImpl explicit MeshImpl(); @@ -87,8 +91,8 @@ class MeshImpl : public eckit::Owned { /// @brief Return the memory footprint of the mesh size_t footprint() const; - size_t partition() const; - size_t nb_partitions() const; + idx_t partition() const; + idx_t nb_partitions() const; void cloneToDevice() const; @@ -102,7 +106,7 @@ class MeshImpl : public eckit::Owned { PartitionGraph::Neighbours nearestNeighbourPartitions() const; - const PartitionPolygon& polygon( size_t halo = 0 ) const; + const PartitionPolygon& polygon( idx_t halo = 0 ) const; const Grid& grid() const { return *grid_; } @@ -125,25 +129,25 @@ class MeshImpl : public eckit::Owned { private: // members util::Metadata metadata_; - eckit::SharedPtr nodes_; + util::ObjectHandle nodes_; // dimensionality : 2D | 3D // -------- - eckit::SharedPtr cells_; // 2D | 3D - eckit::SharedPtr facets_; // 1D | 2D - eckit::SharedPtr ridges_; // 0D | 1D - eckit::SharedPtr peaks_; // NA | 0D + util::ObjectHandle cells_; // 2D | 3D + util::ObjectHandle facets_; // 1D | 2D + util::ObjectHandle ridges_; // 0D | 1D + util::ObjectHandle peaks_; // NA | 0D - eckit::SharedPtr edges_; // alias to facets of 2D mesh, ridges of 3D mesh + util::ObjectHandle edges_; // alias to facets of 2D mesh, ridges of 3D mesh - size_t dimensionality_; + idx_t dimensionality_; Projection projection_; std::unique_ptr grid_; - mutable eckit::SharedPtr partition_graph_; + mutable util::ObjectHandle partition_graph_; - mutable std::vector> polygons_; + mutable std::vector> polygons_; mutable std::vector mesh_observers_; }; diff --git a/src/atlas/mesh/detail/MeshIntf.cc b/src/atlas/mesh/detail/MeshIntf.cc index abc47fac8..b6b978aee 100644 --- a/src/atlas/mesh/detail/MeshIntf.cc +++ b/src/atlas/mesh/detail/MeshIntf.cc @@ -10,7 +10,7 @@ #include "atlas/mesh/detail/MeshIntf.h" #include "atlas/mesh/Nodes.h" -#include "atlas/runtime/ErrorHandling.h" +#include "atlas/runtime/Exception.h" namespace atlas { namespace mesh { @@ -23,39 +23,42 @@ Mesh::Implementation* atlas__Mesh__new() { } void atlas__Mesh__delete( Mesh::Implementation* This ) { + ATLAS_ASSERT( This != nullptr, "Cannot access uninitialisd atlas_Mesh" ); delete This; } Nodes* atlas__Mesh__nodes( Mesh::Implementation* This ) { - ATLAS_ERROR_HANDLING( ASSERT( This ); return &This->nodes(); ); - return nullptr; + ATLAS_ASSERT( This != nullptr, "Cannot access uninitialisd atlas_Mesh" ); + return &This->nodes(); } Edges* atlas__Mesh__edges( Mesh::Implementation* This ) { - ATLAS_ERROR_HANDLING( ASSERT( This ); return &This->edges(); ); - return nullptr; + ATLAS_ASSERT( This != nullptr, "Cannot access uninitialisd atlas_Mesh" ); + return &This->edges(); } Cells* atlas__Mesh__cells( Mesh::Implementation* This ) { - ATLAS_ERROR_HANDLING( ASSERT( This ); return &This->cells(); ); - return nullptr; + ATLAS_ASSERT( This != nullptr, "Cannot access uninitialisd atlas_Mesh" ); + return &This->cells(); } size_t atlas__Mesh__footprint( Mesh::Implementation* This ) { - size_t size( 0 ); - ATLAS_ERROR_HANDLING( ASSERT( This ); size = This->footprint(); ); - return size; + ATLAS_ASSERT( This != nullptr, "Cannot access uninitialisd atlas_Mesh" ); + return This->footprint(); } void atlas__Mesh__clone_to_device( Mesh::Implementation* This ) { + ATLAS_ASSERT( This != nullptr, "Cannot access uninitialisd atlas_Mesh" ); This->cloneToDevice(); } void atlas__Mesh__clone_from_device( Mesh::Implementation* This ) { + ATLAS_ASSERT( This != nullptr, "Cannot access uninitialisd atlas_Mesh" ); This->cloneFromDevice(); } void atlas__Mesh__sync_host_device( Mesh::Implementation* This ) { + ATLAS_ASSERT( This != nullptr, "Cannot access uninitialisd atlas_Mesh" ); This->syncHostDevice(); } diff --git a/src/atlas/mesh/detail/PartitionGraph.cc b/src/atlas/mesh/detail/PartitionGraph.cc index 8a098e943..0eb027663 100644 --- a/src/atlas/mesh/detail/PartitionGraph.cc +++ b/src/atlas/mesh/detail/PartitionGraph.cc @@ -10,7 +10,6 @@ #include -#include "eckit/exception/Exceptions.h" #include "eckit/log/Bytes.h" #include "eckit/types/FloatCompare.h" @@ -44,23 +43,23 @@ PartitionGraph* build_partition_graph( const MeshImpl& mesh ) { polygon.push_back( xy( node, XX ) ); polygon.push_back( xy( node, YY ) ); } - ASSERT( polygon.size() >= 4 ); + ATLAS_ASSERT( polygon.size() >= 4 ); eckit::mpi::Buffer recv_polygons( mpi_size ); comm.allGatherv( polygon.begin(), polygon.end(), recv_polygons ); using PolygonXY = std::vector; std::vector polygons( mpi_size ); - for ( size_t p = 0; p < mpi_size; ++p ) { - for ( size_t j = 0; j < recv_polygons.counts[p] / 2; ++j ) { + for ( idx_t p = 0; p < mpi_size; ++p ) { + for ( idx_t j = 0; j < recv_polygons.counts[p] / 2; ++j ) { PointXY pxy( *( recv_polygons.begin() + recv_polygons.displs[p] + 2 * j + XX ), *( recv_polygons.begin() + recv_polygons.displs[p] + 2 * j + YY ) ); polygons[p].push_back( pxy ); } } - std::map> uid_2_parts; - size_t jpart = 0; + std::map> uid_2_parts; + idx_t jpart = 0; for ( const PolygonXY& _polygon : polygons ) { for ( const PointXY& pxy : _polygon ) { PointLonLat pll = pxy; @@ -71,28 +70,28 @@ PartitionGraph* build_partition_graph( const MeshImpl& mesh ) { } ++jpart; } - std::vector> graph( mpi_size ); + std::vector> graph( mpi_size ); for ( const auto& u2p : uid_2_parts ) { - const std::set& parts = u2p.second; - for ( size_t jpart : parts ) { - for ( size_t ipart : parts ) { + const std::set& parts = u2p.second; + for ( idx_t jpart : parts ) { + for ( idx_t ipart : parts ) { if ( jpart != ipart ) { graph[jpart].insert( ipart ); } } } } - std::vector counts( mpi_size ); - std::vector displs( mpi_size ); - size_t values_size = 0; - for ( size_t jpart = 0; jpart < mpi_size; ++jpart ) { + std::vector counts( mpi_size ); + std::vector displs( mpi_size ); + idx_t values_size = 0; + for ( idx_t jpart = 0; jpart < mpi_size; ++jpart ) { counts[jpart] = graph[jpart].size(); displs[jpart] = values_size; values_size += counts[jpart]; } - std::vector values; + std::vector values; values.reserve( values_size ); - for ( const std::set& graph_node : graph ) { - for ( size_t v : graph_node ) { + for ( const std::set& graph_node : graph ) { + for ( idx_t v : graph_node ) { values.push_back( v ); } } @@ -102,37 +101,37 @@ PartitionGraph* build_partition_graph( const MeshImpl& mesh ) { size_t PartitionGraph::footprint() const { size_t size = sizeof( *this ); - size += sizeof( size_t ) * displs_.capacity(); - size += sizeof( size_t ) * counts_.capacity(); - size += sizeof( size_t ) * values_.capacity(); + size += sizeof( idx_t ) * displs_.capacity(); + size += sizeof( idx_t ) * counts_.capacity(); + size += sizeof( idx_t ) * values_.capacity(); return size; } -size_t PartitionGraph::size() const { +idx_t PartitionGraph::size() const { return displs_.size(); } -PartitionGraph::Neighbours PartitionGraph::nearestNeighbours( const size_t partition ) const { +PartitionGraph::Neighbours PartitionGraph::nearestNeighbours( const idx_t partition ) const { return Neighbours( values_.data() + displs_[partition], values_.data() + displs_[partition] + counts_[partition] ); } PartitionGraph::PartitionGraph() {} -PartitionGraph::PartitionGraph( size_t values[], size_t rows, size_t displs[], size_t counts[] ) { +PartitionGraph::PartitionGraph( idx_t values[], idx_t rows, idx_t displs[], idx_t counts[] ) { displs_.assign( displs, displs + rows ); counts_.assign( counts, counts + rows ); values_.assign( values, values + displs[rows - 1] + counts[rows - 1] ); - for ( size_t jpart = 0; jpart < rows; ++jpart ) { - for ( size_t neighbour : nearestNeighbours( jpart ) ) { + for ( idx_t jpart = 0; jpart < rows; ++jpart ) { + for ( idx_t neighbour : nearestNeighbours( jpart ) ) { bool found( false ); - for ( size_t nextneighbour : nearestNeighbours( neighbour ) ) { + for ( idx_t nextneighbour : nearestNeighbours( neighbour ) ) { if ( nextneighbour == jpart ) found = true; } if ( not found ) { values_.insert( values_.begin() + displs_[neighbour] + counts_[neighbour], jpart ); counts_[neighbour]++; - for ( size_t j = neighbour + 1; j < rows; ++j ) { + for ( idx_t j = neighbour + 1; j < rows; ++j ) { displs_[j]++; } } @@ -140,25 +139,25 @@ PartitionGraph::PartitionGraph( size_t values[], size_t rows, size_t displs[], s } maximum_nearest_neighbours_ = 0; - for ( size_t n : counts_ ) { + for ( idx_t n : counts_ ) { maximum_nearest_neighbours_ = std::max( n, maximum_nearest_neighbours_ ); } } -size_t PartitionGraph::maximumNearestNeighbours() const { +idx_t PartitionGraph::maximumNearestNeighbours() const { return maximum_nearest_neighbours_; } void PartitionGraph::print( std::ostream& os ) const { - for ( size_t jpart = 0; jpart < size(); ++jpart ) { - Log::info() << std::setw( 3 ) << jpart << " : "; - for ( size_t v : nearestNeighbours( jpart ) ) { - Log::info() << std::setw( 3 ) << v << " "; + for ( idx_t jpart = 0; jpart < size(); ++jpart ) { + os << std::setw( 3 ) << jpart << " : "; + for ( idx_t v : nearestNeighbours( jpart ) ) { + os << std::setw( 3 ) << v << " "; } - Log::info() << '\n'; + os << '\n'; } - Log::info() << "partition graph maximum neighbours = " << maximumNearestNeighbours() << '\n'; - Log::info() << "partition graph footprint = " << eckit::Bytes( footprint() ); + os << "partition graph maximum neighbours = " << maximumNearestNeighbours() << '\n'; + os << "partition graph footprint = " << eckit::Bytes( footprint() ); } PartitionGraph::operator bool() const { diff --git a/src/atlas/mesh/detail/PartitionGraph.h b/src/atlas/mesh/detail/PartitionGraph.h index 61d4122c8..697d3e017 100644 --- a/src/atlas/mesh/detail/PartitionGraph.h +++ b/src/atlas/mesh/detail/PartitionGraph.h @@ -11,9 +11,10 @@ #pragma once #include +#include -#include "eckit/memory/Owned.h" -#include "eckit/memory/SharedPtr.h" +#include "atlas/library/config.h" +#include "atlas/util/Object.h" //---------------------------------------------------------------------------------------------------------------------- @@ -25,17 +26,17 @@ class MeshImpl; //---------------------------------------------------------------------------------------------------------------------- -class PartitionGraph : public eckit::Owned { +class PartitionGraph : public util::Object { public: - using Neighbours = std::vector; + using Neighbours = std::vector; public: PartitionGraph(); - PartitionGraph( size_t values[], size_t rows, size_t displs[], size_t counts[] ); + PartitionGraph( idx_t values[], idx_t rows, idx_t displs[], idx_t counts[] ); size_t footprint() const; - size_t size() const; - Neighbours nearestNeighbours( const size_t partition ) const; - size_t maximumNearestNeighbours() const; + idx_t size() const; + Neighbours nearestNeighbours( const idx_t partition ) const; + idx_t maximumNearestNeighbours() const; operator bool() const; private: @@ -43,10 +44,10 @@ class PartitionGraph : public eckit::Owned { friend std::ostream& operator<<( std::ostream& s, const PartitionGraph& p ); private: - std::vector counts_; - std::vector displs_; - std::vector values_; - size_t maximum_nearest_neighbours_; + std::vector counts_; + std::vector displs_; + std::vector values_; + idx_t maximum_nearest_neighbours_; }; PartitionGraph* build_partition_graph( const MeshImpl& mesh ); diff --git a/src/atlas/meshgenerator.h b/src/atlas/meshgenerator.h index d1eed4bf2..df57b2136 100644 --- a/src/atlas/meshgenerator.h +++ b/src/atlas/meshgenerator.h @@ -13,4 +13,3 @@ #pragma once #include "atlas/meshgenerator/MeshGenerator.h" -#include "atlas/meshgenerator/StructuredMeshGenerator.h" diff --git a/src/atlas/meshgenerator/MeshGenerator.cc b/src/atlas/meshgenerator/MeshGenerator.cc index 5be773322..f7f722dad 100644 --- a/src/atlas/meshgenerator/MeshGenerator.cc +++ b/src/atlas/meshgenerator/MeshGenerator.cc @@ -8,289 +8,43 @@ * nor does it submit to any jurisdiction. */ -#include -#include #include -#include "eckit/exception/Exceptions.h" -#include "eckit/thread/AutoLock.h" -#include "eckit/thread/Mutex.h" -#include "eckit/utils/Hash.h" - -#include "atlas/array/ArrayView.h" -#include "atlas/field/Field.h" +#include "atlas/grid/Distribution.h" #include "atlas/grid/Grid.h" -#include "atlas/mesh/HybridElements.h" #include "atlas/mesh/Mesh.h" -#include "atlas/meshgenerator/DelaunayMeshGenerator.h" #include "atlas/meshgenerator/MeshGenerator.h" -#include "atlas/meshgenerator/StructuredMeshGenerator.h" -#include "atlas/parallel/mpi/mpi.h" -#include "atlas/runtime/ErrorHandling.h" -#include "atlas/runtime/Log.h" + +#include "atlas/meshgenerator/detail/MeshGeneratorFactory.h" +#include "atlas/meshgenerator/detail/MeshGeneratorImpl.h" using atlas::Mesh; namespace atlas { -namespace meshgenerator { - -//---------------------------------------------------------------------------------------------------------------------- - -namespace { - -static eckit::Mutex* local_mutex = 0; -static std::map* m = 0; -static pthread_once_t once = PTHREAD_ONCE_INIT; - -static void init() { - local_mutex = new eckit::Mutex(); - m = new std::map(); -} - -template -void load_builder() { - MeshGeneratorBuilder( "tmp" ); -} - -struct force_link { - force_link() { - load_builder(); - load_builder(); - } -}; - -} // namespace - -//---------------------------------------------------------------------------------------------------------------------- - -MeshGeneratorImpl::MeshGeneratorImpl() {} - -MeshGeneratorImpl::~MeshGeneratorImpl() {} - -Mesh MeshGeneratorImpl::operator()( const Grid& grid ) const { - Mesh mesh; - generate( grid, mesh ); - return mesh; -} - -Mesh MeshGeneratorImpl::operator()( const Grid& grid, const grid::Distribution& distribution ) const { - Mesh mesh; - generate( grid, distribution, mesh ); - return mesh; -} - -Mesh MeshGeneratorImpl::generate( const Grid& grid ) const { - Mesh mesh; - generate( grid, mesh ); - return mesh; -} - -Mesh MeshGeneratorImpl::generate( const Grid& grid, const grid::Distribution& distribution ) const { - Mesh mesh; - generate( grid, distribution, mesh ); - return mesh; -} - -//---------------------------------------------------------------------------------------------------------------------- - -void MeshGeneratorImpl::generateGlobalElementNumbering( Mesh& mesh ) const { - size_t loc_nb_elems = mesh.cells().size(); - std::vector elem_counts( mpi::comm().size() ); - std::vector elem_displs( mpi::comm().size() ); - - ATLAS_TRACE_MPI( ALLGATHER ) { mpi::comm().allGather( loc_nb_elems, elem_counts.begin(), elem_counts.end() ); } - - elem_displs.at( 0 ) = 0; - for ( size_t jpart = 1; jpart < mpi::comm().size(); ++jpart ) { - elem_displs.at( jpart ) = elem_displs.at( jpart - 1 ) + elem_counts.at( jpart - 1 ); - } - - gidx_t gid = 1 + elem_displs.at( mpi::comm().rank() ); - - array::ArrayView glb_idx = array::make_view( mesh.cells().global_index() ); - - for ( size_t jelem = 0; jelem < mesh.cells().size(); ++jelem ) { - glb_idx( jelem ) = gid++; - } - - size_t max_glb_idx = std::accumulate( elem_counts.begin(), elem_counts.end(), size_t( 0 ) ); - - mesh.cells().global_index().metadata().set( "human_readable", true ); - mesh.cells().global_index().metadata().set( "min", 1 ); - mesh.cells().global_index().metadata().set( "max", max_glb_idx ); -} - -void MeshGeneratorImpl::setProjection( Mesh& mesh, const Projection& p ) const { - mesh.setProjection( p ); -} - -void MeshGeneratorImpl::setGrid( Mesh& mesh, const Grid& g, const grid::Distribution& d ) const { - mesh.setGrid( g ); - mesh.metadata().set( "distribution", d.type() ); -} - -//---------------------------------------------------------------------------------------------------------------------- - -MeshGeneratorFactory::MeshGeneratorFactory( const std::string& name ) : name_( name ) { - pthread_once( &once, init ); - - eckit::AutoLock lock( local_mutex ); - - ASSERT( m->find( name ) == m->end() ); - ( *m )[name] = this; -} - -MeshGeneratorFactory::~MeshGeneratorFactory() { - eckit::AutoLock lock( local_mutex ); - m->erase( name_ ); -} - -void MeshGeneratorFactory::list( std::ostream& out ) { - pthread_once( &once, init ); - - eckit::AutoLock lock( local_mutex ); - - static force_link static_linking; - - const char* sep = ""; - for ( std::map::const_iterator j = m->begin(); j != m->end(); ++j ) { - out << sep << ( *j ).first; - sep = ", "; - } -} - -const MeshGenerator::Implementation* MeshGeneratorFactory::build( const std::string& name ) { - pthread_once( &once, init ); - - eckit::AutoLock lock( local_mutex ); - - static force_link static_linking; - - std::map::const_iterator j = m->find( name ); - - Log::debug() << "Looking for MeshGeneratorFactory [" << name << "]" << std::endl; - - if ( j == m->end() ) { - Log::error() << "No MeshGeneratorFactory for [" << name << "]" << std::endl; - Log::error() << "MeshGeneratorFactories are:" << std::endl; - for ( j = m->begin(); j != m->end(); ++j ) - Log::error() << " " << ( *j ).first << std::endl; - throw eckit::SeriousBug( std::string( "No MeshGeneratorFactory called " ) + name ); - } - - return ( *j ).second->make(); -} - -const MeshGenerator::Implementation* MeshGeneratorFactory::build( const std::string& name, - const eckit::Parametrisation& param ) { - pthread_once( &once, init ); - - eckit::AutoLock lock( local_mutex ); - - static force_link static_linking; - - std::map::const_iterator j = m->find( name ); - - Log::debug() << "Looking for MeshGeneratorFactory [" << name << "]" << std::endl; - - if ( j == m->end() ) { - Log::error() << "No MeshGeneratorFactory for [" << name << "]" << std::endl; - Log::error() << "MeshGeneratorFactories are:" << std::endl; - for ( j = m->begin(); j != m->end(); ++j ) - Log::error() << " " << ( *j ).first << std::endl; - throw eckit::SeriousBug( std::string( "No MeshGeneratorFactory called " ) + name ); - } - - return ( *j ).second->make( param ); -} - -//---------------------------------------------------------------------------------------------------------------------- - -extern "C" { - -void atlas__MeshGenerator__delete( MeshGenerator::Implementation* This ) { - ATLAS_ERROR_HANDLING( ASSERT( This ); delete This; ); -} - -const MeshGenerator::Implementation* atlas__MeshGenerator__create_noconfig( const char* name ) { - const MeshGenerator::Implementation* meshgenerator( 0 ); - ATLAS_ERROR_HANDLING( { - MeshGenerator m( std::string{name} ); - meshgenerator = m.get(); - meshgenerator->attach(); - } meshgenerator->detach(); ); - return meshgenerator; -} - -const MeshGenerator::Implementation* atlas__MeshGenerator__create( const char* name, - const eckit::Parametrisation* params ) { - const MeshGenerator::Implementation* meshgenerator( 0 ); - ATLAS_ERROR_HANDLING( ASSERT( params ); { - MeshGenerator m( std::string( name ), *params ); - meshgenerator = m.get(); - meshgenerator->attach(); - } meshgenerator->detach(); ); - return meshgenerator; -} - -Mesh::Implementation* atlas__MeshGenerator__generate__grid_griddist( const MeshGenerator::Implementation* This, - const Grid::Implementation* grid, - const grid::Distribution::impl_t* distribution ) { - ATLAS_ERROR_HANDLING( Mesh::Implementation * m; { - Mesh mesh = This->generate( Grid( grid ), grid::Distribution( distribution ) ); - mesh.get()->attach(); - m = mesh.get(); - } m->detach(); - return m; ); - return nullptr; -} - -Mesh::Implementation* atlas__MeshGenerator__generate__grid( const MeshGenerator::Implementation* This, - const Grid::Implementation* grid ) { - ATLAS_ERROR_HANDLING( Mesh::Implementation * m; { - Mesh mesh = This->generate( Grid( grid ) ); - ; - mesh.get()->attach(); - m = mesh.get(); - } m->detach(); - return m; ); - return nullptr; -} -} //---------------------------------------------------------------------------------------------------------------------- -} // namespace meshgenerator - -//---------------------------------------------------------------------------------------------------------------------- - -MeshGenerator::MeshGenerator() : meshgenerator_( nullptr ) {} - -MeshGenerator::MeshGenerator( const Implementation* meshgenerator ) : meshgenerator_( meshgenerator ) {} - -MeshGenerator::MeshGenerator( const MeshGenerator& meshgenerator ) : meshgenerator_( meshgenerator.meshgenerator_ ) {} - MeshGenerator::MeshGenerator( const std::string& key, const eckit::Parametrisation& params ) : - meshgenerator_( meshgenerator::MeshGeneratorFactory::build( key, params ) ) {} + Handle( meshgenerator::MeshGeneratorFactory::build( key, params ) ) {} void MeshGenerator::hash( eckit::Hash& h ) const { - return meshgenerator_->hash( h ); + return get()->hash( h ); } Mesh MeshGenerator::generate( const Grid& g, const grid::Distribution& d ) const { - return meshgenerator_->generate( g, d ); + return get()->generate( g, d ); } Mesh MeshGenerator::generate( const Grid& g ) const { - return meshgenerator_->generate( g ); + return get()->generate( g ); } Mesh MeshGenerator::operator()( const Grid& g, const grid::Distribution& d ) const { - return meshgenerator_->operator()( g, d ); + return get()->operator()( g, d ); } Mesh MeshGenerator::operator()( const Grid& g ) const { - return meshgenerator_->operator()( g ); + return get()->operator()( g ); } //---------------------------------------------------------------------------------------------------------------------- diff --git a/src/atlas/meshgenerator/MeshGenerator.h b/src/atlas/meshgenerator/MeshGenerator.h index 25cefb207..d183065c7 100644 --- a/src/atlas/meshgenerator/MeshGenerator.h +++ b/src/atlas/meshgenerator/MeshGenerator.h @@ -10,134 +10,41 @@ #pragma once -#include #include -#include "eckit/config/Parametrisation.h" -#include "eckit/memory/Owned.h" -#include "eckit/memory/SharedPtr.h" - -#include "atlas/grid/Distribution.h" -#include "atlas/grid/Grid.h" -#include "atlas/mesh/Mesh.h" #include "atlas/util/Config.h" +#include "atlas/util/ObjectHandle.h" namespace eckit { class Hash; -} +class Parametrisation; +} // namespace eckit namespace atlas { class Mesh; -} +class Grid; +class Projection; +} // namespace atlas namespace atlas { namespace grid { class Distribution; -} +} // namespace grid } // namespace atlas namespace atlas { namespace meshgenerator { - -//---------------------------------------------------------------------------------------------------------------------- - -class MeshGeneratorImpl : public eckit::Owned { -public: - MeshGeneratorImpl(); - - virtual ~MeshGeneratorImpl(); - - virtual void hash( eckit::Hash& ) const = 0; - - virtual void generate( const Grid&, const grid::Distribution&, Mesh& ) const = 0; - virtual void generate( const Grid&, Mesh& ) const = 0; - - Mesh generate( const Grid&, const grid::Distribution& ) const; - Mesh generate( const Grid& ) const; - - Mesh operator()( const Grid&, const grid::Distribution& ) const; - Mesh operator()( const Grid& ) const; - -protected: - void generateGlobalElementNumbering( Mesh& mesh ) const; - void setProjection( Mesh&, const Projection& ) const; - void setGrid( Mesh&, const Grid&, const grid::Distribution& ) const; -}; - -//---------------------------------------------------------------------------------------------------------------------- - -class MeshGeneratorFactory { -public: - /*! - * \brief build MeshGenerator with factory key, and default options - * \return mesh generator - */ - static const MeshGeneratorImpl* build( const std::string& ); - - /*! - * \brief build MeshGenerator with factory key inside parametrisation, - * and options specified in parametrisation as well - * \return mesh generator - */ - static const MeshGeneratorImpl* build( const std::string&, const eckit::Parametrisation& ); - - /*! - * \brief list all registered mesh generators - */ - static void list( std::ostream& ); - -private: - std::string name_; - virtual const MeshGeneratorImpl* make() = 0; - virtual const MeshGeneratorImpl* make( const eckit::Parametrisation& ) = 0; - -protected: - MeshGeneratorFactory( const std::string& ); - virtual ~MeshGeneratorFactory(); -}; - -//---------------------------------------------------------------------------------------------------------------------- - -template -class MeshGeneratorBuilder : public MeshGeneratorFactory { - virtual const MeshGeneratorImpl* make() { return new T(); } - virtual const MeshGeneratorImpl* make( const eckit::Parametrisation& param ) { return new T( param ); } - -public: - MeshGeneratorBuilder( const std::string& name ) : MeshGeneratorFactory( name ) {} -}; - -//---------------------------------------------------------------------------------------------------------------------- - -extern "C" { -void atlas__MeshGenerator__delete( MeshGeneratorImpl* This ); -const MeshGeneratorImpl* atlas__MeshGenerator__create_noconfig( const char* name ); -const MeshGeneratorImpl* atlas__MeshGenerator__create( const char* name, const eckit::Parametrisation* params ); -Mesh::Implementation* atlas__MeshGenerator__generate__grid_griddist( const MeshGeneratorImpl* This, - const Grid::Implementation* grid, - const grid::Distribution::impl_t* distribution ); -Mesh::Implementation* atlas__MeshGenerator__generate__grid( const MeshGeneratorImpl* This, - const Grid::Implementation* grid ); +class MeshGeneratorImpl; } //---------------------------------------------------------------------------------------------------------------------- -} // namespace meshgenerator - -//---------------------------------------------------------------------------------------------------------------------- - -class MeshGenerator { +class MeshGenerator : public util::ObjectHandle { public: - using Implementation = meshgenerator::MeshGeneratorImpl; - typedef atlas::util::Config Parameters; - -private: - eckit::SharedPtr meshgenerator_; + using Parameters = atlas::util::Config; public: - MeshGenerator(); - MeshGenerator( const Implementation* ); - MeshGenerator( const MeshGenerator& ); + using Handle::Handle; MeshGenerator( const std::string&, const eckit::Parametrisation& = util::NoConfig() ); void hash( eckit::Hash& ) const; @@ -147,8 +54,16 @@ class MeshGenerator { Mesh operator()( const Grid&, const grid::Distribution& ) const; Mesh operator()( const Grid& ) const; +}; - const Implementation* get() const { return meshgenerator_.get(); } +//---------------------------------------------------------------------------------------------------------------------- + +// Shorthands +class StructuredMeshGenerator : public MeshGenerator { +public: + using MeshGenerator::MeshGenerator; + StructuredMeshGenerator( const eckit::Parametrisation& config = util::NoConfig() ) : + MeshGenerator( "structured", config ) {} }; //---------------------------------------------------------------------------------------------------------------------- diff --git a/src/atlas/meshgenerator/DelaunayMeshGenerator.cc b/src/atlas/meshgenerator/detail/DelaunayMeshGenerator.cc similarity index 91% rename from src/atlas/meshgenerator/DelaunayMeshGenerator.cc rename to src/atlas/meshgenerator/detail/DelaunayMeshGenerator.cc index a466a34f0..5a591c689 100644 --- a/src/atlas/meshgenerator/DelaunayMeshGenerator.cc +++ b/src/atlas/meshgenerator/detail/DelaunayMeshGenerator.cc @@ -15,13 +15,15 @@ #include "atlas/field/Field.h" #include "atlas/grid/Distribution.h" #include "atlas/grid/Grid.h" +#include "atlas/grid/Iterator.h" #include "atlas/mesh/HybridElements.h" #include "atlas/mesh/Mesh.h" #include "atlas/mesh/Nodes.h" #include "atlas/mesh/actions/BuildConvexHull3D.h" #include "atlas/mesh/actions/BuildXYZField.h" #include "atlas/mesh/actions/ExtendNodesGlobal.h" -#include "atlas/meshgenerator/DelaunayMeshGenerator.h" +#include "atlas/meshgenerator/detail/DelaunayMeshGenerator.h" +#include "atlas/meshgenerator/detail/MeshGeneratorFactory.h" #include "atlas/projection/Projection.h" #include "atlas/runtime/Log.h" #include "atlas/util/CoordinateEnums.h" @@ -35,7 +37,7 @@ namespace meshgenerator { DelaunayMeshGenerator::DelaunayMeshGenerator() {} -DelaunayMeshGenerator::DelaunayMeshGenerator( const eckit::Parametrisation& p ) {} +DelaunayMeshGenerator::DelaunayMeshGenerator( const eckit::Parametrisation& ) {} DelaunayMeshGenerator::~DelaunayMeshGenerator() {} @@ -50,7 +52,7 @@ void DelaunayMeshGenerator::generate( const Grid& grid, const grid::Distribution Log::warning() << "Delaunay triangulation does not support a GridDistribution" "with more than 1 partition" << std::endl; - NOTIMP; + ATLAS_NOTIMPLEMENTED; /// TODO: Read mesh on 1 MPI task, and distribute according to /// GridDistribution /// HINT: use atlas/actions/DistributeMesh @@ -64,7 +66,7 @@ void DelaunayMeshGenerator::generate( const Grid& g, Mesh& mesh ) const { createNodes( g, mesh ); array::ArrayView gidx = array::make_view( mesh.nodes().global_index() ); - for ( size_t jnode = 0; jnode < mesh.nodes().size(); ++jnode ) { + for ( idx_t jnode = 0; jnode < mesh.nodes().size(); ++jnode ) { gidx( jnode ) = jnode + 1; } @@ -75,12 +77,12 @@ void DelaunayMeshGenerator::generate( const Grid& g, Mesh& mesh ) const { } void DelaunayMeshGenerator::createNodes( const Grid& grid, Mesh& mesh ) const { - size_t nb_nodes = grid.size(); + idx_t nb_nodes = grid.size(); mesh.nodes().resize( nb_nodes ); array::ArrayView xy = array::make_view( mesh.nodes().xy() ); array::ArrayView lonlat = array::make_view( mesh.nodes().lonlat() ); - size_t jnode( 0 ); + idx_t jnode( 0 ); Projection projection = grid.projection(); PointLonLat Pll; for ( PointXY Pxy : grid.xy() ) { diff --git a/src/atlas/meshgenerator/DelaunayMeshGenerator.h b/src/atlas/meshgenerator/detail/DelaunayMeshGenerator.h similarity index 92% rename from src/atlas/meshgenerator/DelaunayMeshGenerator.h rename to src/atlas/meshgenerator/detail/DelaunayMeshGenerator.h index 55fc6c265..aabc04e64 100644 --- a/src/atlas/meshgenerator/DelaunayMeshGenerator.h +++ b/src/atlas/meshgenerator/detail/DelaunayMeshGenerator.h @@ -11,6 +11,7 @@ #pragma once #include "atlas/meshgenerator/MeshGenerator.h" +#include "atlas/meshgenerator/detail/MeshGeneratorImpl.h" namespace atlas { class Mesh; @@ -27,7 +28,7 @@ class DelaunayMeshGenerator : public MeshGenerator::Implementation { DelaunayMeshGenerator(); DelaunayMeshGenerator( const eckit::Parametrisation& p ); - virtual ~DelaunayMeshGenerator(); + virtual ~DelaunayMeshGenerator() override; private: // methods virtual void hash( eckit::Hash& ) const override; diff --git a/src/atlas/meshgenerator/detail/MeshGeneratorFactory.cc b/src/atlas/meshgenerator/detail/MeshGeneratorFactory.cc new file mode 100644 index 000000000..ee394b939 --- /dev/null +++ b/src/atlas/meshgenerator/detail/MeshGeneratorFactory.cc @@ -0,0 +1,49 @@ +/* + * (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 "atlas/meshgenerator/detail/DelaunayMeshGenerator.h" +#include "atlas/meshgenerator/detail/MeshGeneratorFactory.h" +#include "atlas/meshgenerator/detail/StructuredMeshGenerator.h" + +using atlas::Mesh; + +namespace atlas { +namespace meshgenerator { + +//---------------------------------------------------------------------------------------------------------------------- + +void force_link() { + static struct Link { + Link() { + MeshGeneratorBuilder(); + MeshGeneratorBuilder(); + } + } link; +} + +//---------------------------------------------------------------------------------------------------------------------- + +const MeshGenerator::Implementation* MeshGeneratorFactory::build( const std::string& builder ) { + return build( builder, util::NoConfig() ); +} + +const MeshGenerator::Implementation* MeshGeneratorFactory::build( const std::string& builder, + const eckit::Parametrisation& param ) { + force_link(); + auto factory = get( builder ); + return factory->make( param ); +} + +//---------------------------------------------------------------------------------------------------------------------- + +} // namespace meshgenerator +} // namespace atlas diff --git a/src/atlas/meshgenerator/detail/MeshGeneratorFactory.h b/src/atlas/meshgenerator/detail/MeshGeneratorFactory.h new file mode 100644 index 000000000..5dfe7fce5 --- /dev/null +++ b/src/atlas/meshgenerator/detail/MeshGeneratorFactory.h @@ -0,0 +1,49 @@ +/* + * (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 + +#include "atlas/util/Config.h" +#include "atlas/util/Factory.h" + +namespace atlas { +namespace meshgenerator { + +//---------------------------------------------------------------------------------------------------------------------- + +class MeshGeneratorImpl; +class MeshGeneratorFactory : public util::Factory { +public: + static std::string className() { return "MeshGeneratorFactory"; } + static const MeshGeneratorImpl* build( const std::string& ); + static const MeshGeneratorImpl* build( const std::string&, const eckit::Parametrisation& ); + using Factory::Factory; + +private: + virtual const MeshGeneratorImpl* make( const eckit::Parametrisation& ) = 0; +}; + +//---------------------------------------------------------------------------------------------------------------------- + +template +class MeshGeneratorBuilder : public MeshGeneratorFactory { +private: + virtual const MeshGeneratorImpl* make( const eckit::Parametrisation& param ) { return new T( param ); } + +public: + using MeshGeneratorFactory::MeshGeneratorFactory; +}; + +//---------------------------------------------------------------------------------------------------------------------- + +} // namespace meshgenerator +} // namespace atlas diff --git a/src/atlas/meshgenerator/detail/MeshGeneratorImpl.cc b/src/atlas/meshgenerator/detail/MeshGeneratorImpl.cc new file mode 100644 index 000000000..8d2a5a4f1 --- /dev/null +++ b/src/atlas/meshgenerator/detail/MeshGeneratorImpl.cc @@ -0,0 +1,106 @@ +/* + * (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 "eckit/utils/Hash.h" + +#include "atlas/array/ArrayView.h" +#include "atlas/field/Field.h" +#include "atlas/grid/Distribution.h" +#include "atlas/grid/Grid.h" +#include "atlas/mesh/HybridElements.h" +#include "atlas/mesh/Mesh.h" +#include "atlas/meshgenerator/MeshGenerator.h" +#include "atlas/meshgenerator/detail/MeshGeneratorImpl.h" +#include "atlas/parallel/mpi/mpi.h" + +using atlas::Mesh; + +namespace atlas { +namespace meshgenerator { + +//---------------------------------------------------------------------------------------------------------------------- + +MeshGeneratorImpl::MeshGeneratorImpl() {} + +MeshGeneratorImpl::~MeshGeneratorImpl() {} + +Mesh MeshGeneratorImpl::operator()( const Grid& grid ) const { + Mesh mesh; + generate( grid, mesh ); + return mesh; +} + +Mesh MeshGeneratorImpl::operator()( const Grid& grid, const grid::Distribution& distribution ) const { + Mesh mesh; + generate( grid, distribution, mesh ); + return mesh; +} + +Mesh MeshGeneratorImpl::generate( const Grid& grid ) const { + Mesh mesh; + generate( grid, mesh ); + return mesh; +} + +Mesh MeshGeneratorImpl::generate( const Grid& grid, const grid::Distribution& distribution ) const { + Mesh mesh; + generate( grid, distribution, mesh ); + return mesh; +} + +//---------------------------------------------------------------------------------------------------------------------- + +void MeshGeneratorImpl::generateGlobalElementNumbering( Mesh& mesh ) const { + idx_t mpi_size = static_cast( mpi::comm().size() ); + + gidx_t loc_nb_elems = mesh.cells().size(); + std::vector elem_counts( mpi_size ); + std::vector elem_displs( mpi_size ); + + ATLAS_TRACE_MPI( ALLGATHER ) { mpi::comm().allGather( loc_nb_elems, elem_counts.begin(), elem_counts.end() ); } + + elem_displs.at( 0 ) = 0; + for ( idx_t jpart = 1; jpart < mpi_size; ++jpart ) { + elem_displs.at( jpart ) = elem_displs.at( jpart - 1 ) + elem_counts.at( jpart - 1 ); + } + + gidx_t gid = 1 + elem_displs.at( mpi::comm().rank() ); + + array::ArrayView glb_idx = array::make_view( mesh.cells().global_index() ); + + for ( idx_t jelem = 0; jelem < mesh.cells().size(); ++jelem ) { + glb_idx( jelem ) = gid++; + } + + gidx_t max_glb_idx = std::accumulate( elem_counts.begin(), elem_counts.end(), gidx_t( 0 ) ); + + mesh.cells().global_index().metadata().set( "human_readable", true ); + mesh.cells().global_index().metadata().set( "min", 1 ); + mesh.cells().global_index().metadata().set( "max", max_glb_idx ); +} + +void MeshGeneratorImpl::setProjection( Mesh& mesh, const Projection& p ) const { + mesh.setProjection( p ); +} + +void MeshGeneratorImpl::setGrid( Mesh& mesh, const Grid& g, const grid::Distribution& d ) const { + mesh.setGrid( g ); + mesh.metadata().set( "distribution", d.type() ); +} + +//---------------------------------------------------------------------------------------------------------------------- + +} // namespace meshgenerator + +//---------------------------------------------------------------------------------------------------------------------- + +} // namespace atlas diff --git a/src/atlas/meshgenerator/detail/MeshGeneratorImpl.h b/src/atlas/meshgenerator/detail/MeshGeneratorImpl.h new file mode 100644 index 000000000..679b61c46 --- /dev/null +++ b/src/atlas/meshgenerator/detail/MeshGeneratorImpl.h @@ -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. + */ + +#pragma once + +#include "atlas/util/Object.h" + +namespace eckit { +class Hash; +class Parametrisation; +} // namespace eckit + +namespace atlas { +class Mesh; +class Grid; +class Projection; +} // namespace atlas + +namespace atlas { +namespace grid { +class Distribution; +} // namespace grid +} // namespace atlas + +namespace atlas { +namespace meshgenerator { + +//---------------------------------------------------------------------------------------------------------------------- + +class MeshGeneratorImpl : public util::Object { +public: + MeshGeneratorImpl(); + + virtual ~MeshGeneratorImpl(); + + virtual void hash( eckit::Hash& ) const = 0; + + virtual void generate( const Grid&, const grid::Distribution&, Mesh& ) const = 0; + virtual void generate( const Grid&, Mesh& ) const = 0; + + Mesh generate( const Grid&, const grid::Distribution& ) const; + Mesh generate( const Grid& ) const; + + Mesh operator()( const Grid&, const grid::Distribution& ) const; + Mesh operator()( const Grid& ) const; + +protected: + void generateGlobalElementNumbering( Mesh& mesh ) const; + void setProjection( Mesh&, const Projection& ) const; + void setGrid( Mesh&, const Grid&, const grid::Distribution& ) const; +}; + +//---------------------------------------------------------------------------------------------------------------------- + +} // namespace meshgenerator + +//---------------------------------------------------------------------------------------------------------------------- + +} // namespace atlas diff --git a/src/atlas/meshgenerator/detail/MeshGeneratorInterface.cc b/src/atlas/meshgenerator/detail/MeshGeneratorInterface.cc new file mode 100644 index 000000000..6ef47b49e --- /dev/null +++ b/src/atlas/meshgenerator/detail/MeshGeneratorInterface.cc @@ -0,0 +1,96 @@ +/* + * (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/meshgenerator/detail/MeshGeneratorInterface.h" +#include "atlas/grid/Distribution.h" +#include "atlas/grid/Grid.h" +#include "atlas/mesh/Mesh.h" +#include "atlas/meshgenerator.h" +#include "atlas/meshgenerator/detail/MeshGeneratorImpl.h" +#include "atlas/runtime/Exception.h" + +using atlas::Mesh; + +namespace atlas { +namespace meshgenerator { + +//---------------------------------------------------------------------------------------------------------------------- + +extern "C" { + +void atlas__MeshGenerator__delete( MeshGenerator::Implementation* This ) { + ATLAS_ASSERT( This != nullptr, "Cannot access uninitialisd atlas_MeshGenerator" ); + delete This; +} + +const MeshGenerator::Implementation* atlas__MeshGenerator__create_noconfig( const char* name ) { + const MeshGenerator::Implementation* meshgenerator( nullptr ); + { + MeshGenerator m( std::string{name} ); + meshgenerator = m.get(); + meshgenerator->attach(); + } + meshgenerator->detach(); + return meshgenerator; +} + +const MeshGenerator::Implementation* atlas__MeshGenerator__create( const char* name, + const eckit::Parametrisation* config ) { + const MeshGenerator::Implementation* meshgenerator( nullptr ); + ATLAS_ASSERT( config ); + { + MeshGenerator m( std::string( name ), *config ); + meshgenerator = m.get(); + meshgenerator->attach(); + } + meshgenerator->detach(); + return meshgenerator; +} + +Mesh::Implementation* atlas__MeshGenerator__generate__grid_griddist( + const MeshGenerator::Implementation* This, const Grid::Implementation* grid, + const grid::Distribution::Implementation* distribution ) { + ATLAS_ASSERT( This != nullptr, "Cannot access uninitialisd atlas_MeshGenerator" ); + ATLAS_ASSERT( grid != nullptr, "Cannot access uninitialisd atlas_Grid" ); + ATLAS_ASSERT( distribution != nullptr, "Cannot access uninitialisd atlas_GridDistribution" ); + + Mesh::Implementation* m; + { + Mesh mesh = This->generate( Grid( grid ), grid::Distribution( distribution ) ); + mesh.get()->attach(); + m = mesh.get(); + } + m->detach(); + return m; +} + +Mesh::Implementation* atlas__MeshGenerator__generate__grid( const MeshGenerator::Implementation* This, + const Grid::Implementation* grid ) { + ATLAS_ASSERT( This != nullptr, "Cannot access uninitialisd atlas_MeshGenerator" ); + ATLAS_ASSERT( grid != nullptr, "Cannot access uninitialisd atlas_Grid" ); + Mesh::Implementation* m; + { + Mesh mesh = This->generate( Grid( grid ) ); + ; + mesh.get()->attach(); + m = mesh.get(); + } + m->detach(); + return m; +} +} // extern "C" + +//---------------------------------------------------------------------------------------------------------------------- + +} // namespace meshgenerator + +//---------------------------------------------------------------------------------------------------------------------- + +} // namespace atlas diff --git a/src/atlas/meshgenerator/detail/MeshGeneratorInterface.h b/src/atlas/meshgenerator/detail/MeshGeneratorInterface.h new file mode 100644 index 000000000..0261462d4 --- /dev/null +++ b/src/atlas/meshgenerator/detail/MeshGeneratorInterface.h @@ -0,0 +1,65 @@ +/* + * (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 Parametrisation; +} // namespace eckit + +namespace atlas { +namespace grid { +class DistributionImpl; +} // namespace grid +} // namespace atlas + +namespace atlas { +namespace grid { +namespace detail { +namespace grid { +class Grid; +} // namespace grid +} // namespace detail +} // namespace grid +using GridImpl = grid::detail::grid::Grid; +} // namespace atlas +namespace atlas { +namespace mesh { +namespace detail { +class MeshImpl; +} // namespace detail +} // namespace mesh +} // namespace atlas + + +namespace atlas { +namespace meshgenerator { + +class MeshGeneratorImpl; + +//---------------------------------------------------------------------------------------------------------------------- + +extern "C" { +void atlas__MeshGenerator__delete( MeshGeneratorImpl* This ); +const MeshGeneratorImpl* atlas__MeshGenerator__create_noconfig( const char* name ); +const MeshGeneratorImpl* atlas__MeshGenerator__create( const char* name, const eckit::Parametrisation* params ); +mesh::detail::MeshImpl* atlas__MeshGenerator__generate__grid_griddist( const MeshGeneratorImpl* This, + const GridImpl* grid, + const grid::DistributionImpl* distribution ); +mesh::detail::MeshImpl* atlas__MeshGenerator__generate__grid( const MeshGeneratorImpl* This, const GridImpl* grid ); +} + +//---------------------------------------------------------------------------------------------------------------------- + +} // namespace meshgenerator + +//---------------------------------------------------------------------------------------------------------------------- + +} // namespace atlas diff --git a/src/atlas/meshgenerator/RegularMeshGenerator.cc b/src/atlas/meshgenerator/detail/RegularMeshGenerator.cc similarity index 91% rename from src/atlas/meshgenerator/RegularMeshGenerator.cc rename to src/atlas/meshgenerator/detail/RegularMeshGenerator.cc index 0d66fa9aa..b47b0c26b 100644 --- a/src/atlas/meshgenerator/RegularMeshGenerator.cc +++ b/src/atlas/meshgenerator/detail/RegularMeshGenerator.cc @@ -1,3 +1,12 @@ +/* + * (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 @@ -12,16 +21,18 @@ #include "atlas/array/IndexView.h" #include "atlas/field/Field.h" #include "atlas/grid/Distribution.h" -#include "atlas/grid/Grid.h" #include "atlas/grid/Partitioner.h" +#include "atlas/grid/StructuredGrid.h" #include "atlas/library/config.h" #include "atlas/mesh/ElementType.h" #include "atlas/mesh/Elements.h" #include "atlas/mesh/HybridElements.h" #include "atlas/mesh/Mesh.h" #include "atlas/mesh/Nodes.h" -#include "atlas/meshgenerator/RegularMeshGenerator.h" +#include "atlas/meshgenerator/detail/MeshGeneratorFactory.h" +#include "atlas/meshgenerator/detail/RegularMeshGenerator.h" #include "atlas/parallel/mpi/mpi.h" +#include "atlas/runtime/Exception.h" #include "atlas/runtime/Log.h" #include "atlas/util/CoordinateEnums.h" @@ -88,10 +99,10 @@ void RegularMeshGenerator::configure_defaults() { } void RegularMeshGenerator::generate( const Grid& grid, Mesh& mesh ) const { - ASSERT( !mesh.generated() ); + ATLAS_ASSERT( !mesh.generated() ); - const grid::RegularGrid rg = grid::RegularGrid( grid ); - if ( !rg ) throw eckit::BadCast( "RegularMeshGenerator can only work with a Regular grid", Here() ); + const RegularGrid rg = RegularGrid( grid ); + if ( !rg ) throw_Exception( "RegularMeshGenerator can only work with a Regular grid", Here() ); size_t nb_parts = options.get( "nb_parts" ); @@ -114,18 +125,18 @@ void RegularMeshGenerator::hash( eckit::Hash& h ) const { } void RegularMeshGenerator::generate( const Grid& grid, const grid::Distribution& distribution, Mesh& mesh ) const { - const grid::RegularGrid rg = grid::RegularGrid( grid ); - if ( !rg ) throw eckit::BadCast( "Grid could not be cast to a Regular", Here() ); + const auto rg = RegularGrid( grid ); + if ( !rg ) throw_Exception( "Grid could not be cast to a Regular", Here() ); - ASSERT( !mesh.generated() ); + ATLAS_ASSERT( !mesh.generated() ); - if ( grid.size() != distribution.partition().size() ) { + if ( grid.size() != static_cast( distribution.partition().size() ) ) { std::stringstream msg; msg << "Number of points in grid (" << grid.size() << ") different from " "number of points in grid distribution (" << distribution.partition().size() << ")"; - throw eckit::AssertionFailed( msg.str(), Here() ); + throw_AssertionFailed( msg.str(), Here() ); } // clone some grid properties @@ -134,7 +145,7 @@ void RegularMeshGenerator::generate( const Grid& grid, const grid::Distribution& generate_mesh( rg, distribution, mesh ); } -void RegularMeshGenerator::generate_mesh( const grid::RegularGrid& rg, const std::vector& parts, +void RegularMeshGenerator::generate_mesh( const RegularGrid& rg, const std::vector& parts, // const Region& region, Mesh& mesh ) const { int mypart = options.get( "part" ); @@ -162,7 +173,7 @@ void RegularMeshGenerator::generate_mesh( const grid::RegularGrid& rg, const std // array::ArrayView glb_idx ( nodes.global_index() ); // array::ArrayView part ( nodes.partition() ); // array::ArrayView ghost ( nodes.ghost() ); - // array::ArrayView flags ( nodes.field("flags") ); + // array::ArrayView flags ( nodes.flags() ); // - define cells (only quadrilaterals for now) with // mesh.cells().add( new mesh::temporary::Quadrilateral(), nquads ); // further define cells with @@ -361,22 +372,22 @@ void RegularMeshGenerator::generate_mesh( const grid::RegularGrid& rg, const std // define nodes and associated properties mesh.nodes().resize( nnodes ); - mesh::Nodes& nodes = mesh.nodes(); - array::ArrayView xy = array::make_view( nodes.xy() ); - array::ArrayView lonlat = array::make_view( nodes.lonlat() ); - array::ArrayView glb_idx = array::make_view( nodes.global_index() ); - array::IndexView remote_idx = array::make_indexview( nodes.remote_index() ); - array::ArrayView part = array::make_view( nodes.partition() ); - array::ArrayView ghost = array::make_view( nodes.ghost() ); - array::ArrayView flags = array::make_view( nodes.field( "flags" ) ); + mesh::Nodes& nodes = mesh.nodes(); + auto xy = array::make_view( nodes.xy() ); + auto lonlat = array::make_view( nodes.lonlat() ); + auto glb_idx = array::make_view( nodes.global_index() ); + auto remote_idx = array::make_indexview( nodes.remote_index() ); + auto part = array::make_view( nodes.partition() ); + auto ghost = array::make_view( nodes.ghost() ); + auto flags = array::make_view( nodes.flags() ); // define cells and associated properties mesh.cells().add( new mesh::temporary::Quadrilateral(), ncells ); int quad_begin = mesh.cells().elements( 0 ).begin(); - array::ArrayView cells_part = array::make_view( mesh.cells().partition() ); + auto cells_part = array::make_view( mesh.cells().partition() ); mesh::HybridElements::Connectivity& node_connectivity = mesh.cells().node_connectivity(); - int quad_nodes[4]; + idx_t quad_nodes[4]; int jcell = quad_begin; int inode, inode_nonghost, inode_ghost; diff --git a/src/atlas/meshgenerator/RegularMeshGenerator.h b/src/atlas/meshgenerator/detail/RegularMeshGenerator.h similarity index 67% rename from src/atlas/meshgenerator/RegularMeshGenerator.h rename to src/atlas/meshgenerator/detail/RegularMeshGenerator.h index cdc3530ae..f785eb104 100644 --- a/src/atlas/meshgenerator/RegularMeshGenerator.h +++ b/src/atlas/meshgenerator/detail/RegularMeshGenerator.h @@ -1,7 +1,18 @@ +/* + * (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/meshgenerator/MeshGenerator.h" +#include "atlas/meshgenerator/detail/MeshGeneratorImpl.h" #include "atlas/util/Config.h" #include "atlas/util/Metadata.h" @@ -10,12 +21,12 @@ class Parametrisation; } namespace atlas { +class RegularGrid; class Mesh; -} +} // namespace atlas namespace atlas { namespace grid { -class RegularGrid; class Distribution; } // namespace grid } // namespace atlas @@ -39,7 +50,7 @@ class RegularMeshGenerator : public MeshGenerator::Implementation { void configure_defaults(); - void generate_mesh( const atlas::grid::RegularGrid&, const std::vector& parts, Mesh& m ) const; + void generate_mesh( const RegularGrid&, const std::vector& parts, Mesh& m ) const; private: util::Metadata options; diff --git a/src/atlas/meshgenerator/StructuredMeshGenerator.cc b/src/atlas/meshgenerator/detail/StructuredMeshGenerator.cc similarity index 83% rename from src/atlas/meshgenerator/StructuredMeshGenerator.cc rename to src/atlas/meshgenerator/detail/StructuredMeshGenerator.cc index 028e90a1e..f9745f6e1 100644 --- a/src/atlas/meshgenerator/StructuredMeshGenerator.cc +++ b/src/atlas/meshgenerator/detail/StructuredMeshGenerator.cc @@ -11,11 +11,11 @@ #include #include #include +#include #include #include -#include "eckit/memory/SharedPtr.h" -#include "eckit/runtime/Main.h" +#include "eckit/types/FloatCompare.h" #include "eckit/utils/Hash.h" #include "atlas/array.h" @@ -23,15 +23,16 @@ #include "atlas/array/MakeView.h" #include "atlas/field/Field.h" #include "atlas/grid/Distribution.h" -#include "atlas/grid/Grid.h" #include "atlas/grid/Partitioner.h" +#include "atlas/grid/StructuredGrid.h" #include "atlas/library/config.h" #include "atlas/mesh/ElementType.h" #include "atlas/mesh/Elements.h" #include "atlas/mesh/HybridElements.h" #include "atlas/mesh/Mesh.h" #include "atlas/mesh/Nodes.h" -#include "atlas/meshgenerator/StructuredMeshGenerator.h" +#include "atlas/meshgenerator/detail/MeshGeneratorFactory.h" +#include "atlas/meshgenerator/detail/StructuredMeshGenerator.h" #include "atlas/parallel/mpi/mpi.h" #include "atlas/runtime/Log.h" #include "atlas/runtime/Trace.h" @@ -39,14 +40,12 @@ #define DEBUG_OUTPUT 0 -using namespace eckit; using namespace atlas::array; using atlas::Mesh; using Topology = atlas::mesh::Nodes::Topology; namespace atlas { namespace meshgenerator { -namespace detail { namespace { static double to_rad = M_PI / 180.; @@ -56,13 +55,13 @@ static double to_deg = 180. * M_1_PI; struct Region { int north; int south; - eckit::SharedPtr elems; + std::unique_ptr elems; int ntriags; int nquads; int nnodes; - std::vector lat_begin; - std::vector lat_end; - std::vector nb_lat_elems; + std::vector lat_begin; + std::vector lat_end; + std::vector nb_lat_elems; }; StructuredMeshGenerator::StructuredMeshGenerator( const eckit::Parametrisation& p ) { @@ -160,17 +159,18 @@ void StructuredMeshGenerator::configure_defaults() { } void StructuredMeshGenerator::generate( const Grid& grid, Mesh& mesh ) const { - ASSERT( !mesh.generated() ); + ATLAS_ASSERT( !mesh.generated() ); - const grid::StructuredGrid rg = grid::StructuredGrid( grid ); - if ( !rg ) throw eckit::BadCast( "Structured can only work with a Structured", Here() ); + const StructuredGrid rg = StructuredGrid( grid ); + if ( !rg ) throw_Exception( "Structured can only work with a Structured", Here() ); - size_t nb_parts = options.get( "nb_parts" ); + idx_t nb_parts = options.get( "nb_parts" ); - std::string partitioner_type = "trans"; + std::string partitioner_type = "equal_regions"; options.get( "partitioner", partitioner_type ); - if ( rg.ny() % 2 == 1 ) partitioner_type = "equal_regions"; // Odd number of latitudes + if ( partitioner_type == "trans" && rg.ny() % 2 == 1 ) + partitioner_type = "equal_regions"; // Odd number of latitudes if ( nb_parts == 1 || mpi::comm().size() == 1 ) partitioner_type = "equal_regions"; // Only one part --> Trans is slower @@ -179,7 +179,7 @@ void StructuredMeshGenerator::generate( const Grid& grid, Mesh& mesh ) const { generate( grid, distribution, mesh ); } -void StructuredMeshGenerator::hash( Hash& h ) const { +void StructuredMeshGenerator::hash( eckit::Hash& h ) const { h.add( "Structured" ); options.hash( h ); } @@ -187,21 +187,21 @@ void StructuredMeshGenerator::hash( Hash& h ) const { void StructuredMeshGenerator::generate( const Grid& grid, const grid::Distribution& distribution, Mesh& mesh ) const { ATLAS_TRACE(); - const grid::StructuredGrid rg = grid::StructuredGrid( grid ); - if ( !rg ) throw eckit::BadCast( "Grid could not be cast to a Structured", Here() ); + const StructuredGrid rg = StructuredGrid( grid ); + if ( !rg ) throw_Exception( "Grid could not be cast to a Structured", Here() ); - ASSERT( !mesh.generated() ); + ATLAS_ASSERT( !mesh.generated() ); - if ( grid.size() != distribution.partition().size() ) { + if ( grid.size() != idx_t( distribution.partition().size() ) ) { std::stringstream msg; msg << "Number of points in grid (" << grid.size() << ") different from " "number of points in grid distribution (" << distribution.partition().size() << ")"; - throw eckit::AssertionFailed( msg.str(), Here() ); + throw_AssertionFailed( msg.str(), Here() ); } - int mypart = options.get( "part" ); + idx_t mypart = options.get( "part" ); // show distribution #if DEBUG_OUTPUT @@ -226,15 +226,15 @@ void StructuredMeshGenerator::generate( const Grid& grid, const grid::Distributi generate_mesh( rg, distribution, region, mesh ); } -void StructuredMeshGenerator::generate_region( const grid::StructuredGrid& rg, const std::vector& parts, - int mypart, Region& region ) const { +void StructuredMeshGenerator::generate_region( const StructuredGrid& rg, const std::vector& parts, int mypart, + Region& region ) const { ATLAS_TRACE(); double max_angle = options.get( "angle" ); bool triangulate_quads = options.get( "triangulate" ); bool three_dimensional = options.get( "3d" ); - bool has_north_pole = rg.y().front() == 90; - bool has_south_pole = rg.y().back() == -90; + bool has_north_pole = eckit::types::is_approximately_equal( rg.y().front(), 90. ); + bool has_south_pole = eckit::types::is_approximately_equal( rg.y().back(), -90. ); bool unique_pole = options.get( "unique_pole" ) && three_dimensional && has_north_pole && has_south_pole; bool periodic_east_west = rg.periodic(); @@ -242,10 +242,10 @@ void StructuredMeshGenerator::generate_region( const grid::StructuredGrid& rg, c /* Find min and max latitudes used by this part. */ - n = 0; - int lat_north = -1; - for ( size_t jlat = 0; jlat < rg.ny(); ++jlat ) { - for ( size_t jlon = 0; jlon < rg.nx( jlat ); ++jlon ) { + n = 0; + idx_t lat_north = -1; + for ( idx_t jlat = 0; jlat < rg.ny(); ++jlat ) { + for ( idx_t jlon = 0; jlon < rg.nx( jlat ); ++jlon ) { if ( parts.at( n ) == mypart ) { lat_north = jlat; goto end_north; @@ -255,10 +255,10 @@ Find min and max latitudes used by this part. } end_north: - n = rg.size() - 1; - int lat_south = -1; - for ( int jlat = rg.ny() - 1; jlat >= 0; --jlat ) { - for ( int jlon = rg.nx( jlat ) - 1; jlon >= 0; --jlon ) { + n = rg.size() - 1; + idx_t lat_south = -1; + for ( idx_t jlat = rg.ny() - 1; jlat >= 0; --jlat ) { + for ( idx_t jlon = rg.nx( jlat ) - 1; jlon >= 0; --jlon ) { if ( parts.at( n ) == mypart ) { lat_south = jlat; goto end_south; @@ -268,10 +268,10 @@ Find min and max latitudes used by this part. } end_south: - std::vector offset( rg.ny(), 0 ); + std::vector offset( rg.ny(), 0 ); n = 0; - for ( size_t jlat = 0; jlat < rg.ny(); ++jlat ) { + for ( idx_t jlat = 0; jlat < rg.ny(); ++jlat ) { offset.at( jlat ) = n; n += rg.nx( jlat ); }; @@ -280,7 +280,7 @@ Find min and max latitudes used by this part. We need to connect to next region */ if ( lat_north - 1 >= 0 && rg.nx( lat_north - 1 ) > 0 ) --lat_north; - if ( size_t( lat_south + 1 ) <= rg.ny() - 1 && rg.nx( lat_south + 1 ) > 0 ) ++lat_south; + if ( idx_t( lat_south + 1 ) <= rg.ny() - 1 && rg.nx( lat_south + 1 ) > 0 ) ++lat_south; region.lat_begin.resize( rg.ny(), -1 ); region.lat_end.resize( rg.ny(), -1 ); region.nb_lat_elems.resize( rg.ny(), 0 ); @@ -299,11 +299,11 @@ We need to connect to next region elemview.assign( -1 ); bool stagger = options.get( "stagger" ); - for ( int jlat = lat_north; jlat < lat_south; ++jlat ) { + for ( idx_t jlat = lat_north; jlat < lat_south; ++jlat ) { // std::stringstream filename; filename << "/tmp/debug/"<( region.lat_begin.at( latN ), ipN1 ); - region.lat_begin.at( latS ) = std::min( region.lat_begin.at( latS ), ipS1 ); - region.lat_end.at( latN ) = std::max( region.lat_end.at( latN ), ipN1 ); - region.lat_end.at( latS ) = std::max( region.lat_end.at( latS ), ipS2 ); + region.lat_begin.at( latN ) = std::min( region.lat_begin.at( latN ), ipN1 ); + region.lat_begin.at( latS ) = std::min( region.lat_begin.at( latS ), ipS1 ); + region.lat_end.at( latN ) = std::max( region.lat_end.at( latN ), ipN1 ); + region.lat_end.at( latS ) = std::max( region.lat_end.at( latS ), ipS2 ); } else { #if DEBUG_OUTPUT @@ -614,7 +614,7 @@ We need to connect to next region // and ipN1=ipN1; } else { - throw eckit::SeriousBug( "Could not detect which element to create", Here() ); + throw_Exception( "Could not detect which element to create", Here() ); } ipN2 = std::min( endN, ipN1 + 1 ); ipS2 = std::min( endS, ipS1 + 1 ); @@ -623,8 +623,8 @@ We need to connect to next region #if DEBUG_OUTPUT ATLAS_DEBUG_VAR( region.nb_lat_elems.at( jlat ) ); #endif - if ( region.nb_lat_elems.at( jlat ) == 0 && latN == size_t( region.north ) ) { ++region.north; } - if ( region.nb_lat_elems.at( jlat ) == 0 && latS == size_t( region.south ) ) { --region.south; } + if ( region.nb_lat_elems.at( jlat ) == 0 && latN == region.north ) { ++region.north; } + if ( region.nb_lat_elems.at( jlat ) == 0 && latS == region.south ) { --region.south; } // region.lat_end.at(latN) = std::min(region.lat_end.at(latN), // int(rg.nx(latN)-1)); // region.lat_end.at(latS) = std::min(region.lat_end.at(latS), @@ -646,10 +646,10 @@ We need to connect to next region for ( int jlat = region.north; jlat <= region.south; ++jlat ) { n = offset.at( jlat ); region.lat_begin.at( jlat ) = std::max( 0, region.lat_begin.at( jlat ) ); - for ( size_t jlon = 0; jlon < rg.nx( jlat ); ++jlon ) { + for ( idx_t jlon = 0; jlon < rg.nx( jlat ); ++jlon ) { if ( parts.at( n ) == mypart ) { - region.lat_begin.at( jlat ) = std::min( region.lat_begin.at( jlat ), int( jlon ) ); - region.lat_end.at( jlat ) = std::max( region.lat_end.at( jlat ), int( jlon ) ); + region.lat_begin.at( jlat ) = std::min( region.lat_begin.at( jlat ), jlon ); + region.lat_end.at( jlat ) = std::max( region.lat_end.at( jlat ), jlon ); } ++n; } @@ -662,7 +662,7 @@ We need to connect to next region region.nnodes = nb_region_nodes; if ( region.nnodes == 0 ) { - throw Exception( + throw_Exception( "Trying to generate mesh with too many partitions. Reduce " "the number of partitions.", Here() ); @@ -685,11 +685,11 @@ struct GhostNode { }; } // namespace -void StructuredMeshGenerator::generate_mesh( const grid::StructuredGrid& rg, const std::vector& parts, +void StructuredMeshGenerator::generate_mesh( const StructuredGrid& rg, const std::vector& parts, const Region& region, Mesh& mesh ) const { ATLAS_TRACE(); - ASSERT( !mesh.generated() ); + ATLAS_ASSERT( !mesh.generated() ); int mypart = options.get( "part" ); int nparts = options.get( "nb_parts" ); @@ -721,7 +721,7 @@ void StructuredMeshGenerator::generate_mesh( const grid::StructuredGrid& rg, con ( !has_point_at_south_pole && include_south_pole ? 1 : 0 ); if ( three_dimensional && nparts != 1 ) - throw BadParameter( "Cannot generate three_dimensional mesh in parallel", Here() ); + throw_Exception( "Cannot generate three_dimensional mesh in parallel", Here() ); int nnodes = region.nnodes; int ntriags = region.ntriags; int nquads = region.nquads; @@ -743,11 +743,11 @@ void StructuredMeshGenerator::generate_mesh( const grid::StructuredGrid& rg, con size_t node_numbering_size = nnodes; if ( remove_periodic_ghost_points ) { - for ( size_t jlat = 0; jlat < rg.ny(); ++jlat ) { + for ( idx_t jlat = 0; jlat < rg.ny(); ++jlat ) { if ( region.lat_end[jlat] >= rg.nx( jlat ) ) --nnodes; } } - ASSERT( nnodes >= nnewnodes ); + ATLAS_ASSERT( nnodes >= nnewnodes ); #if DEBUG_OUTPUT ATLAS_DEBUG_VAR( include_periodic_ghost_points ); @@ -767,7 +767,7 @@ void StructuredMeshGenerator::generate_mesh( const grid::StructuredGrid& rg, con std::vector offset_loc( region.south - region.north + 1, 0 ); n = 0; - for ( size_t jlat = 0; jlat < rg.ny(); ++jlat ) { + for ( idx_t jlat = 0; jlat < rg.ny(); ++jlat ) { offset_glb.at( jlat ) = n; n += rg.nx( jlat ); }; @@ -775,7 +775,7 @@ void StructuredMeshGenerator::generate_mesh( const grid::StructuredGrid& rg, con std::vector periodic_glb( rg.ny() ); if ( include_periodic_ghost_points ) { - for ( size_t jlat = 0; jlat < rg.ny(); ++jlat ) { + for ( idx_t jlat = 0; jlat < rg.ny(); ++jlat ) { if ( rg.nx( jlat ) > 0 ) { periodic_glb.at( jlat ) = n; ++n; @@ -783,7 +783,7 @@ void StructuredMeshGenerator::generate_mesh( const grid::StructuredGrid& rg, con } } else { - for ( size_t jlat = 0; jlat < rg.ny(); ++jlat ) { + for ( idx_t jlat = 0; jlat < rg.ny(); ++jlat ) { if ( rg.nx( jlat ) > 0 ) { periodic_glb.at( jlat ) = offset_glb.at( jlat ) + rg.nx( jlat ) - 1; } } } @@ -792,23 +792,24 @@ void StructuredMeshGenerator::generate_mesh( const grid::StructuredGrid& rg, con mesh.nodes().resize( nnodes ); mesh::Nodes& nodes = mesh.nodes(); - array::ArrayView xy = array::make_view( nodes.xy() ); - array::ArrayView lonlat = array::make_view( nodes.lonlat() ); - array::ArrayView glb_idx = array::make_view( nodes.global_index() ); - array::ArrayView part = array::make_view( nodes.partition() ); - array::ArrayView ghost = array::make_view( nodes.ghost() ); - array::ArrayView flags = array::make_view( nodes.field( "flags" ) ); + auto xy = array::make_view( nodes.xy() ); + auto lonlat = array::make_view( nodes.lonlat() ); + auto glb_idx = array::make_view( nodes.global_index() ); + auto part = array::make_view( nodes.partition() ); + auto ghost = array::make_view( nodes.ghost() ); + auto flags = array::make_view( nodes.flags() ); + auto halo = array::make_view( nodes.halo() ); bool stagger = options.get( "stagger" ); - std::vector node_numbering( node_numbering_size, -1 ); + std::vector node_numbering( node_numbering_size, -1 ); if ( options.get( "ghost_at_end" ) ) { std::vector ghost_nodes; ghost_nodes.reserve( nnodes ); - int node_number = 0; - int jnode = 0; - l = 0; - ASSERT( region.south >= region.north ); + idx_t node_number = 0; + idx_t jnode = 0; + l = 0; + ATLAS_ASSERT( region.south >= region.north ); for ( int jlat = region.north; jlat <= region.south; ++jlat ) { int ilat = jlat - region.north; offset_loc.at( ilat ) = l; @@ -819,7 +820,7 @@ void StructuredMeshGenerator::generate_mesh( const grid::StructuredGrid& rg, con ATLAS_DEBUG_VAR( region.lat_begin[jlat] ); ATLAS_DEBUG_VAR( region.lat_end[jlat] ); } - for ( int jlon = region.lat_begin.at( jlat ); jlon <= region.lat_end.at( jlat ); ++jlon ) { + for ( idx_t jlon = region.lat_begin.at( jlat ); jlon <= region.lat_end.at( jlat ); ++jlon ) { if ( jlon < rg.nx( jlat ) ) { n = offset_glb.at( jlat ) + jlon; if ( parts.at( n ) == mypart ) { @@ -837,6 +838,7 @@ void StructuredMeshGenerator::generate_mesh( const grid::StructuredGrid& rg, con part( jnode ) = mypart; // part(jnode) = parts.at( offset_glb.at(jlat) ); ghost( jnode ) = 1; + halo( jnode ) = 0; ghost_nodes.push_back( GhostNode( jlat, rg.nx( jlat ), jnode ) ); ++jnode; } @@ -857,26 +859,26 @@ void StructuredMeshGenerator::generate_mesh( const grid::StructuredGrid& rg, con node_numbering.at( jnode ) = jnode; ++jnode; } - ASSERT( jnode == nnodes ); + ATLAS_ASSERT( jnode == nnodes ); } else // No renumbering { - for ( int jnode = 0; jnode < nnodes; ++jnode ) + for ( idx_t jnode = 0; jnode < nnodes; ++jnode ) node_numbering.at( jnode ) = jnode; } - int jnode = 0; - l = 0; - for ( int jlat = region.north; jlat <= region.south; ++jlat ) { - int ilat = jlat - region.north; + idx_t jnode = 0; + l = 0; + for ( idx_t jlat = region.north; jlat <= region.south; ++jlat ) { + idx_t ilat = jlat - region.north; offset_loc.at( ilat ) = l; l += region.lat_end.at( jlat ) - region.lat_begin.at( jlat ) + 1; double y = rg.y( jlat ); - for ( int jlon = region.lat_begin.at( jlat ); jlon <= region.lat_end.at( jlat ); ++jlon ) { + for ( idx_t jlon = region.lat_begin.at( jlat ); jlon <= region.lat_end.at( jlat ); ++jlon ) { if ( jlon < rg.nx( jlat ) ) { - int inode = node_numbering.at( jnode ); - n = offset_glb.at( jlat ) + jlon; + idx_t inode = node_numbering.at( jnode ); + n = offset_glb.at( jlat ) + jlon; double x = rg.x( jlon, jlat ); // std::cout << "jlat = " << jlat << "; jlon = " << jlon << "; x = " << @@ -895,11 +897,12 @@ void StructuredMeshGenerator::generate_mesh( const grid::StructuredGrid& rg, con glb_idx( inode ) = n + 1; part( inode ) = parts.at( n ); ghost( inode ) = 0; + halo( inode ) = 0; Topology::reset( flags( inode ) ); if ( jlat == 0 && !include_north_pole ) { Topology::set( flags( inode ), Topology::BC | Topology::NORTH ); } - if ( size_t( jlat ) == rg.ny() - 1 && !include_south_pole ) { + if ( jlat == rg.ny() - 1 && !include_south_pole ) { Topology::set( flags( inode ), Topology::BC | Topology::SOUTH ); } if ( jlon == 0 && include_periodic_ghost_points ) { @@ -913,7 +916,7 @@ void StructuredMeshGenerator::generate_mesh( const grid::StructuredGrid& rg, con } else if ( include_periodic_ghost_points ) // add periodic point { - int inode = node_numbering.at( jnode ); + idx_t inode = node_numbering.at( jnode ); // int inode_left = node_numbering.at(jnode-1); double x = rg.x( rg.nx( jlat ), jlat ); if ( stagger && ( jlat + 1 ) % 2 == 0 ) x += 180. / static_cast( rg.nx( jlat ) ); @@ -932,6 +935,7 @@ void StructuredMeshGenerator::generate_mesh( const grid::StructuredGrid& rg, con // part(inode) = parts.at( offset_glb.at(jlat) ); part( inode ) = mypart; // The actual part will be fixed later ghost( inode ) = 1; + halo( inode ) = 0; Topology::reset( flags( inode ) ); Topology::set( flags( inode ), Topology::BC | Topology::EAST ); Topology::set( flags( inode ), Topology::GHOST ); @@ -943,9 +947,9 @@ void StructuredMeshGenerator::generate_mesh( const grid::StructuredGrid& rg, con } }; - int jnorth = -1; + idx_t jnorth = -1; if ( include_north_pole ) { - int inode = node_numbering.at( jnode ); + idx_t inode = node_numbering.at( jnode ); jnorth = jnode; double y = 90.; double x = 180.; @@ -961,14 +965,15 @@ void StructuredMeshGenerator::generate_mesh( const grid::StructuredGrid& rg, con glb_idx( inode ) = periodic_glb.at( rg.ny() - 1 ) + 2; part( inode ) = mypart; ghost( inode ) = 0; + halo( inode ) = 0; Topology::reset( flags( inode ) ); Topology::set( flags( inode ), Topology::NORTH ); ++jnode; } - int jsouth = -1; + idx_t jsouth = -1; if ( include_south_pole ) { - int inode = node_numbering.at( jnode ); + idx_t inode = node_numbering.at( jnode ); jsouth = jnode; double y = -90.; double x = 180.; @@ -984,14 +989,15 @@ void StructuredMeshGenerator::generate_mesh( const grid::StructuredGrid& rg, con glb_idx( inode ) = periodic_glb.at( rg.ny() - 1 ) + 3; part( inode ) = mypart; ghost( inode ) = 0; + halo( inode ) = 0; Topology::reset( flags( inode ) ); Topology::set( flags( inode ), Topology::SOUTH ); ++jnode; } + mesh.metadata().set( "nb_nodes_including_halo[0]", nodes.size() ); nodes.metadata().set( "NbRealPts", size_t( nnodes - nnewnodes ) ); nodes.metadata().set( "NbVirtualPts", size_t( nnewnodes ) ); - nodes.global_index().metadata().set( "human_readable", true ); nodes.global_index().metadata().set( "min", 1 ); nodes.global_index().metadata().set( "max", max_glb_idx ); @@ -1015,21 +1021,21 @@ void StructuredMeshGenerator::generate_mesh( const grid::StructuredGrid& rg, con /* * Fill in connectivity tables with global node indices first */ - int jcell; - int jquad = 0; - int jtriag = 0; - int quad_begin = mesh.cells().elements( 0 ).begin(); - int triag_begin = mesh.cells().elements( 1 ).begin(); - int quad_nodes[4]; - int triag_nodes[3]; - - for ( int jlat = region.north; jlat < region.south; ++jlat ) { - int ilat = jlat - region.north; - int jlatN = jlat; - int jlatS = jlat + 1; - int ilatN = ilat; - int ilatS = ilat + 1; - for ( int jelem = 0; jelem < region.nb_lat_elems.at( jlat ); ++jelem ) { + idx_t jcell; + idx_t jquad = 0; + idx_t jtriag = 0; + idx_t quad_begin = mesh.cells().elements( 0 ).begin(); + idx_t triag_begin = mesh.cells().elements( 1 ).begin(); + idx_t quad_nodes[4]; + idx_t triag_nodes[3]; + + for ( idx_t jlat = region.north; jlat < region.south; ++jlat ) { + idx_t ilat = jlat - region.north; + idx_t jlatN = jlat; + idx_t jlatS = jlat + 1; + idx_t ilatN = ilat; + idx_t ilatS = ilat + 1; + for ( idx_t jelem = 0; jelem < region.nb_lat_elems.at( jlat ); ++jelem ) { const auto elem = array::make_view( *region.elems ).slice( ilat, jelem, Range::all() ); if ( elem( 2 ) >= 0 && elem( 3 ) >= 0 ) // This is a quad @@ -1040,10 +1046,8 @@ void StructuredMeshGenerator::generate_mesh( const grid::StructuredGrid& rg, con quad_nodes[3] = node_numbering.at( offset_loc.at( ilatN ) + elem( 3 ) - region.lat_begin.at( jlatN ) ); if ( three_dimensional && periodic_east_west ) { - if ( size_t( elem( 2 ) ) == rg.nx( jlatS ) ) - quad_nodes[2] = node_numbering.at( offset_loc.at( ilatS ) ); - if ( size_t( elem( 3 ) ) == rg.nx( jlatN ) ) - quad_nodes[3] = node_numbering.at( offset_loc.at( ilatN ) ); + if ( elem( 2 ) == rg.nx( jlatS ) ) quad_nodes[2] = node_numbering.at( offset_loc.at( ilatS ) ); + if ( elem( 3 ) == rg.nx( jlatN ) ) quad_nodes[3] = node_numbering.at( offset_loc.at( ilatN ) ); } jcell = quad_begin + jquad++; @@ -1062,10 +1066,8 @@ void StructuredMeshGenerator::generate_mesh( const grid::StructuredGrid& rg, con triag_nodes[2] = node_numbering.at( offset_loc.at( ilatS ) + elem( 2 ) - region.lat_begin.at( jlatS ) ); if ( three_dimensional && periodic_east_west ) { - if ( size_t( elem( 0 ) ) == rg.nx( jlatN ) ) - triag_nodes[0] = node_numbering.at( offset_loc.at( ilatN ) ); - if ( size_t( elem( 2 ) ) == rg.nx( jlatS ) ) - triag_nodes[2] = node_numbering.at( offset_loc.at( ilatS ) ); + if ( elem( 0 ) == rg.nx( jlatN ) ) triag_nodes[0] = node_numbering.at( offset_loc.at( ilatN ) ); + if ( elem( 2 ) == rg.nx( jlatS ) ) triag_nodes[2] = node_numbering.at( offset_loc.at( ilatS ) ); } } else // This is a triangle pointing down @@ -1077,10 +1079,8 @@ void StructuredMeshGenerator::generate_mesh( const grid::StructuredGrid& rg, con triag_nodes[2] = node_numbering.at( offset_loc.at( ilatN ) + elem( 3 ) - region.lat_begin.at( jlatN ) ); if ( three_dimensional && periodic_east_west ) { - if ( size_t( elem( 1 ) ) == rg.nx( jlatS ) ) - triag_nodes[1] = node_numbering.at( offset_loc.at( ilatS ) ); - if ( size_t( elem( 3 ) ) == rg.nx( jlatN ) ) - triag_nodes[2] = node_numbering.at( offset_loc.at( ilatN ) ); + if ( elem( 1 ) == rg.nx( jlatS ) ) triag_nodes[1] = node_numbering.at( offset_loc.at( ilatS ) ); + if ( elem( 3 ) == rg.nx( jlatN ) ) triag_nodes[2] = node_numbering.at( offset_loc.at( ilatN ) ); } } jcell = triag_begin + jtriag++; @@ -1092,12 +1092,12 @@ void StructuredMeshGenerator::generate_mesh( const grid::StructuredGrid& rg, con } if ( include_north_pole ) { - int ilat = 0; - int ip1 = 0; - size_t nlon = rg.nx( 0 ) - ( periodic_east_west ? 0 : 1 ); - for ( size_t ip2 = 0; ip2 < nlon; ++ip2 ) { - jcell = triag_begin + jtriag++; - size_t ip3 = ip2 + 1; + idx_t ilat = 0; + idx_t ip1 = 0; + idx_t nlon = rg.nx( 0 ) - ( periodic_east_west ? 0 : 1 ); + for ( idx_t ip2 = 0; ip2 < nlon; ++ip2 ) { + jcell = triag_begin + jtriag++; + idx_t ip3 = ip2 + 1; if ( three_dimensional && ip3 == rg.nx( 0 ) ) ip3 = 0; triag_nodes[0] = node_numbering.at( jnorth + ip1 ); triag_nodes[1] = node_numbering.at( offset_loc.at( ilat ) + ip2 ); @@ -1108,13 +1108,13 @@ void StructuredMeshGenerator::generate_mesh( const grid::StructuredGrid& rg, con } } else if ( patch_north_pole ) { - int jlat = 0; - int ilat = 0; - int ip1, ip2, ip3; + idx_t jlat = 0; + idx_t ilat = 0; + idx_t ip1, ip2, ip3; - int jforward = 0; - int jbackward = rg.nx( jlat ) - 1; - bool forward = true; + idx_t jforward = 0; + idx_t jbackward = rg.nx( jlat ) - 1; + bool forward = true; while ( true ) { if ( forward ) { @@ -1153,11 +1153,11 @@ void StructuredMeshGenerator::generate_mesh( const grid::StructuredGrid& rg, con } if ( include_south_pole ) { - int jlat = rg.ny() - 1; - int ilat = region.south - region.north; - int ip1 = 0; - size_t nlon = rg.nx( jlat ) + 1 - ( periodic_east_west ? 0 : 1 ); - for ( size_t ip2 = 1; ip2 < nlon; ++ip2 ) { + idx_t jlat = rg.ny() - 1; + idx_t ilat = region.south - region.north; + idx_t ip1 = 0; + idx_t nlon = rg.nx( jlat ) + 1 - ( periodic_east_west ? 0 : 1 ); + for ( idx_t ip2 = 1; ip2 < nlon; ++ip2 ) { jcell = triag_begin + jtriag++; int ip3 = ip2 - 1; triag_nodes[0] = node_numbering.at( jsouth + ip1 ); @@ -1171,13 +1171,13 @@ void StructuredMeshGenerator::generate_mesh( const grid::StructuredGrid& rg, con } } else if ( patch_south_pole ) { - int jlat = rg.ny() - 1; - int ilat = region.south - region.north; - int ip1, ip2, ip3; + idx_t jlat = rg.ny() - 1; + idx_t ilat = region.south - region.north; + idx_t ip1, ip2, ip3; - int jforward = 0; - int jbackward = rg.nx( jlat ) - 1; - bool forward = true; + idx_t jforward = 0; + idx_t jbackward = rg.nx( jlat ) - 1; + bool forward = true; while ( true ) { if ( forward ) { @@ -1219,8 +1219,7 @@ void StructuredMeshGenerator::generate_mesh( const grid::StructuredGrid& rg, con namespace { static MeshGeneratorBuilder __Structured( "structured" ); -} +} // namespace -} // namespace detail } // namespace meshgenerator } // namespace atlas diff --git a/src/atlas/meshgenerator/StructuredMeshGenerator.h b/src/atlas/meshgenerator/detail/StructuredMeshGenerator.h similarity index 67% rename from src/atlas/meshgenerator/StructuredMeshGenerator.h rename to src/atlas/meshgenerator/detail/StructuredMeshGenerator.h index 928eabf05..ae397dbfd 100644 --- a/src/atlas/meshgenerator/StructuredMeshGenerator.h +++ b/src/atlas/meshgenerator/detail/StructuredMeshGenerator.h @@ -11,6 +11,7 @@ #pragma once #include "atlas/meshgenerator/MeshGenerator.h" +#include "atlas/meshgenerator/detail/MeshGeneratorImpl.h" #include "atlas/util/Config.h" #include "atlas/util/Metadata.h" @@ -23,8 +24,8 @@ class Mesh; } namespace atlas { -namespace grid { class StructuredGrid; +namespace grid { class Distribution; } // namespace grid } // namespace atlas @@ -32,8 +33,6 @@ class Distribution; namespace atlas { namespace meshgenerator { -namespace detail { - struct Region; //---------------------------------------------------------------------------------------------------------------------- @@ -52,28 +51,16 @@ class StructuredMeshGenerator : public MeshGenerator::Implementation { void configure_defaults(); - void generate_region( const grid::StructuredGrid&, const std::vector& parts, int mypart, - Region& region ) const; + void generate_region( const StructuredGrid&, const std::vector& parts, int mypart, Region& region ) const; - void generate_mesh_new( const grid::StructuredGrid&, const std::vector& parts, const Region& region, - Mesh& m ) const; + void generate_mesh_new( const StructuredGrid&, const std::vector& parts, const Region& region, Mesh& m ) const; - void generate_mesh( const grid::StructuredGrid&, const std::vector& parts, const Region& region, - Mesh& m ) const; + void generate_mesh( const StructuredGrid&, const std::vector& parts, const Region& region, Mesh& m ) const; private: util::Metadata options; }; -} // namespace detail - -class StructuredMeshGenerator : public MeshGenerator { -public: - StructuredMeshGenerator( const eckit::Parametrisation& config = util::NoConfig() ) : - MeshGenerator( "structured", config ) {} - StructuredMeshGenerator( const MeshGenerator& m ) : MeshGenerator( m ) {} -}; - //---------------------------------------------------------------------------------------------------------------------- } // namespace meshgenerator diff --git a/src/atlas/numerics/Method.cc b/src/atlas/numerics/Method.cc index 0f4a15f01..67ff673c2 100644 --- a/src/atlas/numerics/Method.cc +++ b/src/atlas/numerics/Method.cc @@ -8,11 +8,9 @@ * nor does it submit to any jurisdiction. */ -#include "eckit/exception/Exceptions.h" - -#include "atlas/library/config.h" #include "atlas/numerics/Method.h" -#include "atlas/runtime/ErrorHandling.h" +#include "atlas/library/config.h" +#include "atlas/runtime/Exception.h" namespace atlas { namespace numerics { @@ -22,12 +20,14 @@ namespace numerics { // C wrapper interfaces to C++ routines extern "C" { void atlas__Method__delete( Method* This ) { - ATLAS_ERROR_HANDLING( ASSERT( This ); delete This; This = 0; ); + ATLAS_ASSERT( This != nullptr ); + delete This; + This = nullptr; } const char* atlas__Method__name( Method* This ) { - ATLAS_ERROR_HANDLING( ASSERT( This ); return This->name().c_str(); ); - return 0; + ATLAS_ASSERT( This != nullptr ); + return This->name().c_str(); } } diff --git a/src/atlas/numerics/Method.h b/src/atlas/numerics/Method.h index 9a30354aa..c02d77ef3 100644 --- a/src/atlas/numerics/Method.h +++ b/src/atlas/numerics/Method.h @@ -12,14 +12,14 @@ #include -#include "eckit/memory/Owned.h" +#include "atlas/util/Object.h" namespace atlas { namespace numerics { /// @brief Method class /// @note Abstract base class -class Method : public eckit::Owned { +class Method : public util::Object { public: Method() {} virtual ~Method() = 0; diff --git a/src/atlas/numerics/Nabla.cc b/src/atlas/numerics/Nabla.cc index a27bf3262..c01511376 100644 --- a/src/atlas/numerics/Nabla.cc +++ b/src/atlas/numerics/Nabla.cc @@ -11,7 +11,6 @@ #include #include -#include "eckit/exception/Exceptions.h" #include "eckit/thread/AutoLock.h" #include "eckit/thread/Mutex.h" @@ -20,14 +19,14 @@ #include "atlas/numerics/Nabla.h" #include "atlas/numerics/fvm/Method.h" #include "atlas/numerics/fvm/Nabla.h" -#include "atlas/runtime/ErrorHandling.h" +#include "atlas/runtime/Exception.h" #include "atlas/runtime/Log.h" #include "atlas/util/Config.h" namespace { -static eckit::Mutex* local_mutex = 0; -static std::map* m = 0; +static eckit::Mutex* local_mutex = nullptr; +static std::map* m = nullptr; static pthread_once_t once = PTHREAD_ONCE_INIT; static void init() { @@ -39,34 +38,28 @@ static void init() { namespace atlas { namespace numerics { -NablaImpl::NablaImpl( const Method& method, const eckit::Parametrisation& p ) {} +NablaImpl::NablaImpl( const Method&, const eckit::Parametrisation& ) {} NablaImpl::~NablaImpl() {} -Nabla::Nabla() : nabla_( nullptr ) {} - -Nabla::Nabla( const Nabla::nabla_t* nabla ) : nabla_( nabla ) {} - -Nabla::Nabla( const Nabla& nabla ) : nabla_( nabla.nabla_ ) {} - -Nabla::Nabla( const Method& method, const eckit::Parametrisation& p ) : nabla_( NablaFactory::build( method, p ) ) {} +Nabla::Nabla( const Method& method, const eckit::Parametrisation& p ) : Handle( NablaFactory::build( method, p ) ) {} Nabla::Nabla( const Method& method ) : Nabla( method, util::NoConfig() ) {} void Nabla::gradient( const Field& scalar, Field& grad ) const { - nabla_->gradient( scalar, grad ); + get()->gradient( scalar, grad ); } void Nabla::divergence( const Field& vector, Field& div ) const { - nabla_->divergence( vector, div ); + get()->divergence( vector, div ); } void Nabla::curl( const Field& vector, Field& curl ) const { - nabla_->curl( vector, curl ); + get()->curl( vector, curl ); } void Nabla::laplacian( const Field& scalar, Field& laplacian ) const { - nabla_->laplacian( scalar, laplacian ); + get()->laplacian( scalar, laplacian ); } namespace { @@ -87,7 +80,7 @@ NablaFactory::NablaFactory( const std::string& name ) : name_( name ) { eckit::AutoLock lock( local_mutex ); - ASSERT( m->find( name ) == m->end() ); + ATLAS_ASSERT( m->find( name ) == m->end() ); ( *m )[name] = this; } @@ -136,7 +129,7 @@ const NablaImpl* NablaFactory::build( const Method& method, const eckit::Paramet Log::error() << "NablaFactories are:" << '\n'; for ( j = m->begin(); j != m->end(); ++j ) Log::error() << " " << ( *j ).first << '\n'; - throw eckit::SeriousBug( std::string( "No NablaFactory called " ) + method.name() ); + throw_Exception( std::string( "No NablaFactory called " ) + method.name() ); } return ( *j ).second->make( method, p ); @@ -144,39 +137,57 @@ const NablaImpl* NablaFactory::build( const Method& method, const eckit::Paramet extern "C" { -void atlas__Nabla__delete( Nabla::nabla_t* This ) { - ATLAS_ERROR_HANDLING( ASSERT( This ); delete This; ); +void atlas__Nabla__delete( Nabla::Implementation* This ) { + ATLAS_ASSERT( This != nullptr, "Cannot access uninitialisd atlas_numerics_Nabla" ); + delete This; } -const Nabla::nabla_t* atlas__Nabla__create( const Method* method, const eckit::Parametrisation* params ) { - const Nabla::nabla_t* nabla( 0 ); - ATLAS_ERROR_HANDLING( ASSERT( method ); ASSERT( params ); { - Nabla n( *method, *params ); +const Nabla::Implementation* atlas__Nabla__create( const Method* method, const eckit::Parametrisation* config ) { + ATLAS_ASSERT( method != nullptr, "Cannot access uninitialisd atlas_numerics_Method" ); + ATLAS_ASSERT( config != nullptr, "Cannot access uninitialisd atlas_Config" ); + const Nabla::Implementation* nabla( nullptr ); + { + Nabla n( *method, *config ); nabla = n.get(); nabla->attach(); - } nabla->detach(); ); + } + nabla->detach(); return nabla; } -void atlas__Nabla__gradient( const Nabla::nabla_t* This, const field::FieldImpl* scalar, field::FieldImpl* grad ) { - ATLAS_ERROR_HANDLING( ASSERT( This ); ASSERT( scalar ); ASSERT( grad ); Field fgrad( grad ); - This->gradient( scalar, fgrad ); ); +void atlas__Nabla__gradient( const Nabla::Implementation* This, const field::FieldImpl* scalar, + field::FieldImpl* grad ) { + ATLAS_ASSERT( This != nullptr, "Cannot access uninitialisd atlas_numerics_Nabla" ); + ATLAS_ASSERT( scalar != nullptr, "Cannot access uninitialisd atlas_Field" ); + ATLAS_ASSERT( grad != nullptr, "Cannot access uninitialisd atlas_Field" ); + Field fgrad( grad ); + This->gradient( scalar, fgrad ); } -void atlas__Nabla__divergence( const Nabla::nabla_t* This, const field::FieldImpl* vector, field::FieldImpl* div ) { - ATLAS_ERROR_HANDLING( ASSERT( This ); ASSERT( vector ); ASSERT( div ); Field fdiv( div ); - This->divergence( vector, fdiv ); ); +void atlas__Nabla__divergence( const Nabla::Implementation* This, const field::FieldImpl* vector, + field::FieldImpl* div ) { + ATLAS_ASSERT( This != nullptr, "Cannot access uninitialisd atlas_numerics_Nabla" ); + ATLAS_ASSERT( vector != nullptr, "Cannot access uninitialisd atlas_Field" ); + ATLAS_ASSERT( div != nullptr, "Cannot access uninitialisd atlas_Field" ); + Field fdiv( div ); + This->divergence( vector, fdiv ); } -void atlas__Nabla__curl( const Nabla::nabla_t* This, const field::FieldImpl* vector, field::FieldImpl* curl ) { - ATLAS_ERROR_HANDLING( ASSERT( This ); ASSERT( vector ); ASSERT( curl ); Field fcurl( curl ); - This->curl( vector, fcurl ); ); +void atlas__Nabla__curl( const Nabla::Implementation* This, const field::FieldImpl* vector, field::FieldImpl* curl ) { + ATLAS_ASSERT( This != nullptr, "Cannot access uninitialisd atlas_numerics_Nabla" ); + ATLAS_ASSERT( vector != nullptr, "Cannot access uninitialisd atlas_Field" ); + ATLAS_ASSERT( curl != nullptr, "Cannot access uninitialisd atlas_Field" ); + Field fcurl( curl ); + This->curl( vector, fcurl ); } -void atlas__Nabla__laplacian( const Nabla::nabla_t* This, const field::FieldImpl* scalar, +void atlas__Nabla__laplacian( const Nabla::Implementation* This, const field::FieldImpl* scalar, field::FieldImpl* laplacian ) { - ATLAS_ERROR_HANDLING( ASSERT( This ); ASSERT( scalar ); ASSERT( laplacian ); Field flaplacian( laplacian ); - This->laplacian( scalar, flaplacian ); ); + ATLAS_ASSERT( This != nullptr, "Cannot access uninitialisd atlas_numerics_Nabla" ); + ATLAS_ASSERT( scalar != nullptr, "Cannot access uninitialisd atlas_Field" ); + ATLAS_ASSERT( laplacian != nullptr, "Cannot access uninitialisd atlas_Field" ); + Field flaplacian( laplacian ); + This->laplacian( scalar, flaplacian ); } } diff --git a/src/atlas/numerics/Nabla.h b/src/atlas/numerics/Nabla.h index 9674e906d..993a54f2a 100644 --- a/src/atlas/numerics/Nabla.h +++ b/src/atlas/numerics/Nabla.h @@ -10,8 +10,10 @@ #pragma once -#include "eckit/memory/Owned.h" -#include "eckit/memory/SharedPtr.h" +#include + +#include "atlas/util/Object.h" +#include "atlas/util/ObjectHandle.h" namespace eckit { class Parametrisation; @@ -33,7 +35,7 @@ class Field; namespace atlas { namespace numerics { -class NablaImpl : public eckit::Owned { +class NablaImpl : public util::Object { public: NablaImpl( const Method&, const eckit::Parametrisation& ); virtual ~NablaImpl(); @@ -46,17 +48,10 @@ class NablaImpl : public eckit::Owned { // ------------------------------------------------------------------ -class Nabla { -public: - using nabla_t = NablaImpl; - -private: - eckit::SharedPtr nabla_; - +class Nabla : public util::ObjectHandle { public: - Nabla(); - Nabla( const nabla_t* ); - Nabla( const Nabla& nabla ); + using Handle::Handle; + Nabla() = default; Nabla( const Method& ); Nabla( const Method&, const eckit::Parametrisation& ); @@ -64,8 +59,6 @@ class Nabla { void divergence( const Field& vector, Field& div ) const; void curl( const Field& vector, Field& curl ) const; void laplacian( const Field& scalar, Field& laplacian ) const; - - const nabla_t* get() const { return nabla_.get(); } }; // ------------------------------------------------------------------ @@ -76,7 +69,7 @@ class NablaFactory { * \brief build Nabla with factory key, constructor arguments * \return Nabla */ - static const Nabla::nabla_t* build( const Method&, const eckit::Parametrisation& ); + static const Nabla::Implementation* build( const Method&, const eckit::Parametrisation& ); /*! * \brief list all registered field creators @@ -85,7 +78,7 @@ class NablaFactory { static bool has( const std::string& name ); private: - virtual const Nabla::nabla_t* make( const Method&, const eckit::Parametrisation& ) = 0; + virtual const Nabla::Implementation* make( const Method&, const eckit::Parametrisation& ) = 0; protected: NablaFactory( const std::string& ); @@ -103,7 +96,7 @@ class NablaBuilder : public NablaFactory { NablaBuilder( const std::string& name ) : NablaFactory( name ) {} private: - virtual const Nabla::nabla_t* make( const Method& method, const eckit::Parametrisation& p ) { + virtual const Nabla::Implementation* make( const Method& method, const eckit::Parametrisation& p ) { return new T( method, p ); } }; @@ -112,12 +105,15 @@ class NablaBuilder : public NablaFactory { extern "C" { -void atlas__Nabla__delete( Nabla::nabla_t* This ); -const Nabla::nabla_t* atlas__Nabla__create( const Method* method, const eckit::Parametrisation* params ); -void atlas__Nabla__gradient( const Nabla::nabla_t* This, const field::FieldImpl* scalar, field::FieldImpl* grad ); -void atlas__Nabla__divergence( const Nabla::nabla_t* This, const field::FieldImpl* vector, field::FieldImpl* div ); -void atlas__Nabla__curl( const Nabla::nabla_t* This, const field::FieldImpl* vector, field::FieldImpl* curl ); -void atlas__Nabla__laplacian( const Nabla::nabla_t* This, const field::FieldImpl* scalar, field::FieldImpl* laplacian ); +void atlas__Nabla__delete( Nabla::Implementation* This ); +const Nabla::Implementation* atlas__Nabla__create( const Method* method, const eckit::Parametrisation* params ); +void atlas__Nabla__gradient( const Nabla::Implementation* This, const field::FieldImpl* scalar, + field::FieldImpl* grad ); +void atlas__Nabla__divergence( const Nabla::Implementation* This, const field::FieldImpl* vector, + field::FieldImpl* div ); +void atlas__Nabla__curl( const Nabla::Implementation* This, const field::FieldImpl* vector, field::FieldImpl* curl ); +void atlas__Nabla__laplacian( const Nabla::Implementation* This, const field::FieldImpl* scalar, + field::FieldImpl* laplacian ); } } // namespace numerics diff --git a/src/atlas/numerics/fvm/Method.cc b/src/atlas/numerics/fvm/Method.cc index 6eda0ffb7..76204a930 100644 --- a/src/atlas/numerics/fvm/Method.cc +++ b/src/atlas/numerics/fvm/Method.cc @@ -10,8 +10,6 @@ #include -#include "eckit/exception/Exceptions.h" - #include "atlas/array/ArrayView.h" #include "atlas/array/MakeView.h" #include "atlas/functionspace/EdgeColumns.h" @@ -24,7 +22,7 @@ #include "atlas/mesh/actions/BuildParallelFields.h" #include "atlas/numerics/fvm/Method.h" #include "atlas/parallel/omp/omp.h" -#include "atlas/runtime/ErrorHandling.h" +#include "atlas/runtime/Exception.h" #include "atlas/runtime/Trace.h" #include "atlas/util/CoordinateEnums.h" #include "atlas/util/Earth.h" @@ -75,23 +73,24 @@ Method::Method( Mesh& mesh, const eckit::Configuration& params ) : void Method::setup() { ATLAS_TRACE( "fvm::Method::setup " ); - util::Config node_columns_config; - node_columns_config.set( "halo", halo_.size() ); - if ( levels_ ) node_columns_config.set( "levels", levels_ ); - node_columns_ = functionspace::NodeColumns( mesh(), node_columns_config ); - if ( edges_.size() == 0 ) { - ATLAS_TRACE_SCOPE( "build_edges" ) build_edges( mesh() ); - ATLAS_TRACE_SCOPE( "build_pole_edges" ) build_pole_edges( mesh() ); - ATLAS_TRACE_SCOPE( "build_edges_parallel_fields" ) build_edges_parallel_fields( mesh() ); + util::Config config; + config.set( "halo", halo_.size() ); + if ( levels_ ) config.set( "levels", levels_ ); + node_columns_ = functionspace::NodeColumns( mesh(), config ); + edge_columns_ = functionspace::EdgeColumns( mesh(), config ); + + { ATLAS_TRACE_SCOPE( "build_median_dual_mesh" ) build_median_dual_mesh( mesh() ); ATLAS_TRACE_SCOPE( "build_node_to_edge_connectivity" ) build_node_to_edge_connectivity( mesh() ); - const size_t nnodes = nodes_.size(); + const idx_t nnodes = nodes_.size(); + + auto edge_flags = array::make_view( edges_.flags() ); + using Topology = mesh::Nodes::Topology; + auto is_pole_edge = [&]( size_t e ) { return Topology::check( edge_flags( e ), Topology::POLE ); }; // Compute sign { - const array::ArrayView is_pole_edge = array::make_view( edges_.field( "is_pole_edge" ) ); - const mesh::Connectivity& node_edge_connectivity = nodes_.edge_connectivity(); const mesh::MultiBlockConnectivity& edge_node_connectivity = edges_.node_connectivity(); if ( !nodes_.has_field( "node2edge_sign" ) ) { @@ -101,10 +100,10 @@ void Method::setup() { array::ArrayView node2edge_sign = array::make_view( nodes_.field( "node2edge_sign" ) ); - atlas_omp_parallel_for( size_t jnode = 0; jnode < nnodes; ++jnode ) { - for ( size_t jedge = 0; jedge < node_edge_connectivity.cols( jnode ); ++jedge ) { - size_t iedge = node_edge_connectivity( jnode, jedge ); - size_t ip1 = edge_node_connectivity( iedge, 0 ); + atlas_omp_parallel_for( idx_t jnode = 0; jnode < nnodes; ++jnode ) { + for ( idx_t jedge = 0; jedge < node_edge_connectivity.cols( jnode ); ++jedge ) { + idx_t iedge = node_edge_connectivity( jnode, jedge ); + idx_t ip1 = edge_node_connectivity( iedge, 0 ); if ( jnode == ip1 ) node2edge_sign( jnode, jedge ) = 1.; else { @@ -114,50 +113,26 @@ void Method::setup() { } } } - - // Metrics - if ( 0 ) { - const size_t nedges = edges_.size(); - const array::ArrayView lonlat_deg = array::make_view( nodes_.lonlat() ); - array::ArrayView dual_volumes = array::make_view( nodes_.field( "dual_volumes" ) ); - array::ArrayView dual_normals = array::make_view( edges_.field( "dual_normals" ) ); - - const double deg2rad = M_PI / 180.; - atlas_omp_parallel_for( size_t jnode = 0; jnode < nnodes; ++jnode ) { - double y = lonlat_deg( jnode, LAT ) * deg2rad; - double hx = radius_ * std::cos( y ); - double hy = radius_; - double G = hx * hy; - dual_volumes( jnode ) *= std::pow( deg2rad, 2 ) * G; - } - - atlas_omp_parallel_for( size_t jedge = 0; jedge < nedges; ++jedge ) { - dual_normals( jedge, LON ) *= deg2rad; - dual_normals( jedge, LAT ) *= deg2rad; - } - } } - edge_columns_ = functionspace::EdgeColumns( mesh() ); } // ------------------------------------------------------------------------------------------ extern "C" { -Method* atlas__numerics__fvm__Method__new( Mesh::Implementation* mesh, const eckit::Configuration* params ) { - Method* method( 0 ); - ATLAS_ERROR_HANDLING( ASSERT( mesh ); Mesh m( mesh ); method = new Method( m, *params ); ); - return method; +Method* atlas__numerics__fvm__Method__new( Mesh::Implementation* mesh, const eckit::Configuration* config ) { + ATLAS_ASSERT( mesh != nullptr, "Cannot access uninitialised atlas_Mesh" ); + ATLAS_ASSERT( config != nullptr, "Cannot access uninitialised atlas_Config" ); + Mesh m( mesh ); + return new Method( m, *config ); } const functionspace::detail::NodeColumns* atlas__numerics__fvm__Method__functionspace_nodes( Method* This ) { - ATLAS_ERROR_HANDLING( - ASSERT( This ); return dynamic_cast( This->node_columns().get() ); ); - return 0; + ATLAS_ASSERT( This != nullptr, "Cannot access uninitialisd atlas_Method" ); + return dynamic_cast( This->node_columns().get() ); } const functionspace::detail::EdgeColumns* atlas__numerics__fvm__Method__functionspace_edges( Method* This ) { - ATLAS_ERROR_HANDLING( - ASSERT( This ); return dynamic_cast( This->edge_columns().get() ); ); - return 0; + ATLAS_ASSERT( This != nullptr, "Cannot access uninitialisd atlas_Method" ); + return dynamic_cast( This->edge_columns().get() ); } } // ------------------------------------------------------------------------------------------ diff --git a/src/atlas/numerics/fvm/Nabla.cc b/src/atlas/numerics/fvm/Nabla.cc index 676127c8e..129d83e7a 100644 --- a/src/atlas/numerics/fvm/Nabla.cc +++ b/src/atlas/numerics/fvm/Nabla.cc @@ -9,7 +9,6 @@ */ #include "eckit/config/Parametrisation.h" -#include "eckit/exception/Exceptions.h" #include "atlas/array/ArrayView.h" #include "atlas/array/MakeView.h" @@ -20,6 +19,7 @@ #include "atlas/numerics/fvm/Method.h" #include "atlas/numerics/fvm/Nabla.h" #include "atlas/parallel/omp/omp.h" +#include "atlas/runtime/Exception.h" #include "atlas/runtime/Log.h" #include "atlas/util/CoordinateEnums.h" @@ -37,9 +37,9 @@ static NablaBuilder __fvm_nabla( "fvm" ); } Nabla::Nabla( const numerics::Method& method, const eckit::Parametrisation& p ) : - atlas::numerics::Nabla::nabla_t( method, p ) { + atlas::numerics::NablaImpl( method, p ) { fvm_ = dynamic_cast( &method ); - if ( !fvm_ ) throw eckit::BadCast( "atlas::numerics::fvm::Nabla needs a atlas::numerics::fvm::Method", Here() ); + if ( !fvm_ ) throw_Exception( "atlas::numerics::fvm::Nabla needs a atlas::numerics::fvm::Method", Here() ); Log::debug() << "Nabla constructed for method " << fvm_->name() << " with " << fvm_->node_columns().nb_nodes_global() << " nodes total" << std::endl; @@ -51,19 +51,20 @@ Nabla::~Nabla() {} void Nabla::setup() { const mesh::Edges& edges = fvm_->mesh().edges(); - const size_t nedges = edges.size(); + const idx_t nedges = fvm_->edge_columns().nb_edges(); - const array::ArrayView edge_is_pole = array::make_view( edges.field( "is_pole_edge" ) ); + const auto edge_flags = array::make_view( edges.flags() ); + auto is_pole_edge = [&]( idx_t e ) { return Topology::check( edge_flags( e ), Topology::POLE ); }; // Filter pole_edges out of all edges - std::vector tmp( nedges ); - size_t c( 0 ); - for ( size_t jedge = 0; jedge < nedges; ++jedge ) { - if ( edge_is_pole( jedge ) ) tmp[c++] = jedge; + std::vector tmp( nedges ); + idx_t c( 0 ); + for ( idx_t jedge = 0; jedge < nedges; ++jedge ) { + if ( is_pole_edge( jedge ) ) tmp[c++] = jedge; } pole_edges_.clear(); pole_edges_.reserve( c ); - for ( size_t jedge = 0; jedge < c; ++jedge ) + for ( idx_t jedge = 0; jedge < c; ++jedge ) pole_edges_.push_back( tmp[jedge] ); } @@ -82,11 +83,11 @@ void Nabla::gradient_of_scalar( const Field& scalar_field, Field& grad_field ) c const mesh::Edges& edges = fvm_->mesh().edges(); const mesh::Nodes& nodes = fvm_->mesh().nodes(); - const size_t nnodes = nodes.size(); - const size_t nedges = edges.size(); - const size_t nlev = scalar_field.levels() ? scalar_field.levels() : 1; + const idx_t nnodes = fvm_->node_columns().nb_nodes(); + const idx_t nedges = fvm_->edge_columns().nb_edges(); + const idx_t nlev = scalar_field.levels() ? scalar_field.levels() : 1; if ( ( grad_field.levels() ? grad_field.levels() : 1 ) != nlev ) - throw eckit::AssertionFailed( "gradient field should have same number of levels", Here() ); + throw_AssertionFailed( "gradient field should have same number of levels", Here() ); const auto scalar = scalar_field.levels() ? array::make_view( scalar_field ).slice( Range::all(), Range::all() ) @@ -109,34 +110,36 @@ void Nabla::gradient_of_scalar( const Field& scalar_field, Field& grad_field ) c const double scale = deg2rad * deg2rad * radius; atlas_omp_parallel { - atlas_omp_for( size_t jedge = 0; jedge < nedges; ++jedge ) { - int ip1 = edge2node( jedge, 0 ); - int ip2 = edge2node( jedge, 1 ); + atlas_omp_for( idx_t jedge = 0; jedge < nedges; ++jedge ) { + idx_t ip1 = edge2node( jedge, 0 ); + idx_t ip2 = edge2node( jedge, 1 ); - for ( size_t jlev = 0; jlev < nlev; ++jlev ) { + for ( idx_t jlev = 0; jlev < nlev; ++jlev ) { double avg = ( scalar( ip1, jlev ) + scalar( ip2, jlev ) ) * 0.5; avgS( jedge, jlev, LON ) = dual_normals( jedge, LON ) * deg2rad * avg; avgS( jedge, jlev, LAT ) = dual_normals( jedge, LAT ) * deg2rad * avg; } } - atlas_omp_for( size_t jnode = 0; jnode < nnodes; ++jnode ) { - for ( size_t jlev = 0; jlev < nlev; ++jlev ) { + atlas_omp_for( idx_t jnode = 0; jnode < nnodes; ++jnode ) { + for ( idx_t jlev = 0; jlev < nlev; ++jlev ) { grad( jnode, jlev, LON ) = 0.; grad( jnode, jlev, LAT ) = 0.; } - for ( size_t jedge = 0; jedge < node2edge.cols( jnode ); ++jedge ) { - const int iedge = node2edge( jnode, jedge ); - const double add = node2edge_sign( jnode, jedge ); - for ( size_t jlev = 0; jlev < nlev; ++jlev ) { - grad( jnode, jlev, LON ) += add * avgS( iedge, jlev, LON ); - grad( jnode, jlev, LAT ) += add * avgS( iedge, jlev, LAT ); + for ( idx_t jedge = 0; jedge < node2edge.cols( jnode ); ++jedge ) { + const idx_t iedge = node2edge( jnode, jedge ); + if ( iedge < nedges ) { + const double add = node2edge_sign( jnode, jedge ); + for ( idx_t jlev = 0; jlev < nlev; ++jlev ) { + grad( jnode, jlev, LON ) += add * avgS( iedge, jlev, LON ); + grad( jnode, jlev, LAT ) += add * avgS( iedge, jlev, LAT ); + } } } const double y = lonlat_deg( jnode, LAT ) * deg2rad; const double metric_y = 1. / ( dual_volumes( jnode ) * scale ); const double metric_x = metric_y / std::cos( y ); - for ( size_t jlev = 0; jlev < nlev; ++jlev ) { + for ( idx_t jlev = 0; jlev < nlev; ++jlev ) { grad( jnode, jlev, LON ) *= metric_x; grad( jnode, jlev, LAT ) *= metric_y; } @@ -154,11 +157,11 @@ void Nabla::gradient_of_vector( const Field& vector_field, Field& grad_field ) c const mesh::Edges& edges = fvm_->mesh().edges(); const mesh::Nodes& nodes = fvm_->mesh().nodes(); - const size_t nnodes = nodes.size(); - const size_t nedges = edges.size(); - const size_t nlev = vector_field.levels(); + const idx_t nnodes = fvm_->node_columns().nb_nodes(); + const idx_t nedges = fvm_->edge_columns().nb_edges(); + const idx_t nlev = vector_field.levels(); if ( vector_field.levels() != nlev ) - throw eckit::AssertionFailed( "gradient field should have same number of levels", Here() ); + throw_AssertionFailed( "gradient field should have same number of levels", Here() ); const auto vector = vector_field.levels() @@ -168,11 +171,12 @@ void Nabla::gradient_of_vector( const Field& vector_field, Field& grad_field ) c ? array::make_view( grad_field ).slice( Range::all(), Range::all(), Range::all() ) : array::make_view( grad_field ).slice( Range::all(), Range::dummy(), Range::all() ); - const array::ArrayView lonlat_deg = array::make_view( nodes.lonlat() ); - const array::ArrayView dual_volumes = array::make_view( nodes.field( "dual_volumes" ) ); - const array::ArrayView dual_normals = array::make_view( edges.field( "dual_normals" ) ); - const array::ArrayView edge_is_pole = array::make_view( edges.field( "is_pole_edge" ) ); - const array::ArrayView node2edge_sign = array::make_view( nodes.field( "node2edge_sign" ) ); + const auto lonlat_deg = array::make_view( nodes.lonlat() ); + const auto dual_volumes = array::make_view( nodes.field( "dual_volumes" ) ); + const auto dual_normals = array::make_view( edges.field( "dual_normals" ) ); + const auto node2edge_sign = array::make_view( nodes.field( "node2edge_sign" ) ); + const auto edge_flags = array::make_view( edges.flags() ); + auto is_pole_edge = [&]( idx_t e ) { return Topology::check( edge_flags( e ), Topology::POLE ); }; const mesh::Connectivity& node2edge = nodes.edge_connectivity(); const mesh::MultiBlockConnectivity& edge2node = edges.node_connectivity(); @@ -191,12 +195,12 @@ void Nabla::gradient_of_vector( const Field& vector_field, Field& grad_field ) c }; atlas_omp_parallel { - atlas_omp_for( size_t jedge = 0; jedge < nedges; ++jedge ) { - int ip1 = edge2node( jedge, 0 ); - int ip2 = edge2node( jedge, 1 ); - double pbc = 1. - 2. * edge_is_pole( jedge ); + atlas_omp_for( idx_t jedge = 0; jedge < nedges; ++jedge ) { + idx_t ip1 = edge2node( jedge, 0 ); + idx_t ip2 = edge2node( jedge, 1 ); + double pbc = 1. - 2. * is_pole_edge( jedge ); - for ( size_t jlev = 0; jlev < nlev; ++jlev ) { + for ( idx_t jlev = 0; jlev < nlev; ++jlev ) { double avg[2] = {( vector( ip1, jlev, LON ) + pbc * vector( ip2, jlev, LON ) ) * 0.5, ( vector( ip1, jlev, LAT ) + pbc * vector( ip2, jlev, LAT ) ) * 0.5}; avgS( jedge, jlev, LONdLON ) = dual_normals( jedge, LON ) * deg2rad * avg[LON]; @@ -208,27 +212,29 @@ void Nabla::gradient_of_vector( const Field& vector_field, Field& grad_field ) c } } - atlas_omp_for( size_t jnode = 0; jnode < nnodes; ++jnode ) { - for ( size_t jlev = 0; jlev < nlev; ++jlev ) { + atlas_omp_for( idx_t jnode = 0; jnode < nnodes; ++jnode ) { + for ( idx_t jlev = 0; jlev < nlev; ++jlev ) { grad( jnode, jlev, LONdLON ) = 0.; grad( jnode, jlev, LONdLAT ) = 0.; grad( jnode, jlev, LATdLON ) = 0.; grad( jnode, jlev, LATdLAT ) = 0.; } - for ( size_t jedge = 0; jedge < node2edge.cols( jnode ); ++jedge ) { - const int iedge = node2edge( jnode, jedge ); - double add = node2edge_sign( jnode, jedge ); - for ( size_t jlev = 0; jlev < nlev; ++jlev ) { - grad( jnode, jlev, LONdLON ) += add * avgS( iedge, jlev, LONdLON ); - grad( jnode, jlev, LONdLAT ) += add * avgS( iedge, jlev, LONdLAT ); - grad( jnode, jlev, LATdLON ) += add * avgS( iedge, jlev, LATdLON ); - grad( jnode, jlev, LATdLAT ) += add * avgS( iedge, jlev, LATdLAT ); + for ( idx_t jedge = 0; jedge < node2edge.cols( jnode ); ++jedge ) { + const idx_t iedge = node2edge( jnode, jedge ); + if ( iedge < nedges ) { + double add = node2edge_sign( jnode, jedge ); + for ( idx_t jlev = 0; jlev < nlev; ++jlev ) { + grad( jnode, jlev, LONdLON ) += add * avgS( iedge, jlev, LONdLON ); + grad( jnode, jlev, LONdLAT ) += add * avgS( iedge, jlev, LONdLAT ); + grad( jnode, jlev, LATdLON ) += add * avgS( iedge, jlev, LATdLON ); + grad( jnode, jlev, LATdLAT ) += add * avgS( iedge, jlev, LATdLAT ); + } } } const double y = lonlat_deg( jnode, LAT ) * deg2rad; const double metric_y = 1. / ( dual_volumes( jnode ) * scale ); const double metric_x = metric_y / std::cos( y ); - for ( size_t jlev = 0; jlev < nlev; ++jlev ) { + for ( idx_t jlev = 0; jlev < nlev; ++jlev ) { grad( jnode, jlev, LONdLON ) *= metric_x; grad( jnode, jlev, LATdLON ) *= metric_x; grad( jnode, jlev, LONdLAT ) *= metric_y; @@ -238,10 +244,10 @@ void Nabla::gradient_of_vector( const Field& vector_field, Field& grad_field ) c } // Fix wrong node2edge_sign for vector quantities for ( size_t jedge = 0; jedge < pole_edges_.size(); ++jedge ) { - const int iedge = pole_edges_[jedge]; - const int jnode = edge2node( iedge, 1 ); + const idx_t iedge = pole_edges_[jedge]; + const idx_t jnode = edge2node( iedge, 1 ); const double metric_y = 1. / ( dual_volumes( jnode ) * scale ); - for ( size_t jlev = 0; jlev < nlev; ++jlev ) { + for ( idx_t jlev = 0; jlev < nlev; ++jlev ) { grad( jnode, jlev, LONdLAT ) -= 2. * avgS( iedge, jlev, LONdLAT ) * metric_y; grad( jnode, jlev, LATdLAT ) -= 2. * avgS( iedge, jlev, LATdLAT ) * metric_y; } @@ -257,11 +263,11 @@ void Nabla::divergence( const Field& vector_field, Field& div_field ) const { const mesh::Edges& edges = fvm_->mesh().edges(); const mesh::Nodes& nodes = fvm_->mesh().nodes(); - const size_t nnodes = nodes.size(); - const size_t nedges = edges.size(); - const size_t nlev = vector_field.levels(); + const idx_t nnodes = fvm_->node_columns().nb_nodes(); + const idx_t nedges = fvm_->edge_columns().nb_edges(); + const idx_t nlev = vector_field.levels(); if ( div_field.levels() != nlev ) - throw eckit::AssertionFailed( "divergence field should have same number of levels", Here() ); + throw_AssertionFailed( "divergence field should have same number of levels", Here() ); const auto vector = vector_field.levels() @@ -270,11 +276,13 @@ void Nabla::divergence( const Field& vector_field, Field& div_field ) const { auto div = div_field.levels() ? array::make_view( div_field ).slice( Range::all(), Range::all() ) : array::make_view( div_field ).slice( Range::all(), Range::dummy() ); - const auto lonlat_deg = array::make_view( nodes.lonlat() ); - const auto dual_volumes = array::make_view( nodes.field( "dual_volumes" ) ); - const auto dual_normals = array::make_view( edges.field( "dual_normals" ) ); - const auto edge_is_pole = array::make_view( edges.field( "is_pole_edge" ) ); - const auto node2edge_sign = array::make_view( nodes.field( "node2edge_sign" ) ); + const auto lonlat_deg = array::make_view( nodes.lonlat() ); + const auto dual_volumes = array::make_view( nodes.field( "dual_volumes" ) ); + const auto dual_normals = array::make_view( edges.field( "dual_normals" ) ); + const auto node2edge_sign = array::make_view( nodes.field( "node2edge_sign" ) ); + const auto edge_flags = array::make_view( edges.flags() ); + auto is_pole_edge = [&]( idx_t e ) { return Topology::check( edge_flags( e ), Topology::POLE ); }; + const mesh::Connectivity& node2edge = nodes.edge_connectivity(); const mesh::MultiBlockConnectivity& edge2node = edges.node_connectivity(); @@ -284,17 +292,17 @@ void Nabla::divergence( const Field& vector_field, Field& div_field ) const { const double scale = deg2rad * deg2rad * radius; atlas_omp_parallel { - atlas_omp_for( size_t jedge = 0; jedge < nedges; ++jedge ) { - size_t ip1 = edge2node( jedge, 0 ); - size_t ip2 = edge2node( jedge, 1 ); + atlas_omp_for( idx_t jedge = 0; jedge < nedges; ++jedge ) { + idx_t ip1 = edge2node( jedge, 0 ); + idx_t ip2 = edge2node( jedge, 1 ); double y1 = lonlat_deg( ip1, LAT ) * deg2rad; double y2 = lonlat_deg( ip2, LAT ) * deg2rad; double cosy1 = std::cos( y1 ); double cosy2 = std::cos( y2 ); - double pbc = 1. - edge_is_pole( jedge ); + double pbc = 1. - is_pole_edge( jedge ); - for ( size_t jlev = 0; jlev < nlev; ++jlev ) { + for ( idx_t jlev = 0; jlev < nlev; ++jlev ) { double avg[2] = { ( vector( ip1, jlev, LON ) + vector( ip2, jlev, LON ) ) * 0.5, ( cosy1 * vector( ip1, jlev, LAT ) + cosy2 * vector( ip2, jlev, LAT ) ) * 0.5 * @@ -310,20 +318,22 @@ void Nabla::divergence( const Field& vector_field, Field& div_field ) const { } } - atlas_omp_for( size_t jnode = 0; jnode < nnodes; ++jnode ) { - for ( size_t jlev = 0; jlev < nlev; ++jlev ) { + atlas_omp_for( idx_t jnode = 0; jnode < nnodes; ++jnode ) { + for ( idx_t jlev = 0; jlev < nlev; ++jlev ) { div( jnode, jlev ) = 0.; } - for ( size_t jedge = 0; jedge < node2edge.cols( jnode ); ++jedge ) { - int iedge = node2edge( jnode, jedge ); - double add = node2edge_sign( jnode, jedge ); - for ( size_t jlev = 0; jlev < nlev; ++jlev ) { - div( jnode, jlev ) += add * ( avgS( iedge, jlev, LON ) + avgS( iedge, jlev, LAT ) ); + for ( idx_t jedge = 0; jedge < node2edge.cols( jnode ); ++jedge ) { + idx_t iedge = node2edge( jnode, jedge ); + if ( iedge < nedges ) { + double add = node2edge_sign( jnode, jedge ); + for ( idx_t jlev = 0; jlev < nlev; ++jlev ) { + div( jnode, jlev ) += add * ( avgS( iedge, jlev, LON ) + avgS( iedge, jlev, LAT ) ); + } } } const double y = lonlat_deg( jnode, LAT ) * deg2rad; double metric = 1. / ( dual_volumes( jnode ) * scale * std::cos( y ) ); - for ( size_t jlev = 0; jlev < nlev; ++jlev ) { + for ( idx_t jlev = 0; jlev < nlev; ++jlev ) { div( jnode, jlev ) *= metric; } } @@ -337,11 +347,10 @@ void Nabla::curl( const Field& vector_field, Field& curl_field ) const { const mesh::Edges& edges = fvm_->mesh().edges(); const mesh::Nodes& nodes = fvm_->mesh().nodes(); - const size_t nnodes = nodes.size(); - const size_t nedges = edges.size(); - const size_t nlev = vector_field.levels(); - if ( curl_field.levels() != nlev ) - throw eckit::AssertionFailed( "curl field should have same number of levels", Here() ); + const idx_t nnodes = fvm_->node_columns().nb_nodes(); + const idx_t nedges = fvm_->edge_columns().nb_edges(); + const idx_t nlev = vector_field.levels(); + if ( curl_field.levels() != nlev ) throw_AssertionFailed( "curl field should have same number of levels", Here() ); const auto vector = vector_field.levels() @@ -353,8 +362,9 @@ void Nabla::curl( const Field& vector_field, Field& curl_field ) const { const auto lonlat_deg = array::make_view( nodes.lonlat() ); const auto dual_volumes = array::make_view( nodes.field( "dual_volumes" ) ); const auto dual_normals = array::make_view( edges.field( "dual_normals" ) ); - const auto edge_is_pole = array::make_view( edges.field( "is_pole_edge" ) ); const auto node2edge_sign = array::make_view( nodes.field( "node2edge_sign" ) ); + const auto edge_flags = array::make_view( edges.flags() ); + auto is_pole_edge = [&]( idx_t e ) { return Topology::check( edge_flags( e ), Topology::POLE ); }; const mesh::Connectivity& node2edge = nodes.edge_connectivity(); const mesh::MultiBlockConnectivity& edge2node = edges.node_connectivity(); @@ -365,17 +375,17 @@ void Nabla::curl( const Field& vector_field, Field& curl_field ) const { const double scale = deg2rad * deg2rad * radius * radius; atlas_omp_parallel { - atlas_omp_for( size_t jedge = 0; jedge < nedges; ++jedge ) { - size_t ip1 = edge2node( jedge, 0 ); - size_t ip2 = edge2node( jedge, 1 ); + atlas_omp_for( idx_t jedge = 0; jedge < nedges; ++jedge ) { + idx_t ip1 = edge2node( jedge, 0 ); + idx_t ip2 = edge2node( jedge, 1 ); double y1 = lonlat_deg( ip1, LAT ) * deg2rad; double y2 = lonlat_deg( ip2, LAT ) * deg2rad; double rcosy1 = radius * std::cos( y1 ); double rcosy2 = radius * std::cos( y2 ); - double pbc = 1 - edge_is_pole( jedge ); + double pbc = 1 - is_pole_edge( jedge ); - for ( size_t jlev = 0; jlev < nlev; ++jlev ) { + for ( idx_t jlev = 0; jlev < nlev; ++jlev ) { double avg[2] = {( rcosy1 * vector( ip1, jlev, LON ) + rcosy2 * vector( ip2, jlev, LON ) ) * 0.5 * pbc, // (force R*cos(y)=0 at pole) ( radius * vector( ip1, jlev, LAT ) + radius * vector( ip2, jlev, LAT ) ) * 0.5}; @@ -389,20 +399,22 @@ void Nabla::curl( const Field& vector_field, Field& curl_field ) const { } } - atlas_omp_for( size_t jnode = 0; jnode < nnodes; ++jnode ) { - for ( size_t jlev = 0; jlev < nlev; ++jlev ) { + atlas_omp_for( idx_t jnode = 0; jnode < nnodes; ++jnode ) { + for ( idx_t jlev = 0; jlev < nlev; ++jlev ) { curl( jnode, jlev ) = 0.; } - for ( size_t jedge = 0; jedge < node2edge.cols( jnode ); ++jedge ) { - size_t iedge = node2edge( jnode, jedge ); - double add = node2edge_sign( jnode, jedge ); - for ( size_t jlev = 0; jlev < nlev; ++jlev ) { - curl( jnode, jlev ) += add * ( avgS( iedge, jlev, LAT ) - avgS( iedge, jlev, LON ) ); + for ( idx_t jedge = 0; jedge < node2edge.cols( jnode ); ++jedge ) { + idx_t iedge = node2edge( jnode, jedge ); + if ( iedge < nedges ) { + double add = node2edge_sign( jnode, jedge ); + for ( idx_t jlev = 0; jlev < nlev; ++jlev ) { + curl( jnode, jlev ) += add * ( avgS( iedge, jlev, LAT ) - avgS( iedge, jlev, LON ) ); + } } } double y = lonlat_deg( jnode, LAT ) * deg2rad; double metric = 1. / ( dual_volumes( jnode ) * scale * std::cos( y ) ); - for ( size_t jlev = 0; jlev < nlev; ++jlev ) { + for ( idx_t jlev = 0; jlev < nlev; ++jlev ) { curl( jnode, jlev ) *= metric; } } diff --git a/src/atlas/numerics/fvm/Nabla.h b/src/atlas/numerics/fvm/Nabla.h index b17f7c553..f12356b36 100644 --- a/src/atlas/numerics/fvm/Nabla.h +++ b/src/atlas/numerics/fvm/Nabla.h @@ -30,7 +30,7 @@ namespace atlas { namespace numerics { namespace fvm { -class Nabla : public atlas::numerics::Nabla::nabla_t { +class Nabla : public atlas::numerics::NablaImpl { public: Nabla( const atlas::numerics::Method&, const eckit::Parametrisation& ); virtual ~Nabla(); diff --git a/src/atlas/option/Options.cc b/src/atlas/option/Options.cc index 3f3abd011..922f9dd97 100644 --- a/src/atlas/option/Options.cc +++ b/src/atlas/option/Options.cc @@ -8,7 +8,9 @@ * nor does it submit to any jurisdiction. */ -#include "atlas/option/Options.h" +#include "Options.h" + +#include "atlas/runtime/Exception.h" #include "atlas/util/Earth.h" // ---------------------------------------------------------------------------- @@ -53,6 +55,11 @@ variables::variables( size_t _variables ) { set( "variables", _variables ); } +vector::vector( size_t _components ) { + set( "variables", _components ); + set( "type", "vector" ); +} + radius::radius( double _radius ) { set( "radius", _radius ); } @@ -60,10 +67,14 @@ radius::radius( double _radius ) { radius::radius( const std::string& key ) { if ( key == "Earth" ) { set( "radius", util::Earth::radius() ); } else { - NOTIMP; + ATLAS_NOTIMPLEMENTED; } } +pole_edges::pole_edges( bool _pole_edges ) { + set( "pole_edges", _pole_edges ); +} + // ---------------------------------------------------------------------------- } // namespace option diff --git a/src/atlas/option/Options.h b/src/atlas/option/Options.h index 10239c357..9ed0b3e04 100644 --- a/src/atlas/option/Options.h +++ b/src/atlas/option/Options.h @@ -48,6 +48,13 @@ class variables : public util::Config { // ---------------------------------------------------------------------------- +class vector : public util::Config { +public: + vector( size_t = 2 ); +}; + +// ---------------------------------------------------------------------------- + class name : public util::Config { public: name( const std::string& ); @@ -85,6 +92,13 @@ class radius : public util::Config { radius( const std::string& = "Earth" ); }; +// --------------------------------- + +class pole_edges : public util::Config { +public: + pole_edges( bool = true ); +}; + // ---------------------------------------------------------------------------- // Definitions // ---------------------------------------------------------------------------- diff --git a/src/atlas/option/TransOptions.cc b/src/atlas/option/TransOptions.cc index d9aa0565e..84930b13e 100644 --- a/src/atlas/option/TransOptions.cc +++ b/src/atlas/option/TransOptions.cc @@ -8,8 +8,11 @@ * nor does it submit to any jurisdiction. */ +#include + +#include "eckit/filesystem/PathName.h" + #include "atlas/option/TransOptions.h" -#include "atlas/grid.h" // ---------------------------------------------------------------------------- diff --git a/src/atlas/option/TransOptions.h b/src/atlas/option/TransOptions.h index 74e71bd86..5f0d7d8af 100644 --- a/src/atlas/option/TransOptions.h +++ b/src/atlas/option/TransOptions.h @@ -12,6 +12,10 @@ #include "atlas/util/Config.h" +namespace eckit { +class PathName; +} + // ---------------------------------------------------------------------------- namespace atlas { diff --git a/src/atlas/output/Gmsh.cc b/src/atlas/output/Gmsh.cc index ae003a6be..d977ebb7b 100644 --- a/src/atlas/output/Gmsh.cc +++ b/src/atlas/output/Gmsh.cc @@ -11,8 +11,6 @@ #include #include -#include "eckit/exception/Exceptions.h" - #include "atlas/field/Field.h" #include "atlas/field/FieldSet.h" #include "atlas/functionspace/FunctionSpace.h" @@ -21,7 +19,7 @@ #include "atlas/mesh/actions/BuildXYZField.h" #include "atlas/output/Gmsh.h" #include "atlas/output/detail/GmshIO.h" -#include "atlas/runtime/ErrorHandling.h" +#include "atlas/runtime/Exception.h" #include "atlas/runtime/Log.h" using atlas::Field; @@ -148,17 +146,17 @@ void Gmsh::setGmshConfiguration( detail::GmshIO& gmsh, const Gmsh::Configuration // ----------------------------------------------------------------------------- -Gmsh::Gmsh( Stream& stream ) { +Gmsh::Gmsh( Stream& ) { defaults(); - NOTIMP; + ATLAS_NOTIMPLEMENTED; } // ----------------------------------------------------------------------------- -Gmsh::Gmsh( Stream& stream, const eckit::Parametrisation& config ) { +Gmsh::Gmsh( Stream&, const eckit::Parametrisation& config ) { defaults(); merge( config_, config ); - NOTIMP; + ATLAS_NOTIMPLEMENTED; } // ----------------------------------------------------------------------------- @@ -254,15 +252,11 @@ void Gmsh::write( const FieldSet& fields, const FunctionSpace& functionspace, extern "C" { Gmsh* atlas__output__Gmsh__create_pathname_mode( const char* pathname, const char* mode ) { - Gmsh* gmsh( 0 ); - ATLAS_ERROR_HANDLING( gmsh = new Gmsh( std::string( pathname ), std::string( mode ) ) ); - return gmsh; + return new Gmsh( std::string( pathname ), std::string( mode ) ); } Gmsh* atlas__output__Gmsh__create_pathname_mode_config( const char* pathname, const char* mode, - const Parametrisation* params ) { - Gmsh* gmsh( 0 ); - ATLAS_ERROR_HANDLING( gmsh = new Gmsh( std::string( pathname ), std::string( mode ), *params ) ); - return gmsh; + const Parametrisation* config ) { + return new Gmsh( std::string( pathname ), std::string( mode ), *config ); } } // extern C diff --git a/src/atlas/output/Gmsh.h b/src/atlas/output/Gmsh.h index 989460551..cd513bb3a 100644 --- a/src/atlas/output/Gmsh.h +++ b/src/atlas/output/Gmsh.h @@ -10,6 +10,8 @@ #pragma once +#include + #include "atlas/output/Output.h" #include "atlas/parallel/mpi/mpi.h" #include "atlas/util/Config.h" @@ -36,7 +38,7 @@ class GmshFileStream : public std::ofstream { // ----------------------------------------------------------------------------- namespace detail { -class Gmsh : public Output::output_t { +class Gmsh : public OutputImpl { public: Gmsh( Stream& ); Gmsh( Stream&, const eckit::Parametrisation& ); diff --git a/src/atlas/output/Output.cc b/src/atlas/output/Output.cc index 575217b03..8837ad2e6 100644 --- a/src/atlas/output/Output.cc +++ b/src/atlas/output/Output.cc @@ -11,7 +11,6 @@ #include #include -#include "eckit/exception/Exceptions.h" #include "eckit/thread/AutoLock.h" #include "eckit/thread/Mutex.h" @@ -21,7 +20,7 @@ #include "atlas/mesh/Mesh.h" #include "atlas/output/Gmsh.h" #include "atlas/output/Output.h" -#include "atlas/runtime/ErrorHandling.h" +#include "atlas/runtime/Exception.h" #include "atlas/runtime/Log.h" using atlas::FieldSet; @@ -34,8 +33,8 @@ using eckit::Parametrisation; namespace atlas { namespace output { -static eckit::Mutex* local_mutex = 0; -static std::map* m = 0; +static eckit::Mutex* local_mutex = nullptr; +static std::map* m = nullptr; static pthread_once_t once = PTHREAD_ONCE_INIT; static void init() { @@ -47,45 +46,39 @@ OutputImpl::OutputImpl() {} OutputImpl::~OutputImpl() {} -Output::Output() : output_( nullptr ) {} - -Output::Output( const output_t* output ) : output_( output ) {} - -Output::Output( const Output& output ) : output_( output.output_ ) {} - Output::Output( const std::string& key, Stream& stream, const eckit::Parametrisation& params ) : - output_( OutputFactory::build( key, stream, params ) ) {} + Handle( OutputFactory::build( key, stream, params ) ) {} /// Write mesh file void Output::write( const Mesh& m, const eckit::Parametrisation& c ) const { - return output_->write( m, c ); + return get()->write( m, c ); } /// Write field to file void Output::write( const Field& f, const eckit::Parametrisation& c ) const { - return output_->write( f, c ); + return get()->write( f, c ); } /// Write fieldset to file using FunctionSpace void Output::write( const FieldSet& f, const eckit::Parametrisation& c ) const { - return output_->write( f, c ); + return get()->write( f, c ); } /// Write field to file using Functionspace void Output::write( const Field& f, const FunctionSpace& fs, const eckit::Parametrisation& c ) const { - return output_->write( f, fs, c ); + return get()->write( f, fs, c ); } /// Write fieldset to file using FunctionSpace void Output::write( const FieldSet& f, const FunctionSpace& fs, const eckit::Parametrisation& c ) const { - return output_->write( f, fs, c ); + return get()->write( f, fs, c ); } OutputFactory::OutputFactory( const std::string& name ) : name_( name ) { pthread_once( &once, init ); eckit::AutoLock lock( local_mutex ); - if ( m->find( name ) != m->end() ) { throw eckit::SeriousBug( "Duplicate OutputFactory entry " + name ); } + if ( m->find( name ) != m->end() ) { throw_Exception( "Duplicate OutputFactory entry " + name ); } ( *m )[name] = this; } @@ -120,7 +113,7 @@ const OutputImpl* OutputFactory::build( const std::string& name, Stream& stream Log::error() << "OutputFactories are:" << std::endl; for ( j = m->begin(); j != m->end(); ++j ) Log::error() << " " << ( *j ).first << std::endl; - throw eckit::SeriousBug( std::string( "No OutputFactory called " ) + name ); + throw_Exception( std::string( "No OutputFactory called " ) + name ); } return ( *j ).second->make( stream ); @@ -139,7 +132,7 @@ const OutputImpl* OutputFactory::build( const std::string& name, Stream& stream, Log::error() << "OutputFactories are:" << std::endl; for ( j = m->begin(); j != m->end(); ++j ) Log::error() << " " << ( *j ).first << std::endl; - throw eckit::SeriousBug( std::string( "No OutputFactory called " ) + name ); + throw_Exception( std::string( "No OutputFactory called " ) + name ); } return ( *j ).second->make( stream, param ); @@ -148,44 +141,57 @@ const OutputImpl* OutputFactory::build( const std::string& name, Stream& stream, extern "C" { void atlas__Output__delete( OutputImpl* This ) { - ATLAS_ERROR_HANDLING( ASSERT( This ); delete This; ); + ATLAS_ASSERT( This != nullptr, "Cannot access uninitialisd atlas_Output" ); + delete This; } const OutputImpl* atlas__Output__create( const char* factory_key, Stream* stream, - const eckit::Parametrisation* params ) { - const OutputImpl* output( 0 ); - ATLAS_ERROR_HANDLING( - // ASSERT(stream); - ASSERT( params ); { - Output o( std::string{factory_key}, *stream, *params ); - output = o.get(); - output->attach(); - } output->detach(); ); + const eckit::Parametrisation* config ) { + ATLAS_ASSERT( config != nullptr, "Cannot access uninitialisd atlas_Config" ); + const OutputImpl* output( nullptr ); + { + Output o( std::string{factory_key}, *stream, *config ); + output = o.get(); + output->attach(); + } + output->detach(); return output; } void atlas__Output__write_mesh( const OutputImpl* This, Mesh::Implementation* mesh, const Parametrisation* params ) { - ATLAS_ERROR_HANDLING( ASSERT( This ); ASSERT( mesh ); ASSERT( params ); Mesh m( mesh ); - This->write( m, *params ); ); + ATLAS_ASSERT( This != nullptr, "Cannot access uninitialisd atlas_Output" ); + Mesh m( mesh ); + This->write( m, *params ); } void atlas__Output__write_fieldset( const OutputImpl* This, const FieldSetImpl* fieldset, - const Parametrisation* params ) { - ATLAS_ERROR_HANDLING( ASSERT( This ); ASSERT( fieldset ); ASSERT( params ); This->write( fieldset, *params ); ); + const Parametrisation* config ) { + ATLAS_ASSERT( This != nullptr, "Cannot access uninitialisd atlas_Output" ); + ATLAS_ASSERT( fieldset != nullptr, "Cannot access uninitialisd atlas_FieldSet" ); + This->write( fieldset, *config ); } -void atlas__Output__write_field( const OutputImpl* This, const FieldImpl* field, const Parametrisation* params ) { - ATLAS_ERROR_HANDLING( ASSERT( This ); ASSERT( field ); ASSERT( params ); This->write( field, *params ); ); +void atlas__Output__write_field( const OutputImpl* This, const FieldImpl* field, const Parametrisation* config ) { + ATLAS_ASSERT( This != nullptr, "Cannot access uninitialisd atlas_Output" ); + ATLAS_ASSERT( field != nullptr, "Cannot access uninitialisd atlas_Field" ); + ATLAS_ASSERT( config != nullptr, "Cannot access uninitialisd atlas_Config" ); + This->write( field, *config ); } void atlas__Output__write_fieldset_fs( const OutputImpl* This, const FieldSetImpl* fieldset, const functionspace::FunctionSpaceImpl* functionspace, const Parametrisation* params ) { - ATLAS_ERROR_HANDLING( ASSERT( This ); ASSERT( fieldset ); ASSERT( functionspace ); ASSERT( params ); - This->write( fieldset, functionspace, *params ); ); + ATLAS_ASSERT( This != nullptr, "Cannot access uninitialisd atlas_Output" ); + ATLAS_ASSERT( fieldset != nullptr, "Cannot access uninitialisd atlas_FieldSet" ); + ATLAS_ASSERT( functionspace != nullptr, "Cannot access uninitialisd atlas_FunctionSpace" ); + + This->write( fieldset, functionspace, *params ); } void atlas__Output__write_field_fs( const OutputImpl* This, const FieldImpl* field, const functionspace::FunctionSpaceImpl* functionspace, - const Parametrisation* params ) { - ATLAS_ERROR_HANDLING( ASSERT( This ); ASSERT( field ); ASSERT( functionspace ); ASSERT( params ); - This->write( field, functionspace, *params ); ); + const Parametrisation* config ) { + ATLAS_ASSERT( This != nullptr, "Cannot access uninitialisd atlas_Output" ); + ATLAS_ASSERT( field != nullptr, "Cannot access uninitialisd atlas_Field" ); + ATLAS_ASSERT( functionspace != nullptr, "Cannot access uninitialisd atlas_FunctionSpace" ); + ATLAS_ASSERT( config != nullptr, "Cannot access uninitialisd atlas_Config" ); + This->write( field, functionspace, *config ); } } diff --git a/src/atlas/output/Output.h b/src/atlas/output/Output.h index 72b04e874..2488f602e 100644 --- a/src/atlas/output/Output.h +++ b/src/atlas/output/Output.h @@ -14,11 +14,11 @@ #include #include "eckit/config/Parametrisation.h" -#include "eckit/memory/Owned.h" -#include "eckit/memory/SharedPtr.h" #include "eckit/serialisation/FileStream.h" #include "atlas/util/Config.h" +#include "atlas/util/Object.h" +#include "atlas/util/ObjectHandle.h" namespace eckit { class Parametrisation; @@ -27,7 +27,12 @@ class PathName; namespace atlas { class Mesh; +namespace mesh { +namespace detail { +class MeshImpl; } +} // namespace mesh +} // namespace atlas namespace atlas { class Field; @@ -53,7 +58,7 @@ typedef eckit::PathName PathName; // ----------------------------------------------------------------------------- -class OutputImpl : public eckit::Owned { +class OutputImpl : public util::Object { public: typedef atlas::util::Config Parameters; @@ -80,17 +85,10 @@ class OutputImpl : public eckit::Owned { const eckit::Parametrisation& = util::NoConfig() ) const = 0; }; -class Output { -public: - using output_t = OutputImpl; - -private: - eckit::SharedPtr output_; - +class Output : public util::ObjectHandle { public: - Output(); - Output( const output_t* ); - Output( const Output& ); + using Handle::Handle; + Output() = default; Output( const std::string&, Stream&, const eckit::Parametrisation& = util::NoConfig() ); /// Write mesh file @@ -107,8 +105,6 @@ class Output { /// Write fieldset to file using FunctionSpace void write( const FieldSet&, const FunctionSpace&, const eckit::Parametrisation& = util::NoConfig() ) const; - - const output_t* get() const { return output_.get(); } }; class OutputFactory { @@ -158,7 +154,7 @@ extern "C" { void atlas__Output__delete( OutputImpl* This ); const OutputImpl* atlas__Output__create( const char* factory_key, Stream* stream, const eckit::Parametrisation* params ); -void atlas__Output__write_mesh( const OutputImpl* This, Mesh::Implementation* mesh, +void atlas__Output__write_mesh( const OutputImpl* This, mesh::detail::MeshImpl* mesh, const eckit::Parametrisation* params ); void atlas__Output__write_fieldset( const OutputImpl* This, const field::FieldSetImpl* fieldset, const eckit::Parametrisation* params ); diff --git a/src/atlas/output/detail/GmshIO.cc b/src/atlas/output/detail/GmshIO.cc index 456bafead..7c2874301 100644 --- a/src/atlas/output/detail/GmshIO.cc +++ b/src/atlas/output/detail/GmshIO.cc @@ -14,7 +14,6 @@ #include #include -#include "eckit/exception/Exceptions.h" #include "eckit/filesystem/PathName.h" #include "atlas/array.h" @@ -32,6 +31,7 @@ #include "atlas/output/detail/GmshIO.h" #include "atlas/parallel/GatherScatter.h" #include "atlas/parallel/mpi/mpi.h" +#include "atlas/runtime/Exception.h" #include "atlas/runtime/Log.h" #include "atlas/util/Constants.h" #include "atlas/util/CoordinateEnums.h" @@ -50,14 +50,16 @@ static double rad2deg = util::Constants::radiansToDegrees(); class GmshFile : public std::ofstream { public: - GmshFile( const PathName& file_path, std::ios_base::openmode mode, int part = atlas::mpi::comm().rank() ) { + GmshFile( const PathName& file_path, std::ios_base::openmode mode, + int part = static_cast( mpi::comm().rank() ) ) { PathName par_path( file_path ); + int mpi_size = static_cast( mpi::comm().size() ); if ( atlas::mpi::comm().size() == 1 || part == -1 ) { std::ofstream::open( par_path.localPath(), mode ); } else { if ( atlas::mpi::comm().rank() == 0 ) { PathName par_path( file_path ); std::ofstream par_file( par_path.localPath(), std::ios_base::out ); - for ( size_t p = 0; p < atlas::mpi::comm().size(); ++p ) { + for ( int p = 0; p < mpi_size; ++p ) { PathName loc_path( file_path ); // loc_path = loc_path.baseName(false) + "_p" + to_str(p) + ".msh"; loc_path = loc_path.baseName( false ) + ".msh.p" + std::to_string( p ); @@ -125,15 +127,15 @@ void write_level( std::ostream& out, const array::ArrayView gidx, int ndata = data.shape( 0 ); int nvars = data.shape( 1 ); if ( nvars == 1 ) { - for ( size_t n = 0; n < ndata; ++n ) { + for ( idx_t n = 0; n < ndata; ++n ) { out << gidx( n ) << " " << data( n, 0 ) << "\n"; } } else if ( nvars <= 3 ) { std::vector data_vec( 3, 0. ); - for ( size_t n = 0; n < ndata; ++n ) { + for ( idx_t n = 0; n < ndata; ++n ) { out << gidx( n ); - for ( size_t v = 0; v < nvars; ++v ) + for ( idx_t v = 0; v < nvars; ++v ) data_vec[v] = data( n, v ); for ( int v = 0; v < 3; ++v ) out << " " << data_vec[v]; @@ -143,7 +145,7 @@ void write_level( std::ostream& out, const array::ArrayView gidx, else if ( nvars <= 9 ) { std::vector data_vec( 9, 0. ); if ( nvars == 4 ) { - for ( size_t n = 0; n < ndata; ++n ) { + for ( int n = 0; n < ndata; ++n ) { for ( int i = 0; i < 2; ++i ) { for ( int j = 0; j < 2; ++j ) { data_vec[i * 3 + j] = data( n, i * 2 + j ); @@ -156,7 +158,7 @@ void write_level( std::ostream& out, const array::ArrayView gidx, } } else if ( nvars == 9 ) { - for ( size_t n = 0; n < ndata; ++n ) { + for ( int n = 0; n < ndata; ++n ) { for ( int i = 0; i < 3; ++i ) { for ( int j = 0; j < 3; ++j ) { data_vec[i * 3 + j] = data( n, i * 2 + j ); @@ -169,21 +171,21 @@ void write_level( std::ostream& out, const array::ArrayView gidx, } } else { - NOTIMP; + ATLAS_NOTIMPLEMENTED; } } else { - NOTIMP; + ATLAS_NOTIMPLEMENTED; } } -std::vector get_levels( int nlev, const Metadata& gmsh_options ) { - std::vector lev; - std::vector gmsh_levels; +std::vector get_levels( int nlev, const Metadata& gmsh_options ) { + std::vector lev; + std::vector gmsh_levels; gmsh_options.get( "levels", gmsh_levels ); if ( gmsh_levels.empty() || nlev == 1 ) { lev.resize( nlev ); - for ( size_t ilev = 0; ilev < nlev; ++ilev ) + for ( int ilev = 0; ilev < nlev; ++ilev ) lev[ilev] = ilev; } else { @@ -231,10 +233,10 @@ void write_field_nodes( const Metadata& gmsh_options, const functionspace::NodeC Log::debug() << "writing NodeColumns field " << field.name() << " defined in NodeColumns..." << std::endl; bool gather( gmsh_options.get( "gather" ) && atlas::mpi::comm().size() > 1 ); - bool binary( !gmsh_options.get( "ascii" ) ); - size_t nlev = std::max( 1, field.levels() ); - size_t ndata = std::min( function_space.nb_nodes(), field.shape( 0 ) ); - size_t nvars = std::max( 1, field.variables() ); + // unused: bool binary( !gmsh_options.get( "ascii" ) ); + idx_t nlev = std::max( 1, field.levels() ); + idx_t ndata = std::min( function_space.nb_nodes(), field.shape( 0 ) ); + idx_t nvars = std::max( 1, field.variables() ); array::ArrayView gidx = array::make_view( function_space.nodes().global_index() ); Field gidx_glb; Field field_glb; @@ -246,12 +248,12 @@ void write_field_nodes( const Metadata& gmsh_options, const functionspace::NodeC field_glb = function_space.createField( field, option::global() ); function_space.gather( field, field_glb ); - ndata = std::min( function_space.nb_nodes_global(), field_glb.shape( 0 ) ); + ndata = std::min( function_space.nb_nodes_global(), field_glb.shape( 0 ) ); } - std::vector lev = get_levels( nlev, gmsh_options ); + std::vector lev = get_levels( nlev, gmsh_options ); for ( size_t ilev = 0; ilev < lev.size(); ++ilev ) { - size_t jlev = lev[ilev]; + int jlev = lev[ilev]; if ( ( gather && atlas::mpi::comm().rank() == 0 ) || !gather ) { out << "$NodeData\n"; out << "1\n"; @@ -272,6 +274,20 @@ void write_field_nodes( const Metadata& gmsh_options, const functionspace::NodeC } // ---------------------------------------------------------------------------- +void print_field_lev( char field_lev[], int jlev ) { + std::sprintf( field_lev, "[%03d]", jlev ); +} + +/* unused +void print_field_lev( char field_lev[], long jlev ) { + std::sprintf( field_lev, "[%03ld]", jlev ); +} + +void print_field_lev( char field_lev[], unsigned long jlev ) { + std::sprintf( field_lev, "[%03lu]", jlev ); +} +**/ + // ---------------------------------------------------------------------------- template void write_field_nodes( const Metadata& gmsh_options, const functionspace::StructuredColumns& function_space, @@ -279,11 +295,11 @@ void write_field_nodes( const Metadata& gmsh_options, const functionspace::Struc Log::debug() << "writing StructuredColumns field " << field.name() << "..." << std::endl; bool gather( gmsh_options.get( "gather" ) && atlas::mpi::comm().size() > 1 ); - bool binary( !gmsh_options.get( "ascii" ) ); - size_t nlev = std::max( 1, field.levels() ); - size_t ndata = std::min( function_space.sizeOwned(), field.shape( 0 ) ); - size_t nvars = std::max( 1, field.variables() ); - auto gidx = array::make_view( function_space.global_index() ); + // unused: bool binary( !gmsh_options.get( "ascii" ) ); + idx_t nlev = std::max( 1, field.levels() ); + idx_t ndata = std::min( function_space.sizeOwned(), field.shape( 0 ) ); + idx_t nvars = std::max( 1, field.variables() ); + auto gidx = array::make_view( function_space.global_index() ); Field gidx_glb; Field field_glb; if ( gather ) { @@ -297,16 +313,12 @@ void write_field_nodes( const Metadata& gmsh_options, const functionspace::Struc ndata = field_glb.shape( 0 ); } - std::vector lev = get_levels( nlev, gmsh_options ); + std::vector lev = get_levels( nlev, gmsh_options ); for ( size_t ilev = 0; ilev < lev.size(); ++ilev ) { - size_t jlev = lev[ilev]; + int jlev = lev[ilev]; char field_lev[6] = {0, 0, 0, 0, 0, 0}; - if ( field.levels() ) { std::sprintf( field_lev, "[%03lu]", jlev ); } - - double time = field.metadata().has( "time" ) ? field.metadata().get( "time" ) : 0.; - - int step = field.metadata().has( "step" ) ? field.metadata().get( "step" ) : 0; + if ( field.levels() ) { print_field_lev( field_lev, jlev ); } out << "$NodeData\n"; out << "1\n"; @@ -501,14 +513,14 @@ mesh::ElementType* make_element_type( int type ) { if ( type == QUAD ) return new mesh::temporary::Quadrilateral(); if ( type == TRIAG ) return new mesh::temporary::Triangle(); if ( type == LINE ) return new mesh::temporary::Line(); - throw eckit::SeriousBug( "Element type not supported", Here() ); + throw_Exception( "Element type not supported", Here() ); } } // namespace void GmshIO::read( const PathName& file_path, Mesh& mesh ) const { std::ifstream file; file.open( file_path.localPath(), std::ios::in | std::ios::binary ); - if ( !file.is_open() ) throw eckit::CantOpenFile( file_path ); + if ( !file.is_open() ) throw_CantOpenFile( file_path ); std::string line; @@ -523,7 +535,7 @@ void GmshIO::read( const PathName& file_path, Mesh& mesh ) const { std::getline( file, line ); // Create nodes - size_t nb_nodes; + idx_t nb_nodes; file >> nb_nodes; mesh.nodes().resize( nb_nodes ); @@ -545,7 +557,7 @@ void GmshIO::read( const PathName& file_path, Mesh& mesh ) const { gidx_t max_glb_idx = 0; while ( binary && file.peek() == '\n' ) file.get(); - for ( size_t n = 0; n < nb_nodes; ++n ) { + for ( idx_t n = 0; n < nb_nodes; ++n ) { if ( binary ) { file.read( reinterpret_cast( &g ), sizeof( int ) ); file.read( reinterpret_cast( &xyz ), sizeof( double ) * 3 ); @@ -567,7 +579,7 @@ void GmshIO::read( const PathName& file_path, Mesh& mesh ) const { zmax = std::max( z, zmax ); } if ( xmax < 4 * M_PI && zmax == 0. ) { - for ( size_t n = 0; n < nb_nodes; ++n ) { + for ( idx_t n = 0; n < nb_nodes; ++n ) { coords( n, XX ) *= rad2deg; coords( n, YY ) *= rad2deg; } @@ -672,7 +684,7 @@ void GmshIO::read( const PathName& file_path, Mesh& mesh ) const { part = std::max( part, *std::max_element( tags + 3, tags + ntags - 1 ) ); // one positive, others negative - int enodes[4]; + idx_t enodes[4]; switch ( etype ) { case ( QUAD ): @@ -710,7 +722,7 @@ void GmshIO::read( const PathName& file_path, Mesh& mesh ) const { break; default: std::cout << "etype " << etype << std::endl; - throw eckit::Exception( "ERROR: element type not supported", Here() ); + throw_Exception( "ERROR: element type not supported", Here() ); } } } @@ -728,9 +740,12 @@ void GmshIO::write( const Mesh& mesh, const PathName& file_path ) const { array::ArrayView coords = array::make_view( nodes.field( nodes_field ) ); array::ArrayView glb_idx = array::make_view( nodes.global_index() ); - const size_t surfdim = coords.shape( 1 ); // nb of variables in coords + const idx_t surfdim = coords.shape( 1 ); // nb of variables in coords + + bool include_patch = ( surfdim == 3 ); - ASSERT( surfdim == 2 || surfdim == 3 ); + + ATLAS_ASSERT( surfdim == 2 || surfdim == 3 ); Log::debug() << "writing mesh to gmsh file " << file_path << std::endl; @@ -747,14 +762,14 @@ void GmshIO::write( const Mesh& mesh, const PathName& file_path ) const { write_header_ascii( file ); // Nodes - const size_t nb_nodes = nodes.size(); + const idx_t nb_nodes = nodes.size(); file << "$Nodes\n"; file << nb_nodes << "\n"; double xyz[3] = {0., 0., 0.}; - for ( size_t n = 0; n < nb_nodes; ++n ) { + for ( idx_t n = 0; n < nb_nodes; ++n ) { gidx_t g = glb_idx( n ); - for ( size_t d = 0; d < surfdim; ++d ) + for ( idx_t d = 0; d < surfdim; ++d ) xyz[d] = coords( n, d ); if ( binary ) { @@ -775,24 +790,29 @@ void GmshIO::write( const Mesh& mesh, const PathName& file_path ) const { if ( options.get( "elements" ) ) grouped_elements.push_back( &mesh.cells() ); if ( options.get( "edges" ) ) grouped_elements.push_back( &mesh.edges() ); - size_t nb_elements( 0 ); - for ( size_t jgroup = 0; jgroup < grouped_elements.size(); ++jgroup ) { - const mesh::HybridElements& hybrid = *grouped_elements[jgroup]; - nb_elements += hybrid.size(); - if ( !include_ghost ) { - const array::ArrayView hybrid_halo = array::make_view( hybrid.halo() ); - for ( size_t e = 0; e < hybrid.size(); ++e ) { - if ( hybrid_halo( e ) ) --nb_elements; - } + idx_t nb_elements( 0 ); + for ( const mesh::HybridElements* hybrid : grouped_elements ) { + nb_elements += hybrid->size(); + const array::ArrayView hybrid_halo = array::make_view( hybrid->halo() ); + const array::ArrayView hybrid_flags = array::make_view( hybrid->flags() ); + auto hybrid_patch = [&]( idx_t e ) { + return mesh::Nodes::Topology::check( hybrid_flags( e ), mesh::Nodes::Topology::PATCH ); + }; + auto exclude = [&]( idx_t e ) { + if ( !include_ghost && hybrid_halo( e ) ) return true; + if ( !include_patch && hybrid_patch( e ) ) return true; + return false; + }; + for ( idx_t e = 0; e < hybrid->size(); ++e ) { + if ( exclude( e ) ) { --nb_elements; } } } file << nb_elements << "\n"; - for ( size_t jgroup = 0; jgroup < grouped_elements.size(); ++jgroup ) { - const mesh::HybridElements& hybrid = *grouped_elements[jgroup]; - for ( size_t etype = 0; etype < hybrid.nb_types(); ++etype ) { - const mesh::Elements& elements = hybrid.elements( etype ); + for ( const mesh::HybridElements* hybrid : grouped_elements ) { + for ( idx_t etype = 0; etype < hybrid->nb_types(); ++etype ) { + const mesh::Elements& elements = hybrid->elements( etype ); const mesh::ElementType& element_type = elements.element_type(); int gmsh_elem_type; if ( element_type.name() == "Line" ) @@ -802,7 +822,7 @@ void GmshIO::write( const Mesh& mesh, const PathName& file_path ) const { else if ( element_type.name() == "Quadrilateral" ) gmsh_elem_type = 3; else - NOTIMP; + ATLAS_NOTIMPLEMENTED; const mesh::BlockConnectivity& node_connectivity = elements.node_connectivity(); @@ -811,9 +831,9 @@ void GmshIO::write( const Mesh& mesh, const PathName& file_path ) const { auto elems_halo = elements.view( elements.halo() ); if ( binary ) { - size_t nb_elems = elements.size(); + idx_t nb_elems = elements.size(); if ( !include_ghost ) { - for ( size_t elem = 0; elem < elements.size(); ++elem ) { + for ( idx_t elem = 0; elem < elements.size(); ++elem ) { if ( elems_halo( elem ) ) --nb_elems; } } @@ -828,11 +848,11 @@ void GmshIO::write( const Mesh& mesh, const PathName& file_path ) const { data[2] = 1; data[3] = 1; size_t datasize = sizeof( int ) * ( 5 + node_connectivity.cols() ); - for ( size_t elem = 0; elem < elements.size(); ++elem ) { + for ( idx_t elem = 0; elem < nb_elems; ++elem ) { if ( include_ghost || !elems_halo( elem ) ) { data[0] = elems_glb_idx( elem ); data[4] = elems_partition( elem ); - for ( size_t n = 0; n < node_connectivity.cols(); ++n ) + for ( idx_t n = 0; n < node_connectivity.cols(); ++n ) data[5 + n] = glb_idx( node_connectivity( elem, n ) ); file.write( reinterpret_cast( &data ), datasize ); } @@ -842,10 +862,10 @@ void GmshIO::write( const Mesh& mesh, const PathName& file_path ) const { std::stringstream ss_elem_info; ss_elem_info << " " << gmsh_elem_type << " 4 1 1 1 "; std::string elem_info = ss_elem_info.str(); - for ( size_t elem = 0; elem < elements.size(); ++elem ) { + for ( idx_t elem = 0; elem < elements.size(); ++elem ) { if ( include_ghost || !elems_halo( elem ) ) { file << elems_glb_idx( elem ) << elem_info << elems_partition( elem ); - for ( size_t n = 0; n < node_connectivity.cols(); ++n ) { + for ( idx_t n = 0; n < node_connectivity.cols(); ++n ) { file << " " << glb_idx( node_connectivity( elem, n ) ); } file << "\n"; @@ -906,7 +926,7 @@ void GmshIO::write( const Field& field, const PathName& file_path, openmode mode std::stringstream msg; msg << "Field [" << field.name() << "] has no functionspace"; - throw eckit::AssertionFailed( msg.str(), Here() ); + throw_AssertionFailed( msg.str(), Here() ); } if ( functionspace::NodeColumns( field.functionspace() ) ) { @@ -925,7 +945,7 @@ void GmshIO::write( const Field& field, const PathName& file_path, openmode mode << "] but requires a [functionspace::NodeColumns " << "or functionspace::StructuredColumns]"; - throw eckit::AssertionFailed( msg.str(), Here() ); + throw_AssertionFailed( msg.str(), Here() ); } } // ---------------------------------------------------------------------------- @@ -955,13 +975,13 @@ void GmshIO::write_delegate( const FieldSet& fieldset, const functionspace::Node bool binary( !options.get( "ascii" ) ); if ( binary ) mode |= std::ios_base::binary; bool gather = options.has( "gather" ) ? options.get( "gather" ) : false; - GmshFile file( file_path, mode, gather ? -1 : int(atlas::mpi::comm().rank()) ); + GmshFile file( file_path, mode, gather ? -1 : int( atlas::mpi::comm().rank() ) ); // Header if ( is_new_file ) { write_header_ascii( file ); } // field::Fields - for ( size_t field_idx = 0; field_idx < fieldset.size(); ++field_idx ) { + for ( idx_t field_idx = 0; field_idx < fieldset.size(); ++field_idx ) { const Field& field = fieldset[field_idx]; Log::debug() << "writing field " << field.name() << " to gmsh file " << file_path << std::endl; @@ -994,13 +1014,13 @@ void GmshIO::write_delegate( const FieldSet& fieldset, const functionspace::Stru bool gather = options.has( "gather" ) ? options.get( "gather" ) : false; - GmshFile file( file_path, mode, gather ? -1 : int(atlas::mpi::comm().rank()) ); + GmshFile file( file_path, mode, gather ? -1 : int( atlas::mpi::comm().rank() ) ); // Header if ( is_new_file ) write_header_ascii( file ); // field::Fields - for ( size_t field_idx = 0; field_idx < fieldset.size(); ++field_idx ) { + for ( idx_t field_idx = 0; field_idx < fieldset.size(); ++field_idx ) { const Field& field = fieldset[field_idx]; Log::debug() << "writing field " << field.name() << " to gmsh file " << file_path << std::endl; @@ -1032,7 +1052,7 @@ void GmshIO::write( const FieldSet& fieldset, const FunctionSpace& funcspace, co else if ( functionspace::StructuredColumns( funcspace ) ) write_delegate( fieldset, functionspace::StructuredColumns( funcspace ), file_path, mode ); else - NOTIMP; + ATLAS_NOTIMPLEMENTED; } // ---------------------------------------------------------------------------- @@ -1044,7 +1064,7 @@ void GmshIO::write( const Field& field, const FunctionSpace& funcspace, const ec else if ( functionspace::StructuredColumns( funcspace ) ) write_delegate( field, functionspace::StructuredColumns( funcspace ), file_path, mode ); else - NOTIMP; + ATLAS_NOTIMPLEMENTED; } // ---------------------------------------------------------------------------- @@ -1095,14 +1115,14 @@ void GmshFortranInterface::atlas__write_gmsh_mesh( const Mesh::Implementation* m void GmshFortranInterface::atlas__write_gmsh_fieldset( const field::FieldSetImpl* fieldset, functionspace::FunctionSpaceImpl* functionspace, char* file_path, - int mode ) { + int /*mode*/ ) { GmshIO writer; writer.write( fieldset, functionspace, PathName( file_path ) ); } void GmshFortranInterface::atlas__write_gmsh_field( const field::FieldImpl* field, functionspace::FunctionSpaceImpl* functionspace, char* file_path, - int mode ) { + int /*mode*/ ) { GmshIO writer; writer.write( field, functionspace, PathName( file_path ) ); } diff --git a/src/atlas/output/detail/GmshIO.h b/src/atlas/output/detail/GmshIO.h index 64613ceb5..ccf1d1db5 100644 --- a/src/atlas/output/detail/GmshIO.h +++ b/src/atlas/output/detail/GmshIO.h @@ -22,6 +22,13 @@ namespace atlas { class Field; class FieldSet; class Mesh; +namespace field { +class FieldImpl; +class FieldSetImpl; +} // namespace field +namespace functionspace { +class FunctionSpaceImpl; +} } // namespace atlas namespace atlas { diff --git a/src/atlas/output/detail/PointCloudIO.cc b/src/atlas/output/detail/PointCloudIO.cc index 1e24441d7..d5b64d2ee 100644 --- a/src/atlas/output/detail/PointCloudIO.cc +++ b/src/atlas/output/detail/PointCloudIO.cc @@ -13,7 +13,6 @@ #include #include -#include "eckit/exception/Exceptions.h" #include "eckit/filesystem/PathName.h" #include "atlas/array/ArrayView.h" @@ -26,6 +25,8 @@ #include "atlas/mesh/Mesh.h" #include "atlas/mesh/Nodes.h" #include "atlas/output/detail/PointCloudIO.h" +#include "atlas/runtime/Exception.h" +#include "atlas/runtime/Log.h" #include "atlas/util/CoordinateEnums.h" namespace atlas { @@ -69,7 +70,7 @@ Mesh PointCloudIO::read( const eckit::PathName& path, std::vector& // open file and read all of header & data std::ifstream f( path.asString().c_str() ); - if ( !f.is_open() ) throw eckit::CantOpenFile( path.asString() ); + if ( !f.is_open() ) throw_CantOpenFile( path.asString() ); // header, part 1: // determine number of rows/columns @@ -82,12 +83,12 @@ Mesh PointCloudIO::read( const eckit::PathName& path, std::vector& std::stringstream errmsg; errmsg << msg << "beginning of file `" << path << "` not found (expected: PointCloudIO, got: " << line << ")"; - throw eckit::BadParameter( errmsg.str(), Here() ); + throw_Exception( errmsg.str(), Here() ); } - if ( nb_pts == 0 ) throw eckit::BadValue( msg + " invalid number of points (failed: nb_pts>0)" ); - if ( nb_columns < 2 ) throw eckit::BadValue( msg + " invalid number of columns (failed: nb_columns>=2)" ); + if ( nb_pts == 0 ) throw_AssertionFailed( msg + " invalid number of points (failed: nb_pts>0)" ); + if ( nb_columns < 2 ) throw_AssertionFailed( msg + " invalid number of columns (failed: nb_columns>=2)" ); - mesh.nodes().resize( nb_pts ); + mesh.nodes().resize( static_cast( nb_pts ) ); mesh::Nodes& nodes = mesh.nodes(); array::ArrayView xy = array::make_view( nodes.xy() ); @@ -115,8 +116,8 @@ Mesh PointCloudIO::read( const eckit::PathName& path, std::vector& std::vector> fields; for ( size_t j = 0; j < nb_fld; ++j ) { - fields.emplace_back( array::make_view( - nodes.add( Field( vfnames[j], array::make_datatype(), array::make_shape( nb_pts ) ) ) ) ); + fields.emplace_back( array::make_view( nodes.add( Field( + vfnames[j], array::make_datatype(), array::make_shape( static_cast( nb_pts ) ) ) ) ) ); } size_t i, j; // (index for node/row and field/column, out of scope to check @@ -141,12 +142,12 @@ Mesh PointCloudIO::read( const eckit::PathName& path, std::vector& if ( j < nb_fld ) { oss << " Invalid number of fields in data section, on line " << ( i + 1 ) << ", read " << j << " fields, expected " << nb_fld << "."; - throw eckit::BadValue( msg + oss.str() ); + throw_AssertionFailed( msg + oss.str() ); } } if ( i < nb_pts ) { oss << " Invalid number of lines in data section, read " << ( i ) << " lines, expected " << nb_pts << "."; - throw eckit::BadValue( msg + oss.str() ); + throw_AssertionFailed( msg + oss.str() ); } f.close(); @@ -171,13 +172,13 @@ void PointCloudIO::write( const eckit::PathName& path, const Mesh& mesh ) { const mesh::Nodes& nodes = mesh.nodes(); const array::ArrayView lonlat = array::make_view( nodes.lonlat() ); - if ( !lonlat.size() ) throw eckit::BadParameter( msg + "invalid number of points (failed: nb_pts>0)" ); + if ( !lonlat.size() ) throw_Exception( msg + "invalid number of points (failed: nb_pts>0)" ); // get the fields (sanitized) names and values // (bypasses fields ("lonlat"|"lonlat") as shape(1)!=1) std::vector vfnames; std::vector> vfvalues; - for ( size_t i = 0; i < nodes.nb_fields(); ++i ) { + for ( idx_t i = 0; i < nodes.nb_fields(); ++i ) { const Field& field = nodes.field( i ); if ( field.shape( 0 ) == lonlat.shape( 0 ) && field.shape( 1 ) == 1 && field.datatype() == array::DataType::real64() ) // FIXME: no support for @@ -189,7 +190,7 @@ void PointCloudIO::write( const eckit::PathName& path, const Mesh& mesh ) { } std::ofstream f( path.asString().c_str() ); - if ( !f.is_open() ) throw eckit::CantOpenFile( path.asString() ); + if ( !f.is_open() ) throw_CantOpenFile( path.asString() ); const size_t Npts = lonlat.shape( 0 ); const size_t Nfld = vfvalues.size(); @@ -221,16 +222,16 @@ void PointCloudIO::write( const eckit::PathName& path, const FieldSet& fieldset, // transversing data structures // @warning: several copy operations here - ASSERT( fieldset.size() ); + ATLAS_ASSERT( fieldset.size() ); array::ArrayView lonlat = array::make_view( function_space.nodes().xy() ); - if ( !lonlat.size() ) throw eckit::BadParameter( msg + "invalid number of points (failed: nb_pts>0)" ); + if ( !lonlat.size() ) throw_Exception( msg + "invalid number of points (failed: nb_pts>0)" ); // get the fields (sanitized) names and values // (bypasses fields ("lonlat"|"lonlat") as shape(1)!=1) std::vector vfnames; std::vector> vfvalues; - for ( size_t i = 0; i < fieldset.size(); ++i ) { + for ( idx_t i = 0; i < fieldset.size(); ++i ) { const Field& field = fieldset[i]; if ( field.shape( 0 ) == lonlat.shape( 0 ) && field.rank() == 1 && field.name() != "glb_idx" ) // FIXME: no support for non-int types! @@ -241,7 +242,7 @@ void PointCloudIO::write( const eckit::PathName& path, const FieldSet& fieldset, } std::ofstream f( path.asString().c_str() ); - if ( !f.is_open() ) throw eckit::CantOpenFile( path.asString() ); + if ( !f.is_open() ) throw_CantOpenFile( path.asString() ); const size_t Npts = lonlat.shape( 0 ), Nfld = vfvalues.size(); // header @@ -267,7 +268,7 @@ void PointCloudIO::write( const eckit::PathName& path, const std::vector const std::string msg( "PointCloudIO::write: " ); const size_t Npts( lon.size() ), Nfld( vfvalues.size() ); - if ( Npts != lat.size() ) throw eckit::BadParameter( msg + "number of points inconsistent (failed: #lon == #lat)" ); + if ( Npts != lat.size() ) throw_Exception( msg + "number of points inconsistent (failed: #lon == #lat)" ); if ( Nfld != vfnames.size() ) - throw eckit::BadParameter( msg + "number of fields inconsistent (failed: #vfvalues == #vfnames)" ); + throw_Exception( msg + "number of fields inconsistent (failed: #vfvalues == #vfnames)" ); for ( size_t j = 0; j < Nfld; ++j ) if ( Npts != vfvalues[j]->size() ) - throw eckit::BadParameter( msg + - "number of points inconsistent (failed: " - "#lon == #lat == #*vfvalues[])" ); + throw_Exception( msg + + "number of points inconsistent (failed: " + "#lon == #lat == #*vfvalues[])" ); std::ofstream f( path.asString().c_str() ); - if ( !f.is_open() ) throw eckit::CantOpenFile( path.asString() ); + if ( !f.is_open() ) throw_CantOpenFile( path.asString() ); // header f << "PointCloudIO\t" << Npts << '\t' << ( 2 + Nfld ) << "\tlon\tlat"; @@ -322,12 +323,12 @@ void PointCloudIO::write( const eckit::PathName& path, const int& nb_pts, const const std::string msg( "PointCloudIO::write: " ); const size_t Npts( nb_pts > 0 ? nb_pts : 0 ), Nfld( nb_fld > 0 && afvalues && afnames ? nb_fld : 0 ); - if ( !Npts ) throw eckit::BadParameter( msg + "invalid number of points (nb_nodes)" ); - if ( !lon ) throw eckit::BadParameter( msg + "invalid array describing longitude (lon)" ); - if ( !lat ) throw eckit::BadParameter( msg + "invalid array describing latitude (lat)" ); + if ( !Npts ) throw_Exception( msg + "invalid number of points (nb_nodes)" ); + if ( !lon ) throw_Exception( msg + "invalid array describing longitude (lon)" ); + if ( !lat ) throw_Exception( msg + "invalid array describing latitude (lat)" ); std::ofstream f( path.asString().c_str() ); - if ( !f.is_open() ) throw eckit::CantOpenFile( path.asString() ); + if ( !f.is_open() ) throw_CantOpenFile( path.asString() ); // header f << "PointCloudIO\t" << Npts << '\t' << ( 2 + Nfld ) << "\tlon\tlat"; diff --git a/src/atlas/parallel/Checksum.cc b/src/atlas/parallel/Checksum.cc index 120503003..6722151fb 100644 --- a/src/atlas/parallel/Checksum.cc +++ b/src/atlas/parallel/Checksum.cc @@ -23,23 +23,23 @@ Checksum::Checksum( const std::string& name ) : name_( name ) { is_setup_ = false; } -void Checksum::setup( const int part[], const int remote_idx[], const int base, const gidx_t glb_idx[], +void Checksum::setup( const int part[], const idx_t remote_idx[], const int base, const gidx_t glb_idx[], const int parsize ) { parsize_ = parsize; - gather_.reset( new GatherScatter() ); + gather_ = util::ObjectHandle( new GatherScatter() ); gather_->setup( part, remote_idx, base, glb_idx, parsize ); is_setup_ = true; } -void Checksum::setup( const int part[], const int remote_idx[], const int base, const gidx_t glb_idx[], +void Checksum::setup( const int part[], const idx_t remote_idx[], const int base, const gidx_t glb_idx[], const int mask[], const int parsize ) { parsize_ = parsize; - gather_.reset( new GatherScatter() ); + gather_ = util::ObjectHandle( new GatherScatter() ); gather_->setup( part, remote_idx, base, glb_idx, mask, parsize ); is_setup_ = true; } -void Checksum::setup( const eckit::SharedPtr& gather ) { +void Checksum::setup( const util::ObjectHandle& gather ) { gather_ = gather; parsize_ = gather->parsize_; is_setup_ = true; @@ -55,7 +55,7 @@ void atlas__Checksum__delete( Checksum* This ) { delete This; } -void atlas__Checksum__setup32( Checksum* This, int part[], int remote_idx[], int base, int glb_idx[], int parsize ) { +void atlas__Checksum__setup32( Checksum* This, int part[], idx_t remote_idx[], int base, int glb_idx[], int parsize ) { #if ATLAS_BITS_GLOBAL == 32 This->setup( part, remote_idx, base, glb_idx, parsize ); #else @@ -67,7 +67,7 @@ void atlas__Checksum__setup32( Checksum* This, int part[], int remote_idx[], int #endif } -void atlas__Checksum__setup64( Checksum* This, int part[], int remote_idx[], int base, long glb_idx[], int parsize ) { +void atlas__Checksum__setup64( Checksum* This, int part[], idx_t remote_idx[], int base, long glb_idx[], int parsize ) { #if ATLAS_BITS_GLOBAL == 64 This->setup( part, remote_idx, base, glb_idx, parsize ); #else @@ -94,6 +94,11 @@ void atlas__Checksum__execute_strided_double( Checksum* This, double lfield[], i std::strcpy( checksum, This->execute( lfield, lvar_strides, lvar_extents, lvar_rank ).c_str() ); } +void atlas__Checksum__execute_strided_long( Checksum* This, long lfield[], int lvar_strides[], int lvar_extents[], + int lvar_rank, char* checksum ) { + std::strcpy( checksum, This->execute( lfield, lvar_strides, lvar_extents, lvar_rank ).c_str() ); +} + // const char* atlas__Checksum__execute_strided_double (Checksum* This, // double lfield[], int // lvar_strides[], int diff --git a/src/atlas/parallel/Checksum.h b/src/atlas/parallel/Checksum.h index 111f716bc..3fb0c27b8 100644 --- a/src/atlas/parallel/Checksum.h +++ b/src/atlas/parallel/Checksum.h @@ -12,23 +12,19 @@ #include -#include "eckit/memory/Owned.h" -#include "eckit/memory/SharedPtr.h" #include "eckit/utils/Translator.h" #include "atlas/array/ArrayView.h" #include "atlas/parallel/GatherScatter.h" #include "atlas/parallel/mpi/mpi.h" -#include "atlas/runtime/Log.h" #include "atlas/util/Checksum.h" +#include "atlas/util/Object.h" +#include "atlas/util/ObjectHandle.h" namespace atlas { namespace parallel { -class Checksum : public eckit::Owned { -public: // types - typedef eckit::SharedPtr Ptr; - +class Checksum : public util::Object { public: Checksum(); Checksum( const std::string& name ); @@ -46,7 +42,7 @@ class Checksum : public eckit::Owned { /// To Checksum everything, set to val > max value in /// domain /// @param [in] parsize size of given lists - void setup( const int part[], const int remote_idx[], const int base, const gidx_t glb_idx[], const int parsize ); + void setup( const int part[], const idx_t remote_idx[], const int base, const gidx_t glb_idx[], const int parsize ); /// @brief Setup /// @param [in] part List of partitions @@ -56,11 +52,11 @@ class Checksum : public eckit::Owned { /// @param [in] mask Mask indices not to include in the communication /// pattern (0=include,1=exclude) /// @param [in] parsize size of given lists - void setup( const int part[], const int remote_idx[], const int base, const gidx_t glb_idx[], const int mask[], + void setup( const int part[], const idx_t remote_idx[], const int base, const gidx_t glb_idx[], const int mask[], const int parsize ); /// @brief Setup - void setup( const eckit::SharedPtr& ); + void setup( const util::ObjectHandle& ); template std::string execute( const DATA_TYPE lfield[], const int lvar_strides[], const int lvar_extents[], @@ -78,7 +74,7 @@ class Checksum : public eckit::Owned { private: // data std::string name_; - eckit::SharedPtr gather_; + util::ObjectHandle gather_; bool is_setup_; size_t parsize_; }; @@ -88,7 +84,7 @@ std::string Checksum::execute( const DATA_TYPE data[], const int var_strides[], const int var_rank ) const { size_t root = 0; - if ( !is_setup_ ) { throw eckit::SeriousBug( "Checksum was not setup", Here() ); } + if ( !is_setup_ ) { throw_Exception( "Checksum was not setup", Here() ); } std::vector local_checksums( parsize_ ); int var_size = var_extents[0] * var_strides[0]; @@ -140,14 +136,13 @@ void Checksum::var_info( const array::ArrayView& arr, std::vect template std::string Checksum::execute( const array::ArrayView& lfield ) const { - if ( lfield.shape( 0 ) == parsize_ ) { + if ( size_t( lfield.shape( 0 ) ) == parsize_ ) { std::vector lvarstrides, lvarextents; var_info( lfield, lvarstrides, lvarextents ); return execute( lfield.data(), lvarstrides.data(), lvarextents.data(), lvarstrides.size() ); } else { - Log::error() << "lfield.shape(0) = " << lfield.shape( 0 ); - NOTIMP; // Need to implement with parallel ranks > 1 + ATLAS_NOTIMPLEMENTED; // Need to implement with parallel ranks > 1 } } @@ -156,14 +151,16 @@ std::string Checksum::execute( const array::ArrayView& lfield extern "C" { Checksum* atlas__Checksum__new(); void atlas__Checksum__delete( Checksum* This ); -void atlas__Checksum__setup32( Checksum* This, int part[], int remote_idx[], int base, int glb_idx[], int parsize ); -void atlas__Checksum__setup64( Checksum* This, int part[], int remote_idx[], int base, long glb_idx[], int parsize ); +void atlas__Checksum__setup32( Checksum* This, int part[], idx_t remote_idx[], int base, int glb_idx[], int parsize ); +void atlas__Checksum__setup64( Checksum* This, int part[], idx_t remote_idx[], int base, long glb_idx[], int parsize ); void atlas__Checksum__execute_strided_int( Checksum* This, int lfield[], int lvar_strides[], int lvar_extents[], int lvar_rank, char* checksum ); void atlas__Checksum__execute_strided_float( Checksum* This, float lfield[], int lvar_strides[], int lvar_extents[], int lvar_rank, char* checksum ); void atlas__Checksum__execute_strided_double( Checksum* This, double lfield[], int lvar_strides[], int lvar_extents[], int lvar_rank, char* checksum ); +void atlas__Checksum__execute_strided_long( Checksum* This, long lfield[], int lvar_strides[], int lvar_extents[], + int lvar_rank, char* checksum ); } // ------------------------------------------------------------------ diff --git a/src/atlas/parallel/GatherScatter.cc b/src/atlas/parallel/GatherScatter.cc index e0e91069e..701ea53d0 100644 --- a/src/atlas/parallel/GatherScatter.cc +++ b/src/atlas/parallel/GatherScatter.cc @@ -8,6 +8,7 @@ * nor does it submit to any jurisdiction. */ +#include #include #include #include @@ -25,30 +26,31 @@ namespace parallel { namespace { struct IsGhostPoint { - IsGhostPoint( const int part[], const int ridx[], const int base, const int N ) { + IsGhostPoint( const int part[], const idx_t ridx[], const idx_t base, const int N ) { part_ = part; ridx_ = ridx; base_ = base; mypart_ = mpi::comm().rank(); } - bool operator()( int idx ) { + bool operator()( idx_t idx ) { if ( part_[idx] != mypart_ ) return true; if ( ridx_[idx] != base_ + idx ) return true; return false; } int mypart_; const int* part_; - const int* ridx_; - int base_; + const idx_t* ridx_; + idx_t base_; }; struct Node { - gidx_t p, i; + int p; + idx_t i; gidx_t g; Node() {} - Node( gidx_t gid, int part, int idx ) { + Node( gidx_t gid, int part, idx_t idx ) { g = gid; p = part; i = idx; @@ -71,8 +73,8 @@ GatherScatter::GatherScatter( const std::string& name ) : name_( name ), is_setu nproc = mpi::comm().size(); } -void GatherScatter::setup( const int part[], const int remote_idx[], const int base, const gidx_t glb_idx[], - const int mask[], const size_t parsize ) { +void GatherScatter::setup( const int part[], const idx_t remote_idx[], const int base, const gidx_t glb_idx[], + const int mask[], const idx_t parsize ) { ATLAS_TRACE( "GatherScatter::setup" ); parsize_ = parsize; @@ -81,12 +83,12 @@ void GatherScatter::setup( const int part[], const int remote_idx[], const int b glbcounts_.assign( nproc, 0 ); glbdispls_.resize( nproc ); glbdispls_.assign( nproc, 0 ); - const size_t nvar = 3; + const idx_t nvar = 3; std::vector sendnodes( parsize_ * nvar ); loccnt_ = 0; - for ( size_t n = 0; n < parsize_; ++n ) { + for ( idx_t n = 0; n < parsize_; ++n ) { if ( !mask[n] ) { sendnodes[loccnt_++] = glb_idx[n]; sendnodes[loccnt_++] = part[n]; @@ -99,7 +101,7 @@ void GatherScatter::setup( const int part[], const int remote_idx[], const int b glbcnt_ = std::accumulate( glbcounts_.begin(), glbcounts_.end(), 0 ); glbdispls_[0] = 0; - for ( size_t jproc = 1; jproc < nproc; ++jproc ) // start at 1 + for ( idx_t jproc = 1; jproc < nproc; ++jproc ) // start at 1 { glbdispls_[jproc] = glbcounts_[jproc - 1] + glbdispls_[jproc - 1]; } @@ -111,9 +113,9 @@ void GatherScatter::setup( const int part[], const int remote_idx[], const int b } // Load recvnodes in sorting structure - size_t nb_recv_nodes = glbcnt_ / nvar; + idx_t nb_recv_nodes = glbcnt_ / nvar; std::vector node_sort( nb_recv_nodes ); - for ( size_t n = 0; n < nb_recv_nodes; ++n ) { + for ( idx_t n = 0; n < nb_recv_nodes; ++n ) { node_sort[n].g = recvnodes[n * nvar + 0]; node_sort[n].p = recvnodes[n * nvar + 1]; node_sort[n].i = recvnodes[n * nvar + 2]; @@ -133,7 +135,7 @@ void GatherScatter::setup( const int part[], const int remote_idx[], const int b } glbdispls_[0] = 0; - for ( size_t jproc = 1; jproc < nproc; ++jproc ) // start at 1 + for ( idx_t jproc = 1; jproc < nproc; ++jproc ) // start at 1 { glbdispls_[jproc] = glbcounts_[jproc - 1] + glbdispls_[jproc - 1]; } @@ -145,11 +147,13 @@ void GatherScatter::setup( const int part[], const int remote_idx[], const int b locmap_.clear(); locmap_.resize( loccnt_ ); std::vector idx( nproc, 0 ); - for ( size_t n = 0; n < node_sort.size(); ++n ) { - size_t jproc = node_sort[n].p; - glbmap_[glbdispls_[jproc] + idx[jproc]] = n; - if ( jproc == myproc ) locmap_[idx[jproc]] = node_sort[n].i; + int n{0}; + for ( const auto& node : node_sort ) { + idx_t jproc = node.p; + glbmap_[glbdispls_[jproc] + idx[jproc]] = n++; + + if ( jproc == myproc ) locmap_[idx[jproc]] = node.i; ++idx[jproc]; } @@ -157,11 +161,11 @@ void GatherScatter::setup( const int part[], const int remote_idx[], const int b is_setup_ = true; } -void GatherScatter::setup( const int part[], const int remote_idx[], const int base, const gidx_t glb_idx[], - const size_t parsize ) { +void GatherScatter::setup( const int part[], const idx_t remote_idx[], const int base, const gidx_t glb_idx[], + const idx_t parsize ) { std::vector mask( parsize ); IsGhostPoint is_ghost( part, remote_idx, base, parsize ); - for ( size_t jj = 0; jj < parsize; ++jj ) { + for ( idx_t jj = 0; jj < parsize; ++jj ) { mask[jj] = is_ghost( jj ) ? 1 : 0; } setup( part, remote_idx, base, glb_idx, mask.data(), parsize ); @@ -177,7 +181,7 @@ void atlas__GatherScatter__delete( GatherScatter* This ) { delete This; } -void atlas__GatherScatter__setup32( GatherScatter* This, int part[], int remote_idx[], int base, int glb_idx[], +void atlas__GatherScatter__setup32( GatherScatter* This, int part[], idx_t remote_idx[], int base, int glb_idx[], int parsize ) { #if ATLAS_BITS_GLOBAL == 32 This->setup( part, remote_idx, base, glb_idx, parsize ); @@ -190,13 +194,13 @@ void atlas__GatherScatter__setup32( GatherScatter* This, int part[], int remote_ #endif } -void atlas__GatherScatter__setup64( GatherScatter* This, int part[], int remote_idx[], int base, long glb_idx[], +void atlas__GatherScatter__setup64( GatherScatter* This, int part[], idx_t remote_idx[], int base, long glb_idx[], int parsize ) { #if ATLAS_BITS_GLOBAL == 64 This->setup( part, remote_idx, base, glb_idx, parsize ); #else std::vector glb_idx_convert( parsize ); - for ( size_t j = 0; j < parsize; ++j ) { + for ( idx_t j = 0; j < parsize; ++j ) { glb_idx_convert[j] = glb_idx[j]; } This->setup( part, remote_idx, base, glb_idx_convert.data(), parsize ); @@ -210,10 +214,10 @@ int atlas__GatherScatter__glb_dof( GatherScatter* This ) { void atlas__GatherScatter__gather_int( GatherScatter* This, int lfield[], int lvar_strides[], int lvar_extents[], int lvar_rank, int gfield[], int gvar_strides[], int gvar_extents[], int gvar_rank ) { - std::vector lvstrides( lvar_rank ); - std::vector lvextents( lvar_rank ); - std::vector gvstrides( gvar_rank ); - std::vector gvextents( gvar_rank ); + std::vector lvstrides( lvar_rank ); + std::vector lvextents( lvar_rank ); + std::vector gvstrides( gvar_rank ); + std::vector gvextents( gvar_rank ); for ( int n = 0; n < lvar_rank; ++n ) { lvstrides[n] = lvar_strides[n]; lvextents[n] = lvar_extents[n]; @@ -229,10 +233,10 @@ void atlas__GatherScatter__gather_int( GatherScatter* This, int lfield[], int lv void atlas__GatherScatter__gather_long( GatherScatter* This, long lfield[], int lvar_strides[], int lvar_extents[], int lvar_rank, long gfield[], int gvar_strides[], int gvar_extents[], int gvar_rank ) { - std::vector lvstrides( lvar_rank ); - std::vector lvextents( lvar_rank ); - std::vector gvstrides( gvar_rank ); - std::vector gvextents( gvar_rank ); + std::vector lvstrides( lvar_rank ); + std::vector lvextents( lvar_rank ); + std::vector gvstrides( gvar_rank ); + std::vector gvextents( gvar_rank ); for ( int n = 0; n < lvar_rank; ++n ) { lvstrides[n] = lvar_strides[n]; lvextents[n] = lvar_extents[n]; @@ -248,10 +252,10 @@ void atlas__GatherScatter__gather_long( GatherScatter* This, long lfield[], int void atlas__GatherScatter__gather_float( GatherScatter* This, float lfield[], int lvar_strides[], int lvar_extents[], int lvar_rank, float gfield[], int gvar_strides[], int gvar_extents[], int gvar_rank ) { - std::vector lvstrides( lvar_rank ); - std::vector lvextents( lvar_rank ); - std::vector gvstrides( gvar_rank ); - std::vector gvextents( gvar_rank ); + std::vector lvstrides( lvar_rank ); + std::vector lvextents( lvar_rank ); + std::vector gvstrides( gvar_rank ); + std::vector gvextents( gvar_rank ); for ( int n = 0; n < lvar_rank; ++n ) { lvstrides[n] = lvar_strides[n]; lvextents[n] = lvar_extents[n]; @@ -267,10 +271,10 @@ void atlas__GatherScatter__gather_float( GatherScatter* This, float lfield[], in void atlas__GatherScatter__gather_double( GatherScatter* This, double lfield[], int lvar_strides[], int lvar_extents[], int lvar_rank, double gfield[], int gvar_strides[], int gvar_extents[], int gvar_rank ) { - std::vector lvstrides( lvar_rank ); - std::vector lvextents( lvar_rank ); - std::vector gvstrides( gvar_rank ); - std::vector gvextents( gvar_rank ); + std::vector lvstrides( lvar_rank ); + std::vector lvextents( lvar_rank ); + std::vector gvstrides( gvar_rank ); + std::vector gvextents( gvar_rank ); for ( int n = 0; n < lvar_rank; ++n ) { lvstrides[n] = lvar_strides[n]; lvextents[n] = lvar_extents[n]; @@ -286,10 +290,10 @@ void atlas__GatherScatter__gather_double( GatherScatter* This, double lfield[], void atlas__GatherScatter__scatter_int( GatherScatter* This, int gfield[], int gvar_strides[], int gvar_extents[], int gvar_rank, int lfield[], int lvar_strides[], int lvar_extents[], int lvar_rank ) { - std::vector lvstrides( lvar_rank ); - std::vector lvextents( lvar_rank ); - std::vector gvstrides( gvar_rank ); - std::vector gvextents( gvar_rank ); + std::vector lvstrides( lvar_rank ); + std::vector lvextents( lvar_rank ); + std::vector gvstrides( gvar_rank ); + std::vector gvextents( gvar_rank ); for ( int n = 0; n < lvar_rank; ++n ) { lvstrides[n] = lvar_strides[n]; lvextents[n] = lvar_extents[n]; @@ -305,10 +309,10 @@ void atlas__GatherScatter__scatter_int( GatherScatter* This, int gfield[], int g void atlas__GatherScatter__scatter_long( GatherScatter* This, long gfield[], int gvar_strides[], int gvar_extents[], int gvar_rank, long lfield[], int lvar_strides[], int lvar_extents[], int lvar_rank ) { - std::vector lvstrides( lvar_rank ); - std::vector lvextents( lvar_rank ); - std::vector gvstrides( gvar_rank ); - std::vector gvextents( gvar_rank ); + std::vector lvstrides( lvar_rank ); + std::vector lvextents( lvar_rank ); + std::vector gvstrides( gvar_rank ); + std::vector gvextents( gvar_rank ); for ( int n = 0; n < lvar_rank; ++n ) { lvstrides[n] = lvar_strides[n]; lvextents[n] = lvar_extents[n]; @@ -324,10 +328,10 @@ void atlas__GatherScatter__scatter_long( GatherScatter* This, long gfield[], int void atlas__GatherScatter__scatter_float( GatherScatter* This, float gfield[], int gvar_strides[], int gvar_extents[], int gvar_rank, float lfield[], int lvar_strides[], int lvar_extents[], int lvar_rank ) { - std::vector lvstrides( lvar_rank ); - std::vector lvextents( lvar_rank ); - std::vector gvstrides( gvar_rank ); - std::vector gvextents( gvar_rank ); + std::vector lvstrides( lvar_rank ); + std::vector lvextents( lvar_rank ); + std::vector gvstrides( gvar_rank ); + std::vector gvextents( gvar_rank ); for ( int n = 0; n < lvar_rank; ++n ) { lvstrides[n] = lvar_strides[n]; lvextents[n] = lvar_extents[n]; @@ -343,10 +347,10 @@ void atlas__GatherScatter__scatter_float( GatherScatter* This, float gfield[], i void atlas__GatherScatter__scatter_double( GatherScatter* This, double gfield[], int gvar_strides[], int gvar_extents[], int gvar_rank, double lfield[], int lvar_strides[], int lvar_extents[], int lvar_rank ) { - std::vector lvstrides( lvar_rank ); - std::vector lvextents( lvar_rank ); - std::vector gvstrides( gvar_rank ); - std::vector gvextents( gvar_rank ); + std::vector lvstrides( lvar_rank ); + std::vector lvextents( lvar_rank ); + std::vector gvstrides( gvar_rank ); + std::vector gvextents( gvar_rank ); for ( int n = 0; n < lvar_rank; ++n ) { lvstrides[n] = lvar_strides[n]; lvextents[n] = lvar_extents[n]; diff --git a/src/atlas/parallel/GatherScatter.h b/src/atlas/parallel/GatherScatter.h index 8146af252..1191a1d76 100644 --- a/src/atlas/parallel/GatherScatter.h +++ b/src/atlas/parallel/GatherScatter.h @@ -10,16 +10,15 @@ #pragma once +#include #include #include -#include "eckit/memory/Owned.h" -#include "eckit/memory/SharedPtr.h" - #include "atlas/array/ArrayView.h" #include "atlas/library/config.h" #include "atlas/parallel/mpi/mpi.h" -#include "atlas/runtime/Log.h" +#include "atlas/runtime/Exception.h" +#include "atlas/util/Object.h" namespace atlas { namespace parallel { @@ -53,14 +52,14 @@ class Field { public: Field() {} - Field( DATA_TYPE data_[], const size_t var_strides_[], const size_t var_shape_[], const size_t var_rank_ ) : + Field( DATA_TYPE data_[], const idx_t var_strides_[], const idx_t var_shape_[], const idx_t var_rank_ ) : data( const_cast( data_ ) ), var_rank( var_rank_ ) { var_strides.assign( var_strides_, var_strides_ + var_rank_ ); var_shape.assign( var_shape_, var_shape_ + var_rank_ ); } - Field( DATA_TYPE data_[], const size_t nb_vars ) : data( const_cast( data_ ) ), var_rank( 1 ) { + Field( DATA_TYPE data_[], const idx_t nb_vars ) : data( const_cast( data_ ) ), var_rank( 1 ) { var_strides.assign( 1, 1 ); var_shape.assign( 1, nb_vars ); } @@ -111,12 +110,12 @@ class Field { public: DATA_TYPE* data; - std::vector var_strides; - std::vector var_shape; - size_t var_rank; + std::vector var_strides; + std::vector var_shape; + idx_t var_rank; }; -class GatherScatter : public eckit::Owned { +class GatherScatter : public util::Object { public: GatherScatter(); GatherScatter( const std::string& name ); @@ -131,8 +130,8 @@ class GatherScatter : public eckit::Owned { /// @param [in] base values of remote_idx start at "base" /// @param [in] glb_idx List of global indices /// @param [in] parsize size of given lists - void setup( const int part[], const int remote_idx[], const int base, const gidx_t glb_idx[], - const size_t parsize ); + void setup( const int part[], const idx_t remote_idx[], const int base, const gidx_t glb_idx[], + const idx_t parsize ); /// @brief Setup /// @param [in] part List of partitions @@ -142,50 +141,50 @@ class GatherScatter : public eckit::Owned { /// @param [in] parsize size of given lists /// @param [in] mask Mask indices not to include in the communication /// pattern (0=include,1=exclude) - void setup( const int part[], const int remote_idx[], const int base, const gidx_t glb_idx[], const int mask[], - const size_t parsize ); + void setup( const int part[], const idx_t remote_idx[], const int base, const gidx_t glb_idx[], const int mask[], + const idx_t parsize ); template - void gather( const DATA_TYPE ldata[], const size_t lstrides[], const size_t lshape[], const size_t lrank, - const size_t lmpl_idxpos[], const size_t lmpl_rank, DATA_TYPE gdata[], const size_t gstrides[], - const size_t gshape[], const size_t grank, const size_t gmpl_idxpos[], const size_t gmpl_rank, - const size_t root ) const; + void gather( const DATA_TYPE ldata[], const idx_t lstrides[], const idx_t lshape[], const idx_t lrank, + const idx_t lmpl_idxpos[], const idx_t lmpl_rank, DATA_TYPE gdata[], const idx_t gstrides[], + const idx_t gshape[], const idx_t grank, const idx_t gmpl_idxpos[], const idx_t gmpl_rank, + const idx_t root ) const; template - void gather( const DATA_TYPE ldata[], const size_t lvar_strides[], const size_t lvar_shape[], - const size_t lvar_rank, DATA_TYPE gdata[], const size_t gvar_strides[], const size_t gvar_shape[], - const size_t gvar_rank, const size_t root = 0 ) const; + void gather( const DATA_TYPE ldata[], const idx_t lvar_strides[], const idx_t lvar_shape[], const idx_t lvar_rank, + DATA_TYPE gdata[], const idx_t gvar_strides[], const idx_t gvar_shape[], const idx_t gvar_rank, + const idx_t root = 0 ) const; template void gather( parallel::Field lfields[], parallel::Field gfields[], - const size_t nb_fields, const size_t root = 0 ) const; + const idx_t nb_fields, const idx_t root = 0 ) const; template void gather( const array::ArrayView& ldata, array::ArrayView& gdata, - const size_t root = 0 ) const; + const idx_t root = 0 ) const; template void scatter( parallel::Field gfields[], parallel::Field lfields[], - const size_t nb_fields, const size_t root = 0 ) const; + const idx_t nb_fields, const idx_t root = 0 ) const; template - void scatter( const DATA_TYPE gdata[], const size_t gstrides[], const size_t gshape[], const size_t grank, - const size_t gmpl_idxpos[], const size_t gmpl_rank, DATA_TYPE ldata[], const size_t lstrides[], - const size_t lshape[], const size_t lrank, const size_t lmpl_idxpos[], const size_t lmpl_rank, - const size_t root ) const; + void scatter( const DATA_TYPE gdata[], const idx_t gstrides[], const idx_t gshape[], const idx_t grank, + const idx_t gmpl_idxpos[], const idx_t gmpl_rank, DATA_TYPE ldata[], const idx_t lstrides[], + const idx_t lshape[], const idx_t lrank, const idx_t lmpl_idxpos[], const idx_t lmpl_rank, + const idx_t root ) const; template - void scatter( const DATA_TYPE gdata[], const size_t gvar_strides[], const size_t gvar_shape[], - const size_t gvar_rank, DATA_TYPE ldata[], const size_t lvar_strides[], const size_t lvar_shape[], - const size_t lvar_rank, const size_t root = 0 ) const; + void scatter( const DATA_TYPE gdata[], const idx_t gvar_strides[], const idx_t gvar_shape[], const idx_t gvar_rank, + DATA_TYPE ldata[], const idx_t lvar_strides[], const idx_t lvar_shape[], const idx_t lvar_rank, + const idx_t root = 0 ) const; template void scatter( const array::ArrayView& gdata, array::ArrayView& ldata, - const size_t root = 0 ) const; + const idx_t root = 0 ) const; - int glb_dof() const { return glbcnt_; } + gidx_t glb_dof() const { return glbcnt_; } - int loc_dof() const { return loccnt_; } + idx_t loc_dof() const { return loccnt_; } private: // methods template @@ -197,8 +196,8 @@ class GatherScatter : public eckit::Owned { const parallel::Field& field ) const; template - void var_info( const array::ArrayView& arr, std::vector& varstrides, - std::vector& varshape ) const; + void var_info( const array::ArrayView& arr, std::vector& varstrides, + std::vector& varshape ) const; private: // data std::string name_; @@ -209,39 +208,39 @@ class GatherScatter : public eckit::Owned { std::vector locmap_; std::vector glbmap_; - size_t nproc; - size_t myproc; + idx_t nproc; + idx_t myproc; bool is_setup_; - size_t parsize_; + idx_t parsize_; friend class Checksum; - int glb_cnt( size_t root ) const { return myproc == root ? glbcnt_ : 0; } + int glb_cnt( idx_t root ) const { return myproc == root ? glbcnt_ : 0; } }; -//////////////////////////////////////////////////////////////////////////////// +//-------------------------------------------------------------------------------------------------- template void GatherScatter::gather( parallel::Field lfields[], parallel::Field gfields[], - size_t nb_fields, const size_t root ) const { - if ( !is_setup_ ) { throw eckit::SeriousBug( "GatherScatter was not setup", Here() ); } - - for ( size_t jfield = 0; jfield < nb_fields; ++jfield ) { - const size_t lvar_size = std::accumulate( lfields[jfield].var_shape.data(), - lfields[jfield].var_shape.data() + lfields[jfield].var_rank, 1, - std::multiplies() ); - const size_t gvar_size = std::accumulate( gfields[jfield].var_shape.data(), - gfields[jfield].var_shape.data() + gfields[jfield].var_rank, 1, - std::multiplies() ); - const int loc_size = loccnt_ * lvar_size; - const int glb_size = glb_cnt( root ) * gvar_size; + idx_t nb_fields, const idx_t root ) const { + if ( !is_setup_ ) { throw_Exception( "GatherScatter was not setup", Here() ); } + + for ( idx_t jfield = 0; jfield < nb_fields; ++jfield ) { + const idx_t lvar_size = + std::accumulate( lfields[jfield].var_shape.data(), + lfields[jfield].var_shape.data() + lfields[jfield].var_rank, 1, std::multiplies() ); + const idx_t gvar_size = + std::accumulate( gfields[jfield].var_shape.data(), + gfields[jfield].var_shape.data() + gfields[jfield].var_rank, 1, std::multiplies() ); + const int loc_size = loccnt_ * lvar_size; + const int glb_size = glb_cnt( root ) * gvar_size; std::vector loc_buffer( loc_size ); std::vector glb_buffer( glb_size ); std::vector glb_displs( nproc ); std::vector glb_counts( nproc ); - for ( size_t jproc = 0; jproc < nproc; ++jproc ) { + for ( idx_t jproc = 0; jproc < nproc; ++jproc ) { glb_counts[jproc] = glbcounts_[jproc] * gvar_size; glb_displs[jproc] = glbdispls_[jproc] * gvar_size; } @@ -260,9 +259,9 @@ void GatherScatter::gather( parallel::Field lfields[], parallel } template -void GatherScatter::gather( const DATA_TYPE ldata[], const size_t lvar_strides[], const size_t lvar_shape[], - const size_t lvar_rank, DATA_TYPE gdata[], const size_t gvar_strides[], - const size_t gvar_shape[], const size_t gvar_rank, const size_t root ) const { +void GatherScatter::gather( const DATA_TYPE ldata[], const idx_t lvar_strides[], const idx_t lvar_shape[], + const idx_t lvar_rank, DATA_TYPE gdata[], const idx_t gvar_strides[], + const idx_t gvar_shape[], const idx_t gvar_rank, const idx_t root ) const { parallel::Field lfield( ldata, lvar_strides, lvar_shape, lvar_rank ); parallel::Field gfield( gdata, gvar_strides, gvar_shape, gvar_rank ); gather( &lfield, &gfield, 1, root ); @@ -270,10 +269,10 @@ void GatherScatter::gather( const DATA_TYPE ldata[], const size_t lvar_strides[] template void GatherScatter::scatter( parallel::Field gfields[], parallel::Field lfields[], - const size_t nb_fields, const size_t root ) const { - if ( !is_setup_ ) { throw eckit::SeriousBug( "GatherScatter was not setup", Here() ); } + const idx_t nb_fields, const idx_t root ) const { + if ( !is_setup_ ) { throw_Exception( "GatherScatter was not setup", Here() ); } - for ( size_t jfield = 0; jfield < nb_fields; ++jfield ) { + for ( idx_t jfield = 0; jfield < nb_fields; ++jfield ) { const int lvar_size = std::accumulate( lfields[jfield].var_shape.data(), lfields[jfield].var_shape.data() + lfields[jfield].var_rank, 1, std::multiplies() ); @@ -287,7 +286,7 @@ void GatherScatter::scatter( parallel::Field gfields[], paralle std::vector glb_displs( nproc ); std::vector glb_counts( nproc ); - for ( size_t jproc = 0; jproc < nproc; ++jproc ) { + for ( idx_t jproc = 0; jproc < nproc; ++jproc ) { glb_counts[jproc] = glbcounts_[jproc] * gvar_size; glb_displs[jproc] = glbdispls_[jproc] * gvar_size; } @@ -308,9 +307,9 @@ void GatherScatter::scatter( parallel::Field gfields[], paralle } template -void GatherScatter::scatter( const DATA_TYPE gdata[], const size_t gvar_strides[], const size_t gvar_shape[], - const size_t gvar_rank, DATA_TYPE ldata[], const size_t lvar_strides[], - const size_t lvar_shape[], const size_t lvar_rank, const size_t root ) const { +void GatherScatter::scatter( const DATA_TYPE gdata[], const idx_t gvar_strides[], const idx_t gvar_shape[], + const idx_t gvar_rank, DATA_TYPE ldata[], const idx_t lvar_strides[], + const idx_t lvar_shape[], const idx_t lvar_rank, const idx_t root ) const { parallel::Field gfield( gdata, gvar_strides, gvar_shape, gvar_rank ); parallel::Field lfield( ldata, lvar_strides, lvar_shape, lvar_rank ); scatter( &gfield, &lfield, 1, root ); @@ -319,40 +318,40 @@ void GatherScatter::scatter( const DATA_TYPE gdata[], const size_t gvar_strides[ template void GatherScatter::pack_send_buffer( const parallel::Field& field, const std::vector& sendmap, DATA_TYPE send_buffer[] ) const { - const size_t sendcnt = sendmap.size(); + const idx_t sendcnt = static_cast( sendmap.size() ); - size_t ibuf = 0; - const size_t send_stride = field.var_strides[0] * field.var_shape[0]; + idx_t ibuf = 0; + const idx_t send_stride = field.var_strides[0] * field.var_shape[0]; switch ( field.var_rank ) { case 1: - for ( size_t p = 0; p < sendcnt; ++p ) { - const size_t pp = send_stride * sendmap[p]; - for ( size_t i = 0; i < field.var_shape[0]; ++i ) { + for ( idx_t p = 0; p < sendcnt; ++p ) { + const idx_t pp = send_stride * sendmap[p]; + for ( idx_t i = 0; i < field.var_shape[0]; ++i ) { DATA_TYPE tmp = field.data[pp + i * field.var_strides[0]]; send_buffer[ibuf++] = tmp; } } break; case 2: - for ( size_t p = 0; p < sendcnt; ++p ) { - const size_t pp = send_stride * sendmap[p]; - for ( size_t i = 0; i < field.var_shape[0]; ++i ) { - const size_t ii = pp + i * field.var_strides[0]; - for ( size_t j = 0; j < field.var_shape[1]; ++j ) { + for ( idx_t p = 0; p < sendcnt; ++p ) { + const idx_t pp = send_stride * sendmap[p]; + for ( idx_t i = 0; i < field.var_shape[0]; ++i ) { + const idx_t ii = pp + i * field.var_strides[0]; + for ( idx_t j = 0; j < field.var_shape[1]; ++j ) { send_buffer[ibuf++] = field.data[ii + j * field.var_strides[1]]; } } } break; case 3: - for ( size_t p = 0; p < sendcnt; ++p ) { - const size_t pp = send_stride * sendmap[p]; - for ( size_t i = 0; i < field.var_shape[0]; ++i ) { - const size_t ii = pp + i * field.var_strides[0]; - for ( size_t j = 0; j < field.var_shape[1]; ++j ) { - const size_t jj = ii + j * field.var_strides[1]; - for ( size_t k = 0; k < field.var_shape[2]; ++k ) { + for ( idx_t p = 0; p < sendcnt; ++p ) { + const idx_t pp = send_stride * sendmap[p]; + for ( idx_t i = 0; i < field.var_shape[0]; ++i ) { + const idx_t ii = pp + i * field.var_strides[0]; + for ( idx_t j = 0; j < field.var_shape[1]; ++j ) { + const idx_t jj = ii + j * field.var_strides[1]; + for ( idx_t k = 0; k < field.var_shape[2]; ++k ) { send_buffer[ibuf++] = field.data[jj + k * field.var_strides[2]]; } } @@ -360,46 +359,46 @@ void GatherScatter::pack_send_buffer( const parallel::Field& fi } break; default: - NOTIMP; + ATLAS_NOTIMPLEMENTED; } } template void GatherScatter::unpack_recv_buffer( const std::vector& recvmap, const DATA_TYPE recv_buffer[], const parallel::Field& field ) const { - const size_t recvcnt = recvmap.size(); + const idx_t recvcnt = static_cast( recvmap.size() ); - int ibuf = 0; - const size_t recv_stride = field.var_strides[0] * field.var_shape[0]; + int ibuf = 0; + const idx_t recv_stride = field.var_strides[0] * field.var_shape[0]; switch ( field.var_rank ) { case 1: - for ( size_t p = 0; p < recvcnt; ++p ) { - const size_t pp = recv_stride * recvmap[p]; - for ( size_t i = 0; i < field.var_shape[0]; ++i ) { + for ( idx_t p = 0; p < recvcnt; ++p ) { + const idx_t pp = recv_stride * recvmap[p]; + for ( idx_t i = 0; i < field.var_shape[0]; ++i ) { field.data[pp + i * field.var_strides[0]] = recv_buffer[ibuf++]; } } break; case 2: - for ( size_t p = 0; p < recvcnt; ++p ) { - const size_t pp = recv_stride * recvmap[p]; - for ( size_t i = 0; i < field.var_shape[0]; ++i ) { - const size_t ii = pp + i * field.var_strides[0]; - for ( size_t j = 0; j < field.var_shape[1]; ++j ) { + for ( idx_t p = 0; p < recvcnt; ++p ) { + const idx_t pp = recv_stride * recvmap[p]; + for ( idx_t i = 0; i < field.var_shape[0]; ++i ) { + const idx_t ii = pp + i * field.var_strides[0]; + for ( idx_t j = 0; j < field.var_shape[1]; ++j ) { field.data[ii + j * field.var_strides[1]] = recv_buffer[ibuf++]; } } } break; case 3: - for ( size_t p = 0; p < recvcnt; ++p ) { - const size_t pp = recv_stride * recvmap[p]; - for ( size_t i = 0; i < field.var_shape[0]; ++i ) { - const size_t ii = pp + i * field.var_strides[0]; - for ( size_t j = 0; j < field.var_shape[1]; ++j ) { - const size_t jj = ii + j * field.var_strides[1]; - for ( size_t k = 0; k < field.var_shape[2]; ++k ) { + for ( idx_t p = 0; p < recvcnt; ++p ) { + const idx_t pp = recv_stride * recvmap[p]; + for ( idx_t i = 0; i < field.var_shape[0]; ++i ) { + const idx_t ii = pp + i * field.var_strides[0]; + for ( idx_t j = 0; j < field.var_shape[1]; ++j ) { + const idx_t jj = ii + j * field.var_strides[1]; + for ( idx_t k = 0; k < field.var_shape[2]; ++k ) { field.data[jj + k * field.var_strides[2]] = recv_buffer[ibuf++]; } } @@ -407,19 +406,19 @@ void GatherScatter::unpack_recv_buffer( const std::vector& recvmap, const D } break; default: - NOTIMP; + ATLAS_NOTIMPLEMENTED; } } template -void GatherScatter::var_info( const array::ArrayView& arr, std::vector& varstrides, - std::vector& varshape ) const { +void GatherScatter::var_info( const array::ArrayView& arr, std::vector& varstrides, + std::vector& varshape ) const { int rank = std::max( 1, RANK - 1 ); varstrides.resize( rank ); varshape.resize( rank ); if ( RANK > 1 ) { - size_t stride = 1; + idx_t stride = 1; for ( int j = RANK - 1; j > 0; --j ) { varstrides[j - 1] = stride; varshape[j - 1] = arr.shape( j ); @@ -436,35 +435,27 @@ void GatherScatter::var_info( const array::ArrayView& arr, std: template void GatherScatter::gather( const array::ArrayView& ldata, array::ArrayView& gdata, - const size_t root ) const { - if ( ldata.shape( 0 ) == parsize_ && gdata.shape( 0 ) == size_t( glb_cnt( root ) ) ) { + const idx_t root ) const { + if ( ldata.shape( 0 ) == parsize_ && gdata.shape( 0 ) == idx_t( glb_cnt( root ) ) ) { std::vector> lfields( 1, parallel::Field( ldata ) ); std::vector> gfields( 1, parallel::Field( gdata ) ); gather( lfields.data(), gfields.data(), 1, root ); } else { - ATLAS_DEBUG_VAR( parsize_ ); - ATLAS_DEBUG_VAR( ldata.shape( 0 ) ); - ATLAS_DEBUG_VAR( glb_cnt( root ) ); - ATLAS_DEBUG_VAR( gdata.shape( 0 ) ); - NOTIMP; // Need to implement with parallel ranks > 1 + ATLAS_NOTIMPLEMENTED; // Need to implement with parallel ranks > 1 } } template void GatherScatter::scatter( const array::ArrayView& gdata, array::ArrayView& ldata, - const size_t root ) const { - if ( ldata.shape( 0 ) == parsize_ && gdata.shape( 0 ) == size_t( glb_cnt( root ) ) ) { + const idx_t root ) const { + if ( ldata.shape( 0 ) == parsize_ && gdata.shape( 0 ) == idx_t( glb_cnt( root ) ) ) { std::vector> gfields( 1, parallel::Field( gdata ) ); std::vector> lfields( 1, parallel::Field( ldata ) ); scatter( gfields.data(), lfields.data(), 1, root ); } else { - ATLAS_DEBUG_VAR( parsize_ ); - ATLAS_DEBUG_VAR( ldata.shape( 0 ) ); - ATLAS_DEBUG_VAR( glb_cnt( root ) ); - ATLAS_DEBUG_VAR( gdata.shape( 0 ) ); - NOTIMP; // Need to implement with parallel ranks > 1 + ATLAS_NOTIMPLEMENTED; // Need to implement with parallel ranks > 1 } } @@ -473,9 +464,9 @@ void GatherScatter::scatter( const array::ArrayView& gdata, ar extern "C" { GatherScatter* atlas__GatherScatter__new(); void atlas__GatherScatter__delete( GatherScatter* This ); -void atlas__GatherScatter__setup32( GatherScatter* This, int part[], int remote_idx[], int base, int glb_idx[], +void atlas__GatherScatter__setup32( GatherScatter* This, int part[], idx_t remote_idx[], int base, int glb_idx[], int parsize ); -void atlas__GatherScatter__setup64( GatherScatter* This, int part[], int remote_idx[], int base, long glb_idx[], +void atlas__GatherScatter__setup64( GatherScatter* This, int part[], idx_t remote_idx[], int base, long glb_idx[], int parsize ); int atlas__GatherScatter__glb_dof( GatherScatter* This ); void atlas__GatherScatter__gather_int( GatherScatter* This, int ldata[], int lvar_strides[], int lvar_shape[], @@ -504,7 +495,7 @@ void atlas__GatherScatter__scatter_double( GatherScatter* This, double gdata[], int lvar_rank ); } -// ------------------------------------------------------------------ +//-------------------------------------------------------------------------------------------------- // typedef GatherScatter Gather; diff --git a/src/atlas/parallel/HaloExchange.cc b/src/atlas/parallel/HaloExchange.cc index aafd9de0e..48397f91c 100644 --- a/src/atlas/parallel/HaloExchange.cc +++ b/src/atlas/parallel/HaloExchange.cc @@ -11,6 +11,7 @@ /// @author Willem Deconinck /// @date Nov 2013 +#include #include #include #include @@ -24,22 +25,22 @@ namespace parallel { namespace { struct IsGhostPoint { - IsGhostPoint( const int part[], const int ridx[], const int base, const int N ) { + IsGhostPoint( const int part[], const idx_t ridx[], const idx_t base, const int N ) { part_ = part; ridx_ = ridx; base_ = base; mypart_ = mpi::comm().rank(); } - bool operator()( size_t idx ) { + bool operator()( idx_t idx ) { if ( part_[idx] != mypart_ ) return true; - if ( size_t( ridx_[idx] ) != base_ + idx ) return true; + if ( ridx_[idx] != base_ + idx ) return true; return false; } int mypart_; const int* part_; - const int* ridx_; - int base_; + const idx_t* ridx_; + idx_t base_; }; } // namespace @@ -53,7 +54,7 @@ HaloExchange::HaloExchange( const std::string& name ) : name_( name ), is_setup_ nproc = mpi::comm().size(); } -void HaloExchange::setup( const int part[], const int remote_idx[], const int base, const size_t parsize ) { +void HaloExchange::setup( const int part[], const idx_t remote_idx[], const int base, const idx_t parsize ) { ATLAS_TRACE( "HaloExchange::setup" ); parsize_ = parsize; @@ -142,15 +143,15 @@ void execute_halo_exchange( HaloExchange* This, Value field[], int var_strides[] // WARNING: Only works if there is only one parallel dimension AND being // slowest moving - array::ArrayShape shape{size_t( This->backdoor.parsize )}; - for ( size_t j = 0; j < var_rank; ++j ) + array::ArrayShape shape{This->backdoor.parsize}; + for ( int j = 0; j < var_rank; ++j ) shape.push_back( var_extents[j] ); - array::ArrayStrides strides{size_t( var_extents[0] * var_strides[0] )}; - for ( size_t j = 0; j < var_rank; ++j ) + array::ArrayStrides strides{var_extents[0] * var_strides[0]}; + for ( int j = 0; j < var_rank; ++j ) strides.push_back( var_strides[j] ); - eckit::SharedPtr arr( array::Array::wrap( field, array::ArraySpec{shape, strides} ) ); + std::unique_ptr arr( array::Array::wrap( field, array::ArraySpec{shape, strides} ) ); switch ( arr->rank() ) { case 1: { @@ -170,7 +171,7 @@ void execute_halo_exchange( HaloExchange* This, Value field[], int var_strides[] break; } default: - throw eckit::AssertionFailed( "Rank not supported in halo exchange" ); + throw_NotImplemented( "Rank not supported in halo exchange", Here() ); } } } // namespace @@ -185,7 +186,7 @@ void atlas__HaloExchange__delete( HaloExchange* This ) { delete This; } -void atlas__HaloExchange__setup( HaloExchange* This, int part[], int remote_idx[], int base, int size ) { +void atlas__HaloExchange__setup( HaloExchange* This, int part[], idx_t remote_idx[], int base, int size ) { This->setup( part, remote_idx, base, size ); } diff --git a/src/atlas/parallel/HaloExchange.h b/src/atlas/parallel/HaloExchange.h index 92b26b6f1..48a46fd62 100644 --- a/src/atlas/parallel/HaloExchange.h +++ b/src/atlas/parallel/HaloExchange.h @@ -20,16 +20,16 @@ #include "atlas/parallel/HaloExchangeImpl.h" #include "atlas/parallel/mpi/Statistics.h" #include "atlas/parallel/mpi/mpi.h" -#include "eckit/exception/Exceptions.h" -#include "eckit/memory/Owned.h" -#include "eckit/memory/SharedPtr.h" + #include "atlas/array/ArrayView.h" #include "atlas/array/ArrayViewDefs.h" #include "atlas/array/ArrayViewUtil.h" #include "atlas/array/SVector.h" #include "atlas/array_fwd.h" -#include "atlas/runtime/Log.h" +#include "atlas/library/config.h" +#include "atlas/runtime/Exception.h" +#include "atlas/util/Object.h" #ifdef ATLAS_GRIDTOOLS_STORAGE_BACKEND_CUDA #include "atlas/parallel/HaloExchangeCUDA.h" @@ -38,10 +38,7 @@ namespace atlas { namespace parallel { -class HaloExchange : public eckit::Owned { -public: // types - typedef eckit::SharedPtr Ptr; - +class HaloExchange : public util::Object { public: HaloExchange(); HaloExchange( const std::string& name ); @@ -50,25 +47,23 @@ class HaloExchange : public eckit::Owned { public: // methods const std::string& name() const { return name_; } - void setup( const int part[], const int remote_idx[], const int base, size_t size ); + void setup( const int part[], const idx_t remote_idx[], const int base, idx_t size ); // template - // void execute( DATA_TYPE field[], size_t nb_vars ) const; + // void execute( DATA_TYPE field[], idx_t nb_vars ) const; template void execute( array::Array& field, bool on_device = false ) const; private: // methods - void create_mappings( std::vector& send_map, std::vector& recv_map, size_t nb_vars ) const; + void create_mappings( std::vector& send_map, std::vector& recv_map, idx_t nb_vars ) const; template - void create_mappings_impl( std::vector& send_map, std::vector& recv_map, size_t nb_vars ) const; + void create_mappings_impl( std::vector& send_map, std::vector& recv_map, idx_t nb_vars ) const; - size_t index( size_t i, size_t j, size_t k, size_t ni, size_t nj, size_t nk ) const { - return ( i + ni * ( j + nj * k ) ); - } + idx_t index( idx_t i, idx_t j, idx_t k, idx_t ni, idx_t nj, idx_t nk ) const { return ( i + ni * ( j + nj * k ) ); } - size_t index( size_t i, size_t j, size_t ni, size_t nj ) const { return ( i + ni * j ); } + idx_t index( idx_t i, idx_t j, idx_t ni, idx_t nj ) const { return ( i + ni * j ); } template void pack_send_buffer( const array::ArrayView& hfield, @@ -81,8 +76,8 @@ class HaloExchange : public eckit::Owned { array::ArrayView& dfield, const bool on_device ) const; template - void var_info( const array::ArrayView& arr, std::vector& varstrides, - std::vector& varshape ) const; + void var_info( const array::ArrayView& arr, std::vector& varstrides, + std::vector& varshape ) const; private: // data std::string name_; @@ -109,7 +104,7 @@ class HaloExchange : public eckit::Owned { template void HaloExchange::execute( array::Array& field, bool on_device ) const { - if ( !is_setup_ ) { throw eckit::SeriousBug( "HaloExchange was not setup", Here() ); } + if ( !is_setup_ ) { throw_Exception( "HaloExchange was not setup", Here() ); } ATLAS_TRACE( "HaloExchange", {"halo-exchange"} ); @@ -117,7 +112,7 @@ void HaloExchange::execute( array::Array& field, bool on_device ) const { int tag = 1; constexpr int parallelDim = array::get_parallel_dim( field_hv ); - size_t var_size = array::get_var_size( field_hv ); + idx_t var_size = array::get_var_size( field_hv ); int send_size = sendcnt_ * var_size; int recv_size = recvcnt_ * var_size; @@ -184,22 +179,22 @@ void HaloExchange::execute( array::Array& field, bool on_device ) const { template struct halo_packer { template - static void pack( const unsigned int sendcnt, array::SVector const& sendmap, + static void pack( const int sendcnt, array::SVector const& sendmap, const array::ArrayView& field, array::SVector& send_buffer ) { - size_t ibuf = 0; + idx_t ibuf = 0; for ( int node_cnt = 0; node_cnt < sendcnt; ++node_cnt ) { - const size_t node_idx = sendmap[node_cnt]; + const idx_t node_idx = sendmap[node_cnt]; halo_packer_impl::apply( ibuf, node_idx, field, send_buffer ); } } template - static void unpack( const unsigned int recvcnt, array::SVector const& recvmap, + static void unpack( const int recvcnt, array::SVector const& recvmap, array::SVector const& recv_buffer, array::ArrayView& field ) { - size_t ibuf = 0; + idx_t ibuf = 0; for ( int node_cnt = 0; node_cnt < recvcnt; ++node_cnt ) { - const size_t node_idx = recvmap[node_cnt]; + const idx_t node_idx = recvmap[node_cnt]; halo_unpacker_impl::apply( ibuf, node_idx, recv_buffer, field ); } } @@ -234,12 +229,12 @@ void HaloExchange::unpack_recv_buffer( const array::SVector& recv_buf } // template -// void HaloExchange::execute( DATA_TYPE field[], size_t nb_vars ) const +// void HaloExchange::execute( DATA_TYPE field[], idx_t nb_vars ) const //{ -// throw eckit::AssertionFailed("Call not supported"); +// throw_AssertionFailed("Call not supported"); -// size_t strides[] = {1}; -// size_t shape[] = {nb_vars}; +// idx_t strides[] = {1}; +// idx_t shape[] = {nb_vars}; // execute( field, strides, shape, 1); //} @@ -254,7 +249,7 @@ void HaloExchange::unpack_recv_buffer( const array::SVector& recv_buf extern "C" { HaloExchange* atlas__HaloExchange__new(); void atlas__HaloExchange__delete( HaloExchange* This ); -void atlas__HaloExchange__setup( HaloExchange* This, int part[], int remote_idx[], int base, int size ); +void atlas__HaloExchange__setup( HaloExchange* This, int part[], idx_t remote_idx[], int base, int size ); void atlas__HaloExchange__execute_strided_int( HaloExchange* This, int field[], int var_strides[], int var_shape[], int var_rank ); void atlas__HaloExchange__execute_strided_long( HaloExchange* This, long field[], int var_strides[], int var_shape[], diff --git a/src/atlas/parallel/HaloExchangeCUDA.cu b/src/atlas/parallel/HaloExchangeCUDA.cu index 945e65e14..f118f8424 100644 --- a/src/atlas/parallel/HaloExchangeCUDA.cu +++ b/src/atlas/parallel/HaloExchangeCUDA.cu @@ -8,9 +8,11 @@ * does it submit to any jurisdiction. */ + #include "atlas/parallel/HaloExchangeCUDA.h" #include "atlas/parallel/HaloExchangeImpl.h" #include "atlas/array/SVector.h" +#include "atlas/runtime/Exception.h" namespace atlas { namespace parallel { @@ -19,8 +21,8 @@ template struct get_buffer_index{ template ATLAS_HOST_DEVICE - static size_t apply(const array::ArrayView& field, - const size_t node_cnt, const size_t var1_idx) { + static idx_t apply(const array::ArrayView& field, + const idx_t node_cnt, const idx_t var1_idx) { return field.data_view().template length() * field.data_view().template length() * node_cnt + field.data_view().template length() * var1_idx; } @@ -30,20 +32,20 @@ template struct get_buffer_index{ template ATLAS_HOST_DEVICE - static size_t apply(const array::ArrayView& field, - const size_t node_cnt, const size_t var1_idx) { + static idx_t apply(const array::ArrayView& field, + const idx_t node_cnt, const idx_t var1_idx) { return field.data_view().template length<1>() * node_cnt + var1_idx; } }; template -__global__ void pack_kernel(const int sendcnt, const int* sendmap_ptr, const size_t sendmap_size, +__global__ void pack_kernel(const int sendcnt, const int* sendmap_ptr, const idx_t sendmap_size, const array::ArrayView field, DATA_TYPE* send_buffer_ptr, - const size_t send_buffer_size, const typename std::enable_if::type = 0) { + const idx_t send_buffer_size, const typename std::enable_if::type = 0) { const array::SVector sendmap(const_cast(sendmap_ptr), sendmap_size); array::SVector send_buffer(const_cast(send_buffer_ptr), send_buffer_size); - const size_t node_cnt = blockIdx.x*blockDim.x + threadIdx.x; + const idx_t node_cnt = blockIdx.x*blockDim.x + threadIdx.x; if(node_cnt >= sendcnt) return; @@ -51,56 +53,56 @@ __global__ void pack_kernel(const int sendcnt, const int* sendmap_ptr, const siz } template -__global__ void pack_kernel(const int sendcnt, const int* sendmap_ptr, const size_t sendmap_size, +__global__ void pack_kernel(const int sendcnt, const int* sendmap_ptr, const idx_t sendmap_size, const array::ArrayView field, DATA_TYPE* send_buffer_ptr, - const size_t send_buffer_size, const typename std::enable_if=2, int>::type = 0) { + const idx_t send_buffer_size, const typename std::enable_if=2, int>::type = 0) { const array::SVector sendmap(const_cast(sendmap_ptr), sendmap_size); array::SVector send_buffer(const_cast(send_buffer_ptr), send_buffer_size); - const size_t node_cnt = blockIdx.x*blockDim.x + threadIdx.x; - const size_t var1_idx = blockIdx.y*blockDim.y + threadIdx.y; + const idx_t node_cnt = blockIdx.x*blockDim.x + threadIdx.x; + const idx_t var1_idx = blockIdx.y*blockDim.y + threadIdx.y; if(node_cnt >= sendcnt || var1_idx >= field.data_view().template length<1>() ) return; - size_t buff_idx = get_buffer_index::apply(field, node_cnt, var1_idx); - const size_t node_idx = sendmap[node_cnt]; + idx_t buff_idx = get_buffer_index::apply(field, node_cnt, var1_idx); + const idx_t node_idx = sendmap[node_cnt]; halo_packer_impl<0, (RANK>=3) ? (RANK-2) : 0, 2>::apply(buff_idx, node_idx, field, send_buffer, node_idx,var1_idx); } template -__global__ void unpack_kernel(const int recvcnt, const int* recvmap_ptr, const size_t recvmap_size, - const DATA_TYPE* recv_buffer_ptr, const size_t recv_buffer_size, array::ArrayView field, const typename std::enable_if::type = 0) { const array::SVector recvmap(const_cast(recvmap_ptr), recvmap_size); const array::SVector recv_buffer(const_cast(recv_buffer_ptr), recv_buffer_size); - size_t node_cnt = blockIdx.x*blockDim.x + threadIdx.x; + idx_t node_cnt = blockIdx.x*blockDim.x + threadIdx.x; if(node_cnt >= recvcnt) return; - const size_t node_idx = recvmap[node_cnt]; + const idx_t node_idx = recvmap[node_cnt]; field(node_idx) = recv_buffer[node_cnt]; } template -__global__ void unpack_kernel(const int recvcnt, const int* recvmap_ptr, const size_t recvmap_size, - const DATA_TYPE* recv_buffer_ptr, const size_t recv_buffer_size, array::ArrayView field, const typename std::enable_if=2, int>::type = 0) { const array::SVector recvmap(const_cast(recvmap_ptr), recvmap_size); const array::SVector recv_buffer(const_cast(recv_buffer_ptr), recv_buffer_size); - const size_t node_cnt = blockIdx.x*blockDim.x + threadIdx.x; - const size_t var1_idx = blockIdx.y*blockDim.y + threadIdx.y; + const idx_t node_cnt = blockIdx.x*blockDim.x + threadIdx.x; + const idx_t var1_idx = blockIdx.y*blockDim.y + threadIdx.y; if(node_cnt >= recvcnt || var1_idx >= field.data_view().template length<1>() ) return; - const size_t node_idx = recvmap[node_cnt]; + const idx_t node_idx = recvmap[node_cnt]; - size_t buff_idx = get_buffer_index::apply(field, node_cnt, var1_idx); + idx_t buff_idx = get_buffer_index::apply(field, node_cnt, var1_idx); halo_unpacker_impl<0, (RANK>=3) ? (RANK-2) : 0, 2>::apply(buff_idx, node_idx, recv_buffer, field,node_idx,var1_idx); } @@ -156,19 +158,19 @@ void halo_packer_cuda::pack( const int sendcnt, ar cudaError_t err = cudaGetLastError(); if (err != cudaSuccess) { std::string msg = std::string("Error synchronizing device")+ cudaGetErrorString(err); - throw eckit::Exception(msg); + throw_Exception(msg); } pack_kernel<<>>(sendcnt, sendmap.data(), sendmap.size(), dfield, send_buffer.data(), send_buffer.size()); err = cudaGetLastError(); if (err != cudaSuccess) - throw eckit::Exception("Error launching GPU packing kernel"); + throw_Exception("Error launching GPU packing kernel"); cudaDeviceSynchronize(); err = cudaGetLastError(); if (err != cudaSuccess) { std::string msg = std::string("Error synchronizing device")+ cudaGetErrorString(err); - throw eckit::Exception(msg); + throw_Exception(msg); } } @@ -190,7 +192,7 @@ void halo_packer_cuda::unpack(const int recvcnt, a cudaError_t err = cudaGetLastError(); if (err != cudaSuccess) { std::string msg = std::string("Error synchronizing device")+ cudaGetErrorString(err); - throw eckit::Exception(msg); + throw_Exception(msg); } unpack_kernel<<>>(recvcnt, recvmap.data(), recvmap.size(), recv_buffer.data(), recv_buffer.size(), dfield); @@ -198,14 +200,14 @@ void halo_packer_cuda::unpack(const int recvcnt, a err = cudaGetLastError(); if (err != cudaSuccess) { std::string msg = std::string("Error launching GPU packing kernel")+ cudaGetErrorString(err); - throw eckit::Exception(msg); + throw_Exception(msg); } cudaDeviceSynchronize(); err = cudaGetLastError(); if (err != cudaSuccess) { std::string msg = std::string("Error synchronizing device")+ cudaGetErrorString(err); - throw eckit::Exception(msg); + throw_Exception(msg); } } diff --git a/src/atlas/parallel/HaloExchangeImpl.h b/src/atlas/parallel/HaloExchangeImpl.h index 59c15e908..5608379ad 100644 --- a/src/atlas/parallel/HaloExchangeImpl.h +++ b/src/atlas/parallel/HaloExchangeImpl.h @@ -19,10 +19,10 @@ namespace parallel { template struct halo_packer_impl { template - ATLAS_HOST_DEVICE static void apply( size_t& buf_idx, const size_t node_idx, + ATLAS_HOST_DEVICE static void apply( idx_t& buf_idx, const idx_t node_idx, const array::ArrayView& field, array::SVector& send_buffer, Idx... idxs ) { - for ( size_t i = 0; i < field.template shape(); ++i ) { + for ( idx_t i = 0; i < field.template shape(); ++i ) { halo_packer_impl::apply( buf_idx, node_idx, field, send_buffer, idxs..., i ); } @@ -32,7 +32,7 @@ struct halo_packer_impl { template struct halo_packer_impl { template - ATLAS_HOST_DEVICE static void apply( size_t& buf_idx, const size_t node_idx, + ATLAS_HOST_DEVICE static void apply( idx_t& buf_idx, const idx_t node_idx, const array::ArrayView& field, array::SVector& send_buffer, Idx... idxs ) { send_buffer[buf_idx++] = field( idxs... ); @@ -42,7 +42,7 @@ struct halo_packer_impl { template struct halo_packer_impl { template - ATLAS_HOST_DEVICE static void apply( size_t& buf_idx, const size_t node_idx, + ATLAS_HOST_DEVICE static void apply( idx_t& buf_idx, const idx_t node_idx, const array::ArrayView& field, array::SVector& send_buffer, Idx... idxs ) { halo_packer_impl::apply( buf_idx, node_idx, field, send_buffer, idxs..., @@ -53,7 +53,7 @@ struct halo_packer_impl { template struct halo_packer_impl { template - ATLAS_HOST_DEVICE static void apply( size_t& buf_idx, const size_t node_idx, + ATLAS_HOST_DEVICE static void apply( idx_t& buf_idx, const idx_t node_idx, const array::ArrayView& field, array::SVector& send_buffer, Idx... idxs ) { send_buffer[buf_idx++] = field( idxs... ); @@ -63,10 +63,10 @@ struct halo_packer_impl { template struct halo_unpacker_impl { template - ATLAS_HOST_DEVICE static void apply( size_t& buf_idx, const size_t node_idx, + ATLAS_HOST_DEVICE static void apply( idx_t& buf_idx, const idx_t node_idx, array::SVector const& recv_buffer, array::ArrayView& field, Idx... idxs ) { - for ( size_t i = 0; i < field.template shape(); ++i ) { + for ( idx_t i = 0; i < field.template shape(); ++i ) { halo_unpacker_impl::apply( buf_idx, node_idx, recv_buffer, field, idxs..., i ); } @@ -76,7 +76,7 @@ struct halo_unpacker_impl { template struct halo_unpacker_impl { template - ATLAS_HOST_DEVICE static void apply( size_t& buf_idx, const size_t node_idx, + ATLAS_HOST_DEVICE static void apply( idx_t& buf_idx, const idx_t node_idx, array::SVector const& recv_buffer, array::ArrayView& field, Idx... idxs ) { field( idxs... ) = recv_buffer[buf_idx++]; @@ -86,7 +86,7 @@ struct halo_unpacker_impl { template struct halo_unpacker_impl { template - ATLAS_HOST_DEVICE static void apply( size_t& buf_idx, const size_t node_idx, + ATLAS_HOST_DEVICE static void apply( idx_t& buf_idx, const idx_t node_idx, array::SVector const& recv_buffer, array::ArrayView& field, Idx... idxs ) { halo_unpacker_impl::apply( buf_idx, node_idx, recv_buffer, field, @@ -97,7 +97,7 @@ struct halo_unpacker_impl { template struct halo_unpacker_impl { template - ATLAS_HOST_DEVICE static void apply( size_t& buf_idx, const size_t node_idx, + ATLAS_HOST_DEVICE static void apply( idx_t& buf_idx, const idx_t node_idx, array::SVector const& recv_buffer, array::ArrayView& field, Idx... idxs ) { field( idxs... ) = recv_buffer[buf_idx++]; diff --git a/src/atlas/parallel/omp/omp.h b/src/atlas/parallel/omp/omp.h index 98858f65e..98f9abc5d 100644 --- a/src/atlas/parallel/omp/omp.h +++ b/src/atlas/parallel/omp/omp.h @@ -24,14 +24,14 @@ void atlas_omp_set_nested( int nested ); int atlas_omp_get_nested( void ); #if ATLAS_HAVE_OMP -#define __ATLAS_OMP_STR( x ) #x -#define __ATLAS_OMP_STRINGIFY( x ) __ATLAS_OMP_STR( x ) -#define atlas_omp_pragma( x ) _Pragma( __ATLAS_OMP_STRINGIFY( x ) ) +#define ATLAS_OMP_STR( x ) #x +#define ATLAS_OMP_STRINGIFY( x ) ATLAS_OMP_STR( x ) +#define atlas_omp_pragma( x ) _Pragma( ATLAS_OMP_STRINGIFY( x ) ) #else #define atlas_omp_pragma( x ) #endif -#define atlas_omp_parallel_for atlas_omp_pragma(omp parallel for) for +#define atlas_omp_parallel_for atlas_omp_pragma(omp parallel for schedule(static) ) for #define atlas_omp_for atlas_omp_pragma(omp for) for #define atlas_omp_parallel atlas_omp_pragma( omp parallel ) #define atlas_omp_critical atlas_omp_pragma( omp critical ) @@ -48,12 +48,12 @@ class atlas_omp_scoped_helper { bool once_; }; -#define __atlas_omp_scoped( T, VAR, VAL ) for ( atlas_omp_scoped_helper VAR( VAL ); VAR.once(); VAR.done() ) +#define _atlas_omp_scoped( T, VAR, VAL ) for ( atlas_omp_scoped_helper VAR( VAL ); VAR.once(); VAR.done() ) -#define atlas_omp_critical_ordered \ - __atlas_omp_scoped(const size_t, _nthreads, atlas_omp_get_num_threads()) \ +#define atlas_omp_critical_ordered \ + _atlas_omp_scoped(const size_t, _nthreads, atlas_omp_get_num_threads()) \ atlas_omp_pragma( omp for ordered schedule(static,1) )\ for( size_t _thread=0; _thread<_nthreads.value; ++_thread )\ atlas_omp_pragma( omp ordered ) -#undef __atlas_omp_scoped +#undef _atlas_omp_scoped diff --git a/src/atlas/projection/Projection.cc b/src/atlas/projection/Projection.cc index 2366fe3b7..65acd4199 100644 --- a/src/atlas/projection/Projection.cc +++ b/src/atlas/projection/Projection.cc @@ -8,20 +8,58 @@ * nor does it submit to any jurisdiction. */ +#include "eckit/utils/Hash.h" + +#include "atlas/option/Options.h" #include "atlas/projection/Projection.h" +#include "atlas/projection/detail/LonLatProjection.h" +#include "atlas/projection/detail/ProjectionImpl.h" +#include "atlas/util/Config.h" namespace atlas { -Projection::Projection() : projection_( Implementation::create() ) {} - -Projection::Projection( const Projection& projection ) : projection_( projection.projection_ ) {} +Projection::Projection() : Handle( new projection::detail::LonLatProjection() ) {} -Projection::Projection( const Implementation* projection ) : projection_( const_cast( projection ) ) {} +Projection::Projection( const eckit::Parametrisation& p ) : Handle( Implementation::create( p ) ) {} -Projection::Projection( const eckit::Parametrisation& p ) : projection_( Implementation::create( p ) ) {} +atlas::Projection::operator bool() const { + return get()->operator bool(); +} void Projection::hash( eckit::Hash& h ) const { - return projection_->hash( h ); + return get()->hash( h ); +} + +void atlas::Projection::xy2lonlat( double crd[] ) const { + return get()->xy2lonlat( crd ); +} + +void atlas::Projection::lonlat2xy( double crd[] ) const { + return get()->lonlat2xy( crd ); +} + +PointLonLat atlas::Projection::lonlat( const PointXY& xy ) const { + return get()->lonlat( xy ); +} + +PointXY atlas::Projection::xy( const PointLonLat& lonlat ) const { + return get()->xy( lonlat ); +} + +bool atlas::Projection::strictlyRegional() const { + return get()->strictlyRegional(); +} + +Projection::Spec atlas::Projection::spec() const { + return get()->spec(); +} + +std::string atlas::Projection::units() const { + return get()->units(); +} + +std::string Projection::type() const { + return get()->type(); } } // namespace atlas diff --git a/src/atlas/projection/Projection.h b/src/atlas/projection/Projection.h index ed1797a3f..a7af6650e 100644 --- a/src/atlas/projection/Projection.h +++ b/src/atlas/projection/Projection.h @@ -12,37 +12,44 @@ #include -#include "eckit/config/Parametrisation.h" -#include "eckit/memory/SharedPtr.h" -#include "eckit/utils/Hash.h" - -#include "atlas/projection/detail/ProjectionImpl.h" -#include "atlas/util/Point.h" +#include "atlas/util/ObjectHandle.h" //--------------------------------------------------------------------------------------------------------------------- // Forward declarations namespace eckit { class Parametrisation; -} +class Hash; +} // namespace eckit //--------------------------------------------------------------------------------------------------------------------- namespace atlas { +class PointLonLat; +class PointXY; + //--------------------------------------------------------------------------------------------------------------------- +namespace util { +class Config; +} +namespace projection { +namespace detail { +class ProjectionImpl; +} +} // namespace projection -class Projection { +class Projection : public util::ObjectHandle { public: - using Implementation = projection::detail::ProjectionImpl; - using Spec = Implementation::Spec; + using Spec = util::Config; public: + using Handle::Handle; Projection(); - Projection( const Projection& ); - Projection( const Implementation* ); Projection( const eckit::Parametrisation& ); + operator bool() const; + void xy2lonlat( double crd[] ) const; void lonlat2xy( double crd[] ) const; @@ -55,43 +62,11 @@ class Projection { std::string units() const; - operator bool() const; - - std::string type() const { return projection_->type(); } + std::string type() const; void hash( eckit::Hash& ) const; - -private: - eckit::SharedPtr projection_; }; //--------------------------------------------------------------------------------------------------------------------- -inline void Projection::xy2lonlat( double crd[] ) const { - return projection_->xy2lonlat( crd ); -} -inline void Projection::lonlat2xy( double crd[] ) const { - return projection_->lonlat2xy( crd ); -} -inline PointLonLat Projection::lonlat( const PointXY& xy ) const { - return projection_->lonlat( xy ); -} -inline PointXY Projection::xy( const PointLonLat& lonlat ) const { - return projection_->xy( lonlat ); -} -inline bool Projection::strictlyRegional() const { - return projection_->strictlyRegional(); -} -inline Projection::Spec Projection::spec() const { - return projection_->spec(); -} -inline std::string Projection::units() const { - return projection_->units(); -} -inline Projection::operator bool() const { - return projection_->operator bool(); -} - -//--------------------------------------------------------------------------------------------------------------------- - } // namespace atlas diff --git a/src/atlas/projection/detail/LambertProjection.cc b/src/atlas/projection/detail/LambertProjection.cc index 45cbe479e..f579e204f 100644 --- a/src/atlas/projection/detail/LambertProjection.cc +++ b/src/atlas/projection/detail/LambertProjection.cc @@ -9,8 +9,14 @@ */ #include +#include + +#include "eckit/utils/Hash.h" #include "atlas/projection/detail/LambertProjection.h" +#include "atlas/projection/detail/ProjectionFactory.h" +#include "atlas/runtime/Exception.h" +#include "atlas/util/Config.h" #include "atlas/util/Constants.h" #include "atlas/util/Earth.h" @@ -40,17 +46,17 @@ LambertProjection::LambertProjection( const eckit::Parametrisation& params ) { // check presence of radius if ( !params.get( "radius", radius_ ) ) radius_ = util::Earth::radius(); // check presence of lat1 and lat2 - if ( !params.get( "latitude1", lat1_ ) ) throw eckit::BadParameter( "latitude1 missing in Params", Here() ); + if ( !params.get( "latitude1", lat1_ ) ) throw_Exception( "latitude1 missing in Params", Here() ); if ( !params.get( "latitude2", lat2_ ) ) lat2_ = lat1_; // check presence of lon0 - if ( !params.get( "longitude0", lon0_ ) ) throw eckit::BadParameter( "longitude0 missing in Params", Here() ); + if ( !params.get( "longitude0", lon0_ ) ) throw_Exception( "longitude0 missing in Params", Here() ); setup(); } void LambertProjection::setup() { // setup (derived) constants - is_tangent_ = ( lat1_ == lat2_ ); + is_tangent_ = std::equal_to()( lat1_, lat2_ ); if ( is_tangent_ ) { n_ = std::sin( D2R( lat1_ ) ); } else { n_ = std::log( std::cos( D2R( lat1_ ) ) / std::cos( D2R( lat2_ ) ) ) / @@ -95,7 +101,7 @@ LambertProjection::Spec LambertProjection::spec() const { proj_spec.set( "latitude1", lat1_ ); proj_spec.set( "latitude2", lat2_ ); proj_spec.set( "longitude0", lon0_ ); - if ( radius_ != util::Earth::radius() ) proj_spec.set( "radius", radius_ ); + if ( std::not_equal_to()( radius_, util::Earth::radius() ) ) proj_spec.set( "radius", radius_ ); return proj_spec; } @@ -107,7 +113,9 @@ void LambertProjection::hash( eckit::Hash& hsh ) const { hsh.add( radius_ ); } -register_BuilderT1( ProjectionImpl, LambertProjection, LambertProjection::static_type() ); +namespace { +static ProjectionBuilder register_projection( LambertProjection::static_type() ); +} // namespace } // namespace detail } // namespace projection diff --git a/src/atlas/projection/detail/LambertProjection.h b/src/atlas/projection/detail/LambertProjection.h index 71975cf6a..6fb507969 100644 --- a/src/atlas/projection/detail/LambertProjection.h +++ b/src/atlas/projection/detail/LambertProjection.h @@ -22,7 +22,7 @@ class LambertProjection : public ProjectionImpl { LambertProjection( const eckit::Parametrisation& p ); // destructor - ~LambertProjection() {} + ~LambertProjection() override {} // class name static std::string static_type() { return "lambert"; } diff --git a/src/atlas/projection/detail/LonLatProjection.cc b/src/atlas/projection/detail/LonLatProjection.cc index aa19fe94b..75a0abb15 100644 --- a/src/atlas/projection/detail/LonLatProjection.cc +++ b/src/atlas/projection/detail/LonLatProjection.cc @@ -8,7 +8,11 @@ * nor does it submit to any jurisdiction. */ +#include "eckit/utils/Hash.h" + #include "atlas/projection/detail/LonLatProjection.h" +#include "atlas/projection/detail/ProjectionFactory.h" +#include "atlas/util/Config.h" namespace atlas { namespace projection { @@ -33,8 +37,13 @@ void LonLatProjectionT::hash( eckit::Hash& hsh ) const { rotation_.hash( hsh ); } -register_BuilderT1( ProjectionImpl, LonLatProjection, LonLatProjection::static_type() ); -register_BuilderT1( ProjectionImpl, RotatedLonLatProjection, RotatedLonLatProjection::static_type() ); +template class LonLatProjectionT; +template class LonLatProjectionT; + +namespace { +static ProjectionBuilder register_1( LonLatProjection::static_type() ); +static ProjectionBuilder register_2( RotatedLonLatProjection::static_type() ); +} // namespace } // namespace detail } // namespace projection diff --git a/src/atlas/projection/detail/LonLatProjection.h b/src/atlas/projection/detail/LonLatProjection.h index 5208c23ef..9e01459af 100644 --- a/src/atlas/projection/detail/LonLatProjection.h +++ b/src/atlas/projection/detail/LonLatProjection.h @@ -11,7 +11,10 @@ #pragma once #include "atlas/projection/detail/ProjectionImpl.h" -#include "atlas/runtime/Log.h" + +namespace atlas { +class Projection; +} namespace atlas { namespace projection { @@ -20,8 +23,8 @@ namespace detail { template class LonLatProjectionT : public ProjectionImpl { private: - friend class ProjectionImpl; - LonLatProjectionT() : ProjectionImpl() {} + friend class atlas::Projection; + LonLatProjectionT() = default; public: // constructor @@ -53,8 +56,8 @@ class LonLatProjectionT : public ProjectionImpl { Rotation rotation_; }; -typedef LonLatProjectionT LonLatProjection; -typedef LonLatProjectionT RotatedLonLatProjection; +using LonLatProjection = LonLatProjectionT; +using RotatedLonLatProjection = LonLatProjectionT; // -------------------------------------------------------------------------------------------------------------------- diff --git a/src/atlas/projection/detail/MercatorProjection.cc b/src/atlas/projection/detail/MercatorProjection.cc index 5f1768d3e..92602299b 100644 --- a/src/atlas/projection/detail/MercatorProjection.cc +++ b/src/atlas/projection/detail/MercatorProjection.cc @@ -9,8 +9,14 @@ */ #include +#include + +#include "eckit/config/Parametrisation.h" +#include "eckit/utils/Hash.h" #include "atlas/projection/detail/MercatorProjection.h" +#include "atlas/projection/detail/ProjectionFactory.h" +#include "atlas/util/Config.h" #include "atlas/util/Constants.h" #include "atlas/util/Earth.h" @@ -74,7 +80,7 @@ typename MercatorProjectionT::Spec MercatorProjectionT::spec Spec proj_spec; proj_spec.set( "type", static_type() ); proj_spec.set( "longitude0", lon0_ ); - if ( radius_ != util::Earth::radius() ) proj_spec.set( "radius", radius_ ); + if ( std::not_equal_to()( radius_, util::Earth::radius() ) ) { proj_spec.set( "radius", radius_ ); } rotation_.spec( proj_spec ); return proj_spec; } @@ -87,8 +93,13 @@ void MercatorProjectionT::hash( eckit::Hash& hsh ) const { hsh.add( radius_ ); } -register_BuilderT1( ProjectionImpl, MercatorProjection, MercatorProjection::static_type() ); -register_BuilderT1( ProjectionImpl, RotatedMercatorProjection, RotatedMercatorProjection::static_type() ); +template class MercatorProjectionT; +template class MercatorProjectionT; + +namespace { +static ProjectionBuilder register_1( MercatorProjection::static_type() ); +static ProjectionBuilder register_2( RotatedMercatorProjection::static_type() ); +} // namespace } // namespace detail } // namespace projection diff --git a/src/atlas/projection/detail/MercatorProjection.h b/src/atlas/projection/detail/MercatorProjection.h index de50b37de..cb1f0291a 100644 --- a/src/atlas/projection/detail/MercatorProjection.h +++ b/src/atlas/projection/detail/MercatorProjection.h @@ -52,8 +52,8 @@ class MercatorProjectionT : public ProjectionImpl { Rotation rotation_; }; -typedef MercatorProjectionT MercatorProjection; -typedef MercatorProjectionT RotatedMercatorProjection; +using MercatorProjection = MercatorProjectionT; +using RotatedMercatorProjection = MercatorProjectionT; } // namespace detail } // namespace projection diff --git a/src/atlas/projection/detail/ProjectionFactory.cc b/src/atlas/projection/detail/ProjectionFactory.cc new file mode 100644 index 000000000..4522fa71b --- /dev/null +++ b/src/atlas/projection/detail/ProjectionFactory.cc @@ -0,0 +1,57 @@ +/* + * (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 "atlas/projection/Projection.h" +#include "atlas/projection/detail/ProjectionFactory.h" +#include "atlas/util/Config.h" + +#include "atlas/projection/detail/LambertProjection.h" +#include "atlas/projection/detail/LonLatProjection.h" +#include "atlas/projection/detail/MercatorProjection.h" +#include "atlas/projection/detail/SchmidtProjection.h" + +namespace atlas { +namespace projection { + +//---------------------------------------------------------------------------------------------------------------------- + +void force_link() { + static struct Link { + Link() { + ProjectionBuilder(); + ProjectionBuilder(); + ProjectionBuilder(); + ProjectionBuilder(); + ProjectionBuilder(); + ProjectionBuilder(); + ProjectionBuilder(); + } + } link; +} + +//---------------------------------------------------------------------------------------------------------------------- + +const Projection::Implementation* ProjectionFactory::build( const std::string& builder ) { + return build( builder, util::NoConfig() ); +} + +const Projection::Implementation* ProjectionFactory::build( const std::string& builder, + const eckit::Parametrisation& param ) { + force_link(); + auto factory = get( builder ); + return factory->make( param ); +} + +//---------------------------------------------------------------------------------------------------------------------- + +} // namespace projection +} // namespace atlas diff --git a/src/atlas/projection/detail/ProjectionFactory.h b/src/atlas/projection/detail/ProjectionFactory.h new file mode 100644 index 000000000..72b54d4da --- /dev/null +++ b/src/atlas/projection/detail/ProjectionFactory.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 + +#include + +#include "atlas/projection/Projection.h" +#include "atlas/util/Factory.h" + +namespace eckit { +class Parametrisation; +} + +namespace atlas { +namespace projection { + +//---------------------------------------------------------------------------------------------------------------------- + +class ProjectionFactory : public util::Factory { +public: + static std::string className() { return "ProjectionFactory"; } + static const Projection::Implementation* build( const std::string& ); + static const Projection::Implementation* build( const std::string&, const eckit::Parametrisation& ); + using Factory::Factory; + +private: + virtual const Projection::Implementation* make( const eckit::Parametrisation& ) = 0; +}; + +//---------------------------------------------------------------------------------------------------------------------- + +template +class ProjectionBuilder : public ProjectionFactory { +private: + virtual const Projection::Implementation* make( const eckit::Parametrisation& param ) { return new T( param ); } + +public: + using ProjectionFactory::ProjectionFactory; +}; + +//---------------------------------------------------------------------------------------------------------------------- + +} // namespace projection +} // namespace atlas diff --git a/src/atlas/projection/detail/ProjectionImpl.cc b/src/atlas/projection/detail/ProjectionImpl.cc index 40f2b8c35..a31f0d78f 100644 --- a/src/atlas/projection/detail/ProjectionImpl.cc +++ b/src/atlas/projection/detail/ProjectionImpl.cc @@ -8,27 +8,25 @@ * nor does it submit to any jurisdiction. */ -#include "atlas/projection/detail/ProjectionImpl.h" +#include "eckit/utils/Hash.h" + #include "atlas/projection/detail/LonLatProjection.h" +#include "atlas/projection/detail/ProjectionFactory.h" +#include "atlas/projection/detail/ProjectionImpl.h" +#include "atlas/runtime/Exception.h" #include "atlas/util/Config.h" + namespace atlas { namespace projection { namespace detail { -ProjectionImpl* ProjectionImpl::create() { - // default: no projection, i.e. stay in (lon,lat)-space - return new LonLatProjection(); -} - -ProjectionImpl* ProjectionImpl::create( const eckit::Parametrisation& p ) { +const ProjectionImpl* ProjectionImpl::create( const eckit::Parametrisation& p ) { std::string projectionType; - if ( p.get( "type", projectionType ) ) { - return eckit::Factory::instance().get( projectionType ).create( p ); - } + if ( p.get( "type", projectionType ) ) { return ProjectionFactory::build( projectionType, p ); } // should return error here - throw eckit::BadParameter( "type missing in Params", Here() ); + throw_Exception( "type missing in Params", Here() ); } Rotated::Rotated( const PointLonLat& south_pole, double rotation_angle ) : diff --git a/src/atlas/projection/detail/ProjectionImpl.h b/src/atlas/projection/detail/ProjectionImpl.h index 4d11b8114..9ade4a3d9 100644 --- a/src/atlas/projection/detail/ProjectionImpl.h +++ b/src/atlas/projection/detail/ProjectionImpl.h @@ -12,29 +12,31 @@ #include -#include "eckit/config/Parametrisation.h" -#include "eckit/memory/Builder.h" -#include "eckit/memory/Owned.h" -#include "eckit/utils/Hash.h" - -#include "atlas/util/Config.h" +#include "atlas/util/Object.h" #include "atlas/util/Point.h" #include "atlas/util/Rotation.h" +namespace eckit { +class Parametrisation; +class Hash; +} // namespace eckit + +namespace atlas { +namespace util { +class Config; +} +} // namespace atlas + namespace atlas { namespace projection { namespace detail { -class ProjectionImpl : public eckit::Owned { +class ProjectionImpl : public util::Object { public: - using ARG1 = const eckit::Parametrisation&; - using builder_t = eckit::BuilderT1; - using Spec = atlas::util::Config; - static std::string className() { return "atlas.Projection"; } + using Spec = atlas::util::Config; public: - static ProjectionImpl* create(); // creates the LonLatProjection - static ProjectionImpl* create( const eckit::Parametrisation& p ); + static const ProjectionImpl* create( const eckit::Parametrisation& p ); ProjectionImpl() {} virtual ~ProjectionImpl() {} // destructor should be virtual @@ -97,9 +99,9 @@ class NotRotated { static std::string classNamePrefix() { return ""; } // deliberately empty static std::string typePrefix() { return ""; } // deliberately empty - void rotate( double crd[] ) const { /* do nothing */ + void rotate( double* ) const { /* do nothing */ } - void unrotate( double crd[] ) const { /* do nothing */ + void unrotate( double* ) const { /* do nothing */ } bool rotated() const { return false; } diff --git a/src/atlas/projection/detail/SchmidtProjection.cc b/src/atlas/projection/detail/SchmidtProjection.cc index adfca413b..186ce9adc 100644 --- a/src/atlas/projection/detail/SchmidtProjection.cc +++ b/src/atlas/projection/detail/SchmidtProjection.cc @@ -10,7 +10,13 @@ #include +#include "eckit/config/Parametrisation.h" +#include "eckit/utils/Hash.h" + +#include "atlas/projection/detail/ProjectionFactory.h" #include "atlas/projection/detail/SchmidtProjection.h" +#include "atlas/runtime/Exception.h" +#include "atlas/util/Config.h" #include "atlas/util/Constants.h" namespace { @@ -31,10 +37,13 @@ template SchmidtProjectionT::SchmidtProjectionT( const eckit::Parametrisation& params ) : ProjectionImpl(), rotation_( params ) { - if ( !params.get( "stretching_factor", c_ ) ) - throw eckit::BadParameter( "stretching_factor missing in Params", Here() ); + if ( !params.get( "stretching_factor", c_ ) ) throw_Exception( "stretching_factor missing in Params", Here() ); } +// constructor +template +SchmidtProjectionT::SchmidtProjectionT() : ProjectionImpl(), rotation_( util::NoConfig() ) {} + template void SchmidtProjectionT::xy2lonlat( double crd[] ) const { // stretch @@ -72,8 +81,13 @@ void SchmidtProjectionT::hash( eckit::Hash& hsh ) const { hsh.add( c_ ); } -register_BuilderT1( ProjectionImpl, SchmidtProjection, SchmidtProjection::static_type() ); -register_BuilderT1( ProjectionImpl, RotatedSchmidtProjection, RotatedSchmidtProjection::static_type() ); +template class SchmidtProjectionT; +template class SchmidtProjectionT; + +namespace { +static ProjectionBuilder register_1( SchmidtProjection::static_type() ); +static ProjectionBuilder register_2( RotatedSchmidtProjection::static_type() ); +} // namespace } // namespace detail } // namespace projection diff --git a/src/atlas/projection/detail/SchmidtProjection.h b/src/atlas/projection/detail/SchmidtProjection.h index 53ffe62a3..df61f9da2 100644 --- a/src/atlas/projection/detail/SchmidtProjection.h +++ b/src/atlas/projection/detail/SchmidtProjection.h @@ -21,7 +21,7 @@ class SchmidtProjectionT : public ProjectionImpl { public: // constructor SchmidtProjectionT( const eckit::Parametrisation& p ); - SchmidtProjectionT() {} + SchmidtProjectionT(); // class name static std::string static_type() { return Rotation::typePrefix() + "schmidt"; } @@ -45,8 +45,8 @@ class SchmidtProjectionT : public ProjectionImpl { Rotation rotation_; }; -typedef SchmidtProjectionT SchmidtProjection; -typedef SchmidtProjectionT RotatedSchmidtProjection; +using SchmidtProjection = SchmidtProjectionT; +using RotatedSchmidtProjection = SchmidtProjectionT; } // namespace detail } // namespace projection diff --git a/src/atlas/runtime/AtlasTool.cc b/src/atlas/runtime/AtlasTool.cc index 62f95a8ba..efd6fc746 100644 --- a/src/atlas/runtime/AtlasTool.cc +++ b/src/atlas/runtime/AtlasTool.cc @@ -17,6 +17,12 @@ #include "atlas/library/config.h" #include "atlas/runtime/AtlasTool.h" +namespace atlas { +static void usage( const std::string& name ) { + Log::info() << "dummy usage" << std::endl; +} +} // namespace atlas + namespace { int digits( int number ) { @@ -181,7 +187,7 @@ void atlas::AtlasTool::setupLogging() { eckit::LogTarget* logfile = new eckit::FileTarget( displayName() + ".log.p" + rankstr ); - if ( mpi::comm().rank() == log_rank ) { + if ( int( mpi::comm().rank() ) == log_rank ) { if ( Log::info() ) Log::info().addTarget( logfile ); if ( Log::warning() ) Log::warning().addTarget( logfile ); if ( Log::error() ) Log::error().addTarget( logfile ); @@ -195,7 +201,7 @@ void atlas::AtlasTool::setupLogging() { } } else { - if ( mpi::comm().rank() != log_rank ) { + if ( int( mpi::comm().rank() ) != log_rank ) { if ( Log::info() ) Log::info().reset(); if ( Log::warning() ) Log::warning().reset(); if ( Log::error() ) Log::error().reset(); diff --git a/src/atlas/runtime/AtlasTool.h b/src/atlas/runtime/AtlasTool.h index 97398956c..b05b8c568 100644 --- a/src/atlas/runtime/AtlasTool.h +++ b/src/atlas/runtime/AtlasTool.h @@ -35,10 +35,6 @@ using eckit::option::VectorOption; namespace atlas { -static void usage( const std::string& name ) { - Log::info() << "dummy usage" << std::endl; -} - class AtlasTool : public eckit::Tool { protected: typedef std::vector Options; diff --git a/src/atlas/runtime/ErrorHandling.cc b/src/atlas/runtime/ErrorHandling.cc deleted file mode 100644 index 2fe0d5d48..000000000 --- a/src/atlas/runtime/ErrorHandling.cc +++ /dev/null @@ -1,182 +0,0 @@ -#include "eckit/log/CodeLocation.h" -#include "eckit/os/BackTrace.h" -#include "eckit/utils/Translator.h" - -#include "atlas/parallel/mpi/mpi.h" -#include "atlas/runtime/ErrorHandling.h" -#include "atlas/runtime/Log.h" - -using namespace atlas; - -namespace { // anonymous -template -static bool get_env( const std::string& var, T& val ) { - const char* env = ::getenv( var.c_str() ); - if ( env ) { - std::string val_str = env; - val = eckit::Translator()( val_str ); - return true; - } - return false; -} -} // namespace - -namespace atlas { -namespace runtime { - -Error::Error() { - clear(); - throws_ = false; - aborts_ = true; - backtrace_ = true; - get_env( "ATLAS_ERROR_THROWS", throws_ ); - get_env( "ATLAS_ERROR_ABORTS", aborts_ ); - get_env( "ATLAS_ERROR_BACKTRACE", backtrace_ ); -} - -Error& Error::instance() { - static Error error_instance; - return error_instance; -} - -void Error::clear() { - code_ = atlas_err_cleared; - msg_ = std::string( "Error code was not set!" ); -} - -void handle_error( const eckit::Exception& exception, const int errorCode ) { - std::stringstream msg; - if ( Error::instance().backtrace() || Error::instance().aborts() ) { - msg << "=========================================\n" - << "ERROR\n" - << "-----------------------------------------\n" - << exception.what() << "\n"; - if ( exception.location() ) - msg << "-----------------------------------------\n" - << "LOCATION: " << exception.location() << "\n"; - - msg << "-----------------------------------------\n" - << "BACKTRACE\n" - << "-----------------------------------------\n" - << exception.callStack() << "\n" - << "========================================="; - } - else { - msg << exception.what(); - } - Error::instance().set_code( errorCode ); - Error::instance().set_msg( msg.str() ); - - if ( Error::instance().aborts() ) { - Log::error() << msg.str() << std::endl; - mpi::comm().abort( errorCode ); - } - if ( Error::instance().throws() ) { throw exception; } -} - -} // namespace runtime -} // namespace atlas - -using eckit::AssertionFailed; -using eckit::BackTrace; -using eckit::CodeLocation; -using eckit::Exception; -using eckit::Exception; -using eckit::NotImplemented; -using eckit::OutOfRange; -using eckit::SeriousBug; -using eckit::UserError; - -void atlas__Error_set_aborts( int on_off ) { - atlas::runtime::Error::instance().set_aborts( on_off ); -} - -void atlas__Error_set_throws( int on_off ) { - atlas::runtime::Error::instance().set_throws( on_off ); -} - -void atlas__Error_set_backtrace( int on_off ) { - atlas::runtime::Error::instance().set_backtrace( on_off ); -} - -void atlas__Error_success() { - atlas::runtime::Error::instance().set_code( atlas::runtime::atlas_err_noerr ); - atlas::runtime::Error::instance().set_msg( std::string() ); -} - -void atlas__Error_clear() { - atlas::runtime::Error::instance().clear(); -} - -int atlas__Error_code() { - return atlas::runtime::Error::instance().code(); -} - -char* atlas__Error_msg() { - return const_cast( atlas::runtime::Error::instance().msg().c_str() ); -} - -template -EXCEPTION create_exception( char* msg, char* file, int line, char* function ) { - if ( file && std::string( file ).size() && std::string( msg ).size() ) - return EXCEPTION( std::string( msg ), CodeLocation( file, line, function ) ); - else if ( file && std::string( file ).size() ) - return EXCEPTION( std::string(), CodeLocation( file, line, function ) ); - else if ( std::string( msg ).size() ) - return EXCEPTION( std::string( msg ), CodeLocation() ); - else - return EXCEPTION( std::string(), CodeLocation() ); -} - -void atlas__throw_exception( char* msg, char* file, int line, char* function ) { - Exception exception( create_exception( msg, file, line, function ) ); - atlas::runtime::handle_error( exception, atlas::runtime::atlas_err_exception ); -} - -void atlas__throw_notimplemented( char* msg, char* file, int line, char* function ) { - NotImplemented exception( create_exception( msg, file, line, function ) ); - atlas::runtime::handle_error( exception, atlas::runtime::atlas_err_notimplemented ); -} - -void atlas__throw_outofrange( char* msg, char* file, int line, char* function ) { - OutOfRange exception( create_exception( msg, file, line, function ) ); - atlas::runtime::handle_error( exception, atlas::runtime::atlas_err_outofrange ); -} - -void atlas__throw_usererror( char* msg, char* file, int line, char* function ) { - UserError exception( create_exception( msg, file, line, function ) ); - atlas::runtime::handle_error( exception, atlas::runtime::atlas_err_usererror ); -} - -void atlas__throw_assertionfailed( char* msg, char* file, int line, char* function ) { - AssertionFailed exception( create_exception( msg, file, line, function ) ); - atlas::runtime::handle_error( exception, atlas::runtime::atlas_err_assertionfailed ); -} - -void atlas__throw_seriousbug( char* msg, char* file, int line, char* function ) { - SeriousBug exception( create_exception( msg, file, line, function ) ); - atlas::runtime::handle_error( exception, atlas::runtime::atlas_err_seriousbug ); -} - -void atlas__abort( char* msg, char* file, int line, char* function ) { - Log::error() << "=========================================\n" - << "ABORT\n"; - if ( msg && std::string( msg ).size() ) - Log::error() << "-----------------------------------------\n" << msg << "\n"; - - if ( file && std::string( file ).size() ) - Log::error() << "-----------------------------------------\n" - << "LOCATION: " << CodeLocation( file, line, function ) << "\n"; - - Log::error() << "-----------------------------------------\n" - << "BACKTRACE\n" - << "-----------------------------------------\n" - << BackTrace::dump() << "\n" - << "=========================================" << std::endl; - - mpi::comm().abort( -1 ); -} - -void atlas__error_example() { - ATLAS_ERROR_HANDLING( throw OutOfRange( 12, 5, Here() ) ); -} diff --git a/src/atlas/runtime/ErrorHandling.h b/src/atlas/runtime/ErrorHandling.h deleted file mode 100644 index 8b083a15a..000000000 --- a/src/atlas/runtime/ErrorHandling.h +++ /dev/null @@ -1,121 +0,0 @@ -#pragma once - -#include "eckit/exception/Exceptions.h" - -namespace atlas { -namespace runtime { - -static const int atlas_err_cleared = 1; -static const int atlas_err_noerr = 0; -static const int atlas_err_exception = -1; -static const int atlas_err_usererror = -2; -static const int atlas_err_seriousbug = -3; -static const int atlas_err_notimplemented = -4; -static const int atlas_err_assertionfailed = -5; -static const int atlas_err_badparameter = -6; -static const int atlas_err_outofrange = -7; -static const int atlas_err_stop = -100; -static const int atlas_err_abort = -101; -static const int atlas_err_cancel = -102; -static const int atlas_err_readerror = -200; -static const int atlas_err_writeerror = -201; -static const int atlas_err_unknown = -999; - -void handle_error( const eckit::Exception& exception, const int err_code ); - -#define ATLAS_ERROR_HANDLING( STATEMENTS ) \ - do { \ - try { \ - STATEMENTS; \ - } \ - catch ( eckit::SeriousBug & e ) { \ - atlas::runtime::handle_error( e, atlas::runtime::atlas_err_seriousbug ); \ - } \ - catch ( eckit::NotImplemented & e ) { \ - atlas::runtime::handle_error( e, atlas::runtime::atlas_err_notimplemented ); \ - } \ - catch ( eckit::OutOfRange & e ) { \ - atlas::runtime::handle_error( e, atlas::runtime::atlas_err_outofrange ); \ - } \ - catch ( eckit::UserError & e ) { \ - atlas::runtime::handle_error( e, atlas::runtime::atlas_err_usererror ); \ - } \ - catch ( eckit::AssertionFailed & e ) { \ - atlas::runtime::handle_error( e, atlas::runtime::atlas_err_assertionfailed ); \ - } \ - catch ( eckit::BadParameter & e ) { \ - atlas::runtime::handle_error( e, atlas::runtime::atlas_err_badparameter ); \ - } \ - catch ( eckit::ReadError & e ) { \ - atlas::runtime::handle_error( e, atlas::runtime::atlas_err_readerror ); \ - } \ - catch ( eckit::WriteError & e ) { \ - atlas::runtime::handle_error( e, atlas::runtime::atlas_err_writeerror ); \ - } \ - catch ( eckit::Exception & e ) { \ - atlas::runtime::handle_error( e, atlas::runtime::atlas_err_exception ); \ - } \ - catch ( ... ) { \ - atlas::runtime::handle_error( eckit::Exception( "Unknown exception" ), \ - atlas::runtime::atlas_err_exception ); \ - } \ - } while ( 0 ) - -class Error { -private: - Error(); - -public: - static Error& instance(); - - int code() const { return code_; } - - const std::string& msg() const { return msg_; } - - bool throws() const { return throws_; } - - bool backtrace() const { return backtrace_; } - - bool aborts() const { return aborts_; } - - void set_code( int c ) { code_ = c; } - - void set_msg( const std::string& m ) { msg_ = m; } - - void set_aborts( bool b ) { aborts_ = b; } - - void set_throws( bool b ) { throws_ = b; } - - void set_backtrace( bool b ) { backtrace_ = b; } - - void clear(); - -private: - std::string msg_; - int code_; - bool aborts_; - bool throws_; - bool backtrace_; -}; - -} // namespace runtime -} // namespace atlas - -extern "C" { -void atlas__abort( char* msg, char* file, int line, char* function ); -void atlas__throw_exception( char* msg, char* file, int line, char* function ); -void atlas__throw_notimplemented( char* msg, char* file, int line, char* function ); -void atlas__throw_outofrange( char* msg, char* file, int line, char* function ); -void atlas__throw_seriousbug( char* msg, char* file, int line, char* function ); -void atlas__throw_usererror( char* msg, char* file, int line, char* function ); -void atlas__throw_assertionfailed( char* msg, char* file, int line, char* function ); -void atlas__throw_( char* msg, char* file, int line, char* function ); -int atlas__Error_code(); -void atlas__Error_clear(); -void atlas__Error_success(); -void atlas__Error_set_aborts( int on_off ); -void atlas__Error_set_throws( int on_off ); -void atlas__Error_set_backtrace( int on_off ); -char* atlas__Error_msg(); -void atlas__error_example(); -} diff --git a/src/atlas/runtime/Exception.cc b/src/atlas/runtime/Exception.cc new file mode 100644 index 000000000..3f44c6c57 --- /dev/null +++ b/src/atlas/runtime/Exception.cc @@ -0,0 +1,63 @@ +/* + * (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 "eckit/exception/Exceptions.h" + +#include "atlas/runtime/Exception.h" + +namespace atlas { + +void throw_NotImplemented( const eckit::CodeLocation& loc ) { + throw eckit::NotImplemented( loc ); +} + +void throw_NotImplemented( const std::string& msg, const eckit::CodeLocation& loc ) { + throw eckit::NotImplemented( msg, loc ); +} + +void throw_AssertionFailed( const std::string& msg ) { + throw eckit::AssertionFailed( msg ); +} + +void throw_AssertionFailed( const std::string& msg, const eckit::CodeLocation& loc ) { + throw eckit::AssertionFailed( msg, loc ); +} + +void throw_AssertionFailed( const std::string& code, const std::string& msg, const eckit::CodeLocation& loc ) { + std::ostringstream ss; + ss << " [[ " << code << " ]]\n" << msg; + throw eckit::AssertionFailed( ss.str(), loc ); +} + +void throw_Exception( const std::string& msg ) { + throw eckit::Exception( msg ); +} + +void throw_Exception( const std::string& msg, const eckit::CodeLocation& loc ) { + throw eckit::Exception( msg, loc ); +} + +void throw_CantOpenFile( const std::string& file ) { + throw eckit::CantOpenFile( file ); +} + +void throw_CantOpenFile( const std::string& file, const eckit::CodeLocation& loc ) { + throw eckit::CantOpenFile( file, loc ); +} + +void throw_OutOfRange( const std::string& varname, idx_t index, idx_t size, const eckit::CodeLocation& loc ) { + std::ostringstream ss; + ss << "OutOfRange: Tried to access " << varname << " index " << index << " but maximum allowed index is " + << size - 1; + throw eckit::Exception( ss.str(), loc ); +} + + +} // namespace atlas diff --git a/src/atlas/runtime/Exception.h b/src/atlas/runtime/Exception.h new file mode 100644 index 000000000..8d2ea40bf --- /dev/null +++ b/src/atlas/runtime/Exception.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 + +#include "eckit/log/CodeLocation.h" + +#include "atlas/library/config.h" + +namespace atlas { + +[[noreturn]] void throw_NotImplemented( const eckit::CodeLocation& ); +[[noreturn]] void throw_NotImplemented( const std::string&, const eckit::CodeLocation& ); + +[[noreturn]] void throw_AssertionFailed( const std::string& ); +[[noreturn]] void throw_AssertionFailed( const std::string&, const eckit::CodeLocation& ); +[[noreturn]] void throw_AssertionFailed( const std::string&, const std::string&, const eckit::CodeLocation& ); + +[[noreturn]] void throw_Exception( const std::string& ); +[[noreturn]] void throw_Exception( const std::string&, const eckit::CodeLocation& ); + +[[noreturn]] void throw_CantOpenFile( const std::string& ); +[[noreturn]] void throw_CantOpenFile( const std::string&, const eckit::CodeLocation& ); + +[[noreturn]] void throw_OutOfRange( const std::string& varname, idx_t index, idx_t size, const eckit::CodeLocation& ); + +namespace detail { +inline void Assert( bool success, const char* code, const char* file, int line, const char* func ) { + if ( not success ) { throw_AssertionFailed( code, eckit::CodeLocation( file, line, func ) ); } +} +inline void Assert( bool success, const char* code, const char* msg, const char* file, int line, const char* func ) { + if ( not success ) { throw_AssertionFailed( code, msg, eckit::CodeLocation( file, line, func ) ); } +} +} // namespace detail +} // namespace atlas + +#include "atlas/util/detail/BlackMagic.h" + +#define ATLAS_NOTIMPLEMENTED ::atlas::throw_NotImplemented( Here() ) + +#define ATLAS_ASSERT_NOMSG( code ) ::atlas::detail::Assert( ( code ), #code, __FILE__, __LINE__, __func__ ) +#define ATLAS_ASSERT_MSG( code, msg ) ::atlas::detail::Assert( ( code ), #code, msg, __FILE__, __LINE__, __func__ ) + +#define ATLAS_ASSERT( ... ) __ATLAS_SPLICE( __ATLAS_ASSERT_, __ATLAS_NARG( __VA_ARGS__ ) )( __VA_ARGS__ ) +#define __ATLAS_ASSERT_1 ATLAS_ASSERT_NOMSG +#define __ATLAS_ASSERT_2 ATLAS_ASSERT_MSG + +#define ATLAS_THROW_EXCEPTION( WHAT ) \ + std::ostringstream ss; \ + ss << WHAT; diff --git a/src/atlas/runtime/Log.cc b/src/atlas/runtime/Log.cc index 5103c8314..63fa652f0 100644 --- a/src/atlas/runtime/Log.cc +++ b/src/atlas/runtime/Log.cc @@ -10,6 +10,7 @@ #include "eckit/os/BackTrace.h" +#include "atlas/library/Library.h" #include "atlas/parallel/mpi/mpi.h" #include "atlas/runtime/Log.h" @@ -35,4 +36,18 @@ void debug_parallel_what( const eckit::CodeLocation& here, const std::string& wh } // namespace detail +Log::Channel& Log::info() { + return atlas::Library::instance().infoChannel(); +} + +Log::Channel& Log::trace() { + return atlas::Library::instance().traceChannel(); +} + +Log::Channel& Log::debug() { + return atlas::Library::instance().debugChannel(); +} + +// namespace detail + } // namespace atlas diff --git a/src/atlas/runtime/Log.h b/src/atlas/runtime/Log.h index 9dbc946bf..8ccdce0fa 100644 --- a/src/atlas/runtime/Log.h +++ b/src/atlas/runtime/Log.h @@ -1,6 +1,15 @@ +/* + * (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/library/Library.h" #include "atlas/library/config.h" #if ATLAS_HAVE_FORTRAN @@ -25,9 +34,9 @@ class Log : public detail::LogBase { public: using Channel = eckit::Channel; // derives from std::ostream - static Channel& info() { return atlas::Library::instance().infoChannel(); } - static Channel& trace() { return atlas::Library::instance().traceChannel(); } - static Channel& debug() { return atlas::Library::instance().debugChannel(); } + static Channel& info(); + static Channel& trace(); + static Channel& debug(); #if !ATLAS_HAVE_FORTRAN // Stubs for what fckit::Log provides @@ -50,16 +59,19 @@ class Log : public detail::LogBase { std::string backtrace(); +} // namespace atlas + +#include +#include "atlas/util/detail/BlackMagic.h" +#include "eckit/log/CodeLocation.h" + +namespace atlas { namespace detail { void debug_parallel_here( const eckit::CodeLocation& ); void debug_parallel_what( const eckit::CodeLocation&, const std::string& ); } // namespace detail - } // namespace atlas -#include -#include "atlas/util/detail/BlackMagic.h" - #define ATLAS_DEBUG_HERE() \ do { \ ::atlas::Log::info() << "DEBUG() @ " << Here() << std::endl; \ diff --git a/src/atlas/runtime/trace/CallStack.cc b/src/atlas/runtime/trace/CallStack.cc index d441c2930..cc73a7c5d 100644 --- a/src/atlas/runtime/trace/CallStack.cc +++ b/src/atlas/runtime/trace/CallStack.cc @@ -1,15 +1,24 @@ +/* + * (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 "CallStack.h" #include -#include "eckit/log/CodeLocation.h" +#include "atlas/runtime/trace/CodeLocation.h" namespace atlas { namespace runtime { namespace trace { -void CallStack::push_front( const eckit::CodeLocation& loc, const std::string& id ) { +void CallStack::push_front( const CodeLocation& loc, const std::string& id ) { stack_.push_front( std::hash{}( loc.asString() + id ) ); } diff --git a/src/atlas/runtime/trace/CallStack.h b/src/atlas/runtime/trace/CallStack.h index 72c50d06c..06142adc3 100644 --- a/src/atlas/runtime/trace/CallStack.h +++ b/src/atlas/runtime/trace/CallStack.h @@ -1,10 +1,20 @@ +/* + * (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 #include #include -namespace eckit { +namespace atlas { class CodeLocation; } @@ -13,14 +23,14 @@ namespace runtime { namespace trace { /// @class CallStack -/// Instances of CallStack can keep track of nested eckit::CodeLocations +/// Instances of CallStack can keep track of nested CodeLocations class CallStack { public: using const_iterator = std::list::const_iterator; using const_reverse_iterator = std::list::const_reverse_iterator; public: - void push_front( const eckit::CodeLocation&, const std::string& id = "" ); + void push_front( const CodeLocation&, const std::string& id = "" ); void pop_front(); const_iterator begin() const { return stack_.begin(); } @@ -32,6 +42,8 @@ class CallStack { size_t hash() const; size_t size() const { return stack_.size(); } + operator bool() const { return not stack_.empty(); } + private: std::list stack_; mutable size_t hash_{0}; diff --git a/src/atlas/runtime/trace/CodeLocation.cc b/src/atlas/runtime/trace/CodeLocation.cc new file mode 100644 index 000000000..1bbf01395 --- /dev/null +++ b/src/atlas/runtime/trace/CodeLocation.cc @@ -0,0 +1,20 @@ +/* + * (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 "CodeLocation.h" + +namespace atlas { + +std::ostream& operator<<( std::ostream& s, const CodeLocation& loc ) { + s << loc.loc_; + return s; +} + +} // namespace atlas diff --git a/src/atlas/runtime/trace/CodeLocation.h b/src/atlas/runtime/trace/CodeLocation.h new file mode 100644 index 000000000..1f435a7f2 --- /dev/null +++ b/src/atlas/runtime/trace/CodeLocation.h @@ -0,0 +1,62 @@ +/* + * (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 +#include +#include "eckit/log/CodeLocation.h" + +namespace atlas { + +class CodeLocation { +public: + CodeLocation( const CodeLocation& loc ) : CodeLocation( loc.file(), loc.line(), loc.func(), loc.stored_ ) {} + CodeLocation( const eckit::CodeLocation& loc ) : loc_( loc ), stored_( false ) {} + CodeLocation( const char* file, int line, const char* function, bool store = false ) : stored_( store ) { + if ( stored_ ) { + if ( file ) { + file_str_ = std::string( file ); + file_ = file_str_.c_str(); + } + if ( function ) { + function_str_ = std::string( function ); + function_ = function_str_.c_str(); + } + loc_ = eckit::CodeLocation( file_, line, function_ ); + } + else { + loc_ = eckit::CodeLocation( file, line, function ); + } + } + operator const eckit::CodeLocation&() const { return loc_; } + + /// conversion to bool for checking if location was set + operator bool() const { return loc_; } + + std::string asString() const { return loc_.asString(); } + /// accessor to line + int line() const { return loc_.line(); } + /// accessor to file + const char* file() const { return loc_.file(); } + /// accessor to function + const char* func() const { return loc_.func(); } + friend std::ostream& operator<<( std::ostream& s, const CodeLocation& loc ); + +private: + eckit::CodeLocation loc_; + bool stored_ = false; + const char* file_ = nullptr; + const char* function_ = nullptr; + std::string file_str_; + std::string function_str_; +}; + +} // namespace atlas diff --git a/src/atlas/runtime/trace/Logging.cc b/src/atlas/runtime/trace/Logging.cc index 3a5963278..eec7701c1 100644 --- a/src/atlas/runtime/trace/Logging.cc +++ b/src/atlas/runtime/trace/Logging.cc @@ -15,6 +15,7 @@ #include "eckit/log/Channel.h" #include "atlas/library/Library.h" +#include "atlas/parallel/omp/omp.h" //----------------------------------------------------------------------------------------------------------- @@ -24,6 +25,10 @@ namespace trace { //----------------------------------------------------------------------------------------------------------- +bool Control::enabled() { + return atlas_omp_get_thread_num() == 0; +} + class LoggingState { private: std::ostream* channel_; @@ -71,6 +76,7 @@ std::ostream& Logging::channel() { bool Logging::enabled() { return LoggingState::instance(); } + void Logging::start( const std::string& title ) { if ( enabled() ) channel() << title << " ..." << std::endl; } diff --git a/src/atlas/runtime/trace/Logging.h b/src/atlas/runtime/trace/Logging.h index 632239ae3..7a90d4999 100644 --- a/src/atlas/runtime/trace/Logging.h +++ b/src/atlas/runtime/trace/Logging.h @@ -18,6 +18,11 @@ namespace atlas { namespace runtime { namespace trace { +class Control { +public: + static bool enabled(); +}; + //----------------------------------------------------------------------------------------------------------- // Class used to avoid any printing before and after a timer diff --git a/src/atlas/runtime/trace/Nesting.cc b/src/atlas/runtime/trace/Nesting.cc index c01d5f2d8..fa86108e0 100644 --- a/src/atlas/runtime/trace/Nesting.cc +++ b/src/atlas/runtime/trace/Nesting.cc @@ -14,51 +14,6 @@ namespace atlas { namespace runtime { -namespace trace { - -class NestingState { -private: - NestingState() {} - CallStack stack_; - -public: - NestingState( NestingState const& ) = delete; - void operator=( NestingState const& ) = delete; - static NestingState& instance() { - static NestingState state; - return state; - } - operator CallStack() const { return stack_; } - CallStack& push( const eckit::CodeLocation& loc, const std::string& id ) { - stack_.push_front( loc, id ); - return stack_; - } - void pop() { stack_.pop_front(); } -}; - -Nesting::Nesting( const eckit::CodeLocation& loc, const std::string& id ) : - loc_( loc ), - id_( id ), - stack_( NestingState::instance().push( loc, id ) ) {} - -Nesting::~Nesting() { - stop(); -} - -void Nesting::stop() { - if ( running_ ) { - NestingState::instance().pop(); - running_ = false; - } -} - -void Nesting::start() { - if ( not running_ ) { - NestingState::instance().push( loc_, id_ ); - running_ = true; - } -} - -} // namespace trace +namespace trace {} // namespace trace } // namespace runtime } // namespace atlas diff --git a/src/atlas/runtime/trace/Nesting.h b/src/atlas/runtime/trace/Nesting.h index ccf64cc49..c2ec44fa7 100644 --- a/src/atlas/runtime/trace/Nesting.h +++ b/src/atlas/runtime/trace/Nesting.h @@ -10,9 +10,9 @@ #pragma once -#include "eckit/log/CodeLocation.h" - #include "atlas/runtime/trace/CallStack.h" +#include "atlas/runtime/trace/CodeLocation.h" +#include "atlas/runtime/trace/Logging.h" //----------------------------------------------------------------------------------------------------------- @@ -20,19 +20,26 @@ namespace atlas { namespace runtime { namespace trace { -class Nesting { -public: - Nesting( const eckit::CodeLocation&, const std::string& id = "" ); - ~Nesting(); - operator CallStack() const { return stack_; } - void stop(); - void start(); - +class CurrentCallStack { private: + CurrentCallStack() {} CallStack stack_; - eckit::CodeLocation loc_; - std::string id_; - bool running_{true}; + +public: + CurrentCallStack( CurrentCallStack const& ) = delete; + CurrentCallStack& operator=( CurrentCallStack const& ) = delete; + static CurrentCallStack& instance() { + static CurrentCallStack state; + return state; + } + operator CallStack() const { return stack_; } + CallStack& push( const CodeLocation& loc, const std::string& id ) { + if ( Control::enabled() ) stack_.push_front( loc, id ); + return stack_; + } + void pop() { + if ( Control::enabled() ) stack_.pop_front(); + } }; } // namespace trace diff --git a/src/atlas/runtime/trace/Timings.cc b/src/atlas/runtime/trace/Timings.cc index b6c191b68..58e63f5eb 100644 --- a/src/atlas/runtime/trace/Timings.cc +++ b/src/atlas/runtime/trace/Timings.cc @@ -12,6 +12,7 @@ #include "Timings.h" #include +#include #include #include #include @@ -21,7 +22,9 @@ #include "eckit/filesystem/PathName.h" #include "atlas/parallel/mpi/mpi.h" +#include "atlas/runtime/Log.h" #include "atlas/runtime/trace/CallStack.h" +#include "atlas/runtime/trace/CodeLocation.h" #include "atlas/util/Config.h" //----------------------------------------------------------------------------------------------------------- @@ -38,7 +41,7 @@ class TimingsRegistry { std::vector max_timings_; std::vector var_timings_; std::vector titles_; - std::vector locations_; + std::vector locations_; std::vector nest_; std::vector stack_; std::map index_; @@ -53,7 +56,7 @@ class TimingsRegistry { return registry; } - size_t add( const eckit::CodeLocation&, const CallStack& stack, const std::string& title, const Timings::Labels& ); + size_t add( const CodeLocation&, const CallStack& stack, const std::string& title, const Timings::Labels& ); void update( size_t idx, double seconds ); @@ -65,7 +68,7 @@ class TimingsRegistry { std::string filter_filepath( const std::string& filepath ) const; }; -size_t TimingsRegistry::add( const eckit::CodeLocation& loc, const CallStack& stack, const std::string& title, +size_t TimingsRegistry::add( const CodeLocation& loc, const CallStack& stack, const std::string& title, const Timings::Labels& labels ) { size_t key = stack.hash(); auto it = index_.find( key ); @@ -113,7 +116,7 @@ void TimingsRegistry::report( std::ostream& out, const eckit::Configuration& con auto box_horizontal = []( int n ) { std::string s; s.reserve( 2 * n ); - for ( size_t i = 0; i < n; ++i ) + for ( int i = 0; i < n; ++i ) s += "\u2500"; return s; }; @@ -251,7 +254,7 @@ void TimingsRegistry::report( std::ostream& out, const eckit::Configuration& con const auto& nest = nest_[k]; const CallStack& this_stack = stack_[k]; - const CallStack& next_stack = ( k == size() - 1 ) ? this_stack : stack_[k + 1]; + const CallStack& next_stack = ( k == long( size() ) - 1 ) ? this_stack : stack_[k + 1]; auto this_it = this_stack.rbegin(); auto next_it = next_stack.rbegin(); @@ -272,14 +275,14 @@ void TimingsRegistry::report( std::ostream& out, const eckit::Configuration& con out << box_vertical; else out << " "; - for ( size_t j = 1; j < indent; ++j ) + for ( long j = 1; j < indent; ++j ) out << " "; } if ( active[nest - 1] ) out << box_T_right; else out << box_corner_bl; - for ( size_t j = 1; j < indent; ++j ) + for ( long j = 1; j < indent; ++j ) out << box_horizontal( 1 ); prefix_[k] = out.str(); @@ -288,20 +291,20 @@ void TimingsRegistry::report( std::ostream& out, const eckit::Configuration& con for ( size_t j = 0; j < size(); ++j ) { auto& tot = tot_timings_[j]; - auto& min = min_timings_[j]; auto& max = max_timings_[j]; + auto& min = std::min( max, min_timings_[j] ); auto& count = counts_[j]; auto& title = titles_[j]; auto& loc = locations_[j]; auto& nest = nest_[j]; auto std = std::sqrt( var_timings_[j] ); - auto avg = tot / double( count ); + auto avg = ( count == 0 ? 0. : tot / double( count ) ); // mpi::comm().allReduceInPlace(min,eckit::mpi::min()); // mpi::comm().allReduceInPlace(max,eckit::mpi::max()); if ( not excluded( j ) ) { - out << std::setw( digits( size() ) ) << j << " : " << prefix_[j] // prefix(indent,nest,next_nest) + out << std::setw( digits( long( size() ) ) ) << j << " : " << prefix_[j] // prefix(indent,nest,next_nest) << std::left << std::setw( max_title_length - nest * indent ) << title << sep << std::string( header ? "" : "count: " ) << std::left << std::setw( max_count_length ) << count << sep << std::string( header ? "" : "tot: " ) << print_time( tot ) << sep diff --git a/src/atlas/runtime/trace/Timings.h b/src/atlas/runtime/trace/Timings.h index 2297c5472..5d851a3c6 100644 --- a/src/atlas/runtime/trace/Timings.h +++ b/src/atlas/runtime/trace/Timings.h @@ -18,7 +18,7 @@ namespace eckit { class Configuration; } -namespace eckit { +namespace atlas { class CodeLocation; } @@ -31,7 +31,7 @@ class CallStack; class Timings { public: using Configuration = eckit::Configuration; - using CodeLocation = eckit::CodeLocation; + using CodeLocation = atlas::CodeLocation; using Identifier = size_t; using Labels = std::vector; diff --git a/src/atlas/runtime/trace/TraceT.h b/src/atlas/runtime/trace/TraceT.h index 8f86e863f..cc9d2abed 100644 --- a/src/atlas/runtime/trace/TraceT.h +++ b/src/atlas/runtime/trace/TraceT.h @@ -14,6 +14,9 @@ #include #include +#include "atlas/parallel/omp/omp.h" +#include "atlas/runtime/trace/CallStack.h" +#include "atlas/runtime/trace/CodeLocation.h" #include "atlas/runtime/trace/Nesting.h" #include "atlas/runtime/trace/StopWatch.h" #include "atlas/runtime/trace/Timings.h" @@ -21,7 +24,6 @@ //----------------------------------------------------------------------------------------------------------- namespace eckit { -class CodeLocation; class Configuration; } // namespace eckit @@ -45,9 +47,9 @@ class TraceT { static std::string report( const eckit::Configuration& config ); public: - TraceT( const eckit::CodeLocation& ); - TraceT( const eckit::CodeLocation&, const std::string& title ); - TraceT( const eckit::CodeLocation&, const std::string& title, const Labels& ); + TraceT( const CodeLocation& ); + TraceT( const CodeLocation&, const std::string& title ); + TraceT( const CodeLocation&, const std::string& title, const Labels& ); ~TraceT(); @@ -73,13 +75,15 @@ class TraceT { void registerTimer(); + static std::string formatTitle( const std::string& ); + private: // member data - bool running_{true}; + bool running_{false}; StopWatch stopwatch_; - eckit::CodeLocation loc_; + CodeLocation loc_; std::string title_; Identifier id_; - Nesting nesting_; + CallStack callstack_; Labels labels_; }; @@ -87,26 +91,29 @@ class TraceT { // Definitions template -inline TraceT::TraceT( const eckit::CodeLocation& loc, const std::string& title ) : +inline std::string TraceT::formatTitle( const std::string& _title ) { + std::string title = _title; + +( Barriers::state() ? " [b]" : "" ) + + ( atlas_omp_get_num_threads() > 1 ? " @thread[" + std::to_string( atlas_omp_get_thread_num() ) + "]" : "" ); + return title; +} + +template +inline TraceT::TraceT( const CodeLocation& loc, const std::string& title ) : loc_( loc ), - title_( title ), - nesting_( loc, title ) { + title_( formatTitle( title ) ) { start(); } template -inline TraceT::TraceT( const eckit::CodeLocation& loc ) : - loc_( loc ), - title_( loc_ ? loc_.func() : "" ), - nesting_( loc_ ) { +inline TraceT::TraceT( const CodeLocation& loc ) : loc_( loc ), title_( loc_ ? loc_.func() : "" ) { start(); } template -inline TraceT::TraceT( const eckit::CodeLocation& loc, const std::string& title, const Labels& labels ) : +inline TraceT::TraceT( const CodeLocation& loc, const std::string& title, const Labels& labels ) : loc_( loc ), title_( title ), - nesting_( loc, title ), labels_( labels ) { start(); } @@ -123,7 +130,10 @@ inline void TraceT::barrier() const { template inline void TraceT::registerTimer() { - id_ = Timings::add( loc_, nesting_, title_ + ( Barriers::state() ? " [b]" : "" ), labels_ ); + std::string title = + title_ + ( Barriers::state() ? " [b]" : "" ) + + ( atlas_omp_get_num_threads() > 1 ? " @thread[" + std::to_string( atlas_omp_get_thread_num() ) + "]" : "" ); + id_ = Timings::add( loc_, callstack_, title, labels_ ); } template @@ -138,10 +148,14 @@ inline bool TraceT::running() const { template inline void TraceT::start() { - registerTimer(); - Tracing::start( title_ ); - barrier(); - stopwatch_.start(); + if ( Control::enabled() ) { + running_ = true; + if ( not callstack_ ) { callstack_ = CurrentCallStack::instance().push( loc_, title_ ); } + registerTimer(); + Tracing::start( title_ ); + barrier(); + stopwatch_.start(); + } } template @@ -149,7 +163,7 @@ inline void TraceT::stop() { if ( running_ ) { barrier(); stopwatch_.stop(); - nesting_.stop(); + CurrentCallStack::instance().pop(); updateTimings(); Tracing::stop( title_, stopwatch_.elapsed() ); running_ = false; @@ -161,7 +175,7 @@ inline void TraceT::pause() { if ( running_ ) { barrier(); stopwatch_.stop(); - nesting_.stop(); + CurrentCallStack::instance().pop(); } } @@ -169,7 +183,7 @@ template inline void TraceT::resume() { if ( running_ ) { barrier(); - nesting_.start(); + CurrentCallStack::instance().push( loc_, title_ ); stopwatch_.start(); } } diff --git a/src/atlas/trans/Cache.cc b/src/atlas/trans/Cache.cc index fa6cf1d26..1b18c76ce 100644 --- a/src/atlas/trans/Cache.cc +++ b/src/atlas/trans/Cache.cc @@ -11,23 +11,13 @@ #include "atlas/trans/Cache.h" #include -#include "eckit/exception/Exceptions.h" #include "eckit/io/DataHandle.h" -#include "eckit/thread/AutoLock.h" -#include "eckit/thread/Mutex.h" +#include "atlas/runtime/Exception.h" #include "atlas/runtime/Log.h" #include "atlas/runtime/Trace.h" #include "atlas/trans/Trans.h" -namespace { -static eckit::Mutex* local_mutex = 0; -static pthread_once_t once = PTHREAD_ONCE_INIT; -static void init() { - local_mutex = new eckit::Mutex(); -} -} // namespace - namespace atlas { namespace trans { @@ -41,8 +31,8 @@ TransCacheFileEntry::TransCacheFileEntry( const eckit::PathName& path ) : buffer } TransCacheMemoryEntry::TransCacheMemoryEntry( const void* data, size_t size ) : data_( data ), size_( size ) { - ASSERT( data_ ); - ASSERT( size_ ); + ATLAS_ASSERT( data_ ); + ATLAS_ASSERT( size_ ); } LegendreFFTCache::LegendreFFTCache( const void* legendre_address, size_t legendre_size, const void* fft_address, @@ -85,10 +75,7 @@ Cache::operator bool() const { return trans_ || bool( legendre() ); } -Cache::~Cache() { - pthread_once( &once, init ); - eckit::AutoLock lock( local_mutex ); -} +Cache::~Cache() {} TransCache::TransCache( const Trans& trans ) : Cache( trans.get() ) {} diff --git a/src/atlas/trans/Cache.h b/src/atlas/trans/Cache.h index 318ba373c..e403cdd7c 100644 --- a/src/atlas/trans/Cache.h +++ b/src/atlas/trans/Cache.h @@ -14,7 +14,8 @@ #include "eckit/filesystem/PathName.h" #include "eckit/io/Buffer.h" -#include "eckit/memory/SharedPtr.h" + +#include "atlas/util/ObjectHandle.h" //----------------------------------------------------------------------------- // Forward declarations @@ -41,6 +42,7 @@ namespace trans { class TransCacheEntry { public: operator bool() const { return size() != 0; } + virtual ~TransCacheEntry() = default; virtual size_t size() const = 0; virtual const void* data() const = 0; }; @@ -82,7 +84,7 @@ class TransCacheMemoryEntry final : public TransCacheEntry { class TransCacheOwnedMemoryEntry final : public TransCacheEntry { public: TransCacheOwnedMemoryEntry( size_t size ); - ~TransCacheOwnedMemoryEntry(); + virtual ~TransCacheOwnedMemoryEntry() override; virtual const void* data() const override { return data_; } virtual size_t size() const override { return size_; } @@ -109,8 +111,7 @@ class Cache { Cache( const TransImpl* ); private: - eckit::SharedPtr trans_; - // const TransImpl* trans_ = nullptr; + util::ObjectHandle trans_; std::shared_ptr legendre_; std::shared_ptr fft_; }; diff --git a/src/atlas/trans/LegendreCacheCreator.cc b/src/atlas/trans/LegendreCacheCreator.cc index f5411e6b6..8b5a2cda7 100644 --- a/src/atlas/trans/LegendreCacheCreator.cc +++ b/src/atlas/trans/LegendreCacheCreator.cc @@ -8,12 +8,12 @@ * nor does it submit to any jurisdiction. */ -#include "eckit/exception/Exceptions.h" #include "eckit/thread/AutoLock.h" #include "eckit/thread/Mutex.h" #include "atlas/grid/Grid.h" #include "atlas/library/defines.h" +#include "atlas/runtime/Exception.h" #include "atlas/runtime/Log.h" #include "atlas/trans/LegendreCacheCreator.h" @@ -30,8 +30,8 @@ LegendreCacheCreatorImpl::~LegendreCacheCreatorImpl() {} namespace { -static eckit::Mutex* local_mutex = 0; -static std::map* m = 0; +static eckit::Mutex* local_mutex = nullptr; +static std::map* m = nullptr; static pthread_once_t once = PTHREAD_ONCE_INIT; static void init() { @@ -60,7 +60,7 @@ LegendreCacheCreatorFactory& factory( const std::string& name ) { Log::error() << "TransFactories are:" << std::endl; for ( j = m->begin(); j != m->end(); ++j ) Log::error() << " " << ( *j ).first << std::endl; - throw eckit::SeriousBug( std::string( "No LegendreCacheCreatorFactory called " ) + name ); + throw_Exception( std::string( "No LegendreCacheCreatorFactory called " ) + name ); } return *j->second; } @@ -72,7 +72,7 @@ LegendreCacheCreatorFactory::LegendreCacheCreatorFactory( const std::string& nam eckit::AutoLock lock( local_mutex ); - ASSERT( m->find( name ) == m->end() ); + ATLAS_ASSERT( m->find( name ) == m->end() ); ( *m )[name] = this; } @@ -123,33 +123,29 @@ LegendreCacheCreator::Implementation* LegendreCacheCreatorFactory::build( const return factory( name ).make( grid, truncation, options ); } -LegendreCacheCreator::LegendreCacheCreator() {} - -LegendreCacheCreator::LegendreCacheCreator( Implementation* impl ) : impl_( impl ) {} LegendreCacheCreator::LegendreCacheCreator( const Grid& grid, int truncation, const eckit::Configuration& config ) : - impl_( LegendreCacheCreatorFactory::build( grid, truncation, config ) ) {} + Handle( LegendreCacheCreatorFactory::build( grid, truncation, config ) ) {} -LegendreCacheCreator::LegendreCacheCreator( const LegendreCacheCreator& creator ) : impl_( creator.impl_ ) {} bool LegendreCacheCreator::supported() const { - return impl_->supported(); + return get()->supported(); } std::string LegendreCacheCreator::uid() const { - return impl_->uid(); + return get()->uid(); } void LegendreCacheCreator::create( const std::string& path ) const { - impl_->create( path ); + get()->create( path ); } Cache LegendreCacheCreator::create() const { - return impl_->create(); + return get()->create(); } size_t LegendreCacheCreator::estimate() const { - return impl_->estimate(); + return get()->estimate(); } } // namespace trans diff --git a/src/atlas/trans/LegendreCacheCreator.h b/src/atlas/trans/LegendreCacheCreator.h index f6be334c4..369b3df9c 100644 --- a/src/atlas/trans/LegendreCacheCreator.h +++ b/src/atlas/trans/LegendreCacheCreator.h @@ -12,12 +12,10 @@ #include -#include "eckit/config/Configuration.h" -#include "eckit/memory/Owned.h" -#include "eckit/memory/SharedPtr.h" - #include "atlas/trans/Trans.h" #include "atlas/util/Config.h" +#include "atlas/util/Object.h" +#include "atlas/util/ObjectHandle.h" //----------------------------------------------------------------------------- // Forward declarations @@ -33,7 +31,7 @@ namespace trans { //----------------------------------------------------------------------------- -class LegendreCacheCreatorImpl : public eckit::Owned { +class LegendreCacheCreatorImpl : public util::Object { public: virtual ~LegendreCacheCreatorImpl() = 0; @@ -50,23 +48,12 @@ class LegendreCacheCreatorImpl : public eckit::Owned { // ------------------------------------------------------------------ -class LegendreCacheCreator { +class LegendreCacheCreator : public util::ObjectHandle { public: - using Implementation = LegendreCacheCreatorImpl; - -private: - eckit::SharedPtr impl_; - -public: - LegendreCacheCreator(); - LegendreCacheCreator( Implementation* ); - LegendreCacheCreator( const LegendreCacheCreator& ); - + using Handle::Handle; + LegendreCacheCreator() = default; LegendreCacheCreator( const Grid&, int truncation, const eckit::Configuration& = util::NoConfig() ); - const Implementation* get() const { return impl_.get(); } - operator bool() const { return impl_.owners(); } - bool supported() const; std::string uid() const; @@ -97,7 +84,7 @@ class LegendreCacheCreatorFactory { private: std::string name_; - virtual LegendreCacheCreatorImpl* make( const Grid& gp, int truncation, const eckit::Configuration& ) { + virtual LegendreCacheCreatorImpl* make( const Grid& /*gp*/, int truncation, const eckit::Configuration& ) { return nullptr; } diff --git a/src/atlas/trans/Trans.cc b/src/atlas/trans/Trans.cc index 08ff4616c..9cc8c4376 100644 --- a/src/atlas/trans/Trans.cc +++ b/src/atlas/trans/Trans.cc @@ -8,328 +8,117 @@ * nor does it submit to any jurisdiction. */ -#include "eckit/exception/Exceptions.h" -#include "eckit/thread/AutoLock.h" -#include "eckit/thread/Mutex.h" #include "eckit/utils/Hash.h" #include "atlas/functionspace.h" #include "atlas/grid/Grid.h" #include "atlas/library/defines.h" +#include "atlas/runtime/Exception.h" #include "atlas/runtime/Log.h" #include "atlas/trans/Trans.h" - -namespace { -struct default_backend { -#if ATLAS_HAVE_TRANS - std::string value = "ifs"; -#else - std::string value = "local"; -#endif - static default_backend instance() { - static default_backend x; - return x; - } - -private: - default_backend() = default; -}; -} // namespace +#include "atlas/trans/detail/TransFactory.h" +#include "atlas/trans/detail/TransImpl.h" namespace atlas { namespace trans { - -class TransBackend { -public: - static void list( std::ostream& ); - static bool has( const std::string& name ); - static void backend( const std::string& ); - static std::string backend(); - static void config( const eckit::Configuration& ); - static const eckit::Configuration& config(); - -private: - static util::Config default_options_; -}; - -util::Config TransBackend::default_options_ = util::Config( "type", default_backend::instance().value ); - -TransImpl::~TransImpl() {} - namespace { - -static eckit::Mutex* local_mutex = 0; -static std::map* b = 0; -static std::map* m = 0; -static pthread_once_t once = PTHREAD_ONCE_INIT; - -static void init() { - local_mutex = new eckit::Mutex(); - b = new std::map(); - m = new std::map(); -} - -TransFactory& factory( const std::string& name ) { - std::map::const_iterator j = m->find( name ); - if ( j == m->end() ) { - Log::error() << "No TransFactory for [" << name << "]" << std::endl; - Log::error() << "TransFactories are:" << std::endl; - for ( j = m->begin(); j != m->end(); ++j ) - Log::error() << " " << ( *j ).first << std::endl; - throw eckit::SeriousBug( std::string( "No TransFactory called " ) + name ); - } - return *j->second; +util::Config options( const eckit::Configuration& config ) { + util::Config opts = Trans::config(); + opts.set( config ); + return opts; } - } // namespace -TransFactory::TransFactory( const std::string& name, const std::string& backend ) : name_( name ), backend_( backend ) { - pthread_once( &once, init ); - - eckit::AutoLock lock( local_mutex ); - - ASSERT( m->find( name ) == m->end() ); - ( *m )[name] = this; - - if ( b->find( backend ) == b->end() ) ( *b )[backend] = 0; - ( *b )[backend]++; -} - -TransFactory::~TransFactory() { - eckit::AutoLock lock( local_mutex ); - m->erase( name_ ); - ( *b )[backend_]--; - if ( ( *b )[backend_] == 0 ) b->erase( backend_ ); -} - -bool TransFactory::has( const std::string& name ) { - pthread_once( &once, init ); - eckit::AutoLock lock( local_mutex ); - return ( m->find( name ) != m->end() ); -} - -bool TransBackend::has( const std::string& name ) { - pthread_once( &once, init ); - eckit::AutoLock lock( local_mutex ); - return ( b->find( name ) != b->end() ); -} - -void TransBackend::backend( const std::string& backend ) { - pthread_once( &once, init ); - eckit::AutoLock lock( local_mutex ); - default_options_.set( "type", backend ); -} - -std::string TransBackend::backend() { - return default_options_.getString( "type" ); -} - -const eckit::Configuration& TransBackend::config() { - return default_options_; -} - -void TransBackend::config( const eckit::Configuration& config ) { - std::string type = default_options_.getString( "type" ); - default_options_ = config; - if ( not config.has( "type" ) ) { default_options_.set( "type", type ); } -} - -void TransBackend::list( std::ostream& out ) { - pthread_once( &once, init ); - eckit::AutoLock lock( local_mutex ); - const char* sep = ""; - for ( std::map::const_iterator j = b->begin(); j != b->end(); ++j ) { - out << sep << ( *j ).first; - sep = ", "; - } -} - -void TransFactory::list( std::ostream& out ) { - TransBackend::list( out ); -} - -Trans::Implementation* TransFactory::build( const FunctionSpace& gp, const FunctionSpace& sp, - const eckit::Configuration& config ) { - return build( Cache(), gp, sp, config ); -} - -Trans::Implementation* TransFactory::build( const Cache& cache, const FunctionSpace& gp, const FunctionSpace& sp, - const eckit::Configuration& config ) { - if ( cache.trans() ) { - Log::debug() << "Creating Trans from cache, ignoring any other arguments" << std::endl; - return cache.trans(); - } - - pthread_once( &once, init ); - - eckit::AutoLock lock( local_mutex ); - - util::Config options = TransBackend::config(); - options.set( config ); - - std::string backend = options.getString( "type" ); - - Log::debug() << "Looking for TransFactory [" << backend << "]" << std::endl; - if ( !TransBackend::has( backend ) ) { - Log::error() << "No TransFactory for [" << backend << "]" << std::endl; - Log::error() << "TransFactories are :" << std::endl; - TransBackend::list( Log::error() ); - Log::error() << std::endl; - throw eckit::SeriousBug( std::string( "No TransFactory called " ) + backend ); - } - - std::string suffix( "(" + gp.type() + "," + sp.type() + ")" ); - std::string name = backend + suffix; - - Log::debug() << "Looking for TransFactory [" << name << "]" << std::endl; - - return factory( name ).make( cache, gp, sp, options ); -} - -Trans::Implementation* TransFactory::build( const Grid& grid, int truncation, const eckit::Configuration& config ) { - return build( Cache(), grid, truncation, config ); -} - -Trans::Implementation* TransFactory::build( const Grid& grid, const Domain& domain, int truncation, - const eckit::Configuration& config ) { - return build( Cache(), grid, domain, truncation, config ); -} - -Trans::Implementation* TransFactory::build( const Cache& cache, const Grid& grid, int truncation, - const eckit::Configuration& config ) { - return build( cache, grid, grid.domain(), truncation, config ); -} - -Trans::Implementation* TransFactory::build( const Cache& cache, const Grid& grid, const Domain& domain, int truncation, - const eckit::Configuration& config ) { - if ( cache.trans() ) { - Log::debug() << "Creating Trans from cache, ignoring any other arguments" << std::endl; - return cache.trans(); - } - - pthread_once( &once, init ); - - eckit::AutoLock lock( local_mutex ); - - util::Config options = TransBackend::config(); - options.set( config ); - - std::string backend = options.getString( "type" ); - - Log::debug() << "Looking for TransFactory [" << backend << "]" << std::endl; - if ( !TransBackend::has( backend ) ) { - Log::error() << "No TransFactory for [" << backend << "]" << std::endl; - Log::error() << "TransFactories are :" << std::endl; - TransBackend::list( Log::error() ); - Log::error() << std::endl; - throw eckit::SeriousBug( std::string( "No TransFactory called " ) + backend ); - } - - std::string name = backend; - - return factory( name ).make( cache, grid, domain, truncation, options ); +void Trans::listBackends( std::ostream& out ) { + TransFactory::list( out ); } bool Trans::hasBackend( const std::string& backend ) { - return TransBackend::has( backend ); + return TransFactory::has( backend ); } void Trans::backend( const std::string& backend ) { - ASSERT( hasBackend( backend ) ); - TransBackend::backend( backend ); + ATLAS_ASSERT( hasBackend( backend ) ); + TransFactory::backend( backend ); } std::string Trans::backend() { - return TransBackend::backend(); + return TransFactory::backend(); } const eckit::Configuration& Trans::config() { - return TransBackend::config(); + return TransFactory::config(); } -void Trans::config( const eckit::Configuration& options ) { - TransBackend::config( options ); +void Trans::config( const eckit::Configuration& _config ) { + TransFactory::config( _config ); } -namespace { -util::Config options( const eckit::Configuration& config ) { - util::Config opts = Trans::config(); - opts.set( config ); - return opts; -} -} // namespace - -Trans::Trans() {} - -Trans::Trans( Implementation* impl ) : impl_( impl ) {} - Trans::Trans( const FunctionSpace& gp, const FunctionSpace& sp, const eckit::Configuration& config ) : - impl_( TransFactory::build( gp, sp, config ) ) {} + Handle( TransFactory::build( gp, sp, config ) ) {} Trans::Trans( const Grid& grid, int truncation, const eckit::Configuration& config ) : - impl_( TransFactory::build( grid, truncation, config ) ) {} + Handle( TransFactory::build( grid, truncation, config ) ) {} Trans::Trans( const Grid& grid, const Domain& domain, int truncation, const eckit::Configuration& config ) : - impl_( TransFactory::build( grid, domain, truncation, config ) ) {} + Handle( TransFactory::build( grid, domain, truncation, config ) ) {} Trans::Trans( const Cache& cache, const FunctionSpace& gp, const FunctionSpace& sp, const eckit::Configuration& config ) : - impl_( TransFactory::build( cache, gp, sp, config ) ) {} + Handle( TransFactory::build( cache, gp, sp, config ) ) {} Trans::Trans( const Cache& cache, const Grid& grid, int truncation, const eckit::Configuration& config ) : - impl_( TransFactory::build( cache, grid, truncation, config ) ) {} + Handle( TransFactory::build( cache, grid, truncation, config ) ) {} Trans::Trans( const Cache& cache, const Grid& grid, const Domain& domain, int truncation, const eckit::Configuration& config ) : - impl_( TransFactory::build( cache, grid, domain, truncation, config ) ) {} - -Trans::Trans( const Trans& trans ) : impl_( trans.impl_ ) {} + Handle( TransFactory::build( cache, grid, domain, truncation, config ) ) {} int Trans::truncation() const { - return impl_->truncation(); + return get()->truncation(); } const Grid& Trans::grid() const { - return impl_->grid(); + return get()->grid(); } size_t Trans::spectralCoefficients() const { - return impl_->spectralCoefficients(); + return get()->spectralCoefficients(); } void Trans::dirtrans( const Field& gpfield, Field& spfield, const eckit::Configuration& config ) const { - impl_->dirtrans( gpfield, spfield, options( config ) ); + get()->dirtrans( gpfield, spfield, options( config ) ); } void Trans::dirtrans( const FieldSet& gpfields, FieldSet& spfields, const eckit::Configuration& config ) const { - impl_->dirtrans( gpfields, spfields, options( config ) ); + get()->dirtrans( gpfields, spfields, options( config ) ); } void Trans::dirtrans_wind2vordiv( const Field& gpwind, Field& spvor, Field& spdiv, const eckit::Configuration& config ) const { - impl_->dirtrans_wind2vordiv( gpwind, spvor, spdiv, options( config ) ); + get()->dirtrans_wind2vordiv( gpwind, spvor, spdiv, options( config ) ); } void Trans::invtrans( const Field& spfield, Field& gpfield, const eckit::Configuration& config ) const { - impl_->invtrans( spfield, gpfield, options( config ) ); + get()->invtrans( spfield, gpfield, options( config ) ); } void Trans::invtrans( const FieldSet& spfields, FieldSet& gpfields, const eckit::Configuration& config ) const { - impl_->invtrans( spfields, gpfields, options( config ) ); + get()->invtrans( spfields, gpfields, options( config ) ); } void Trans::invtrans_grad( const Field& spfield, Field& gradfield, const eckit::Configuration& config ) const { - impl_->invtrans_grad( spfield, gradfield, options( config ) ); + get()->invtrans_grad( spfield, gradfield, options( config ) ); } void Trans::invtrans_grad( const FieldSet& spfields, FieldSet& gradfields, const eckit::Configuration& config ) const { - impl_->invtrans_grad( spfields, gradfields, options( config ) ); + get()->invtrans_grad( spfields, gradfields, options( config ) ); } void Trans::invtrans_vordiv2wind( const Field& spvor, const Field& spdiv, Field& gpwind, const eckit::Configuration& config ) const { - impl_->invtrans_vordiv2wind( spvor, spdiv, gpwind, options( config ) ); + get()->invtrans_vordiv2wind( spvor, spdiv, gpwind, options( config ) ); } // -- IFS type fields -- @@ -349,7 +138,7 @@ void Trans::invtrans_vordiv2wind( const Field& spvor, const Field& spdiv, Field& void Trans::invtrans( const int nb_scalar_fields, const double scalar_spectra[], const int nb_vordiv_fields, const double vorticity_spectra[], const double divergence_spectra[], double gp_fields[], const eckit::Configuration& config ) const { - impl_->invtrans( nb_scalar_fields, scalar_spectra, nb_vordiv_fields, vorticity_spectra, divergence_spectra, + get()->invtrans( nb_scalar_fields, scalar_spectra, nb_vordiv_fields, vorticity_spectra, divergence_spectra, gp_fields, options( config ) ); } @@ -361,7 +150,7 @@ void Trans::invtrans( const int nb_scalar_fields, const double scalar_spectra[], */ void Trans::invtrans( const int nb_scalar_fields, const double scalar_spectra[], double gp_fields[], const eckit::Configuration& config ) const { - impl_->invtrans( nb_scalar_fields, scalar_spectra, gp_fields, options( config ) ); + get()->invtrans( nb_scalar_fields, scalar_spectra, gp_fields, options( config ) ); } /*! @@ -370,7 +159,7 @@ void Trans::invtrans( const int nb_scalar_fields, const double scalar_spectra[], */ void Trans::invtrans( const int nb_vordiv_fields, const double vorticity_spectra[], const double divergence_spectra[], double gp_fields[], const eckit::Configuration& config ) const { - impl_->invtrans( nb_vordiv_fields, vorticity_spectra, divergence_spectra, gp_fields, options( config ) ); + get()->invtrans( nb_vordiv_fields, vorticity_spectra, divergence_spectra, gp_fields, options( config ) ); } /*! @@ -378,7 +167,7 @@ void Trans::invtrans( const int nb_vordiv_fields, const double vorticity_spectra */ void Trans::dirtrans( const int nb_fields, const double scalar_fields[], double scalar_spectra[], const eckit::Configuration& config ) const { - impl_->dirtrans( nb_fields, scalar_fields, scalar_spectra, options( config ) ); + get()->dirtrans( nb_fields, scalar_fields, scalar_spectra, options( config ) ); } /*! @@ -387,7 +176,7 @@ void Trans::dirtrans( const int nb_fields, const double scalar_fields[], double */ void Trans::dirtrans( const int nb_fields, const double wind_fields[], double vorticity_spectra[], double divergence_spectra[], const eckit::Configuration& config ) const { - impl_->dirtrans( nb_fields, wind_fields, vorticity_spectra, divergence_spectra, options( config ) ); + get()->dirtrans( nb_fields, wind_fields, vorticity_spectra, divergence_spectra, options( config ) ); } } // namespace trans diff --git a/src/atlas/trans/Trans.h b/src/atlas/trans/Trans.h index a92164441..53bc8048f 100644 --- a/src/atlas/trans/Trans.h +++ b/src/atlas/trans/Trans.h @@ -10,11 +10,11 @@ #pragma once -#include "eckit/memory/Owned.h" -#include "eckit/memory/SharedPtr.h" +#include #include "atlas/trans/Cache.h" #include "atlas/util/Config.h" +#include "atlas/util/ObjectHandle.h" //----------------------------------------------------------------------------- // Forward declarations @@ -32,191 +32,20 @@ class Domain; namespace atlas { namespace trans { -//----------------------------------------------------------------------------- - -class TransImpl : public eckit::Owned { -public: - virtual ~TransImpl() = 0; - - virtual int truncation() const = 0; - - virtual size_t spectralCoefficients() const = 0; - - virtual const Grid& grid() const = 0; - - virtual void dirtrans( const Field& gpfield, Field& spfield, - const eckit::Configuration& = util::NoConfig() ) const = 0; - - virtual void dirtrans( const FieldSet& gpfields, FieldSet& spfields, - const eckit::Configuration& = util::NoConfig() ) const = 0; - - virtual void dirtrans_wind2vordiv( const Field& gpwind, Field& spvor, Field& spdiv, - const eckit::Configuration& = util::NoConfig() ) const = 0; - - virtual void invtrans( const Field& spfield, Field& gpfield, - const eckit::Configuration& = util::NoConfig() ) const = 0; - - virtual void invtrans( const FieldSet& spfields, FieldSet& gpfields, - const eckit::Configuration& = util::NoConfig() ) const = 0; - - virtual void invtrans_grad( const Field& spfield, Field& gradfield, - const eckit::Configuration& = util::NoConfig() ) const = 0; - - virtual void invtrans_grad( const FieldSet& spfields, FieldSet& gradfields, - const eckit::Configuration& = util::NoConfig() ) const = 0; - - virtual void invtrans_vordiv2wind( const Field& spvor, const Field& spdiv, Field& gpwind, - const eckit::Configuration& = util::NoConfig() ) const = 0; - - // -- IFS type fields -- - // These fields have special interpretation required. You need to know what - // you're doing. - // See IFS trans library. - - /*! - * @brief invtrans - * @param nb_scalar_fields - * @param scalar_spectra - * @param nb_vordiv_fields - * @param vorticity_spectra - * @param divergence_spectra - * @param gp_fields - */ - virtual void invtrans( const int nb_scalar_fields, const double scalar_spectra[], const int nb_vordiv_fields, - const double vorticity_spectra[], const double divergence_spectra[], double gp_fields[], - const eckit::Configuration& = util::NoConfig() ) const = 0; - - /*! - * @brief invtrans - * @param nb_fields - * @param scalar_spectra - * @param scalar_fields - */ - virtual void invtrans( const int nb_scalar_fields, const double scalar_spectra[], double gp_fields[], - const eckit::Configuration& = util::NoConfig() ) const = 0; - - /*! - * @brief Inverse transform of vorticity/divergence to wind(U/V) - * @param nb_fields [in] Number of fields ( both components of wind count as 1 - * ) - */ - virtual void invtrans( const int nb_vordiv_fields, const double vorticity_spectra[], - const double divergence_spectra[], double gp_fields[], - const eckit::Configuration& = util::NoConfig() ) const = 0; - - /*! - * @brief Direct transform of scalar fields - */ - virtual void dirtrans( const int nb_fields, const double scalar_fields[], double scalar_spectra[], - const eckit::Configuration& = util::NoConfig() ) const = 0; - - /*! - * @brief Direct transform of wind(U/V) to vorticity/divergence - * @param nb_fields [in] Number of fields ( both components of wind count as 1 - * ) - */ - virtual void dirtrans( const int nb_fields, const double wind_fields[], double vorticity_spectra[], - double divergence_spectra[], const eckit::Configuration& = util::NoConfig() ) const = 0; -}; - -// ------------------------------------------------------------------ - -class TransFactory { -protected: - using Trans_t = const TransImpl; - -public: - /*! - * \brief build Trans - * \return TransImpl - */ - static Trans_t* build( const FunctionSpace& gp, const FunctionSpace& sp, - const eckit::Configuration& = util::Config() ); - static Trans_t* build( const Grid&, int truncation, const eckit::Configuration& = util::Config() ); - - static Trans_t* build( const Grid&, const Domain&, int truncation, const eckit::Configuration& = util::Config() ); - - static Trans_t* build( const Cache&, const FunctionSpace& gp, const FunctionSpace& sp, - const eckit::Configuration& = util::Config() ); - - static Trans_t* build( const Cache&, const Grid&, int truncation, const eckit::Configuration& = util::Config() ); - - static Trans_t* build( const Cache&, const Grid&, const Domain&, int truncation, - const eckit::Configuration& = util::Config() ); - - /*! - * \brief list all registered trans implementations - */ - static void list( std::ostream& ); - - static bool has( const std::string& name ); - -private: - std::string name_; - std::string backend_; - virtual Trans_t* make( const Cache&, const FunctionSpace& gp, const FunctionSpace& sp, - const eckit::Configuration& ) { - return nullptr; - } - virtual Trans_t* make( const Cache&, const Grid& gp, const Domain&, int truncation, const eckit::Configuration& ) { - return nullptr; - } - -protected: - TransFactory(); - TransFactory( const std::string& name, const std::string& backend ); - virtual ~TransFactory(); -}; - //---------------------------------------------------------------------------------------------------------------------- -template -class TransBuilderFunctionSpace : public TransFactory { - virtual Trans_t* make( const Cache& cache, const FunctionSpace& gp, const FunctionSpace& sp, - const eckit::Configuration& config ) { - return new T( cache, gp, sp, config ); - } - virtual Trans_t* make( const Cache&, const Grid&, const Domain&, int, const eckit::Configuration& ) { - throw eckit::SeriousBug( "This function should not be called", Here() ); - } - -public: - TransBuilderFunctionSpace( const std::string& name, const std::string& backend ) : TransFactory( name, backend ) {} -}; - -template -class TransBuilderGrid : public TransFactory { - virtual Trans_t* make( const Cache& cache, const Grid& grid, const Domain& domain, int truncation, - const eckit::Configuration& config ) { - return new T( cache, grid, domain, truncation, config ); - } - virtual Trans_t* make( const Cache&, const FunctionSpace&, const FunctionSpace&, const eckit::Configuration& ) { - throw eckit::SeriousBug( "This function should not be called", Here() ); - } - -public: - TransBuilderGrid( const std::string& name, const std::string& backend ) : TransFactory( name, backend ) {} -}; - -//---------------------------------------------------------------------------------------------------------------------- - -class Trans { -public: - using Implementation = const TransImpl; - -private: - eckit::SharedPtr impl_; - +class TransImpl; +class Trans : public util::ObjectHandle { public: + static void listBackends( std::ostream& ); static bool hasBackend( const std::string& ); static void backend( const std::string& ); static std::string backend(); static void config( const eckit::Configuration& ); static const eckit::Configuration& config(); - Trans(); - Trans( Implementation* ); - Trans( const Trans& ); + using Handle::Handle; + Trans() = default; Trans( const FunctionSpace& gp, const FunctionSpace& sp, const eckit::Configuration& = util::NoConfig() ); Trans( const Grid&, int truncation, const eckit::Configuration& = util::NoConfig() ); @@ -228,8 +57,6 @@ class Trans { Trans( const Cache&, const Grid&, const Domain&, int truncation, const eckit::Configuration& = util::NoConfig() ); void hash( eckit::Hash& ) const; - Implementation* get() const { return impl_.get(); } - operator bool() const { return impl_.owners(); } int truncation() const; size_t spectralCoefficients() const; diff --git a/src/atlas/trans/VorDivToUV.cc b/src/atlas/trans/VorDivToUV.cc index e160062b5..de85938a0 100644 --- a/src/atlas/trans/VorDivToUV.cc +++ b/src/atlas/trans/VorDivToUV.cc @@ -8,7 +8,6 @@ * nor does it submit to any jurisdiction. */ -#include "eckit/exception/Exceptions.h" #include "eckit/thread/AutoLock.h" #include "eckit/thread/Mutex.h" #include "eckit/utils/Hash.h" @@ -16,6 +15,7 @@ #include "atlas/functionspace.h" #include "atlas/grid/Grid.h" #include "atlas/library/defines.h" +#include "atlas/runtime/Exception.h" #include "atlas/runtime/Log.h" #include "atlas/trans/VorDivToUV.h" @@ -35,8 +35,8 @@ VorDivToUVImpl::~VorDivToUVImpl() {} namespace { -static eckit::Mutex* local_mutex = 0; -static std::map* m = 0; +static eckit::Mutex* local_mutex = nullptr; +static std::map* m = nullptr; static pthread_once_t once = PTHREAD_ONCE_INIT; static void init() { @@ -65,7 +65,7 @@ VorDivToUVFactory& factory( const std::string& name ) { Log::error() << "VorDivToUVFactory are:" << std::endl; for ( j = m->begin(); j != m->end(); ++j ) Log::error() << " " << ( *j ).first << std::endl; - throw eckit::SeriousBug( std::string( "No VorDivToUVFactory called " ) + name ); + throw_Exception( std::string( "No VorDivToUVFactory called " ) + name ); } return *j->second; } @@ -77,7 +77,7 @@ VorDivToUVFactory::VorDivToUVFactory( const std::string& name ) : name_( name ) eckit::AutoLock lock( local_mutex ); - ASSERT( m->find( name ) == m->end() ); + ATLAS_ASSERT( m->find( name ) == m->end() ); ( *m )[name] = this; } @@ -149,20 +149,14 @@ VorDivToUV::Implementation* VorDivToUVFactory::build( int truncation, const ecki return factory( name ).make( truncation, config ); } -VorDivToUV::VorDivToUV() {} - -VorDivToUV::VorDivToUV( Implementation* impl ) : impl_( impl ) {} - VorDivToUV::VorDivToUV( const FunctionSpace& sp, const eckit::Configuration& config ) : - impl_( VorDivToUVFactory::build( sp, config ) ) {} + Handle( VorDivToUVFactory::build( sp, config ) ) {} VorDivToUV::VorDivToUV( int truncation, const eckit::Configuration& config ) : - impl_( VorDivToUVFactory::build( truncation, config ) ) {} - -VorDivToUV::VorDivToUV( const VorDivToUV& other ) : impl_( other.impl_ ) {} + Handle( VorDivToUVFactory::build( truncation, config ) ) {} int VorDivToUV::truncation() const { - return impl_->truncation(); + return get()->truncation(); } // -- IFS type fields -- @@ -172,7 +166,7 @@ int VorDivToUV::truncation() const { void VorDivToUV::execute( const int nb_coeff, const int nb_fields, const double vorticity[], const double divergence[], double U[], double V[], const eckit::Configuration& config ) const { - impl_->execute( nb_coeff, nb_fields, vorticity, divergence, U, V, config ); + get()->execute( nb_coeff, nb_fields, vorticity, divergence, U, V, config ); } } // namespace trans diff --git a/src/atlas/trans/VorDivToUV.h b/src/atlas/trans/VorDivToUV.h index 9bfddbb0b..c4968fa3e 100644 --- a/src/atlas/trans/VorDivToUV.h +++ b/src/atlas/trans/VorDivToUV.h @@ -12,13 +12,9 @@ #include -#include "eckit/config/Configuration.h" -#include "eckit/io/Buffer.h" -#include "eckit/io/DataHandle.h" -#include "eckit/memory/Owned.h" -#include "eckit/memory/SharedPtr.h" - #include "atlas/util/Config.h" +#include "atlas/util/Object.h" +#include "atlas/util/ObjectHandle.h" //----------------------------------------------------------------------------- // Forward declarations @@ -37,7 +33,7 @@ namespace trans { //----------------------------------------------------------------------------- -class VorDivToUVImpl : public eckit::Owned { +class VorDivToUVImpl : public util::Object { public: virtual ~VorDivToUVImpl() = 0; @@ -84,8 +80,8 @@ class VorDivToUVFactory { private: std::string name_; - virtual VorDivToUVImpl* make( const FunctionSpace& sp, const eckit::Configuration& ) { return nullptr; } - virtual VorDivToUVImpl* make( int truncation, const eckit::Configuration& ) { return nullptr; } + virtual VorDivToUVImpl* make( const FunctionSpace& sp, const eckit::Configuration& ) = 0; + virtual VorDivToUVImpl* make( int truncation, const eckit::Configuration& ) = 0; protected: VorDivToUVFactory( const std::string& ); @@ -109,24 +105,15 @@ class VorDivToUVBuilder : public VorDivToUVFactory { //---------------------------------------------------------------------------------------------------------------------- -class VorDivToUV { -public: - using Implementation = VorDivToUVImpl; - -private: - eckit::SharedPtr impl_; - +class VorDivToUV : public util::ObjectHandle { public: - VorDivToUV(); - VorDivToUV( Implementation* ); - VorDivToUV( const VorDivToUV& ); + using Handle::Handle; + VorDivToUV() = default; VorDivToUV( const FunctionSpace& sp, const eckit::Configuration& = util::NoConfig() ); VorDivToUV( int truncation, const eckit::Configuration& = util::NoConfig() ); void hash( eckit::Hash& ) const; - const Implementation* get() const { return impl_.get(); } - operator bool() const { return impl_.owners(); } int truncation() const; diff --git a/src/atlas/trans/detail/TransFactory.cc b/src/atlas/trans/detail/TransFactory.cc new file mode 100644 index 000000000..dbb480e6d --- /dev/null +++ b/src/atlas/trans/detail/TransFactory.cc @@ -0,0 +1,253 @@ +/* + * (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 +#include +#include +#include + +#include "TransFactory.h" + +#include "atlas/functionspace.h" +#include "atlas/grid/Grid.h" +#include "atlas/library/config.h" +#include "atlas/runtime/Exception.h" +#include "atlas/runtime/Log.h" +#include "atlas/trans/Cache.h" +#include "atlas/trans/Trans.h" + +#include "atlas/trans/local/TransLocal.h" +#if ATLAS_HAVE_TRANS +#include "atlas/trans/ifs/TransIFS.h" +#include "atlas/trans/ifs/TransIFSNodeColumns.h" +#include "atlas/trans/ifs/TransIFSStructuredColumns.h" +#endif + +namespace atlas { +namespace trans { + +//---------------------------------------------------------------------------------------------------------------------- + +void force_link() { + static struct Link { + Link() { + TransBuilderGrid(); +#if ATLAS_HAVE_TRANS + TransBuilderGrid(); + TransBuilderFunctionSpace(); + TransBuilderFunctionSpace(); +#endif + } + } link; +} + +//---------------------------------------------------------------------------------------------------------------------- + +namespace { +struct default_backend { +#if ATLAS_HAVE_TRANS + std::string value = "ifs"; +#else + std::string value = "local"; +#endif + static default_backend instance() { + static default_backend x; + return x; + } + +private: + default_backend() = default; +}; +} // namespace + +class TransBackend { + using lock_guard = std::lock_guard; + +protected: + TransBackend() { default_options_ = util::Config( "type", default_backend::instance().value ); } + +private: + mutable std::mutex mutex_; + std::map backends_; + + util::Config default_options_; + +public: + std::vector keys() const { + lock_guard lock( mutex_ ); + std::vector _keys; + _keys.reserve( backends_.size() ); + for ( const auto& key_value : backends_ ) { + _keys.emplace_back( key_value.first ); + } + return _keys; + } + void list( std::ostream& out ) const { + lock_guard lock( mutex_ ); + const char* sep = ""; + for ( const auto& map_pair : backends_ ) { + out << sep << map_pair.first; + sep = ", "; + } + } + bool has( const std::string& backend ) const { + lock_guard lock( mutex_ ); + return ( backends_.find( backend ) != backends_.end() ); + } + void add( const std::string& backend ) { + lock_guard lock( mutex_ ); + if ( backends_.find( backend ) == backends_.end() ) { backends_[backend] = 1; } + else { + ++backends_[backend]; + } + } + void remove( const std::string& backend ) { + lock_guard lock( mutex_ ); + --backends_[backend]; + if ( backends_[backend] == 0 ) { backends_.erase( backend ); } + } + + void backend( const std::string& backend ) { + lock_guard lock( mutex_ ); + default_options_.set( "type", backend ); + } + std::string backend() { return default_options_.getString( "type" ); } + void config( const eckit::Configuration& config ) { + std::string type = default_options_.getString( "type" ); + default_options_ = config; + if ( not config.has( "type" ) ) { default_options_.set( "type", type ); } + } + const eckit::Configuration& config() { return default_options_; } + + +public: + static TransBackend& instance() { + static TransBackend env; + return env; + } +}; + + +TransFactory::TransFactory( const std::string& name, const std::string& backend ) : + Factory( name ), + name_( name ), + backend_( backend ) { + TransBackend::instance().add( backend ); +} + +TransFactory::~TransFactory() { + TransBackend::instance().remove( backend_ ); +} + +void TransFactory::list( std::ostream& out ) { + return TransBackend::instance().list( out ); +} + +bool TransFactory::has( const std::string& backend ) { + return TransBackend::instance().has( backend ); +} + +void TransFactory::backend( const std::string& backend ) { + TransBackend::instance().backend( backend ); +} + +std::string TransFactory::backend() { + return TransBackend::instance().backend(); +} + +const eckit::Configuration& TransFactory::config() { + return TransBackend::instance().config(); +} + +void TransFactory::config( const eckit::Configuration& config ) { + TransBackend::instance().config( config ); +} + +const TransImpl* TransFactory::build( const FunctionSpace& gp, const FunctionSpace& sp, + const eckit::Configuration& config ) { + return build( Cache(), gp, sp, config ); +} + +const TransImpl* TransFactory::build( const Cache& cache, const FunctionSpace& gp, const FunctionSpace& sp, + const eckit::Configuration& config ) { + force_link(); + + if ( cache.trans() ) { + Log::debug() << "Creating Trans from cache, ignoring any other arguments" << std::endl; + return cache.trans(); + } + + util::Config options = TransBackend::instance().config(); + options.set( config ); + + std::string backend = options.getString( "type" ); + + Log::debug() << "Looking for TransFactory [" << backend << "]" << std::endl; + if ( !TransBackend::instance().has( backend ) ) { + Log::error() << "No TransFactory for [" << backend << "]" << std::endl; + Log::error() << "TransFactories are :" << std::endl; + TransBackend::instance().list( Log::error() ); + Log::error() << std::endl; + throw_Exception( std::string( "No TransFactory called " ) + backend ); + } + + std::string suffix( "(" + gp.type() + "," + sp.type() + ")" ); + std::string builder = backend + suffix; + + Log::debug() << "Looking for TransFactory [" << builder << "]" << std::endl; + auto factory = get( builder ); + return factory->make( cache, gp, sp, options ); +} + +const TransImpl* TransFactory::build( const Grid& grid, int truncation, const eckit::Configuration& config ) { + return build( Cache(), grid, truncation, config ); +} + +const TransImpl* TransFactory::build( const Grid& grid, const Domain& domain, int truncation, + const eckit::Configuration& config ) { + return build( Cache(), grid, domain, truncation, config ); +} + +const TransImpl* TransFactory::build( const Cache& cache, const Grid& grid, int truncation, + const eckit::Configuration& config ) { + return build( cache, grid, grid.domain(), truncation, config ); +} + +const TransImpl* TransFactory::build( const Cache& cache, const Grid& grid, const Domain& domain, int truncation, + const eckit::Configuration& config ) { + force_link(); + + if ( cache.trans() ) { + Log::debug() << "Creating Trans from cache, ignoring any other arguments" << std::endl; + return cache.trans(); + } + util::Config options = TransBackend::instance().config(); + options.set( config ); + + std::string backend = options.getString( "type" ); + + Log::debug() << "Looking for TransFactory [" << backend << "]" << std::endl; + if ( !TransBackend::instance().has( backend ) ) { + Log::error() << "No TransFactory for [" << backend << "]" << std::endl; + Log::error() << "TransFactories are :" << std::endl; + TransBackend::instance().list( Log::error() ); + Log::error() << std::endl; + throw_Exception( std::string( "No TransFactory called " ) + backend ); + } + std::string builder = backend; + auto factory = get( builder ); + return factory->make( cache, grid, domain, truncation, options ); +} + +//---------------------------------------------------------------------------------------------------------------------- + +} // namespace trans +} // namespace atlas diff --git a/src/atlas/trans/detail/TransFactory.h b/src/atlas/trans/detail/TransFactory.h new file mode 100644 index 000000000..a1b48bc43 --- /dev/null +++ b/src/atlas/trans/detail/TransFactory.h @@ -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. + */ + +#pragma once + +#include + +#include "atlas/runtime/Exception.h" +#include "atlas/util/Config.h" +#include "atlas/util/Factory.h" + +//---------------------------------------------------------------------------------------------------------------------- + +// forward declarations +namespace atlas { +class Grid; +class FunctionSpace; +class Domain; +namespace trans { +class TransImpl; +class Cache; +} // namespace trans +} // namespace atlas + +//---------------------------------------------------------------------------------------------------------------------- + +namespace atlas { +namespace trans { + +//---------------------------------------------------------------------------------------------------------------------- + +class TransFactory : public util::Factory { +public: + static std::string className() { return "TransFactory"; } + +public: + /*! + * \brief build Trans + * \return TransImpl + */ + static const TransImpl* build( const FunctionSpace& gp, const FunctionSpace& sp, + const eckit::Configuration& = util::Config() ); + static const TransImpl* build( const Grid&, int truncation, const eckit::Configuration& = util::Config() ); + + static const TransImpl* build( const Grid&, const Domain&, int truncation, + const eckit::Configuration& = util::Config() ); + + static const TransImpl* build( const Cache&, const FunctionSpace& gp, const FunctionSpace& sp, + const eckit::Configuration& = util::Config() ); + + static const TransImpl* build( const Cache&, const Grid&, int truncation, + const eckit::Configuration& = util::Config() ); + + static const TransImpl* build( const Cache&, const Grid&, const Domain&, int truncation, + const eckit::Configuration& = util::Config() ); + + static void list( std::ostream& out ); + + static bool has( const std::string& backend ); + + static void backend( const std::string& ); + + static std::string backend(); + + static const eckit::Configuration& config(); + + static void config( const eckit::Configuration& ); + +public: + TransFactory( const std::string& name, const std::string& backend ); + virtual ~TransFactory(); + + TransFactory() {} + +private: + std::string name_; + std::string backend_; + + virtual const TransImpl* make( const Cache&, const FunctionSpace& /*gp*/, const FunctionSpace& /*sp*/, + const eckit::Configuration& ) { + return nullptr; + } + virtual const TransImpl* make( const Cache&, const Grid& /*gp*/, const Domain&, int /*truncation*/, + const eckit::Configuration& ) { + return nullptr; + } +}; + +//---------------------------------------------------------------------------------------------------------------------- + +template +class TransBuilderFunctionSpace : public TransFactory { + virtual const TransImpl* make( const Cache& cache, const FunctionSpace& gp, const FunctionSpace& sp, + const eckit::Configuration& config ) override { + return new T( cache, gp, sp, config ); + } + virtual const TransImpl* make( const Cache&, const Grid&, const Domain&, int, + const eckit::Configuration& ) override { + throw_Exception( "This function should not be called", Here() ); + } + +public: + TransBuilderFunctionSpace( const std::string& name, const std::string& backend ) : TransFactory( name, backend ) {} + + TransBuilderFunctionSpace() {} +}; + +template +class TransBuilderGrid : public TransFactory { + virtual const TransImpl* make( const Cache& cache, const Grid& grid, const Domain& domain, int truncation, + const eckit::Configuration& config ) override { + return new T( cache, grid, domain, truncation, config ); + } + virtual const TransImpl* make( const Cache&, const FunctionSpace&, const FunctionSpace&, + const eckit::Configuration& ) override { + throw_Exception( "This function should not be called", Here() ); + } + +public: + TransBuilderGrid( const std::string& name, const std::string& backend ) : TransFactory( name, backend ) {} + + TransBuilderGrid() {} +}; + +//---------------------------------------------------------------------------------------------------------------------- + + +} // namespace trans +} // namespace atlas diff --git a/src/atlas/trans/detail/TransImpl.cc b/src/atlas/trans/detail/TransImpl.cc new file mode 100644 index 000000000..1d03ee973 --- /dev/null +++ b/src/atlas/trans/detail/TransImpl.cc @@ -0,0 +1,20 @@ +/* + * (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 "TransImpl.h" + +namespace atlas { +namespace trans { + +TransImpl::~TransImpl() {} + +} // namespace trans +} // namespace atlas diff --git a/src/atlas/trans/detail/TransImpl.h b/src/atlas/trans/detail/TransImpl.h new file mode 100644 index 000000000..b75439714 --- /dev/null +++ b/src/atlas/trans/detail/TransImpl.h @@ -0,0 +1,123 @@ +/* + * (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/trans/Cache.h" +#include "atlas/util/Config.h" +#include "atlas/util/Object.h" + +//----------------------------------------------------------------------------- +// Forward declarations + +namespace atlas { +class Field; +class FieldSet; +class FunctionSpace; +class Grid; +class Domain; +} // namespace atlas + +//----------------------------------------------------------------------------- + +namespace atlas { +namespace trans { + +//----------------------------------------------------------------------------- + +class TransImpl : public util::Object { +public: + virtual ~TransImpl() = 0; + + virtual int truncation() const = 0; + + virtual size_t spectralCoefficients() const = 0; + + virtual const Grid& grid() const = 0; + + virtual void dirtrans( const Field& gpfield, Field& spfield, + const eckit::Configuration& = util::NoConfig() ) const = 0; + + virtual void dirtrans( const FieldSet& gpfields, FieldSet& spfields, + const eckit::Configuration& = util::NoConfig() ) const = 0; + + virtual void dirtrans_wind2vordiv( const Field& gpwind, Field& spvor, Field& spdiv, + const eckit::Configuration& = util::NoConfig() ) const = 0; + + virtual void invtrans( const Field& spfield, Field& gpfield, + const eckit::Configuration& = util::NoConfig() ) const = 0; + + virtual void invtrans( const FieldSet& spfields, FieldSet& gpfields, + const eckit::Configuration& = util::NoConfig() ) const = 0; + + virtual void invtrans_grad( const Field& spfield, Field& gradfield, + const eckit::Configuration& = util::NoConfig() ) const = 0; + + virtual void invtrans_grad( const FieldSet& spfields, FieldSet& gradfields, + const eckit::Configuration& = util::NoConfig() ) const = 0; + + virtual void invtrans_vordiv2wind( const Field& spvor, const Field& spdiv, Field& gpwind, + const eckit::Configuration& = util::NoConfig() ) const = 0; + + // -- IFS type fields -- + // These fields have special interpretation required. You need to know what + // you're doing. + // See IFS trans library. + + /*! + * @brief invtrans + * @param nb_scalar_fields + * @param scalar_spectra + * @param nb_vordiv_fields + * @param vorticity_spectra + * @param divergence_spectra + * @param gp_fields + */ + virtual void invtrans( const int nb_scalar_fields, const double scalar_spectra[], const int nb_vordiv_fields, + const double vorticity_spectra[], const double divergence_spectra[], double gp_fields[], + const eckit::Configuration& = util::NoConfig() ) const = 0; + + /*! + * @brief invtrans + * @param nb_fields + * @param scalar_spectra + * @param scalar_fields + */ + virtual void invtrans( const int nb_scalar_fields, const double scalar_spectra[], double gp_fields[], + const eckit::Configuration& = util::NoConfig() ) const = 0; + + /*! + * @brief Inverse transform of vorticity/divergence to wind(U/V) + * @param nb_fields [in] Number of fields ( both components of wind count as 1 + * ) + */ + virtual void invtrans( const int nb_vordiv_fields, const double vorticity_spectra[], + const double divergence_spectra[], double gp_fields[], + const eckit::Configuration& = util::NoConfig() ) const = 0; + + /*! + * @brief Direct transform of scalar fields + */ + virtual void dirtrans( const int nb_fields, const double scalar_fields[], double scalar_spectra[], + const eckit::Configuration& = util::NoConfig() ) const = 0; + + /*! + * @brief Direct transform of wind(U/V) to vorticity/divergence + * @param nb_fields [in] Number of fields ( both components of wind count as 1 + * ) + */ + virtual void dirtrans( const int nb_fields, const double wind_fields[], double vorticity_spectra[], + double divergence_spectra[], const eckit::Configuration& = util::NoConfig() ) const = 0; +}; + +//---------------------------------------------------------------------------------------------------------------------- + +} // namespace trans +} // namespace atlas diff --git a/src/atlas/trans/ifs/LegendreCacheCreatorIFS.cc b/src/atlas/trans/ifs/LegendreCacheCreatorIFS.cc index 54b276d64..bc42d8da1 100644 --- a/src/atlas/trans/ifs/LegendreCacheCreatorIFS.cc +++ b/src/atlas/trans/ifs/LegendreCacheCreatorIFS.cc @@ -32,8 +32,8 @@ std::string truncate( const std::string& str ) { std::string hash( const Grid& grid ) { eckit::MD5 h; - if ( grid::StructuredGrid( grid ) && not grid.projection() ) { - auto g = grid::StructuredGrid( grid ); + if ( StructuredGrid( grid ) && not grid.projection() ) { + auto g = StructuredGrid( grid ); h.add( g.y().data(), g.y().size() * sizeof( double ) ); } else { @@ -57,17 +57,15 @@ std::string LegendreCacheCreatorIFS::uid() const { if ( unique_identifier_.empty() ) { std::ostringstream stream; stream << "ifs-T" << truncation_ << "-"; - if ( grid::GaussianGrid( grid_ ) ) { - if ( grid::RegularGaussianGrid( grid_ ) ) { - stream << "RegularGaussianN" << grid::GaussianGrid( grid_ ).N(); - } + if ( GaussianGrid( grid_ ) ) { + if ( RegularGaussianGrid( grid_ ) ) { stream << "RegularGaussianN" << GaussianGrid( grid_ ).N(); } else { - stream << "ReducedGaussianN" << grid::GaussianGrid( grid_ ).N() << "-PL"; + stream << "ReducedGaussianN" << GaussianGrid( grid_ ).N() << "-PL"; stream << hash( grid_ ); } } - else if ( grid::RegularLonLatGrid( grid_ ) ) { - auto g = grid::RegularLonLatGrid( grid_ ); + else if ( RegularLonLatGrid( grid_ ) ) { + auto g = RegularLonLatGrid( grid_ ); if ( g.standard() || g.shifted() ) { stream << ( g.standard() ? "L" : "S" ) << g.nx() << "x" << g.ny(); } else { // We cannot make more assumptions on reusability for different grids @@ -87,9 +85,9 @@ std::string LegendreCacheCreatorIFS::uid() const { LegendreCacheCreatorIFS::~LegendreCacheCreatorIFS() {} bool LegendreCacheCreatorIFS::supported() const { - if ( grid::GaussianGrid( grid_ ) ) { return true; } - else if ( grid::RegularLonLatGrid( grid_ ) ) { - auto g = grid::RegularLonLatGrid( grid_ ); + if ( GaussianGrid( grid_ ) ) { return true; } + else if ( RegularLonLatGrid( grid_ ) ) { + auto g = RegularLonLatGrid( grid_ ); if ( g.standard() || g.shifted() ) { return true; } } return false; diff --git a/src/atlas/trans/ifs/TransIFS.cc b/src/atlas/trans/ifs/TransIFS.cc index 791a47017..f1fb11681 100644 --- a/src/atlas/trans/ifs/TransIFS.cc +++ b/src/atlas/trans/ifs/TransIFS.cc @@ -11,14 +11,17 @@ #include "eckit/parser/JSON.h" #include "atlas/array.h" +#include "atlas/field/FieldSet.h" #include "atlas/functionspace/NodeColumns.h" #include "atlas/functionspace/Spectral.h" #include "atlas/functionspace/StructuredColumns.h" +#include "atlas/library/config.h" #include "atlas/mesh/IsGhostNode.h" #include "atlas/mesh/Nodes.h" #include "atlas/parallel/mpi/mpi.h" -#include "atlas/runtime/ErrorHandling.h" +#include "atlas/runtime/Exception.h" #include "atlas/runtime/Log.h" +#include "atlas/trans/detail/TransFactory.h" #include "atlas/trans/ifs/TransIFS.h" using Topology = atlas::mesh::Nodes::Topology; @@ -26,8 +29,8 @@ using atlas::Field; using atlas::FunctionSpace; using atlas::array::ArrayView; using atlas::array::LocalView; -using atlas::array::make_view; using atlas::array::make_shape; +using atlas::array::make_view; using atlas::functionspace::NodeColumns; using atlas::functionspace::Spectral; using atlas::functionspace::StructuredColumns; @@ -71,7 +74,7 @@ class TransParameters { int ngpblks() const { int _ngptot = trans_->ngptot; int _nproma = nproma(); - ASSERT( _ngptot % _nproma == 0 ); // assert _ngptot is divisable by nproma + ATLAS_ASSERT( _ngptot % _nproma == 0 ); // assert _ngptot is divisable by nproma return _ngptot / _nproma; } @@ -83,17 +86,17 @@ class TransParameters { namespace { std::string fieldset_functionspace( const FieldSet& fields ) { std::string functionspace( "undefined" ); - for ( size_t jfld = 0; jfld < fields.size(); ++jfld ) { + for ( idx_t jfld = 0; jfld < fields.size(); ++jfld ) { if ( functionspace == "undefined" ) functionspace = fields[jfld].functionspace().type(); if ( fields[jfld].functionspace().type() != functionspace ) { - throw eckit::SeriousBug( ": fielset has fields with different functionspaces", Here() ); + throw_Exception( ": fielset has fields with different functionspaces", Here() ); } } return functionspace; } void assert_spectral_functionspace( const FieldSet& fields ) { - for ( size_t jfld = 0; jfld < fields.size(); ++jfld ) { - ASSERT( functionspace::Spectral( fields[jfld].functionspace() ) ); + for ( idx_t jfld = 0; jfld < fields.size(); ++jfld ) { + ATLAS_ASSERT( functionspace::Spectral( fields[jfld].functionspace() ) ); } } @@ -102,23 +105,23 @@ void trans_check( const int code, const char* msg, const eckit::CodeLocation& lo std::stringstream errmsg; errmsg << "atlas::trans ERROR: " << msg << " failed: \n"; errmsg << ::trans_error_msg( code ); - throw eckit::Exception( errmsg.str(), location ); + throw_Exception( errmsg.str(), location ); } } #define TRANS_CHECK( CALL ) trans_check( CALL, #CALL, Here() ) static int compute_nfld( const Field& f ) { - int nfld=1; - for( int i=1; i gpfield = make_view( field ); - size_t n = 0; - for ( size_t jnode = 0; jnode < gpfield.shape( 0 ); ++jnode ) { + idx_t n = 0; + for ( idx_t jnode = 0; jnode < gpfield.shape( 0 ); ++jnode ) { if ( !is_ghost( jnode ) ) { rgpview_( f, n ) = gpfield( jnode ); ++n; @@ -347,12 +349,12 @@ struct PackNodeColumns { } ++f; } - void pack_2( const Field& field, int ) { + void pack_2( const Field& field, idx_t ) { const ArrayView gpfield = make_view( field ); - const size_t nvars = gpfield.shape( 1 ); - for ( size_t jvar = 0; jvar < nvars; ++jvar ) { - size_t n = 0; - for ( size_t jnode = 0; jnode < gpfield.shape( 0 ); ++jnode ) { + const idx_t nvars = gpfield.shape( 1 ); + for ( idx_t jvar = 0; jvar < nvars; ++jvar ) { + idx_t n = 0; + for ( idx_t jnode = 0; jnode < gpfield.shape( 0 ); ++jnode ) { if ( !is_ghost( jnode ) ) { rgpview_( f, n ) = gpfield( jnode, jvar ); ++n; @@ -361,13 +363,13 @@ struct PackNodeColumns { ++f; } } - void pack_3( const Field& field, int components ) { + void pack_3( const Field& field, idx_t components ) { const ArrayView gpfield = make_view( field ); if ( not components ) components = gpfield.shape( 2 ); - for ( size_t jcomp = 0; jcomp < size_t( components ); ++jcomp ) { - for ( size_t jlev = 0; jlev < gpfield.shape( 1 ); ++jlev ) { - size_t n = 0; - for ( size_t jnode = 0; jnode < gpfield.shape( 0 ); ++jnode ) { + for ( idx_t jcomp = 0; jcomp < components; ++jcomp ) { + for ( idx_t jlev = 0; jlev < gpfield.shape( 1 ); ++jlev ) { + idx_t n = 0; + for ( idx_t jnode = 0; jnode < gpfield.shape( 0 ); ++jnode ) { if ( !is_ghost( jnode ) ) { rgpview_( f, n ) = gpfield( jnode, jlev, jcomp ); ++n; @@ -395,15 +397,15 @@ struct PackStructuredColumns { break; default: ATLAS_DEBUG_VAR( field.rank() ); - NOTIMP; + ATLAS_NOTIMPLEMENTED; //break; } } void pack_1( const Field& field ) { const ArrayView gpfield = make_view( field ); - size_t n = 0; - for ( size_t jnode = 0; jnode < gpfield.shape( 0 ); ++jnode ) { + idx_t n = 0; + for ( idx_t jnode = 0; jnode < gpfield.shape( 0 ); ++jnode ) { rgpview_( f, n ) = gpfield( jnode ); ++n; } @@ -411,10 +413,10 @@ struct PackStructuredColumns { } void pack_2( const Field& field ) { const ArrayView gpfield = make_view( field ); - const size_t nvars = gpfield.shape( 1 ); - for ( size_t jvar = 0; jvar < nvars; ++jvar ) { - size_t n = 0; - for ( size_t jnode = 0; jnode < gpfield.shape( 0 ); ++jnode ) { + const idx_t nvars = gpfield.shape( 1 ); + for ( idx_t jvar = 0; jvar < nvars; ++jvar ) { + idx_t n = 0; + for ( idx_t jnode = 0; jnode < gpfield.shape( 0 ); ++jnode ) { rgpview_( f, n ) = gpfield( jnode, jvar ); ++n; } @@ -438,7 +440,7 @@ struct PackSpectral { break; default: ATLAS_DEBUG_VAR( field.rank() ); - NOTIMP; + ATLAS_NOTIMPLEMENTED; //break; } } @@ -446,7 +448,7 @@ struct PackSpectral { void pack_1( const Field& field ) { const ArrayView spfield = make_view( field ); - for ( size_t jwave = 0; jwave < spfield.shape( 0 ); ++jwave ) { + for ( idx_t jwave = 0; jwave < spfield.shape( 0 ); ++jwave ) { rspecview_( jwave, f ) = spfield( jwave ); } ++f; @@ -454,10 +456,10 @@ struct PackSpectral { void pack_2( const Field& field ) { const ArrayView spfield = make_view( field ); - const size_t nvars = spfield.shape( 1 ); + const idx_t nvars = spfield.shape( 1 ); - for ( size_t jvar = 0; jvar < nvars; ++jvar ) { - for ( size_t jwave = 0; jwave < spfield.shape( 0 ); ++jwave ) { + for ( idx_t jvar = 0; jvar < nvars; ++jvar ) { + for ( idx_t jwave = 0; jwave < spfield.shape( 0 ); ++jwave ) { rspecview_( jwave, f ) = spfield( jwave, jvar ); } ++f; @@ -488,15 +490,15 @@ struct UnpackNodeColumns { break; default: ATLAS_DEBUG_VAR( field.rank() ); - NOTIMP; + ATLAS_NOTIMPLEMENTED; //break; } } - void unpack_1( Field& field, int ) { + void unpack_1( Field& field, idx_t ) { ArrayView gpfield = make_view( field ); - size_t n( 0 ); - for ( size_t jnode = 0; jnode < gpfield.shape( 0 ); ++jnode ) { + idx_t n( 0 ); + for ( idx_t jnode = 0; jnode < gpfield.shape( 0 ); ++jnode ) { if ( !is_ghost( jnode ) ) { gpfield( jnode ) = rgpview_( f, n ); ++n; @@ -504,12 +506,12 @@ struct UnpackNodeColumns { } ++f; } - void unpack_2( Field& field, int ) { + void unpack_2( Field& field, idx_t ) { ArrayView gpfield = make_view( field ); - const size_t nvars = gpfield.shape( 1 ); - for ( size_t jvar = 0; jvar < nvars; ++jvar ) { - int n = 0; - for ( size_t jnode = 0; jnode < gpfield.shape( 0 ); ++jnode ) { + const idx_t nvars = gpfield.shape( 1 ); + for ( idx_t jvar = 0; jvar < nvars; ++jvar ) { + idx_t n = 0; + for ( idx_t jnode = 0; jnode < gpfield.shape( 0 ); ++jnode ) { if ( !is_ghost( jnode ) ) { gpfield( jnode, jvar ) = rgpview_( f, n ); ++n; @@ -518,13 +520,13 @@ struct UnpackNodeColumns { ++f; } } - void unpack_3( Field& field, int components ) { + void unpack_3( Field& field, idx_t components ) { ArrayView gpfield = make_view( field ); if ( not components ) components = gpfield.shape( 2 ); - for ( size_t jcomp = 0; jcomp < size_t( components ); ++jcomp ) { - for ( size_t jlev = 0; jlev < gpfield.shape( 1 ); ++jlev ) { - size_t n = 0; - for ( size_t jnode = 0; jnode < gpfield.shape( 0 ); ++jnode ) { + for ( idx_t jcomp = 0; jcomp < components; ++jcomp ) { + for ( idx_t jlev = 0; jlev < gpfield.shape( 1 ); ++jlev ) { + idx_t n = 0; + for ( idx_t jnode = 0; jnode < gpfield.shape( 0 ); ++jnode ) { if ( !is_ghost( jnode ) ) { gpfield( jnode, jlev, jcomp ) = rgpview_( f, n ); ++n; @@ -552,15 +554,15 @@ struct UnpackStructuredColumns { break; default: ATLAS_DEBUG_VAR( field.rank() ); - NOTIMP; + ATLAS_NOTIMPLEMENTED; //break; } } void unpack_1( Field& field ) { ArrayView gpfield = make_view( field ); - size_t n = 0; - for ( size_t jnode = 0; jnode < gpfield.shape( 0 ); ++jnode ) { + idx_t n = 0; + for ( idx_t jnode = 0; jnode < gpfield.shape( 0 ); ++jnode ) { gpfield( jnode ) = rgpview_( f, n ); ++n; } @@ -568,10 +570,10 @@ struct UnpackStructuredColumns { } void unpack_2( Field& field ) { ArrayView gpfield = make_view( field ); - const size_t nvars = gpfield.shape( 1 ); - for ( size_t jvar = 0; jvar < nvars; ++jvar ) { - size_t n = 0; - for ( size_t jnode = 0; jnode < gpfield.shape( 0 ); ++jnode ) { + const idx_t nvars = gpfield.shape( 1 ); + for ( idx_t jvar = 0; jvar < nvars; ++jvar ) { + idx_t n = 0; + for ( idx_t jnode = 0; jnode < gpfield.shape( 0 ); ++jnode ) { gpfield( jnode, jvar ) = rgpview_( f, n ); ++n; } @@ -595,7 +597,7 @@ struct UnpackSpectral { break; default: ATLAS_DEBUG_VAR( field.rank() ); - NOTIMP; + ATLAS_NOTIMPLEMENTED; //break; } } @@ -603,7 +605,7 @@ struct UnpackSpectral { void unpack_1( Field& field ) { ArrayView spfield = make_view( field ); - for ( size_t jwave = 0; jwave < spfield.shape( 0 ); ++jwave ) { + for ( idx_t jwave = 0; jwave < spfield.shape( 0 ); ++jwave ) { spfield( jwave ) = rspecview_( jwave, f ); } ++f; @@ -611,10 +613,10 @@ struct UnpackSpectral { void unpack_2( Field& field ) { ArrayView spfield = make_view( field ); - const size_t nvars = spfield.shape( 1 ); + const idx_t nvars = spfield.shape( 1 ); - for ( size_t jvar = 0; jvar < nvars; ++jvar ) { - for ( size_t jwave = 0; jwave < spfield.shape( 0 ); ++jwave ) { + for ( idx_t jvar = 0; jvar < nvars; ++jvar ) { + for ( idx_t jwave = 0; jwave < spfield.shape( 0 ); ++jwave ) { spfield( jwave, jvar ) = rspecview_( jwave, f ); } ++f; @@ -623,6 +625,7 @@ struct UnpackSpectral { }; } // end anonymous namespace +} // namespace atlas namespace atlas { namespace trans { @@ -632,11 +635,11 @@ void TransIFS::assertCompatibleDistributions( const FunctionSpace& gp, const Fun if ( gp_dist != "trans" && // distribution computed by TransPartitioner gp_dist != "serial" && // serial distribution always works gp_dist != "custom" ) { // trust user that he knows what he is doing - throw eckit::Exception( gp.type() + " functionspace has unsupported distribution (" + gp_dist + - ") " - "to do spectral transforms. Please " - "partition grid with TransPartitioner", - Here() ); + throw_Exception( gp.type() + " functionspace has unsupported distribution (" + gp_dist + + ") " + "to do spectral transforms. Please " + "partition grid with TransPartitioner", + Here() ); } } @@ -644,15 +647,15 @@ TransIFS::TransIFS( const Cache& cache, const Grid& grid, const long truncation, grid_( grid ), cache_( cache.legendre().data() ), cachesize_( cache.legendre().size() ) { - ASSERT( grid.domain().global() ); - ASSERT( not grid.projection() ); + ATLAS_ASSERT( grid.domain().global() ); + ATLAS_ASSERT( not grid.projection() ); ctor( grid, truncation, config ); } TransIFS::TransIFS( const Grid& grid, const long truncation, const eckit::Configuration& config ) : TransIFS( Cache(), grid, truncation, config ) { - ASSERT( grid.domain().global() ); - ASSERT( not grid.projection() ); + ATLAS_ASSERT( grid.domain().global() ); + ATLAS_ASSERT( not grid.projection() ); } TransIFS::TransIFS( const Grid& grid, const eckit::Configuration& config ) : @@ -662,13 +665,13 @@ TransIFS::TransIFS( const Grid& grid, const eckit::Configuration& config ) : TransIFS::TransIFS( const Grid& grid, const Domain& domain, const long truncation, const eckit::Configuration& config ) : TransIFS( Cache(), grid, truncation, config ) { - ASSERT( domain.global() ); + ATLAS_ASSERT( domain.global() ); } TransIFS::TransIFS( const Cache& cache, const Grid& grid, const Domain& domain, const long truncation, const eckit::Configuration& config ) : TransIFS( cache, grid, truncation, config ) { - ASSERT( domain.global() ); + ATLAS_ASSERT( domain.global() ); } TransIFS::~TransIFS() {} @@ -679,17 +682,17 @@ void TransIFS::ctor( const Grid& grid, long truncation, const eckit::Configurati delete p; } ); - if ( auto gg = grid::GaussianGrid( grid ) ) { + if ( auto gg = GaussianGrid( grid ) ) { ctor_rgg( gg.ny(), gg.nx().data(), truncation, config ); return; } - if ( auto ll = grid::RegularLonLatGrid( grid ) ) { + if ( auto ll = RegularLonLatGrid( grid ) ) { if ( ll.standard() || ll.shifted() ) { ctor_lonlat( ll.nx(), ll.ny(), truncation, config ); return; } } - throw eckit::NotImplemented( "Grid type not supported for Spectral Transforms", Here() ); + throw_NotImplemented( "Grid type not supported for Spectral Transforms", Here() ); } void TransIFS::ctor_spectral_only( long truncation, const eckit::Configuration& ) { @@ -703,7 +706,7 @@ void TransIFS::ctor_spectral_only( long truncation, const eckit::Configuration& TRANS_CHECK(::trans_setup( trans_.get() ) ); } -void TransIFS::ctor_rgg( const long nlat, const long pl[], long truncation, const eckit::Configuration& config ) { +void TransIFS::ctor_rgg( const long nlat, const idx_t pl[], long truncation, const eckit::Configuration& config ) { TransParameters p( *this, config ); std::vector nloen( nlat ); for ( long jlat = 0; jlat < nlat; ++jlat ) @@ -720,7 +723,7 @@ void TransIFS::ctor_rgg( const long nlat, const long pl[], long truncation, cons if ( not file.exists() ) { std::stringstream msg; msg << "File " << file << " doesn't exist"; - throw eckit::CantOpenFile( msg.str(), Here() ); + throw_CantOpenFile( msg.str(), Here() ); } TRANS_CHECK(::trans_set_read( trans_.get(), file.asString().c_str() ) ); } @@ -748,7 +751,7 @@ void TransIFS::ctor_lonlat( const long nlon, const long nlat, long truncation, c if ( not file.exists() ) { std::stringstream msg; msg << "File " << file << " doesn't exist"; - throw eckit::CantOpenFile( msg.str(), Here() ); + throw_CantOpenFile( msg.str(), Here() ); } TRANS_CHECK(::trans_set_read( trans_.get(), file.asString().c_str() ) ); } @@ -779,27 +782,26 @@ void TransIFS::__dirtrans( const functionspace::NodeColumns& gp, const Field& gp void TransIFS::__dirtrans( const functionspace::NodeColumns& gp, const FieldSet& gpfields, const Spectral& sp, FieldSet& spfields, const eckit::Configuration& ) const { - assertCompatibleDistributions( gp, sp ); // Count total number of fields and do sanity checks - const int nfld = compute_nfld( gpfields ); + const int nfld = compute_nfld( gpfields ); const int trans_sp_nfld = compute_nfld( spfields ); if ( nfld != trans_sp_nfld ) { - throw eckit::SeriousBug( "dirtrans: different number of gridpoint fields than spectral fields", Here() ); + throw_Exception( "dirtrans: different number of gridpoint fields than spectral fields", Here() ); } // Arrays Trans expects std::vector rgp( nfld * ngptot() ); std::vector rsp( nspec2() * nfld ); - auto rgpview = LocalView( rgp.data(), make_shape( nfld, ngptot() ) ); - auto rspview = LocalView( rsp.data(), make_shape( nspec2(), nfld ) ); + auto rgpview = LocalView( rgp.data(), make_shape( nfld, ngptot() ) ); + auto rspview = LocalView( rsp.data(), make_shape( nspec2(), nfld ) ); // Pack gridpoints { PackNodeColumns pack( rgpview, gp ); - for ( size_t jfld = 0; jfld < gpfields.size(); ++jfld ) + for ( idx_t jfld = 0; jfld < gpfields.size(); ++jfld ) pack( gpfields[jfld] ); } @@ -815,7 +817,7 @@ void TransIFS::__dirtrans( const functionspace::NodeColumns& gp, const FieldSet& // Unpack the spectral fields { UnpackSpectral unpack( rspview ); - for ( size_t jfld = 0; jfld < spfields.size(); ++jfld ) + for ( idx_t jfld = 0; jfld < spfields.size(); ++jfld ) unpack( spfields[jfld] ); } } @@ -824,25 +826,24 @@ void TransIFS::__dirtrans( const functionspace::NodeColumns& gp, const FieldSet& void TransIFS::__dirtrans( const StructuredColumns& gp, const Field& gpfield, const Spectral& sp, Field& spfield, const eckit::Configuration& ) const { - - ASSERT( gpfield.functionspace() == 0 || functionspace::StructuredColumns( gpfield.functionspace() ) ); - ASSERT( spfield.functionspace() == 0 || functionspace::Spectral( spfield.functionspace() ) ); + ATLAS_ASSERT( gpfield.functionspace() == 0 || functionspace::StructuredColumns( gpfield.functionspace() ) ); + ATLAS_ASSERT( spfield.functionspace() == 0 || functionspace::Spectral( spfield.functionspace() ) ); assertCompatibleDistributions( gp, sp ); if ( compute_nfld( gpfield ) != compute_nfld( spfield ) ) { - throw eckit::SeriousBug( "dirtrans: different number of gridpoint fields than spectral fields", Here() ); + throw_Exception( "dirtrans: different number of gridpoint fields than spectral fields", Here() ); } if ( (int)gpfield.shape( 0 ) != ngptot() ) { - throw eckit::SeriousBug( "dirtrans: slowest moving index must be ngptot", Here() ); + throw_Exception( "dirtrans: slowest moving index must be ngptot", Here() ); } const int nfld = compute_nfld( gpfield ); // Arrays Trans expects std::vector rgp( nfld * ngptot() ); std::vector rsp( nspec2() * nfld ); - auto rgpview = LocalView( rgp.data(), make_shape( nfld, ngptot() ) ); - auto rspview = LocalView( rsp.data(), make_shape( nspec2(), nfld ) ); + auto rgpview = LocalView( rgp.data(), make_shape( nfld, ngptot() ) ); + auto rspview = LocalView( rsp.data(), make_shape( nspec2(), nfld ) ); // Pack gridpoints { @@ -866,43 +867,41 @@ void TransIFS::__dirtrans( const StructuredColumns& gp, const Field& gpfield, co UnpackSpectral unpack( rspview ); unpack( spfield ); } - } void TransIFS::__dirtrans( const StructuredColumns& gp, const FieldSet& gpfields, const Spectral& sp, FieldSet& spfields, const eckit::Configuration& ) const { - assertCompatibleDistributions( gp, sp ); // Count total number of fields and do sanity checks - const int nfld = compute_nfld( gpfields ); - for ( size_t jfld = 0; jfld < gpfields.size(); ++jfld ) { + const idx_t nfld = compute_nfld( gpfields ); + for ( idx_t jfld = 0; jfld < gpfields.size(); ++jfld ) { const Field& f = gpfields[jfld]; - ASSERT( f.functionspace() == 0 || functionspace::StructuredColumns( f.functionspace() ) ); + ATLAS_ASSERT( f.functionspace() == 0 || functionspace::StructuredColumns( f.functionspace() ) ); } const int trans_sp_nfld = compute_nfld( spfields ); if ( nfld != trans_sp_nfld ) { - throw eckit::SeriousBug( "dirtrans: different number of gridpoint fields than spectral fields", Here() ); + throw_Exception( "dirtrans: different number of gridpoint fields than spectral fields", Here() ); } // Arrays Trans expects std::vector rgp( nfld * ngptot() ); std::vector rsp( nspec2() * nfld ); - auto rgpview = LocalView( rgp.data(), make_shape( nfld, ngptot() ) ); - auto rspview = LocalView( rsp.data(), make_shape( nspec2(), nfld ) ); + auto rgpview = LocalView( rgp.data(), make_shape( nfld, ngptot() ) ); + auto rspview = LocalView( rsp.data(), make_shape( nspec2(), nfld ) ); // Pack gridpoints { PackStructuredColumns pack( rgpview ); - for ( size_t jfld = 0; jfld < gpfields.size(); ++jfld ) + for ( idx_t jfld = 0; jfld < gpfields.size(); ++jfld ) pack( gpfields[jfld] ); } // Do transform { struct ::DirTrans_t transform = ::new_dirtrans( trans_.get() ); - transform.nscalar = nfld; + transform.nscalar = int( nfld ); transform.rgp = rgp.data(); transform.rspscalar = rsp.data(); @@ -912,7 +911,7 @@ void TransIFS::__dirtrans( const StructuredColumns& gp, const FieldSet& gpfields // Unpack the spectral fields { UnpackSpectral unpack( rspview ); - for ( size_t jfld = 0; jfld < spfields.size(); ++jfld ) + for ( idx_t jfld = 0; jfld < spfields.size(); ++jfld ) unpack( spfields[jfld] ); } } @@ -930,15 +929,14 @@ void TransIFS::__invtrans_grad( const Spectral& sp, const Field& spfield, const void TransIFS::__invtrans_grad( const Spectral& sp, const FieldSet& spfields, const functionspace::NodeColumns& gp, FieldSet& gradfields, const eckit::Configuration& config ) const { - assertCompatibleDistributions( gp, sp ); // Count total number of fields and do sanity checks const int nb_gridpoint_field = compute_nfld( gradfields ); - const int nfld = compute_nfld( spfields ); + const int nfld = compute_nfld( spfields ); if ( nb_gridpoint_field != 2 * nfld ) // factor 2 because N-S and E-W derivatives - throw eckit::SeriousBug( + throw_Exception( "invtrans_grad: different number of gridpoint " "fields than spectral fields", Here() ); @@ -947,14 +945,14 @@ void TransIFS::__invtrans_grad( const Spectral& sp, const FieldSet& spfields, co // Allocate space for std::vector rgp( 3 * nfld * ngptot() ); // (scalars) + (NS ders) + (EW ders) std::vector rsp( nspec2() * nfld ); - auto rgpview = LocalView( rgp.data(), make_shape(3 * nfld, ngptot() ) ); - auto rspview = LocalView( rsp.data(), make_shape( nspec2(), nfld ) ); + auto rgpview = LocalView( rgp.data(), make_shape( 3 * nfld, ngptot() ) ); + auto rspview = LocalView( rsp.data(), make_shape( nspec2(), nfld ) ); // Pack spectral fields { PackSpectral pack( rspview ); - for ( size_t jfld = 0; jfld < spfields.size(); ++jfld ) + for ( idx_t jfld = 0; jfld < spfields.size(); ++jfld ) pack( spfields[jfld] ); } @@ -973,33 +971,33 @@ void TransIFS::__invtrans_grad( const Spectral& sp, const FieldSet& spfields, co { mesh::IsGhostNode is_ghost( gp.nodes() ); int f = nfld; // skip to where derivatives start - for ( size_t dim = 0; dim < 2; ++dim ) { - for ( size_t jfld = 0; jfld < gradfields.size(); ++jfld ) { - const size_t nb_nodes = gradfields[jfld].shape( 0 ); - const size_t nlev = gradfields[jfld].levels(); - if( nlev ) { - auto field = make_view( gradfields[jfld] ); - for ( size_t jlev = 0; jlev < nlev; ++jlev ) { + for ( idx_t dim = 0; dim < 2; ++dim ) { + for ( idx_t jfld = 0; jfld < gradfields.size(); ++jfld ) { + const idx_t nb_nodes = gradfields[jfld].shape( 0 ); + const idx_t nlev = gradfields[jfld].levels(); + if ( nlev ) { + auto field = make_view( gradfields[jfld] ); + for ( idx_t jlev = 0; jlev < nlev; ++jlev ) { int n = 0; - for ( size_t jnode = 0; jnode < nb_nodes; ++jnode ) { + for ( idx_t jnode = 0; jnode < nb_nodes; ++jnode ) { if ( !is_ghost( jnode ) ) { field( jnode, jlev, 1 - dim ) = rgpview( f, n ); ++n; } } - ASSERT( n == ngptot() ); + ATLAS_ASSERT( n == ngptot() ); } } else { - auto field = make_view( gradfields[jfld] ); - int n = 0; - for ( size_t jnode = 0; jnode < nb_nodes; ++jnode ) { + auto field = make_view( gradfields[jfld] ); + int n = 0; + for ( idx_t jnode = 0; jnode < nb_nodes; ++jnode ) { if ( !is_ghost( jnode ) ) { field( jnode, 1 - dim ) = rgpview( f, n ); ++n; } } - ASSERT( n == ngptot() ); + ATLAS_ASSERT( n == ngptot() ); } ++f; } @@ -1022,16 +1020,15 @@ void TransIFS::__invtrans( const Spectral& sp, const Field& spfield, const funct void TransIFS::__invtrans( const Spectral& sp, const FieldSet& spfields, const functionspace::NodeColumns& gp, FieldSet& gpfields, const eckit::Configuration& config ) const { - assertCompatibleDistributions( gp, sp ); // Count total number of fields and do sanity checks - const int nfld = compute_nfld( gpfields ); + const int nfld = compute_nfld( gpfields ); const int nb_spectral_fields = compute_nfld( spfields ); if ( nfld != nb_spectral_fields ) - throw eckit::SeriousBug( "invtrans: different number of gridpoint fields than spectral fields", Here() ); + throw_Exception( "invtrans: different number of gridpoint fields than spectral fields", Here() ); // Arrays Trans expects std::vector rgp( nfld * ngptot() ); @@ -1042,7 +1039,7 @@ void TransIFS::__invtrans( const Spectral& sp, const FieldSet& spfields, const f // Pack spectral fields { PackSpectral pack( rspview ); - for ( size_t jfld = 0; jfld < spfields.size(); ++jfld ) + for ( idx_t jfld = 0; jfld < spfields.size(); ++jfld ) pack( spfields[jfld] ); } @@ -1058,7 +1055,7 @@ void TransIFS::__invtrans( const Spectral& sp, const FieldSet& spfields, const f // Unpack the gridpoint fields { UnpackNodeColumns unpack( rgpview, gp ); - for ( size_t jfld = 0; jfld < gpfields.size(); ++jfld ) + for ( idx_t jfld = 0; jfld < gpfields.size(); ++jfld ) unpack( gpfields[jfld] ); } } @@ -1068,24 +1065,23 @@ void TransIFS::__invtrans( const Spectral& sp, const FieldSet& spfields, const f void TransIFS::__invtrans( const functionspace::Spectral& sp, const Field& spfield, const functionspace::StructuredColumns& gp, Field& gpfield, const eckit::Configuration& config ) const { - assertCompatibleDistributions( gp, sp ); - ASSERT( gpfield.functionspace() == 0 || functionspace::StructuredColumns( gpfield.functionspace() ) ); - ASSERT( spfield.functionspace() == 0 || functionspace::Spectral( spfield.functionspace() ) ); + ATLAS_ASSERT( gpfield.functionspace() == 0 || functionspace::StructuredColumns( gpfield.functionspace() ) ); + ATLAS_ASSERT( spfield.functionspace() == 0 || functionspace::Spectral( spfield.functionspace() ) ); if ( compute_nfld( gpfield ) != compute_nfld( spfield ) ) { - throw eckit::SeriousBug( "dirtrans: different number of gridpoint fields than spectral fields", Here() ); + throw_Exception( "dirtrans: different number of gridpoint fields than spectral fields", Here() ); } if ( (int)gpfield.shape( 0 ) != ngptot() ) { - throw eckit::SeriousBug( "dirtrans: slowest moving index must be ngptot", Here() ); + throw_Exception( "dirtrans: slowest moving index must be ngptot", Here() ); } const int nfld = compute_nfld( gpfield ); // Arrays Trans expects std::vector rgp( nfld * ngptot() ); std::vector rsp( nspec2() * nfld ); - auto rgpview = LocalView( rgp.data(), make_shape( nfld, ngptot() ) ); - auto rspview = LocalView( rsp.data(), make_shape( nspec2(), nfld ) ); + auto rgpview = LocalView( rgp.data(), make_shape( nfld, ngptot() ) ); + auto rspview = LocalView( rsp.data(), make_shape( nspec2(), nfld ) ); // Pack spectral fields { @@ -1116,14 +1112,13 @@ void TransIFS::__invtrans( const functionspace::Spectral& sp, const Field& spfie void TransIFS::__invtrans( const functionspace::Spectral& sp, const FieldSet& spfields, const functionspace::StructuredColumns& gp, FieldSet& gpfields, const eckit::Configuration& config ) const { - assertCompatibleDistributions( gp, sp ); // Count total number of fields and do sanity checks const int nfld = compute_nfld( gpfields ); - for ( size_t jfld = 0; jfld < gpfields.size(); ++jfld ) { + for ( idx_t jfld = 0; jfld < gpfields.size(); ++jfld ) { const Field& f = gpfields[jfld]; - ASSERT( f.functionspace() == 0 || functionspace::StructuredColumns( f.functionspace() ) ); + ATLAS_ASSERT( f.functionspace() == 0 || functionspace::StructuredColumns( f.functionspace() ) ); } const int nb_spectral_fields = compute_nfld( spfields ); @@ -1132,19 +1127,19 @@ void TransIFS::__invtrans( const functionspace::Spectral& sp, const FieldSet& sp std::stringstream msg; msg << "invtrans: different number of gridpoint fields than spectral fields" << "[ " << nfld << " != " << nb_spectral_fields << " ]"; - throw eckit::SeriousBug( msg.str(), Here() ); + throw_Exception( msg.str(), Here() ); } // Arrays Trans expects std::vector rgp( nfld * ngptot() ); std::vector rsp( nspec2() * nfld ); - auto rgpview = LocalView( rgp.data(), make_shape( nfld, ngptot() ) ); - auto rspview = LocalView( rsp.data(), make_shape( nspec2(), nfld ) ); + auto rgpview = LocalView( rgp.data(), make_shape( nfld, ngptot() ) ); + auto rspview = LocalView( rsp.data(), make_shape( nspec2(), nfld ) ); // Pack spectral fields { PackSpectral pack( rspview ); - for ( size_t jfld = 0; jfld < spfields.size(); ++jfld ) + for ( idx_t jfld = 0; jfld < spfields.size(); ++jfld ) pack( spfields[jfld] ); } @@ -1161,7 +1156,7 @@ void TransIFS::__invtrans( const functionspace::Spectral& sp, const FieldSet& sp // Unpack the gridpoint fields { UnpackStructuredColumns unpack( rgpview ); - for ( size_t jfld = 0; jfld < gpfields.size(); ++jfld ) + for ( idx_t jfld = 0; jfld < gpfields.size(); ++jfld ) unpack( gpfields[jfld] ); } } @@ -1170,35 +1165,34 @@ void TransIFS::__invtrans( const functionspace::Spectral& sp, const FieldSet& sp void TransIFS::__dirtrans_wind2vordiv( const functionspace::NodeColumns& gp, const Field& gpwind, const Spectral& sp, Field& spvor, Field& spdiv, const eckit::Configuration& ) const { - assertCompatibleDistributions( gp, sp ); // Count total number of fields and do sanity checks const size_t nfld = compute_nfld( spvor ); if ( spdiv.shape( 0 ) != spvor.shape( 0 ) ) - throw eckit::SeriousBug( "invtrans: vorticity not compatible with divergence.", Here() ); + throw_Exception( "invtrans: vorticity not compatible with divergence.", Here() ); if ( spdiv.shape( 1 ) != spvor.shape( 1 ) ) - throw eckit::SeriousBug( "invtrans: vorticity not compatible with divergence.", Here() ); - const size_t nwindfld = compute_nfld( gpwind); + throw_Exception( "invtrans: vorticity not compatible with divergence.", Here() ); + const size_t nwindfld = compute_nfld( gpwind ); if ( nwindfld != 2 * nfld && nwindfld != 3 * nfld ) - throw eckit::SeriousBug( "dirtrans: wind field is not compatible with vorticity, divergence.", Here() ); + throw_Exception( "dirtrans: wind field is not compatible with vorticity, divergence.", Here() ); - if ( spdiv.shape( 0 ) != size_t( nspec2() ) ) { + if ( spdiv.shape( 0 ) != nspec2() ) { std::stringstream msg; msg << "dirtrans: Spectral vorticity and divergence have wrong dimension: " "nspec2 " << spdiv.shape( 0 ) << " should be " << nspec2(); - throw eckit::SeriousBug( msg.str(), Here() ); + throw_Exception( msg.str(), Here() ); } - if ( spvor.size() == 0 ) throw eckit::SeriousBug( "dirtrans: spectral vorticity field is empty." ); - if ( spdiv.size() == 0 ) throw eckit::SeriousBug( "dirtrans: spectral divergence field is empty." ); + if ( spvor.size() == 0 ) throw_Exception( "dirtrans: spectral vorticity field is empty." ); + if ( spdiv.size() == 0 ) throw_Exception( "dirtrans: spectral divergence field is empty." ); // Arrays Trans expects std::vector rgp( 2 * nfld * ngptot() ); std::vector rspvor( nspec2() * nfld ); std::vector rspdiv( nspec2() * nfld ); - auto rgpview = LocalView( rgp.data(), make_shape( 2 * nfld, ngptot() ) ); + auto rgpview = LocalView( rgp.data(), make_shape( 2 * nfld, ngptot() ) ); auto rspvorview = LocalView( rspvor.data(), make_shape( nspec2(), nfld ) ); auto rspdivview = LocalView( rspdiv.data(), make_shape( nspec2(), nfld ) ); @@ -1212,62 +1206,64 @@ void TransIFS::__dirtrans_wind2vordiv( const functionspace::NodeColumns& gp, con // Do transform { struct ::DirTrans_t transform = ::new_dirtrans( trans_.get() ); - transform.nvordiv = nfld; + transform.nvordiv = int( nfld ); transform.rgp = rgp.data(); transform.rspvor = rspvor.data(); transform.rspdiv = rspdiv.data(); - ASSERT( transform.rspvor ); - ASSERT( transform.rspdiv ); + ATLAS_ASSERT( transform.rspvor ); + ATLAS_ASSERT( transform.rspdiv ); TRANS_CHECK(::trans_dirtrans( &transform ) ); } // Pack spectral fields - UnpackSpectral unpack_vor( rspvorview ); unpack_vor( spvor ); - UnpackSpectral unpack_div( rspdivview ); unpack_div( spdiv ); - + UnpackSpectral unpack_vor( rspvorview ); + unpack_vor( spvor ); + UnpackSpectral unpack_div( rspdivview ); + unpack_div( spdiv ); } void TransIFS::__invtrans_vordiv2wind( const Spectral& sp, const Field& spvor, const Field& spdiv, const functionspace::NodeColumns& gp, Field& gpwind, - const eckit::Configuration& config ) const { - + const eckit::Configuration& ) const { assertCompatibleDistributions( gp, sp ); // Count total number of fields and do sanity checks const int nfld = compute_nfld( spvor ); if ( spdiv.shape( 0 ) != spvor.shape( 0 ) ) - throw eckit::SeriousBug( "invtrans: vorticity not compatible with divergence.", Here() ); + throw_Exception( "invtrans: vorticity not compatible with divergence.", Here() ); if ( spdiv.shape( 1 ) != spvor.shape( 1 ) ) - throw eckit::SeriousBug( "invtrans: vorticity not compatible with divergence.", Here() ); + throw_Exception( "invtrans: vorticity not compatible with divergence.", Here() ); const int nwindfld = compute_nfld( gpwind ); if ( nwindfld != 2 * nfld && nwindfld != 3 * nfld ) - throw eckit::SeriousBug( "invtrans: wind field is not compatible with vorticity, divergence.", Here() ); + throw_Exception( "invtrans: wind field is not compatible with vorticity, divergence.", Here() ); - if ( spdiv.shape( 0 ) != size_t( nspec2() ) ) { + if ( spdiv.shape( 0 ) != nspec2() ) { std::stringstream msg; msg << "invtrans: Spectral vorticity and divergence have wrong dimension: " "nspec2 " << spdiv.shape( 0 ) << " should be " << nspec2(); - throw eckit::SeriousBug( msg.str(), Here() ); + throw_Exception( msg.str(), Here() ); } - ASSERT( spvor.rank() == 2 ); - ASSERT( spdiv.rank() == 2 ); - if ( spvor.size() == 0 ) throw eckit::SeriousBug( "invtrans: spectral vorticity field is empty." ); - if ( spdiv.size() == 0 ) throw eckit::SeriousBug( "invtrans: spectral divergence field is empty." ); + ATLAS_ASSERT( spvor.rank() == 2 ); + ATLAS_ASSERT( spdiv.rank() == 2 ); + if ( spvor.size() == 0 ) throw_Exception( "invtrans: spectral vorticity field is empty." ); + if ( spdiv.size() == 0 ) throw_Exception( "invtrans: spectral divergence field is empty." ); // Arrays Trans expects std::vector rgp( 2 * nfld * ngptot() ); std::vector rspvor( nspec2() * nfld ); std::vector rspdiv( nspec2() * nfld ); - auto rgpview = LocalView( rgp.data(), make_shape( 2 * nfld, ngptot() ) ); + auto rgpview = LocalView( rgp.data(), make_shape( 2 * nfld, ngptot() ) ); auto rspvorview = LocalView( rspvor.data(), make_shape( nspec2(), nfld ) ); auto rspdivview = LocalView( rspdiv.data(), make_shape( nspec2(), nfld ) ); // Pack spectral fields - PackSpectral pack_vor( rspvorview ); pack_vor( spvor ); - PackSpectral pack_div( rspdivview ); pack_div( spdiv ); + PackSpectral pack_vor( rspvorview ); + pack_vor( spvor ); + PackSpectral pack_div( rspdivview ); + pack_div( spdiv ); // Do transform { @@ -1277,8 +1273,8 @@ void TransIFS::__invtrans_vordiv2wind( const Spectral& sp, const Field& spvor, c transform.rspvor = rspvor.data(); transform.rspdiv = rspdiv.data(); - ASSERT( transform.rspvor ); - ASSERT( transform.rspdiv ); + ATLAS_ASSERT( transform.rspvor ); + ATLAS_ASSERT( transform.rspdiv ); TRANS_CHECK(::trans_invtrans( &transform ) ); } @@ -1354,157 +1350,204 @@ void TransIFS::specnorm( const int nb_fields, const double spectra[], double nor extern "C" { TransIFS* atlas__Trans__new( const Grid::Implementation* grid, int nsmax ) { - TransIFS* trans( 0 ); - ATLAS_ERROR_HANDLING( ASSERT( grid ); trans = new TransIFS( Grid( grid ), nsmax ); ); - return trans; + ATLAS_ASSERT( grid != nullptr ); + return new TransIFS( Grid( grid ), nsmax ); } void atlas__Trans__delete( TransIFS* This ) { - ASSERT( This ); - ATLAS_ERROR_HANDLING( delete This ); + ATLAS_ASSERT( This != nullptr ); + delete This; } int atlas__Trans__handle( const TransIFS* This ) { - ASSERT( This ); - ATLAS_ERROR_HANDLING(::Trans_t* t = *This; return t->handle; ); - return 0; + ATLAS_ASSERT( This != nullptr ); + ::Trans_t* t = *This; + return t->handle; } void atlas__Trans__distspec( const TransIFS* t, int nb_fields, int origin[], double global_spectra[], double spectra[] ) { - ATLAS_ERROR_HANDLING( ASSERT( t ); struct ::DistSpec_t args = new_distspec( t->trans() ); args.nfld = nb_fields; - args.rspecg = global_spectra; args.nfrom = origin; args.rspec = spectra; - TRANS_CHECK(::trans_distspec( &args ) ); ); + ATLAS_ASSERT( t != nullptr ); + struct ::DistSpec_t args = new_distspec( t->trans() ); + args.nfld = nb_fields; + args.rspecg = global_spectra; + args.nfrom = origin; + args.rspec = spectra; + TRANS_CHECK(::trans_distspec( &args ) ); } void atlas__Trans__gathspec( const TransIFS* t, int nb_fields, int destination[], double spectra[], double global_spectra[] ) { - ATLAS_ERROR_HANDLING( ASSERT( t ); struct ::GathSpec_t args = new_gathspec( t->trans() ); args.nfld = nb_fields; - args.rspecg = global_spectra; args.nto = destination; args.rspec = spectra; - TRANS_CHECK(::trans_gathspec( &args ) ); ); + ATLAS_ASSERT( t != nullptr ); + struct ::GathSpec_t args = new_gathspec( t->trans() ); + args.nfld = nb_fields; + args.rspecg = global_spectra; + args.nto = destination; + args.rspec = spectra; + TRANS_CHECK(::trans_gathspec( &args ) ); } void atlas__Trans__distgrid( const TransIFS* t, int nb_fields, int origin[], double global_fields[], double fields[] ) { - ATLAS_ERROR_HANDLING( ASSERT( t ); struct ::DistGrid_t args = new_distgrid( t->trans() ); args.nfld = nb_fields; - args.nfrom = origin; args.rgpg = global_fields; args.rgp = fields; - TRANS_CHECK(::trans_distgrid( &args ) ); ); + ATLAS_ASSERT( t != nullptr ); + struct ::DistGrid_t args = new_distgrid( t->trans() ); + args.nfld = nb_fields; + args.nfrom = origin; + args.rgpg = global_fields; + args.rgp = fields; + TRANS_CHECK(::trans_distgrid( &args ) ); } void atlas__Trans__gathgrid( const TransIFS* t, int nb_fields, int destination[], double fields[], double global_fields[] ) { - ATLAS_ERROR_HANDLING( ASSERT( t ); struct ::GathGrid_t args = new_gathgrid( t->trans() ); args.nfld = nb_fields; - args.nto = destination; args.rgp = fields; args.rgpg = global_fields; - TRANS_CHECK(::trans_gathgrid( &args ) ); ); + ATLAS_ASSERT( t = nullptr ); + struct ::GathGrid_t args = new_gathgrid( t->trans() ); + args.nfld = nb_fields; + args.nto = destination; + args.rgp = fields; + args.rgpg = global_fields; + TRANS_CHECK(::trans_gathgrid( &args ) ); } void atlas__Trans__invtrans_scalar( const TransIFS* t, int nb_fields, double scalar_spectra[], double scalar_fields[] ) { - ATLAS_ERROR_HANDLING( ASSERT( t ); return t->invtrans( nb_fields, scalar_spectra, scalar_fields ); ); + ATLAS_ASSERT( t != nullptr ); + return t->invtrans( nb_fields, scalar_spectra, scalar_fields ); } void atlas__Trans__invtrans_vordiv2wind( const TransIFS* t, int nb_fields, double vorticity_spectra[], double divergence_spectra[], double wind_fields[] ) { - ATLAS_ERROR_HANDLING( ASSERT( t ); - return t->invtrans( nb_fields, vorticity_spectra, divergence_spectra, wind_fields ); ); + ATLAS_ASSERT( t != nullptr ); + return t->invtrans( nb_fields, vorticity_spectra, divergence_spectra, wind_fields ); } void atlas__Trans__dirtrans_scalar( const TransIFS* t, int nb_fields, double scalar_fields[], double scalar_spectra[] ) { - ATLAS_ERROR_HANDLING( ASSERT( t ); return t->dirtrans( nb_fields, scalar_fields, scalar_spectra ); ); + ATLAS_ASSERT( t != nullptr ); + return t->dirtrans( nb_fields, scalar_fields, scalar_spectra ); } void atlas__Trans__dirtrans_wind2vordiv( const TransIFS* t, int nb_fields, double wind_fields[], double vorticity_spectra[], double divergence_spectra[] ) { - ATLAS_ERROR_HANDLING( ASSERT( t ); - return t->dirtrans( nb_fields, wind_fields, vorticity_spectra, divergence_spectra ); ); + ATLAS_ASSERT( t != nullptr ); + return t->dirtrans( nb_fields, wind_fields, vorticity_spectra, divergence_spectra ); } void atlas__Trans__specnorm( const TransIFS* t, int nb_fields, double spectra[], double norms[], int rank ) { - ATLAS_ERROR_HANDLING( ASSERT( t ); return t->specnorm( nb_fields, spectra, norms, rank ); ); + ATLAS_ASSERT( t != nullptr ); + return t->specnorm( nb_fields, spectra, norms, rank ); } int atlas__Trans__nspec2( const TransIFS* This ) { - ATLAS_ERROR_HANDLING( ASSERT( This ); return This->trans()->nspec2; ); - return 0; + ATLAS_ASSERT( This != nullptr ); + return This->trans()->nspec2; } int atlas__Trans__nspec2g( const TransIFS* This ) { - ATLAS_ERROR_HANDLING( ASSERT( This ); return This->trans()->nspec2g; ); - return 0; + ATLAS_ASSERT( This != nullptr ); + return This->trans()->nspec2g; } int atlas__Trans__ngptot( const TransIFS* This ) { - ATLAS_ERROR_HANDLING( ASSERT( This ); return This->trans()->ngptot; ); - return 0; + ATLAS_ASSERT( This != nullptr ); + return This->trans()->ngptot; } int atlas__Trans__ngptotg( const TransIFS* This ) { - ATLAS_ERROR_HANDLING( ASSERT( This ); return This->trans()->ngptotg; ); - return 0; + ATLAS_ASSERT( This != nullptr ); + return This->trans()->ngptotg; } int atlas__Trans__truncation( const TransIFS* This ) { - ATLAS_ERROR_HANDLING( ASSERT( This ); return This->truncation(); ); - return 0; + ATLAS_ASSERT( This != nullptr ); + return This->truncation(); } const Grid::Implementation* atlas__Trans__grid( const TransIFS* This ) { - ATLAS_ERROR_HANDLING( ASSERT( This ); ASSERT( This->grid() ); - return This->grid().get(); ); - return nullptr; + ATLAS_ASSERT( This != nullptr ); + ATLAS_ASSERT( This->grid() ); + return This->grid().get(); } void atlas__Trans__dirtrans_fieldset( const TransIFS* This, const field::FieldSetImpl* gpfields, field::FieldSetImpl* spfields, const eckit::Configuration* parameters ) { - ATLAS_ERROR_HANDLING( ASSERT( This ); ASSERT( gpfields ); ASSERT( spfields ); ASSERT( parameters ); - FieldSet fspfields( spfields ); This->dirtrans( gpfields, fspfields, *parameters ); ); + ATLAS_ASSERT( This != nullptr ); + ATLAS_ASSERT( gpfields ); + ATLAS_ASSERT( spfields ); + ATLAS_ASSERT( parameters ); + FieldSet fspfields( spfields ); + This->dirtrans( gpfields, fspfields, *parameters ); } void atlas__Trans__dirtrans_field( const TransIFS* This, const field::FieldImpl* gpfield, field::FieldImpl* spfield, const eckit::Configuration* parameters ) { - ATLAS_ERROR_HANDLING( ASSERT( This ); ASSERT( spfield ); ASSERT( gpfield ); ASSERT( parameters ); - Field fspfield( spfield ); This->dirtrans( gpfield, fspfield, *parameters ); ); + ATLAS_ASSERT( This != nullptr ); + ATLAS_ASSERT( spfield ); + ATLAS_ASSERT( gpfield ); + ATLAS_ASSERT( parameters ); + Field fspfield( spfield ); + This->dirtrans( gpfield, fspfield, *parameters ); } void atlas__Trans__invtrans_fieldset( const TransIFS* This, const field::FieldSetImpl* spfields, field::FieldSetImpl* gpfields, const eckit::Configuration* parameters ) { - ATLAS_ERROR_HANDLING( ASSERT( This ); ASSERT( spfields ); ASSERT( gpfields ); ASSERT( parameters ); - FieldSet fgpfields( gpfields ); This->invtrans( spfields, fgpfields, *parameters ); ); + ATLAS_ASSERT( This != nullptr ); + ATLAS_ASSERT( spfields ); + ATLAS_ASSERT( gpfields ); + ATLAS_ASSERT( parameters ); + FieldSet fgpfields( gpfields ); + This->invtrans( spfields, fgpfields, *parameters ); } void atlas__Trans__invtrans_field( const TransIFS* This, const field::FieldImpl* spfield, field::FieldImpl* gpfield, const eckit::Configuration* parameters ) { - ATLAS_ERROR_HANDLING( ASSERT( This ); ASSERT( spfield ); ASSERT( gpfield ); ASSERT( parameters ); - Field fgpfield( gpfield ); This->invtrans( spfield, fgpfield, *parameters ); ); + ATLAS_ASSERT( This != nullptr ); + ATLAS_ASSERT( spfield ); + ATLAS_ASSERT( gpfield ); + ATLAS_ASSERT( parameters ); + Field fgpfield( gpfield ); + This->invtrans( spfield, fgpfield, *parameters ); } void atlas__Trans__dirtrans_wind2vordiv_field( const TransIFS* This, const field::FieldImpl* gpwind, field::FieldImpl* spvor, field::FieldImpl* spdiv, const eckit::Configuration* parameters ) { - ATLAS_ERROR_HANDLING( ASSERT( This ); ASSERT( gpwind ); ASSERT( spvor ); ASSERT( spdiv ); ASSERT( parameters ); - Field fspvor( spvor ); Field fspdiv( spdiv ); - This->dirtrans_wind2vordiv( gpwind, fspvor, fspdiv, *parameters ); ); + ATLAS_ASSERT( This != nullptr ); + ATLAS_ASSERT( gpwind ); + ATLAS_ASSERT( spvor ); + ATLAS_ASSERT( spdiv ); + ATLAS_ASSERT( parameters ); + Field fspvor( spvor ); + Field fspdiv( spdiv ); + This->dirtrans_wind2vordiv( gpwind, fspvor, fspdiv, *parameters ); } void atlas__Trans__invtrans_vordiv2wind_field( const TransIFS* This, const field::FieldImpl* spvor, const field::FieldImpl* spdiv, field::FieldImpl* gpwind, const eckit::Configuration* parameters ) { - ATLAS_ERROR_HANDLING( ASSERT( This ); ASSERT( spvor ); ASSERT( spdiv ); ASSERT( gpwind ); ASSERT( parameters ); - Field fgpwind( gpwind ); This->invtrans_vordiv2wind( spvor, spdiv, fgpwind, *parameters ); ); + ATLAS_ASSERT( This != nullptr ); + ATLAS_ASSERT( spvor ); + ATLAS_ASSERT( spdiv ); + ATLAS_ASSERT( gpwind ); + ATLAS_ASSERT( parameters ); + Field fgpwind( gpwind ); + This->invtrans_vordiv2wind( spvor, spdiv, fgpwind, *parameters ); } void atlas__Trans__invtrans( const TransIFS* This, int nb_scalar_fields, double scalar_spectra[], int nb_vordiv_fields, double vorticity_spectra[], double divergence_spectra[], double gp_fields[], const eckit::Configuration* parameters ) { - ATLAS_ERROR_HANDLING( ASSERT( This ); - This->invtrans( nb_scalar_fields, scalar_spectra, nb_vordiv_fields, vorticity_spectra, - divergence_spectra, gp_fields, *parameters ); ); + ATLAS_ASSERT( This != nullptr ); + This->invtrans( nb_scalar_fields, scalar_spectra, nb_vordiv_fields, vorticity_spectra, divergence_spectra, + gp_fields, *parameters ); } void atlas__Trans__invtrans_grad_field( const TransIFS* This, const field::FieldImpl* spfield, field::FieldImpl* gpfield, const eckit::Configuration* config ) { - ATLAS_ERROR_HANDLING( ASSERT( This ); ASSERT( spfield ); ASSERT( gpfield ); Field fgpfield( gpfield ); - This->invtrans_grad( spfield, fgpfield, *config ); ); + ATLAS_ASSERT( This != nullptr ); + ATLAS_ASSERT( spfield ); + ATLAS_ASSERT( gpfield ); + Field fgpfield( gpfield ); + This->invtrans_grad( spfield, fgpfield, *config ); } } diff --git a/src/atlas/trans/ifs/TransIFS.h b/src/atlas/trans/ifs/TransIFS.h index 1ae224e2e..85645c042 100644 --- a/src/atlas/trans/ifs/TransIFS.h +++ b/src/atlas/trans/ifs/TransIFS.h @@ -16,7 +16,9 @@ #include "atlas/array/LocalView.h" #include "atlas/grid/Grid.h" -#include "atlas/trans/Trans.h" +#include "atlas/grid/StructuredGrid.h" +#include "atlas/runtime/Exception.h" +#include "atlas/trans/detail/TransImpl.h" //----------------------------------------------------------------------------- // Forward declarations @@ -63,6 +65,7 @@ class TransPartitioner; } // namespace grid } // namespace atlas + //----------------------------------------------------------------------------- namespace atlas { @@ -81,7 +84,7 @@ class TransIFS : public trans::TransImpl { TransIFS( const Cache&, const Grid&, const Domain&, const long truncation, const eckit::Configuration& = util::NoConfig() ); - virtual ~TransIFS(); + virtual ~TransIFS() override; operator ::Trans_t*() const { return trans(); } ::Trans_t* trans() const { return trans_.get(); } @@ -212,7 +215,7 @@ class TransIFS : public trans::TransImpl { private: void ctor( const Grid&, long nsmax, const eckit::Configuration& ); - void ctor_rgg( const long nlat, const long pl[], long nsmax, const eckit::Configuration& ); + void ctor_rgg( const long nlat, const idx_t pl[], long nsmax, const eckit::Configuration& ); void ctor_lonlat( const long nlon, const long nlat, long nsmax, const eckit::Configuration& ); @@ -243,68 +246,68 @@ class TransIFS : public trans::TransImpl { const int* nloen( int& size ) const { size = trans_->ndgl; - ASSERT( trans_->nloen != NULL ); + ATLAS_ASSERT( trans_->nloen != nullptr ); return trans_->nloen; } array::LocalView nloen() const { - ASSERT( trans_->nloen != NULL ); + ATLAS_ASSERT( trans_->nloen != nullptr ); return array::LocalView( trans_->nloen, array::make_shape( trans_->ndgl ) ); } const int* n_regions( int& size ) const { size = trans_->n_regions_NS; - ASSERT( trans_->n_regions != NULL ); + ATLAS_ASSERT( trans_->n_regions != nullptr ); return trans_->n_regions; } array::LocalView n_regions() const { - ASSERT( trans_->n_regions != NULL ); + ATLAS_ASSERT( trans_->n_regions != nullptr ); return array::LocalView( trans_->n_regions, array::make_shape( trans_->n_regions_NS ) ); } const int* nfrstlat( int& size ) const { size = trans_->n_regions_NS; - if ( trans_->nfrstlat == NULL ) ::trans_inquire( trans_.get(), "nfrstlat" ); + if ( trans_->nfrstlat == nullptr ) ::trans_inquire( trans_.get(), "nfrstlat" ); return trans_->nfrstlat; } array::LocalView nfrstlat() const { - if ( trans_->nfrstlat == NULL ) ::trans_inquire( trans_.get(), "nfrstlat" ); + if ( trans_->nfrstlat == nullptr ) ::trans_inquire( trans_.get(), "nfrstlat" ); return array::LocalView( trans_->nfrstlat, array::make_shape( trans_->n_regions_NS ) ); } const int* nlstlat( int& size ) const { size = trans_->n_regions_NS; - if ( trans_->nlstlat == NULL ) ::trans_inquire( trans_.get(), "nlstlat" ); + if ( trans_->nlstlat == nullptr ) ::trans_inquire( trans_.get(), "nlstlat" ); return trans_->nlstlat; } array::LocalView nlstlat() const { - if ( trans_->nlstlat == NULL ) ::trans_inquire( trans_.get(), "nlstlat" ); + if ( trans_->nlstlat == nullptr ) ::trans_inquire( trans_.get(), "nlstlat" ); return array::LocalView( trans_->nlstlat, array::make_shape( trans_->n_regions_NS ) ); } const int* nptrfrstlat( int& size ) const { size = trans_->n_regions_NS; - if ( trans_->nptrfrstlat == NULL ) ::trans_inquire( trans_.get(), "nptrfrstlat" ); + if ( trans_->nptrfrstlat == nullptr ) ::trans_inquire( trans_.get(), "nptrfrstlat" ); return trans_->nptrfrstlat; } array::LocalView nptrfrstlat() const { - if ( trans_->nptrfrstlat == NULL ) ::trans_inquire( trans_.get(), "nptrfrstlat" ); + if ( trans_->nptrfrstlat == nullptr ) ::trans_inquire( trans_.get(), "nptrfrstlat" ); return array::LocalView( trans_->nptrfrstlat, array::make_shape( trans_->n_regions_NS ) ); } const int* nsta( int& sizef2, int& sizef1 ) const { sizef1 = trans_->ndgl + trans_->n_regions_NS - 1; sizef2 = trans_->n_regions_EW; - if ( trans_->nsta == NULL ) ::trans_inquire( trans_.get(), "nsta" ); + if ( trans_->nsta == nullptr ) ::trans_inquire( trans_.get(), "nsta" ); return trans_->nsta; } array::LocalView nsta() const { - if ( trans_->nsta == NULL ) ::trans_inquire( trans_.get(), "nsta" ); + if ( trans_->nsta == nullptr ) ::trans_inquire( trans_.get(), "nsta" ); return array::LocalView( trans_->nsta, array::make_shape( trans_->n_regions_EW, trans_->ndgl + trans_->n_regions_NS - 1 ) ); } @@ -312,46 +315,46 @@ class TransIFS : public trans::TransImpl { const int* nonl( int& sizef2, int& sizef1 ) const { sizef1 = trans_->ndgl + trans_->n_regions_NS - 1; sizef2 = trans_->n_regions_EW; - if ( trans_->nonl == NULL ) ::trans_inquire( trans_.get(), "nonl" ); + if ( trans_->nonl == nullptr ) ::trans_inquire( trans_.get(), "nonl" ); return trans_->nonl; } array::LocalView nonl() const { - if ( trans_->nonl == NULL ) ::trans_inquire( trans_.get(), "nonl" ); + if ( trans_->nonl == nullptr ) ::trans_inquire( trans_.get(), "nonl" ); return array::LocalView( trans_->nonl, array::make_shape( trans_->n_regions_EW, trans_->ndgl + trans_->n_regions_NS - 1 ) ); } const int* nmyms( int& size ) const { size = trans_->nump; - if ( trans_->nmyms == NULL ) ::trans_inquire( trans_.get(), "nmyms" ); + if ( trans_->nmyms == nullptr ) ::trans_inquire( trans_.get(), "nmyms" ); return trans_->nmyms; } array::LocalView nmyms() const { - if ( trans_->nmyms == NULL ) ::trans_inquire( trans_.get(), "nmyms" ); + if ( trans_->nmyms == nullptr ) ::trans_inquire( trans_.get(), "nmyms" ); return array::LocalView( trans_->nmyms, array::make_shape( trans_->nump ) ); } const int* nasm0( int& size ) const { size = trans_->nsmax + 1; // +1 because zeroth wave included - if ( trans_->nasm0 == NULL ) ::trans_inquire( trans_.get(), "nasm0" ); + if ( trans_->nasm0 == nullptr ) ::trans_inquire( trans_.get(), "nasm0" ); return trans_->nasm0; } array::LocalView nasm0() const { - if ( trans_->nasm0 == NULL ) ::trans_inquire( trans_.get(), "nasm0" ); + if ( trans_->nasm0 == nullptr ) ::trans_inquire( trans_.get(), "nasm0" ); return array::LocalView( trans_->nasm0, array::make_shape( trans_->nsmax + 1 ) ); } const int* nvalue( int& size ) const { size = trans_->nspec2; - if ( trans_->nvalue == NULL ) ::trans_inquire( trans_.get(), "nvalue" ); + if ( trans_->nvalue == nullptr ) ::trans_inquire( trans_.get(), "nvalue" ); return trans_->nvalue; } array::LocalView nvalue() const { - if ( trans_->nvalue == NULL ) ::trans_inquire( trans_.get(), "nvalue" ); + if ( trans_->nvalue == nullptr ) ::trans_inquire( trans_.get(), "nvalue" ); return array::LocalView( trans_->nvalue, array::make_shape( trans_->nspec2 ) ); } @@ -396,7 +399,7 @@ class TransIFS : public trans::TransImpl { private: friend class functionspace::detail::Spectral; mutable std::shared_ptr<::Trans_t> trans_; - grid::StructuredGrid grid_; + StructuredGrid grid_; const void* cache_{nullptr}; size_t cachesize_{0}; }; diff --git a/src/atlas/trans/ifs/TransIFSNodeColumns.cc b/src/atlas/trans/ifs/TransIFSNodeColumns.cc index 28a00dfdf..2c8ef92ae 100644 --- a/src/atlas/trans/ifs/TransIFSNodeColumns.cc +++ b/src/atlas/trans/ifs/TransIFSNodeColumns.cc @@ -11,6 +11,7 @@ #include "atlas/trans/ifs/TransIFSNodeColumns.h" #include "atlas/functionspace/NodeColumns.h" #include "atlas/functionspace/Spectral.h" +#include "atlas/trans/detail/TransFactory.h" namespace atlas { namespace trans { diff --git a/src/atlas/trans/ifs/TransIFSStructuredColumns.cc b/src/atlas/trans/ifs/TransIFSStructuredColumns.cc index 6725b8cce..af999a777 100644 --- a/src/atlas/trans/ifs/TransIFSStructuredColumns.cc +++ b/src/atlas/trans/ifs/TransIFSStructuredColumns.cc @@ -11,6 +11,7 @@ #include "atlas/trans/ifs/TransIFSStructuredColumns.h" #include "atlas/functionspace/Spectral.h" #include "atlas/functionspace/StructuredColumns.h" +#include "atlas/trans/detail/TransFactory.h" namespace atlas { namespace trans { diff --git a/src/atlas/trans/ifs/VorDivToUVIFS.cc b/src/atlas/trans/ifs/VorDivToUVIFS.cc index 75e052afd..5bbd544c2 100644 --- a/src/atlas/trans/ifs/VorDivToUVIFS.cc +++ b/src/atlas/trans/ifs/VorDivToUVIFS.cc @@ -11,6 +11,7 @@ #include "atlas/trans/ifs/VorDivToUVIFS.h" #include "atlas/functionspace/Spectral.h" #include "atlas/parallel/mpi/mpi.h" +#include "atlas/runtime/Exception.h" #include "atlas/runtime/Log.h" using atlas::FunctionSpace; @@ -29,7 +30,7 @@ void trans_check( const int code, const char* msg, const eckit::CodeLocation& lo std::stringstream errmsg; errmsg << "atlas::trans ERROR: " << msg << " failed: \n"; errmsg << ::trans_error_msg( code ); - throw eckit::Exception( errmsg.str(), location ); + throw_Exception( errmsg.str(), location ); } } #define TRANS_CHECK( CALL ) trans_check( CALL, #CALL, Here() ) @@ -37,8 +38,7 @@ void trans_check( const int code, const char* msg, const eckit::CodeLocation& lo } // namespace void VorDivToUVIFS::execute( const int nb_coeff, const int nb_fields, const double vorticity[], - const double divergence[], double U[], double V[], - const eckit::Configuration& config ) const { + const double divergence[], double U[], double V[], const eckit::Configuration& ) const { struct ::VorDivToUV_t vordiv_to_UV = new_vordiv_to_UV(); vordiv_to_UV.rspvor = vorticity; vordiv_to_UV.rspdiv = divergence; @@ -50,9 +50,9 @@ void VorDivToUVIFS::execute( const int nb_coeff, const int nb_fields, const doub TRANS_CHECK(::trans_vordiv_to_UV( &vordiv_to_UV ) ); } -VorDivToUVIFS::VorDivToUVIFS( const int truncation, const eckit::Configuration& config ) : truncation_( truncation ) {} +VorDivToUVIFS::VorDivToUVIFS( const int truncation, const eckit::Configuration& ) : truncation_( truncation ) {} -VorDivToUVIFS::VorDivToUVIFS( const FunctionSpace& fs, const eckit::Configuration& config ) : +VorDivToUVIFS::VorDivToUVIFS( const FunctionSpace& fs, const eckit::Configuration& ) : truncation_( Spectral( fs ).truncation() ) {} VorDivToUVIFS::~VorDivToUVIFS() {} diff --git a/src/atlas/trans/local/LegendreCacheCreatorLocal.cc b/src/atlas/trans/local/LegendreCacheCreatorLocal.cc index 54e58060c..6e7231a83 100644 --- a/src/atlas/trans/local/LegendreCacheCreatorLocal.cc +++ b/src/atlas/trans/local/LegendreCacheCreatorLocal.cc @@ -9,14 +9,18 @@ */ #include "atlas/trans/local/LegendreCacheCreatorLocal.h" + #include #include + +#include "eckit/types/FloatCompare.h" +#include "eckit/utils/MD5.h" + #include "atlas/grid.h" #include "atlas/option.h" +#include "atlas/runtime/Exception.h" #include "atlas/trans/Trans.h" #include "atlas/trans/local/TransLocal.h" -#include "eckit/types/FloatCompare.h" -#include "eckit/utils/MD5.h" namespace atlas { namespace trans { @@ -34,8 +38,8 @@ std::string truncate( const std::string& str ) { std::string hash( const Grid& grid ) { eckit::MD5 h; - if ( grid::StructuredGrid( grid ) && not grid.projection() ) { - auto g = grid::StructuredGrid( grid ); + if ( StructuredGrid( grid ) && not grid.projection() ) { + auto g = StructuredGrid( grid ); h.add( g.y().data(), g.y().size() * sizeof( double ) ); } else { @@ -63,14 +67,14 @@ std::string LegendreCacheCreatorLocal::uid() const { stream << "grid-" << hash( grid_ ); }; stream << "local-T" << truncation_ << "-"; - grid::StructuredGrid structured( grid_ ); - if ( grid::GaussianGrid( grid_ ) ) { + StructuredGrid structured( grid_ ); + if ( GaussianGrid( grid_ ) ) { // Same cache for any global Gaussian grid - stream << "GaussianN" << grid::GaussianGrid( grid_ ).N(); + stream << "GaussianN" << GaussianGrid( grid_ ).N(); } - else if ( grid::RegularLonLatGrid( grid_ ) ) { + else if ( RegularLonLatGrid( grid_ ) ) { // Same cache for any global regular grid - auto g = grid::RegularLonLatGrid( grid_ ); + auto g = RegularLonLatGrid( grid_ ); const double dy_2 = 90. / double( g.ny() ); bool shifted_lat = eckit::types::is_approximately_equal( g.y().front(), 90. - dy_2 ) && @@ -90,9 +94,9 @@ std::string LegendreCacheCreatorLocal::uid() const { give_up(); } } - else if ( grid::RegularGrid( grid_ ) && not grid_.projection() && structured.yspace().type() == "linear" ) { + else if ( RegularGrid( grid_ ) && not grid_.projection() && structured.yspace().type() == "linear" ) { RectangularDomain domain( grid_.domain() ); - ASSERT( domain ); + ATLAS_ASSERT( domain ); stream << "Regional"; stream << "-south" << domain.ymin(); stream << "-north" << domain.ymax(); @@ -116,7 +120,7 @@ LegendreCacheCreatorLocal::LegendreCacheCreatorLocal( const Grid& grid, int trun config_( config ) {} bool LegendreCacheCreatorLocal::supported() const { - if ( not grid::StructuredGrid( grid_ ) ) return false; + if ( not StructuredGrid( grid_ ) ) return false; if ( grid_.projection() ) return false; return true; } diff --git a/src/atlas/trans/local/LegendreCacheCreatorLocal.h b/src/atlas/trans/local/LegendreCacheCreatorLocal.h index ff3d14752..e3d56af91 100644 --- a/src/atlas/trans/local/LegendreCacheCreatorLocal.h +++ b/src/atlas/trans/local/LegendreCacheCreatorLocal.h @@ -25,7 +25,7 @@ class LegendreCacheCreatorLocal : public trans::LegendreCacheCreatorImpl { public: LegendreCacheCreatorLocal( const Grid&, int truncation, const eckit::Configuration& = util::NoConfig() ); - virtual ~LegendreCacheCreatorLocal(); + virtual ~LegendreCacheCreatorLocal() override; virtual bool supported() const override; diff --git a/src/atlas/trans/local/LegendrePolynomials.cc b/src/atlas/trans/local/LegendrePolynomials.cc index 38084bdd5..ac6a523c4 100644 --- a/src/atlas/trans/local/LegendrePolynomials.cc +++ b/src/atlas/trans/local/LegendrePolynomials.cc @@ -21,7 +21,7 @@ namespace trans { //----------------------------------------------------------------------------- -void compute_zfn( const size_t trc, double zfn[] ) { +void compute_zfn( const int trc, double zfn[] ) { auto idxzfn = [&]( int jn, int jk ) { return jk + ( trc + 1 ) * jn; }; int iodd = 0; // Compute coefficients for Taylor series in Belousov (19) and (21) @@ -45,7 +45,7 @@ void compute_zfn( const size_t trc, double zfn[] ) { } -void compute_legendre_polynomials_lat( const size_t trc, // truncation (in) +void compute_legendre_polynomials_lat( const int trc, // truncation (in) const double lat, // latitude in radians (in) double legpol[], // legendre polynomials double zfn[] ) { @@ -150,7 +150,7 @@ void compute_legendre_polynomials_lat( const size_t trc, // truncation (in) void compute_legendre_polynomials( - const size_t trc, // truncation (in) + const int truncation, // truncation (in) const int nlats, // number of latitudes const double lats[], // latitudes in radians (in) double leg_sym[], // values of associated Legendre functions, symmetric part @@ -158,30 +158,29 @@ void compute_legendre_polynomials( size_t leg_start_sym[], // start indices for different zonal wave numbers, symmetric part size_t leg_start_asym[] ) // start indices for different zonal wave numbers, asymmetric part { - auto legendre_size = [&]( int truncation ) { return ( truncation + 2 ) * ( truncation + 1 ) / 2; }; - std::vector legpol( legendre_size( trc ) ); + size_t trc = static_cast( truncation ); + size_t legendre_size = ( trc + 2 ) * ( trc + 1 ) / 2; + std::vector legpol( legendre_size ); std::vector zfn( ( trc + 1 ) * ( trc + 1 ) ); - auto idxmn = [&]( int jm, int jn ) { return ( 2 * trc + 3 - jm ) * jm / 2 + jn - jm; }; - compute_zfn( trc, zfn.data() ); + auto idxmn = [&]( size_t jm, size_t jn ) { return ( 2 * trc + 3 - jm ) * jm / 2 + jn - jm; }; + compute_zfn( truncation, zfn.data() ); // Loop over latitudes: - for ( int jlat = 0; jlat < nlats; ++jlat ) { + for ( size_t jlat = 0; jlat < size_t( nlats ); ++jlat ) { // compute legendre polynomials for current latitude: - compute_legendre_polynomials_lat( trc, lats[jlat], legpol.data(), zfn.data() ); + compute_legendre_polynomials_lat( truncation, lats[jlat], legpol.data(), zfn.data() ); // split polynomials into symmetric and antisymmetric parts: { //ATLAS_TRACE( "add to global arrays" ); - for ( int jm = 0; jm <= trc; jm++ ) { - int is1 = 0, ia1 = 0; - for ( int jn = jm; jn <= trc; jn++ ) { - if ( ( jn - jm ) % 2 == 0 ) { is1++; } - else { - ia1++; - } + for ( size_t jm = 0; jm <= trc; jm++ ) { + size_t is1 = 0, ia1 = 0; + for ( size_t jn = jm; jn <= trc; jn++ ) { + ( jn - jm ) % 2 ? ia1++ : is1++; } - int is2 = 0, ia2 = 0; + + size_t is2 = 0, ia2 = 0; // the choice between the following two code lines determines whether // total wavenumbers are summed in an ascending or descending order. // The trans library in IFS uses descending order because it should @@ -189,13 +188,14 @@ void compute_legendre_polynomials( // This also needs to be changed when splitting the spectral data in // TransLocal::invtrans_uv! //for ( int jn = jm; jn <= trc; jn++ ) { - for ( int jn = trc; jn >= jm; jn-- ) { + for ( long ljn = long( trc ), ljm = long( jm ); ljn >= ljm; ljn-- ) { + size_t jn = size_t( ljn ); if ( ( jn - jm ) % 2 == 0 ) { - int is = leg_start_sym[jm] + is1 * jlat + is2++; + size_t is = leg_start_sym[jm] + is1 * jlat + is2++; leg_sym[is] = legpol[idxmn( jm, jn )]; } else { - int ia = leg_start_asym[jm] + ia1 * jlat + ia2++; + size_t ia = leg_start_asym[jm] + ia1 * jlat + ia2++; leg_asym[ia] = legpol[idxmn( jm, jn )]; } } @@ -204,27 +204,29 @@ void compute_legendre_polynomials( } } -void compute_legendre_polynomials_all( const size_t trc, // truncation (in) - const int nlats, // number of latitudes - const double lats[], // latitudes in radians (in) - double legendre[] ) // legendre polynomials for all latitudes +void compute_legendre_polynomials_all( const int truncation, // truncation (in) + const int nlats, // number of latitudes + const double lats[], // latitudes in radians (in) + double legendre[] ) // legendre polynomials for all latitudes { - auto legendre_size = [&]( int truncation ) { return ( truncation + 2 ) * ( truncation + 1 ) / 2; }; - std::vector legpol( legendre_size( trc ) ); + size_t trc = static_cast( truncation ); + size_t legendre_size = ( trc + 2 ) * ( trc + 1 ) / 2; + size_t ny = nlats; + std::vector legpol( legendre_size ); std::vector zfn( ( trc + 1 ) * ( trc + 1 ) ); - auto idxmn = [&]( int jm, int jn ) { return ( 2 * trc + 3 - jm ) * jm / 2 + jn - jm; }; - auto idxmnl = [&]( int jm, int jn, int jlat ) { - return ( 2 * trc + 3 - jm ) * jm / 2 * nlats + jlat * ( trc - jm + 1 ) + jn - jm; + auto idxmn = [&]( size_t jm, size_t jn ) { return ( 2 * trc + 3 - jm ) * jm / 2 + jn - jm; }; + auto idxmnl = [&]( size_t jm, size_t jn, size_t jlat ) { + return ( 2 * trc + 3 - jm ) * jm / 2 * ny + jlat * ( trc - jm + 1 ) + jn - jm; }; - compute_zfn( trc, zfn.data() ); + compute_zfn( truncation, zfn.data() ); // Loop over latitudes: - for ( int jlat = 0; jlat < nlats; ++jlat ) { + for ( size_t jlat = 0; jlat < ny; ++jlat ) { // compute legendre polynomials for current latitude: - compute_legendre_polynomials_lat( trc, lats[jlat], legpol.data(), zfn.data() ); + compute_legendre_polynomials_lat( truncation, lats[jlat], legpol.data(), zfn.data() ); - for ( int jm = 0; jm <= trc; ++jm ) { - for ( int jn = jm; jn <= trc; ++jn ) { + for ( size_t jm = 0; jm <= trc; ++jm ) { + for ( size_t jn = jm; jn <= trc; ++jn ) { legendre[idxmnl( jm, jn, jlat )] = legpol[idxmn( jm, jn )]; } } diff --git a/src/atlas/trans/local/LegendrePolynomials.h b/src/atlas/trans/local/LegendrePolynomials.h index 43edbb221..e89885bb3 100644 --- a/src/atlas/trans/local/LegendrePolynomials.h +++ b/src/atlas/trans/local/LegendrePolynomials.h @@ -32,15 +32,15 @@ namespace trans { // Ported to C++ by: // Andreas Mueller *ECMWF* // -void compute_zfn( const size_t trc, double zfn[] ); +void compute_zfn( const int trc, double zfn[] ); -void compute_legendre_polynomials_lat( const size_t trc, // truncation (in) +void compute_legendre_polynomials_lat( const int trc, // truncation (in) const double lat, // latitude in radians (in) double legpol[], // legendre polynomials double zfn[] ); void compute_legendre_polynomials( - const size_t trc, // truncation (in) + const int trc, // truncation (in) const int nlats, // number of latitudes const double lats[], // latitudes in radians (in) double legendre_sym[], // values of associated Legendre functions, symmetric part @@ -48,7 +48,7 @@ void compute_legendre_polynomials( size_t leg_start_sym[], // start indices for different zonal wave numbers, symmetric part size_t leg_start_asym[] ); // start indices for different zonal wave numbers, asymmetric part -void compute_legendre_polynomials_all( const size_t trc, // truncation (in) +void compute_legendre_polynomials_all( const int trc, // truncation (in) const int nlats, // number of latitudes const double lats[], // latitudes in radians (in) double legendre[] ); // legendre polynomials for all latitudes diff --git a/src/atlas/trans/local/TransLocal.cc b/src/atlas/trans/local/TransLocal.cc index 962e10db4..b1f628491 100644 --- a/src/atlas/trans/local/TransLocal.cc +++ b/src/atlas/trans/local/TransLocal.cc @@ -9,23 +9,31 @@ */ #include "atlas/trans/local/TransLocal.h" + #include #include +#include + +#include "eckit/config/YAMLConfiguration.h" +#include "eckit/eckit.h" +#include "eckit/io/DataHandle.h" +#include "eckit/linalg/LinearAlgebra.h" +#include "eckit/linalg/Matrix.h" +#include "eckit/log/Bytes.h" +#include "eckit/parser/JSON.h" +#include "eckit/types/FloatCompare.h" + #include "atlas/array.h" +#include "atlas/grid/Iterator.h" +#include "atlas/grid/StructuredGrid.h" #include "atlas/option.h" #include "atlas/parallel/mpi/mpi.h" -#include "atlas/runtime/ErrorHandling.h" +#include "atlas/runtime/Exception.h" #include "atlas/runtime/Log.h" #include "atlas/trans/VorDivToUV.h" +#include "atlas/trans/detail/TransFactory.h" #include "atlas/trans/local/LegendrePolynomials.h" #include "atlas/util/Constants.h" -#include "eckit/config/YAMLConfiguration.h" -#include "eckit/eckit_config.h" -#include "eckit/linalg/LinearAlgebra.h" -#include "eckit/linalg/Matrix.h" -#include "eckit/log/Bytes.h" -#include "eckit/parser/JSON.h" -#include "eckit/types/FloatCompare.h" #include "atlas/library/defines.h" #if ATLAS_HAVE_FFTW @@ -34,7 +42,7 @@ // move latitudes at the poles to the following latitude: // (otherwise we would divide by zero when computing u,v from U,V) -double latPole = 89.9999999; +static constexpr double latPole = 89.9999999; // (latPole=89.9999999 seems to produce the best accuracy. Moving it further away // or closer to the pole both increase the errors!) @@ -73,11 +81,11 @@ class TransParameters { bool export_legendre() const { return config_.getBool( "export_legendre", false ); } - int warning() const { return config_.getLong( "warning", 1 ); } + int warning() const { return config_.getInt( "warning", 1 ); } int fft() const { - static const std::map string_to_FFT = {{"OFF", (int)option::FFT::OFF}, - {"FFTW", (int)option::FFT::FFTW}}; + static const std::map string_to_FFT = {{"OFF", static_cast( option::FFT::OFF )}, + {"FFTW", static_cast( option::FFT::FFTW )}}; #ifdef ATLAS_HAVE_FFTW std::string fft_default = "FFTW"; #else @@ -92,17 +100,17 @@ class TransParameters { struct ReadCache { ReadCache( const void* cache ) { - begin = (char*)cache; + begin = reinterpret_cast( cache ); pos = 0; } template T* read( size_t size ) { - T* v = (T*)( begin + pos ); + const T* v = reinterpret_cast( begin + pos ); pos += size * sizeof( T ); - return v; + return const_cast( v ); } - char* begin; + const char* begin; size_t pos; }; @@ -111,7 +119,7 @@ struct WriteCache { if ( file_path.exists() ) { std::stringstream err; err << "Cannot open cache file " << file_path << " for writing as it already exists. Remove first."; - throw eckit::BadParameter( err.str(), Here() ); + throw_Exception( err.str(), Here() ); } dh_->openForWrite( 0 ); pos = 0; @@ -144,18 +152,6 @@ struct WriteCache { size_t pos; }; -#if ATLAS_HAVE_FFTW -struct FFTW_Wisdom { - char* wisdom; - FFTW_Wisdom() { wisdom = fftw_export_wisdom_to_string(); } - ~FFTW_Wisdom() { free( wisdom ); } -}; -//std::ostream& operator<<( std::ostream& out, const FFTW_Wisdom& w ) { -// out << w.wisdom; -// return out; -//} -#endif - } // namespace // -------------------------------------------------------------------------------------------------------------------- @@ -172,36 +168,25 @@ size_t legendre_size( const size_t truncation ) { // // using ceil here should make it possible to have odd number of latitudes (with the centre latitude being the equator) //} -int num_n( const int truncation, const int m, const bool symmetric ) { - int len = 0; - if ( symmetric ) { len = ( truncation - m + 2 ) / 2; } - else { - len = ( truncation - m + 1 ) / 2; - } - return len; +size_t num_n( const int truncation, const int m, const bool symmetric ) { + int len = ( truncation - m + ( symmetric ? 2 : 1 ) ) / 2; + ATLAS_ASSERT( len >= 0 ); + return size_t( len ); } -class AllocationFailed : public eckit::Exception { -public: - AllocationFailed( size_t bytes, const eckit::CodeLocation& ); - -private: - static std::string error_message( size_t bytes ) { - std::stringstream ss; - ss << "AllocationFailed: Could not allocate " << eckit::Bytes( bytes ); - return ss.str(); - } -}; -AllocationFailed::AllocationFailed( size_t bytes, const eckit::CodeLocation& loc ) : - Exception( error_message( bytes ), loc ) {} +[[noreturn]] void throw_AllocationFailed( size_t bytes, const eckit::CodeLocation& loc ) { + std::stringstream ss; + ss << "AllocationFailed: Could not allocate " << eckit::Bytes( bytes ); + throw_Exception( ss.str(), loc ); +} void alloc_aligned( double*& ptr, size_t n ) { const size_t alignment = 64 * sizeof( double ); size_t bytes = sizeof( double ) * n; int err = posix_memalign( (void**)&ptr, alignment, bytes ); - if ( err ) { throw AllocationFailed( bytes, Here() ); } + if ( err ) { throw_AllocationFailed( bytes, Here() ); } } void free_aligned( double*& ptr ) { @@ -209,15 +194,27 @@ void free_aligned( double*& ptr ) { ptr = nullptr; } -int add_padding( int n ) { - return std::ceil( n / 8. ) * 8; +void alloc_aligned( double*& ptr, size_t n, const char* msg ) { + ATLAS_ASSERT( msg ); + Log::debug() << "TransLocal: allocating '" << msg << "': " << eckit::Bytes( sizeof( double ) * n ) << std::endl; + alloc_aligned( ptr, n ); +} + +void free_aligned( double*& ptr, const char* msg ) { + ATLAS_ASSERT( msg ); + Log::debug() << "TransLocal: dellocating '" << msg << "'" << std::endl; + free_aligned( ptr ); +} + +size_t add_padding( size_t n ) { + return size_t( std::ceil( n / 8. ) ) * 8; } } // namespace int fourier_truncation( const int truncation, // truncation const int nx, // number of longitudes - const int nxmax, // maximum nx + const int /*nxmax*/, // maximum nx const int ndgl, // number of latitudes const double lat, // latitude in radian const bool fullgrid ) { // regular grid @@ -233,13 +230,13 @@ int fourier_truncation( const int truncation, // truncation double weight = 3 * ( trclin - truncation ) / ndgl; double sqcos = std::pow( std::cos( lat ), 2 ); - trc = ( nx - 1 ) / ( 2 + weight * sqcos ); + trc = static_cast( ( nx - 1 ) / ( 2 + weight * sqcos ) ); } else { // cubic double sqcos = std::pow( std::cos( lat ), 2 ); - trc = ( nx - 1 ) / ( 2 + sqcos ) - 1; + trc = static_cast( ( nx - 1 ) / ( 2 + sqcos ) - 1 ); } trc = std::min( truncation, trc ); return trc; @@ -277,7 +274,7 @@ bool TransLocal::warning( const eckit::Configuration& config ) const { TransLocal::TransLocal( const Cache& cache, const Grid& grid, const Domain& domain, const long truncation, const eckit::Configuration& config ) : grid_( grid, domain ), - truncation_( truncation ), + truncation_( static_cast( truncation ) ), precompute_( config.getBool( "precompute", true ) ), cache_( cache ), legendre_cache_( cache.legendre().data() ), @@ -304,13 +301,13 @@ TransLocal::TransLocal( const Cache& cache, const Grid& grid, const Domain& doma nlatsLegReduced_ = 0; bool useGlobalLeg = true; bool no_nest = false; - if ( grid::StructuredGrid( grid_ ) && not grid_.projection() ) { - grid::StructuredGrid g( grid_ ); + if ( StructuredGrid( grid_ ) && not grid_.projection() ) { + StructuredGrid g( grid_ ); nlats = g.ny(); nlonsMax = g.nxmax(); // check location of domain relative to the equator: - for ( size_t j = 0; j < nlats; ++j ) { + for ( idx_t j = 0; j < nlats; ++j ) { // assumptions: latitudes in g.y(j) are monotone and decreasing // no assumption on whether we have 0, 1 or 2 latitudes at the equator double lat = g.y( j ); @@ -327,7 +324,7 @@ TransLocal::TransLocal( const Cache& cache, const Grid& grid, const Domain& doma gridGlobal_ = grid; if ( not gridGlobal_.domain().global() ) { - if ( grid::RegularGrid( grid_ ) ) { + if ( RegularGrid( grid_ ) ) { // non-nested regular grid no_nest = true; no_symmetry_ = true; @@ -339,15 +336,15 @@ TransLocal::TransLocal( const Cache& cache, const Grid& grid, const Domain& doma useGlobalLeg = false; } else { - NOTIMP; + ATLAS_NOTIMPLEMENTED; // non-nested reduced grids are not supported } } - grid::StructuredGrid gs_global( gridGlobal_ ); - ASSERT( gs_global ); // assert structured grid - grid::StructuredGrid gsLeg = ( useGlobalLeg ? gs_global : g ); - nlonsMaxGlobal_ = gs_global.nxmax(); + StructuredGrid gs_global( gridGlobal_ ); + ATLAS_ASSERT( gs_global ); // assert structured grid + StructuredGrid gsLeg = ( useGlobalLeg ? gs_global : g ); + nlonsMaxGlobal_ = gs_global.nxmax(); jlonMin_.resize( 1 ); jlonMin_[0] = 0; jlatMin_ = 0; @@ -388,7 +385,7 @@ TransLocal::TransLocal( const Cache& cache, const Grid& grid, const Domain& doma for ( int jlat = 0; jlat < nlatsGlobal_ / 2; jlat++ ) { double lat = gs_global.y( jlat ) * util::Constants::degreesToRadians(); int nmen = fourier_truncation( truncation_, gs_global.nx( jlat ), gs_global.nxmax(), nlatsGlobal_, lat, - grid::RegularGrid( gs_global ) ); + RegularGrid( gs_global ) ); nmen = std::max( nmen0, nmen ); int ndgluj = nlatsLeg_ - std::min( nlatsLeg_, nlatsLeg_ + jlatMinLeg_ - jlat ); if ( useGlobalLeg ) { ndgluj = std::max( jlatMinLeg_, jlat ); } @@ -416,19 +413,19 @@ TransLocal::TransLocal( const Cache& cache, const Grid& grid, const Domain& doma if ( nlonsMax < fft_threshold * nlonsMaxGlobal_ ) { useFFT_ = false; } else { // need to use FFT with cropped grid - if ( grid::RegularGrid( gridGlobal_ ) ) { - for ( size_t jlon = 0; jlon < nlonsMaxGlobal_; ++jlon ) { + if ( RegularGrid( gridGlobal_ ) ) { + for ( idx_t jlon = 0; jlon < nlonsMaxGlobal_; ++jlon ) { if ( gs_global.x( jlon, 0 ) < lonmin ) { jlonMin_[0]++; } } } else { nlonsGlobal_.resize( nlats ); jlonMin_.resize( nlats ); - for ( size_t jlat = 0; jlat < nlats; jlat++ ) { + for ( idx_t jlat = 0; jlat < nlats; jlat++ ) { double lonmin = wrapAngle( g.x( 0, jlat ) ); nlonsGlobal_[jlat] = gs_global.nx( jlat + jlatMin_ ); jlonMin_[jlat] = 0; - for ( size_t jlon = 0; jlon < nlonsGlobal_[jlat]; ++jlon ) { + for ( idx_t jlon = 0; jlon < nlonsGlobal_[jlat]; ++jlon ) { if ( gs_global.x( jlon, jlat + jlatMin_ ) < lonmin ) { jlonMin_[jlat]++; } } } @@ -439,7 +436,7 @@ TransLocal::TransLocal( const Cache& cache, const Grid& grid, const Domain& doma std::vector lats( nlatsLeg_ ); std::vector lons( nlonsMax ); if ( nlatsNH_ >= nlatsSH_ || useGlobalLeg ) { - for ( size_t j = 0; j < nlatsLeg_; ++j ) { + for ( idx_t j = 0; j < nlatsLeg_; ++j ) { double lat = gsLeg.y( j ); if ( lat > latPole ) { lat = latPole; } if ( lat < -latPole ) { lat = -latPole; } @@ -447,14 +444,14 @@ TransLocal::TransLocal( const Cache& cache, const Grid& grid, const Domain& doma } } else { - for ( size_t j = nlats - 1, idx = 0; idx < nlatsLeg_; --j, ++idx ) { + for ( idx_t j = nlats - 1, idx = 0; idx < nlatsLeg_; --j, ++idx ) { double lat = gsLeg.y( j ); if ( lat > latPole ) { lat = latPole; } if ( lat < -latPole ) { lat = -latPole; } lats[idx] = -lat * util::Constants::degreesToRadians(); } } - for ( size_t j = 0; j < nlonsMax; ++j ) { + for ( idx_t j = 0; j < nlonsMax; ++j ) { lons[j] = g.x( j, 0 ) * util::Constants::degreesToRadians(); } /*Log::info() << "lats: "; @@ -465,15 +462,16 @@ TransLocal::TransLocal( const Cache& cache, const Grid& grid, const Domain& doma // precomputations for Legendre polynomials: { - int size_sym = 0; - int size_asym = 0; + const auto nlatsLeg = size_t( nlatsLeg_ ); + size_t size_sym = 0; + size_t size_asym = 0; legendre_sym_begin_.resize( truncation_ + 3 ); legendre_asym_begin_.resize( truncation_ + 3 ); legendre_sym_begin_[0] = 0; legendre_asym_begin_[0] = 0; - for ( int jm = 0; jm <= truncation_ + 1; jm++ ) { - size_sym += add_padding( num_n( truncation_ + 1, jm, true ) * nlatsLeg_ ); - size_asym += add_padding( num_n( truncation_ + 1, jm, false ) * nlatsLeg_ ); + for ( idx_t jm = 0; jm <= truncation_ + 1; jm++ ) { + size_sym += add_padding( num_n( truncation_ + 1, jm, /*symmetric*/ true ) * nlatsLeg ); + size_asym += add_padding( num_n( truncation_ + 1, jm, /*symmetric*/ false ) * nlatsLeg ); legendre_sym_begin_[jm + 1] = size_sym; legendre_asym_begin_[jm + 1] = size_asym; } @@ -482,13 +480,17 @@ TransLocal::TransLocal( const Cache& cache, const Grid& grid, const Domain& doma ReadCache legendre( legendre_cache_ ); legendre_sym_ = legendre.read( size_sym ); legendre_asym_ = legendre.read( size_asym ); - ASSERT( legendre.pos == legendre_cachesize_ ); + ATLAS_ASSERT( legendre.pos == legendre_cachesize_ ); // TODO: check this is all aligned... } else { if ( TransParameters( config ).export_legendre() ) { - ASSERT( not cache_.legendre() ); - export_legendre_ = LegendreCache( sizeof( double ) * ( size_sym + size_asym ) ); + ATLAS_ASSERT( not cache_.legendre() ); + + size_t bytes = sizeof( double ) * ( size_sym + size_asym ); + Log::debug() << "TransLocal: allocating LegendreCache: " << eckit::Bytes( bytes ) << std::endl; + export_legendre_ = LegendreCache( bytes ); + legendre_cachesize_ = export_legendre_.legendre().size(); legendre_cache_ = export_legendre_.legendre().data(); ReadCache legendre( legendre_cache_ ); @@ -496,8 +498,8 @@ TransLocal::TransLocal( const Cache& cache, const Grid& grid, const Domain& doma legendre_asym_ = legendre.read( size_asym ); } else { - alloc_aligned( legendre_sym_, size_sym ); - alloc_aligned( legendre_asym_, size_asym ); + alloc_aligned( legendre_sym_, size_sym, "symmetric" ); + alloc_aligned( legendre_asym_, size_asym, "asymmetric" ); } ATLAS_TRACE_SCOPE( "Legendre precomputations (structured)" ) { @@ -529,7 +531,7 @@ TransLocal::TransLocal( const Cache& cache, const Grid& grid, const Domain& doma if ( fft_cache_ ) { Log::debug() << "Import FFTW wisdom from cache" << std::endl; - fftw_import_wisdom_from_string( (const char*)fft_cache_ ); + fftw_import_wisdom_from_string( static_cast( fft_cache_ ) ); } // std::string wisdomString( "" ); // std::ifstream read( "wisdom.bin" ); @@ -543,11 +545,11 @@ TransLocal::TransLocal( const Cache& cache, const Grid& grid, const Domain& doma // } // read.close(); // if ( wisdomString.length() > 0 ) { fftw_import_wisdom_from_string( &wisdomString[0u] ); } - if ( grid::RegularGrid( gridGlobal_ ) ) { + if ( RegularGrid( gridGlobal_ ) ) { fftw_->plans.resize( 1 ); fftw_->plans[0] = - fftw_plan_many_dft_c2r( 1, &nlonsMaxGlobal_, nlats, fftw_->in, NULL, 1, num_complex, fftw_->out, - NULL, 1, nlonsMaxGlobal_, FFTW_ESTIMATE ); + fftw_plan_many_dft_c2r( 1, &nlonsMaxGlobal_, nlats, fftw_->in, nullptr, 1, num_complex, + fftw_->out, nullptr, 1, nlonsMaxGlobal_, FFTW_ESTIMATE ); } else { fftw_->plans.resize( nlatsLegDomain_ ); @@ -576,7 +578,7 @@ TransLocal::TransLocal( const Cache& cache, const Grid& grid, const Domain& doma // write.close(); // } } - // other FFT implementations should be added with #elif statements + // other FFT implementations should be added with #elif statements #else useFFT_ = false; // no FFT implemented => default to dgemm std::string file_path = TransParameters( config ).write_fft(); @@ -593,7 +595,7 @@ TransLocal::TransLocal( const Cache& cache, const Grid& grid, const Domain& doma << "WARNING: Spectral transform results may contain aliasing errors. This will be addressed soon." << std::endl; - alloc_aligned( fourier_, 2 * ( truncation_ + 1 ) * nlonsMax ); + alloc_aligned( fourier_, 2 * ( truncation_ + 1 ) * nlonsMax, "Fourier coeffs." ); #if !TRANSLOCAL_DGEMM2 { ATLAS_TRACE( "Fourier precomputations (NoFFT)" ); @@ -643,7 +645,7 @@ TransLocal::TransLocal( const Cache& cache, const Grid& grid, const Domain& doma } std::vector lats( grid_.size() ); - alloc_aligned( legendre_, legendre_size( truncation_ ) * grid_.size() ); + alloc_aligned( legendre_, legendre_size( truncation_ ) * grid_.size(), "Legendre coeffs." ); int j( 0 ); for ( PointLonLat p : grid_.lonlat() ) { lats[j++] = p.lat() * util::Constants::degreesToRadians(); @@ -651,7 +653,7 @@ TransLocal::TransLocal( const Cache& cache, const Grid& grid, const Domain& doma compute_legendre_polynomials_all( truncation_, grid_.size(), lats.data(), legendre_ ); } if ( TransParameters( config ).write_legendre().size() ) { - throw eckit::NotImplemented( + throw_NotImplemented( "Caching for unstructured grids or structured grids with projections not yet implemented", Here() ); } } @@ -673,14 +675,14 @@ TransLocal::TransLocal( const Cache& cache, const Grid& grid, const long truncat // -------------------------------------------------------------------------------------------------------------------- TransLocal::~TransLocal() { - if ( grid::StructuredGrid( grid_ ) && not grid_.projection() ) { + if ( StructuredGrid( grid_ ) && not grid_.projection() ) { if ( not legendre_cache_ ) { - free_aligned( legendre_sym_ ); - free_aligned( legendre_asym_ ); + free_aligned( legendre_sym_, "symmetric" ); + free_aligned( legendre_asym_, "asymmetric" ); } if ( useFFT_ ) { #if ATLAS_HAVE_FFTW && !TRANSLOCAL_DGEMM2 - for ( int j = 0; j < fftw_->plans.size(); j++ ) { + for ( idx_t j = 0, size = static_cast( fftw_->plans.size() ); j < size; j++ ) { fftw_destroy_plan( fftw_->plans[j] ); } fftw_free( fftw_->in ); @@ -688,44 +690,44 @@ TransLocal::~TransLocal() { #endif } else { - free_aligned( fourier_ ); + free_aligned( fourier_, "Fourier coeffs." ); } } else { - if ( unstruct_precomp_ ) { free_aligned( legendre_ ); } + if ( unstruct_precomp_ ) { free_aligned( legendre_, "Legendre coeffs." ); } } } // -------------------------------------------------------------------------------------------------------------------- -void TransLocal::invtrans( const Field& spfield, Field& gpfield, const eckit::Configuration& config ) const { - NOTIMP; +void TransLocal::invtrans( const Field& /*spfield*/, Field& /*gpfield*/, const eckit::Configuration& ) const { + ATLAS_NOTIMPLEMENTED; } // -------------------------------------------------------------------------------------------------------------------- -void TransLocal::invtrans( const FieldSet& spfields, FieldSet& gpfields, const eckit::Configuration& config ) const { - NOTIMP; +void TransLocal::invtrans( const FieldSet& /*spfields*/, FieldSet& /*gpfields*/, const eckit::Configuration& ) const { + ATLAS_NOTIMPLEMENTED; } // -------------------------------------------------------------------------------------------------------------------- -void TransLocal::invtrans_grad( const Field& spfield, Field& gradfield, const eckit::Configuration& config ) const { - NOTIMP; +void TransLocal::invtrans_grad( const Field& /*spfield*/, Field& /*gradfield*/, const eckit::Configuration& ) const { + ATLAS_NOTIMPLEMENTED; } // -------------------------------------------------------------------------------------------------------------------- -void TransLocal::invtrans_grad( const FieldSet& spfields, FieldSet& gradfields, - const eckit::Configuration& config ) const { - NOTIMP; +void TransLocal::invtrans_grad( const FieldSet& /*spfields*/, FieldSet& /*gradfields*/, + const eckit::Configuration& ) const { + ATLAS_NOTIMPLEMENTED; } // -------------------------------------------------------------------------------------------------------------------- -void TransLocal::invtrans_vordiv2wind( const Field& spvor, const Field& spdiv, Field& gpwind, - const eckit::Configuration& config ) const { - NOTIMP; +void TransLocal::invtrans_vordiv2wind( const Field& /*spvor*/, const Field& /*spdiv*/, Field& /*gpwind*/, + const eckit::Configuration& ) const { + ATLAS_NOTIMPLEMENTED; } // -------------------------------------------------------------------------------------------------------------------- @@ -748,18 +750,17 @@ void gp_transpose( const int nb_size, const int nb_fields, const double gp_tmp[] // -------------------------------------------------------------------------------------------------------------------- void TransLocal::invtrans_legendre( const int truncation, const int nlats, const int nb_fields, - const int nb_vordiv_fields, const double scalar_spectra[], double scl_fourier[], - const eckit::Configuration& config ) const { + const int /*nb_vordiv_fields*/, const double scalar_spectra[], double scl_fourier[], + const eckit::Configuration& ) const { // Legendre transform: { Log::debug() << "Legendre dgemm: using " << nlatsLegReduced_ - nlat0_[0] << " latitudes out of " << nlatsGlobal_ / 2 << std::endl; ATLAS_TRACE( "Inverse Legendre Transform (GEMM)" ); for ( int jm = 0; jm <= truncation_; jm++ ) { - int size_sym = num_n( truncation_ + 1, jm, true ); - int size_asym = num_n( truncation_ + 1, jm, false ); - int n_imag = 2; - if ( jm == 0 ) { n_imag = 1; } + size_t size_sym = num_n( truncation_ + 1, jm, true ); + size_t size_asym = num_n( truncation_ + 1, jm, false ); + const int n_imag = ( jm ? 2 : 1 ); int size_fourier = nb_fields * n_imag * ( nlatsLegReduced_ - nlat0_[jm] ); if ( size_fourier > 0 ) { auto posFourier = [&]( int jfld, int imag, int jlat, int jm, int nlatsH ) { @@ -775,7 +776,7 @@ void TransLocal::invtrans_legendre( const int truncation, const int nlats, const alloc_aligned( scl_fourier_asym, size_fourier ); { //ATLAS_TRACE( "Legendre split" ); - int idx = 0, is = 0, ia = 0, ioff = ( 2 * truncation + 3 - jm ) * jm / 2 * nb_fields * 2; + idx_t idx = 0, is = 0, ia = 0, ioff = ( 2 * truncation + 3 - jm ) * jm / 2 * nb_fields * 2; // the choice between the following two code lines determines whether // total wavenumbers are summed in an ascending or descending order. // The trans library in IFS uses descending order because it should @@ -802,7 +803,8 @@ void TransLocal::invtrans_legendre( const int truncation, const int nlats, const } } } - ASSERT( ia == n_imag * nb_fields * size_asym && is == n_imag * nb_fields * size_sym ); + ATLAS_ASSERT( size_t( ia ) == n_imag * nb_fields * size_asym && + size_t( is ) == n_imag * nb_fields * size_sym ); } if ( nlatsLegReduced_ - nlat0_[jm] > 0 ) { { @@ -901,7 +903,7 @@ void TransLocal::invtrans_legendre( const int truncation, const int nlats, const // -------------------------------------------------------------------------------------------------------------------- void TransLocal::invtrans_fourier_regular( const int nlats, const int nlons, const int nb_fields, double scl_fourier[], - double gp_fields[], const eckit::Configuration& config ) const { + double gp_fields[], const eckit::Configuration& ) const { // Fourier transformation: if ( useFFT_ ) { #if ATLAS_HAVE_FFTW && !TRANSLOCAL_DGEMM2 @@ -947,24 +949,6 @@ void TransLocal::invtrans_fourier_regular( const int nlats, const int nlons, con eckit::linalg::Matrix B( scl_fourier, ( truncation_ + 1 ) * 2, nb_fields * nlats ); eckit::linalg::Matrix C( gp_fields, nlons, nb_fields * nlats ); - // BUG ATLAS-159: valgrind warns here, saying that B(1,:) is uninitialised - // if workaround above labeled ATLAS-159 is not applied. - // - // for( int i=0; i= nlonsGlobal_[jlat] ) { j -= nlonsGlobal_[jlat]; } //Log::info() << fftw_->out[j] << " "; - ASSERT( j < nlonsMaxGlobal_ ); + ATLAS_ASSERT( j < nlonsMaxGlobal_ ); gp_fields[jgp++] = fftw_->out[j]; } //Log::info() << std::endl; @@ -1053,7 +1036,7 @@ void TransLocal::invtrans_fourier_reduced( const int nlats, const grid::Structur #endif } else { - throw eckit::NotImplemented( + throw_NotImplemented( "Using dgemm in Fourier transform for reduced grids is extremely slow. Please install and use FFTW!", Here() ); } @@ -1063,7 +1046,7 @@ void TransLocal::invtrans_fourier_reduced( const int nlats, const grid::Structur void TransLocal::invtrans_unstructured_precomp( const int truncation, const int nb_fields, const int nb_vordiv_fields, const double scalar_spectra[], double gp_fields[], - const eckit::Configuration& config ) const { + const eckit::Configuration& ) const { ATLAS_TRACE( "invtrans_uv unstructured" ); const int nlats = grid_.size(); @@ -1270,8 +1253,8 @@ void TransLocal::invtrans_uv( const int truncation, const int nb_scalar_fields, int nb_fields = nb_scalar_fields; // Transform - if ( grid::StructuredGrid( grid_ ) && not grid_.projection() ) { - auto g = grid::StructuredGrid( grid_ ); + if ( StructuredGrid( grid_ ) && not grid_.projection() ) { + auto g = StructuredGrid( grid_ ); ATLAS_TRACE( "invtrans_uv structured" ); int nlats = g.ny(); int nlons = g.nxmax(); @@ -1290,7 +1273,7 @@ void TransLocal::invtrans_uv( const int truncation, const int nb_scalar_fields, config ); // Fourier transformation: - if ( grid::RegularGrid( gridGlobal_ ) ) { + if ( RegularGrid( gridGlobal_ ) ) { invtrans_fourier_regular( nlats, nlons, nb_fields, scl_fourier, gp_fields, config ); } else { @@ -1302,7 +1285,7 @@ void TransLocal::invtrans_uv( const int truncation, const int nb_scalar_fields, if ( nb_vordiv_fields > 0 ) { ATLAS_TRACE( "compute u,v from U,V" ); std::vector coslatinvs( nlats ); - for ( size_t j = 0; j < nlats; ++j ) { + for ( idx_t j = 0; j < nlats; ++j ) { double lat = g.y( j ); if ( lat > latPole ) { lat = latPole; } if ( lat < -latPole ) { lat = -latPole; } @@ -1311,9 +1294,9 @@ void TransLocal::invtrans_uv( const int truncation, const int nb_scalar_fields, //Log::info() << "lat=" << g.y( j ) << " coslat=" << coslat << std::endl; } int idx = 0; - for ( int jfld = 0; jfld < 2 * nb_vordiv_fields && jfld < nb_fields; jfld++ ) { - for ( int jlat = 0; jlat < g.ny(); jlat++ ) { - for ( int jlon = 0; jlon < g.nx( jlat ); jlon++ ) { + for ( idx_t jfld = 0; jfld < 2 * nb_vordiv_fields && jfld < nb_fields; jfld++ ) { + for ( idx_t jlat = 0; jlat < g.ny(); jlat++ ) { + for ( idx_t jlon = 0; jlon < g.nx( jlat ); jlon++ ) { gp_fields[idx] *= coslatinvs[jlat]; idx++; } @@ -1428,10 +1411,10 @@ void TransLocal::invtrans( const int nb_scalar_fields, const double scalar_spect } int nb_vordiv_size = 2 * legendre_size( truncation_ + 1 ) * nb_vordiv_fields; int nb_scalar_size = 2 * legendre_size( truncation_ + 1 ) * nb_scalar_fields; - ASSERT( k == nb_all_size ); - ASSERT( i == nb_vordiv_size ); - ASSERT( j == nb_vordiv_size ); - ASSERT( l == nb_scalar_size ); + ATLAS_ASSERT( k == nb_all_size ); + ATLAS_ASSERT( i == nb_vordiv_size ); + ATLAS_ASSERT( j == nb_vordiv_size ); + ATLAS_ASSERT( l == nb_scalar_size ); invtrans_uv( truncation_ + 1, nb_all_fields, nb_vordiv_fields, all_spectra.data(), gp_fields, config ); } else { @@ -1445,7 +1428,7 @@ void TransLocal::invtrans( const int nb_scalar_fields, const double scalar_spect // -------------------------------------------------------------------------------------------------------------------- void TransLocal::dirtrans( const Field& gpfield, Field& spfield, const eckit::Configuration& config ) const { - NOTIMP; + ATLAS_NOTIMPLEMENTED; // Not implemented and not planned. // Use the TransIFS implementation instead. } @@ -1453,7 +1436,7 @@ void TransLocal::dirtrans( const Field& gpfield, Field& spfield, const eckit::Co // -------------------------------------------------------------------------------------------------------------------- void TransLocal::dirtrans( const FieldSet& gpfields, FieldSet& spfields, const eckit::Configuration& config ) const { - NOTIMP; + ATLAS_NOTIMPLEMENTED; // Not implemented and not planned. // Use the TransIFS implementation instead. } @@ -1462,7 +1445,7 @@ void TransLocal::dirtrans( const FieldSet& gpfields, FieldSet& spfields, const e void TransLocal::dirtrans_wind2vordiv( const Field& gpwind, Field& spvor, Field& spdiv, const eckit::Configuration& config ) const { - NOTIMP; + ATLAS_NOTIMPLEMENTED; // Not implemented and not planned. // Use the TransIFS implementation instead. } @@ -1471,7 +1454,7 @@ void TransLocal::dirtrans_wind2vordiv( const Field& gpwind, Field& spvor, Field& void TransLocal::dirtrans( const int nb_fields, const double scalar_fields[], double scalar_spectra[], const eckit::Configuration& ) const { - NOTIMP; + ATLAS_NOTIMPLEMENTED; // Not implemented and not planned. // Use the TransIFS implementation instead. } @@ -1480,7 +1463,7 @@ void TransLocal::dirtrans( const int nb_fields, const double scalar_fields[], do void TransLocal::dirtrans( const int nb_fields, const double wind_fields[], double vorticity_spectra[], double divergence_spectra[], const eckit::Configuration& ) const { - NOTIMP; + ATLAS_NOTIMPLEMENTED; // Not implemented and not planned. // Use the TransIFS implementation instead. } diff --git a/src/atlas/trans/local/TransLocal.h b/src/atlas/trans/local/TransLocal.h index 4e66473ee..2d5611cf3 100644 --- a/src/atlas/trans/local/TransLocal.h +++ b/src/atlas/trans/local/TransLocal.h @@ -15,7 +15,7 @@ #include "atlas/array.h" #include "atlas/grid/Grid.h" -#include "atlas/trans/Trans.h" +#include "atlas/trans/detail/TransImpl.h" #define TRANSLOCAL_DGEMM2 0 @@ -31,6 +31,7 @@ class LinearAlgebra; namespace atlas { class Field; class FieldSet; +class StructuredGrid; } // namespace atlas //----------------------------------------------------------------------------- @@ -72,7 +73,7 @@ class TransLocal : public trans::TransImpl { TransLocal( const Cache&, const Grid&, const Domain&, const long truncation, const eckit::Configuration& = util::NoConfig() ); - virtual ~TransLocal(); + virtual ~TransLocal() override; virtual int truncation() const override { return truncation_; } virtual size_t spectralCoefficients() const override { return ( truncation_ + 1 ) * ( truncation_ + 2 ); } @@ -132,7 +133,7 @@ class TransLocal : public trans::TransImpl { #else return jfld + nb_fields * ( jlat + nlats * ( imag + 2 * ( jm ) ) ); #endif - }; + } void invtrans_legendre( const int truncation, const int nlats, const int nb_fields, const int nb_vordiv_fields, const double scalar_spectra[], double scl_fourier[], @@ -141,8 +142,8 @@ class TransLocal : public trans::TransImpl { void invtrans_fourier_regular( const int nlats, const int nlons, const int nb_fields, double scl_fourier[], double gp_fields[], const eckit::Configuration& config ) const; - void invtrans_fourier_reduced( const int nlats, const grid::StructuredGrid g, const int nb_fields, - double scl_fourier[], double gp_fields[], const eckit::Configuration& config ) const; + void invtrans_fourier_reduced( const int nlats, const StructuredGrid& g, const int nb_fields, double scl_fourier[], + double gp_fields[], const eckit::Configuration& config ) const; void invtrans_unstructured_precomp( const int truncation, const int nb_scalar_fields, const int nb_vordiv_fields, const double scalar_spectra[], double gp_fields[], @@ -168,18 +169,18 @@ class TransLocal : public trans::TransImpl { bool unstruct_precomp_; bool no_symmetry_; int truncation_; - int nlatsNH_; - int nlatsSH_; - int nlatsLeg_; - int nlatsLegReduced_; - int nlatsLegDomain_; - std::vector jlonMin_; - int jlatMin_; - int jlatMinLeg_; - int nlonsMaxGlobal_; - std::vector nlonsGlobal_; - std::vector nlat0_; - int nlatsGlobal_; + idx_t nlatsNH_; + idx_t nlatsSH_; + idx_t nlatsLeg_; + idx_t nlatsLegReduced_; + idx_t nlatsLegDomain_; + std::vector jlonMin_; + idx_t jlatMin_; + idx_t jlatMinLeg_; + idx_t nlonsMaxGlobal_; + std::vector nlonsGlobal_; + std::vector nlat0_; + idx_t nlatsGlobal_; bool precompute_; double* legendre_; double* legendre_sym_; @@ -190,9 +191,6 @@ class TransLocal : public trans::TransImpl { std::vector legendre_sym_begin_; std::vector legendre_asym_begin_; - - std::unique_ptr fftw_; - Cache cache_; Cache export_legendre_; const void* legendre_cache_{nullptr}; @@ -200,6 +198,8 @@ class TransLocal : public trans::TransImpl { const void* fft_cache_{nullptr}; size_t fft_cachesize_{0}; + std::unique_ptr fftw_; + const eckit::linalg::LinearAlgebra& linalg_; int warning_ = 0; }; diff --git a/src/atlas/util/Allocate.cc b/src/atlas/util/Allocate.cc new file mode 100644 index 000000000..8d2136381 --- /dev/null +++ b/src/atlas/util/Allocate.cc @@ -0,0 +1,76 @@ +/* +* (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 "Allocate.h" + +#include "atlas/library/config.h" +#include "atlas/runtime/Exception.h" +#include "eckit/log/CodeLocation.h" + +#if ATLAS_GRIDTOOLS_STORAGE_BACKEND_CUDA +#include +#endif + +namespace atlas { +namespace util { + +//------------------------------------------------------------------------------ +namespace detail { +//------------------------------------------------------------------------------ + +void allocate_cudamanaged( void** ptr, size_t size ) { +#if ATLAS_GRIDTOOLS_STORAGE_BACKEND_CUDA + cudaError_t err = cudaMallocManaged( ptr, size ); + if ( err != cudaSuccess ) throw_AssertionFailed( "failed to allocate GPU memory", Here() ); +#else + *ptr = malloc( size ); +#endif +} + +void deallocate_cudamanaged( void* ptr ) { +#if ATLAS_GRIDTOOLS_STORAGE_BACKEND_CUDA + cudaError_t err = cudaDeviceSynchronize(); + if ( err != cudaSuccess ) throw_AssertionFailed( "failed to synchronize memory", Here() ); + + err = cudaFree( ptr ); + // The following throws an invalid device memory + if ( err != cudaSuccess ) throw_AssertionFailed( "failed to free GPU memory", Here() ); +#else + free( ptr ); +#endif +} + +//------------------------------------------------------------------------------ +} // namespace detail +//------------------------------------------------------------------------------ + +extern "C" { +void atlas__allocate_managedmem_double( double*& a, int N ) { + allocate_managedmem( a, N ); +} +void atlas__allocate_managedmem_float( float*& a, int N ) { + allocate_managedmem( a, N ); +} +void atlas__allocate_managedmem_int( int*& a, int N ) { + allocate_managedmem( a, N ); +} +void atlas__allocate_managedmem_long( long*& a, int N ) { + allocate_managedmem( a, N ); +} +void atlas__deallocate_managedmem( void*& a ) { + delete_managedmem( a ); +} +} + +//------------------------------------------------------------------------------ + +} // namespace util +} // namespace atlas diff --git a/src/atlas/util/Allocate.h b/src/atlas/util/Allocate.h new file mode 100644 index 000000000..3c35c4a21 --- /dev/null +++ b/src/atlas/util/Allocate.h @@ -0,0 +1,55 @@ +/* +* (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 + +#include "atlas/library/config.h" + +namespace atlas { +namespace util { + +//------------------------------------------------------------------------------ + +namespace detail { +void allocate_cudamanaged( void** ptr, size_t size ); +void deallocate_cudamanaged( void* ptr ); +} // namespace detail + +template +void allocate_managedmem( T*& data, idx_t N ) { + if ( N != 0 ) { + detail::allocate_cudamanaged( reinterpret_cast( &data ), static_cast( N ) * sizeof( T ) ); + } +} + +template +void delete_managedmem( T*& data ) { + if ( data ) { + detail::deallocate_cudamanaged( data ); + data = nullptr; + } +} + +//------------------------------------------------------------------------------ + +extern "C" { +void atlas__allocate_managedmem_double( double*& a, idx_t N ); +void atlas__allocate_managedmem_float( float*& a, idx_t N ); +void atlas__allocate_managedmem_int( int*& a, idx_t N ); +void atlas__allocate_managedmem_long( long*& a, idx_t N ); +void atlas__deallocate_managedmem( void*& a ); +} + +//------------------------------------------------------------------------------ + +} // namespace util +} // namespace atlas diff --git a/src/atlas/util/Checksum.cc b/src/atlas/util/Checksum.cc index 955a91ee8..a4715b032 100644 --- a/src/atlas/util/Checksum.cc +++ b/src/atlas/util/Checksum.cc @@ -1,3 +1,12 @@ +/* + * (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 diff --git a/src/atlas/util/Checksum.h b/src/atlas/util/Checksum.h index a8f68ee33..43ba3c37f 100644 --- a/src/atlas/util/Checksum.h +++ b/src/atlas/util/Checksum.h @@ -1,3 +1,13 @@ +/* + * (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 diff --git a/src/atlas/util/Config.cc b/src/atlas/util/Config.cc index 6284d7c81..8240b2639 100644 --- a/src/atlas/util/Config.cc +++ b/src/atlas/util/Config.cc @@ -9,18 +9,19 @@ */ #include +#include +#include #include #include #include -#include "eckit/exception/Exceptions.h" #include "eckit/filesystem/PathName.h" #include "eckit/parser/JSON.h" #include "eckit/parser/YAMLParser.h" #include "atlas/grid/Grid.h" #include "atlas/mesh/Mesh.h" -#include "atlas/runtime/ErrorHandling.h" +#include "atlas/runtime/Exception.h" #include "atlas/util/Config.h" using std::string; @@ -36,9 +37,9 @@ static eckit::Value yaml_from_stream( std::istream& stream ) { } static eckit::Value yaml_from_path( const eckit::PathName& path ) { - if ( !path.exists() ) { throw eckit::Exception( "File " + std::string( path ) + " does not exist." ); } + if ( !path.exists() ) { throw_Exception( "File " + std::string( path ) + " does not exist." ); } std::ifstream file( path.localPath() ); - if ( !file.is_open() ) { throw eckit::Exception( "Unable to open json file " + std::string( path ), Here() ); } + if ( !file.is_open() ) { throw_Exception( "Unable to open json file " + std::string( path ), Here() ); } eckit::Value value = yaml_from_stream( file ); file.close(); return value; @@ -50,8 +51,7 @@ Config::Config() : eckit::LocalConfiguration() {} Config::Config( const eckit::Configuration& p ) : eckit::LocalConfiguration( p ) {} -Config::Config( std::istream& stream, const std::string& format ) : - eckit::LocalConfiguration( yaml_from_stream( stream ) ) {} +Config::Config( std::istream& stream, const std::string& ) : eckit::LocalConfiguration( yaml_from_stream( stream ) ) {} Config::Config( const eckit::PathName& path ) : eckit::LocalConfiguration( yaml_from_path( path ) ) {} @@ -63,9 +63,9 @@ Config Config::operator|( const Config& other ) const { Config& Config::set( const eckit::LocalConfiguration& other ) { eckit::ValueMap otherval = other.get(); - + eckit::Value& root = const_cast( get() ); for ( eckit::ValueMap::const_iterator vit = otherval.begin(); vit != otherval.end(); ++vit ) { - root_[vit->first] = vit->second; + root[vit->first] = vit->second; } return *this; } @@ -110,126 +110,182 @@ Config* atlas__Config__new_from_file( const char* path ) { } void atlas__Config__delete( Config* This ) { - ASSERT( This != 0 ); + ATLAS_ASSERT( This != nullptr, "Cannot access uninitialised atlas_Config" ); delete This; } void atlas__Config__set_config( Config* This, const char* name, const Config* value ) { - ATLAS_ERROR_HANDLING( This->set( std::string( name ), *value ) ); + ATLAS_ASSERT( This != nullptr, "Cannot access uninitialised atlas_Config" ); + This->set( std::string( name ), *value ); } void atlas__Config__set_config_list( Config* This, const char* name, const Config* value[], int size ) { + ATLAS_ASSERT( This != nullptr, "Cannot access uninitialised atlas_Config" ); std::vector params( size ); for ( int i = 0; i < size; ++i ) { params[i] = Config( *value[i] ); } - ATLAS_ERROR_HANDLING( This->set( std::string( name ), params ) ); + This->set( std::string( name ), params ); } void atlas__Config__set_int( Config* This, const char* name, int value ) { - ATLAS_ERROR_HANDLING( This->set( std::string( name ), long( value ) ) ); + ATLAS_ASSERT( This != nullptr, "Cannot access uninitialised atlas_Config" ); + This->set( std::string( name ), long( value ) ); } void atlas__Config__set_long( Config* This, const char* name, long value ) { - ATLAS_ERROR_HANDLING( This->set( std::string( name ), value ) ); + ATLAS_ASSERT( This != nullptr, "Cannot access uninitialised atlas_Config" ); + This->set( std::string( name ), value ); } void atlas__Config__set_float( Config* This, const char* name, float value ) { - ATLAS_ERROR_HANDLING( This->set( std::string( name ), double( value ) ) ); + ATLAS_ASSERT( This != nullptr, "Cannot access uninitialised atlas_Config" ); + This->set( std::string( name ), double( value ) ); } void atlas__Config__set_double( Config* This, const char* name, double value ) { - ATLAS_ERROR_HANDLING( This->set( std::string( name ), value ) ); + ATLAS_ASSERT( This != nullptr, "Cannot access uninitialised atlas_Config" ); + This->set( std::string( name ), value ); } void atlas__Config__set_string( Config* This, const char* name, const char* value ) { - ATLAS_ERROR_HANDLING( This->set( std::string( name ), std::string( value ) ) ); + ATLAS_ASSERT( This != nullptr, "Cannot access uninitialised atlas_Config" ); + This->set( std::string( name ), std::string( value ) ); } void atlas__Config__set_array_int( Config* This, const char* name, int value[], int size ) { - ATLAS_ERROR_HANDLING( std::vector v; v.assign( value, value + size ); This->set( std::string( name ), v ); ); + ATLAS_ASSERT( This != nullptr, "Cannot access uninitialised atlas_Config" ); + std::vector v; + v.assign( value, value + size ); + This->set( std::string( name ), v ); } void atlas__Config__set_array_long( Config* This, const char* name, long value[], int size ) { - ATLAS_ERROR_HANDLING( std::vector v; v.assign( value, value + size ); This->set( std::string( name ), v ); ); + ATLAS_ASSERT( This != nullptr, "Cannot access uninitialised atlas_Config" ); + std::vector v; + v.assign( value, value + size ); + This->set( std::string( name ), v ); } void atlas__Config__set_array_float( Config* This, const char* name, float value[], int size ) { - ATLAS_ERROR_HANDLING( std::vector v; v.assign( value, value + size ); This->set( std::string( name ), v ); ); + ATLAS_ASSERT( This != nullptr, "Cannot access uninitialised atlas_Config" ); + std::vector v; + v.assign( value, value + size ); + This->set( std::string( name ), v ); } void atlas__Config__set_array_double( Config* This, const char* name, double value[], int size ) { - ATLAS_ERROR_HANDLING( std::vector v; v.assign( value, value + size ); - This->set( std::string( name ), v ); ); + ATLAS_ASSERT( This != nullptr, "Cannot access uninitialised atlas_Config" ); + std::vector v; + v.assign( value, value + size ); + This->set( std::string( name ), v ); } int atlas__Config__get_config( Config* This, const char* name, Config* value ) { - ATLAS_ERROR_HANDLING( if ( !This->get( std::string( name ), *value ) ) return false; ); + ATLAS_ASSERT( This != nullptr, "Cannot access uninitialised atlas_Config" ); + if ( !This->get( std::string( name ), *value ) ) return false; return true; } int atlas__Config__get_config_list( Config* This, const char* name, Config**& value, int& size, int& allocated ) { - value = 0; - ATLAS_ERROR_HANDLING( std::vector vector; if ( !This->get( std::string( name ), vector ) ) return false; - size = vector.size(); value = new Config*[size]; allocated = true; - for ( int i = 0; i < size; ++i ) { value[i] = new Config( vector[i] ); } ); + ATLAS_ASSERT( This != nullptr, "Cannot access uninitialised atlas_Config" ); + value = nullptr; + std::vector vector; + if ( !This->get( std::string( name ), vector ) ) return false; + size = vector.size(); + value = new Config*[size]; + allocated = true; + for ( int i = 0; i < size; ++i ) { + value[i] = new Config( vector[i] ); + } return true; } int atlas__Config__get_int( Config* This, const char* name, int& value ) { + ATLAS_ASSERT( This != nullptr, "Cannot access uninitialised atlas_Config" ); long long_value = value; - ATLAS_ERROR_HANDLING( if ( !This->get( std::string( name ), long_value ) ) return false; ); - ASSERT( int( long_value ) == long_value ); + if ( !This->get( std::string( name ), long_value ) ) return false; + ATLAS_ASSERT( int( long_value ) == long_value ); value = long_value; return true; } int atlas__Config__get_long( Config* This, const char* name, long& value ) { - ATLAS_ERROR_HANDLING( if ( !This->get( std::string( name ), value ) ) return false; ); + ATLAS_ASSERT( This != nullptr, "Cannot access uninitialised atlas_Config" ); + if ( !This->get( std::string( name ), value ) ) return false; return true; } int atlas__Config__get_float( Config* This, const char* name, float& value ) { + ATLAS_ASSERT( This != nullptr, "Cannot access uninitialised atlas_Config" ); double double_value; - ATLAS_ERROR_HANDLING( if ( !This->get( std::string( name ), double_value ) ) return false; ); - value = double_value; + if ( !This->get( std::string( name ), double_value ) ) return false; + value = static_cast( double_value ); return true; } int atlas__Config__get_double( Config* This, const char* name, double& value ) { - ATLAS_ERROR_HANDLING( if ( !This->get( std::string( name ), value ) ) return false; ); + ATLAS_ASSERT( This != nullptr, "Cannot access uninitialised atlas_Config" ); + if ( !This->get( std::string( name ), value ) ) return false; return true; } int atlas__Config__get_string( Config* This, const char* name, char*& value, int& size, int& allocated ) { - ATLAS_ERROR_HANDLING( std::string s; if ( !This->get( std::string( name ), s ) ) { - value = NULL; + ATLAS_ASSERT( This != nullptr, "Cannot access uninitialised atlas_Config" ); + std::string s; + if ( !This->get( std::string( name ), s ) ) { + value = nullptr; return false; - } size = s.size() + 1; - value = new char[size]; strcpy( value, s.c_str() ); allocated = true; ); + } + size = s.size() + 1; + value = new char[size]; + strcpy( value, s.c_str() ); + allocated = true; return true; } int atlas__Config__get_array_int( Config* This, const char* name, int*& value, int& size, int& allocated ) { - ATLAS_ERROR_HANDLING( std::vector v; if ( !This->get( std::string( name ), v ) ) return false; - size = v.size(); value = new int[size]; for ( size_t j = 0; j < v.size(); ++j ) { - ASSERT( int( v[j] ) == v[j] ); - value[j] = v[j]; - } allocated = true; ); + ATLAS_ASSERT( This != nullptr, "Cannot access uninitialised atlas_Config" ); + std::vector v; + if ( !This->get( std::string( name ), v ) ) return false; + size = v.size(); + value = new int[size]; + for ( size_t j = 0; j < v.size(); ++j ) { + ATLAS_ASSERT( int( v[j] ) == v[j] ); + value[j] = v[j]; + } + allocated = true; return true; } int atlas__Config__get_array_long( Config* This, const char* name, long*& value, int& size, int& allocated ) { - ATLAS_ERROR_HANDLING( std::vector v; if ( !This->get( std::string( name ), v ) ) return false; - size = v.size(); value = new long[size]; - for ( size_t j = 0; j < v.size(); ++j ) value[j] = v[j]; allocated = true; ); + ATLAS_ASSERT( This != nullptr, "Cannot access uninitialised atlas_Config" ); + std::vector v; + if ( !This->get( std::string( name ), v ) ) return false; + size = v.size(); + value = new long[size]; + for ( size_t j = 0; j < v.size(); ++j ) + value[j] = v[j]; + allocated = true; return true; } int atlas__Config__get_array_float( Config* This, const char* name, float*& value, int& size, int& allocated ) { - ATLAS_ERROR_HANDLING( std::vector v; if ( !This->get( std::string( name ), v ) ) return false; - size = v.size(); value = new float[size]; - for ( size_t j = 0; j < v.size(); ++j ) { value[j] = v[j]; } allocated = true; ); + ATLAS_ASSERT( This != nullptr, "Cannot access uninitialised atlas_Config" ); + std::vector v; + if ( !This->get( std::string( name ), v ) ) return false; + size = v.size(); + value = new float[size]; + for ( size_t j = 0; j < v.size(); ++j ) { + value[j] = static_cast( v[j] ); + } + allocated = true; return true; } int atlas__Config__get_array_double( Config* This, const char* name, double*& value, int& size, int& allocated ) { - ATLAS_ERROR_HANDLING( std::vector v; if ( !This->get( std::string( name ), v ) ) return false; - size = v.size(); value = new double[size]; - for ( size_t j = 0; j < v.size(); ++j ) value[j] = v[j]; allocated = true; ); + ATLAS_ASSERT( This != nullptr, "Cannot access uninitialised atlas_Config" ); + std::vector v; + if ( !This->get( std::string( name ), v ) ) return false; + size = v.size(); + value = new double[size]; + for ( size_t j = 0; j < v.size(); ++j ) + value[j] = v[j]; + allocated = true; return true; } int atlas__Config__has( Config* This, const char* name ) { - ATLAS_ERROR_HANDLING( return This->has( std::string( name ) ) ); - return 0; + ATLAS_ASSERT( This != nullptr, "Cannot access uninitialised atlas_Config" ); + return This->has( std::string( name ) ); } void atlas__Config__json( Config* This, char*& json, int& size, int& allocated ) { + ATLAS_ASSERT( This != nullptr, "Cannot access uninitialised atlas_Config" ); std::stringstream s; eckit::JSON j( s ); j.precision( 16 ); diff --git a/src/atlas/util/Config.h b/src/atlas/util/Config.h index da77b78a1..94ae33ae3 100644 --- a/src/atlas/util/Config.h +++ b/src/atlas/util/Config.h @@ -12,14 +12,12 @@ #include #include -#include "eckit/config/Parametrisation.h" -#include "eckit/utils/Hash.h" - -#include "atlas/util/Metadata.h" +#include "eckit/config/LocalConfiguration.h" namespace eckit { class PathName; -} +class Hash; +} // namespace eckit namespace atlas { namespace util { @@ -135,14 +133,16 @@ class NoConfig : public Config { virtual bool get( const std::string& name, bool& value ) const { return false; } virtual bool get( const std::string& name, int& value ) const { return false; } virtual bool get( const std::string& name, long& value ) const { return false; } - virtual bool get( const std::string& name, size_t& value ) const { return false; } + virtual bool get( const std::string& name, long long& value ) const { return false; } + virtual bool get( const std::string& name, std::size_t& value ) const { return false; } virtual bool get( const std::string& name, float& value ) const { return false; } virtual bool get( const std::string& name, double& value ) const { return false; } virtual bool get( const std::string& name, std::vector& value ) const { return false; } virtual bool get( const std::string& name, std::vector& value ) const { return false; } virtual bool get( const std::string& name, std::vector& value ) const { return false; } - virtual bool get( const std::string& name, std::vector& value ) const { return false; } + virtual bool get( const std::string& name, std::vector& value ) const { return false; } + virtual bool get( const std::string& name, std::vector& value ) const { return false; } virtual bool get( const std::string& name, std::vector& value ) const { return false; } virtual bool get( const std::string& name, std::vector& value ) const { return false; } }; diff --git a/src/atlas/util/Factory.cc b/src/atlas/util/Factory.cc new file mode 100644 index 000000000..ef6516644 --- /dev/null +++ b/src/atlas/util/Factory.cc @@ -0,0 +1,110 @@ +/* + * (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 "atlas/runtime/Exception.h" +#include "atlas/runtime/Log.h" +#include "atlas/util/Factory.h" + +// #define DEBUG_FACTORY_REGISTRATION + +using lock_guard = std::lock_guard; + +namespace atlas { +namespace util { + +bool FactoryRegistry::has( const std::string& builder ) const { + lock_guard lock( mutex_ ); + return ( factories_.find( builder ) != factories_.end() ); +} + +FactoryBase* FactoryRegistry::get( const std::string& builder ) const { + lock_guard lock( mutex_ ); + auto iterator = factories_.find( builder ); + + if ( iterator == factories_.end() ) { + Log::error() << "No " << factory_ << " for [" << builder << "]" << std::endl; + Log::error() << "Factories are:" << std::endl; + for ( const auto& map_pair : factories_ ) { + Log::error() << " " << map_pair.first << std::endl; + } + throw_Exception( std::string( "No " ) + factory_ + std::string( " called " ) + builder ); + } + else { + return iterator->second; + } +} + +void FactoryRegistry::add( const std::string& builder, FactoryBase* factory ) { + lock_guard lock( mutex_ ); + ATLAS_ASSERT( factories_.find( builder ) == factories_.end(), "Cannot find builder in factory" ); + factories_[builder] = factory; +#ifdef DEBUG_FACTORY_REGISTRATION + std::cout << "Registered " << builder << " in " << factory_ << std::endl; +#endif +} + +void FactoryRegistry::remove( const std::string& builder ) { + lock_guard lock( mutex_ ); + factories_.erase( builder ); +#ifdef DEBUG_FACTORY_REGISTRATION + std::cout << "Unregistered " << builder << " from " << factory_ << std::endl; +#endif +} + +FactoryRegistry::FactoryRegistry( const std::string& factory ) : factory_( factory ) { +#ifdef DEBUG_FACTORY_REGISTRATION + std::cout << "Created " << factory << std::endl; +#endif +} + +FactoryRegistry::~FactoryRegistry() { + while ( not factories_.empty() ) { + delete factories_.begin()->second; // will remove itself from registry in its destructor + } +} + +std::vector FactoryRegistry::keys() const { + lock_guard lock( mutex_ ); + std::vector _keys; + _keys.reserve( factories_.size() ); + for ( const auto& key_value : factories_ ) { + _keys.emplace_back( key_value.first ); + } + return _keys; +} + +void FactoryRegistry::list( std::ostream& out ) const { + lock_guard lock( mutex_ ); + const char* sep = ""; + for ( const auto& map_pair : factories_ ) { + out << sep << map_pair.first; + sep = ", "; + } +} + + +//---------------------------------------------------------------------------------------------------------------------- + +FactoryBase::FactoryBase( FactoryRegistry& registry, const std::string& builder ) : + registry_( registry ), + builder_( builder ) { + if ( not builder_.empty() ) { registry_.add( builder, this ); } +} + +FactoryBase::~FactoryBase() { + if ( not builder_.empty() ) { registry_.remove( builder_ ); } +} + +//---------------------------------------------------------------------------------------------------------------------- + +} // namespace util +} // namespace atlas diff --git a/src/atlas/util/Factory.h b/src/atlas/util/Factory.h new file mode 100644 index 000000000..87b60d55e --- /dev/null +++ b/src/atlas/util/Factory.h @@ -0,0 +1,87 @@ +/* + * (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 +#include +#include +#include + +namespace eckit { +class Parametrisation; +} + +namespace atlas { +namespace util { + +class FactoryBase; + +class FactoryRegistry { +protected: + FactoryRegistry( const std::string& factory ); + ~FactoryRegistry(); + +private: + mutable std::mutex mutex_; + std::map factories_; + std::string factory_; + +public: + std::vector keys() const; + void list( std::ostream& ) const; + bool has( const std::string& builder ) const; + void add( const std::string& builder, FactoryBase* ); + void remove( const std::string& builder ); + FactoryBase* get( const std::string& builder ) const; +}; + +template +struct FactoryRegistryT : public FactoryRegistry { +public: + static FactoryRegistryT& instance() { + static FactoryRegistryT env( T::className() ); + return env; + } + +private: + FactoryRegistryT( const std::string& factory ) : FactoryRegistry( factory ) {} +}; + +class FactoryBase { +private: + FactoryRegistry& registry_; + std::string builder_; + +protected: + FactoryBase( FactoryRegistry&, const std::string& builder ); + virtual ~FactoryBase(); + friend class FactoryRegistry; +}; + +template +class Factory : public FactoryBase { +public: + static std::vector keys() { return registry().keys(); } + static void list( std::ostream& out ) { return registry().list( out ); } + static bool has( const std::string& builder ) { return registry().has( builder ); } + static T* get( const std::string& builder ) { return dynamic_cast( registry().get( builder ) ); } + + Factory( const std::string& builder = "" ) : FactoryBase( registry(), builder ) {} + +protected: + virtual ~Factory() = default; + static FactoryRegistryT& registry() { return FactoryRegistryT::instance(); } +}; + +//---------------------------------------------------------------------------------------------------------------------- + +} // namespace util +} // namespace atlas diff --git a/src/atlas/util/LonLatPolygon.cc b/src/atlas/util/LonLatPolygon.cc index b1bab0bc1..4cca4f1d1 100644 --- a/src/atlas/util/LonLatPolygon.cc +++ b/src/atlas/util/LonLatPolygon.cc @@ -14,6 +14,7 @@ #include #include +#include "atlas/runtime/Exception.h" #include "atlas/util/CoordinateEnums.h" #include "atlas/util/LonLatPolygon.h" @@ -38,7 +39,7 @@ LonLatPolygon::LonLatPolygon( const Polygon& poly, const atlas::Field& lonlat, b LonLatPolygon::LonLatPolygon( const std::vector& points ) : PolygonCoordinates( points ) {} bool LonLatPolygon::contains( const PointLonLat& P ) const { - ASSERT( coordinates_.size() >= 2 ); + ATLAS_ASSERT( coordinates_.size() >= 2 ); // check first bounding box if ( coordinatesMax_.lon() <= P.lon() || P.lon() < coordinatesMin_.lon() || coordinatesMax_.lat() <= P.lat() || diff --git a/src/atlas/util/Metadata.cc b/src/atlas/util/Metadata.cc index c0831bb77..e4c3357db 100644 --- a/src/atlas/util/Metadata.cc +++ b/src/atlas/util/Metadata.cc @@ -14,24 +14,23 @@ #include #include -#include "eckit/exception/Exceptions.h" #include "eckit/parser/JSON.h" #include "eckit/parser/JSONParser.h" #include "eckit/utils/Hash.h" #include "atlas/parallel/mpi/mpi.h" -#include "atlas/runtime/ErrorHandling.h" +#include "atlas/runtime/Exception.h" using std::string; namespace atlas { namespace util { -void Metadata::throw_exception( const std::string& name ) const { +void Metadata::throw_not_found( const std::string& name ) const { std::stringstream msg; msg << "Could not find metadata \"" << name << "\""; - throw eckit::OutOfRange( msg.str(), Here() ); + throw_Exception( msg.str(), Here() ); } size_t Metadata::footprint() const { @@ -58,7 +57,7 @@ void Metadata::broadcast( Metadata& dest ) { void Metadata::broadcast( Metadata& dest, const size_t root ) { std::string buffer; - int buffer_size; + int buffer_size{0}; if ( atlas::mpi::comm().rank() == root ) { std::stringstream s; eckit::JSON json( s ); @@ -90,7 +89,7 @@ void Metadata::broadcast( Metadata& dest ) const { void Metadata::broadcast( Metadata& dest, const size_t root ) const { std::string buffer; - int buffer_size; + int buffer_size{0}; if ( atlas::mpi::comm().rank() == root ) { std::stringstream s; eckit::JSON json( s ); @@ -125,101 +124,130 @@ Metadata* atlas__Metadata__new() { } void atlas__Metadata__delete( Metadata* This ) { + ATLAS_ASSERT( This != nullptr, "Cannot access uninitialised atlas_Metadata" ); delete This; } void atlas__Metadata__set_int( Metadata* This, const char* name, int value ) { - ATLAS_ERROR_HANDLING( ASSERT( This != NULL ); This->set( std::string( name ), long( value ) ) ); + ATLAS_ASSERT( This != nullptr, "Cannot access uninitialised atlas_Metadata" ); + This->set( std::string( name ), long( value ) ); } void atlas__Metadata__set_long( Metadata* This, const char* name, long value ) { - ATLAS_ERROR_HANDLING( ASSERT( This != NULL ); This->set( std::string( name ), value ); ); + ATLAS_ASSERT( This != nullptr, "Cannot access uninitialised atlas_Metadata" ); + This->set( std::string( name ), value ); } void atlas__Metadata__set_float( Metadata* This, const char* name, float value ) { - ATLAS_ERROR_HANDLING( ASSERT( This != NULL ); This->set( std::string( name ), double( value ) ); ); + ATLAS_ASSERT( This != nullptr, "Cannot access uninitialised atlas_Metadata" ); + This->set( std::string( name ), double( value ) ); } void atlas__Metadata__set_double( Metadata* This, const char* name, double value ) { - ATLAS_ERROR_HANDLING( ASSERT( This != NULL ); This->set( std::string( name ), value ); ); + ATLAS_ASSERT( This != nullptr, "Cannot access uninitialised atlas_Metadata" ); + This->set( std::string( name ), value ); } void atlas__Metadata__set_string( Metadata* This, const char* name, const char* value ) { - ATLAS_ERROR_HANDLING( ASSERT( This != NULL ); This->set( std::string( name ), std::string( value ) ); ); + ATLAS_ASSERT( This != nullptr, "Cannot access uninitialised atlas_Metadata" ); + This->set( std::string( name ), std::string( value ) ); } void atlas__Metadata__set_array_int( Metadata* This, const char* name, int value[], int size ) { - ATLAS_ERROR_HANDLING( ASSERT( This != NULL ); std::vector v; v.assign( value, value + size ); - This->set( std::string( name ), v ); ); + ATLAS_ASSERT( This != nullptr, "Cannot access uninitialised atlas_Metadata" ); + std::vector v; + v.assign( value, value + size ); + This->set( std::string( name ), v ); } void atlas__Metadata__set_array_long( Metadata* This, const char* name, long value[], int size ) { - ATLAS_ERROR_HANDLING( ASSERT( This != NULL ); std::vector v; v.assign( value, value + size ); - This->set( std::string( name ), v ); ); + ATLAS_ASSERT( This != nullptr, "Cannot access uninitialised atlas_Metadata" ); + std::vector v; + v.assign( value, value + size ); + This->set( std::string( name ), v ); } void atlas__Metadata__set_array_float( Metadata* This, const char* name, float value[], int size ) { - ATLAS_ERROR_HANDLING( ASSERT( This != NULL ); std::vector v; v.assign( value, value + size ); - This->set( std::string( name ), v ); ); + ATLAS_ASSERT( This != nullptr, "Cannot access uninitialised atlas_Metadata" ); + std::vector v; + v.assign( value, value + size ); + This->set( std::string( name ), v ); } void atlas__Metadata__set_array_double( Metadata* This, const char* name, double value[], int size ) { - ATLAS_ERROR_HANDLING( ASSERT( This != NULL ); std::vector v; v.assign( value, value + size ); - This->set( std::string( name ), v ); ); + ATLAS_ASSERT( This != nullptr, "Cannot access uninitialised atlas_Metadata" ); + std::vector v; + v.assign( value, value + size ); + This->set( std::string( name ), v ); } int atlas__Metadata__get_int( Metadata* This, const char* name ) { - ATLAS_ERROR_HANDLING( ASSERT( This != NULL ); return This->get( std::string( name ) ) ); - return 0; + ATLAS_ASSERT( This != nullptr, "Cannot access uninitialised atlas_Metadata" ); + return This->get( std::string( name ) ); } long atlas__Metadata__get_long( Metadata* This, const char* name ) { - ATLAS_ERROR_HANDLING( ASSERT( This != NULL ); return This->get( std::string( name ) ); ); - return 0; + ATLAS_ASSERT( This != nullptr, "Cannot access uninitialised atlas_Metadata" ); + return This->get( std::string( name ) ); } float atlas__Metadata__get_float( Metadata* This, const char* name ) { - ATLAS_ERROR_HANDLING( ASSERT( This != NULL ); return This->get( std::string( name ) ); ); - return 0; + ATLAS_ASSERT( This != nullptr, "Cannot access uninitialised atlas_Metadata" ); + return This->get( std::string( name ) ); } double atlas__Metadata__get_double( Metadata* This, const char* name ) { - ATLAS_ERROR_HANDLING( ASSERT( This != NULL ); return This->get( std::string( name ) ); ); - return 0; + ATLAS_ASSERT( This != nullptr, "Cannot access uninitialised atlas_Metadata" ); + return This->get( std::string( name ) ); } void atlas__Metadata__get_string( Metadata* This, const char* name, char* output_str, int max_len ) { - ATLAS_ERROR_HANDLING( ASSERT( This != NULL ); std::string s = This->get( std::string( name ) ); - if ( s.size() > size_t( max_len ) ) { - std::stringstream msg; - msg << "Cannot copy string `" << s << "` of metadata `" << name - << "`" - "in buffer of length " - << max_len; - throw eckit::OutOfRange( msg.str(), Here() ); - } strcpy( output_str, s.c_str() ); - return ); - output_str = NULL; + ATLAS_ASSERT( This != nullptr, "Cannot access uninitialised atlas_Metadata" ); + std::string s = This->get( std::string( name ) ); + if ( s.size() > size_t( max_len ) ) { + std::stringstream msg; + msg << "Cannot copy string `" << s << "` of metadata `" << name + << "`" + "in buffer of length " + << max_len; + throw_Exception( msg.str(), Here() ); + } + strcpy( output_str, s.c_str() ); } void atlas__Metadata__get_array_int( Metadata* This, const char* name, int*& value, int& size, int& allocated ) { - ATLAS_ERROR_HANDLING( ASSERT( This != NULL ); - std::vector v = This->get>( std::string( name ) ); size = v.size(); - value = new int[size]; for ( size_t j = 0; j < v.size(); ++j ) value[j] = v[j]; - allocated = true; ); + ATLAS_ASSERT( This != nullptr, "Cannot access uninitialised atlas_Metadata" ); + std::vector v = This->get>( std::string( name ) ); + size = v.size(); + value = new int[size]; + for ( size_t j = 0; j < v.size(); ++j ) + value[j] = v[j]; + allocated = true; } void atlas__Metadata__get_array_long( Metadata* This, const char* name, long*& value, int& size, int& allocated ) { - ATLAS_ERROR_HANDLING( ASSERT( This != NULL ); - std::vector v = This->get>( std::string( name ) ); size = v.size(); - value = new long[size]; for ( size_t j = 0; j < v.size(); ++j ) value[j] = v[j]; - allocated = true; ); + ATLAS_ASSERT( This != nullptr, "Cannot access uninitialised atlas_Metadata" ); + std::vector v = This->get>( std::string( name ) ); + size = v.size(); + value = new long[size]; + for ( size_t j = 0; j < v.size(); ++j ) + value[j] = v[j]; + allocated = true; } void atlas__Metadata__get_array_float( Metadata* This, const char* name, float*& value, int& size, int& allocated ) { - ATLAS_ERROR_HANDLING( ASSERT( This != NULL ); - std::vector v = This->get>( std::string( name ) ); size = v.size(); - value = new float[size]; for ( size_t j = 0; j < v.size(); ++j ) value[j] = v[j]; - allocated = true; ); + ATLAS_ASSERT( This != nullptr, "Cannot access uninitialised atlas_Metadata" ); + std::vector v = This->get>( std::string( name ) ); + size = v.size(); + value = new float[size]; + for ( size_t j = 0; j < v.size(); ++j ) + value[j] = v[j]; + allocated = true; } void atlas__Metadata__get_array_double( Metadata* This, const char* name, double*& value, int& size, int& allocated ) { - ATLAS_ERROR_HANDLING( ASSERT( This != NULL ); - std::vector v = This->get>( std::string( name ) ); - size = v.size(); value = new double[size]; - for ( size_t j = 0; j < v.size(); ++j ) value[j] = v[j]; allocated = true; ); + ATLAS_ASSERT( This != nullptr, "Cannot access uninitialised atlas_Metadata" ); + std::vector v = This->get>( std::string( name ) ); + size = v.size(); + value = new double[size]; + for ( size_t j = 0; j < v.size(); ++j ) { + value[j] = v[j]; + } + allocated = true; } int atlas__Metadata__has( Metadata* This, const char* name ) { - ATLAS_ERROR_HANDLING( ASSERT( This != NULL ); return This->has( std::string( name ) ); ); - return 0; + ATLAS_ASSERT( This != nullptr, "Cannot access uninitialised atlas_Metadata" ); + return This->has( std::string( name ) ); } void atlas__Metadata__print( Metadata* This, std::ostream* channel ) { - ATLAS_ERROR_HANDLING( ASSERT( This != NULL ); ASSERT( channel != NULL ); *channel << *This; ); + ATLAS_ASSERT( This != nullptr, "Cannot access uninitialised atlas_Metadata" ); + ATLAS_ASSERT( channel != nullptr ); + *channel << *This; } void atlas__Metadata__json( Metadata* This, char*& json, int& size, int& allocated ) { diff --git a/src/atlas/util/Metadata.h b/src/atlas/util/Metadata.h index f8f10d7da..be62406ea 100644 --- a/src/atlas/util/Metadata.h +++ b/src/atlas/util/Metadata.h @@ -10,11 +10,10 @@ #pragma once +#include + #include "eckit/config/LocalConfiguration.h" #include "eckit/config/Parametrisation.h" -#include "eckit/utils/Hash.h" - -#include namespace atlas { namespace util { @@ -39,7 +38,7 @@ class Metadata : public eckit::LocalConfiguration { template ValueT get( const std::string& name ) const { ValueT value; - if ( not eckit::LocalConfiguration::get( name, value ) ) throw_exception( name ); + if ( not eckit::LocalConfiguration::get( name, value ) ) throw_not_found( name ); return value; } @@ -58,7 +57,7 @@ class Metadata : public eckit::LocalConfiguration { size_t footprint() const; private: - void throw_exception( const std::string& ) const; + [[noreturn]] void throw_not_found( const std::string& ) const; Metadata( const eckit::Value& ); }; diff --git a/src/atlas/util/MicroDeg.h b/src/atlas/util/MicroDeg.h index f5cb1c91c..7645ff9b1 100644 --- a/src/atlas/util/MicroDeg.h +++ b/src/atlas/util/MicroDeg.h @@ -16,7 +16,7 @@ namespace util { inline int microdeg( const double& deg ) { assert( deg < 2145. ); // Since INT_MAX == 2147483647 assert( deg > -2145. ); // Since INT_MIN == –2147483648 - return int( deg * 1.e6 + 0.5 ); + return static_cast( deg * 1.e6 + 0.5 ); } } // namespace util diff --git a/src/atlas/util/NormaliseLongitude.h b/src/atlas/util/NormaliseLongitude.h new file mode 100644 index 000000000..79b77e73a --- /dev/null +++ b/src/atlas/util/NormaliseLongitude.h @@ -0,0 +1,46 @@ +/* + * (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 + +/// @file NormaliseLongitude.h + +namespace atlas { + +class NormaliseLongitude { +public: + // Normalise longitude between (west - eps, east - eps ) with west = 0., east = 360. + constexpr NormaliseLongitude() : west_( -eps_ ), east_( 360. - eps_ ) {} + + // Normalise longitude between ( west-eps, east-eps ) with east = west + 360 + constexpr NormaliseLongitude( double west ) : west_( west - eps_ ), east_( west + 360. - eps_ ) {} + + // Normalise longitude between ( west-eps, east+eps ) + constexpr NormaliseLongitude( double west, double east ) : west_( west - eps_ ), east_( east + eps_ ) {} + + double operator()( double lon ) const { + while ( lon < west_ ) { + lon += 360.; + } + while ( lon > east_ ) { + lon -= 360.; + } + return lon; + } + +private: + const double west_; + const double east_; + +public: + static constexpr double eps_ = 1.e-11; +}; + +} // namespace atlas diff --git a/src/atlas/util/Object.cc b/src/atlas/util/Object.cc new file mode 100644 index 000000000..9ac33b4f4 --- /dev/null +++ b/src/atlas/util/Object.cc @@ -0,0 +1,11 @@ +/* + * (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/util/Object.h" diff --git a/src/atlas/util/Object.h b/src/atlas/util/Object.h new file mode 100644 index 000000000..2a9d03705 --- /dev/null +++ b/src/atlas/util/Object.h @@ -0,0 +1,21 @@ +/* + * (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 "eckit/memory/Owned.h" + +namespace atlas { +namespace util { + +class Object : public eckit::Owned {}; + +} // namespace util +} // namespace atlas diff --git a/src/atlas/util/ObjectHandle.cc b/src/atlas/util/ObjectHandle.cc new file mode 100644 index 000000000..15f6d0d53 --- /dev/null +++ b/src/atlas/util/ObjectHandle.cc @@ -0,0 +1,61 @@ +/* + * (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 "atlas/runtime/Log.h" +#include "atlas/util/Object.h" +#include "atlas/util/ObjectHandle.h" + +namespace atlas { +namespace util { + +//---------------------------------------------------------------------------------------------------------------------- + +int ObjectHandleBase::owners() const { + return static_cast( object_->owners() ); +} + +void ObjectHandleBase::release() { + object_->lock(); + object_->detach(); /* lock/unlock in detach() isn't sufficient, else there is race + condition on owners() */ + + if ( object_->owners() == 0 ) { + object_->unlock(); + delete object_; + object_ = nullptr; + return; + } + object_->unlock(); + object_ = nullptr; +} + +void ObjectHandleBase::assign( const ObjectHandleBase& other ) { + assign( other.object_ ); +} + +void ObjectHandleBase::assign( const Object* other ) { + if ( object_ ) { release(); } + + object_ = const_cast( other ); + + attach(); +} + + +void ObjectHandleBase::attach() { + if ( !null() ) object_->attach(); +} + +// ------------------------------------------------------------------ + +} // namespace util +} // namespace atlas diff --git a/src/atlas/util/ObjectHandle.h b/src/atlas/util/ObjectHandle.h new file mode 100644 index 000000000..975847314 --- /dev/null +++ b/src/atlas/util/ObjectHandle.h @@ -0,0 +1,75 @@ +/* + * (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 atlas { +namespace util { + +class Object; + +class ObjectHandleBase { +public: + ObjectHandleBase() = default; + ObjectHandleBase( const Object* object ) : object_( const_cast( object ) ) { attach(); } + + virtual ~ObjectHandleBase() { + if ( object_ ) { release(); } + } + + const ObjectHandleBase& operator=( const ObjectHandleBase& other ) { + if ( object_ != other.object_ ) { assign( other ); } + return *this; + } + + operator bool() const { return object_ != nullptr; } + + void reset( const Object* other ) { + if ( object_ != other ) { assign( other ); } + } + + int owners() const; + +private: + void release(); + + void assign( const ObjectHandleBase& other ); + + void assign( const Object* other ); + + void attach(); + + bool null() const { return ( object_ == nullptr ); } + +protected: + Object* object_{nullptr}; +}; + +template +class ObjectHandle : public ObjectHandleBase { +public: + using Implementation = T; + using Handle = ObjectHandle; + +public: + T* get() { return reinterpret_cast( object_ ); } + const T* get() const { return reinterpret_cast( object_ ); } + ObjectHandle() = default; + ObjectHandle( const T* object ) : ObjectHandleBase( reinterpret_cast( object ) ) {} + ObjectHandle( const ObjectHandle& handle ) : ObjectHandleBase( reinterpret_cast( handle.get() ) ) {} + const T* operator->() const { return get(); } + T* operator->() { return get(); } + const T& operator*() const { return *get(); } + T& operator*() { return *get(); } + void reset( const T* object ) { ObjectHandleBase::reset( reinterpret_cast( object ) ); } +}; + +} // namespace util +} // namespace atlas diff --git a/src/atlas/mesh/detail/PeriodicTransform.h b/src/atlas/util/PeriodicTransform.h similarity index 84% rename from src/atlas/mesh/detail/PeriodicTransform.h rename to src/atlas/util/PeriodicTransform.h index 7b84d35a4..5f4b98fc2 100644 --- a/src/atlas/mesh/detail/PeriodicTransform.h +++ b/src/atlas/util/PeriodicTransform.h @@ -10,11 +10,11 @@ #pragma once +#include #include "atlas/util/LonLatMicroDeg.h" namespace atlas { -namespace mesh { -namespace detail { +namespace util { class PeriodicTransform { protected: @@ -22,6 +22,7 @@ class PeriodicTransform { public: PeriodicTransform() { x_translation_ = 360.; } + PeriodicTransform( const double& translation ) { x_translation_ = translation; } void operator()( double source[2], double dest[2], double direction, double scale = 1. ) const { dest[0] = source[0] + direction * x_translation_ * scale; @@ -47,8 +48,12 @@ class PeriodicTransform { inplace.set_lon( inplace.lon() + direction * util::microdeg( x_translation_ ) ); // inplace.set_lat( inplace.lat() ); null operation } + + void operator()( std::array& inplace ) const { + inplace[0] = inplace[0] + x_translation_; + // inplace[1] = inplace[1]; null operation + } }; -} // namespace detail -} // namespace mesh +} // namespace util } // namespace atlas diff --git a/src/atlas/util/Point.cc b/src/atlas/util/Point.cc new file mode 100644 index 000000000..3d60455a8 --- /dev/null +++ b/src/atlas/util/Point.cc @@ -0,0 +1,31 @@ +/* + * (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/util/Point.h" +#include "atlas/util/NormaliseLongitude.h" + +namespace atlas { + +void PointLonLat::normalise() { + constexpr NormaliseLongitude normalize_from_zero; + lon() = normalize_from_zero( lon() ); +} + +void PointLonLat::normalise( double west ) { + NormaliseLongitude normalize_from_west( west ); + lon() = normalize_from_west( lon() ); +} + +void PointLonLat::normalise( double west, double east ) { + NormaliseLongitude normalize_between_west_and_east( west, east ); + lon() = normalize_between_west_and_east( lon() ); +} + +} // namespace atlas diff --git a/src/atlas/util/Point.h b/src/atlas/util/Point.h index c5ba433bb..e8ffc8b14 100644 --- a/src/atlas/util/Point.h +++ b/src/atlas/util/Point.h @@ -1,3 +1,13 @@ +/* + * (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 /// @file Point.h @@ -117,6 +127,12 @@ class PointLonLat : public Point2 { x_[1] *= a; return *this; } + + void normalise(); + + void normalise( double west ); + + void normalise( double west, double east ); }; } // namespace atlas diff --git a/src/atlas/util/Polygon.cc b/src/atlas/util/Polygon.cc index ba4f24edf..d578ecd41 100644 --- a/src/atlas/util/Polygon.cc +++ b/src/atlas/util/Polygon.cc @@ -13,10 +13,12 @@ #include #include -#include "eckit/exception/Exceptions.h" #include "eckit/types/FloatCompare.h" +#include "atlas/array.h" #include "atlas/mesh/Nodes.h" +#include "atlas/runtime/Exception.h" +#include "atlas/runtime/Trace.h" #include "atlas/util/CoordinateEnums.h" #include "atlas/util/Polygon.h" @@ -38,12 +40,13 @@ double cross_product_analog( const PointLonLat& A, const PointLonLat& B, const P Polygon::Polygon() {} Polygon::Polygon( const Polygon::edge_set_t& edges ) { + ATLAS_TRACE(); // get external edges by attempting to remove reversed edges, if any edge_set_t extEdges; for ( const edge_t& e : edges ) { if ( !extEdges.erase( e.reverse() ) ) { extEdges.insert( e ); } } - ASSERT( extEdges.size() >= 2 ); + ATLAS_ASSERT( extEdges.size() >= 2 ); // set one polygon cycle, by picking next edge with first node same as second // node of last edge @@ -56,7 +59,7 @@ Polygon::Polygon( const Polygon::edge_set_t& edges ) { push_back( e->second ); extEdges.erase( *e ); } - ASSERT( front() == back() ); + ATLAS_ASSERT( front() == back() ); // exhaust remaining edges, should represent additional cycles, if any while ( !extEdges.empty() ) { @@ -74,7 +77,7 @@ Polygon& Polygon::operator+=( const Polygon& other ) { // polygon can have multiple cycles, but must be connected graphs // Note: a 'cycle' is handled by repeating the indices, excluding (repeated) // last index - ASSERT( other.front() == other.back() ); + ATLAS_ASSERT( other.front() == other.back() ); const difference_type N = difference_type( other.size() ) - 1; container_t cycle( 2 * size_t( N ) ); @@ -89,7 +92,7 @@ Polygon& Polygon::operator+=( const Polygon& other ) { } } - throw eckit::AssertionFailed( "Polygon: could not merge polygons, they are not connected", Here() ); + throw_AssertionFailed( "Polygon: could not merge polygons, they are not connected", Here() ); } void Polygon::print( std::ostream& s ) const { @@ -104,8 +107,8 @@ void Polygon::print( std::ostream& s ) const { //------------------------------------------------------------------------------------------------------ PolygonCoordinates::PolygonCoordinates( const Polygon& poly, const atlas::Field& lonlat, bool removeAlignedPoints ) { - ASSERT( poly.size() > 2 ); - ASSERT( poly.front() == poly.back() ); + ATLAS_ASSERT( poly.size() > 2 ); + ATLAS_ASSERT( poly.front() == poly.back() ); // Point coordinates // - use a bounding box to quickly discard points, @@ -140,12 +143,12 @@ PolygonCoordinates::PolygonCoordinates( const Polygon& poly, const atlas::Field& coordinates_.push_back( A ); } - ASSERT( coordinates_.size() == poly.size() - nb_removed_points_due_to_alignment ); + ATLAS_ASSERT( coordinates_.size() == poly.size() - nb_removed_points_due_to_alignment ); } PolygonCoordinates::PolygonCoordinates( const std::vector& points ) : coordinates_( points ) { - ASSERT( coordinates_.size() > 2 ); - ASSERT( eckit::geometry::points_equal( coordinates_.front(), coordinates_.back() ) ); + ATLAS_ASSERT( coordinates_.size() > 2 ); + ATLAS_ASSERT( eckit::geometry::points_equal( coordinates_.front(), coordinates_.back() ) ); coordinatesMin_ = coordinates_.front(); coordinatesMax_ = coordinatesMin_; diff --git a/src/atlas/util/Rotation.cc b/src/atlas/util/Rotation.cc index 1ea3ed83c..b30ef0972 100644 --- a/src/atlas/util/Rotation.cc +++ b/src/atlas/util/Rotation.cc @@ -18,9 +18,6 @@ #include "atlas/util/UnitSphere.h" #include "eckit/config/Parametrisation.h" -// Temporary option to activate implementation by RMI during ESCAPE -#define OLD_IMPLEMENTATION 0 - namespace atlas { namespace util { @@ -104,10 +101,6 @@ Rotation::Rotation( const PointLonLat& south_pole, double rotation_angle ) { } Rotation::Rotation( const eckit::Parametrisation& p ) { -#if OLD_IMPLEMENTATION - npole_ = {0., 90.}; -#endif - // get rotation angle p.get( "rotation_angle", angle_ ); @@ -199,11 +192,6 @@ inline PointXYZ rotate_geocentric( const PointXYZ& p, const RotationMatrix& R ) } void Rotation::rotate( double crd[] ) const { -#if OLD_IMPLEMENTATION - rotate_old( crd ); - return; -#endif - if ( !rotated_ ) { return; } else if ( rotation_angle_only_ ) { crd[LON] -= angle_; @@ -224,11 +212,6 @@ void Rotation::rotate( double crd[] ) const { } void Rotation::unrotate( double crd[] ) const { -#if OLD_IMPLEMENTATION - unrotate_old( crd ); - return; -#endif - if ( !rotated_ ) { return; } else if ( rotation_angle_only_ ) { crd[LON] += angle_; diff --git a/src/atlas/util/SphericalPolygon.cc b/src/atlas/util/SphericalPolygon.cc index 2b1c036e7..4c8ef3e80 100644 --- a/src/atlas/util/SphericalPolygon.cc +++ b/src/atlas/util/SphericalPolygon.cc @@ -15,6 +15,7 @@ #include "eckit/types/FloatCompare.h" +#include "atlas/runtime/Exception.h" #include "atlas/util/CoordinateEnums.h" #include "atlas/util/SphericalPolygon.h" @@ -29,7 +30,9 @@ SphericalPolygon::SphericalPolygon( const Polygon& poly, const atlas::Field& lon SphericalPolygon::SphericalPolygon( const std::vector& points ) : PolygonCoordinates( points ) {} bool SphericalPolygon::contains( const PointLonLat& P ) const { - ASSERT( coordinates_.size() >= 2 ); + using eckit::types::is_approximately_equal; + + ATLAS_ASSERT( coordinates_.size() >= 2 ); // check first bounding box if ( coordinatesMax_.lon() <= P.lon() || P.lon() < coordinatesMin_.lon() ) { return false; } @@ -47,10 +50,18 @@ bool SphericalPolygon::contains( const PointLonLat& P ) const { const bool BPA = ( B.lon() <= P.lon() && P.lon() < A.lon() ); if ( APB != BPA ) { - const double lat = util::Earth::greatCircleLatitudeGivenLongitude( A, B, P.lon() ); - - ASSERT( !std::isnan( lat ) ); - if ( eckit::types::is_approximately_equal( P.lat(), lat ) ) { return true; } + const double lat = [&] { + if ( is_approximately_equal( A.lat(), B.lat() ) && + is_approximately_equal( std::abs( A.lat() ), 90. ) ) { + return A.lat(); + } + else { + return util::Earth::greatCircleLatitudeGivenLongitude( A, B, P.lon() ); + } + }(); + + ATLAS_ASSERT( !std::isnan( lat ) ); + if ( is_approximately_equal( P.lat(), lat ) ) { return true; } wn += ( P.lat() > lat ? -1 : 1 ) * ( APB ? -1 : 1 ); } diff --git a/src/atlas/util/Unique.cc b/src/atlas/util/Unique.cc new file mode 100644 index 000000000..40755d1a0 --- /dev/null +++ b/src/atlas/util/Unique.cc @@ -0,0 +1,41 @@ +/* + * (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/util/Unique.h" +#include "atlas/util/PeriodicTransform.h" + +namespace atlas { +namespace util { + +uidx_t unique_lonlat( const double& lon, const double& lat, const PeriodicTransform& transform ) { + std::array lonlat{lon, lat}; + transform( lonlat ); + return unique_lonlat( lonlat ); +} + + +uidx_t UniqueLonLat::operator()( const mesh::Connectivity::Row& elem_nodes, const PeriodicTransform& transform ) const { + std::array centroid; + centroid[LON] = 0.; + centroid[LAT] = 0.; + size_t npts = elem_nodes.size(); + for ( size_t jnode = 0; jnode < npts; ++jnode ) { + centroid[LON] += lonlat( elem_nodes( jnode ), LON ); + centroid[LAT] += lonlat( elem_nodes( jnode ), LAT ); + } + centroid[LON] /= static_cast( npts ); + centroid[LAT] /= static_cast( npts ); + transform( centroid ); + return unique_lonlat( centroid ); +} + + +} // namespace util +} // namespace atlas diff --git a/src/atlas/util/Unique.h b/src/atlas/util/Unique.h index 4c57d1136..2197ecfd5 100644 --- a/src/atlas/util/Unique.h +++ b/src/atlas/util/Unique.h @@ -11,7 +11,6 @@ #pragma once #include -#include #include "atlas/array/ArrayView.h" #include "atlas/array/IndexView.h" #include "atlas/array/LocalView.h" @@ -24,10 +23,13 @@ #include "atlas/util/CoordinateEnums.h" #include "atlas/util/LonLatMicroDeg.h" #include "atlas/util/MicroDeg.h" +#include "atlas/util/PeriodicTransform.h" namespace atlas { namespace util { +class PeriodicTransform; + // ---------------------------------------------------------------------------- /// @brief Compute unique positive index from lon-lat coordinates in @@ -50,6 +52,11 @@ uidx_t unique_lonlat( const LonLatMicroDeg& ); uidx_t unique_lonlat( const double& lon, const double& lat ); uidx_t unique_lonlat( const double lonlat[] ); uidx_t unique_lonlat( const array::LocalView& lonlat ); +uidx_t unique_lonlat( const std::array& lonlat ); + +/// @brief Compute unique positive index from lon-lat coordinates in degrees +/// @return uidx_t Return type depends on ATLAS_BITS_GLOBAL [32/64] bits +uidx_t unique_lonlat( const double& lon, const double& lat, const PeriodicTransform& ); /// @brief Compute unique positive index from lon-lat coordinates in degrees. /// coordinates are stored in order: @@ -66,7 +73,7 @@ class UniqueLonLat { /// @brief Constructor, needs nodes functionspace to cache the lonlat field UniqueLonLat( const mesh::Nodes& ); - /// @brief Constructor, needs nodes functionspace to cache the lonlat field + /// @brief Constructor UniqueLonLat( const Mesh& ); /// @brief Compute unique positive index of a node defined by node index. @@ -79,6 +86,12 @@ class UniqueLonLat { /// @return uidx_t Return type depends on ATLAS_BITS_GLOBAL [32/64] bits uidx_t operator()( const mesh::Connectivity::Row& elem_nodes ) const; + /// @brief Compute unique positive index of element defined by node indices. + /// The assumption is that the elements exist in a lon-lat domain and don't + // degenerate to a line. + /// @return uidx_t Return type depends on ATLAS_BITS_GLOBAL [32/64] bits + uidx_t operator()( const mesh::Connectivity::Row& elem_nodes, const PeriodicTransform& transform ) const; + /// @brief Compute unique positive index of element defined by node indices. /// The assumption is that the elements exist in a lon-lat domain and don't // degenerate to a line. @@ -90,7 +103,7 @@ class UniqueLonLat { private: const mesh::Nodes* nodes; - array::ArrayView xy; + array::ArrayView lonlat; }; // ---------------------------------------------------------------------------- @@ -164,14 +177,16 @@ inline uidx_t unique_lonlat( const double lonlat[] ) { return detail::uniqueT( microdeg( lonlat[LON] ), microdeg( lonlat[LAT] ) ); } +inline uidx_t unique_lonlat( const std::array& lonlat ) { + return detail::uniqueT( microdeg( lonlat[LON] ), microdeg( lonlat[LAT] ) ); +} + inline uidx_t unique_lonlat( const array::LocalView& lonlat ) { return unique_lonlat( lonlat.data() ); } inline uidx_t unique_lonlat( const double elem_lonlat[], size_t npts ) { - double centroid[2]; - centroid[LON] = 0.; - centroid[LAT] = 0.; + std::array centroid{0., 0.}; for ( size_t jnode = 0; jnode < npts; ++jnode ) { centroid[LON] += elem_lonlat[jnode * 2 + LON]; centroid[LAT] += elem_lonlat[jnode * 2 + LAT]; @@ -179,68 +194,53 @@ inline uidx_t unique_lonlat( const double elem_lonlat[], size_t npts ) { centroid[LON] /= static_cast( npts ); centroid[LAT] /= static_cast( npts ); - // FIXME: this should be `unique_lonlat( centroid )` - // but this causes some weird behavior in parallelisation - return unique_lonlat( centroid[LON], centroid[LAT] ); - // return detail::unique32( microdeg(centroid[LON]), microdeg(centroid[LAT]) - // ); + return unique_lonlat( centroid ); } inline UniqueLonLat::UniqueLonLat( const Mesh& mesh ) : nodes( &mesh.nodes() ), - xy( array::make_view( nodes->xy() ) ) { - ASSERT( mesh.projection().units() == "degrees" ); + lonlat( array::make_view( nodes->lonlat() ) ) { update(); } inline UniqueLonLat::UniqueLonLat( const mesh::Nodes& _nodes ) : nodes( &_nodes ), - xy( array::make_view( nodes->xy() ) ) { + lonlat( array::make_view( nodes->lonlat() ) ) { update(); } inline uidx_t UniqueLonLat::operator()( int node ) const { - return unique_lonlat( xy( node, XX ), xy( node, YY ) ); + return unique_lonlat( lonlat( node, LON ), lonlat( node, LAT ) ); } inline uidx_t UniqueLonLat::operator()( const mesh::Connectivity::Row& elem_nodes ) const { - double centroid[2]; - centroid[XX] = 0.; - centroid[YY] = 0.; - size_t npts = elem_nodes.size(); + std::array centroid{0., 0.}; + size_t npts = elem_nodes.size(); for ( size_t jnode = 0; jnode < npts; ++jnode ) { - centroid[XX] += xy( elem_nodes( jnode ), XX ); - centroid[YY] += xy( elem_nodes( jnode ), YY ); + centroid[LON] += lonlat( elem_nodes( jnode ), LON ); + centroid[LAT] += lonlat( elem_nodes( jnode ), LAT ); } - centroid[XX] /= static_cast( npts ); - centroid[YY] /= static_cast( npts ); + centroid[LON] /= static_cast( npts ); + centroid[LAT] /= static_cast( npts ); - // FIXME: this should be `unique_lonlat( centroid )` - // but this causes some weird behavior in parallelisation - return unique_lonlat( centroid[XX], centroid[YY] ); - // return detail::unique32( microdeg(centroid[XX]), microdeg(centroid[YY]) ); + return unique_lonlat( centroid ); } inline uidx_t UniqueLonLat::operator()( const int elem_nodes[], size_t npts ) const { - double centroid[2]; - centroid[XX] = 0.; - centroid[YY] = 0.; + std::array centroid{0., 0.}; + for ( size_t jnode = 0; jnode < npts; ++jnode ) { - centroid[XX] += xy( elem_nodes[jnode], XX ); - centroid[YY] += xy( elem_nodes[jnode], YY ); + centroid[LON] += lonlat( elem_nodes[jnode], LON ); + centroid[LAT] += lonlat( elem_nodes[jnode], LAT ); } - centroid[XX] /= static_cast( npts ); - centroid[YY] /= static_cast( npts ); - - // FIXME: this should be `unique_lonlat( centroid )` - // but this causes some weird behavior in parallelisation + centroid[LON] /= static_cast( npts ); + centroid[LAT] /= static_cast( npts ); - return unique_lonlat( centroid[XX], centroid[YY] ); - // return detail::unique32( microdeg(centroid[XX]), microdeg(centroid[YY]) ); + return unique_lonlat( centroid ); } inline void UniqueLonLat::update() { - xy = array::make_view( nodes->xy() ); + lonlat = array::make_view( nodes->lonlat() ); } // ---------------------------------------------------------------------------- diff --git a/src/atlas/util/UnitSphere.h b/src/atlas/util/UnitSphere.h index de3889222..c1458468f 100644 --- a/src/atlas/util/UnitSphere.h +++ b/src/atlas/util/UnitSphere.h @@ -1,11 +1,11 @@ /* - * (C) Copyright 1996-2017 ECMWF. + * (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. + * granted to it by virtue of its status as an intergovernmental organisation + * nor does it submit to any jurisdiction. */ #pragma once diff --git a/src/atlas/util/detail/BlackMagic.h b/src/atlas/util/detail/BlackMagic.h index 9105643fd..2b3b65e4b 100644 --- a/src/atlas/util/detail/BlackMagic.h +++ b/src/atlas/util/detail/BlackMagic.h @@ -1,3 +1,13 @@ +/* + * (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 // This file contains preprocessor black magic. It contains macros that diff --git a/src/atlas/util/detail/Cache.h b/src/atlas/util/detail/Cache.h index 828343ec4..2c7c9f08c 100644 --- a/src/atlas/util/detail/Cache.h +++ b/src/atlas/util/detail/Cache.h @@ -13,9 +13,8 @@ #include #include -#include "eckit/memory/SharedPtr.h" - #include "atlas/runtime/Log.h" +#include "atlas/util/ObjectHandle.h" namespace atlas { namespace util { @@ -29,11 +28,13 @@ class Cache { Cache( const std::string& name ) : name_( name ) {} - eckit::SharedPtr get_or_create( const key_type& key, const creator_type& creator ) { + virtual ~Cache() {} + + ObjectHandle get_or_create( const key_type& key, const creator_type& creator ) { std::lock_guard guard( lock_ ); auto it = map_.find( key ); if ( it != map_.end() ) { - eckit::SharedPtr value = it->second; + ObjectHandle value = it->second; if ( value ) { Log::debug() << "Key \"" << key << "\" was found in cache \"" << name_ << "\"" << std::endl; return value; @@ -44,7 +45,7 @@ class Cache { } } Log::debug() << "Key \"" << key << "\" not found in cache \"" << name_ << "\" , creating new" << std::endl; - eckit::SharedPtr value( creator() ); + ObjectHandle value( creator() ); map_[key] = value; return value; } @@ -63,7 +64,7 @@ class Cache { private: std::string name_; std::mutex lock_; - std::map> map_; + std::map> map_; }; } // namespace util diff --git a/src/atlas/util/detail/Debug.h b/src/atlas/util/detail/Debug.h index 39638f967..a29d85881 100644 --- a/src/atlas/util/detail/Debug.h +++ b/src/atlas/util/detail/Debug.h @@ -1,3 +1,15 @@ +/* + * (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 "eckit/config/Resource.h" #include "atlas/field.h" diff --git a/src/atlas_acc_support/atlas_acc_map_data.c b/src/atlas_acc_support/atlas_acc_map_data.c index c8567aa39..e9a8ac8b9 100644 --- a/src/atlas_acc_support/atlas_acc_map_data.c +++ b/src/atlas_acc_support/atlas_acc_map_data.c @@ -1,3 +1,14 @@ +/* + * (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 needs to be compiled with an OpenACC capable C compiler that is // compatible with the Fortran compiler diff --git a/src/atlas_f/CMakeLists.txt b/src/atlas_f/CMakeLists.txt index e07d5a8fe..6aaf20f36 100644 --- a/src/atlas_f/CMakeLists.txt +++ b/src/atlas_f/CMakeLists.txt @@ -7,9 +7,12 @@ # does it submit to any jurisdiction. configure_file( ${CMAKE_CURRENT_SOURCE_DIR}/atlas_f.h.in - ${CMAKE_CURRENT_BINARY_DIR}/../atlas/atlas_f.h ) + ${CMAKE_CURRENT_BINARY_DIR}/../atlas/atlas_f.h @ONLY ) + +execute_process( COMMAND ${CMAKE_COMMAND} -E create_symlink ${CMAKE_CURRENT_SOURCE_DIR}/atlas_f.fypp ${CMAKE_CURRENT_BINARY_DIR}/../atlas/atlas_f.fypp) install( FILES + ${CMAKE_CURRENT_SOURCE_DIR}/atlas_f.fypp ${CMAKE_CURRENT_BINARY_DIR}/../atlas/atlas_f.h DESTINATION ${INSTALL_INCLUDE_DIR}/atlas ) @@ -37,70 +40,30 @@ function(generate_fortran_bindings output filename) set( _PAR_MODULE "atlas_${base}_c_binding" ) endif() + set( FINT32 "integer(c_int)" ) + set( FINT64 "integer(c_long)" ) + set( F_GIDX ${FINT${ATLAS_BITS_GLOBAL}} ) + set( F_IDX ${FINT${ATLAS_BITS_LOCAL}} ) + add_custom_command( OUTPUT ${outfile} - COMMAND ${PYTHON_EXECUTABLE} ${PROJECT_SOURCE_DIR}/tools/c2f.py ${CMAKE_CURRENT_SOURCE_DIR}/${filename} -o ${outfile} -m ${_PAR_MODULE} + COMMAND ${PYTHON_EXECUTABLE} ${PROJECT_SOURCE_DIR}/tools/c2f.py ${CMAKE_CURRENT_SOURCE_DIR}/${filename} + -o ${outfile} -m ${_PAR_MODULE} + -t '{"idx_t":"${F_IDX}","gidx_t":"${F_GIDX}"}' DEPENDS ${filename} ) set_source_files_properties(${outfile} PROPERTIES GENERATED TRUE) endfunction() -set( PYTHON_VERSION "${PYTHON_VERSION_MAJOR}.${PYTHON_VERSION_MINOR}.${PYTHON_VERSION_PATCH}") -set( PYTHON_REQUIRED_VERSION 2.7.8 ) -if( PYTHON_VERSION VERSION_LESS ${PYTHON_REQUIRED_VERSION} ) - ecbuild_warn("Python version ${PYTHON_VERSION} is inadequate to use Fortran preprocessor 'fypp'." - "Required version is ${PYTHON_REQUIRED_VERSION}. No problem, previously preprocessed files will be used." - "Just be aware that these will not be updated." ) - - function(preprocess_fypp output filename) - - set( options "" ) - set( single_value_args OUTPUT ) - set( multi_value_args "" ) - cmake_parse_arguments( _PAR "${options}" "${single_value_args}" "${multi_value_args}" ${_FIRST_ARG} ${ARGN} ) - - get_filename_component(base ${filename} NAME_WE) - set(base_abs ${CMAKE_CURRENT_SOURCE_DIR}/${base}) - set(outfile ${CMAKE_CURRENT_SOURCE_DIR}/autogenerated/${base}_fypp.F90) - - if( _PAR_OUTPUT ) - set(outfile ${_PAR_OUTPUT}) - endif() - set(${output} ${${output}} ${outfile} PARENT_SCOPE) - endfunction() - -else() - - function(preprocess_fypp output filename) - - set( options "" ) - set( single_value_args OUTPUT ) - set( multi_value_args "" ) - cmake_parse_arguments( _PAR "${options}" "${single_value_args}" "${multi_value_args}" ${_FIRST_ARG} ${ARGN} ) - - get_filename_component(base ${filename} NAME_WE) - set(base_abs ${CMAKE_CURRENT_SOURCE_DIR}/${base}) - set(outfile ${CMAKE_CURRENT_SOURCE_DIR}/autogenerated/${base}_fypp.F90) - # set(outfile ${CMAKE_CURRENT_BINARY_DIR}/${filename}) - - if( _PAR_OUTPUT ) - set(outfile ${_PAR_OUTPUT}) - endif() - set(${output} ${${output}} ${outfile} PARENT_SCOPE) - - add_custom_command( - OUTPUT ${outfile} - COMMAND ${PYTHON_EXECUTABLE} ${PROJECT_SOURCE_DIR}/tools/fypp -l 132 -p ${CMAKE_CURRENT_SOURCE_DIR}/${filename} ${outfile} - DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/${filename} ) - set_source_files_properties(${outfile} PROPERTIES GENERATED TRUE) - endfunction() - -endif() - generate_fortran_bindings(FORTRAN_BINDINGS ../atlas/grid.h) generate_fortran_bindings(FORTRAN_BINDINGS ../atlas/grid/detail/grid/Structured.h MODULE atlas_grid_Structured_c_binding OUTPUT grid_Structured_c_binding.f90 ) -generate_fortran_bindings(FORTRAN_BINDINGS ../atlas/grid/Distribution.h) +generate_fortran_bindings(FORTRAN_BINDINGS ../atlas/grid/detail/distribution/DistributionImpl.h + MODULE atlas_distribution_c_binding + OUTPUT distribution_c_binding.f90 ) +generate_fortran_bindings(FORTRAN_BINDINGS ../atlas/grid/detail/vertical/VerticalInterface.h + MODULE atlas_vertical_c_binding + OUTPUT vertical_c_binding.f90 ) generate_fortran_bindings(FORTRAN_BINDINGS ../atlas/grid/Partitioner.h) generate_fortran_bindings(FORTRAN_BINDINGS ../atlas/mesh/detail/MeshIntf.h MODULE atlas_mesh_c_binding @@ -116,24 +79,28 @@ generate_fortran_bindings(FORTRAN_BINDINGS ../atlas/mesh/actions/BuildHalo.h) generate_fortran_bindings(FORTRAN_BINDINGS ../atlas/mesh/actions/BuildEdges.h) generate_fortran_bindings(FORTRAN_BINDINGS ../atlas/mesh/actions/BuildDualMesh.h) generate_fortran_bindings(FORTRAN_BINDINGS ../atlas/mesh/actions/WriteLoadBalanceReport.h) -generate_fortran_bindings(FORTRAN_BINDINGS ../atlas/meshgenerator/MeshGenerator.h) +generate_fortran_bindings(FORTRAN_BINDINGS ../atlas/meshgenerator/detail/MeshGeneratorInterface.h + MODULE atlas_meshgenerator_c_binding + OUTPUT meshgenerator_c_binding.f90 ) generate_fortran_bindings(FORTRAN_BINDINGS ../atlas/output/Output.h) generate_fortran_bindings(FORTRAN_BINDINGS ../atlas/output/Gmsh.h MODULE atlas_output_gmsh_c_binding OUTPUT outout_Gmsh_c_binding.f90) generate_fortran_bindings(FORTRAN_BINDINGS ../atlas/field/State.h) -generate_fortran_bindings(FORTRAN_BINDINGS ../atlas/field/detail/FieldImpl.h +generate_fortran_bindings(FORTRAN_BINDINGS ../atlas/field/detail/FieldInterface.h MODULE atlas_field_c_binding OUTPUT field_c_binding.f90 ) generate_fortran_bindings(FORTRAN_BINDINGS ../atlas/field/FieldSet.h) -generate_fortran_bindings(FORTRAN_BINDINGS ../atlas/functionspace/FunctionSpace.h) +generate_fortran_bindings(FORTRAN_BINDINGS ../atlas/functionspace/detail/FunctionSpaceInterface.h + MODULE atlas_functionspace_c_binding + OUTPUT functionspace_c_binding.f90 ) generate_fortran_bindings(FORTRAN_BINDINGS ../atlas/functionspace/Spectral.h MODULE atlas_functionspace_Spectral_c_binding OUTPUT functionspace_Spectral_c_binding.f90 ) -generate_fortran_bindings(FORTRAN_BINDINGS ../atlas/functionspace/StructuredColumns.h +generate_fortran_bindings(FORTRAN_BINDINGS ../atlas/functionspace/detail/StructuredColumnsInterface.h MODULE atlas_functionspace_StructuredColumns_c_binding OUTPUT functionspace_StructuredColumns_c_binding.f90 ) -generate_fortran_bindings(FORTRAN_BINDINGS ../atlas/functionspace/NodeColumnsInterface.h +generate_fortran_bindings(FORTRAN_BINDINGS ../atlas/functionspace/detail/NodeColumnsInterface.h MODULE atlas_functionspace_NodeColumns_c_binding OUTPUT functionspace_NodeColumns_c_binding.f90) generate_fortran_bindings(FORTRAN_BINDINGS ../atlas/functionspace/EdgeColumns.h @@ -146,27 +113,22 @@ generate_fortran_bindings(FORTRAN_BINDINGS ../atlas/numerics/fvm/Method.h MODULE atlas_fvm_method_c_binding OUTPUT fvm_method_c_binding.f90 ) generate_fortran_bindings(FORTRAN_BINDINGS ../atlas/interpolation/Interpolation.h - MODULE atlas_interpolation_c_binding - OUTPUT interpolation_c_binding.f90 ) + MODULE atlas_interpolation_c_binding + OUTPUT interpolation_c_binding.f90 ) generate_fortran_bindings(FORTRAN_BINDINGS ../atlas/trans/ifs/TransIFS.h - MODULE atlas_trans_c_binding - OUTPUT trans_c_binding.f90 ) + MODULE atlas_trans_c_binding + OUTPUT trans_c_binding.f90 ) +generate_fortran_bindings(FORTRAN_BINDINGS ../atlas/util/Allocate.h) generate_fortran_bindings(FORTRAN_BINDINGS ../atlas/util/Metadata.h) generate_fortran_bindings(FORTRAN_BINDINGS ../atlas/util/Config.h) generate_fortran_bindings(FORTRAN_BINDINGS ../atlas/output/detail/GmshIO.h) generate_fortran_bindings(FORTRAN_BINDINGS ../atlas/parallel/HaloExchange.h) generate_fortran_bindings(FORTRAN_BINDINGS ../atlas/parallel/GatherScatter.h) generate_fortran_bindings(FORTRAN_BINDINGS ../atlas/parallel/Checksum.h) -generate_fortran_bindings(FORTRAN_BINDINGS ../atlas/runtime/ErrorHandling.h) generate_fortran_bindings(FORTRAN_BINDINGS internals/atlas_read_file.h) generate_fortran_bindings(FORTRAN_BINDINGS internals/Library.h) +generate_fortran_bindings(FORTRAN_BINDINGS runtime/atlas_trace.h MODULE atlas_trace_c_binding OUTPUT atlas_trace_c_binding.f90 ) -preprocess_fypp( atlas_f_src field/atlas_Field_module.F90 ) - -## gridtools_storage_files ## -add_custom_target( pre_processed_files SOURCES field/atlas_Field_module.F90 ) - -ecbuild_debug_var( atlas_f_src ) ### atlas fortran lib ecbuild_add_library( TARGET atlas_f @@ -174,23 +136,24 @@ ecbuild_add_library( TARGET atlas_f CONDITION CMAKE_Fortran_COMPILER_LOADED SOURCES ${FORTRAN_BINDINGS} - ${atlas_f_src} atlas_module.F90 util/atlas_kinds_module.F90 util/atlas_JSON_module.F90 util/atlas_Config_module.F90 util/atlas_Metadata_module.F90 - util/atlas_Error_module.F90 + util/atlas_allocate_module.F90 output/atlas_output_module.F90 functionspace/atlas_FunctionSpace_module.F90 functionspace/atlas_functionspace_EdgeColumns_module.F90 - functionspace/atlas_functionspace_NodeColumns_module.F90 + functionspace/atlas_functionspace_NodeColumns_module.fypp functionspace/atlas_functionspace_StructuredColumns_module.F90 functionspace/atlas_functionspace_Spectral_module.F90 field/atlas_FieldSet_module.F90 field/atlas_State_module.F90 + field/atlas_Field_module.fypp grid/atlas_Grid_module.F90 grid/atlas_GridDistribution_module.F90 + grid/atlas_Vertical_module.F90 grid/atlas_Partitioner_module.F90 mesh/atlas_MeshGenerator_module.F90 mesh/atlas_Mesh_module.F90 @@ -206,19 +169,27 @@ ecbuild_add_library( TARGET atlas_f numerics/atlas_fvm_module.F90 numerics/atlas_Nabla_module.F90 interpolation/atlas_Interpolation_module.F90 - parallel/atlas_mpi_module.F90 - parallel/atlas_GatherScatter_module.F90 - parallel/atlas_Checksum_module.F90 - parallel/atlas_HaloExchange_module.F90 + parallel/atlas_GatherScatter_module.fypp + parallel/atlas_Checksum_module.fypp + parallel/atlas_HaloExchange_module.fypp trans/atlas_Trans_module.F90 internals/atlas_read_file.h internals/atlas_read_file.cc internals/atlas_write_to_fortran_unit.F90 internals/Library.h internals/Library.cc + runtime/atlas_trace.cc + runtime/atlas_Trace_module.F90 PRIVATE_INCLUDES ${FCKIT_INCLUDE_DIRS} LIBS atlas fckit ) +target_include_directories( atlas_f PUBLIC $ ) + +fckit_target_preprocess_fypp( atlas_f + DEPENDS + ${CMAKE_CURRENT_SOURCE_DIR}/atlas_f.h.in + ${CMAKE_CURRENT_SOURCE_DIR}/atlas_f.fypp + ${CMAKE_CURRENT_SOURCE_DIR}/internals/atlas_generics.fypp ) diff --git a/src/atlas_f/atlas_f.fypp b/src/atlas_f/atlas_f.fypp new file mode 100644 index 000000000..ed50231a5 --- /dev/null +++ b/src/atlas_f/atlas_f.fypp @@ -0,0 +1,87 @@ +! (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. + +#:mute + +#:def ENABLE_ATLAS_MACROS() +#! Use this macro in the "use " location to enable +#! Usage: +#! @:ENABLE_ATLAS_MACROS() + use fckit_exception_module, only : fckit_exception + use atlas_trace_module, only : atlas_Trace +#:enddef + + +#:def ATLAS_ABORT( string ) +#! Abort with message +#! Usage: +#! if( condition ) @{ ATLAS_ABORT( "error message" ) }@ +#! + call fckit_exception%abort( ${string}$, "${_FILE_}$", ${_LINE_}$ ) +#:enddef + + +#:def ATLAS_ASSERT( cond ) +#! Assert condition evaluates to .True. , otherwise abort +#! Usage: +#! @:ATLAS_ASSERT( cond ) +#! or inline: +#! @{ ATLAS_ASSERT( cond ) }@ +#! +if (.not. (${cond}$)) then + call fckit_exception%abort( '${cond.replace("'", "''")}$', "${_FILE_}$", ${_LINE_}$ ) +end if +#:enddef + +#:def ATLAS_TRACE( title, labels = None ) +#! Create a right-hand-side atlas_Trace object in a nicer way +#! Usage: +#! type( atlas_Trace ) :: trace +#! trace = @{ ATLAS_TRACE( "title" ) }@ +#! ... +#! call trace%final() +#! +#! or with labels: +#! type( atlas_Trace ) :: trace +#! trace = @{ ATLAS_TRACE( "title", {"label1","label2"} ) }@ +#! ... +#! call trace%final() +#! + #:if labels is not None + atlas_Trace( "${_FILE_}$", ${_LINE_}$, ${title}$, ${labels}$ ) + #:else + atlas_Trace( "${_FILE_}$", ${_LINE_}$, ${title}$ ) + #:endif +#:enddef + +#:def ATLAS_TRACE_BEGIN( trace, title, labels = None ) +#! Create a right-hand-side atlas_Trace object in a nicer way +#! Usage: +#! type( atlas_Trace ) :: trace +#! trace = @{ ATLAS_TRACE( "title" ) }@ +#! ... +#! call trace%final() +#! +#! or with labels: +#! type( atlas_Trace ) :: trace +#! trace = @{ ATLAS_TRACE( "title", {"label1","label2"} ) }@ +#! ... +#! call trace%final() +#! + #:if labels is not None + ${trace}$ = atlas_Trace( "${_FILE_}$", ${_LINE_}$, ${title}$, ${labels}$ ) + #:else + ${trace}$ = atlas_Trace( "${_FILE_}$", ${_LINE_}$, ${title}$ ) + #:endif +#:enddef + +#:def ATLAS_TRACE_END( trace ) + call ${trace}$ % final() +#:enddef + +#:endmute diff --git a/src/atlas_f/atlas_f.h.in b/src/atlas_f/atlas_f.h.in index ef083f9d7..9d9b55eb8 100644 --- a/src/atlas_f/atlas_f.h.in +++ b/src/atlas_f/atlas_f.h.in @@ -1,18 +1,33 @@ +#if 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. + +// clang-format off +#endif + #ifndef atlas_f_h #define atlas_f_h #include "fckit/fckit.h" -#define ATLAS_HAVE_OMP @ATLAS_HAVE_OMP@ -#define ATLAS_HAVE_TRANS @ATLAS_HAVE_TRANS@ -#define ATLAS_HAVE_ACC @ATLAS_HAVE_ACC@ + +#define ATLAS_HAVE_OMP @ATLAS_HAVE_OMP@ +#define ATLAS_HAVE_TRANS @ATLAS_HAVE_TRANS@ +#define ATLAS_HAVE_ACC @ATLAS_HAVE_ACC@ #define ATLAS_BITS_GLOBAL @ATLAS_BITS_GLOBAL@ +#define ATLAS_BITS_LOCAL @ATLAS_BITS_LOCAL@ -#ifdef FCKIT_FINAL #define ATLAS_FINAL FCKIT_FINAL -#else -! Compatibility with fckit < v0.5.1 -#define ATLAS_FINAL + +#ifndef PGIBUG_ATLAS_197 +#define CPTR_PGIBUG_A c_ptr() +#define CPTR_PGIBUG_B c_ptr() +#define PGIBUG_ATLAS_197 0 #endif #endif diff --git a/src/atlas_f/atlas_module.F90 b/src/atlas_f/atlas_module.F90 index 813317503..3481ae60c 100644 --- a/src/atlas_f/atlas_module.F90 +++ b/src/atlas_f/atlas_module.F90 @@ -1,3 +1,11 @@ +! (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_module @@ -9,8 +17,6 @@ module atlas_module ! !------------------------------------------------------------------------------ -use atlas_mpi_module - use atlas_Field_module, only: & & atlas_Field, & & atlas_real, & @@ -29,41 +35,6 @@ module atlas_module & atlas_PathName use atlas_Metadata_module, only: & & atlas_Metadata -use atlas_Error_module, only: & - & atlas_CodeLocation, & - & atlas_code_location_str, & - & atlas_code_location, & - & atlas_abort, & - & atlas_throw_exception, & - & atlas_throw_notimplemented, & - & atlas_throw_outofrange, & - & atlas_throw_seriousbug, & - & atlas_throw_usererror, & - & atlas_throw_assertionfailed, & - & atlas_err, & - & atlas_noerr, & - & atlas_err_clear, & - & atlas_err_success, & - & atlas_err_code, & - & atlas_err_msg, & - & atlas_err_set_aborts, & - & atlas_err_set_throws, & - & atlas_err_set_backtrace, & - & atlas_err_cleared, & - & atlas_err_noerr, & - & atlas_err_exception, & - & atlas_err_usererror, & - & atlas_err_seriousbug, & - & atlas_err_notimplemented, & - & atlas_err_assertionfailed, & - & atlas_err_badparameter, & - & atlas_err_outofrange, & - & atlas_err_stop, & - & atlas_err_abort, & - & atlas_err_cancel, & - & atlas_err_readerror, & - & atlas_err_writeerror, & - & atlas_err_unknown use atlas_HybridElements_module, only: & & atlas_HybridElements use atlas_mesh_Edges_module, only: & @@ -145,6 +116,8 @@ module atlas_module use atlas_output_module, only: & & atlas_Output, & & atlas_output_Gmsh +use atlas_trace_module, only : & + & atlas_Trace use fckit_log_module, only: atlas_log => fckit_log @@ -186,7 +159,7 @@ subroutine atlas_init( comm ) use atlas_library_c_binding use iso_fortran_env, only : stdout => output_unit use fckit_main_module, only: fckit_main - use atlas_mpi_module, only : atlas_mpi_set_comm + use fckit_mpi_module, only : fckit_mpi_setCommDefault integer, intent(in), optional :: comm @@ -205,7 +178,7 @@ subroutine atlas_init( comm ) endif if( present(comm) ) then - call atlas_mpi_set_comm(comm) + call fckit_mpi_setCommDefault(comm) endif call atlas__atlas_init_noargs() diff --git a/src/atlas_f/autogenerated/atlas_Field_module_fypp.F90 b/src/atlas_f/autogenerated/atlas_Field_module_fypp.F90 deleted file mode 100644 index f437e6420..000000000 --- a/src/atlas_f/autogenerated/atlas_Field_module_fypp.F90 +++ /dev/null @@ -1,3140 +0,0 @@ -#include "atlas/atlas_f.h" - - - -module atlas_field_module - -use fckit_owned_object_module, only : fckit_owned_object -use atlas_Error_module, only: atlas_code_location, atlas_abort, atlas_throw_outofrange -use atlas_Config_module, only: atlas_Config -implicit none - -public :: atlas_Field -public :: atlas_real -public :: atlas_integer -public :: atlas_logical -public :: atlas_data_type - -character(len=*), parameter :: filename = 'atlas_Field_module.F90' - -private - - -!------------------------------------------------------------------------------ -TYPE, extends(fckit_owned_object) :: atlas_Field - -! Purpose : -! ------- -! *Field* : Object containing field data and Metadata - -! Methods : -! ------- -! name : The name or tag this field was created with -! data : Return the field as a fortran array of specified shape -! Metadata : Return object that can contain a variety of Metadata - -! Author : -! ------ -! 20-Nov-2013 Willem Deconinck *ECMWF* - -!------------------------------------------------------------------------------ -contains - procedure :: name => Field__name - procedure :: functionspace => Field__functionspace - procedure :: datatype => Field__datatype - procedure :: metadata => Field__metadata - procedure, private :: shape_array => Field__shape_array - procedure, private :: shape_idx => Field__shape_idx - procedure :: size => Field__size - procedure :: rank => Field__rank - procedure :: bytes => Field__bytes - procedure :: levels => Field__levels - procedure :: kind => Field__kind - generic :: shape => shape_array, shape_idx - - procedure :: rename - procedure :: set_levels - procedure :: set_functionspace - - procedure, private :: access_host_data_int32_r1 - procedure, private :: access_host_data_int32_r1_shape - procedure, private :: access_device_data_int32_r1 - procedure, private :: access_device_data_int32_r1_shape - procedure, private :: access_host_data_int64_r1 - procedure, private :: access_host_data_int64_r1_shape - procedure, private :: access_device_data_int64_r1 - procedure, private :: access_device_data_int64_r1_shape - procedure, private :: access_host_data_real32_r1 - procedure, private :: access_host_data_real32_r1_shape - procedure, private :: access_device_data_real32_r1 - procedure, private :: access_device_data_real32_r1_shape - procedure, private :: access_host_data_real64_r1 - procedure, private :: access_host_data_real64_r1_shape - procedure, private :: access_device_data_real64_r1 - procedure, private :: access_device_data_real64_r1_shape - procedure, private :: access_host_data_logical32_r1 - procedure, private :: access_host_data_logical32_r1_shape - procedure, private :: access_device_data_logical32_r1 - procedure, private :: access_device_data_logical32_r1_shape - procedure, private :: access_host_data_int32_r2 - procedure, private :: access_host_data_int32_r2_shape - procedure, private :: access_device_data_int32_r2 - procedure, private :: access_device_data_int32_r2_shape - procedure, private :: access_host_data_int64_r2 - procedure, private :: access_host_data_int64_r2_shape - procedure, private :: access_device_data_int64_r2 - procedure, private :: access_device_data_int64_r2_shape - procedure, private :: access_host_data_real32_r2 - procedure, private :: access_host_data_real32_r2_shape - procedure, private :: access_device_data_real32_r2 - procedure, private :: access_device_data_real32_r2_shape - procedure, private :: access_host_data_real64_r2 - procedure, private :: access_host_data_real64_r2_shape - procedure, private :: access_device_data_real64_r2 - procedure, private :: access_device_data_real64_r2_shape - procedure, private :: access_host_data_logical32_r2 - procedure, private :: access_host_data_logical32_r2_shape - procedure, private :: access_device_data_logical32_r2 - procedure, private :: access_device_data_logical32_r2_shape - procedure, private :: access_host_data_int32_r3 - procedure, private :: access_host_data_int32_r3_shape - procedure, private :: access_device_data_int32_r3 - procedure, private :: access_device_data_int32_r3_shape - procedure, private :: access_host_data_int64_r3 - procedure, private :: access_host_data_int64_r3_shape - procedure, private :: access_device_data_int64_r3 - procedure, private :: access_device_data_int64_r3_shape - procedure, private :: access_host_data_real32_r3 - procedure, private :: access_host_data_real32_r3_shape - procedure, private :: access_device_data_real32_r3 - procedure, private :: access_device_data_real32_r3_shape - procedure, private :: access_host_data_real64_r3 - procedure, private :: access_host_data_real64_r3_shape - procedure, private :: access_device_data_real64_r3 - procedure, private :: access_device_data_real64_r3_shape - procedure, private :: access_host_data_logical32_r3 - procedure, private :: access_host_data_logical32_r3_shape - procedure, private :: access_device_data_logical32_r3 - procedure, private :: access_device_data_logical32_r3_shape - procedure, private :: access_host_data_int32_r4 - procedure, private :: access_host_data_int32_r4_shape - procedure, private :: access_device_data_int32_r4 - procedure, private :: access_device_data_int32_r4_shape - procedure, private :: access_host_data_int64_r4 - procedure, private :: access_host_data_int64_r4_shape - procedure, private :: access_device_data_int64_r4 - procedure, private :: access_device_data_int64_r4_shape - procedure, private :: access_host_data_real32_r4 - procedure, private :: access_host_data_real32_r4_shape - procedure, private :: access_device_data_real32_r4 - procedure, private :: access_device_data_real32_r4_shape - procedure, private :: access_host_data_real64_r4 - procedure, private :: access_host_data_real64_r4_shape - procedure, private :: access_device_data_real64_r4 - procedure, private :: access_device_data_real64_r4_shape - procedure, private :: access_host_data_logical32_r4 - procedure, private :: access_host_data_logical32_r4_shape - procedure, private :: access_device_data_logical32_r4 - procedure, private :: access_device_data_logical32_r4_shape - - generic, public :: data => & - & access_host_data_int32_r1, & - & access_host_data_int32_r1_shape, & - & access_host_data_int64_r1, & - & access_host_data_int64_r1_shape, & - & access_host_data_real32_r1, & - & access_host_data_real32_r1_shape, & - & access_host_data_real64_r1, & - & access_host_data_real64_r1_shape, & - & access_host_data_logical32_r1, & - & access_host_data_logical32_r1_shape, & - & access_host_data_int32_r2, & - & access_host_data_int32_r2_shape, & - & access_host_data_int64_r2, & - & access_host_data_int64_r2_shape, & - & access_host_data_real32_r2, & - & access_host_data_real32_r2_shape, & - & access_host_data_real64_r2, & - & access_host_data_real64_r2_shape, & - & access_host_data_logical32_r2, & - & access_host_data_logical32_r2_shape, & - & access_host_data_int32_r3, & - & access_host_data_int32_r3_shape, & - & access_host_data_int64_r3, & - & access_host_data_int64_r3_shape, & - & access_host_data_real32_r3, & - & access_host_data_real32_r3_shape, & - & access_host_data_real64_r3, & - & access_host_data_real64_r3_shape, & - & access_host_data_logical32_r3, & - & access_host_data_logical32_r3_shape, & - & access_host_data_int32_r4, & - & access_host_data_int32_r4_shape, & - & access_host_data_int64_r4, & - & access_host_data_int64_r4_shape, & - & access_host_data_real32_r4, & - & access_host_data_real32_r4_shape, & - & access_host_data_real64_r4, & - & access_host_data_real64_r4_shape, & - & access_host_data_logical32_r4, & - & access_host_data_logical32_r4_shape, & - & dummy - - generic, public :: host_data => & - & access_host_data_int32_r1, & - & access_host_data_int32_r1_shape, & - & access_host_data_int64_r1, & - & access_host_data_int64_r1_shape, & - & access_host_data_real32_r1, & - & access_host_data_real32_r1_shape, & - & access_host_data_real64_r1, & - & access_host_data_real64_r1_shape, & - & access_host_data_logical32_r1, & - & access_host_data_logical32_r1_shape, & - & access_host_data_int32_r2, & - & access_host_data_int32_r2_shape, & - & access_host_data_int64_r2, & - & access_host_data_int64_r2_shape, & - & access_host_data_real32_r2, & - & access_host_data_real32_r2_shape, & - & access_host_data_real64_r2, & - & access_host_data_real64_r2_shape, & - & access_host_data_logical32_r2, & - & access_host_data_logical32_r2_shape, & - & access_host_data_int32_r3, & - & access_host_data_int32_r3_shape, & - & access_host_data_int64_r3, & - & access_host_data_int64_r3_shape, & - & access_host_data_real32_r3, & - & access_host_data_real32_r3_shape, & - & access_host_data_real64_r3, & - & access_host_data_real64_r3_shape, & - & access_host_data_logical32_r3, & - & access_host_data_logical32_r3_shape, & - & access_host_data_int32_r4, & - & access_host_data_int32_r4_shape, & - & access_host_data_int64_r4, & - & access_host_data_int64_r4_shape, & - & access_host_data_real32_r4, & - & access_host_data_real32_r4_shape, & - & access_host_data_real64_r4, & - & access_host_data_real64_r4_shape, & - & access_host_data_logical32_r4, & - & access_host_data_logical32_r4_shape, & - & dummy - - generic, public :: device_data => & - & access_device_data_int32_r1, & - & access_device_data_int32_r1_shape, & - & access_device_data_int64_r1, & - & access_device_data_int64_r1_shape, & - & access_device_data_real32_r1, & - & access_device_data_real32_r1_shape, & - & access_device_data_real64_r1, & - & access_device_data_real64_r1_shape, & - & access_device_data_logical32_r1, & - & access_device_data_logical32_r1_shape, & - & access_device_data_int32_r2, & - & access_device_data_int32_r2_shape, & - & access_device_data_int64_r2, & - & access_device_data_int64_r2_shape, & - & access_device_data_real32_r2, & - & access_device_data_real32_r2_shape, & - & access_device_data_real64_r2, & - & access_device_data_real64_r2_shape, & - & access_device_data_logical32_r2, & - & access_device_data_logical32_r2_shape, & - & access_device_data_int32_r3, & - & access_device_data_int32_r3_shape, & - & access_device_data_int64_r3, & - & access_device_data_int64_r3_shape, & - & access_device_data_real32_r3, & - & access_device_data_real32_r3_shape, & - & access_device_data_real64_r3, & - & access_device_data_real64_r3_shape, & - & access_device_data_logical32_r3, & - & access_device_data_logical32_r3_shape, & - & access_device_data_int32_r4, & - & access_device_data_int32_r4_shape, & - & access_device_data_int64_r4, & - & access_device_data_int64_r4_shape, & - & access_device_data_real32_r4, & - & access_device_data_real32_r4_shape, & - & access_device_data_real64_r4, & - & access_device_data_real64_r4_shape, & - & access_device_data_logical32_r4, & - & access_device_data_logical32_r4_shape, & - & dummy - - procedure, public :: host_needs_update - procedure, public :: device_needs_update - procedure, public :: clone_to_device - procedure, public :: clone_from_device - procedure, public :: sync_host_device - - procedure, private :: dummy - -#if FCKIT_FINAL_NOT_INHERITING - final :: atlas_Field__final_auto -#endif - -END TYPE atlas_Field - -interface atlas_Field - module procedure atlas_Field__cptr - module procedure atlas_Field__create - module procedure atlas_Field__create_name_kind_shape_int32 - module procedure atlas_Field__create_name_kind_shape_int64 - module procedure atlas_Field__create_kind_shape_int32 - module procedure atlas_Field__create_kind_shape_int64 - - module procedure atlas_Field__wrap_int32_r1 - module procedure atlas_Field__wrap_name_int32_r1 - module procedure atlas_Field__wrap_int64_r1 - module procedure atlas_Field__wrap_name_int64_r1 - module procedure atlas_Field__wrap_real32_r1 - module procedure atlas_Field__wrap_name_real32_r1 - module procedure atlas_Field__wrap_real64_r1 - module procedure atlas_Field__wrap_name_real64_r1 - module procedure atlas_Field__wrap_int32_r2 - module procedure atlas_Field__wrap_name_int32_r2 - module procedure atlas_Field__wrap_int64_r2 - module procedure atlas_Field__wrap_name_int64_r2 - module procedure atlas_Field__wrap_real32_r2 - module procedure atlas_Field__wrap_name_real32_r2 - module procedure atlas_Field__wrap_real64_r2 - module procedure atlas_Field__wrap_name_real64_r2 - module procedure atlas_Field__wrap_int32_r3 - module procedure atlas_Field__wrap_name_int32_r3 - module procedure atlas_Field__wrap_int64_r3 - module procedure atlas_Field__wrap_name_int64_r3 - module procedure atlas_Field__wrap_real32_r3 - module procedure atlas_Field__wrap_name_real32_r3 - module procedure atlas_Field__wrap_real64_r3 - module procedure atlas_Field__wrap_name_real64_r3 - module procedure atlas_Field__wrap_int32_r4 - module procedure atlas_Field__wrap_name_int32_r4 - module procedure atlas_Field__wrap_int64_r4 - module procedure atlas_Field__wrap_name_int64_r4 - module procedure atlas_Field__wrap_real32_r4 - module procedure atlas_Field__wrap_name_real32_r4 - module procedure atlas_Field__wrap_real64_r4 - module procedure atlas_Field__wrap_name_real64_r4 -end interface - -! ---------------------------------------------------- -! ENUM DataType -integer, private, parameter :: ATLAS_KIND_INT32 = -4 -integer, private, parameter :: ATLAS_KIND_INT64 = -8 -integer, private, parameter :: ATLAS_KIND_REAL32 = 4 -integer, private, parameter :: ATLAS_KIND_REAL64 = 8 -! ---------------------------------------------------- - - -interface array_c_to_f - module procedure array_c_to_f_int32_r1 - module procedure array_c_to_f_int64_r1 - module procedure array_c_to_f_real32_r1 - module procedure array_c_to_f_real64_r1 - module procedure array_c_to_f_logical32_r1 - module procedure array_c_to_f_int32_r2 - module procedure array_c_to_f_int64_r2 - module procedure array_c_to_f_real32_r2 - module procedure array_c_to_f_real64_r2 - module procedure array_c_to_f_logical32_r2 - module procedure array_c_to_f_int32_r3 - module procedure array_c_to_f_int64_r3 - module procedure array_c_to_f_real32_r3 - module procedure array_c_to_f_real64_r3 - module procedure array_c_to_f_logical32_r3 - module procedure array_c_to_f_int32_r4 - module procedure array_c_to_f_int64_r4 - module procedure array_c_to_f_real32_r4 - module procedure array_c_to_f_real64_r4 - module procedure array_c_to_f_logical32_r4 -end interface -!------------------------------------------------------------------------------- - - -private :: fckit_owned_object -private :: atlas_code_location, atlas_abort, atlas_throw_outofrange -private :: atlas_Config - -!======================================================== -contains -!======================================================== - -!------------------------------------------------------------------------------- -subroutine array_c_to_f_int32_r1(array_cptr,rank,shape_cptr,strides_cptr,array_fptr) - use, intrinsic :: iso_c_binding, only : c_ptr, c_int, c_double, c_long, c_float, c_f_pointer - - type(c_ptr), intent(in) :: array_cptr - integer(c_int), intent(in) :: rank - type(c_ptr), intent(in) :: shape_cptr - type(c_ptr), intent(in) :: strides_cptr - integer(c_int), pointer, intent(inout) :: array_fptr(:) - integer(c_int), pointer :: tmp(:) - integer, pointer :: shape(:) - integer, pointer :: strides(:) - integer :: eshape(1) - integer :: j - - if( rank /= 1 ) call atlas_abort("Rank mismatch",atlas_code_location("atlas_Field_module.F90",178)) - - call c_f_pointer ( shape_cptr, shape , [rank] ) - call c_f_pointer ( strides_cptr, strides , [rank] ) - do j=1,rank-1 - if( strides(j) /= 0 ) then - eshape(j) = strides(j+1)/strides(j) - else - eshape(j) = shape(j) - endif - enddo - eshape(rank) = shape(rank) - call c_f_pointer ( array_cptr , tmp , shape=eshape ) - array_fptr => tmp(1:shape(1)) - - - -end subroutine - -!------------------------------------------------------------------------------- - -!------------------------------------------------------------------------------- -subroutine array_c_to_f_int64_r1(array_cptr,rank,shape_cptr,strides_cptr,array_fptr) - use, intrinsic :: iso_c_binding, only : c_ptr, c_int, c_double, c_long, c_float, c_f_pointer - - type(c_ptr), intent(in) :: array_cptr - integer(c_int), intent(in) :: rank - type(c_ptr), intent(in) :: shape_cptr - type(c_ptr), intent(in) :: strides_cptr - integer(c_long), pointer, intent(inout) :: array_fptr(:) - integer(c_long), pointer :: tmp(:) - integer, pointer :: shape(:) - integer, pointer :: strides(:) - integer :: eshape(1) - integer :: j - - if( rank /= 1 ) call atlas_abort("Rank mismatch",atlas_code_location("atlas_Field_module.F90",178)) - - call c_f_pointer ( shape_cptr, shape , [rank] ) - call c_f_pointer ( strides_cptr, strides , [rank] ) - do j=1,rank-1 - if( strides(j) /= 0 ) then - eshape(j) = strides(j+1)/strides(j) - else - eshape(j) = shape(j) - endif - enddo - eshape(rank) = shape(rank) - call c_f_pointer ( array_cptr , tmp , shape=eshape ) - array_fptr => tmp(1:shape(1)) - - - -end subroutine - -!------------------------------------------------------------------------------- - -!------------------------------------------------------------------------------- -subroutine array_c_to_f_real32_r1(array_cptr,rank,shape_cptr,strides_cptr,array_fptr) - use, intrinsic :: iso_c_binding, only : c_ptr, c_int, c_double, c_long, c_float, c_f_pointer - - type(c_ptr), intent(in) :: array_cptr - integer(c_int), intent(in) :: rank - type(c_ptr), intent(in) :: shape_cptr - type(c_ptr), intent(in) :: strides_cptr - real(c_float), pointer, intent(inout) :: array_fptr(:) - real(c_float), pointer :: tmp(:) - integer, pointer :: shape(:) - integer, pointer :: strides(:) - integer :: eshape(1) - integer :: j - - if( rank /= 1 ) call atlas_abort("Rank mismatch",atlas_code_location("atlas_Field_module.F90",178)) - - call c_f_pointer ( shape_cptr, shape , [rank] ) - call c_f_pointer ( strides_cptr, strides , [rank] ) - do j=1,rank-1 - if( strides(j) /= 0 ) then - eshape(j) = strides(j+1)/strides(j) - else - eshape(j) = shape(j) - endif - enddo - eshape(rank) = shape(rank) - call c_f_pointer ( array_cptr , tmp , shape=eshape ) - array_fptr => tmp(1:shape(1)) - - - -end subroutine - -!------------------------------------------------------------------------------- - -!------------------------------------------------------------------------------- -subroutine array_c_to_f_real64_r1(array_cptr,rank,shape_cptr,strides_cptr,array_fptr) - use, intrinsic :: iso_c_binding, only : c_ptr, c_int, c_double, c_long, c_float, c_f_pointer - - type(c_ptr), intent(in) :: array_cptr - integer(c_int), intent(in) :: rank - type(c_ptr), intent(in) :: shape_cptr - type(c_ptr), intent(in) :: strides_cptr - real(c_double), pointer, intent(inout) :: array_fptr(:) - real(c_double), pointer :: tmp(:) - integer, pointer :: shape(:) - integer, pointer :: strides(:) - integer :: eshape(1) - integer :: j - - if( rank /= 1 ) call atlas_abort("Rank mismatch",atlas_code_location("atlas_Field_module.F90",178)) - - call c_f_pointer ( shape_cptr, shape , [rank] ) - call c_f_pointer ( strides_cptr, strides , [rank] ) - do j=1,rank-1 - if( strides(j) /= 0 ) then - eshape(j) = strides(j+1)/strides(j) - else - eshape(j) = shape(j) - endif - enddo - eshape(rank) = shape(rank) - call c_f_pointer ( array_cptr , tmp , shape=eshape ) - array_fptr => tmp(1:shape(1)) - - - -end subroutine - -!------------------------------------------------------------------------------- - -!------------------------------------------------------------------------------- -subroutine array_c_to_f_logical32_r1(array_cptr,rank,shape_cptr,strides_cptr,array_fptr) - use, intrinsic :: iso_c_binding, only : c_ptr, c_int, c_double, c_long, c_float, c_f_pointer - - type(c_ptr), intent(in) :: array_cptr - integer(c_int), intent(in) :: rank - type(c_ptr), intent(in) :: shape_cptr - type(c_ptr), intent(in) :: strides_cptr - logical, pointer, intent(inout) :: array_fptr(:) - logical, pointer :: tmp(:) - integer, pointer :: shape(:) - integer, pointer :: strides(:) - integer :: eshape(1) - integer :: j - - if( rank /= 1 ) call atlas_abort("Rank mismatch",atlas_code_location("atlas_Field_module.F90",178)) - - call c_f_pointer ( shape_cptr, shape , [rank] ) - call c_f_pointer ( strides_cptr, strides , [rank] ) - do j=1,rank-1 - if( strides(j) /= 0 ) then - eshape(j) = strides(j+1)/strides(j) - else - eshape(j) = shape(j) - endif - enddo - eshape(rank) = shape(rank) - call c_f_pointer ( array_cptr , tmp , shape=eshape ) - array_fptr => tmp(1:shape(1)) - - - -end subroutine - -!------------------------------------------------------------------------------- - -!------------------------------------------------------------------------------- -subroutine array_c_to_f_int32_r2(array_cptr,rank,shape_cptr,strides_cptr,array_fptr) - use, intrinsic :: iso_c_binding, only : c_ptr, c_int, c_double, c_long, c_float, c_f_pointer - - type(c_ptr), intent(in) :: array_cptr - integer(c_int), intent(in) :: rank - type(c_ptr), intent(in) :: shape_cptr - type(c_ptr), intent(in) :: strides_cptr - integer(c_int), pointer, intent(inout) :: array_fptr(:,:) - integer(c_int), pointer :: tmp(:,:) - integer, pointer :: shape(:) - integer, pointer :: strides(:) - integer :: eshape(2) - integer :: j - - if( rank /= 2 ) call atlas_abort("Rank mismatch",atlas_code_location("atlas_Field_module.F90",178)) - - call c_f_pointer ( shape_cptr, shape , [rank] ) - call c_f_pointer ( strides_cptr, strides , [rank] ) - do j=1,rank-1 - if( strides(j) /= 0 ) then - eshape(j) = strides(j+1)/strides(j) - else - eshape(j) = shape(j) - endif - enddo - eshape(rank) = shape(rank) - call c_f_pointer ( array_cptr , tmp , shape=eshape ) - - array_fptr => tmp(1:shape(1),1:shape(2)) - - -end subroutine - -!------------------------------------------------------------------------------- - -!------------------------------------------------------------------------------- -subroutine array_c_to_f_int64_r2(array_cptr,rank,shape_cptr,strides_cptr,array_fptr) - use, intrinsic :: iso_c_binding, only : c_ptr, c_int, c_double, c_long, c_float, c_f_pointer - - type(c_ptr), intent(in) :: array_cptr - integer(c_int), intent(in) :: rank - type(c_ptr), intent(in) :: shape_cptr - type(c_ptr), intent(in) :: strides_cptr - integer(c_long), pointer, intent(inout) :: array_fptr(:,:) - integer(c_long), pointer :: tmp(:,:) - integer, pointer :: shape(:) - integer, pointer :: strides(:) - integer :: eshape(2) - integer :: j - - if( rank /= 2 ) call atlas_abort("Rank mismatch",atlas_code_location("atlas_Field_module.F90",178)) - - call c_f_pointer ( shape_cptr, shape , [rank] ) - call c_f_pointer ( strides_cptr, strides , [rank] ) - do j=1,rank-1 - if( strides(j) /= 0 ) then - eshape(j) = strides(j+1)/strides(j) - else - eshape(j) = shape(j) - endif - enddo - eshape(rank) = shape(rank) - call c_f_pointer ( array_cptr , tmp , shape=eshape ) - - array_fptr => tmp(1:shape(1),1:shape(2)) - - -end subroutine - -!------------------------------------------------------------------------------- - -!------------------------------------------------------------------------------- -subroutine array_c_to_f_real32_r2(array_cptr,rank,shape_cptr,strides_cptr,array_fptr) - use, intrinsic :: iso_c_binding, only : c_ptr, c_int, c_double, c_long, c_float, c_f_pointer - - type(c_ptr), intent(in) :: array_cptr - integer(c_int), intent(in) :: rank - type(c_ptr), intent(in) :: shape_cptr - type(c_ptr), intent(in) :: strides_cptr - real(c_float), pointer, intent(inout) :: array_fptr(:,:) - real(c_float), pointer :: tmp(:,:) - integer, pointer :: shape(:) - integer, pointer :: strides(:) - integer :: eshape(2) - integer :: j - - if( rank /= 2 ) call atlas_abort("Rank mismatch",atlas_code_location("atlas_Field_module.F90",178)) - - call c_f_pointer ( shape_cptr, shape , [rank] ) - call c_f_pointer ( strides_cptr, strides , [rank] ) - do j=1,rank-1 - if( strides(j) /= 0 ) then - eshape(j) = strides(j+1)/strides(j) - else - eshape(j) = shape(j) - endif - enddo - eshape(rank) = shape(rank) - call c_f_pointer ( array_cptr , tmp , shape=eshape ) - - array_fptr => tmp(1:shape(1),1:shape(2)) - - -end subroutine - -!------------------------------------------------------------------------------- - -!------------------------------------------------------------------------------- -subroutine array_c_to_f_real64_r2(array_cptr,rank,shape_cptr,strides_cptr,array_fptr) - use, intrinsic :: iso_c_binding, only : c_ptr, c_int, c_double, c_long, c_float, c_f_pointer - - type(c_ptr), intent(in) :: array_cptr - integer(c_int), intent(in) :: rank - type(c_ptr), intent(in) :: shape_cptr - type(c_ptr), intent(in) :: strides_cptr - real(c_double), pointer, intent(inout) :: array_fptr(:,:) - real(c_double), pointer :: tmp(:,:) - integer, pointer :: shape(:) - integer, pointer :: strides(:) - integer :: eshape(2) - integer :: j - - if( rank /= 2 ) call atlas_abort("Rank mismatch",atlas_code_location("atlas_Field_module.F90",178)) - - call c_f_pointer ( shape_cptr, shape , [rank] ) - call c_f_pointer ( strides_cptr, strides , [rank] ) - do j=1,rank-1 - if( strides(j) /= 0 ) then - eshape(j) = strides(j+1)/strides(j) - else - eshape(j) = shape(j) - endif - enddo - eshape(rank) = shape(rank) - call c_f_pointer ( array_cptr , tmp , shape=eshape ) - - array_fptr => tmp(1:shape(1),1:shape(2)) - - -end subroutine - -!------------------------------------------------------------------------------- - -!------------------------------------------------------------------------------- -subroutine array_c_to_f_logical32_r2(array_cptr,rank,shape_cptr,strides_cptr,array_fptr) - use, intrinsic :: iso_c_binding, only : c_ptr, c_int, c_double, c_long, c_float, c_f_pointer - - type(c_ptr), intent(in) :: array_cptr - integer(c_int), intent(in) :: rank - type(c_ptr), intent(in) :: shape_cptr - type(c_ptr), intent(in) :: strides_cptr - logical, pointer, intent(inout) :: array_fptr(:,:) - logical, pointer :: tmp(:,:) - integer, pointer :: shape(:) - integer, pointer :: strides(:) - integer :: eshape(2) - integer :: j - - if( rank /= 2 ) call atlas_abort("Rank mismatch",atlas_code_location("atlas_Field_module.F90",178)) - - call c_f_pointer ( shape_cptr, shape , [rank] ) - call c_f_pointer ( strides_cptr, strides , [rank] ) - do j=1,rank-1 - if( strides(j) /= 0 ) then - eshape(j) = strides(j+1)/strides(j) - else - eshape(j) = shape(j) - endif - enddo - eshape(rank) = shape(rank) - call c_f_pointer ( array_cptr , tmp , shape=eshape ) - - array_fptr => tmp(1:shape(1),1:shape(2)) - - -end subroutine - -!------------------------------------------------------------------------------- - -!------------------------------------------------------------------------------- -subroutine array_c_to_f_int32_r3(array_cptr,rank,shape_cptr,strides_cptr,array_fptr) - use, intrinsic :: iso_c_binding, only : c_ptr, c_int, c_double, c_long, c_float, c_f_pointer - - type(c_ptr), intent(in) :: array_cptr - integer(c_int), intent(in) :: rank - type(c_ptr), intent(in) :: shape_cptr - type(c_ptr), intent(in) :: strides_cptr - integer(c_int), pointer, intent(inout) :: array_fptr(:,:,:) - integer(c_int), pointer :: tmp(:,:,:) - integer, pointer :: shape(:) - integer, pointer :: strides(:) - integer :: eshape(3) - integer :: j - - if( rank /= 3 ) call atlas_abort("Rank mismatch",atlas_code_location("atlas_Field_module.F90",178)) - - call c_f_pointer ( shape_cptr, shape , [rank] ) - call c_f_pointer ( strides_cptr, strides , [rank] ) - do j=1,rank-1 - if( strides(j) /= 0 ) then - eshape(j) = strides(j+1)/strides(j) - else - eshape(j) = shape(j) - endif - enddo - eshape(rank) = shape(rank) - call c_f_pointer ( array_cptr , tmp , shape=eshape ) - - - array_fptr => tmp(1:shape(1),1:shape(2),1:shape(3)) - -end subroutine - -!------------------------------------------------------------------------------- - -!------------------------------------------------------------------------------- -subroutine array_c_to_f_int64_r3(array_cptr,rank,shape_cptr,strides_cptr,array_fptr) - use, intrinsic :: iso_c_binding, only : c_ptr, c_int, c_double, c_long, c_float, c_f_pointer - - type(c_ptr), intent(in) :: array_cptr - integer(c_int), intent(in) :: rank - type(c_ptr), intent(in) :: shape_cptr - type(c_ptr), intent(in) :: strides_cptr - integer(c_long), pointer, intent(inout) :: array_fptr(:,:,:) - integer(c_long), pointer :: tmp(:,:,:) - integer, pointer :: shape(:) - integer, pointer :: strides(:) - integer :: eshape(3) - integer :: j - - if( rank /= 3 ) call atlas_abort("Rank mismatch",atlas_code_location("atlas_Field_module.F90",178)) - - call c_f_pointer ( shape_cptr, shape , [rank] ) - call c_f_pointer ( strides_cptr, strides , [rank] ) - do j=1,rank-1 - if( strides(j) /= 0 ) then - eshape(j) = strides(j+1)/strides(j) - else - eshape(j) = shape(j) - endif - enddo - eshape(rank) = shape(rank) - call c_f_pointer ( array_cptr , tmp , shape=eshape ) - - - array_fptr => tmp(1:shape(1),1:shape(2),1:shape(3)) - -end subroutine - -!------------------------------------------------------------------------------- - -!------------------------------------------------------------------------------- -subroutine array_c_to_f_real32_r3(array_cptr,rank,shape_cptr,strides_cptr,array_fptr) - use, intrinsic :: iso_c_binding, only : c_ptr, c_int, c_double, c_long, c_float, c_f_pointer - - type(c_ptr), intent(in) :: array_cptr - integer(c_int), intent(in) :: rank - type(c_ptr), intent(in) :: shape_cptr - type(c_ptr), intent(in) :: strides_cptr - real(c_float), pointer, intent(inout) :: array_fptr(:,:,:) - real(c_float), pointer :: tmp(:,:,:) - integer, pointer :: shape(:) - integer, pointer :: strides(:) - integer :: eshape(3) - integer :: j - - if( rank /= 3 ) call atlas_abort("Rank mismatch",atlas_code_location("atlas_Field_module.F90",178)) - - call c_f_pointer ( shape_cptr, shape , [rank] ) - call c_f_pointer ( strides_cptr, strides , [rank] ) - do j=1,rank-1 - if( strides(j) /= 0 ) then - eshape(j) = strides(j+1)/strides(j) - else - eshape(j) = shape(j) - endif - enddo - eshape(rank) = shape(rank) - call c_f_pointer ( array_cptr , tmp , shape=eshape ) - - - array_fptr => tmp(1:shape(1),1:shape(2),1:shape(3)) - -end subroutine - -!------------------------------------------------------------------------------- - -!------------------------------------------------------------------------------- -subroutine array_c_to_f_real64_r3(array_cptr,rank,shape_cptr,strides_cptr,array_fptr) - use, intrinsic :: iso_c_binding, only : c_ptr, c_int, c_double, c_long, c_float, c_f_pointer - - type(c_ptr), intent(in) :: array_cptr - integer(c_int), intent(in) :: rank - type(c_ptr), intent(in) :: shape_cptr - type(c_ptr), intent(in) :: strides_cptr - real(c_double), pointer, intent(inout) :: array_fptr(:,:,:) - real(c_double), pointer :: tmp(:,:,:) - integer, pointer :: shape(:) - integer, pointer :: strides(:) - integer :: eshape(3) - integer :: j - - if( rank /= 3 ) call atlas_abort("Rank mismatch",atlas_code_location("atlas_Field_module.F90",178)) - - call c_f_pointer ( shape_cptr, shape , [rank] ) - call c_f_pointer ( strides_cptr, strides , [rank] ) - do j=1,rank-1 - if( strides(j) /= 0 ) then - eshape(j) = strides(j+1)/strides(j) - else - eshape(j) = shape(j) - endif - enddo - eshape(rank) = shape(rank) - call c_f_pointer ( array_cptr , tmp , shape=eshape ) - - - array_fptr => tmp(1:shape(1),1:shape(2),1:shape(3)) - -end subroutine - -!------------------------------------------------------------------------------- - -!------------------------------------------------------------------------------- -subroutine array_c_to_f_logical32_r3(array_cptr,rank,shape_cptr,strides_cptr,array_fptr) - use, intrinsic :: iso_c_binding, only : c_ptr, c_int, c_double, c_long, c_float, c_f_pointer - - type(c_ptr), intent(in) :: array_cptr - integer(c_int), intent(in) :: rank - type(c_ptr), intent(in) :: shape_cptr - type(c_ptr), intent(in) :: strides_cptr - logical, pointer, intent(inout) :: array_fptr(:,:,:) - logical, pointer :: tmp(:,:,:) - integer, pointer :: shape(:) - integer, pointer :: strides(:) - integer :: eshape(3) - integer :: j - - if( rank /= 3 ) call atlas_abort("Rank mismatch",atlas_code_location("atlas_Field_module.F90",178)) - - call c_f_pointer ( shape_cptr, shape , [rank] ) - call c_f_pointer ( strides_cptr, strides , [rank] ) - do j=1,rank-1 - if( strides(j) /= 0 ) then - eshape(j) = strides(j+1)/strides(j) - else - eshape(j) = shape(j) - endif - enddo - eshape(rank) = shape(rank) - call c_f_pointer ( array_cptr , tmp , shape=eshape ) - - - array_fptr => tmp(1:shape(1),1:shape(2),1:shape(3)) - -end subroutine - -!------------------------------------------------------------------------------- - -!------------------------------------------------------------------------------- -subroutine array_c_to_f_int32_r4(array_cptr,rank,shape_cptr,strides_cptr,array_fptr) - use, intrinsic :: iso_c_binding, only : c_ptr, c_int, c_double, c_long, c_float, c_f_pointer - - type(c_ptr), intent(in) :: array_cptr - integer(c_int), intent(in) :: rank - type(c_ptr), intent(in) :: shape_cptr - type(c_ptr), intent(in) :: strides_cptr - integer(c_int), pointer, intent(inout) :: array_fptr(:,:,:,:) - integer(c_int), pointer :: tmp(:,:,:,:) - integer, pointer :: shape(:) - integer, pointer :: strides(:) - integer :: eshape(4) - integer :: j - - if( rank /= 4 ) call atlas_abort("Rank mismatch",atlas_code_location("atlas_Field_module.F90",178)) - - call c_f_pointer ( shape_cptr, shape , [rank] ) - call c_f_pointer ( strides_cptr, strides , [rank] ) - do j=1,rank-1 - if( strides(j) /= 0 ) then - eshape(j) = strides(j+1)/strides(j) - else - eshape(j) = shape(j) - endif - enddo - eshape(rank) = shape(rank) - call c_f_pointer ( array_cptr , tmp , shape=eshape ) - - - - array_fptr => tmp(1:shape(1),1:shape(2),1:shape(3),1:shape(4)) -end subroutine - -!------------------------------------------------------------------------------- - -!------------------------------------------------------------------------------- -subroutine array_c_to_f_int64_r4(array_cptr,rank,shape_cptr,strides_cptr,array_fptr) - use, intrinsic :: iso_c_binding, only : c_ptr, c_int, c_double, c_long, c_float, c_f_pointer - - type(c_ptr), intent(in) :: array_cptr - integer(c_int), intent(in) :: rank - type(c_ptr), intent(in) :: shape_cptr - type(c_ptr), intent(in) :: strides_cptr - integer(c_long), pointer, intent(inout) :: array_fptr(:,:,:,:) - integer(c_long), pointer :: tmp(:,:,:,:) - integer, pointer :: shape(:) - integer, pointer :: strides(:) - integer :: eshape(4) - integer :: j - - if( rank /= 4 ) call atlas_abort("Rank mismatch",atlas_code_location("atlas_Field_module.F90",178)) - - call c_f_pointer ( shape_cptr, shape , [rank] ) - call c_f_pointer ( strides_cptr, strides , [rank] ) - do j=1,rank-1 - if( strides(j) /= 0 ) then - eshape(j) = strides(j+1)/strides(j) - else - eshape(j) = shape(j) - endif - enddo - eshape(rank) = shape(rank) - call c_f_pointer ( array_cptr , tmp , shape=eshape ) - - - - array_fptr => tmp(1:shape(1),1:shape(2),1:shape(3),1:shape(4)) -end subroutine - -!------------------------------------------------------------------------------- - -!------------------------------------------------------------------------------- -subroutine array_c_to_f_real32_r4(array_cptr,rank,shape_cptr,strides_cptr,array_fptr) - use, intrinsic :: iso_c_binding, only : c_ptr, c_int, c_double, c_long, c_float, c_f_pointer - - type(c_ptr), intent(in) :: array_cptr - integer(c_int), intent(in) :: rank - type(c_ptr), intent(in) :: shape_cptr - type(c_ptr), intent(in) :: strides_cptr - real(c_float), pointer, intent(inout) :: array_fptr(:,:,:,:) - real(c_float), pointer :: tmp(:,:,:,:) - integer, pointer :: shape(:) - integer, pointer :: strides(:) - integer :: eshape(4) - integer :: j - - if( rank /= 4 ) call atlas_abort("Rank mismatch",atlas_code_location("atlas_Field_module.F90",178)) - - call c_f_pointer ( shape_cptr, shape , [rank] ) - call c_f_pointer ( strides_cptr, strides , [rank] ) - do j=1,rank-1 - if( strides(j) /= 0 ) then - eshape(j) = strides(j+1)/strides(j) - else - eshape(j) = shape(j) - endif - enddo - eshape(rank) = shape(rank) - call c_f_pointer ( array_cptr , tmp , shape=eshape ) - - - - array_fptr => tmp(1:shape(1),1:shape(2),1:shape(3),1:shape(4)) -end subroutine - -!------------------------------------------------------------------------------- - -!------------------------------------------------------------------------------- -subroutine array_c_to_f_real64_r4(array_cptr,rank,shape_cptr,strides_cptr,array_fptr) - use, intrinsic :: iso_c_binding, only : c_ptr, c_int, c_double, c_long, c_float, c_f_pointer - - type(c_ptr), intent(in) :: array_cptr - integer(c_int), intent(in) :: rank - type(c_ptr), intent(in) :: shape_cptr - type(c_ptr), intent(in) :: strides_cptr - real(c_double), pointer, intent(inout) :: array_fptr(:,:,:,:) - real(c_double), pointer :: tmp(:,:,:,:) - integer, pointer :: shape(:) - integer, pointer :: strides(:) - integer :: eshape(4) - integer :: j - - if( rank /= 4 ) call atlas_abort("Rank mismatch",atlas_code_location("atlas_Field_module.F90",178)) - - call c_f_pointer ( shape_cptr, shape , [rank] ) - call c_f_pointer ( strides_cptr, strides , [rank] ) - do j=1,rank-1 - if( strides(j) /= 0 ) then - eshape(j) = strides(j+1)/strides(j) - else - eshape(j) = shape(j) - endif - enddo - eshape(rank) = shape(rank) - call c_f_pointer ( array_cptr , tmp , shape=eshape ) - - - - array_fptr => tmp(1:shape(1),1:shape(2),1:shape(3),1:shape(4)) -end subroutine - -!------------------------------------------------------------------------------- - -!------------------------------------------------------------------------------- -subroutine array_c_to_f_logical32_r4(array_cptr,rank,shape_cptr,strides_cptr,array_fptr) - use, intrinsic :: iso_c_binding, only : c_ptr, c_int, c_double, c_long, c_float, c_f_pointer - - type(c_ptr), intent(in) :: array_cptr - integer(c_int), intent(in) :: rank - type(c_ptr), intent(in) :: shape_cptr - type(c_ptr), intent(in) :: strides_cptr - logical, pointer, intent(inout) :: array_fptr(:,:,:,:) - logical, pointer :: tmp(:,:,:,:) - integer, pointer :: shape(:) - integer, pointer :: strides(:) - integer :: eshape(4) - integer :: j - - if( rank /= 4 ) call atlas_abort("Rank mismatch",atlas_code_location("atlas_Field_module.F90",178)) - - call c_f_pointer ( shape_cptr, shape , [rank] ) - call c_f_pointer ( strides_cptr, strides , [rank] ) - do j=1,rank-1 - if( strides(j) /= 0 ) then - eshape(j) = strides(j+1)/strides(j) - else - eshape(j) = shape(j) - endif - enddo - eshape(rank) = shape(rank) - call c_f_pointer ( array_cptr , tmp , shape=eshape ) - - - - array_fptr => tmp(1:shape(1),1:shape(2),1:shape(3),1:shape(4)) -end subroutine - -!------------------------------------------------------------------------------- - -subroutine access_host_data_int32_r1(this, field) - use atlas_field_c_binding - use, intrinsic :: iso_c_binding, only : c_ptr, c_int, c_long, c_float, c_double - class(atlas_Field), intent(in) :: this - integer(c_int), pointer, intent(inout) :: field(:) - type(c_ptr) :: field_cptr - type(c_ptr) :: shape_cptr - type(c_ptr) :: strides_cptr - integer(c_int) :: rank - call atlas__Field__host_data_int_specf(this%c_ptr(), field_cptr, rank, shape_cptr, strides_cptr) - call array_c_to_f(field_cptr,rank,shape_cptr,strides_cptr, field) -end subroutine - -subroutine access_device_data_int32_r1(this, field) - use atlas_field_c_binding - use, intrinsic :: iso_c_binding, only : c_ptr, c_int, c_long, c_float, c_double - class(atlas_Field), intent(in) :: this - integer(c_int), pointer, intent(inout) :: field(:) - type(c_ptr) :: field_cptr - type(c_ptr) :: shape_cptr - type(c_ptr) :: strides_cptr - integer(c_int) :: rank - call atlas__Field__device_data_int_specf(this%c_ptr(), field_cptr, rank, shape_cptr, strides_cptr) - call array_c_to_f(field_cptr,rank,shape_cptr,strides_cptr, field) -end subroutine - -!------------------------------------------------------------------------------- - -subroutine access_host_data_int64_r1(this, field) - use atlas_field_c_binding - use, intrinsic :: iso_c_binding, only : c_ptr, c_int, c_long, c_float, c_double - class(atlas_Field), intent(in) :: this - integer(c_long), pointer, intent(inout) :: field(:) - type(c_ptr) :: field_cptr - type(c_ptr) :: shape_cptr - type(c_ptr) :: strides_cptr - integer(c_int) :: rank - call atlas__Field__host_data_long_specf(this%c_ptr(), field_cptr, rank, shape_cptr, strides_cptr) - call array_c_to_f(field_cptr,rank,shape_cptr,strides_cptr, field) -end subroutine - -subroutine access_device_data_int64_r1(this, field) - use atlas_field_c_binding - use, intrinsic :: iso_c_binding, only : c_ptr, c_int, c_long, c_float, c_double - class(atlas_Field), intent(in) :: this - integer(c_long), pointer, intent(inout) :: field(:) - type(c_ptr) :: field_cptr - type(c_ptr) :: shape_cptr - type(c_ptr) :: strides_cptr - integer(c_int) :: rank - call atlas__Field__device_data_long_specf(this%c_ptr(), field_cptr, rank, shape_cptr, strides_cptr) - call array_c_to_f(field_cptr,rank,shape_cptr,strides_cptr, field) -end subroutine - -!------------------------------------------------------------------------------- - -subroutine access_host_data_real32_r1(this, field) - use atlas_field_c_binding - use, intrinsic :: iso_c_binding, only : c_ptr, c_int, c_long, c_float, c_double - class(atlas_Field), intent(in) :: this - real(c_float), pointer, intent(inout) :: field(:) - type(c_ptr) :: field_cptr - type(c_ptr) :: shape_cptr - type(c_ptr) :: strides_cptr - integer(c_int) :: rank - call atlas__Field__host_data_float_specf(this%c_ptr(), field_cptr, rank, shape_cptr, strides_cptr) - call array_c_to_f(field_cptr,rank,shape_cptr,strides_cptr, field) -end subroutine - -subroutine access_device_data_real32_r1(this, field) - use atlas_field_c_binding - use, intrinsic :: iso_c_binding, only : c_ptr, c_int, c_long, c_float, c_double - class(atlas_Field), intent(in) :: this - real(c_float), pointer, intent(inout) :: field(:) - type(c_ptr) :: field_cptr - type(c_ptr) :: shape_cptr - type(c_ptr) :: strides_cptr - integer(c_int) :: rank - call atlas__Field__device_data_float_specf(this%c_ptr(), field_cptr, rank, shape_cptr, strides_cptr) - call array_c_to_f(field_cptr,rank,shape_cptr,strides_cptr, field) -end subroutine - -!------------------------------------------------------------------------------- - -subroutine access_host_data_real64_r1(this, field) - use atlas_field_c_binding - use, intrinsic :: iso_c_binding, only : c_ptr, c_int, c_long, c_float, c_double - class(atlas_Field), intent(in) :: this - real(c_double), pointer, intent(inout) :: field(:) - type(c_ptr) :: field_cptr - type(c_ptr) :: shape_cptr - type(c_ptr) :: strides_cptr - integer(c_int) :: rank - call atlas__Field__host_data_double_specf(this%c_ptr(), field_cptr, rank, shape_cptr, strides_cptr) - call array_c_to_f(field_cptr,rank,shape_cptr,strides_cptr, field) -end subroutine - -subroutine access_device_data_real64_r1(this, field) - use atlas_field_c_binding - use, intrinsic :: iso_c_binding, only : c_ptr, c_int, c_long, c_float, c_double - class(atlas_Field), intent(in) :: this - real(c_double), pointer, intent(inout) :: field(:) - type(c_ptr) :: field_cptr - type(c_ptr) :: shape_cptr - type(c_ptr) :: strides_cptr - integer(c_int) :: rank - call atlas__Field__device_data_double_specf(this%c_ptr(), field_cptr, rank, shape_cptr, strides_cptr) - call array_c_to_f(field_cptr,rank,shape_cptr,strides_cptr, field) -end subroutine - -!------------------------------------------------------------------------------- - -subroutine access_host_data_logical32_r1(this, field) - use atlas_field_c_binding - use, intrinsic :: iso_c_binding, only : c_ptr, c_int, c_long, c_float, c_double - class(atlas_Field), intent(in) :: this - logical, pointer, intent(inout) :: field(:) - type(c_ptr) :: field_cptr - type(c_ptr) :: shape_cptr - type(c_ptr) :: strides_cptr - integer(c_int) :: rank - call atlas__Field__host_data_int_specf(this%c_ptr(), field_cptr, rank, shape_cptr, strides_cptr) - call array_c_to_f(field_cptr,rank,shape_cptr,strides_cptr, field) -end subroutine - -subroutine access_device_data_logical32_r1(this, field) - use atlas_field_c_binding - use, intrinsic :: iso_c_binding, only : c_ptr, c_int, c_long, c_float, c_double - class(atlas_Field), intent(in) :: this - logical, pointer, intent(inout) :: field(:) - type(c_ptr) :: field_cptr - type(c_ptr) :: shape_cptr - type(c_ptr) :: strides_cptr - integer(c_int) :: rank - call atlas__Field__device_data_int_specf(this%c_ptr(), field_cptr, rank, shape_cptr, strides_cptr) - call array_c_to_f(field_cptr,rank,shape_cptr,strides_cptr, field) -end subroutine - -!------------------------------------------------------------------------------- - -subroutine access_host_data_int32_r2(this, field) - use atlas_field_c_binding - use, intrinsic :: iso_c_binding, only : c_ptr, c_int, c_long, c_float, c_double - class(atlas_Field), intent(in) :: this - integer(c_int), pointer, intent(inout) :: field(:,:) - type(c_ptr) :: field_cptr - type(c_ptr) :: shape_cptr - type(c_ptr) :: strides_cptr - integer(c_int) :: rank - call atlas__Field__host_data_int_specf(this%c_ptr(), field_cptr, rank, shape_cptr, strides_cptr) - call array_c_to_f(field_cptr,rank,shape_cptr,strides_cptr, field) -end subroutine - -subroutine access_device_data_int32_r2(this, field) - use atlas_field_c_binding - use, intrinsic :: iso_c_binding, only : c_ptr, c_int, c_long, c_float, c_double - class(atlas_Field), intent(in) :: this - integer(c_int), pointer, intent(inout) :: field(:,:) - type(c_ptr) :: field_cptr - type(c_ptr) :: shape_cptr - type(c_ptr) :: strides_cptr - integer(c_int) :: rank - call atlas__Field__device_data_int_specf(this%c_ptr(), field_cptr, rank, shape_cptr, strides_cptr) - call array_c_to_f(field_cptr,rank,shape_cptr,strides_cptr, field) -end subroutine - -!------------------------------------------------------------------------------- - -subroutine access_host_data_int64_r2(this, field) - use atlas_field_c_binding - use, intrinsic :: iso_c_binding, only : c_ptr, c_int, c_long, c_float, c_double - class(atlas_Field), intent(in) :: this - integer(c_long), pointer, intent(inout) :: field(:,:) - type(c_ptr) :: field_cptr - type(c_ptr) :: shape_cptr - type(c_ptr) :: strides_cptr - integer(c_int) :: rank - call atlas__Field__host_data_long_specf(this%c_ptr(), field_cptr, rank, shape_cptr, strides_cptr) - call array_c_to_f(field_cptr,rank,shape_cptr,strides_cptr, field) -end subroutine - -subroutine access_device_data_int64_r2(this, field) - use atlas_field_c_binding - use, intrinsic :: iso_c_binding, only : c_ptr, c_int, c_long, c_float, c_double - class(atlas_Field), intent(in) :: this - integer(c_long), pointer, intent(inout) :: field(:,:) - type(c_ptr) :: field_cptr - type(c_ptr) :: shape_cptr - type(c_ptr) :: strides_cptr - integer(c_int) :: rank - call atlas__Field__device_data_long_specf(this%c_ptr(), field_cptr, rank, shape_cptr, strides_cptr) - call array_c_to_f(field_cptr,rank,shape_cptr,strides_cptr, field) -end subroutine - -!------------------------------------------------------------------------------- - -subroutine access_host_data_real32_r2(this, field) - use atlas_field_c_binding - use, intrinsic :: iso_c_binding, only : c_ptr, c_int, c_long, c_float, c_double - class(atlas_Field), intent(in) :: this - real(c_float), pointer, intent(inout) :: field(:,:) - type(c_ptr) :: field_cptr - type(c_ptr) :: shape_cptr - type(c_ptr) :: strides_cptr - integer(c_int) :: rank - call atlas__Field__host_data_float_specf(this%c_ptr(), field_cptr, rank, shape_cptr, strides_cptr) - call array_c_to_f(field_cptr,rank,shape_cptr,strides_cptr, field) -end subroutine - -subroutine access_device_data_real32_r2(this, field) - use atlas_field_c_binding - use, intrinsic :: iso_c_binding, only : c_ptr, c_int, c_long, c_float, c_double - class(atlas_Field), intent(in) :: this - real(c_float), pointer, intent(inout) :: field(:,:) - type(c_ptr) :: field_cptr - type(c_ptr) :: shape_cptr - type(c_ptr) :: strides_cptr - integer(c_int) :: rank - call atlas__Field__device_data_float_specf(this%c_ptr(), field_cptr, rank, shape_cptr, strides_cptr) - call array_c_to_f(field_cptr,rank,shape_cptr,strides_cptr, field) -end subroutine - -!------------------------------------------------------------------------------- - -subroutine access_host_data_real64_r2(this, field) - use atlas_field_c_binding - use, intrinsic :: iso_c_binding, only : c_ptr, c_int, c_long, c_float, c_double - class(atlas_Field), intent(in) :: this - real(c_double), pointer, intent(inout) :: field(:,:) - type(c_ptr) :: field_cptr - type(c_ptr) :: shape_cptr - type(c_ptr) :: strides_cptr - integer(c_int) :: rank - call atlas__Field__host_data_double_specf(this%c_ptr(), field_cptr, rank, shape_cptr, strides_cptr) - call array_c_to_f(field_cptr,rank,shape_cptr,strides_cptr, field) -end subroutine - -subroutine access_device_data_real64_r2(this, field) - use atlas_field_c_binding - use, intrinsic :: iso_c_binding, only : c_ptr, c_int, c_long, c_float, c_double - class(atlas_Field), intent(in) :: this - real(c_double), pointer, intent(inout) :: field(:,:) - type(c_ptr) :: field_cptr - type(c_ptr) :: shape_cptr - type(c_ptr) :: strides_cptr - integer(c_int) :: rank - call atlas__Field__device_data_double_specf(this%c_ptr(), field_cptr, rank, shape_cptr, strides_cptr) - call array_c_to_f(field_cptr,rank,shape_cptr,strides_cptr, field) -end subroutine - -!------------------------------------------------------------------------------- - -subroutine access_host_data_logical32_r2(this, field) - use atlas_field_c_binding - use, intrinsic :: iso_c_binding, only : c_ptr, c_int, c_long, c_float, c_double - class(atlas_Field), intent(in) :: this - logical, pointer, intent(inout) :: field(:,:) - type(c_ptr) :: field_cptr - type(c_ptr) :: shape_cptr - type(c_ptr) :: strides_cptr - integer(c_int) :: rank - call atlas__Field__host_data_int_specf(this%c_ptr(), field_cptr, rank, shape_cptr, strides_cptr) - call array_c_to_f(field_cptr,rank,shape_cptr,strides_cptr, field) -end subroutine - -subroutine access_device_data_logical32_r2(this, field) - use atlas_field_c_binding - use, intrinsic :: iso_c_binding, only : c_ptr, c_int, c_long, c_float, c_double - class(atlas_Field), intent(in) :: this - logical, pointer, intent(inout) :: field(:,:) - type(c_ptr) :: field_cptr - type(c_ptr) :: shape_cptr - type(c_ptr) :: strides_cptr - integer(c_int) :: rank - call atlas__Field__device_data_int_specf(this%c_ptr(), field_cptr, rank, shape_cptr, strides_cptr) - call array_c_to_f(field_cptr,rank,shape_cptr,strides_cptr, field) -end subroutine - -!------------------------------------------------------------------------------- - -subroutine access_host_data_int32_r3(this, field) - use atlas_field_c_binding - use, intrinsic :: iso_c_binding, only : c_ptr, c_int, c_long, c_float, c_double - class(atlas_Field), intent(in) :: this - integer(c_int), pointer, intent(inout) :: field(:,:,:) - type(c_ptr) :: field_cptr - type(c_ptr) :: shape_cptr - type(c_ptr) :: strides_cptr - integer(c_int) :: rank - call atlas__Field__host_data_int_specf(this%c_ptr(), field_cptr, rank, shape_cptr, strides_cptr) - call array_c_to_f(field_cptr,rank,shape_cptr,strides_cptr, field) -end subroutine - -subroutine access_device_data_int32_r3(this, field) - use atlas_field_c_binding - use, intrinsic :: iso_c_binding, only : c_ptr, c_int, c_long, c_float, c_double - class(atlas_Field), intent(in) :: this - integer(c_int), pointer, intent(inout) :: field(:,:,:) - type(c_ptr) :: field_cptr - type(c_ptr) :: shape_cptr - type(c_ptr) :: strides_cptr - integer(c_int) :: rank - call atlas__Field__device_data_int_specf(this%c_ptr(), field_cptr, rank, shape_cptr, strides_cptr) - call array_c_to_f(field_cptr,rank,shape_cptr,strides_cptr, field) -end subroutine - -!------------------------------------------------------------------------------- - -subroutine access_host_data_int64_r3(this, field) - use atlas_field_c_binding - use, intrinsic :: iso_c_binding, only : c_ptr, c_int, c_long, c_float, c_double - class(atlas_Field), intent(in) :: this - integer(c_long), pointer, intent(inout) :: field(:,:,:) - type(c_ptr) :: field_cptr - type(c_ptr) :: shape_cptr - type(c_ptr) :: strides_cptr - integer(c_int) :: rank - call atlas__Field__host_data_long_specf(this%c_ptr(), field_cptr, rank, shape_cptr, strides_cptr) - call array_c_to_f(field_cptr,rank,shape_cptr,strides_cptr, field) -end subroutine - -subroutine access_device_data_int64_r3(this, field) - use atlas_field_c_binding - use, intrinsic :: iso_c_binding, only : c_ptr, c_int, c_long, c_float, c_double - class(atlas_Field), intent(in) :: this - integer(c_long), pointer, intent(inout) :: field(:,:,:) - type(c_ptr) :: field_cptr - type(c_ptr) :: shape_cptr - type(c_ptr) :: strides_cptr - integer(c_int) :: rank - call atlas__Field__device_data_long_specf(this%c_ptr(), field_cptr, rank, shape_cptr, strides_cptr) - call array_c_to_f(field_cptr,rank,shape_cptr,strides_cptr, field) -end subroutine - -!------------------------------------------------------------------------------- - -subroutine access_host_data_real32_r3(this, field) - use atlas_field_c_binding - use, intrinsic :: iso_c_binding, only : c_ptr, c_int, c_long, c_float, c_double - class(atlas_Field), intent(in) :: this - real(c_float), pointer, intent(inout) :: field(:,:,:) - type(c_ptr) :: field_cptr - type(c_ptr) :: shape_cptr - type(c_ptr) :: strides_cptr - integer(c_int) :: rank - call atlas__Field__host_data_float_specf(this%c_ptr(), field_cptr, rank, shape_cptr, strides_cptr) - call array_c_to_f(field_cptr,rank,shape_cptr,strides_cptr, field) -end subroutine - -subroutine access_device_data_real32_r3(this, field) - use atlas_field_c_binding - use, intrinsic :: iso_c_binding, only : c_ptr, c_int, c_long, c_float, c_double - class(atlas_Field), intent(in) :: this - real(c_float), pointer, intent(inout) :: field(:,:,:) - type(c_ptr) :: field_cptr - type(c_ptr) :: shape_cptr - type(c_ptr) :: strides_cptr - integer(c_int) :: rank - call atlas__Field__device_data_float_specf(this%c_ptr(), field_cptr, rank, shape_cptr, strides_cptr) - call array_c_to_f(field_cptr,rank,shape_cptr,strides_cptr, field) -end subroutine - -!------------------------------------------------------------------------------- - -subroutine access_host_data_real64_r3(this, field) - use atlas_field_c_binding - use, intrinsic :: iso_c_binding, only : c_ptr, c_int, c_long, c_float, c_double - class(atlas_Field), intent(in) :: this - real(c_double), pointer, intent(inout) :: field(:,:,:) - type(c_ptr) :: field_cptr - type(c_ptr) :: shape_cptr - type(c_ptr) :: strides_cptr - integer(c_int) :: rank - call atlas__Field__host_data_double_specf(this%c_ptr(), field_cptr, rank, shape_cptr, strides_cptr) - call array_c_to_f(field_cptr,rank,shape_cptr,strides_cptr, field) -end subroutine - -subroutine access_device_data_real64_r3(this, field) - use atlas_field_c_binding - use, intrinsic :: iso_c_binding, only : c_ptr, c_int, c_long, c_float, c_double - class(atlas_Field), intent(in) :: this - real(c_double), pointer, intent(inout) :: field(:,:,:) - type(c_ptr) :: field_cptr - type(c_ptr) :: shape_cptr - type(c_ptr) :: strides_cptr - integer(c_int) :: rank - call atlas__Field__device_data_double_specf(this%c_ptr(), field_cptr, rank, shape_cptr, strides_cptr) - call array_c_to_f(field_cptr,rank,shape_cptr,strides_cptr, field) -end subroutine - -!------------------------------------------------------------------------------- - -subroutine access_host_data_logical32_r3(this, field) - use atlas_field_c_binding - use, intrinsic :: iso_c_binding, only : c_ptr, c_int, c_long, c_float, c_double - class(atlas_Field), intent(in) :: this - logical, pointer, intent(inout) :: field(:,:,:) - type(c_ptr) :: field_cptr - type(c_ptr) :: shape_cptr - type(c_ptr) :: strides_cptr - integer(c_int) :: rank - call atlas__Field__host_data_int_specf(this%c_ptr(), field_cptr, rank, shape_cptr, strides_cptr) - call array_c_to_f(field_cptr,rank,shape_cptr,strides_cptr, field) -end subroutine - -subroutine access_device_data_logical32_r3(this, field) - use atlas_field_c_binding - use, intrinsic :: iso_c_binding, only : c_ptr, c_int, c_long, c_float, c_double - class(atlas_Field), intent(in) :: this - logical, pointer, intent(inout) :: field(:,:,:) - type(c_ptr) :: field_cptr - type(c_ptr) :: shape_cptr - type(c_ptr) :: strides_cptr - integer(c_int) :: rank - call atlas__Field__device_data_int_specf(this%c_ptr(), field_cptr, rank, shape_cptr, strides_cptr) - call array_c_to_f(field_cptr,rank,shape_cptr,strides_cptr, field) -end subroutine - -!------------------------------------------------------------------------------- - -subroutine access_host_data_int32_r4(this, field) - use atlas_field_c_binding - use, intrinsic :: iso_c_binding, only : c_ptr, c_int, c_long, c_float, c_double - class(atlas_Field), intent(in) :: this - integer(c_int), pointer, intent(inout) :: field(:,:,:,:) - type(c_ptr) :: field_cptr - type(c_ptr) :: shape_cptr - type(c_ptr) :: strides_cptr - integer(c_int) :: rank - call atlas__Field__host_data_int_specf(this%c_ptr(), field_cptr, rank, shape_cptr, strides_cptr) - call array_c_to_f(field_cptr,rank,shape_cptr,strides_cptr, field) -end subroutine - -subroutine access_device_data_int32_r4(this, field) - use atlas_field_c_binding - use, intrinsic :: iso_c_binding, only : c_ptr, c_int, c_long, c_float, c_double - class(atlas_Field), intent(in) :: this - integer(c_int), pointer, intent(inout) :: field(:,:,:,:) - type(c_ptr) :: field_cptr - type(c_ptr) :: shape_cptr - type(c_ptr) :: strides_cptr - integer(c_int) :: rank - call atlas__Field__device_data_int_specf(this%c_ptr(), field_cptr, rank, shape_cptr, strides_cptr) - call array_c_to_f(field_cptr,rank,shape_cptr,strides_cptr, field) -end subroutine - -!------------------------------------------------------------------------------- - -subroutine access_host_data_int64_r4(this, field) - use atlas_field_c_binding - use, intrinsic :: iso_c_binding, only : c_ptr, c_int, c_long, c_float, c_double - class(atlas_Field), intent(in) :: this - integer(c_long), pointer, intent(inout) :: field(:,:,:,:) - type(c_ptr) :: field_cptr - type(c_ptr) :: shape_cptr - type(c_ptr) :: strides_cptr - integer(c_int) :: rank - call atlas__Field__host_data_long_specf(this%c_ptr(), field_cptr, rank, shape_cptr, strides_cptr) - call array_c_to_f(field_cptr,rank,shape_cptr,strides_cptr, field) -end subroutine - -subroutine access_device_data_int64_r4(this, field) - use atlas_field_c_binding - use, intrinsic :: iso_c_binding, only : c_ptr, c_int, c_long, c_float, c_double - class(atlas_Field), intent(in) :: this - integer(c_long), pointer, intent(inout) :: field(:,:,:,:) - type(c_ptr) :: field_cptr - type(c_ptr) :: shape_cptr - type(c_ptr) :: strides_cptr - integer(c_int) :: rank - call atlas__Field__device_data_long_specf(this%c_ptr(), field_cptr, rank, shape_cptr, strides_cptr) - call array_c_to_f(field_cptr,rank,shape_cptr,strides_cptr, field) -end subroutine - -!------------------------------------------------------------------------------- - -subroutine access_host_data_real32_r4(this, field) - use atlas_field_c_binding - use, intrinsic :: iso_c_binding, only : c_ptr, c_int, c_long, c_float, c_double - class(atlas_Field), intent(in) :: this - real(c_float), pointer, intent(inout) :: field(:,:,:,:) - type(c_ptr) :: field_cptr - type(c_ptr) :: shape_cptr - type(c_ptr) :: strides_cptr - integer(c_int) :: rank - call atlas__Field__host_data_float_specf(this%c_ptr(), field_cptr, rank, shape_cptr, strides_cptr) - call array_c_to_f(field_cptr,rank,shape_cptr,strides_cptr, field) -end subroutine - -subroutine access_device_data_real32_r4(this, field) - use atlas_field_c_binding - use, intrinsic :: iso_c_binding, only : c_ptr, c_int, c_long, c_float, c_double - class(atlas_Field), intent(in) :: this - real(c_float), pointer, intent(inout) :: field(:,:,:,:) - type(c_ptr) :: field_cptr - type(c_ptr) :: shape_cptr - type(c_ptr) :: strides_cptr - integer(c_int) :: rank - call atlas__Field__device_data_float_specf(this%c_ptr(), field_cptr, rank, shape_cptr, strides_cptr) - call array_c_to_f(field_cptr,rank,shape_cptr,strides_cptr, field) -end subroutine - -!------------------------------------------------------------------------------- - -subroutine access_host_data_real64_r4(this, field) - use atlas_field_c_binding - use, intrinsic :: iso_c_binding, only : c_ptr, c_int, c_long, c_float, c_double - class(atlas_Field), intent(in) :: this - real(c_double), pointer, intent(inout) :: field(:,:,:,:) - type(c_ptr) :: field_cptr - type(c_ptr) :: shape_cptr - type(c_ptr) :: strides_cptr - integer(c_int) :: rank - call atlas__Field__host_data_double_specf(this%c_ptr(), field_cptr, rank, shape_cptr, strides_cptr) - call array_c_to_f(field_cptr,rank,shape_cptr,strides_cptr, field) -end subroutine - -subroutine access_device_data_real64_r4(this, field) - use atlas_field_c_binding - use, intrinsic :: iso_c_binding, only : c_ptr, c_int, c_long, c_float, c_double - class(atlas_Field), intent(in) :: this - real(c_double), pointer, intent(inout) :: field(:,:,:,:) - type(c_ptr) :: field_cptr - type(c_ptr) :: shape_cptr - type(c_ptr) :: strides_cptr - integer(c_int) :: rank - call atlas__Field__device_data_double_specf(this%c_ptr(), field_cptr, rank, shape_cptr, strides_cptr) - call array_c_to_f(field_cptr,rank,shape_cptr,strides_cptr, field) -end subroutine - -!------------------------------------------------------------------------------- - -subroutine access_host_data_logical32_r4(this, field) - use atlas_field_c_binding - use, intrinsic :: iso_c_binding, only : c_ptr, c_int, c_long, c_float, c_double - class(atlas_Field), intent(in) :: this - logical, pointer, intent(inout) :: field(:,:,:,:) - type(c_ptr) :: field_cptr - type(c_ptr) :: shape_cptr - type(c_ptr) :: strides_cptr - integer(c_int) :: rank - call atlas__Field__host_data_int_specf(this%c_ptr(), field_cptr, rank, shape_cptr, strides_cptr) - call array_c_to_f(field_cptr,rank,shape_cptr,strides_cptr, field) -end subroutine - -subroutine access_device_data_logical32_r4(this, field) - use atlas_field_c_binding - use, intrinsic :: iso_c_binding, only : c_ptr, c_int, c_long, c_float, c_double - class(atlas_Field), intent(in) :: this - logical, pointer, intent(inout) :: field(:,:,:,:) - type(c_ptr) :: field_cptr - type(c_ptr) :: shape_cptr - type(c_ptr) :: strides_cptr - integer(c_int) :: rank - call atlas__Field__device_data_int_specf(this%c_ptr(), field_cptr, rank, shape_cptr, strides_cptr) - call array_c_to_f(field_cptr,rank,shape_cptr,strides_cptr, field) -end subroutine - -!------------------------------------------------------------------------------- - -subroutine access_host_data_int32_r1_shape(this, field, shape) - use atlas_field_c_binding - use, intrinsic :: iso_c_binding, only : c_ptr, c_int, c_long, c_float, c_double, c_f_pointer - class(atlas_Field), intent(in) :: this - integer(c_int), pointer, intent(inout) :: field(:) - integer(c_int), intent(in) :: shape(:) - type(c_ptr) :: field_cptr - type(c_ptr) :: shape_cptr - type(c_ptr) :: strides_cptr - integer(c_int) :: rank - call atlas__Field__host_data_int_specf(this%c_ptr(), field_cptr, rank, shape_cptr, strides_cptr) - call c_f_pointer( field_cptr, field, shape ) -end subroutine - -subroutine access_device_data_int32_r1_shape(this, field, shape) - use atlas_field_c_binding - use, intrinsic :: iso_c_binding, only : c_ptr, c_int, c_long, c_float, c_double, c_f_pointer - class(atlas_Field), intent(in) :: this - integer(c_int), pointer, intent(inout) :: field(:) - integer(c_int), intent(in) :: shape(:) - type(c_ptr) :: field_cptr - type(c_ptr) :: shape_cptr - type(c_ptr) :: strides_cptr - integer(c_int) :: rank - call atlas__Field__device_data_int_specf(this%c_ptr(), field_cptr, rank, shape_cptr, strides_cptr) - call c_f_pointer( field_cptr, field, shape ) -end subroutine - -!------------------------------------------------------------------------------- -subroutine access_host_data_int64_r1_shape(this, field, shape) - use atlas_field_c_binding - use, intrinsic :: iso_c_binding, only : c_ptr, c_int, c_long, c_float, c_double, c_f_pointer - class(atlas_Field), intent(in) :: this - integer(c_long), pointer, intent(inout) :: field(:) - integer(c_int), intent(in) :: shape(:) - type(c_ptr) :: field_cptr - type(c_ptr) :: shape_cptr - type(c_ptr) :: strides_cptr - integer(c_int) :: rank - call atlas__Field__host_data_long_specf(this%c_ptr(), field_cptr, rank, shape_cptr, strides_cptr) - call c_f_pointer( field_cptr, field, shape ) -end subroutine - -subroutine access_device_data_int64_r1_shape(this, field, shape) - use atlas_field_c_binding - use, intrinsic :: iso_c_binding, only : c_ptr, c_int, c_long, c_float, c_double, c_f_pointer - class(atlas_Field), intent(in) :: this - integer(c_long), pointer, intent(inout) :: field(:) - integer(c_int), intent(in) :: shape(:) - type(c_ptr) :: field_cptr - type(c_ptr) :: shape_cptr - type(c_ptr) :: strides_cptr - integer(c_int) :: rank - call atlas__Field__device_data_long_specf(this%c_ptr(), field_cptr, rank, shape_cptr, strides_cptr) - call c_f_pointer( field_cptr, field, shape ) -end subroutine - -!------------------------------------------------------------------------------- -subroutine access_host_data_real32_r1_shape(this, field, shape) - use atlas_field_c_binding - use, intrinsic :: iso_c_binding, only : c_ptr, c_int, c_long, c_float, c_double, c_f_pointer - class(atlas_Field), intent(in) :: this - real(c_float), pointer, intent(inout) :: field(:) - integer(c_int), intent(in) :: shape(:) - type(c_ptr) :: field_cptr - type(c_ptr) :: shape_cptr - type(c_ptr) :: strides_cptr - integer(c_int) :: rank - call atlas__Field__host_data_float_specf(this%c_ptr(), field_cptr, rank, shape_cptr, strides_cptr) - call c_f_pointer( field_cptr, field, shape ) -end subroutine - -subroutine access_device_data_real32_r1_shape(this, field, shape) - use atlas_field_c_binding - use, intrinsic :: iso_c_binding, only : c_ptr, c_int, c_long, c_float, c_double, c_f_pointer - class(atlas_Field), intent(in) :: this - real(c_float), pointer, intent(inout) :: field(:) - integer(c_int), intent(in) :: shape(:) - type(c_ptr) :: field_cptr - type(c_ptr) :: shape_cptr - type(c_ptr) :: strides_cptr - integer(c_int) :: rank - call atlas__Field__device_data_float_specf(this%c_ptr(), field_cptr, rank, shape_cptr, strides_cptr) - call c_f_pointer( field_cptr, field, shape ) -end subroutine - -!------------------------------------------------------------------------------- -subroutine access_host_data_real64_r1_shape(this, field, shape) - use atlas_field_c_binding - use, intrinsic :: iso_c_binding, only : c_ptr, c_int, c_long, c_float, c_double, c_f_pointer - class(atlas_Field), intent(in) :: this - real(c_double), pointer, intent(inout) :: field(:) - integer(c_int), intent(in) :: shape(:) - type(c_ptr) :: field_cptr - type(c_ptr) :: shape_cptr - type(c_ptr) :: strides_cptr - integer(c_int) :: rank - call atlas__Field__host_data_double_specf(this%c_ptr(), field_cptr, rank, shape_cptr, strides_cptr) - call c_f_pointer( field_cptr, field, shape ) -end subroutine - -subroutine access_device_data_real64_r1_shape(this, field, shape) - use atlas_field_c_binding - use, intrinsic :: iso_c_binding, only : c_ptr, c_int, c_long, c_float, c_double, c_f_pointer - class(atlas_Field), intent(in) :: this - real(c_double), pointer, intent(inout) :: field(:) - integer(c_int), intent(in) :: shape(:) - type(c_ptr) :: field_cptr - type(c_ptr) :: shape_cptr - type(c_ptr) :: strides_cptr - integer(c_int) :: rank - call atlas__Field__device_data_double_specf(this%c_ptr(), field_cptr, rank, shape_cptr, strides_cptr) - call c_f_pointer( field_cptr, field, shape ) -end subroutine - -!------------------------------------------------------------------------------- -subroutine access_host_data_logical32_r1_shape(this, field, shape) - use atlas_field_c_binding - use, intrinsic :: iso_c_binding, only : c_ptr, c_int, c_long, c_float, c_double, c_f_pointer - class(atlas_Field), intent(in) :: this - logical, pointer, intent(inout) :: field(:) - integer(c_int), intent(in) :: shape(:) - type(c_ptr) :: field_cptr - type(c_ptr) :: shape_cptr - type(c_ptr) :: strides_cptr - integer(c_int) :: rank - call atlas__Field__host_data_int_specf(this%c_ptr(), field_cptr, rank, shape_cptr, strides_cptr) - call c_f_pointer( field_cptr, field, shape ) -end subroutine - -subroutine access_device_data_logical32_r1_shape(this, field, shape) - use atlas_field_c_binding - use, intrinsic :: iso_c_binding, only : c_ptr, c_int, c_long, c_float, c_double, c_f_pointer - class(atlas_Field), intent(in) :: this - logical, pointer, intent(inout) :: field(:) - integer(c_int), intent(in) :: shape(:) - type(c_ptr) :: field_cptr - type(c_ptr) :: shape_cptr - type(c_ptr) :: strides_cptr - integer(c_int) :: rank - call atlas__Field__device_data_int_specf(this%c_ptr(), field_cptr, rank, shape_cptr, strides_cptr) - call c_f_pointer( field_cptr, field, shape ) -end subroutine - -!------------------------------------------------------------------------------- -subroutine access_host_data_int32_r2_shape(this, field, shape) - use atlas_field_c_binding - use, intrinsic :: iso_c_binding, only : c_ptr, c_int, c_long, c_float, c_double, c_f_pointer - class(atlas_Field), intent(in) :: this - integer(c_int), pointer, intent(inout) :: field(:,:) - integer(c_int), intent(in) :: shape(:) - type(c_ptr) :: field_cptr - type(c_ptr) :: shape_cptr - type(c_ptr) :: strides_cptr - integer(c_int) :: rank - call atlas__Field__host_data_int_specf(this%c_ptr(), field_cptr, rank, shape_cptr, strides_cptr) - call c_f_pointer( field_cptr, field, shape ) -end subroutine - -subroutine access_device_data_int32_r2_shape(this, field, shape) - use atlas_field_c_binding - use, intrinsic :: iso_c_binding, only : c_ptr, c_int, c_long, c_float, c_double, c_f_pointer - class(atlas_Field), intent(in) :: this - integer(c_int), pointer, intent(inout) :: field(:,:) - integer(c_int), intent(in) :: shape(:) - type(c_ptr) :: field_cptr - type(c_ptr) :: shape_cptr - type(c_ptr) :: strides_cptr - integer(c_int) :: rank - call atlas__Field__device_data_int_specf(this%c_ptr(), field_cptr, rank, shape_cptr, strides_cptr) - call c_f_pointer( field_cptr, field, shape ) -end subroutine - -!------------------------------------------------------------------------------- -subroutine access_host_data_int64_r2_shape(this, field, shape) - use atlas_field_c_binding - use, intrinsic :: iso_c_binding, only : c_ptr, c_int, c_long, c_float, c_double, c_f_pointer - class(atlas_Field), intent(in) :: this - integer(c_long), pointer, intent(inout) :: field(:,:) - integer(c_int), intent(in) :: shape(:) - type(c_ptr) :: field_cptr - type(c_ptr) :: shape_cptr - type(c_ptr) :: strides_cptr - integer(c_int) :: rank - call atlas__Field__host_data_long_specf(this%c_ptr(), field_cptr, rank, shape_cptr, strides_cptr) - call c_f_pointer( field_cptr, field, shape ) -end subroutine - -subroutine access_device_data_int64_r2_shape(this, field, shape) - use atlas_field_c_binding - use, intrinsic :: iso_c_binding, only : c_ptr, c_int, c_long, c_float, c_double, c_f_pointer - class(atlas_Field), intent(in) :: this - integer(c_long), pointer, intent(inout) :: field(:,:) - integer(c_int), intent(in) :: shape(:) - type(c_ptr) :: field_cptr - type(c_ptr) :: shape_cptr - type(c_ptr) :: strides_cptr - integer(c_int) :: rank - call atlas__Field__device_data_long_specf(this%c_ptr(), field_cptr, rank, shape_cptr, strides_cptr) - call c_f_pointer( field_cptr, field, shape ) -end subroutine - -!------------------------------------------------------------------------------- -subroutine access_host_data_real32_r2_shape(this, field, shape) - use atlas_field_c_binding - use, intrinsic :: iso_c_binding, only : c_ptr, c_int, c_long, c_float, c_double, c_f_pointer - class(atlas_Field), intent(in) :: this - real(c_float), pointer, intent(inout) :: field(:,:) - integer(c_int), intent(in) :: shape(:) - type(c_ptr) :: field_cptr - type(c_ptr) :: shape_cptr - type(c_ptr) :: strides_cptr - integer(c_int) :: rank - call atlas__Field__host_data_float_specf(this%c_ptr(), field_cptr, rank, shape_cptr, strides_cptr) - call c_f_pointer( field_cptr, field, shape ) -end subroutine - -subroutine access_device_data_real32_r2_shape(this, field, shape) - use atlas_field_c_binding - use, intrinsic :: iso_c_binding, only : c_ptr, c_int, c_long, c_float, c_double, c_f_pointer - class(atlas_Field), intent(in) :: this - real(c_float), pointer, intent(inout) :: field(:,:) - integer(c_int), intent(in) :: shape(:) - type(c_ptr) :: field_cptr - type(c_ptr) :: shape_cptr - type(c_ptr) :: strides_cptr - integer(c_int) :: rank - call atlas__Field__device_data_float_specf(this%c_ptr(), field_cptr, rank, shape_cptr, strides_cptr) - call c_f_pointer( field_cptr, field, shape ) -end subroutine - -!------------------------------------------------------------------------------- -subroutine access_host_data_real64_r2_shape(this, field, shape) - use atlas_field_c_binding - use, intrinsic :: iso_c_binding, only : c_ptr, c_int, c_long, c_float, c_double, c_f_pointer - class(atlas_Field), intent(in) :: this - real(c_double), pointer, intent(inout) :: field(:,:) - integer(c_int), intent(in) :: shape(:) - type(c_ptr) :: field_cptr - type(c_ptr) :: shape_cptr - type(c_ptr) :: strides_cptr - integer(c_int) :: rank - call atlas__Field__host_data_double_specf(this%c_ptr(), field_cptr, rank, shape_cptr, strides_cptr) - call c_f_pointer( field_cptr, field, shape ) -end subroutine - -subroutine access_device_data_real64_r2_shape(this, field, shape) - use atlas_field_c_binding - use, intrinsic :: iso_c_binding, only : c_ptr, c_int, c_long, c_float, c_double, c_f_pointer - class(atlas_Field), intent(in) :: this - real(c_double), pointer, intent(inout) :: field(:,:) - integer(c_int), intent(in) :: shape(:) - type(c_ptr) :: field_cptr - type(c_ptr) :: shape_cptr - type(c_ptr) :: strides_cptr - integer(c_int) :: rank - call atlas__Field__device_data_double_specf(this%c_ptr(), field_cptr, rank, shape_cptr, strides_cptr) - call c_f_pointer( field_cptr, field, shape ) -end subroutine - -!------------------------------------------------------------------------------- -subroutine access_host_data_logical32_r2_shape(this, field, shape) - use atlas_field_c_binding - use, intrinsic :: iso_c_binding, only : c_ptr, c_int, c_long, c_float, c_double, c_f_pointer - class(atlas_Field), intent(in) :: this - logical, pointer, intent(inout) :: field(:,:) - integer(c_int), intent(in) :: shape(:) - type(c_ptr) :: field_cptr - type(c_ptr) :: shape_cptr - type(c_ptr) :: strides_cptr - integer(c_int) :: rank - call atlas__Field__host_data_int_specf(this%c_ptr(), field_cptr, rank, shape_cptr, strides_cptr) - call c_f_pointer( field_cptr, field, shape ) -end subroutine - -subroutine access_device_data_logical32_r2_shape(this, field, shape) - use atlas_field_c_binding - use, intrinsic :: iso_c_binding, only : c_ptr, c_int, c_long, c_float, c_double, c_f_pointer - class(atlas_Field), intent(in) :: this - logical, pointer, intent(inout) :: field(:,:) - integer(c_int), intent(in) :: shape(:) - type(c_ptr) :: field_cptr - type(c_ptr) :: shape_cptr - type(c_ptr) :: strides_cptr - integer(c_int) :: rank - call atlas__Field__device_data_int_specf(this%c_ptr(), field_cptr, rank, shape_cptr, strides_cptr) - call c_f_pointer( field_cptr, field, shape ) -end subroutine - -!------------------------------------------------------------------------------- -subroutine access_host_data_int32_r3_shape(this, field, shape) - use atlas_field_c_binding - use, intrinsic :: iso_c_binding, only : c_ptr, c_int, c_long, c_float, c_double, c_f_pointer - class(atlas_Field), intent(in) :: this - integer(c_int), pointer, intent(inout) :: field(:,:,:) - integer(c_int), intent(in) :: shape(:) - type(c_ptr) :: field_cptr - type(c_ptr) :: shape_cptr - type(c_ptr) :: strides_cptr - integer(c_int) :: rank - call atlas__Field__host_data_int_specf(this%c_ptr(), field_cptr, rank, shape_cptr, strides_cptr) - call c_f_pointer( field_cptr, field, shape ) -end subroutine - -subroutine access_device_data_int32_r3_shape(this, field, shape) - use atlas_field_c_binding - use, intrinsic :: iso_c_binding, only : c_ptr, c_int, c_long, c_float, c_double, c_f_pointer - class(atlas_Field), intent(in) :: this - integer(c_int), pointer, intent(inout) :: field(:,:,:) - integer(c_int), intent(in) :: shape(:) - type(c_ptr) :: field_cptr - type(c_ptr) :: shape_cptr - type(c_ptr) :: strides_cptr - integer(c_int) :: rank - call atlas__Field__device_data_int_specf(this%c_ptr(), field_cptr, rank, shape_cptr, strides_cptr) - call c_f_pointer( field_cptr, field, shape ) -end subroutine - -!------------------------------------------------------------------------------- -subroutine access_host_data_int64_r3_shape(this, field, shape) - use atlas_field_c_binding - use, intrinsic :: iso_c_binding, only : c_ptr, c_int, c_long, c_float, c_double, c_f_pointer - class(atlas_Field), intent(in) :: this - integer(c_long), pointer, intent(inout) :: field(:,:,:) - integer(c_int), intent(in) :: shape(:) - type(c_ptr) :: field_cptr - type(c_ptr) :: shape_cptr - type(c_ptr) :: strides_cptr - integer(c_int) :: rank - call atlas__Field__host_data_long_specf(this%c_ptr(), field_cptr, rank, shape_cptr, strides_cptr) - call c_f_pointer( field_cptr, field, shape ) -end subroutine - -subroutine access_device_data_int64_r3_shape(this, field, shape) - use atlas_field_c_binding - use, intrinsic :: iso_c_binding, only : c_ptr, c_int, c_long, c_float, c_double, c_f_pointer - class(atlas_Field), intent(in) :: this - integer(c_long), pointer, intent(inout) :: field(:,:,:) - integer(c_int), intent(in) :: shape(:) - type(c_ptr) :: field_cptr - type(c_ptr) :: shape_cptr - type(c_ptr) :: strides_cptr - integer(c_int) :: rank - call atlas__Field__device_data_long_specf(this%c_ptr(), field_cptr, rank, shape_cptr, strides_cptr) - call c_f_pointer( field_cptr, field, shape ) -end subroutine - -!------------------------------------------------------------------------------- -subroutine access_host_data_real32_r3_shape(this, field, shape) - use atlas_field_c_binding - use, intrinsic :: iso_c_binding, only : c_ptr, c_int, c_long, c_float, c_double, c_f_pointer - class(atlas_Field), intent(in) :: this - real(c_float), pointer, intent(inout) :: field(:,:,:) - integer(c_int), intent(in) :: shape(:) - type(c_ptr) :: field_cptr - type(c_ptr) :: shape_cptr - type(c_ptr) :: strides_cptr - integer(c_int) :: rank - call atlas__Field__host_data_float_specf(this%c_ptr(), field_cptr, rank, shape_cptr, strides_cptr) - call c_f_pointer( field_cptr, field, shape ) -end subroutine - -subroutine access_device_data_real32_r3_shape(this, field, shape) - use atlas_field_c_binding - use, intrinsic :: iso_c_binding, only : c_ptr, c_int, c_long, c_float, c_double, c_f_pointer - class(atlas_Field), intent(in) :: this - real(c_float), pointer, intent(inout) :: field(:,:,:) - integer(c_int), intent(in) :: shape(:) - type(c_ptr) :: field_cptr - type(c_ptr) :: shape_cptr - type(c_ptr) :: strides_cptr - integer(c_int) :: rank - call atlas__Field__device_data_float_specf(this%c_ptr(), field_cptr, rank, shape_cptr, strides_cptr) - call c_f_pointer( field_cptr, field, shape ) -end subroutine - -!------------------------------------------------------------------------------- -subroutine access_host_data_real64_r3_shape(this, field, shape) - use atlas_field_c_binding - use, intrinsic :: iso_c_binding, only : c_ptr, c_int, c_long, c_float, c_double, c_f_pointer - class(atlas_Field), intent(in) :: this - real(c_double), pointer, intent(inout) :: field(:,:,:) - integer(c_int), intent(in) :: shape(:) - type(c_ptr) :: field_cptr - type(c_ptr) :: shape_cptr - type(c_ptr) :: strides_cptr - integer(c_int) :: rank - call atlas__Field__host_data_double_specf(this%c_ptr(), field_cptr, rank, shape_cptr, strides_cptr) - call c_f_pointer( field_cptr, field, shape ) -end subroutine - -subroutine access_device_data_real64_r3_shape(this, field, shape) - use atlas_field_c_binding - use, intrinsic :: iso_c_binding, only : c_ptr, c_int, c_long, c_float, c_double, c_f_pointer - class(atlas_Field), intent(in) :: this - real(c_double), pointer, intent(inout) :: field(:,:,:) - integer(c_int), intent(in) :: shape(:) - type(c_ptr) :: field_cptr - type(c_ptr) :: shape_cptr - type(c_ptr) :: strides_cptr - integer(c_int) :: rank - call atlas__Field__device_data_double_specf(this%c_ptr(), field_cptr, rank, shape_cptr, strides_cptr) - call c_f_pointer( field_cptr, field, shape ) -end subroutine - -!------------------------------------------------------------------------------- -subroutine access_host_data_logical32_r3_shape(this, field, shape) - use atlas_field_c_binding - use, intrinsic :: iso_c_binding, only : c_ptr, c_int, c_long, c_float, c_double, c_f_pointer - class(atlas_Field), intent(in) :: this - logical, pointer, intent(inout) :: field(:,:,:) - integer(c_int), intent(in) :: shape(:) - type(c_ptr) :: field_cptr - type(c_ptr) :: shape_cptr - type(c_ptr) :: strides_cptr - integer(c_int) :: rank - call atlas__Field__host_data_int_specf(this%c_ptr(), field_cptr, rank, shape_cptr, strides_cptr) - call c_f_pointer( field_cptr, field, shape ) -end subroutine - -subroutine access_device_data_logical32_r3_shape(this, field, shape) - use atlas_field_c_binding - use, intrinsic :: iso_c_binding, only : c_ptr, c_int, c_long, c_float, c_double, c_f_pointer - class(atlas_Field), intent(in) :: this - logical, pointer, intent(inout) :: field(:,:,:) - integer(c_int), intent(in) :: shape(:) - type(c_ptr) :: field_cptr - type(c_ptr) :: shape_cptr - type(c_ptr) :: strides_cptr - integer(c_int) :: rank - call atlas__Field__device_data_int_specf(this%c_ptr(), field_cptr, rank, shape_cptr, strides_cptr) - call c_f_pointer( field_cptr, field, shape ) -end subroutine - -!------------------------------------------------------------------------------- -subroutine access_host_data_int32_r4_shape(this, field, shape) - use atlas_field_c_binding - use, intrinsic :: iso_c_binding, only : c_ptr, c_int, c_long, c_float, c_double, c_f_pointer - class(atlas_Field), intent(in) :: this - integer(c_int), pointer, intent(inout) :: field(:,:,:,:) - integer(c_int), intent(in) :: shape(:) - type(c_ptr) :: field_cptr - type(c_ptr) :: shape_cptr - type(c_ptr) :: strides_cptr - integer(c_int) :: rank - call atlas__Field__host_data_int_specf(this%c_ptr(), field_cptr, rank, shape_cptr, strides_cptr) - call c_f_pointer( field_cptr, field, shape ) -end subroutine - -subroutine access_device_data_int32_r4_shape(this, field, shape) - use atlas_field_c_binding - use, intrinsic :: iso_c_binding, only : c_ptr, c_int, c_long, c_float, c_double, c_f_pointer - class(atlas_Field), intent(in) :: this - integer(c_int), pointer, intent(inout) :: field(:,:,:,:) - integer(c_int), intent(in) :: shape(:) - type(c_ptr) :: field_cptr - type(c_ptr) :: shape_cptr - type(c_ptr) :: strides_cptr - integer(c_int) :: rank - call atlas__Field__device_data_int_specf(this%c_ptr(), field_cptr, rank, shape_cptr, strides_cptr) - call c_f_pointer( field_cptr, field, shape ) -end subroutine - -!------------------------------------------------------------------------------- -subroutine access_host_data_int64_r4_shape(this, field, shape) - use atlas_field_c_binding - use, intrinsic :: iso_c_binding, only : c_ptr, c_int, c_long, c_float, c_double, c_f_pointer - class(atlas_Field), intent(in) :: this - integer(c_long), pointer, intent(inout) :: field(:,:,:,:) - integer(c_int), intent(in) :: shape(:) - type(c_ptr) :: field_cptr - type(c_ptr) :: shape_cptr - type(c_ptr) :: strides_cptr - integer(c_int) :: rank - call atlas__Field__host_data_long_specf(this%c_ptr(), field_cptr, rank, shape_cptr, strides_cptr) - call c_f_pointer( field_cptr, field, shape ) -end subroutine - -subroutine access_device_data_int64_r4_shape(this, field, shape) - use atlas_field_c_binding - use, intrinsic :: iso_c_binding, only : c_ptr, c_int, c_long, c_float, c_double, c_f_pointer - class(atlas_Field), intent(in) :: this - integer(c_long), pointer, intent(inout) :: field(:,:,:,:) - integer(c_int), intent(in) :: shape(:) - type(c_ptr) :: field_cptr - type(c_ptr) :: shape_cptr - type(c_ptr) :: strides_cptr - integer(c_int) :: rank - call atlas__Field__device_data_long_specf(this%c_ptr(), field_cptr, rank, shape_cptr, strides_cptr) - call c_f_pointer( field_cptr, field, shape ) -end subroutine - -!------------------------------------------------------------------------------- -subroutine access_host_data_real32_r4_shape(this, field, shape) - use atlas_field_c_binding - use, intrinsic :: iso_c_binding, only : c_ptr, c_int, c_long, c_float, c_double, c_f_pointer - class(atlas_Field), intent(in) :: this - real(c_float), pointer, intent(inout) :: field(:,:,:,:) - integer(c_int), intent(in) :: shape(:) - type(c_ptr) :: field_cptr - type(c_ptr) :: shape_cptr - type(c_ptr) :: strides_cptr - integer(c_int) :: rank - call atlas__Field__host_data_float_specf(this%c_ptr(), field_cptr, rank, shape_cptr, strides_cptr) - call c_f_pointer( field_cptr, field, shape ) -end subroutine - -subroutine access_device_data_real32_r4_shape(this, field, shape) - use atlas_field_c_binding - use, intrinsic :: iso_c_binding, only : c_ptr, c_int, c_long, c_float, c_double, c_f_pointer - class(atlas_Field), intent(in) :: this - real(c_float), pointer, intent(inout) :: field(:,:,:,:) - integer(c_int), intent(in) :: shape(:) - type(c_ptr) :: field_cptr - type(c_ptr) :: shape_cptr - type(c_ptr) :: strides_cptr - integer(c_int) :: rank - call atlas__Field__device_data_float_specf(this%c_ptr(), field_cptr, rank, shape_cptr, strides_cptr) - call c_f_pointer( field_cptr, field, shape ) -end subroutine - -!------------------------------------------------------------------------------- -subroutine access_host_data_real64_r4_shape(this, field, shape) - use atlas_field_c_binding - use, intrinsic :: iso_c_binding, only : c_ptr, c_int, c_long, c_float, c_double, c_f_pointer - class(atlas_Field), intent(in) :: this - real(c_double), pointer, intent(inout) :: field(:,:,:,:) - integer(c_int), intent(in) :: shape(:) - type(c_ptr) :: field_cptr - type(c_ptr) :: shape_cptr - type(c_ptr) :: strides_cptr - integer(c_int) :: rank - call atlas__Field__host_data_double_specf(this%c_ptr(), field_cptr, rank, shape_cptr, strides_cptr) - call c_f_pointer( field_cptr, field, shape ) -end subroutine - -subroutine access_device_data_real64_r4_shape(this, field, shape) - use atlas_field_c_binding - use, intrinsic :: iso_c_binding, only : c_ptr, c_int, c_long, c_float, c_double, c_f_pointer - class(atlas_Field), intent(in) :: this - real(c_double), pointer, intent(inout) :: field(:,:,:,:) - integer(c_int), intent(in) :: shape(:) - type(c_ptr) :: field_cptr - type(c_ptr) :: shape_cptr - type(c_ptr) :: strides_cptr - integer(c_int) :: rank - call atlas__Field__device_data_double_specf(this%c_ptr(), field_cptr, rank, shape_cptr, strides_cptr) - call c_f_pointer( field_cptr, field, shape ) -end subroutine - -!------------------------------------------------------------------------------- -subroutine access_host_data_logical32_r4_shape(this, field, shape) - use atlas_field_c_binding - use, intrinsic :: iso_c_binding, only : c_ptr, c_int, c_long, c_float, c_double, c_f_pointer - class(atlas_Field), intent(in) :: this - logical, pointer, intent(inout) :: field(:,:,:,:) - integer(c_int), intent(in) :: shape(:) - type(c_ptr) :: field_cptr - type(c_ptr) :: shape_cptr - type(c_ptr) :: strides_cptr - integer(c_int) :: rank - call atlas__Field__host_data_int_specf(this%c_ptr(), field_cptr, rank, shape_cptr, strides_cptr) - call c_f_pointer( field_cptr, field, shape ) -end subroutine - -subroutine access_device_data_logical32_r4_shape(this, field, shape) - use atlas_field_c_binding - use, intrinsic :: iso_c_binding, only : c_ptr, c_int, c_long, c_float, c_double, c_f_pointer - class(atlas_Field), intent(in) :: this - logical, pointer, intent(inout) :: field(:,:,:,:) - integer(c_int), intent(in) :: shape(:) - type(c_ptr) :: field_cptr - type(c_ptr) :: shape_cptr - type(c_ptr) :: strides_cptr - integer(c_int) :: rank - call atlas__Field__device_data_int_specf(this%c_ptr(), field_cptr, rank, shape_cptr, strides_cptr) - call c_f_pointer( field_cptr, field, shape ) -end subroutine - -!------------------------------------------------------------------------------- -subroutine dummy(this) - use atlas_field_c_binding - class(atlas_Field), intent(in) :: this - FCKIT_SUPPRESS_UNUSED(this) -end subroutine - -!------------------------------------------------------------------------------- - -integer function atlas_real(kind) - use, intrinsic :: iso_c_binding, only : c_double, c_float - integer :: kind - if (kind == c_double) then - atlas_real = ATLAS_KIND_REAL64 - else if (kind == c_float) then - atlas_real = ATLAS_KIND_REAL32 - else - call atlas_abort("Unsupported real kind",atlas_code_location("atlas_Field_module.F90",282)) - end if -end function - -!------------------------------------------------------------------------------- - -integer function atlas_integer(kind) - use, intrinsic :: iso_c_binding, only : c_int, c_long - integer, optional :: kind - atlas_integer = ATLAS_KIND_INT32 - if ( present(kind) ) then - if (kind == c_int) then - atlas_integer = ATLAS_KIND_INT32 - else if (kind == c_long) then - atlas_integer = ATLAS_KIND_INT64 - else - call atlas_abort("Unsupported real kind",atlas_code_location("atlas_Field_module.F90",298)) - end if - end if -end function - -!------------------------------------------------------------------------------- - -integer function atlas_logical(kind) - integer, optional :: kind - atlas_logical = ATLAS_KIND_INT32 - FCKIT_SUPPRESS_UNUSED(kind) -end function - -!------------------------------------------------------------------------------- - -function atlas_data_type(kind) - character(len=6) :: atlas_data_type - integer, intent(in) :: kind - if( kind == ATLAS_KIND_INT32 ) then - atlas_data_type = "int32" - else if( kind == ATLAS_KIND_INT64 ) then - atlas_data_type = "int64" - else if( kind == ATLAS_KIND_REAL32 ) then - atlas_data_type = "real32" - else if( kind == ATLAS_KIND_REAL64 ) then - atlas_data_type = "real64" - else - call atlas_abort("cannot convert kind to data_type",atlas_code_location("atlas_Field_module.F90",325)) - endif -end function - -!------------------------------------------------------------------------------- - -function atlas_Field__cptr(cptr) result(field) - use, intrinsic :: iso_c_binding, only : c_ptr - type(atlas_Field) :: field - type(c_ptr), intent(in) :: cptr - call field%reset_c_ptr( cptr ) - call field%return() -end function - -!------------------------------------------------------------------------------- - -function atlas_Field__create(params) result(field) - use atlas_field_c_binding - type(atlas_Field) :: field - class(atlas_Config), intent(in) :: params - field = atlas_Field__cptr( atlas__Field__create(params%c_ptr()) ) - call field%return() -end function - -!------------------------------------------------------------------------------- - -function atlas_Field__create_name_kind_shape_int32(name,kind,shape) result(field) - use atlas_field_c_binding - use, intrinsic :: iso_c_binding, only : c_int - type(atlas_Field) :: field - character(len=*), intent(in) :: name - integer, intent(in) :: kind - integer(c_int), intent(in) :: shape(:) - - type(atlas_Config) :: params - - params = atlas_Config() - call params%set("creator","ArraySpec") - call params%set("shape",shape) - call params%set("fortran",.True.) - call params%set("datatype",atlas_data_type(kind)) - call params%set("name",name) - - field = atlas_Field__cptr( atlas__Field__create(params%c_ptr()) ) - call params%final() - call field%return() -end function - -!------------------------------------------------------------------------------- - -function atlas_Field__create_name_kind_shape_int64(name,kind,shape) result(field) - use atlas_field_c_binding - use, intrinsic :: iso_c_binding, only : c_long - type(atlas_Field) :: field - character(len=*), intent(in) :: name - integer, intent(in) :: kind - integer(c_long), intent(in) :: shape(:) - - type(atlas_Config) :: params - - params = atlas_Config() - call params%set("creator","ArraySpec") - call params%set("shape",shape) - call params%set("fortran",.True.) - call params%set("datatype",atlas_data_type(kind)) - call params%set("name",name) - - field = atlas_Field__cptr( atlas__Field__create(params%c_ptr()) ) - call params%final() - call field%return() -end function - -!------------------------------------------------------------------------------- - -function atlas_Field__create_kind_shape_int32(kind,shape) result(field) - use atlas_field_c_binding - use, intrinsic :: iso_c_binding, only : c_int - type(atlas_Field) :: field - integer(c_int), intent(in) :: kind - integer, intent(in) :: shape(:) - - type(atlas_Config) :: params - - params = atlas_Config() - call params%set("creator","ArraySpec") - call params%set("shape",shape) - call params%set("fortran",.True.) - call params%set("datatype",atlas_data_type(kind)) - - field = atlas_Field__cptr( atlas__Field__create(params%c_ptr()) ) - call params%final() - call field%return() -end function - -function atlas_Field__create_kind_shape_int64(kind,shape) result(field) - use atlas_field_c_binding - use, intrinsic :: iso_c_binding, only : c_int, c_long - type(atlas_Field) :: field - integer(c_int), intent(in) :: kind - integer(c_long), intent(in) :: shape(:) - - type(atlas_Config) :: params - - params = atlas_Config() - call params%set("creator","ArraySpec") - call params%set("shape",shape) - call params%set("fortran",.True.) - call params%set("datatype",atlas_data_type(kind)) - - field = atlas_Field__cptr( atlas__Field__create(params%c_ptr()) ) - call params%final() - call field%return() -end function - - -!------------------------------------------------------------------------------- - -function atlas_Field__wrap_name_int32_r1(name,data) result(field) - use atlas_field_c_binding - use fckit_array_module, only : array_strides, array_view1d - use, intrinsic :: iso_c_binding, only : c_int, c_long, c_float, c_double - type(atlas_Field) :: field - character(len=*), intent(in) :: name - integer(c_int), intent(in) :: data(:) - integer(c_int) :: shapef(1) - integer(c_int) :: stridesf(1) - integer(c_int), pointer :: data1d(:) - shapef = shape(data) - stridesf = array_strides(data) - data1d => array_view1d(data) - field = atlas_Field__cptr( atlas__Field__wrap_int_specf(name,data1d,size(shapef),shapef, stridesf) ) - call field%return() -end function -function atlas_Field__wrap_int32_r1(data) result(field) - use atlas_field_c_binding - use, intrinsic :: iso_c_binding, only : c_int, c_long, c_float, c_double - use fckit_c_interop_module, only : c_str - use fckit_array_module, only : array_strides, array_view1d - type(atlas_Field) :: field - integer(c_int), intent(in) :: data(:) - integer(c_int) :: shapef(1) - integer(c_int) :: stridesf(1) - integer(c_int), pointer :: data1d(:) - shapef = shape(data) - stridesf = array_strides(data) - data1d => array_view1d(data) - field = atlas_Field__cptr( atlas__Field__wrap_int_specf(c_str(""),data1d,size(shapef),shapef, stridesf) ) - call field%return() -end function -function atlas_Field__wrap_name_int64_r1(name,data) result(field) - use atlas_field_c_binding - use fckit_array_module, only : array_strides, array_view1d - use, intrinsic :: iso_c_binding, only : c_int, c_long, c_float, c_double - type(atlas_Field) :: field - character(len=*), intent(in) :: name - integer(c_long), intent(in) :: data(:) - integer(c_int) :: shapef(1) - integer(c_int) :: stridesf(1) - integer(c_long), pointer :: data1d(:) - shapef = shape(data) - stridesf = array_strides(data) - data1d => array_view1d(data) - field = atlas_Field__cptr( atlas__Field__wrap_long_specf(name,data1d,size(shapef),shapef, stridesf) ) - call field%return() -end function -function atlas_Field__wrap_int64_r1(data) result(field) - use atlas_field_c_binding - use, intrinsic :: iso_c_binding, only : c_int, c_long, c_float, c_double - use fckit_c_interop_module, only : c_str - use fckit_array_module, only : array_strides, array_view1d - type(atlas_Field) :: field - integer(c_long), intent(in) :: data(:) - integer(c_int) :: shapef(1) - integer(c_int) :: stridesf(1) - integer(c_long), pointer :: data1d(:) - shapef = shape(data) - stridesf = array_strides(data) - data1d => array_view1d(data) - field = atlas_Field__cptr( atlas__Field__wrap_long_specf(c_str(""),data1d,size(shapef),shapef, stridesf) ) - call field%return() -end function -function atlas_Field__wrap_name_real32_r1(name,data) result(field) - use atlas_field_c_binding - use fckit_array_module, only : array_strides, array_view1d - use, intrinsic :: iso_c_binding, only : c_int, c_long, c_float, c_double - type(atlas_Field) :: field - character(len=*), intent(in) :: name - real(c_float), intent(in) :: data(:) - integer(c_int) :: shapef(1) - integer(c_int) :: stridesf(1) - real(c_float), pointer :: data1d(:) - shapef = shape(data) - stridesf = array_strides(data) - data1d => array_view1d(data) - field = atlas_Field__cptr( atlas__Field__wrap_float_specf(name,data1d,size(shapef),shapef, stridesf) ) - call field%return() -end function -function atlas_Field__wrap_real32_r1(data) result(field) - use atlas_field_c_binding - use, intrinsic :: iso_c_binding, only : c_int, c_long, c_float, c_double - use fckit_c_interop_module, only : c_str - use fckit_array_module, only : array_strides, array_view1d - type(atlas_Field) :: field - real(c_float), intent(in) :: data(:) - integer(c_int) :: shapef(1) - integer(c_int) :: stridesf(1) - real(c_float), pointer :: data1d(:) - shapef = shape(data) - stridesf = array_strides(data) - data1d => array_view1d(data) - field = atlas_Field__cptr( atlas__Field__wrap_float_specf(c_str(""),data1d,size(shapef),shapef, stridesf) ) - call field%return() -end function -function atlas_Field__wrap_name_real64_r1(name,data) result(field) - use atlas_field_c_binding - use fckit_array_module, only : array_strides, array_view1d - use, intrinsic :: iso_c_binding, only : c_int, c_long, c_float, c_double - type(atlas_Field) :: field - character(len=*), intent(in) :: name - real(c_double), intent(in) :: data(:) - integer(c_int) :: shapef(1) - integer(c_int) :: stridesf(1) - real(c_double), pointer :: data1d(:) - shapef = shape(data) - stridesf = array_strides(data) - data1d => array_view1d(data) - field = atlas_Field__cptr( atlas__Field__wrap_double_specf(name,data1d,size(shapef),shapef, stridesf) ) - call field%return() -end function -function atlas_Field__wrap_real64_r1(data) result(field) - use atlas_field_c_binding - use, intrinsic :: iso_c_binding, only : c_int, c_long, c_float, c_double - use fckit_c_interop_module, only : c_str - use fckit_array_module, only : array_strides, array_view1d - type(atlas_Field) :: field - real(c_double), intent(in) :: data(:) - integer(c_int) :: shapef(1) - integer(c_int) :: stridesf(1) - real(c_double), pointer :: data1d(:) - shapef = shape(data) - stridesf = array_strides(data) - data1d => array_view1d(data) - field = atlas_Field__cptr( atlas__Field__wrap_double_specf(c_str(""),data1d,size(shapef),shapef, stridesf) ) - call field%return() -end function -function atlas_Field__wrap_name_int32_r2(name,data) result(field) - use atlas_field_c_binding - use fckit_array_module, only : array_strides, array_view1d - use, intrinsic :: iso_c_binding, only : c_int, c_long, c_float, c_double - type(atlas_Field) :: field - character(len=*), intent(in) :: name - integer(c_int), intent(in) :: data(:,:) - integer(c_int) :: shapef(2) - integer(c_int) :: stridesf(2) - integer(c_int), pointer :: data1d(:) - shapef = shape(data) - stridesf = array_strides(data) - data1d => array_view1d(data) - field = atlas_Field__cptr( atlas__Field__wrap_int_specf(name,data1d,size(shapef),shapef, stridesf) ) - call field%return() -end function -function atlas_Field__wrap_int32_r2(data) result(field) - use atlas_field_c_binding - use, intrinsic :: iso_c_binding, only : c_int, c_long, c_float, c_double - use fckit_c_interop_module, only : c_str - use fckit_array_module, only : array_strides, array_view1d - type(atlas_Field) :: field - integer(c_int), intent(in) :: data(:,:) - integer(c_int) :: shapef(2) - integer(c_int) :: stridesf(2) - integer(c_int), pointer :: data1d(:) - shapef = shape(data) - stridesf = array_strides(data) - data1d => array_view1d(data) - field = atlas_Field__cptr( atlas__Field__wrap_int_specf(c_str(""),data1d,size(shapef),shapef, stridesf) ) - call field%return() -end function -function atlas_Field__wrap_name_int64_r2(name,data) result(field) - use atlas_field_c_binding - use fckit_array_module, only : array_strides, array_view1d - use, intrinsic :: iso_c_binding, only : c_int, c_long, c_float, c_double - type(atlas_Field) :: field - character(len=*), intent(in) :: name - integer(c_long), intent(in) :: data(:,:) - integer(c_int) :: shapef(2) - integer(c_int) :: stridesf(2) - integer(c_long), pointer :: data1d(:) - shapef = shape(data) - stridesf = array_strides(data) - data1d => array_view1d(data) - field = atlas_Field__cptr( atlas__Field__wrap_long_specf(name,data1d,size(shapef),shapef, stridesf) ) - call field%return() -end function -function atlas_Field__wrap_int64_r2(data) result(field) - use atlas_field_c_binding - use, intrinsic :: iso_c_binding, only : c_int, c_long, c_float, c_double - use fckit_c_interop_module, only : c_str - use fckit_array_module, only : array_strides, array_view1d - type(atlas_Field) :: field - integer(c_long), intent(in) :: data(:,:) - integer(c_int) :: shapef(2) - integer(c_int) :: stridesf(2) - integer(c_long), pointer :: data1d(:) - shapef = shape(data) - stridesf = array_strides(data) - data1d => array_view1d(data) - field = atlas_Field__cptr( atlas__Field__wrap_long_specf(c_str(""),data1d,size(shapef),shapef, stridesf) ) - call field%return() -end function -function atlas_Field__wrap_name_real32_r2(name,data) result(field) - use atlas_field_c_binding - use fckit_array_module, only : array_strides, array_view1d - use, intrinsic :: iso_c_binding, only : c_int, c_long, c_float, c_double - type(atlas_Field) :: field - character(len=*), intent(in) :: name - real(c_float), intent(in) :: data(:,:) - integer(c_int) :: shapef(2) - integer(c_int) :: stridesf(2) - real(c_float), pointer :: data1d(:) - shapef = shape(data) - stridesf = array_strides(data) - data1d => array_view1d(data) - field = atlas_Field__cptr( atlas__Field__wrap_float_specf(name,data1d,size(shapef),shapef, stridesf) ) - call field%return() -end function -function atlas_Field__wrap_real32_r2(data) result(field) - use atlas_field_c_binding - use, intrinsic :: iso_c_binding, only : c_int, c_long, c_float, c_double - use fckit_c_interop_module, only : c_str - use fckit_array_module, only : array_strides, array_view1d - type(atlas_Field) :: field - real(c_float), intent(in) :: data(:,:) - integer(c_int) :: shapef(2) - integer(c_int) :: stridesf(2) - real(c_float), pointer :: data1d(:) - shapef = shape(data) - stridesf = array_strides(data) - data1d => array_view1d(data) - field = atlas_Field__cptr( atlas__Field__wrap_float_specf(c_str(""),data1d,size(shapef),shapef, stridesf) ) - call field%return() -end function -function atlas_Field__wrap_name_real64_r2(name,data) result(field) - use atlas_field_c_binding - use fckit_array_module, only : array_strides, array_view1d - use, intrinsic :: iso_c_binding, only : c_int, c_long, c_float, c_double - type(atlas_Field) :: field - character(len=*), intent(in) :: name - real(c_double), intent(in) :: data(:,:) - integer(c_int) :: shapef(2) - integer(c_int) :: stridesf(2) - real(c_double), pointer :: data1d(:) - shapef = shape(data) - stridesf = array_strides(data) - data1d => array_view1d(data) - field = atlas_Field__cptr( atlas__Field__wrap_double_specf(name,data1d,size(shapef),shapef, stridesf) ) - call field%return() -end function -function atlas_Field__wrap_real64_r2(data) result(field) - use atlas_field_c_binding - use, intrinsic :: iso_c_binding, only : c_int, c_long, c_float, c_double - use fckit_c_interop_module, only : c_str - use fckit_array_module, only : array_strides, array_view1d - type(atlas_Field) :: field - real(c_double), intent(in) :: data(:,:) - integer(c_int) :: shapef(2) - integer(c_int) :: stridesf(2) - real(c_double), pointer :: data1d(:) - shapef = shape(data) - stridesf = array_strides(data) - data1d => array_view1d(data) - field = atlas_Field__cptr( atlas__Field__wrap_double_specf(c_str(""),data1d,size(shapef),shapef, stridesf) ) - call field%return() -end function -function atlas_Field__wrap_name_int32_r3(name,data) result(field) - use atlas_field_c_binding - use fckit_array_module, only : array_strides, array_view1d - use, intrinsic :: iso_c_binding, only : c_int, c_long, c_float, c_double - type(atlas_Field) :: field - character(len=*), intent(in) :: name - integer(c_int), intent(in) :: data(:,:,:) - integer(c_int) :: shapef(3) - integer(c_int) :: stridesf(3) - integer(c_int), pointer :: data1d(:) - shapef = shape(data) - stridesf = array_strides(data) - data1d => array_view1d(data) - field = atlas_Field__cptr( atlas__Field__wrap_int_specf(name,data1d,size(shapef),shapef, stridesf) ) - call field%return() -end function -function atlas_Field__wrap_int32_r3(data) result(field) - use atlas_field_c_binding - use, intrinsic :: iso_c_binding, only : c_int, c_long, c_float, c_double - use fckit_c_interop_module, only : c_str - use fckit_array_module, only : array_strides, array_view1d - type(atlas_Field) :: field - integer(c_int), intent(in) :: data(:,:,:) - integer(c_int) :: shapef(3) - integer(c_int) :: stridesf(3) - integer(c_int), pointer :: data1d(:) - shapef = shape(data) - stridesf = array_strides(data) - data1d => array_view1d(data) - field = atlas_Field__cptr( atlas__Field__wrap_int_specf(c_str(""),data1d,size(shapef),shapef, stridesf) ) - call field%return() -end function -function atlas_Field__wrap_name_int64_r3(name,data) result(field) - use atlas_field_c_binding - use fckit_array_module, only : array_strides, array_view1d - use, intrinsic :: iso_c_binding, only : c_int, c_long, c_float, c_double - type(atlas_Field) :: field - character(len=*), intent(in) :: name - integer(c_long), intent(in) :: data(:,:,:) - integer(c_int) :: shapef(3) - integer(c_int) :: stridesf(3) - integer(c_long), pointer :: data1d(:) - shapef = shape(data) - stridesf = array_strides(data) - data1d => array_view1d(data) - field = atlas_Field__cptr( atlas__Field__wrap_long_specf(name,data1d,size(shapef),shapef, stridesf) ) - call field%return() -end function -function atlas_Field__wrap_int64_r3(data) result(field) - use atlas_field_c_binding - use, intrinsic :: iso_c_binding, only : c_int, c_long, c_float, c_double - use fckit_c_interop_module, only : c_str - use fckit_array_module, only : array_strides, array_view1d - type(atlas_Field) :: field - integer(c_long), intent(in) :: data(:,:,:) - integer(c_int) :: shapef(3) - integer(c_int) :: stridesf(3) - integer(c_long), pointer :: data1d(:) - shapef = shape(data) - stridesf = array_strides(data) - data1d => array_view1d(data) - field = atlas_Field__cptr( atlas__Field__wrap_long_specf(c_str(""),data1d,size(shapef),shapef, stridesf) ) - call field%return() -end function -function atlas_Field__wrap_name_real32_r3(name,data) result(field) - use atlas_field_c_binding - use fckit_array_module, only : array_strides, array_view1d - use, intrinsic :: iso_c_binding, only : c_int, c_long, c_float, c_double - type(atlas_Field) :: field - character(len=*), intent(in) :: name - real(c_float), intent(in) :: data(:,:,:) - integer(c_int) :: shapef(3) - integer(c_int) :: stridesf(3) - real(c_float), pointer :: data1d(:) - shapef = shape(data) - stridesf = array_strides(data) - data1d => array_view1d(data) - field = atlas_Field__cptr( atlas__Field__wrap_float_specf(name,data1d,size(shapef),shapef, stridesf) ) - call field%return() -end function -function atlas_Field__wrap_real32_r3(data) result(field) - use atlas_field_c_binding - use, intrinsic :: iso_c_binding, only : c_int, c_long, c_float, c_double - use fckit_c_interop_module, only : c_str - use fckit_array_module, only : array_strides, array_view1d - type(atlas_Field) :: field - real(c_float), intent(in) :: data(:,:,:) - integer(c_int) :: shapef(3) - integer(c_int) :: stridesf(3) - real(c_float), pointer :: data1d(:) - shapef = shape(data) - stridesf = array_strides(data) - data1d => array_view1d(data) - field = atlas_Field__cptr( atlas__Field__wrap_float_specf(c_str(""),data1d,size(shapef),shapef, stridesf) ) - call field%return() -end function -function atlas_Field__wrap_name_real64_r3(name,data) result(field) - use atlas_field_c_binding - use fckit_array_module, only : array_strides, array_view1d - use, intrinsic :: iso_c_binding, only : c_int, c_long, c_float, c_double - type(atlas_Field) :: field - character(len=*), intent(in) :: name - real(c_double), intent(in) :: data(:,:,:) - integer(c_int) :: shapef(3) - integer(c_int) :: stridesf(3) - real(c_double), pointer :: data1d(:) - shapef = shape(data) - stridesf = array_strides(data) - data1d => array_view1d(data) - field = atlas_Field__cptr( atlas__Field__wrap_double_specf(name,data1d,size(shapef),shapef, stridesf) ) - call field%return() -end function -function atlas_Field__wrap_real64_r3(data) result(field) - use atlas_field_c_binding - use, intrinsic :: iso_c_binding, only : c_int, c_long, c_float, c_double - use fckit_c_interop_module, only : c_str - use fckit_array_module, only : array_strides, array_view1d - type(atlas_Field) :: field - real(c_double), intent(in) :: data(:,:,:) - integer(c_int) :: shapef(3) - integer(c_int) :: stridesf(3) - real(c_double), pointer :: data1d(:) - shapef = shape(data) - stridesf = array_strides(data) - data1d => array_view1d(data) - field = atlas_Field__cptr( atlas__Field__wrap_double_specf(c_str(""),data1d,size(shapef),shapef, stridesf) ) - call field%return() -end function -function atlas_Field__wrap_name_int32_r4(name,data) result(field) - use atlas_field_c_binding - use fckit_array_module, only : array_strides, array_view1d - use, intrinsic :: iso_c_binding, only : c_int, c_long, c_float, c_double - type(atlas_Field) :: field - character(len=*), intent(in) :: name - integer(c_int), intent(in) :: data(:,:,:,:) - integer(c_int) :: shapef(4) - integer(c_int) :: stridesf(4) - integer(c_int), pointer :: data1d(:) - shapef = shape(data) - stridesf = array_strides(data) - data1d => array_view1d(data) - field = atlas_Field__cptr( atlas__Field__wrap_int_specf(name,data1d,size(shapef),shapef, stridesf) ) - call field%return() -end function -function atlas_Field__wrap_int32_r4(data) result(field) - use atlas_field_c_binding - use, intrinsic :: iso_c_binding, only : c_int, c_long, c_float, c_double - use fckit_c_interop_module, only : c_str - use fckit_array_module, only : array_strides, array_view1d - type(atlas_Field) :: field - integer(c_int), intent(in) :: data(:,:,:,:) - integer(c_int) :: shapef(4) - integer(c_int) :: stridesf(4) - integer(c_int), pointer :: data1d(:) - shapef = shape(data) - stridesf = array_strides(data) - data1d => array_view1d(data) - field = atlas_Field__cptr( atlas__Field__wrap_int_specf(c_str(""),data1d,size(shapef),shapef, stridesf) ) - call field%return() -end function -function atlas_Field__wrap_name_int64_r4(name,data) result(field) - use atlas_field_c_binding - use fckit_array_module, only : array_strides, array_view1d - use, intrinsic :: iso_c_binding, only : c_int, c_long, c_float, c_double - type(atlas_Field) :: field - character(len=*), intent(in) :: name - integer(c_long), intent(in) :: data(:,:,:,:) - integer(c_int) :: shapef(4) - integer(c_int) :: stridesf(4) - integer(c_long), pointer :: data1d(:) - shapef = shape(data) - stridesf = array_strides(data) - data1d => array_view1d(data) - field = atlas_Field__cptr( atlas__Field__wrap_long_specf(name,data1d,size(shapef),shapef, stridesf) ) - call field%return() -end function -function atlas_Field__wrap_int64_r4(data) result(field) - use atlas_field_c_binding - use, intrinsic :: iso_c_binding, only : c_int, c_long, c_float, c_double - use fckit_c_interop_module, only : c_str - use fckit_array_module, only : array_strides, array_view1d - type(atlas_Field) :: field - integer(c_long), intent(in) :: data(:,:,:,:) - integer(c_int) :: shapef(4) - integer(c_int) :: stridesf(4) - integer(c_long), pointer :: data1d(:) - shapef = shape(data) - stridesf = array_strides(data) - data1d => array_view1d(data) - field = atlas_Field__cptr( atlas__Field__wrap_long_specf(c_str(""),data1d,size(shapef),shapef, stridesf) ) - call field%return() -end function -function atlas_Field__wrap_name_real32_r4(name,data) result(field) - use atlas_field_c_binding - use fckit_array_module, only : array_strides, array_view1d - use, intrinsic :: iso_c_binding, only : c_int, c_long, c_float, c_double - type(atlas_Field) :: field - character(len=*), intent(in) :: name - real(c_float), intent(in) :: data(:,:,:,:) - integer(c_int) :: shapef(4) - integer(c_int) :: stridesf(4) - real(c_float), pointer :: data1d(:) - shapef = shape(data) - stridesf = array_strides(data) - data1d => array_view1d(data) - field = atlas_Field__cptr( atlas__Field__wrap_float_specf(name,data1d,size(shapef),shapef, stridesf) ) - call field%return() -end function -function atlas_Field__wrap_real32_r4(data) result(field) - use atlas_field_c_binding - use, intrinsic :: iso_c_binding, only : c_int, c_long, c_float, c_double - use fckit_c_interop_module, only : c_str - use fckit_array_module, only : array_strides, array_view1d - type(atlas_Field) :: field - real(c_float), intent(in) :: data(:,:,:,:) - integer(c_int) :: shapef(4) - integer(c_int) :: stridesf(4) - real(c_float), pointer :: data1d(:) - shapef = shape(data) - stridesf = array_strides(data) - data1d => array_view1d(data) - field = atlas_Field__cptr( atlas__Field__wrap_float_specf(c_str(""),data1d,size(shapef),shapef, stridesf) ) - call field%return() -end function -function atlas_Field__wrap_name_real64_r4(name,data) result(field) - use atlas_field_c_binding - use fckit_array_module, only : array_strides, array_view1d - use, intrinsic :: iso_c_binding, only : c_int, c_long, c_float, c_double - type(atlas_Field) :: field - character(len=*), intent(in) :: name - real(c_double), intent(in) :: data(:,:,:,:) - integer(c_int) :: shapef(4) - integer(c_int) :: stridesf(4) - real(c_double), pointer :: data1d(:) - shapef = shape(data) - stridesf = array_strides(data) - data1d => array_view1d(data) - field = atlas_Field__cptr( atlas__Field__wrap_double_specf(name,data1d,size(shapef),shapef, stridesf) ) - call field%return() -end function -function atlas_Field__wrap_real64_r4(data) result(field) - use atlas_field_c_binding - use, intrinsic :: iso_c_binding, only : c_int, c_long, c_float, c_double - use fckit_c_interop_module, only : c_str - use fckit_array_module, only : array_strides, array_view1d - type(atlas_Field) :: field - real(c_double), intent(in) :: data(:,:,:,:) - integer(c_int) :: shapef(4) - integer(c_int) :: stridesf(4) - real(c_double), pointer :: data1d(:) - shapef = shape(data) - stridesf = array_strides(data) - data1d => array_view1d(data) - field = atlas_Field__cptr( atlas__Field__wrap_double_specf(c_str(""),data1d,size(shapef),shapef, stridesf) ) - call field%return() -end function - -!------------------------------------------------------------------------------- - -function Field__name(this) result(field_name) - use atlas_field_c_binding - use, intrinsic :: iso_c_binding, only : c_ptr - use fckit_c_interop_module, only : c_ptr_to_string, c_str - class(atlas_Field), intent(in) :: this - character(len=:), allocatable :: field_name - type(c_ptr) :: field_name_c_str - field_name_c_str = atlas__Field__name(this%c_ptr()) - field_name = c_ptr_to_string(field_name_c_str) -end function Field__name - -!------------------------------------------------------------------------------- - -function Field__functionspace(this) result(functionspace) - use atlas_field_c_binding - type(fckit_owned_object) :: functionspace - class(atlas_Field), intent(in) :: this - call functionspace%reset_c_ptr( atlas__Field__functionspace(this%c_ptr()) ) - call functionspace%return() -end function Field__functionspace - -!------------------------------------------------------------------------------- - -function Field__datatype(this) result(datatype) - use atlas_field_c_binding - use, intrinsic :: iso_c_binding, only : c_ptr, c_int - use fckit_c_interop_module, only : c_ptr_free, c_ptr_to_string - class(atlas_Field), intent(in) :: this - character(len=:), allocatable :: datatype - type(c_ptr) :: datatype_cptr - integer(c_int) :: datatype_size - integer(c_int) :: datatype_allocated - call atlas__Field__datatype(this%c_ptr(),datatype_cptr,datatype_size,datatype_allocated) - allocate(character(len=datatype_size) :: datatype ) - datatype= c_ptr_to_string(datatype_cptr) - if( datatype_allocated == 1 ) call c_ptr_free(datatype_cptr) -end function Field__datatype - -!------------------------------------------------------------------------------- - -function Field__size(this) result(fieldsize) - use atlas_field_c_binding - class(atlas_Field), intent(in) :: this - integer :: fieldsize - fieldsize = atlas__Field__size(this%c_ptr()) -end function Field__size - -!------------------------------------------------------------------------------- - -function Field__rank(this) result(rank) - use atlas_field_c_binding - class(atlas_Field), intent(in) :: this - integer :: rank - rank = atlas__Field__rank(this%c_ptr()) -end function Field__rank - -!------------------------------------------------------------------------------- - -function Field__bytes(this) result(bytes) - use atlas_field_c_binding - use, intrinsic :: iso_c_binding, only : c_double - class(atlas_Field), intent(in) :: this - real(c_double) :: bytes - bytes = atlas__Field__bytes(this%c_ptr()) -end function Field__bytes - -!------------------------------------------------------------------------------- - -function Field__kind(this) result(kind) - use atlas_field_c_binding - class(atlas_Field), intent(in) :: this - integer :: kind - kind = atlas__Field__kind(this%c_ptr()) -end function Field__kind - -!------------------------------------------------------------------------------- - -function Field__levels(this) result(levels) - use atlas_field_c_binding - class(atlas_Field), intent(in) :: this - integer :: levels - levels = atlas__Field__levels(this%c_ptr()) -end function Field__levels - -!------------------------------------------------------------------------------- - -function Field__metadata(this) result(metadata) - use atlas_field_c_binding - use atlas_metadata_module - class(atlas_Field), intent(in) :: this - type(atlas_Metadata) :: Metadata - call metadata%reset_c_ptr( atlas__Field__metadata(this%c_ptr()) ) -end function Field__metadata - -!------------------------------------------------------------------------------- - -function Field__shape_array(this) result(shape) - use atlas_field_c_binding - use, intrinsic :: iso_c_binding, only : c_ptr, c_int, c_f_pointer - class(atlas_Field), intent(in) :: this - integer, allocatable :: shape(:) - type(c_ptr) :: shape_c_ptr - integer, pointer :: shape_f_ptr(:) - integer(c_int) :: field_rank - call atlas__Field__shapef(this%c_ptr(), shape_c_ptr, field_rank) - call c_f_pointer ( shape_c_ptr , shape_f_ptr , (/field_rank/) ) - allocate( shape(field_rank) ) - shape(:) = shape_f_ptr(:) -end function Field__shape_array - -!------------------------------------------------------------------------------- - -function Field__shape_idx(this,idx) result(shape_val) - use atlas_field_c_binding - use, intrinsic :: iso_c_binding, only : c_ptr, c_int, c_f_pointer - integer :: shape_val - class(atlas_Field), intent(in) :: this - integer, intent(in) :: idx - type(c_ptr) :: shape_c_ptr - integer, pointer :: shape_f_ptr(:) - integer(c_int) :: field_rank - call atlas__Field__shapef(this%c_ptr(), shape_c_ptr, field_rank) - call c_f_pointer ( shape_c_ptr , shape_f_ptr , (/field_rank/) ) - if( idx > field_rank ) call atlas_throw_outofrange("shape",idx,field_rank, & -& atlas_code_location(filename,__LINE__)) - shape_val = shape_f_ptr(idx) -end function Field__shape_idx - -!------------------------------------------------------------------------------- - -subroutine set_levels(this,nb_levels) - use atlas_field_c_binding - class(atlas_Field), intent(inout) :: this - integer, intent(in) :: nb_levels - call atlas__field__set_levels(this%c_ptr(),nb_levels) -end subroutine - -!------------------------------------------------------------------------------- - -subroutine rename(this,name) - use atlas_field_c_binding - use fckit_c_interop_module, only : c_str - class(atlas_Field), intent(inout) :: this - character(len=*), intent(in) :: name - call atlas__field__rename(this%c_ptr(),c_str(name)) -end subroutine - -!------------------------------------------------------------------------------- - -subroutine set_functionspace(this,functionspace) - use atlas_field_c_binding - class(atlas_Field), intent(inout) :: this - class(fckit_owned_object), intent(in) :: functionspace - call atlas__field__set_functionspace(this%c_ptr(),functionspace%c_ptr()) -end subroutine - -!------------------------------------------------------------------------------- - -function host_needs_update(this) - use atlas_field_c_binding - logical :: host_needs_update - class(atlas_Field), intent(in) :: this - if( atlas__Field__host_needs_update(this%c_ptr()) == 1 ) then - host_needs_update = .true. - else - host_needs_update = .false. - endif -end function - -!------------------------------------------------------------------------------- - -function device_needs_update(this) - use atlas_field_c_binding - logical :: device_needs_update - class(atlas_Field), intent(in) :: this - if( atlas__Field__device_needs_update(this%c_ptr()) == 1 ) then - device_needs_update = .true. - else - device_needs_update = .false. - endif -end function - -!------------------------------------------------------------------------------- - -subroutine clone_to_device(this) - use atlas_field_c_binding - class(atlas_Field), intent(inout) :: this - call atlas__Field__clone_to_device(this%c_ptr()) -end subroutine - -!------------------------------------------------------------------------------- - -subroutine clone_from_device(this) - use atlas_field_c_binding - class(atlas_Field), intent(inout) :: this - call atlas__Field__clone_from_device(this%c_ptr()) -end subroutine - -!------------------------------------------------------------------------------- - -subroutine sync_host_device(this) - use atlas_field_c_binding - class(atlas_Field), intent(inout) :: this - call atlas__Field__sync_host_device(this%c_ptr()) -end subroutine - -!------------------------------------------------------------------------------- - -ATLAS_FINAL subroutine atlas_Field__final_auto(this) - type(atlas_Field), intent(inout) :: this -#if FCKIT_FINAL_DEBUGGING - write(0,*) "atlas_Field__final_auto" -#endif -#if FCKIT_FINAL_NOT_PROPAGATING - call this%final() -#endif - FCKIT_SUPPRESS_UNUSED( this ) -end subroutine - -!------------------------------------------------------------------------------- - -end module atlas_field_module - diff --git a/src/atlas_f/defines.h.in b/src/atlas_f/defines.h.in deleted file mode 100644 index 859c804e5..000000000 --- a/src/atlas_f/defines.h.in +++ /dev/null @@ -1,56 +0,0 @@ -#ifndef atlas_library_defines_h -#define atlas_library_defines_h - -#if 0 -// Do not use cmakedefine as this file needs to be included by fortran as well -#endif - -#if @CGAL_FOUND@ -#define CGAL_FOUND -#endif - -#if @ATLAS_HAVE_OMP@ -#define ATLAS_HAVE_OMP -#endif - -#if @ATLAS_HAVE_TESSELATION@ -#define ATLAS_HAVE_TESSELATION -#endif - -#if @ATLAS_HAVE_FORTRAN@ -#define ATLAS_HAVE_FORTRAN -#endif - -#if @ATLAS_HAVE_TRANS@ -#define ATLAS_HAVE_TRANS -#endif - -#if @ATLAS_HAVE_EIGEN@ -#define ATLAS_HAVE_EIGEN -#endif - -#if @ATLAS_HAVE_GRIDTOOLS_STORAGE@ -#define ATLAS_HAVE_GRIDTOOLS_STORAGE -#define BOOST_RESULT_OF_USE_TR1 -#define ATLAS_GRIDTOOLS_STORAGE_BACKEND_HOST @ATLAS_GRIDTOOLS_STORAGE_BACKEND_HOST@ -#define ATLAS_GRIDTOOLS_STORAGE_BACKEND_CUDA @ATLAS_GRIDTOOLS_STORAGE_BACKEND_CUDA@ -#endif - -#ifdef __CUDACC__ -#define ATLAS_HOST_DEVICE __host__ __device__ -#define ATLAS_DEVICE __device__ -#define ATLAS_HOST __host__ -#else -#define ATLAS_HOST_DEVICE -#define ATLAS_DEVICE -#define ATLAS_HOST -#endif - -#define ATLAS_BITS_GLOBAL @ATLAS_BITS_GLOBAL@ - -#if @ATLAS_HAVE_BOUNDSCHECKING@ -#define ATLAS_ARRAYVIEW_BOUNDS_CHECKING -#define ATLAS_INDEXVIEW_BOUNDS_CHECKING -#endif - -#endif \ No newline at end of file diff --git a/src/atlas_f/field/atlas_FieldSet_module.F90 b/src/atlas_f/field/atlas_FieldSet_module.F90 index 5b24f2e48..9d9d86ef3 100644 --- a/src/atlas_f/field/atlas_FieldSet_module.F90 +++ b/src/atlas_f/field/atlas_FieldSet_module.F90 @@ -1,8 +1,17 @@ +! (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_FieldSet_module use fckit_owned_object_module, only: fckit_owned_object +use atlas_kinds_module, only : ATLAS_KIND_IDX implicit none @@ -36,9 +45,12 @@ module atlas_FieldSet_module procedure, public :: has_field procedure, private :: field_by_name procedure, private :: field_by_idx_int - procedure, private :: field_by_idx_size_t + procedure, private :: field_by_idx_long procedure, public :: add - generic :: field => field_by_name, field_by_idx_int, field_by_idx_size_t + generic :: field => field_by_name, field_by_idx_int, field_by_idx_long + + procedure, public :: set_dirty + procedure, public :: halo_exchange #if FCKIT_FINAL_NOT_INHERITING final :: atlas_FieldSet__final_auto @@ -86,7 +98,7 @@ subroutine add(this,field) use atlas_Field_module, only: atlas_Field class(atlas_FieldSet), intent(in) :: this type(atlas_Field), intent(in) :: field - call atlas__FieldSet__add_field(this%c_ptr(), field%c_ptr()) + call atlas__FieldSet__add_field(this%CPTR_PGIBUG_A, field%CPTR_PGIBUG_A) end subroutine function has_field(this,name) result(flag) @@ -97,7 +109,7 @@ function has_field(this,name) result(flag) character(len=*), intent(in) :: name logical :: flag integer(c_int) :: rc - rc = atlas__FieldSet__has_field(this%c_ptr(), c_str(name)) + rc = atlas__FieldSet__has_field(this%CPTR_PGIBUG_A, c_str(name)) if( rc == 0 ) then flag = .False. else @@ -106,11 +118,10 @@ function has_field(this,name) result(flag) end function function FieldSet__size(this) result(nb_fields) - use, intrinsic :: iso_c_binding, only: c_size_t use atlas_fieldset_c_binding class(atlas_FieldSet), intent(in) :: this - integer(c_size_t) :: nb_fields - nb_fields = atlas__FieldSet__size(this%c_ptr()) + integer(ATLAS_KIND_IDX) :: nb_fields + nb_fields = atlas__FieldSet__size(this%CPTR_PGIBUG_A) end function function field_by_name(this,name) result(field) @@ -120,34 +131,69 @@ function field_by_name(this,name) result(field) class(atlas_FieldSet), intent(in) :: this character(len=*), intent(in) :: name type(atlas_Field) :: field - field = atlas_Field( atlas__FieldSet__field_by_name(this%c_ptr(), c_str(name) ) ) + field = atlas_Field( atlas__FieldSet__field_by_name(this%CPTR_PGIBUG_A, c_str(name) ) ) call field%return() end function -function field_by_idx_size_t(this,idx) result(field) - use, intrinsic :: iso_c_binding, only: c_size_t +function field_by_idx_long(this,idx) result(field) + use, intrinsic :: iso_c_binding, only: c_long use atlas_fieldset_c_binding use atlas_Field_module, only: atlas_Field class(atlas_FieldSet), intent(in) :: this - integer(c_size_t), intent(in) :: idx + integer(c_long), intent(in) :: idx type(atlas_Field) :: field - field = atlas_Field( atlas__FieldSet__field_by_idx(this%c_ptr(), idx-1_c_size_t) ) ! C index + field = atlas_Field( atlas__FieldSet__field_by_idx(this%CPTR_PGIBUG_A, int(idx-1_c_long,ATLAS_KIND_IDX) ) ) ! C index call field%return() end function function field_by_idx_int(this,idx) result(field) - use, intrinsic :: iso_c_binding, only: c_size_t, c_int + use, intrinsic :: iso_c_binding, only: c_int use atlas_fieldset_c_binding use atlas_Field_module, only: atlas_Field class(atlas_FieldSet), intent(in) :: this integer(c_int), intent(in) :: idx type(atlas_Field) :: field - field = atlas_Field( atlas__FieldSet__field_by_idx(this%c_ptr(), int(idx-1,c_size_t) ) ) ! C index + field = atlas_Field( atlas__FieldSet__field_by_idx(this%CPTR_PGIBUG_A, int(idx-1_c_int,ATLAS_KIND_IDX) ) ) ! C index call field%return() end function !------------------------------------------------------------------------------- +subroutine halo_exchange(this,on_device) + use, intrinsic :: iso_c_binding, only : c_int + use atlas_fieldset_c_binding + class(atlas_FieldSet), intent(inout) :: this + logical, optional :: on_device + integer(c_int) :: on_device_int + on_device_int = 0 + if( present(on_device) ) then + if( on_device ) on_device_int = 1 + endif + call atlas__FieldSet__halo_exchange(this%CPTR_PGIBUG_A, on_device_int) +end subroutine + +!------------------------------------------------------------------------------- + +subroutine set_dirty(this,value) + use, intrinsic :: iso_c_binding, only : c_int + use atlas_fieldset_c_binding + class(atlas_FieldSet), intent(inout) :: this + logical, optional, intent(in) :: value + integer(c_int) :: value_int + if( present(value) ) then + if( value ) then + value_int = 1 + else + value_int = 0 + endif + else + value_int = 1 + endif + call atlas__FieldSet__set_dirty(this%CPTR_PGIBUG_A, value_int) +end subroutine + +!------------------------------------------------------------------------------- + ATLAS_FINAL subroutine atlas_FieldSet__final_auto(this) type(atlas_FieldSet), intent(inout) :: this #if FCKIT_FINAL_DEBUGGING diff --git a/src/atlas_f/field/atlas_Field_module.F90 b/src/atlas_f/field/atlas_Field_module.fypp similarity index 74% rename from src/atlas_f/field/atlas_Field_module.F90 rename to src/atlas_f/field/atlas_Field_module.fypp index 7b1a9ae5d..f31be9852 100644 --- a/src/atlas_f/field/atlas_Field_module.F90 +++ b/src/atlas_f/field/atlas_Field_module.fypp @@ -1,21 +1,21 @@ -#include "atlas/atlas_f.h" +! (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. -#:setvar ranks [1,2,3,4] -#:setvar dim ['',':',':,:',':,:,:',':,:,:,:',':,:,:,:,:'] -#:setvar ftypes ['integer(c_int)','integer(c_long)','real(c_float)','real(c_double)', 'logical'] -#:setvar ctypes ['int','long','float','double', 'int'] -#:setvar dtypes ['int32', 'int64', 'real32', 'real64', 'logical32'] -#:setvar types list(zip(dtypes,ftypes,ctypes)) +#include "atlas/atlas_f.h" -#:def atlas_abort(string) -atlas_abort("${string}$",atlas_code_location("atlas_Field_module.F90",${_LINE_}$)) -#:enddef +#:include "atlas/atlas_f.fypp" +#:include "internals/atlas_generics.fypp" module atlas_field_module use fckit_owned_object_module, only : fckit_owned_object -use atlas_Error_module, only: atlas_code_location, atlas_abort, atlas_throw_outofrange use atlas_Config_module, only: atlas_Config + implicit none public :: atlas_Field @@ -24,11 +24,8 @@ module atlas_field_module public :: atlas_logical public :: atlas_data_type -character(len=*), parameter :: filename = 'atlas_Field_module.F90' - private - !------------------------------------------------------------------------------ TYPE, extends(fckit_owned_object) :: atlas_Field @@ -61,42 +58,26 @@ module atlas_field_module procedure :: kind => Field__kind generic :: shape => shape_array, shape_idx + procedure :: halo_exchange + procedure :: dirty + procedure :: set_dirty + procedure :: rename procedure :: set_levels procedure :: set_functionspace #:for rank in ranks #:for dtype in dtypes - procedure, private :: access_host_data_${dtype}$_r${rank}$ - procedure, private :: access_host_data_${dtype}$_r${rank}$_shape - procedure, private :: access_device_data_${dtype}$_r${rank}$ - procedure, private :: access_device_data_${dtype}$_r${rank}$_shape + procedure, private :: access_data_${dtype}$_r${rank}$ + procedure, private :: access_data_${dtype}$_r${rank}$_shape #:endfor #:endfor generic, public :: data => & #:for rank in ranks #:for dtype in dtypes - & access_host_data_${dtype}$_r${rank}$, & - & access_host_data_${dtype}$_r${rank}$_shape, & -#:endfor -#:endfor - & dummy - - generic, public :: host_data => & -#:for rank in ranks -#:for dtype in dtypes - & access_host_data_${dtype}$_r${rank}$, & - & access_host_data_${dtype}$_r${rank}$_shape, & -#:endfor -#:endfor - & dummy - - generic, public :: device_data => & -#:for rank in ranks -#:for dtype in dtypes - & access_device_data_${dtype}$_r${rank}$, & - & access_device_data_${dtype}$_r${rank}$_shape, & + & access_data_${dtype}$_r${rank}$, & + & access_data_${dtype}$_r${rank}$_shape, & #:endfor #:endfor & dummy @@ -113,15 +94,15 @@ module atlas_field_module final :: atlas_Field__final_auto #endif -END TYPE atlas_Field +END TYPE interface atlas_Field module procedure atlas_Field__cptr module procedure atlas_Field__create - module procedure atlas_Field__create_name_kind_shape_int32 - module procedure atlas_Field__create_name_kind_shape_int64 - module procedure atlas_Field__create_kind_shape_int32 - module procedure atlas_Field__create_kind_shape_int64 +#:for dtype in integer_dtypes + module procedure atlas_Field__create_name_kind_shape_${dtype}$ + module procedure atlas_Field__create_kind_shape_${dtype}$ +#:endfor #:for rank in ranks #:for dtype in dtypes[:-1] #! skip logical types @@ -151,7 +132,6 @@ module atlas_field_module private :: fckit_owned_object -private :: atlas_code_location, atlas_abort, atlas_throw_outofrange private :: atlas_Config !======================================================== @@ -163,7 +143,7 @@ module atlas_field_module !------------------------------------------------------------------------------- subroutine array_c_to_f_${dtype}$_r${rank}$(array_cptr,rank,shape_cptr,strides_cptr,array_fptr) use, intrinsic :: iso_c_binding, only : c_ptr, c_int, c_double, c_long, c_float, c_f_pointer - + @:ENABLE_ATLAS_MACROS() type(c_ptr), intent(in) :: array_cptr integer(c_int), intent(in) :: rank type(c_ptr), intent(in) :: shape_cptr @@ -175,7 +155,9 @@ subroutine array_c_to_f_${dtype}$_r${rank}$(array_cptr,rank,shape_cptr,strides_c integer :: eshape(${rank}$) integer :: j - if( rank /= ${rank}$ ) call ${atlas_abort("Rank mismatch")}$ + if( rank /= ${rank}$ ) then + @:ATLAS_ABORT("Rank mismatch") + endif call c_f_pointer ( shape_cptr, shape , [rank] ) call c_f_pointer ( strides_cptr, strides , [rank] ) @@ -200,20 +182,7 @@ subroutine array_c_to_f_${dtype}$_r${rank}$(array_cptr,rank,shape_cptr,strides_c #:endfor #:for rank in ranks #:for dtype,ftype,ctype in types -subroutine access_host_data_${dtype}$_r${rank}$(this, field) - use atlas_field_c_binding - use, intrinsic :: iso_c_binding, only : c_ptr, c_int, c_long, c_float, c_double - class(atlas_Field), intent(in) :: this - ${ftype}$, pointer, intent(inout) :: field(${dim[rank]}$) - type(c_ptr) :: field_cptr - type(c_ptr) :: shape_cptr - type(c_ptr) :: strides_cptr - integer(c_int) :: rank - call atlas__Field__host_data_${ctype}$_specf(this%c_ptr(), field_cptr, rank, shape_cptr, strides_cptr) - call array_c_to_f(field_cptr,rank,shape_cptr,strides_cptr, field) -end subroutine - -subroutine access_device_data_${dtype}$_r${rank}$(this, field) +subroutine access_data_${dtype}$_r${rank}$(this, field) use atlas_field_c_binding use, intrinsic :: iso_c_binding, only : c_ptr, c_int, c_long, c_float, c_double class(atlas_Field), intent(in) :: this @@ -222,7 +191,7 @@ subroutine access_device_data_${dtype}$_r${rank}$(this, field) type(c_ptr) :: shape_cptr type(c_ptr) :: strides_cptr integer(c_int) :: rank - call atlas__Field__device_data_${ctype}$_specf(this%c_ptr(), field_cptr, rank, shape_cptr, strides_cptr) + call atlas__Field__data_${ctype}$_specf(this%CPTR_PGIBUG_A, field_cptr, rank, shape_cptr, strides_cptr) call array_c_to_f(field_cptr,rank,shape_cptr,strides_cptr, field) end subroutine @@ -232,21 +201,7 @@ subroutine access_device_data_${dtype}$_r${rank}$(this, field) #:endfor #:for rank in ranks #:for dtype,ftype,ctype in types -subroutine access_host_data_${dtype}$_r${rank}$_shape(this, field, shape) - use atlas_field_c_binding - use, intrinsic :: iso_c_binding, only : c_ptr, c_int, c_long, c_float, c_double, c_f_pointer - class(atlas_Field), intent(in) :: this - ${ftype}$, pointer, intent(inout) :: field(${dim[rank]}$) - integer(c_int), intent(in) :: shape(:) - type(c_ptr) :: field_cptr - type(c_ptr) :: shape_cptr - type(c_ptr) :: strides_cptr - integer(c_int) :: rank - call atlas__Field__host_data_${ctype}$_specf(this%c_ptr(), field_cptr, rank, shape_cptr, strides_cptr) - call c_f_pointer( field_cptr, field, shape ) -end subroutine - -subroutine access_device_data_${dtype}$_r${rank}$_shape(this, field, shape) +subroutine access_data_${dtype}$_r${rank}$_shape(this, field, shape) use atlas_field_c_binding use, intrinsic :: iso_c_binding, only : c_ptr, c_int, c_long, c_float, c_double, c_f_pointer class(atlas_Field), intent(in) :: this @@ -256,7 +211,7 @@ subroutine access_device_data_${dtype}$_r${rank}$_shape(this, field, shape) type(c_ptr) :: shape_cptr type(c_ptr) :: strides_cptr integer(c_int) :: rank - call atlas__Field__device_data_${ctype}$_specf(this%c_ptr(), field_cptr, rank, shape_cptr, strides_cptr) + call atlas__Field__data_${ctype}$_specf(this%CPTR_PGIBUG_A, field_cptr, rank, shape_cptr, strides_cptr) call c_f_pointer( field_cptr, field, shape ) end subroutine @@ -273,13 +228,14 @@ subroutine dummy(this) integer function atlas_real(kind) use, intrinsic :: iso_c_binding, only : c_double, c_float + @:ENABLE_ATLAS_MACROS() integer :: kind if (kind == c_double) then atlas_real = ATLAS_KIND_REAL64 else if (kind == c_float) then atlas_real = ATLAS_KIND_REAL32 else - call ${atlas_abort("Unsupported real kind")}$ + @:ATLAS_ABORT("Unsupported real kind") end if end function @@ -287,6 +243,7 @@ integer function atlas_real(kind) integer function atlas_integer(kind) use, intrinsic :: iso_c_binding, only : c_int, c_long + @:ENABLE_ATLAS_MACROS() integer, optional :: kind atlas_integer = ATLAS_KIND_INT32 if ( present(kind) ) then @@ -295,7 +252,7 @@ integer function atlas_integer(kind) else if (kind == c_long) then atlas_integer = ATLAS_KIND_INT64 else - call ${atlas_abort("Unsupported real kind")}$ + @:ATLAS_ABORT("Unsupported integer kind") end if end if end function @@ -311,6 +268,7 @@ integer function atlas_logical(kind) !------------------------------------------------------------------------------- function atlas_data_type(kind) + @:ENABLE_ATLAS_MACROS() character(len=6) :: atlas_data_type integer, intent(in) :: kind if( kind == ATLAS_KIND_INT32 ) then @@ -322,7 +280,7 @@ function atlas_data_type(kind) else if( kind == ATLAS_KIND_REAL64 ) then atlas_data_type = "real64" else - call ${atlas_abort("cannot convert kind to data_type")}$ + @:ATLAS_ABORT("cannot convert kind to data_type") endif end function @@ -342,43 +300,20 @@ function atlas_Field__create(params) result(field) use atlas_field_c_binding type(atlas_Field) :: field class(atlas_Config), intent(in) :: params - field = atlas_Field__cptr( atlas__Field__create(params%c_ptr()) ) + field = atlas_Field__cptr( atlas__Field__create(params%CPTR_PGIBUG_B) ) call field%return() end function !------------------------------------------------------------------------------- -function atlas_Field__create_name_kind_shape_int32(name,kind,shape) result(field) +#:for dtype, ftype, ctype in integer_types +function atlas_Field__create_name_kind_shape_${dtype}$(name,kind,shape) result(field) use atlas_field_c_binding - use, intrinsic :: iso_c_binding, only : c_int - type(atlas_Field) :: field - character(len=*), intent(in) :: name - integer, intent(in) :: kind - integer(c_int), intent(in) :: shape(:) - - type(atlas_Config) :: params - - params = atlas_Config() - call params%set("creator","ArraySpec") - call params%set("shape",shape) - call params%set("fortran",.True.) - call params%set("datatype",atlas_data_type(kind)) - call params%set("name",name) - - field = atlas_Field__cptr( atlas__Field__create(params%c_ptr()) ) - call params%final() - call field%return() -end function - -!------------------------------------------------------------------------------- - -function atlas_Field__create_name_kind_shape_int64(name,kind,shape) result(field) - use atlas_field_c_binding - use, intrinsic :: iso_c_binding, only : c_long + use, intrinsic :: iso_c_binding, only : c_int, c_long type(atlas_Field) :: field character(len=*), intent(in) :: name - integer, intent(in) :: kind - integer(c_long), intent(in) :: shape(:) + integer(c_int), intent(in) :: kind + ${ftype}$, intent(in) :: shape(:) type(atlas_Config) :: params @@ -389,39 +324,19 @@ function atlas_Field__create_name_kind_shape_int64(name,kind,shape) result(field call params%set("datatype",atlas_data_type(kind)) call params%set("name",name) - field = atlas_Field__cptr( atlas__Field__create(params%c_ptr()) ) + field = atlas_Field__cptr( atlas__Field__create(params%CPTR_PGIBUG_B) ) call params%final() call field%return() end function !------------------------------------------------------------------------------- -function atlas_Field__create_kind_shape_int32(kind,shape) result(field) - use atlas_field_c_binding - use, intrinsic :: iso_c_binding, only : c_int - type(atlas_Field) :: field - integer(c_int), intent(in) :: kind - integer, intent(in) :: shape(:) - - type(atlas_Config) :: params - - params = atlas_Config() - call params%set("creator","ArraySpec") - call params%set("shape",shape) - call params%set("fortran",.True.) - call params%set("datatype",atlas_data_type(kind)) - - field = atlas_Field__cptr( atlas__Field__create(params%c_ptr()) ) - call params%final() - call field%return() -end function - -function atlas_Field__create_kind_shape_int64(kind,shape) result(field) +function atlas_Field__create_kind_shape_${dtype}$(kind,shape) result(field) use atlas_field_c_binding use, intrinsic :: iso_c_binding, only : c_int, c_long type(atlas_Field) :: field integer(c_int), intent(in) :: kind - integer(c_long), intent(in) :: shape(:) + ${ftype}$, intent(in) :: shape(:) type(atlas_Config) :: params @@ -431,11 +346,11 @@ function atlas_Field__create_kind_shape_int64(kind,shape) result(field) call params%set("fortran",.True.) call params%set("datatype",atlas_data_type(kind)) - field = atlas_Field__cptr( atlas__Field__create(params%c_ptr()) ) + field = atlas_Field__cptr( atlas__Field__create(params%CPTR_PGIBUG_B) ) call params%final() call field%return() end function - +#:endfor !------------------------------------------------------------------------------- @@ -445,6 +360,7 @@ function atlas_Field__wrap_name_${dtype}$_r${rank}$(name,data) result(field) use atlas_field_c_binding use fckit_array_module, only : array_strides, array_view1d use, intrinsic :: iso_c_binding, only : c_int, c_long, c_float, c_double + use fckit_c_interop_module, only : c_str type(atlas_Field) :: field character(len=*), intent(in) :: name ${ftype}$, intent(in) :: data(${dim[rank]}$) @@ -454,7 +370,7 @@ function atlas_Field__wrap_name_${dtype}$_r${rank}$(name,data) result(field) shapef = shape(data) stridesf = array_strides(data) data1d => array_view1d(data) - field = atlas_Field__cptr( atlas__Field__wrap_${ctype}$_specf(name,data1d,size(shapef),shapef, stridesf) ) + field = atlas_Field__cptr( atlas__Field__wrap_${ctype}$_specf(c_str(name),data1d,size(shapef),shapef, stridesf) ) call field%return() end function function atlas_Field__wrap_${dtype}$_r${rank}$(data) result(field) @@ -485,7 +401,7 @@ function Field__name(this) result(field_name) class(atlas_Field), intent(in) :: this character(len=:), allocatable :: field_name type(c_ptr) :: field_name_c_str - field_name_c_str = atlas__Field__name(this%c_ptr()) + field_name_c_str = atlas__Field__name(this%CPTR_PGIBUG_A) field_name = c_ptr_to_string(field_name_c_str) end function Field__name @@ -495,7 +411,7 @@ function Field__functionspace(this) result(functionspace) use atlas_field_c_binding type(fckit_owned_object) :: functionspace class(atlas_Field), intent(in) :: this - call functionspace%reset_c_ptr( atlas__Field__functionspace(this%c_ptr()) ) + call functionspace%reset_c_ptr( atlas__Field__functionspace(this%CPTR_PGIBUG_A) ) call functionspace%return() end function Field__functionspace @@ -510,7 +426,7 @@ function Field__datatype(this) result(datatype) type(c_ptr) :: datatype_cptr integer(c_int) :: datatype_size integer(c_int) :: datatype_allocated - call atlas__Field__datatype(this%c_ptr(),datatype_cptr,datatype_size,datatype_allocated) + call atlas__Field__datatype(this%CPTR_PGIBUG_A,datatype_cptr,datatype_size,datatype_allocated) allocate(character(len=datatype_size) :: datatype ) datatype= c_ptr_to_string(datatype_cptr) if( datatype_allocated == 1 ) call c_ptr_free(datatype_cptr) @@ -522,7 +438,7 @@ function Field__size(this) result(fieldsize) use atlas_field_c_binding class(atlas_Field), intent(in) :: this integer :: fieldsize - fieldsize = atlas__Field__size(this%c_ptr()) + fieldsize = atlas__Field__size(this%CPTR_PGIBUG_A) end function Field__size !------------------------------------------------------------------------------- @@ -531,7 +447,7 @@ function Field__rank(this) result(rank) use atlas_field_c_binding class(atlas_Field), intent(in) :: this integer :: rank - rank = atlas__Field__rank(this%c_ptr()) + rank = atlas__Field__rank(this%CPTR_PGIBUG_A) end function Field__rank !------------------------------------------------------------------------------- @@ -541,7 +457,7 @@ function Field__bytes(this) result(bytes) use, intrinsic :: iso_c_binding, only : c_double class(atlas_Field), intent(in) :: this real(c_double) :: bytes - bytes = atlas__Field__bytes(this%c_ptr()) + bytes = atlas__Field__bytes(this%CPTR_PGIBUG_A) end function Field__bytes !------------------------------------------------------------------------------- @@ -550,7 +466,7 @@ function Field__kind(this) result(kind) use atlas_field_c_binding class(atlas_Field), intent(in) :: this integer :: kind - kind = atlas__Field__kind(this%c_ptr()) + kind = atlas__Field__kind(this%CPTR_PGIBUG_A) end function Field__kind !------------------------------------------------------------------------------- @@ -559,7 +475,7 @@ function Field__levels(this) result(levels) use atlas_field_c_binding class(atlas_Field), intent(in) :: this integer :: levels - levels = atlas__Field__levels(this%c_ptr()) + levels = atlas__Field__levels(this%CPTR_PGIBUG_A) end function Field__levels !------------------------------------------------------------------------------- @@ -569,7 +485,7 @@ function Field__metadata(this) result(metadata) use atlas_metadata_module class(atlas_Field), intent(in) :: this type(atlas_Metadata) :: Metadata - call metadata%reset_c_ptr( atlas__Field__metadata(this%c_ptr()) ) + call metadata%reset_c_ptr( atlas__Field__metadata(this%CPTR_PGIBUG_A) ) end function Field__metadata !------------------------------------------------------------------------------- @@ -582,7 +498,7 @@ function Field__shape_array(this) result(shape) type(c_ptr) :: shape_c_ptr integer, pointer :: shape_f_ptr(:) integer(c_int) :: field_rank - call atlas__Field__shapef(this%c_ptr(), shape_c_ptr, field_rank) + call atlas__Field__shapef(this%CPTR_PGIBUG_A, shape_c_ptr, field_rank) call c_f_pointer ( shape_c_ptr , shape_f_ptr , (/field_rank/) ) allocate( shape(field_rank) ) shape(:) = shape_f_ptr(:) @@ -593,16 +509,16 @@ end function Field__shape_array function Field__shape_idx(this,idx) result(shape_val) use atlas_field_c_binding use, intrinsic :: iso_c_binding, only : c_ptr, c_int, c_f_pointer + @:ENABLE_ATLAS_MACROS() integer :: shape_val class(atlas_Field), intent(in) :: this integer, intent(in) :: idx type(c_ptr) :: shape_c_ptr integer, pointer :: shape_f_ptr(:) integer(c_int) :: field_rank - call atlas__Field__shapef(this%c_ptr(), shape_c_ptr, field_rank) + call atlas__Field__shapef(this%CPTR_PGIBUG_A, shape_c_ptr, field_rank) call c_f_pointer ( shape_c_ptr , shape_f_ptr , (/field_rank/) ) - if( idx > field_rank ) call atlas_throw_outofrange("shape",idx,field_rank, & -& atlas_code_location(filename,__LINE__)) + @:ATLAS_ASSERT( idx <= field_rank ) shape_val = shape_f_ptr(idx) end function Field__shape_idx @@ -612,7 +528,7 @@ subroutine set_levels(this,nb_levels) use atlas_field_c_binding class(atlas_Field), intent(inout) :: this integer, intent(in) :: nb_levels - call atlas__field__set_levels(this%c_ptr(),nb_levels) + call atlas__field__set_levels(this%CPTR_PGIBUG_A,nb_levels) end subroutine !------------------------------------------------------------------------------- @@ -622,7 +538,7 @@ subroutine rename(this,name) use fckit_c_interop_module, only : c_str class(atlas_Field), intent(inout) :: this character(len=*), intent(in) :: name - call atlas__field__rename(this%c_ptr(),c_str(name)) + call atlas__field__rename(this%CPTR_PGIBUG_A,c_str(name)) end subroutine !------------------------------------------------------------------------------- @@ -631,7 +547,7 @@ subroutine set_functionspace(this,functionspace) use atlas_field_c_binding class(atlas_Field), intent(inout) :: this class(fckit_owned_object), intent(in) :: functionspace - call atlas__field__set_functionspace(this%c_ptr(),functionspace%c_ptr()) + call atlas__field__set_functionspace(this%CPTR_PGIBUG_A,functionspace%CPTR_PGIBUG_A) end subroutine !------------------------------------------------------------------------------- @@ -640,7 +556,7 @@ function host_needs_update(this) use atlas_field_c_binding logical :: host_needs_update class(atlas_Field), intent(in) :: this - if( atlas__Field__host_needs_update(this%c_ptr()) == 1 ) then + if( atlas__Field__host_needs_update(this%CPTR_PGIBUG_A) == 1 ) then host_needs_update = .true. else host_needs_update = .false. @@ -653,7 +569,7 @@ function device_needs_update(this) use atlas_field_c_binding logical :: device_needs_update class(atlas_Field), intent(in) :: this - if( atlas__Field__device_needs_update(this%c_ptr()) == 1 ) then + if( atlas__Field__device_needs_update(this%CPTR_PGIBUG_A) == 1 ) then device_needs_update = .true. else device_needs_update = .false. @@ -665,7 +581,7 @@ function device_needs_update(this) subroutine clone_to_device(this) use atlas_field_c_binding class(atlas_Field), intent(inout) :: this - call atlas__Field__clone_to_device(this%c_ptr()) + call atlas__Field__clone_to_device(this%CPTR_PGIBUG_A) end subroutine !------------------------------------------------------------------------------- @@ -673,7 +589,7 @@ subroutine clone_to_device(this) subroutine clone_from_device(this) use atlas_field_c_binding class(atlas_Field), intent(inout) :: this - call atlas__Field__clone_from_device(this%c_ptr()) + call atlas__Field__clone_from_device(this%CPTR_PGIBUG_A) end subroutine !------------------------------------------------------------------------------- @@ -681,11 +597,62 @@ subroutine clone_from_device(this) subroutine sync_host_device(this) use atlas_field_c_binding class(atlas_Field), intent(inout) :: this - call atlas__Field__sync_host_device(this%c_ptr()) + call atlas__Field__sync_host_device(this%CPTR_PGIBUG_A) +end subroutine + +!------------------------------------------------------------------------------- + +subroutine halo_exchange(this,on_device) + use, intrinsic :: iso_c_binding, only : c_int + use atlas_field_c_binding + class(atlas_Field), intent(in) :: this + logical, optional :: on_device + integer(c_int) :: on_device_int + on_device_int = 0 + if( present(on_device) ) then + if( on_device ) on_device_int = 1 + endif + call atlas__Field__halo_exchange(this%CPTR_PGIBUG_A, on_device_int) +end subroutine + +!------------------------------------------------------------------------------- + +subroutine set_dirty(this,value) + use, intrinsic :: iso_c_binding, only : c_int + use atlas_field_c_binding + class(atlas_Field), intent(in) :: this + logical, optional, intent(in) :: value + integer(c_int) :: value_int + if( present(value) ) then + if( value ) then + value_int = 1 + else + value_int = 0 + endif + else + value_int = 1 + endif + call atlas__Field__set_dirty(this%CPTR_PGIBUG_A, value_int) end subroutine !------------------------------------------------------------------------------- +function dirty(this) result(value) + use, intrinsic :: iso_c_binding, only : c_int + use atlas_field_c_binding + class(atlas_Field), intent(inout) :: this + logical :: value + integer(c_int) :: value_int + value_int = atlas__Field__dirty(this%CPTR_PGIBUG_A) + if( value_int == 0 ) then + value = .false. + else + value = .true. + endif +end function + +!------------------------------------------------------------------------------- + ATLAS_FINAL subroutine atlas_Field__final_auto(this) type(atlas_Field), intent(inout) :: this #if FCKIT_FINAL_DEBUGGING diff --git a/src/atlas_f/field/atlas_State_module.F90 b/src/atlas_f/field/atlas_State_module.F90 index a5a8b1db8..75042ca89 100644 --- a/src/atlas_f/field/atlas_State_module.F90 +++ b/src/atlas_f/field/atlas_State_module.F90 @@ -1,10 +1,18 @@ +! (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_State_module use fckit_owned_object_module, only: fckit_owned_object use atlas_Field_module, only: atlas_Field - +use atlas_kinds_module, only: ATLAS_KIND_IDX implicit none private :: fckit_owned_object @@ -96,10 +104,10 @@ function atlas_State__generate(generator, params) result(this) call this%reset_c_ptr( atlas__State__new() ) if( present(params) ) then - call atlas__State__initialize(this%c_ptr(),c_str(generator),params%c_ptr()) + call atlas__State__initialize(this%CPTR_PGIBUG_A,c_str(generator),params%CPTR_PGIBUG_B) else p = atlas_Config() - call atlas__State__initialize(this%c_ptr(),c_str(generator),p%c_ptr()) + call atlas__State__initialize(this%CPTR_PGIBUG_A,c_str(generator),p%CPTR_PGIBUG_B) call p%final() endif call this%return() @@ -109,7 +117,7 @@ subroutine atlas_State__add(this,field) use atlas_state_c_binding class(atlas_State), intent(inout) :: this class(atlas_Field), intent(in) :: field - call atlas__State__add(this%c_ptr(),field%c_ptr()) + call atlas__State__add(this%CPTR_PGIBUG_A,field%CPTR_PGIBUG_A) end subroutine subroutine atlas_State__remove(this,name) @@ -117,7 +125,7 @@ subroutine atlas_State__remove(this,name) use atlas_state_c_binding class(atlas_State), intent(inout) :: this character(len=*), intent(in) :: name - call atlas__State__remove(this%c_ptr(),c_str(name)) + call atlas__State__remove(this%CPTR_PGIBUG_A,c_str(name)) end subroutine function atlas_State__has(this,name) result(has) @@ -127,16 +135,16 @@ function atlas_State__has(this,name) result(has) class(atlas_State), intent(in) :: this character(len=*), intent(in) :: name integer :: has_int - has_int = atlas__State__has(this%c_ptr(),c_str(name)) + has_int = atlas__State__has(this%CPTR_PGIBUG_A,c_str(name)) has = .False. if( has_int == 1 ) has = .True. end function function atlas_State__size(this) result(size) use atlas_state_c_binding - integer :: size + integer(ATLAS_KIND_IDX) :: size class(atlas_State), intent(in) :: this - size = atlas__State__size(this%c_ptr()) + size = atlas__State__size(this%CPTR_PGIBUG_A) end function function atlas_State__field_by_name(this,name) result(field) @@ -145,7 +153,7 @@ function atlas_State__field_by_name(this,name) result(field) type(atlas_Field) :: field class(atlas_State), intent(inout) :: this character(len=*), intent(in) :: name - field = atlas_Field( atlas__State__field_by_name(this%c_ptr(),c_str(name)) ) + field = atlas_Field( atlas__State__field_by_name(this%CPTR_PGIBUG_A,c_str(name)) ) call field%return() end function @@ -154,7 +162,7 @@ function atlas_State__field_by_index(this,index) result(field) type(atlas_Field) :: field class(atlas_State), intent(in) :: this integer, intent(in) :: index - field = atlas_Field( atlas__State__field_by_index(this%c_ptr(),index-1) ) + field = atlas_Field( atlas__State__field_by_index(this%CPTR_PGIBUG_A,int(index-1,ATLAS_KIND_IDX)) ) call field%return() end function @@ -163,7 +171,7 @@ function atlas_State__metadata(this) result(metadata) use atlas_Metadata_module, only: atlas_Metadata type(atlas_Metadata) :: metadata class(atlas_State), intent(in) :: this - call metadata%reset_c_ptr( atlas__State__metadata(this%c_ptr()) ) + call metadata%reset_c_ptr( atlas__State__metadata(this%CPTR_PGIBUG_A) ) end function !------------------------------------------------------------------------------- diff --git a/src/atlas_f/functionspace/atlas_FunctionSpace_module.F90 b/src/atlas_f/functionspace/atlas_FunctionSpace_module.F90 index 5fc43ece4..6cb66799b 100644 --- a/src/atlas_f/functionspace/atlas_FunctionSpace_module.F90 +++ b/src/atlas_f/functionspace/atlas_FunctionSpace_module.F90 @@ -1,15 +1,25 @@ +! (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_module use fckit_owned_object_module, only : fckit_owned_object use atlas_field_module, only : atlas_Field +use atlas_fieldset_module, only : atlas_FieldSet use atlas_config_module, only : atlas_Config implicit none private :: fckit_owned_object private :: atlas_Field +private :: atlas_FieldSet private :: atlas_Config public :: atlas_FunctionSpace @@ -42,12 +52,17 @@ module atlas_functionspace_module procedure, private :: deprecated_create_field_1 ! deprecated procedure, private :: deprecated_create_field_2 ! deprecated + procedure, private :: halo_exchange_field + procedure, private :: halo_exchange_fieldset + generic, public :: create_field => & & create_field_args, & & create_field_template, & & deprecated_create_field_1, & & deprecated_create_field_2 + generic, public :: halo_exchange => halo_exchange_field, halo_exchange_fieldset + #if FCKIT_FINAL_NOT_INHERITING final :: atlas_FunctionSpace__final_auto #endif @@ -78,7 +93,7 @@ function atlas_FunctionSpace__name(this) result(name) character(len=:), allocatable :: name type(c_ptr) :: name_c_str integer :: size - call atlas__FunctionSpace__name(this%c_ptr(), name_c_str, size ) + call atlas__FunctionSpace__name(this%CPTR_PGIBUG_A, name_c_str, size ) name = c_ptr_to_string(name_c_str) call c_ptr_free(name_c_str) end function @@ -108,7 +123,7 @@ function create_field_args(this,kind,name,levels,variables,global,owner) result( if( present(levels) ) call options%set("levels",levels) if( present(variables) ) call options%set("variables",variables) - field = atlas_Field( atlas__FunctionSpace__create_field( this%c_ptr(), options%c_ptr() ) ) + field = atlas_Field( atlas__FunctionSpace__create_field( this%CPTR_PGIBUG_A, options%CPTR_PGIBUG_B ) ) call field%return() call options%final() @@ -135,7 +150,7 @@ function create_field_template(this,template,name,global,owner) result(field) if( present(global) ) call options%set("global",global) field = atlas_Field( atlas__FunctionSpace__create_field_template( & - & this%c_ptr(), template%c_ptr(),options%c_ptr()) ) + & this%CPTR_PGIBUG_A, template%CPTR_PGIBUG_A,options%CPTR_PGIBUG_B) ) call options%final() @@ -144,6 +159,24 @@ function create_field_template(this,template,name,global,owner) result(field) !------------------------------------------------------------------------------ +subroutine halo_exchange_fieldset(this,fieldset) + use atlas_functionspace_c_binding + class(atlas_Functionspace), intent(in) :: this + type(atlas_FieldSet), intent(inout) :: fieldset + call atlas__FunctionSpace__halo_exchange_fieldset(this%CPTR_PGIBUG_A,fieldset%CPTR_PGIBUG_A) +end subroutine + +!------------------------------------------------------------------------------ + +subroutine halo_exchange_field(this,field) + use atlas_functionspace_c_binding + class(atlas_Functionspace), intent(in) :: this + type(atlas_Field), intent(inout) :: field + call atlas__FunctionSpace__halo_exchange_field(this%CPTR_PGIBUG_A,field%CPTR_PGIBUG_A) +end subroutine + +!------------------------------------------------------------------------------ + !------------------------------------------------------------------------------ ! Deprecated versions compatible to support IFS CY45R1 @@ -169,7 +202,7 @@ function deprecated_create_field_1(this,name,kind,levels,vars) result(field) opt_variables = sum(vars) call options%set("variables",opt_variables) - field = atlas_Field( atlas__FunctionSpace__create_field( this%c_ptr(), options%c_ptr() ) ) + field = atlas_Field( atlas__FunctionSpace__create_field( this%CPTR_PGIBUG_A, options%CPTR_PGIBUG_B ) ) call options%final() @@ -192,7 +225,7 @@ function deprecated_create_field_2(this,require_name,kind,levels) result(field) call options%set("name",require_name) call options%set("levels",levels) - field = atlas_Field( atlas__FunctionSpace__create_field( this%c_ptr(), options%c_ptr() ) ) + field = atlas_Field( atlas__FunctionSpace__create_field( this%CPTR_PGIBUG_A, options%CPTR_PGIBUG_B ) ) call options%final() call field%return() diff --git a/src/atlas_f/functionspace/atlas_functionspace_EdgeColumns_module.F90 b/src/atlas_f/functionspace/atlas_functionspace_EdgeColumns_module.F90 index 5dc95913a..041d2b0a4 100644 --- a/src/atlas_f/functionspace/atlas_functionspace_EdgeColumns_module.F90 +++ b/src/atlas_f/functionspace/atlas_functionspace_EdgeColumns_module.F90 @@ -1,3 +1,11 @@ +! (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_EdgeColumns_module @@ -54,9 +62,6 @@ module atlas_functionspace_EdgeColumns_module procedure, public :: mesh procedure, public :: edges - procedure, private :: halo_exchange_fieldset - procedure, private :: halo_exchange_field - generic, public :: halo_exchange => halo_exchange_field, halo_exchange_fieldset procedure, public :: get_halo_exchange procedure, private :: gather_fieldset @@ -110,7 +115,8 @@ function constructor(mesh,halo,levels) result(this) 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__fs__EdgeColumns__new(mesh%c_ptr(),config%c_ptr()) ) + call this%reset_c_ptr( atlas__fs__EdgeColumns__new( & + mesh%CPTR_PGIBUG_A,config%CPTR_PGIBUG_B) ) call config%final() call this%return() end function @@ -121,7 +127,7 @@ function nb_edges(this) use atlas_functionspace_EdgeColumns_c_binding integer :: nb_edges class(atlas_functionspace_EdgeColumns), intent(in) :: this - nb_edges = atlas__fs__EdgeColumns__nb_edges(this%c_ptr()) + nb_edges = atlas__fs__EdgeColumns__nb_edges(this%CPTR_PGIBUG_A) end function !------------------------------------------------------------------------------ @@ -130,7 +136,7 @@ function mesh(this) use atlas_functionspace_EdgeColumns_c_binding type(atlas_Mesh) :: mesh class(atlas_functionspace_EdgeColumns), intent(in) :: this - call mesh%reset_c_ptr( atlas__fs__EdgeColumns__mesh(this%c_ptr()) ) + call mesh%reset_c_ptr( atlas__fs__EdgeColumns__mesh(this%CPTR_PGIBUG_A) ) call mesh%return() end function @@ -140,35 +146,17 @@ function edges(this) use atlas_functionspace_EdgeColumns_c_binding type(atlas_mesh_Edges) :: edges class(atlas_functionspace_EdgeColumns), intent(in) :: this - call edges%reset_c_ptr( atlas__fs__EdgeColumns__edges(this%c_ptr()) ) + call edges%reset_c_ptr( atlas__fs__EdgeColumns__edges(this%CPTR_PGIBUG_A) ) call edges%return() end function !------------------------------------------------------------------------------ -subroutine halo_exchange_fieldset(this,fieldset) - use atlas_functionspace_EdgeColumns_c_binding - class(atlas_functionspace_EdgeColumns), intent(in) :: this - type(atlas_FieldSet), intent(inout) :: fieldset - call atlas__fs__EdgeColumns__halo_exchange_fieldset(this%c_ptr(),fieldset%c_ptr()) -end subroutine - -!------------------------------------------------------------------------------ - -subroutine halo_exchange_field(this,field) - use atlas_functionspace_EdgeColumns_c_binding - class(atlas_functionspace_EdgeColumns), intent(in) :: this - type(atlas_Field), intent(inout) :: field - call atlas__fs__EdgeColumns__halo_exchange_field(this%c_ptr(),field%c_ptr()) -end subroutine - -!------------------------------------------------------------------------------ - function get_gather(this) result(gather) use atlas_functionspace_EdgeColumns_c_binding type(atlas_GatherScatter) :: gather class(atlas_functionspace_EdgeColumns), intent(in) :: this - call gather%reset_c_ptr( atlas__fs__EdgeColumns__get_gather(this%c_ptr()) ) + call gather%reset_c_ptr( atlas__fs__EdgeColumns__get_gather(this%CPTR_PGIBUG_A) ) ! call gather%return() end function @@ -178,7 +166,7 @@ function get_scatter(this) result(scatter) use atlas_functionspace_EdgeColumns_c_binding type(atlas_GatherScatter) :: scatter class(atlas_functionspace_EdgeColumns), intent(in) :: this - call scatter%reset_c_ptr( atlas__fs__EdgeColumns__get_scatter(this%c_ptr()) ) + call scatter%reset_c_ptr( atlas__fs__EdgeColumns__get_scatter(this%CPTR_PGIBUG_A) ) ! call scatter%return() end function @@ -189,7 +177,8 @@ subroutine gather_fieldset(this,local,global) class(atlas_functionspace_EdgeColumns), intent(in) :: this type(atlas_FieldSet), intent(in) :: local type(atlas_FieldSet), intent(inout) :: global - call atlas__fs__EdgeColumns__gather_fieldset(this%c_ptr(),local%c_ptr(),global%c_ptr()) + call atlas__fs__EdgeColumns__gather_fieldset(this%CPTR_PGIBUG_A, & + local%CPTR_PGIBUG_A,global%CPTR_PGIBUG_A) end subroutine !------------------------------------------------------------------------------ @@ -199,7 +188,7 @@ subroutine gather_field(this,local,global) class(atlas_functionspace_EdgeColumns), intent(in) :: this type(atlas_Field), intent(in) :: local type(atlas_Field), intent(inout) :: global - call atlas__fs__EdgeColumns__gather_field(this%c_ptr(),local%c_ptr(),global%c_ptr()) + call atlas__fs__EdgeColumns__gather_field(this%CPTR_PGIBUG_A,local%CPTR_PGIBUG_A,global%CPTR_PGIBUG_A) end subroutine !------------------------------------------------------------------------------ @@ -209,7 +198,8 @@ subroutine scatter_fieldset(this,global,local) class(atlas_functionspace_EdgeColumns), intent(in) :: this type(atlas_FieldSet), intent(in) :: global type(atlas_FieldSet), intent(inout) :: local - call atlas__fs__EdgeColumns__scatter_fieldset(this%c_ptr(),global%c_ptr(),local%c_ptr()) + call atlas__fs__EdgeColumns__scatter_fieldset(this%CPTR_PGIBUG_A, & + global%CPTR_PGIBUG_A,local%CPTR_PGIBUG_A) end subroutine !------------------------------------------------------------------------------ @@ -219,7 +209,8 @@ subroutine scatter_field(this,global,local) class(atlas_functionspace_EdgeColumns), intent(in) :: this type(atlas_Field), intent(in) :: global type(atlas_Field), intent(inout) :: local - call atlas__fs__EdgeColumns__scatter_field(this%c_ptr(),global%c_ptr(),local%c_ptr()) + call atlas__fs__EdgeColumns__scatter_field(this%CPTR_PGIBUG_A, & + global%CPTR_PGIBUG_A,local%CPTR_PGIBUG_A) end subroutine !------------------------------------------------------------------------------ @@ -228,7 +219,7 @@ function get_halo_exchange(this) result(halo_exchange) use atlas_functionspace_EdgeColumns_c_binding type(atlas_HaloExchange) :: halo_exchange class(atlas_functionspace_EdgeColumns), intent(in) :: this - call halo_exchange%reset_c_ptr( atlas__fs__EdgeColumns__get_halo_exchange(this%c_ptr()) ) + call halo_exchange%reset_c_ptr( atlas__fs__EdgeColumns__get_halo_exchange(this%CPTR_PGIBUG_A) ) ! call halo_exchange%return() end function @@ -238,7 +229,7 @@ function get_checksum(this) result(checksum) use atlas_functionspace_EdgeColumns_c_binding type(atlas_Checksum) :: checksum class(atlas_functionspace_EdgeColumns), intent(in) :: this - call checksum%reset_c_ptr( atlas__fs__EdgeColumns__get_checksum(this%c_ptr()) ) + call checksum%reset_c_ptr( atlas__fs__EdgeColumns__get_checksum(this%CPTR_PGIBUG_A) ) ! call checksum%return() end function @@ -251,7 +242,8 @@ function checksum_fieldset(this,fieldset) result(checksum) type(atlas_FieldSet), intent(in) :: fieldset type(c_ptr) :: checksum_cptr integer :: checksum_size, checksum_allocated - call atlas__fs__EdgeColumns__checksum_fieldset(this%c_ptr(),fieldset%c_ptr(),checksum_cptr,checksum_size,checksum_allocated) + call atlas__fs__EdgeColumns__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) @@ -266,7 +258,8 @@ function checksum_field(this,field) result(checksum) type(atlas_Field), intent(in) :: field type(c_ptr) :: checksum_cptr integer :: checksum_size, checksum_allocated - call atlas__fs__EdgeColumns__checksum_field(this%c_ptr(),field%c_ptr(),checksum_cptr,checksum_size,checksum_allocated) + call atlas__fs__EdgeColumns__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) diff --git a/src/atlas_f/functionspace/atlas_functionspace_NodeColumns_module.F90 b/src/atlas_f/functionspace/atlas_functionspace_NodeColumns_module.F90 deleted file mode 100644 index e341c5e68..000000000 --- a/src/atlas_f/functionspace/atlas_functionspace_NodeColumns_module.F90 +++ /dev/null @@ -1,1959 +0,0 @@ -#include "atlas/atlas_f.h" - -module atlas_functionspace_NodeColumns_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_Nodes_module, only: atlas_mesh_Nodes -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_Nodes -private :: atlas_GatherScatter -private :: atlas_HaloExchange -private :: atlas_Checksum -private :: atlas_Mesh -private :: atlas_Config -private :: ATLAS_KIND_GIDX - -public :: atlas_functionspace_NodeColumns - -private - -!------------------------------------------------------------------------------ -TYPE, extends(atlas_FunctionSpace) :: atlas_functionspace_NodeColumns - -! Purpose : -! ------- -! *atlas_functionspace_NodeColumns* : Interpretes fields defined in nodes - -! Methods : -! ------- - -! Author : -! ------ -! August-2015 Willem Deconinck *ECMWF* - -!------------------------------------------------------------------------------ -contains - - - procedure, public :: nb_nodes - procedure, public :: mesh - procedure, public :: nodes - - procedure, private :: halo_exchange_fieldset - procedure, private :: halo_exchange_field - generic, public :: halo_exchange => halo_exchange_fieldset, halo_exchange_field - 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 - - procedure, private :: sum_real64_r0 - procedure, private :: sum_real32_r0 - procedure, private :: sum_int64_r0 - procedure, private :: sum_int32_r0 - procedure, private :: sum_real64_r1 - procedure, private :: sum_real32_r1 - procedure, private :: sum_int64_r1 - procedure, private :: sum_int32_r1 - procedure, private :: order_independent_sum_real32_r0 - procedure, private :: order_independent_sum_real64_r0 - procedure, private :: order_independent_sum_real32_r1 - procedure, private :: order_independent_sum_real64_r1 - procedure, private :: minimum_real32_r0 - procedure, private :: minimum_real64_r0 - procedure, private :: minimum_int32_r0 - procedure, private :: minimum_int64_r0 - procedure, private :: minimum_real32_r1 - procedure, private :: minimum_real64_r1 - procedure, private :: minimum_int32_r1 - procedure, private :: minimum_int64_r1 - procedure, private :: maximum_real32_r0 - procedure, private :: maximum_real64_r0 - procedure, private :: maximum_int32_r0 - procedure, private :: maximum_int64_r0 - procedure, private :: maximum_real32_r1 - procedure, private :: maximum_real64_r1 - procedure, private :: maximum_int32_r1 - procedure, private :: maximum_int64_r1 - procedure, private :: minloc_real32_r0 - procedure, private :: minloc_real64_r0 - procedure, private :: minloc_int32_r0 - procedure, private :: minloc_int64_r0 - procedure, private :: minloc_real32_r1 - procedure, private :: minloc_real64_r1 - procedure, private :: minloc_int32_r1 - procedure, private :: minloc_int64_r1 - procedure, private :: maxloc_real32_r0 - procedure, private :: maxloc_real64_r0 - procedure, private :: maxloc_int32_r0 - procedure, private :: maxloc_int64_r0 - procedure, private :: maxloc_real32_r1 - procedure, private :: maxloc_real64_r1 - procedure, private :: maxloc_int32_r1 - procedure, private :: maxloc_int64_r1 - procedure, private :: mean_real32_r0 - procedure, private :: mean_real64_r0 - procedure, private :: mean_int32_r0 - procedure, private :: mean_int64_r0 - procedure, private :: mean_real32_r1 - procedure, private :: mean_real64_r1 - procedure, private :: mean_int32_r1 - procedure, private :: mean_int64_r1 - procedure, private :: mean_and_stddev_real32_r0 - procedure, private :: mean_and_stddev_real64_r0 - procedure, private :: mean_and_stddev_int32_r0 - procedure, private :: mean_and_stddev_int64_r0 - procedure, private :: mean_and_stddev_real32_r1 - procedure, private :: mean_and_stddev_real64_r1 - procedure, private :: mean_and_stddev_int32_r1 - procedure, private :: mean_and_stddev_int64_r1 - - generic, public :: minimum => & - & minimum_real32_r0, minimum_real32_r1, & - & minimum_real64_r0, minimum_real64_r1, & - & minimum_int32_r0, minimum_int32_r1, & - & minimum_int64_r0, minimum_int64_r1 - - procedure, public :: minimum_per_level - - generic, public :: maximum => & - & maximum_real32_r0, maximum_real32_r1, & - & maximum_real64_r0, maximum_real64_r1, & - & maximum_int32_r0, maximum_int32_r1, & - & maximum_int64_r0, maximum_int64_r1 - - procedure, public :: maximum_per_level - - generic, public :: minimum_and_location => & - & minloc_real32_r0, minloc_real32_r1, & - & minloc_real64_r0, minloc_real64_r1, & - & minloc_int32_r0, minloc_int32_r1, & - & minloc_int64_r0, minloc_int64_r1 - - procedure, public :: minimum_and_location_per_level => & - & minloc_per_level - - generic, public :: maximum_and_location => & - & maxloc_real32_r0, maxloc_real32_r1, & - & maxloc_real64_r0, maxloc_real64_r1, & - & maxloc_int32_r0, maxloc_int32_r1, & - & maxloc_int64_r0, maxloc_int64_r1 - - procedure, public :: maximum_and_location_per_level => & - & maxloc_per_level - - generic, public :: sum => & - & sum_real32_r0, sum_real32_r1, & - & sum_real64_r0, sum_real64_r1, & - & sum_int32_r0, sum_int32_r1, & - & sum_int64_r0, sum_int64_r1 - - procedure, public :: sum_per_level - - generic, public :: order_independent_sum => & - & order_independent_sum_real32_r0, order_independent_sum_real32_r1, & - & order_independent_sum_real64_r0, order_independent_sum_real64_r1 - - - procedure, public :: order_independent_sum_per_level - - generic, public :: mean => & - & mean_real32_r0, mean_real32_r1, & - & mean_real64_r0, mean_real64_r1, & - & mean_int32_r0, mean_int32_r1, & - & mean_int64_r0, mean_int64_r1 - - procedure, public :: mean_per_level - - generic, public :: mean_and_standard_deviation => & - & mean_and_stddev_real32_r0, mean_and_stddev_real32_r1, & - & mean_and_stddev_real64_r0, mean_and_stddev_real64_r1, & - & mean_and_stddev_int32_r0, mean_and_stddev_int32_r1, & - & mean_and_stddev_int64_r0, mean_and_stddev_int64_r1 - - procedure, public :: mean_and_standard_deviation_per_level => & - & mean_and_stddev_per_level - -#if FCKIT_FINAL_NOT_INHERITING - final :: atlas_functionspace_NodeColumns__final_auto -#endif - -END TYPE atlas_functionspace_NodeColumns - -interface atlas_functionspace_NodeColumns - 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_NodeColumns) :: 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_NodeColumns_c_binding - type(atlas_functionspace_NodeColumns) :: 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__NodesFunctionSpace__new(mesh%c_ptr(),config%c_ptr()) ) - call config%final() - call this%return() -end function - -!------------------------------------------------------------------------------ - -function nb_nodes(this) - use atlas_functionspace_NodeColumns_c_binding - integer :: nb_nodes - class(atlas_functionspace_NodeColumns), intent(in) :: this - nb_nodes = atlas__NodesFunctionSpace__nb_nodes(this%c_ptr()) -end function - -!------------------------------------------------------------------------------ - -function mesh(this) - use atlas_functionspace_NodeColumns_c_binding - type(atlas_Mesh) :: mesh - class(atlas_functionspace_NodeColumns), intent(in) :: this - call mesh%reset_c_ptr( atlas__NodesFunctionSpace__mesh(this%c_ptr()) ) - call mesh%return() -end function - -!------------------------------------------------------------------------------ - -function nodes(this) - use atlas_functionspace_NodeColumns_c_binding - type(atlas_mesh_Nodes) :: nodes - class(atlas_functionspace_NodeColumns), intent(in) :: this - call nodes%reset_c_ptr( atlas__NodesFunctionSpace__nodes(this%c_ptr()) ) - call nodes%return() -end function - -!------------------------------------------------------------------------------ -!------------------------------------------------------------------------------ - -subroutine halo_exchange_fieldset(this,fieldset) - use atlas_functionspace_NodeColumns_c_binding - class(atlas_functionspace_NodeColumns), intent(in) :: this - type(atlas_FieldSet), intent(inout) :: fieldset - call atlas__NodesFunctionSpace__halo_exchange_fieldset(this%c_ptr(),fieldset%c_ptr()) -end subroutine - -!------------------------------------------------------------------------------ - -subroutine halo_exchange_field(this,field) - use atlas_functionspace_NodeColumns_c_binding - class(atlas_functionspace_NodeColumns), intent(in) :: this - type(atlas_Field), intent(inout) :: field - call atlas__NodesFunctionSpace__halo_exchange_field(this%c_ptr(),field%c_ptr()) -end subroutine - -!------------------------------------------------------------------------------ - -function get_gather(this) result(gather) - use atlas_functionspace_NodeColumns_c_binding - type(atlas_GatherScatter) :: gather - class(atlas_functionspace_NodeColumns), intent(in) :: this - call gather%reset_c_ptr( atlas__NodesFunctioNSpace__get_gather(this%c_ptr()) ) -end function - -!------------------------------------------------------------------------------ - -function get_scatter(this) result(gather) - use atlas_functionspace_NodeColumns_c_binding - type(atlas_GatherScatter) :: gather - class(atlas_functionspace_NodeColumns), intent(in) :: this - call gather%reset_c_ptr( atlas__NodesFunctioNSpace__get_scatter(this%c_ptr()) ) -end function - -!------------------------------------------------------------------------------ - -subroutine gather_fieldset(this,local,global) - use atlas_functionspace_NodeColumns_c_binding - class(atlas_functionspace_NodeColumns), intent(in) :: this - type(atlas_FieldSet), intent(in) :: local - type(atlas_FieldSet), intent(inout) :: global - call atlas__NodesFunctionSpace__gather_fieldset(this%c_ptr(),local%c_ptr(),global%c_ptr()) -end subroutine - -!------------------------------------------------------------------------------ - -subroutine gather_field(this,local,global) - use atlas_functionspace_NodeColumns_c_binding - class(atlas_functionspace_NodeColumns), intent(in) :: this - type(atlas_Field), intent(in) :: local - type(atlas_Field), intent(inout) :: global - call atlas__NodesFunctionSpace__gather_field(this%c_ptr(),local%c_ptr(),global%c_ptr()) -end subroutine - -!------------------------------------------------------------------------------ - -subroutine scatter_fieldset(this,global,local) - use atlas_functionspace_NodeColumns_c_binding - class(atlas_functionspace_NodeColumns), intent(in) :: this - type(atlas_FieldSet), intent(in) :: global - type(atlas_FieldSet), intent(inout) :: local - call atlas__NodesFunctionSpace__scatter_fieldset(this%c_ptr(),global%c_ptr(),local%c_ptr()) -end subroutine - -!------------------------------------------------------------------------------ - -subroutine scatter_field(this,global,local) - use atlas_functionspace_NodeColumns_c_binding - class(atlas_functionspace_NodeColumns), intent(in) :: this - type(atlas_Field), intent(in) :: global - type(atlas_Field), intent(inout) :: local - call atlas__NodesFunctionSpace__scatter_field(this%c_ptr(),global%c_ptr(),local%c_ptr()) -end subroutine - -!------------------------------------------------------------------------------ - -function get_halo_exchange(this) result(halo_exchange) - use atlas_functionspace_NodeColumns_c_binding - type(atlas_HaloExchange) :: halo_exchange - class(atlas_functionspace_NodeColumns), intent(in) :: this - call halo_exchange%reset_c_ptr( atlas__NodesFunctioNSpace__get_halo_exchange(this%c_ptr()) ) -end function - -!------------------------------------------------------------------------------ - -function get_checksum(this) result(checksum) - use atlas_functionspace_NodeColumns_c_binding - type(atlas_Checksum) :: checksum - class(atlas_functionspace_NodeColumns), intent(in) :: this - call checksum%reset_c_ptr( atlas__NodesFunctioNSpace__get_checksum(this%c_ptr()) ) -end function - -!------------------------------------------------------------------------------ - -function checksum_fieldset(this,fieldset) result(checksum) - use atlas_functionspace_NodeColumns_c_binding - use, intrinsic :: iso_c_binding, only : c_ptr - character(len=:), allocatable :: checksum - class(atlas_functionspace_NodeColumns), intent(in) :: this - type(atlas_FieldSet), intent(in) :: fieldset - type(c_ptr) :: checksum_cptr - integer :: checksum_size, checksum_allocated - call atlas__NodesFunctionSpace__checksum_fieldset(this%c_ptr(),fieldset%c_ptr(),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_NodeColumns_c_binding - use, intrinsic :: iso_c_binding, only : c_ptr - character(len=:), allocatable :: checksum - class(atlas_functionspace_NodeColumns), intent(in) :: this - type(atlas_Field), intent(in) :: field - type(c_ptr) :: checksum_cptr - integer :: checksum_size, checksum_allocated - call atlas__NodesFunctionSpace__checksum_field(this%c_ptr(),field%c_ptr(),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 - -!------------------------------------------------------------------------------ - -subroutine minimum_real32_r0(this,field,minimum) - use atlas_functionspace_NodeColumns_c_binding - use, intrinsic :: iso_c_binding, only : c_float - class(atlas_functionspace_NodeColumns), intent(in) :: this - type(atlas_Field) :: field - real(c_float), intent(out) :: minimum - call atlas__NodesFunctionSpace__min_float(this%c_ptr(),field%c_ptr(),minimum) -end subroutine - -!------------------------------------------------------------------------------ - -subroutine minimum_real32_r1(this,field,minimum) - use atlas_functionspace_NodeColumns_c_binding - use, intrinsic :: iso_c_binding, only : c_float,c_ptr,c_f_pointer - class(atlas_functionspace_NodeColumns), intent(in) :: this - type(atlas_Field) :: field - real(c_float), allocatable, intent(out) :: minimum(:) - type(c_ptr) :: min_cptr - real(c_float), pointer :: min_fptr(:) - integer :: min_size - call atlas__NodesFunctionSpace__min_arr_float(this%c_ptr(),field%c_ptr(),min_cptr,min_size) - call c_f_pointer(min_cptr,min_fptr,(/min_size/)) - allocate(minimum(min_size)) - minimum(:) = min_fptr(:) - call c_ptr_free(min_cptr) -end subroutine - -!------------------------------------------------------------------------------ - -subroutine maximum_real32_r0(this,field,maximum) - use atlas_functionspace_NodeColumns_c_binding - use, intrinsic :: iso_c_binding, only : c_float - class(atlas_functionspace_NodeColumns), intent(in) :: this - type(atlas_Field) :: field - real(c_float), intent(out) :: maximum - call atlas__NodesFunctionSpace__max_float(this%c_ptr(),field%c_ptr(),maximum) -end subroutine - -!------------------------------------------------------------------------------ - -subroutine maximum_real32_r1(this,field,maximum) - use atlas_functionspace_NodeColumns_c_binding - use, intrinsic :: iso_c_binding, only : c_float, c_ptr, c_f_pointer - class(atlas_functionspace_NodeColumns), intent(in) :: this - type(atlas_Field) :: field - real(c_float), allocatable, intent(out) :: maximum(:) - type(c_ptr) :: max_cptr - real(c_float), pointer :: max_fptr(:) - integer :: max_size - call atlas__NodesFunctionSpace__max_arr_float(this%c_ptr(),field%c_ptr(),max_cptr,max_size) - call c_f_pointer(max_cptr,max_fptr,(/max_size/)) - allocate(maximum(max_size)) - maximum(:) = max_fptr(:) - call c_ptr_free(max_cptr) -end subroutine - -!------------------------------------------------------------------------------ - -subroutine minloc_real32_r0(this,field,minimum,location) - use atlas_functionspace_NodeColumns_c_binding - use, intrinsic :: iso_c_binding, only : c_float, c_long - class(atlas_functionspace_NodeColumns), intent(in) :: this - type(atlas_Field) :: field - real(c_float), intent(out) :: minimum - integer(ATLAS_KIND_GIDX), intent(out) :: location - integer(c_long) :: loc - call atlas__NodesFunctionSpace__minloc_float(this%c_ptr(),field%c_ptr(),minimum,loc) - location = loc -end subroutine - -!------------------------------------------------------------------------------ - -subroutine maxloc_real32_r0(this,field,maximum,location) - use atlas_functionspace_NodeColumns_c_binding - use, intrinsic :: iso_c_binding, only : c_float, c_long - class(atlas_functionspace_NodeColumns), intent(in) :: this - type(atlas_Field) :: field - real(c_float), intent(out) :: maximum - integer(ATLAS_KIND_GIDX), intent(out) :: location - integer(c_long) :: loc - call atlas__NodesFunctionSpace__maxloc_float(this%c_ptr(),field%c_ptr(),maximum,loc) - location = loc -end subroutine - -!------------------------------------------------------------------------------ - -subroutine minloc_real32_r1(this,field,minimum,location) - use atlas_functionspace_NodeColumns_c_binding - use, intrinsic :: iso_c_binding, only : c_float, c_ptr, c_f_pointer, c_long - class(atlas_functionspace_NodeColumns), intent(in) :: this - type(atlas_Field) :: field - real(c_float), allocatable, intent(out) :: minimum(:) - integer(ATLAS_KIND_GIDX), allocatable, intent(out) :: location(:) - type(c_ptr) :: min_cptr, loc_cptr - real(c_float), pointer :: min_fptr(:) - integer(c_long),pointer :: loc_fptr(:) - integer :: min_size - call atlas__NodesFunctionSpace__minloc_arr_float(this%c_ptr(),field%c_ptr(),min_cptr,loc_cptr,min_size) - call c_f_pointer(min_cptr,min_fptr,(/min_size/)) - call c_f_pointer(loc_cptr,loc_fptr,(/min_size/)) - allocate(minimum(min_size)) - allocate(location(min_size)) - minimum(:) = min_fptr(:) - location(:) = loc_fptr(:) - call c_ptr_free(min_cptr) - call c_ptr_free(loc_cptr) -end subroutine - -!------------------------------------------------------------------------------ - -subroutine maxloc_real32_r1(this,field,maximum,location) - use atlas_functionspace_NodeColumns_c_binding - use, intrinsic :: iso_c_binding, only : c_float, c_ptr, c_f_pointer, c_long - class(atlas_functionspace_NodeColumns), intent(in) :: this - type(atlas_Field) :: field - real(c_float), allocatable, intent(out) :: maximum(:) - integer(ATLAS_KIND_GIDX), allocatable, intent(out) :: location(:) - type(c_ptr) :: max_cptr, loc_cptr - real(c_float), pointer :: max_fptr(:) - integer(c_long),pointer :: loc_fptr(:) - integer :: max_size - call atlas__NodesFunctionSpace__maxloc_arr_float(this%c_ptr(),field%c_ptr(),max_cptr,loc_cptr,max_size) - call c_f_pointer(max_cptr,max_fptr,(/max_size/)) - call c_f_pointer(loc_cptr,loc_fptr,(/max_size/)) - allocate(maximum(max_size)) - allocate(location(max_size)) - maximum(:) = max_fptr(:) - location(:) = loc_fptr(:) - call c_ptr_free(max_cptr) - call c_ptr_free(loc_cptr) -end subroutine - -!------------------------------------------------------------------------------ - -subroutine sum_real32_r0(this,field,sum,N) - use atlas_functionspace_NodeColumns_c_binding - use, intrinsic :: iso_c_binding, only : c_float, c_int - class(atlas_functionspace_NodeColumns), intent(in) :: this - type(atlas_Field) :: field - real(c_float), intent(out) :: sum - integer(c_int), intent(out), optional :: N - integer(c_int) :: opt_N - call atlas__NodesFunctionSpace__sum_float(this%c_ptr(),field%c_ptr(),sum,opt_N) - if( present(N) ) N = opt_N -end subroutine - -!------------------------------------------------------------------------------ - -subroutine sum_real32_r1(this,field,sum,N) - use atlas_functionspace_NodeColumns_c_binding - use, intrinsic :: iso_c_binding, only : c_float, c_int, c_ptr, c_f_pointer - use fckit_c_interop_module, only : c_ptr_free - class(atlas_functionspace_NodeColumns), intent(in) :: this - type(atlas_Field) :: field - real(c_float), allocatable, intent(out) :: sum(:) - integer(c_int), intent(out), optional :: N - type(c_ptr) :: sum_cptr - real(c_float), pointer :: sum_fptr(:) - integer :: sum_size - integer(c_int) :: opt_N - call atlas__NodesFunctionSpace__sum_arr_float(this%c_ptr(),field%c_ptr(),sum_cptr,sum_size,opt_N) - call c_f_pointer(sum_cptr,sum_fptr,(/sum_size/)) - allocate(sum(sum_size)) - sum(:) = sum_fptr(:) - call c_ptr_free(sum_cptr) - if( present(N) ) N = opt_N -end subroutine - -!------------------------------------------------------------------------------ - -subroutine order_independent_sum_real32_r0(this,field,sum,N) - use atlas_functionspace_NodeColumns_c_binding - use, intrinsic :: iso_c_binding, only : c_float, c_int - class(atlas_functionspace_NodeColumns), intent(in) :: this - type(atlas_Field) :: field - real(c_float), intent(out) :: sum - integer(c_int), intent(out), optional :: N - integer(c_int) :: opt_N - call atlas__NodesFunctionSpace__oisum_float(this%c_ptr(),field%c_ptr(),sum,opt_N) - if( present(N) ) N = opt_N -end subroutine - -!------------------------------------------------------------------------------ - -subroutine order_independent_sum_real32_r1(this,field,sum,N) - use atlas_functionspace_NodeColumns_c_binding - use, intrinsic :: iso_c_binding, only : c_float, c_int, c_ptr, c_f_pointer - use fckit_c_interop_module, only : c_ptr_free - class(atlas_functionspace_NodeColumns), intent(in) :: this - type(atlas_Field) :: field - real(c_float), allocatable, intent(out) :: sum(:) - integer(c_int), intent(out), optional :: N - type(c_ptr) :: sum_cptr - real(c_float), pointer :: sum_fptr(:) - integer :: sum_size - integer(c_int) :: opt_N - call atlas__NodesFunctionSpace__oisum_arr_float(this%c_ptr(),field%c_ptr(),sum_cptr,sum_size,opt_N) - call c_f_pointer(sum_cptr,sum_fptr,(/sum_size/)) - allocate(sum(sum_size)) - sum(:) = sum_fptr(:) - call c_ptr_free(sum_cptr) - if( present(N) ) N = opt_N -end subroutine - -!------------------------------------------------------------------------------ - -subroutine mean_real32_r0(this,field,mean,N) - use atlas_functionspace_NodeColumns_c_binding - use, intrinsic :: iso_c_binding - class(atlas_functionspace_NodeColumns), intent(in) :: this - type(atlas_Field) :: field - real(c_float), intent(out) :: mean - integer(c_int), intent(out), optional :: N - integer(c_int) :: opt_N - call atlas__NodesFunctionSpace__mean_float(this%c_ptr(),field%c_ptr(),mean,opt_N) - if( present(N) ) N = opt_N -end subroutine - -!------------------------------------------------------------------------------ - -subroutine mean_real32_r1(this,field,mean,N) - use atlas_functionspace_NodeColumns_c_binding - use, intrinsic :: iso_c_binding, only : c_float, c_int, c_ptr, c_f_pointer - use fckit_c_interop_module, only : c_ptr_free - class(atlas_functionspace_NodeColumns), intent(in) :: this - type(atlas_Field) :: field - real(c_float), allocatable, intent(out) :: mean(:) - integer(c_int), intent(out), optional :: N - type(c_ptr) :: mean_cptr - real(c_float), pointer :: mean_fptr(:) - integer :: mean_size - integer(c_int) :: opt_N - call atlas__NodesFunctionSpace__mean_arr_float(this%c_ptr(),field%c_ptr(),mean_cptr,mean_size,opt_N) - call c_f_pointer(mean_cptr,mean_fptr,(/mean_size/)) - allocate(mean(mean_size)) - mean(:) = mean_fptr(:) - call c_ptr_free(mean_cptr) - if( present(N) ) N = opt_N -end subroutine - -!------------------------------------------------------------------------------ - -subroutine mean_and_stddev_real32_r0(this,field,mean,stddev,N) - use atlas_functionspace_NodeColumns_c_binding - use, intrinsic :: iso_c_binding, only : c_float, c_int - class(atlas_functionspace_NodeColumns), intent(in) :: this - type(atlas_Field) :: field - real(c_float), intent(out) :: mean - real(c_float), intent(out) :: stddev - integer(c_int), intent(out), optional :: N - integer(c_int) :: opt_N - call atlas__NodesFunctionSpace__mean_and_stddev_float(this%c_ptr(),field%c_ptr(),mean,stddev,opt_N) - if( present(N) ) N = opt_N -end subroutine - -!------------------------------------------------------------------------------ - -subroutine mean_and_stddev_real32_r1(this,field,mean,stddev,N) - use atlas_functionspace_NodeColumns_c_binding - use, intrinsic :: iso_c_binding, only : c_float, c_int ,c_ptr, c_f_pointer - use fckit_c_interop_module, only : c_ptr_free - class(atlas_functionspace_NodeColumns), intent(in) :: this - type(atlas_Field) :: field - real(c_float), allocatable, intent(out) :: mean(:) - real(c_float), allocatable, intent(out) :: stddev(:) - integer(c_int), intent(out), optional :: N - type(c_ptr) :: mean_cptr, stddev_cptr - real(c_float), pointer :: mean_fptr(:), stddev_fptr(:) - integer :: varsize - integer(c_int) :: opt_N - call atlas__NodesFunctionSpace__mean_and_stddev_arr_float(this%c_ptr(),field%c_ptr(),mean_cptr,stddev_cptr,varsize,opt_N) - call c_f_pointer(mean_cptr,mean_fptr,(/varsize/)) - call c_f_pointer(stddev_cptr,stddev_fptr,(/varsize/)) - allocate(mean(varsize)) - allocate(stddev(varsize)) - mean(:) = mean_fptr(:) - stddev(:) = stddev_fptr(:) - call c_ptr_free(mean_cptr) - call c_ptr_free(stddev_cptr) - if( present(N) ) N = opt_N -end subroutine - -!------------------------------------------------------------------------------ - -subroutine minimum_real64_r0(this,field,minimum) - use atlas_functionspace_NodeColumns_c_binding - use, intrinsic :: iso_c_binding, only : c_double - class(atlas_functionspace_NodeColumns), intent(in) :: this - type(atlas_Field) :: field - real(c_double), intent(out) :: minimum - call atlas__NodesFunctionSpace__min_double(this%c_ptr(),field%c_ptr(),minimum) -end subroutine - -!------------------------------------------------------------------------------ - -subroutine minimum_real64_r1(this,field,minimum) - use atlas_functionspace_NodeColumns_c_binding - use, intrinsic :: iso_c_binding, only : c_double, c_ptr, c_f_pointer - use fckit_c_interop_module, only : c_ptr_free - class(atlas_functionspace_NodeColumns), intent(in) :: this - type(atlas_Field) :: field - real(c_double), allocatable, intent(out) :: minimum(:) - type(c_ptr) :: min_cptr - real(c_double), pointer :: min_fptr(:) - integer :: min_size - call atlas__NodesFunctionSpace__min_arr_double(this%c_ptr(),field%c_ptr(),min_cptr,min_size) - call c_f_pointer(min_cptr,min_fptr,(/min_size/)) - allocate(minimum(min_size)) - minimum(:) = min_fptr(:) - call c_ptr_free(min_cptr) -end subroutine - -!------------------------------------------------------------------------------ - -subroutine maximum_real64_r0(this,field,maximum) - use atlas_functionspace_NodeColumns_c_binding - use, intrinsic :: iso_c_binding, only : c_double - class(atlas_functionspace_NodeColumns), intent(in) :: this - type(atlas_Field) :: field - real(c_double), intent(out) :: maximum - call atlas__NodesFunctionSpace__max_double(this%c_ptr(),field%c_ptr(),maximum) -end subroutine - -!------------------------------------------------------------------------------ - -subroutine maximum_real64_r1(this,field,maximum) - use atlas_functionspace_NodeColumns_c_binding - use, intrinsic :: iso_c_binding, only : c_double, c_ptr, c_double, c_f_pointer - class(atlas_functionspace_NodeColumns), intent(in) :: this - type(atlas_Field) :: field - real(c_double), allocatable, intent(out) :: maximum(:) - type(c_ptr) :: max_cptr - real(c_double), pointer :: max_fptr(:) - integer :: max_size - call atlas__NodesFunctionSpace__max_arr_double(this%c_ptr(),field%c_ptr(),max_cptr,max_size) - call c_f_pointer(max_cptr,max_fptr,(/max_size/)) - allocate(maximum(max_size)) - maximum(:) = max_fptr(:) - call c_ptr_free(max_cptr) -end subroutine - -!------------------------------------------------------------------------------ - -subroutine minloc_real64_r0(this,field,minimum,location) - use atlas_functionspace_NodeColumns_c_binding - use, intrinsic :: iso_c_binding, only : c_double, c_long - class(atlas_functionspace_NodeColumns), intent(in) :: this - type(atlas_Field) :: field - real(c_double), intent(out) :: minimum - integer(ATLAS_KIND_GIDX), intent(out) :: location - integer(c_long) :: loc - call atlas__NodesFunctionSpace__minloc_double(this%c_ptr(),field%c_ptr(),minimum,loc) - location = loc -end subroutine - -!------------------------------------------------------------------------------ - -subroutine maxloc_real64_r0(this,field,maximum,location) - use atlas_functionspace_NodeColumns_c_binding - use, intrinsic :: iso_c_binding, only : c_double, c_long - class(atlas_functionspace_NodeColumns), intent(in) :: this - type(atlas_Field) :: field - real(c_double), intent(out) :: maximum - integer(ATLAS_KIND_GIDX), intent(out) :: location - integer(c_long) :: loc - call atlas__NodesFunctionSpace__maxloc_double(this%c_ptr(),field%c_ptr(),maximum,loc) - location = loc -end subroutine - -!------------------------------------------------------------------------------ - -subroutine minloc_real64_r1(this,field,minimum,location) - use atlas_functionspace_NodeColumns_c_binding - use, intrinsic :: iso_c_binding, only : c_double, c_long, c_ptr, c_f_pointer - class(atlas_functionspace_NodeColumns), intent(in) :: this - type(atlas_Field) :: field - real(c_double), allocatable, intent(out) :: minimum(:) - integer(ATLAS_KIND_GIDX), allocatable, intent(out) :: location(:) - type(c_ptr) :: min_cptr, loc_cptr - real(c_double), pointer :: min_fptr(:) - integer(c_long),pointer :: loc_fptr(:) - integer :: min_size - call atlas__NodesFunctionSpace__minloc_arr_double(this%c_ptr(),field%c_ptr(),min_cptr,loc_cptr,min_size) - call c_f_pointer(min_cptr,min_fptr,(/min_size/)) - call c_f_pointer(loc_cptr,loc_fptr,(/min_size/)) - allocate(minimum(min_size)) - allocate(location(min_size)) - minimum(:) = min_fptr(:) - location(:) = loc_fptr(:) - call c_ptr_free(min_cptr) - call c_ptr_free(loc_cptr) -end subroutine - -!------------------------------------------------------------------------------ - -subroutine maxloc_real64_r1(this,field,maximum,location) - use atlas_functionspace_NodeColumns_c_binding - use, intrinsic :: iso_c_binding, only : c_double, c_ptr, c_f_pointer, c_long - class(atlas_functionspace_NodeColumns), intent(in) :: this - type(atlas_Field) :: field - real(c_double), allocatable, intent(out) :: maximum(:) - integer(ATLAS_KIND_GIDX), allocatable, intent(out) :: location(:) - type(c_ptr) :: max_cptr, loc_cptr - real(c_double), pointer :: max_fptr(:) - integer(c_long),pointer :: loc_fptr(:) - integer :: max_size - call atlas__NodesFunctionSpace__maxloc_arr_double(this%c_ptr(),field%c_ptr(),max_cptr,loc_cptr,max_size) - call c_f_pointer(max_cptr,max_fptr,(/max_size/)) - call c_f_pointer(loc_cptr,loc_fptr,(/max_size/)) - allocate(maximum(max_size)) - allocate(location(max_size)) - maximum(:) = max_fptr(:) - location(:) = loc_fptr(:) - call c_ptr_free(max_cptr) - call c_ptr_free(loc_cptr) -end subroutine - -!------------------------------------------------------------------------------ - -subroutine sum_real64_r0(this,field,sum,N) - use atlas_functionspace_NodeColumns_c_binding - use, intrinsic :: iso_c_binding, only : c_double, c_int - class(atlas_functionspace_NodeColumns), intent(in) :: this - type(atlas_Field) :: field - real(c_double), intent(out) :: sum - integer(c_int), intent(out), optional :: N - integer(c_int) :: opt_N - call atlas__NodesFunctionSpace__sum_double(this%c_ptr(),field%c_ptr(),sum,opt_N) - if( present(N) ) N = opt_N -end subroutine - -!------------------------------------------------------------------------------ - -subroutine sum_real64_r1(this,field,sum,N) - use atlas_functionspace_NodeColumns_c_binding - use, intrinsic :: iso_c_binding, only : c_double, c_int, c_ptr, c_f_pointer - class(atlas_functionspace_NodeColumns), intent(in) :: this - type(atlas_Field) :: field - real(c_double), allocatable, intent(out) :: sum(:) - integer(c_int), intent(out), optional :: N - type(c_ptr) :: sum_cptr - real(c_double), pointer :: sum_fptr(:) - integer :: sum_size - integer(c_int) :: opt_N - call atlas__NodesFunctionSpace__sum_arr_double(this%c_ptr(),field%c_ptr(),sum_cptr,sum_size,opt_N) - call c_f_pointer(sum_cptr,sum_fptr,(/sum_size/)) - allocate(sum(sum_size)) - sum(:) = sum_fptr(:) - call c_ptr_free(sum_cptr) - if( present(N) ) N = opt_N -end subroutine - -!------------------------------------------------------------------------------ - -subroutine order_independent_sum_real64_r0(this,field,sum,N) - use atlas_functionspace_NodeColumns_c_binding - use, intrinsic :: iso_c_binding - class(atlas_functionspace_NodeColumns), intent(in) :: this - type(atlas_Field) :: field - real(c_double), intent(out) :: sum - integer(c_int), intent(out), optional :: N - integer(c_int) :: opt_N - call atlas__NodesFunctionSpace__oisum_double(this%c_ptr(),field%c_ptr(),sum,opt_N) - if( present(N) ) N = opt_N -end subroutine - -!------------------------------------------------------------------------------ - -subroutine order_independent_sum_real64_r1(this,field,sum,N) - use atlas_functionspace_NodeColumns_c_binding - use, intrinsic :: iso_c_binding, only : c_double, c_int, c_ptr, c_f_pointer - class(atlas_functionspace_NodeColumns), intent(in) :: this - type(atlas_Field) :: field - real(c_double), allocatable, intent(out) :: sum(:) - integer(c_int), intent(out), optional :: N - type(c_ptr) :: sum_cptr - real(c_double), pointer :: sum_fptr(:) - integer :: sum_size - integer(c_int) :: opt_N - call atlas__NodesFunctionSpace__oisum_arr_double(this%c_ptr(),field%c_ptr(),sum_cptr,sum_size,opt_N) - call c_f_pointer(sum_cptr,sum_fptr,(/sum_size/)) - allocate(sum(sum_size)) - sum(:) = sum_fptr(:) - call c_ptr_free(sum_cptr) - if( present(N) ) N = opt_N -end subroutine - -!------------------------------------------------------------------------------ - -subroutine mean_real64_r0(this,field,mean,N) - use atlas_functionspace_NodeColumns_c_binding - use, intrinsic :: iso_c_binding - class(atlas_functionspace_NodeColumns), intent(in) :: this - type(atlas_Field) :: field - real(c_double), intent(out) :: mean - integer(c_int), intent(out), optional :: N - integer(c_int) :: opt_N - call atlas__NodesFunctionSpace__mean_double(this%c_ptr(),field%c_ptr(),mean,opt_N) - if( present(N) ) N = opt_N -end subroutine - -!------------------------------------------------------------------------------ - -subroutine mean_real64_r1(this,field,mean,N) - use atlas_functionspace_NodeColumns_c_binding - use, intrinsic :: iso_c_binding, only : c_double, c_int, c_ptr, c_f_pointer - class(atlas_functionspace_NodeColumns), intent(in) :: this - type(atlas_Field) :: field - real(c_double), allocatable, intent(out) :: mean(:) - integer(c_int), intent(out), optional :: N - type(c_ptr) :: mean_cptr - real(c_double), pointer :: mean_fptr(:) - integer :: mean_size - integer(c_int) :: opt_N - call atlas__NodesFunctionSpace__mean_arr_double(this%c_ptr(),field%c_ptr(),mean_cptr,mean_size,opt_N) - call c_f_pointer(mean_cptr,mean_fptr,(/mean_size/)) - allocate(mean(mean_size)) - mean(:) = mean_fptr(:) - call c_ptr_free(mean_cptr) - if( present(N) ) N = opt_N -end subroutine - -!------------------------------------------------------------------------------ - -subroutine mean_and_stddev_real64_r0(this,field,mean,stddev,N) - use atlas_functionspace_NodeColumns_c_binding - use, intrinsic :: iso_c_binding - class(atlas_functionspace_NodeColumns), intent(in) :: this - type(atlas_Field) :: field - real(c_double), intent(out) :: mean - real(c_double), intent(out) :: stddev - integer(c_int), intent(out), optional :: N - integer(c_int) :: opt_N - call atlas__NodesFunctionSpace__mean_and_stddev_double(this%c_ptr(),field%c_ptr(),mean,stddev,opt_N) - if( present(N) ) N = opt_N -end subroutine - -!------------------------------------------------------------------------------ - -subroutine mean_and_stddev_real64_r1(this,field,mean,stddev,N) - use atlas_functionspace_NodeColumns_c_binding - use, intrinsic :: iso_c_binding, only : c_double, c_int, c_ptr, c_f_pointer - class(atlas_functionspace_NodeColumns), intent(in) :: this - type(atlas_Field) :: field - real(c_double), allocatable, intent(out) :: mean(:) - real(c_double), allocatable, intent(out) :: stddev(:) - integer(c_int), intent(out), optional :: N - type(c_ptr) :: mean_cptr, stddev_cptr - real(c_double), pointer :: mean_fptr(:), stddev_fptr(:) - integer :: varsize - integer(c_int) :: opt_N - call atlas__NodesFunctionSpace__mean_and_stddev_arr_double(this%c_ptr(),field%c_ptr(),mean_cptr,stddev_cptr,varsize,opt_N) - call c_f_pointer(mean_cptr,mean_fptr,(/varsize/)) - call c_f_pointer(stddev_cptr,stddev_fptr,(/varsize/)) - allocate(mean(varsize)) - allocate(stddev(varsize)) - mean(:) = mean_fptr(:) - stddev(:) = stddev_fptr(:) - call c_ptr_free(mean_cptr) - call c_ptr_free(stddev_cptr) - if( present(N) ) N = opt_N -end subroutine - -!------------------------------------------------------------------------------ - -subroutine minimum_int64_r0(this,field,minimum) - use atlas_functionspace_NodeColumns_c_binding - use, intrinsic :: iso_c_binding, only : c_long - class(atlas_functionspace_NodeColumns), intent(in) :: this - type(atlas_Field) :: field - integer(c_long), intent(out) :: minimum - call atlas__NodesFunctionSpace__min_long(this%c_ptr(),field%c_ptr(),minimum) -end subroutine - -!------------------------------------------------------------------------------ - -subroutine minimum_int64_r1(this,field,minimum) - use atlas_functionspace_NodeColumns_c_binding - use, intrinsic :: iso_c_binding, only : c_long, c_int, c_ptr, c_f_pointer - class(atlas_functionspace_NodeColumns), intent(in) :: this - type(atlas_Field) :: field - integer(c_long), allocatable, intent(out) :: minimum(:) - type(c_ptr) :: min_cptr - integer(c_long), pointer :: min_fptr(:) - integer :: min_size - call atlas__NodesFunctionSpace__min_arr_long(this%c_ptr(),field%c_ptr(),min_cptr,min_size) - call c_f_pointer(min_cptr,min_fptr,(/min_size/)) - allocate(minimum(min_size)) - minimum(:) = min_fptr(:) - call c_ptr_free(min_cptr) -end subroutine - -!------------------------------------------------------------------------------ - -subroutine maximum_int64_r0(this,field,maximum) - use atlas_functionspace_NodeColumns_c_binding - use, intrinsic :: iso_c_binding - class(atlas_functionspace_NodeColumns), intent(in) :: this - type(atlas_Field) :: field - integer(c_long), intent(out) :: maximum - call atlas__NodesFunctionSpace__max_long(this%c_ptr(),field%c_ptr(),maximum) -end subroutine - -!------------------------------------------------------------------------------ - -subroutine maximum_int64_r1(this,field,maximum) - use atlas_functionspace_NodeColumns_c_binding - use, intrinsic :: iso_c_binding, only : c_long, c_ptr, c_f_pointer - class(atlas_functionspace_NodeColumns), intent(in) :: this - type(atlas_Field) :: field - integer(c_long), allocatable, intent(out) :: maximum(:) - type(c_ptr) :: max_cptr - integer(c_long), pointer :: max_fptr(:) - integer :: max_size - call atlas__NodesFunctionSpace__max_arr_long(this%c_ptr(),field%c_ptr(),max_cptr,max_size) - call c_f_pointer(max_cptr,max_fptr,(/max_size/)) - allocate(maximum(max_size)) - maximum(:) = max_fptr(:) - call c_ptr_free(max_cptr) -end subroutine - -!------------------------------------------------------------------------------ - -subroutine minloc_int64_r0(this,field,minimum,location) - use atlas_functionspace_NodeColumns_c_binding - use, intrinsic :: iso_c_binding, only : c_long - class(atlas_functionspace_NodeColumns), intent(in) :: this - type(atlas_Field) :: field - integer(c_long), intent(out) :: minimum - integer(ATLAS_KIND_GIDX), intent(out) :: location - integer(c_long) :: loc - call atlas__NodesFunctionSpace__minloc_long(this%c_ptr(),field%c_ptr(),minimum,loc) - location = loc -end subroutine - -!------------------------------------------------------------------------------ - -subroutine maxloc_int64_r0(this,field,maximum,location) - use atlas_functionspace_NodeColumns_c_binding - use, intrinsic :: iso_c_binding - class(atlas_functionspace_NodeColumns), intent(in) :: this - type(atlas_Field) :: field - integer(c_long), intent(out) :: maximum - integer(ATLAS_KIND_GIDX), intent(out) :: location - integer(c_long) :: loc - call atlas__NodesFunctionSpace__maxloc_long(this%c_ptr(),field%c_ptr(),maximum,loc) - location = loc -end subroutine - -!------------------------------------------------------------------------------ - -subroutine minloc_int64_r1(this,field,minimum,location) - use atlas_functionspace_NodeColumns_c_binding - use, intrinsic :: iso_c_binding, only : c_f_pointer, c_long, c_ptr - class(atlas_functionspace_NodeColumns), intent(in) :: this - type(atlas_Field) :: field - integer(c_long), allocatable, intent(out) :: minimum(:) - integer(ATLAS_KIND_GIDX), allocatable, intent(out) :: location(:) - type(c_ptr) :: min_cptr, loc_cptr - integer(c_long), pointer :: min_fptr(:) - integer(c_long),pointer :: loc_fptr(:) - integer :: min_size - call atlas__NodesFunctionSpace__minloc_arr_long(this%c_ptr(),field%c_ptr(),min_cptr,loc_cptr,min_size) - call c_f_pointer(min_cptr,min_fptr,(/min_size/)) - call c_f_pointer(loc_cptr,loc_fptr,(/min_size/)) - allocate(minimum(min_size)) - allocate(location(min_size)) - minimum(:) = min_fptr(:) - location(:) = loc_fptr(:) - call c_ptr_free(min_cptr) - call c_ptr_free(loc_cptr) -end subroutine - -!------------------------------------------------------------------------------ - -subroutine maxloc_int64_r1(this,field,maximum,location) - use atlas_functionspace_NodeColumns_c_binding - use, intrinsic :: iso_c_binding, only : c_long, c_ptr, c_f_pointer - class(atlas_functionspace_NodeColumns), intent(in) :: this - type(atlas_Field) :: field - integer(c_long), allocatable, intent(out) :: maximum(:) - integer(ATLAS_KIND_GIDX), allocatable, intent(out) :: location(:) - type(c_ptr) :: max_cptr, loc_cptr - integer(c_long), pointer :: max_fptr(:) - integer(c_long),pointer :: loc_fptr(:) - integer :: max_size - call atlas__NodesFunctionSpace__maxloc_arr_long(this%c_ptr(),field%c_ptr(),max_cptr,loc_cptr,max_size) - call c_f_pointer(max_cptr,max_fptr,(/max_size/)) - call c_f_pointer(loc_cptr,loc_fptr,(/max_size/)) - allocate(maximum(max_size)) - allocate(location(max_size)) - maximum(:) = max_fptr(:) - location(:) = loc_fptr(:) - call c_ptr_free(max_cptr) - call c_ptr_free(loc_cptr) -end subroutine - -!------------------------------------------------------------------------------ - -subroutine sum_int64_r0(this,field,sum,N) - use atlas_functionspace_NodeColumns_c_binding - use, intrinsic :: iso_c_binding, only : c_long, c_int - class(atlas_functionspace_NodeColumns), intent(in) :: this - type(atlas_Field) :: field - integer(c_long), intent(out) :: sum - integer(c_int), intent(out), optional :: N - integer(c_int) :: opt_N - call atlas__NodesFunctionSpace__sum_long(this%c_ptr(),field%c_ptr(),sum,opt_N) - if( present(N) ) N = opt_N -end subroutine - -!------------------------------------------------------------------------------ - -subroutine sum_int64_r1(this,field,sum,N) - use atlas_functionspace_NodeColumns_c_binding - use, intrinsic :: iso_c_binding, only : c_long, c_int, c_ptr, c_f_pointer - class(atlas_functionspace_NodeColumns), intent(in) :: this - type(atlas_Field) :: field - integer(c_long), allocatable, intent(out) :: sum(:) - integer(c_int), intent(out), optional :: N - type(c_ptr) :: sum_cptr - integer(c_long), pointer :: sum_fptr(:) - integer :: sum_size - integer(c_int) :: opt_N - call atlas__NodesFunctionSpace__sum_arr_long(this%c_ptr(),field%c_ptr(),sum_cptr,sum_size,opt_N) - call c_f_pointer(sum_cptr,sum_fptr,(/sum_size/)) - allocate(sum(sum_size)) - sum(:) = sum_fptr(:) - call c_ptr_free(sum_cptr) - if( present(N) ) N = opt_N -end subroutine - -!------------------------------------------------------------------------------ - -subroutine mean_int64_r0(this,field,mean,N) - use atlas_functionspace_NodeColumns_c_binding - use, intrinsic :: iso_c_binding - class(atlas_functionspace_NodeColumns), intent(in) :: this - type(atlas_Field) :: field - integer(c_long), intent(out) :: mean - integer(c_int), intent(out), optional :: N - integer(c_int) :: opt_N - call atlas__NodesFunctionSpace__mean_long(this%c_ptr(),field%c_ptr(),mean,opt_N) - if( present(N) ) N = opt_N -end subroutine - -!------------------------------------------------------------------------------ - -subroutine mean_int64_r1(this,field,mean,N) - use atlas_functionspace_NodeColumns_c_binding - use, intrinsic :: iso_c_binding, only : c_long, c_int, c_ptr, c_f_pointer - class(atlas_functionspace_NodeColumns), intent(in) :: this - type(atlas_Field) :: field - integer(c_long), allocatable, intent(out) :: mean(:) - integer(c_int), intent(out), optional :: N - type(c_ptr) :: mean_cptr - integer(c_long), pointer :: mean_fptr(:) - integer :: mean_size - integer(c_int) :: opt_N - call atlas__NodesFunctionSpace__mean_arr_long(this%c_ptr(),field%c_ptr(),mean_cptr,mean_size,opt_N) - call c_f_pointer(mean_cptr,mean_fptr,(/mean_size/)) - allocate(mean(mean_size)) - mean(:) = mean_fptr(:) - call c_ptr_free(mean_cptr) - if( present(N) ) N = opt_N -end subroutine - -!------------------------------------------------------------------------------ - -subroutine mean_and_stddev_int64_r0(this,field,mean,stddev,N) - use atlas_functionspace_NodeColumns_c_binding - use, intrinsic :: iso_c_binding - class(atlas_functionspace_NodeColumns), intent(in) :: this - type(atlas_Field) :: field - integer(c_long), intent(out) :: mean - integer(c_long), intent(out) :: stddev - integer(c_int), intent(out), optional :: N - integer(c_int) :: opt_N - call atlas__NodesFunctionSpace__mean_and_stddev_long(this%c_ptr(),field%c_ptr(),mean,stddev,opt_N) - if( present(N) ) N = opt_N -end subroutine - -!------------------------------------------------------------------------------ - -subroutine mean_and_stddev_int64_r1(this,field,mean,stddev,N) - use atlas_functionspace_NodeColumns_c_binding - use, intrinsic :: iso_c_binding, only : c_long, c_int, c_ptr, c_f_pointer - class(atlas_functionspace_NodeColumns), intent(in) :: this - type(atlas_Field) :: field - integer(c_long), allocatable, intent(out) :: mean(:) - integer(c_long), allocatable, intent(out) :: stddev(:) - integer(c_int), intent(out), optional :: N - type(c_ptr) :: mean_cptr, stddev_cptr - integer(c_long), pointer :: mean_fptr(:), stddev_fptr(:) - integer :: varsize - integer(c_int) :: opt_N - call atlas__NodesFunctionSpace__mean_and_stddev_arr_long(this%c_ptr(),field%c_ptr(),mean_cptr,stddev_cptr,varsize,opt_N) - call c_f_pointer(mean_cptr,mean_fptr,(/varsize/)) - call c_f_pointer(stddev_cptr,stddev_fptr,(/varsize/)) - allocate(mean(varsize)) - allocate(stddev(varsize)) - mean(:) = mean_fptr(:) - stddev(:) = stddev_fptr(:) - call c_ptr_free(mean_cptr) - call c_ptr_free(stddev_cptr) - if( present(N) ) N = opt_N -end subroutine - -!------------------------------------------------------------------------------ - -subroutine minimum_int32_r0(this,field,minimum) - use atlas_functionspace_NodeColumns_c_binding - use, intrinsic :: iso_c_binding - class(atlas_functionspace_NodeColumns), intent(in) :: this - type(atlas_Field) :: field - integer(c_int), intent(out) :: minimum - call atlas__NodesFunctionSpace__min_int(this%c_ptr(),field%c_ptr(),minimum) -end subroutine - -!------------------------------------------------------------------------------ - -subroutine minimum_int32_r1(this,field,minimum) - use atlas_functionspace_NodeColumns_c_binding - use, intrinsic :: iso_c_binding, only : c_f_pointer, c_int, c_ptr - class(atlas_functionspace_NodeColumns), intent(in) :: this - type(atlas_Field) :: field - integer(c_int), allocatable, intent(out) :: minimum(:) - type(c_ptr) :: min_cptr - integer(c_int), pointer :: min_fptr(:) - integer :: min_size - call atlas__NodesFunctionSpace__min_arr_int(this%c_ptr(),field%c_ptr(),min_cptr,min_size) - call c_f_pointer(min_cptr,min_fptr,(/min_size/)) - allocate(minimum(min_size)) - minimum(:) = min_fptr(:) - call c_ptr_free(min_cptr) -end subroutine - -!------------------------------------------------------------------------------ - -subroutine maximum_int32_r0(this,field,maximum) - use atlas_functionspace_NodeColumns_c_binding - use, intrinsic :: iso_c_binding, only : c_int - class(atlas_functionspace_NodeColumns), intent(in) :: this - type(atlas_Field) :: field - integer(c_int), intent(out) :: maximum - call atlas__NodesFunctionSpace__max_int(this%c_ptr(),field%c_ptr(),maximum) -end subroutine - -!------------------------------------------------------------------------------ - -subroutine maximum_int32_r1(this,field,maximum) - use atlas_functionspace_NodeColumns_c_binding - use, intrinsic :: iso_c_binding, only : c_int, c_ptr, c_f_pointer - class(atlas_functionspace_NodeColumns), intent(in) :: this - type(atlas_Field) :: field - integer(c_int), allocatable, intent(out) :: maximum(:) - type(c_ptr) :: max_cptr - integer(c_int), pointer :: max_fptr(:) - integer :: max_size - call atlas__NodesFunctionSpace__max_arr_int(this%c_ptr(),field%c_ptr(),max_cptr,max_size) - call c_f_pointer(max_cptr,max_fptr,(/max_size/)) - allocate(maximum(max_size)) - maximum(:) = max_fptr(:) - call c_ptr_free(max_cptr) -end subroutine - -!------------------------------------------------------------------------------ - -subroutine minloc_int32_r0(this,field,minimum,location) - use atlas_functionspace_NodeColumns_c_binding - use, intrinsic :: iso_c_binding, only : c_int, c_long - class(atlas_functionspace_NodeColumns), intent(in) :: this - type(atlas_Field) :: field - integer(c_int), intent(out) :: minimum - integer(ATLAS_KIND_GIDX), intent(out) :: location - integer(c_long) :: loc - call atlas__NodesFunctionSpace__minloc_int(this%c_ptr(),field%c_ptr(),minimum,loc) - location = loc -end subroutine - -!------------------------------------------------------------------------------ - -subroutine maxloc_int32_r0(this,field,maximum,location) - use atlas_functionspace_NodeColumns_c_binding - use, intrinsic :: iso_c_binding, only : c_int, c_long - class(atlas_functionspace_NodeColumns), intent(in) :: this - type(atlas_Field) :: field - integer(c_int), intent(out) :: maximum - integer(ATLAS_KIND_GIDX), intent(out) :: location - integer(c_long) :: loc - call atlas__NodesFunctionSpace__maxloc_int(this%c_ptr(),field%c_ptr(),maximum,loc) - location = loc -end subroutine - -!------------------------------------------------------------------------------ - -subroutine minloc_int32_r1(this,field,minimum,location) - use atlas_functionspace_NodeColumns_c_binding - use, intrinsic :: iso_c_binding, only : c_int, c_ptr, c_long, c_f_pointer - class(atlas_functionspace_NodeColumns), intent(in) :: this - type(atlas_Field) :: field - integer(c_int), allocatable, intent(out) :: minimum(:) - integer(ATLAS_KIND_GIDX), allocatable, intent(out) :: location(:) - type(c_ptr) :: min_cptr, loc_cptr - integer(c_int), pointer :: min_fptr(:) - integer(c_long),pointer :: loc_fptr(:) - integer :: min_size - call atlas__NodesFunctionSpace__minloc_arr_int(this%c_ptr(),field%c_ptr(),min_cptr,loc_cptr,min_size) - call c_f_pointer(min_cptr,min_fptr,(/min_size/)) - call c_f_pointer(loc_cptr,loc_fptr,(/min_size/)) - allocate(minimum(min_size)) - allocate(location(min_size)) - minimum(:) = min_fptr(:) - location(:) = loc_fptr(:) - call c_ptr_free(min_cptr) - call c_ptr_free(loc_cptr) -end subroutine - -!------------------------------------------------------------------------------ - -subroutine maxloc_int32_r1(this,field,maximum,location) - use atlas_functionspace_NodeColumns_c_binding - use, intrinsic :: iso_c_binding, only : c_int, c_ptr, c_long, c_f_pointer - class(atlas_functionspace_NodeColumns), intent(in) :: this - type(atlas_Field) :: field - integer(c_int), allocatable, intent(out) :: maximum(:) - integer(ATLAS_KIND_GIDX), allocatable, intent(out) :: location(:) - type(c_ptr) :: max_cptr, loc_cptr - integer(c_int), pointer :: max_fptr(:) - integer(c_long),pointer :: loc_fptr(:) - integer :: max_size - call atlas__NodesFunctionSpace__maxloc_arr_int(this%c_ptr(),field%c_ptr(),max_cptr,loc_cptr,max_size) - call c_f_pointer(max_cptr,max_fptr,(/max_size/)) - call c_f_pointer(loc_cptr,loc_fptr,(/max_size/)) - allocate(maximum(max_size)) - allocate(location(max_size)) - maximum(:) = max_fptr(:) - location(:) = loc_fptr(:) - call c_ptr_free(max_cptr) - call c_ptr_free(loc_cptr) -end subroutine - -!------------------------------------------------------------------------------ - -subroutine sum_int32_r0(this,field,sum,N) - use atlas_functionspace_NodeColumns_c_binding - use, intrinsic :: iso_c_binding - class(atlas_functionspace_NodeColumns), intent(in) :: this - type(atlas_Field) :: field - integer(c_int), intent(out) :: sum - integer(c_int), intent(out), optional :: N - integer(c_int) :: opt_N - call atlas__NodesFunctionSpace__sum_int(this%c_ptr(),field%c_ptr(),sum,opt_N) - if( present(N) ) N = opt_N -end subroutine - -!------------------------------------------------------------------------------ - -subroutine sum_int32_r1(this,field,sum,N) - use atlas_functionspace_NodeColumns_c_binding - use, intrinsic :: iso_c_binding, only : c_int, c_ptr, c_f_pointer - class(atlas_functionspace_NodeColumns), intent(in) :: this - type(atlas_Field) :: field - integer(c_int), allocatable, intent(out) :: sum(:) - integer(c_int), intent(out), optional :: N - type(c_ptr) :: sum_cptr - integer(c_int), pointer :: sum_fptr(:) - integer :: sum_size - integer(c_int) :: opt_N - call atlas__NodesFunctionSpace__sum_arr_int(this%c_ptr(),field%c_ptr(),sum_cptr,sum_size,opt_N) - call c_f_pointer(sum_cptr,sum_fptr,(/sum_size/)) - allocate(sum(sum_size)) - sum(:) = sum_fptr(:) - call c_ptr_free(sum_cptr) - if( present(N) ) N = opt_N -end subroutine - -!------------------------------------------------------------------------------ - -subroutine mean_int32_r0(this,field,mean,N) - use atlas_functionspace_NodeColumns_c_binding - use, intrinsic :: iso_c_binding - class(atlas_functionspace_NodeColumns), intent(in) :: this - type(atlas_Field) :: field - integer(c_int), intent(out) :: mean - integer(c_int), intent(out), optional :: N - integer(c_int) :: opt_N - call atlas__NodesFunctionSpace__mean_int(this%c_ptr(),field%c_ptr(),mean,opt_N) - if( present(N) ) N = opt_N -end subroutine - -!------------------------------------------------------------------------------ - -subroutine mean_int32_r1(this,field,mean,N) - use atlas_functionspace_NodeColumns_c_binding - use, intrinsic :: iso_c_binding, only : c_int, c_ptr, c_f_pointer - class(atlas_functionspace_NodeColumns), intent(in) :: this - type(atlas_Field) :: field - integer(c_int), allocatable, intent(out) :: mean(:) - integer(c_int), intent(out), optional :: N - type(c_ptr) :: mean_cptr - integer(c_int), pointer :: mean_fptr(:) - integer :: mean_size - integer(c_int) :: opt_N - call atlas__NodesFunctionSpace__mean_arr_int(this%c_ptr(),field%c_ptr(),mean_cptr,mean_size,opt_N) - call c_f_pointer(mean_cptr,mean_fptr,(/mean_size/)) - allocate(mean(mean_size)) - mean(:) = mean_fptr(:) - call c_ptr_free(mean_cptr) - if( present(N) ) N = opt_N -end subroutine - -!------------------------------------------------------------------------------ - -subroutine mean_and_stddev_int32_r0(this,field,mean,stddev,N) - use atlas_functionspace_NodeColumns_c_binding - use, intrinsic :: iso_c_binding - class(atlas_functionspace_NodeColumns), intent(in) :: this - type(atlas_Field) :: field - integer(c_int), intent(out) :: mean - integer(c_int), intent(out) :: stddev - integer(c_int), intent(out), optional :: N - integer(c_int) :: opt_N - call atlas__NodesFunctionSpace__mean_and_stddev_int(this%c_ptr(),field%c_ptr(),mean,stddev,opt_N) - if( present(N) ) N = opt_N -end subroutine - -!------------------------------------------------------------------------------ - -subroutine mean_and_stddev_int32_r1(this,field,mean,stddev,N) - use atlas_functionspace_NodeColumns_c_binding - use, intrinsic :: iso_c_binding, only : c_int, c_ptr, c_f_pointer - class(atlas_functionspace_NodeColumns), intent(in) :: this - type(atlas_Field) :: field - integer(c_int), allocatable, intent(out) :: mean(:) - integer(c_int), allocatable, intent(out) :: stddev(:) - integer(c_int), intent(out), optional :: N - type(c_ptr) :: mean_cptr, stddev_cptr - integer(c_int), pointer :: mean_fptr(:), stddev_fptr(:) - integer :: varsize - integer(c_int) :: opt_N - call atlas__NodesFunctionSpace__mean_and_stddev_arr_int(this%c_ptr(),field%c_ptr(),mean_cptr,stddev_cptr,varsize,opt_N) - call c_f_pointer(mean_cptr,mean_fptr,(/varsize/)) - call c_f_pointer(stddev_cptr,stddev_fptr,(/varsize/)) - allocate(mean(varsize)) - allocate(stddev(varsize)) - mean(:) = mean_fptr(:) - stddev(:) = stddev_fptr(:) - call c_ptr_free(mean_cptr) - call c_ptr_free(stddev_cptr) - if( present(N) ) N = opt_N -end subroutine - -!------------------------------------------------------------------------------ - -subroutine minloclev_real32_r0(this,field,minimum,location,level) - use atlas_functionspace_NodeColumns_c_binding - use, intrinsic :: iso_c_binding - class(atlas_functionspace_NodeColumns), intent(in) :: this - type(atlas_Field) :: field - real(c_float), intent(out) :: minimum - integer(ATLAS_KIND_GIDX), intent(out) :: location - integer(c_int), intent(out), optional :: level - integer(c_long) :: loc - integer(c_int) :: opt_lev - call atlas__NodesFunctionSpace__minloclev_float(this%c_ptr(),field%c_ptr(),minimum,loc,opt_lev) - location = loc - if( present(level) ) level = opt_lev -end subroutine - -!------------------------------------------------------------------------------ - -subroutine maxloclev_real32_r0(this,field,maximum,location,level) - use atlas_functionspace_NodeColumns_c_binding - use, intrinsic :: iso_c_binding - class(atlas_functionspace_NodeColumns), intent(in) :: this - type(atlas_Field) :: field - real(c_float), intent(out) :: maximum - integer(ATLAS_KIND_GIDX), intent(out) :: location - integer(c_int), intent(out), optional :: level - integer(c_long) :: loc - integer(c_int) :: opt_lev - call atlas__NodesFunctionSpace__maxloclev_float(this%c_ptr(),field%c_ptr(),maximum,loc,opt_lev) - location = loc - if( present(level) ) level = opt_lev -end subroutine - -!------------------------------------------------------------------------------ - -subroutine minloclev_real32_r1(this,field,minimum,location,level) - use atlas_functionspace_NodeColumns_c_binding - use, intrinsic :: iso_c_binding, only : c_int, c_float, c_long, c_ptr, c_f_pointer - class(atlas_functionspace_NodeColumns), intent(in) :: this - type(atlas_Field) :: field - real(c_float), allocatable, intent(out) :: minimum(:) - integer(ATLAS_KIND_GIDX), allocatable, intent(out) :: location(:) - integer(c_int), allocatable, intent(out), optional :: level(:) - type(c_ptr) :: min_cptr, loc_cptr, lev_cptr - real(c_float), pointer :: min_fptr(:) - integer(c_long),pointer :: loc_fptr(:) - integer(c_long),pointer :: lev_fptr(:) - integer :: min_size - call atlas__NodesFunctionSpace__minloclev_arr_float(this%c_ptr(),field%c_ptr(),min_cptr,loc_cptr,lev_cptr,min_size) - call c_f_pointer(min_cptr,min_fptr,(/min_size/)) - call c_f_pointer(loc_cptr,loc_fptr,(/min_size/)) - allocate(minimum(min_size)) - allocate(location(min_size)) - minimum(:) = min_fptr(:) - location(:) = loc_fptr(:) - if( present(level) ) then - call c_f_pointer(lev_cptr,lev_fptr,(/min_size/)) - allocate(level(min_size)) - level(:) = lev_fptr(:) - endif - call c_ptr_free(min_cptr) - call c_ptr_free(loc_cptr) - call c_ptr_free(lev_cptr) -end subroutine - -!------------------------------------------------------------------------------ - -subroutine maxloclev_real32_r1(this,field,maximum,location,level) - use atlas_functionspace_NodeColumns_c_binding - use, intrinsic :: iso_c_binding, only : c_float, c_int, c_long , c_f_pointer, c_ptr - class(atlas_functionspace_NodeColumns), intent(in) :: this - type(atlas_Field) :: field - real(c_float), allocatable, intent(out) :: maximum(:) - integer(ATLAS_KIND_GIDX), allocatable, intent(out) :: location(:) - integer(c_int), allocatable, intent(out), optional :: level(:) - type(c_ptr) :: max_cptr, loc_cptr, lev_cptr - real(c_float), pointer :: max_fptr(:) - integer(c_long),pointer :: loc_fptr(:) - integer(c_long),pointer :: lev_fptr(:) - integer :: max_size - call atlas__NodesFunctionSpace__maxloclev_arr_float(this%c_ptr(),field%c_ptr(),max_cptr,loc_cptr,lev_cptr,max_size) - call c_f_pointer(max_cptr,max_fptr,(/max_size/)) - call c_f_pointer(loc_cptr,loc_fptr,(/max_size/)) - allocate(maximum(max_size)) - allocate(location(max_size)) - maximum(:) = max_fptr(:) - location(:) = loc_fptr(:) - if( present(level) ) then - call c_f_pointer(lev_cptr,lev_fptr,(/max_size/)) - allocate(level(max_size)) - level(:) = lev_fptr(:) - endif - call c_ptr_free(max_cptr) - call c_ptr_free(loc_cptr) - call c_ptr_free(lev_cptr) -end subroutine - -!------------------------------------------------------------------------------ - -subroutine minloclev_real64_r0(this,field,minimum,location,level) - use atlas_functionspace_NodeColumns_c_binding - use, intrinsic :: iso_c_binding, only : c_double, c_int, c_long - class(atlas_functionspace_NodeColumns), intent(in) :: this - type(atlas_Field) :: field - real(c_double), intent(out) :: minimum - integer(ATLAS_KIND_GIDX), intent(out) :: location - integer(c_int), intent(out), optional :: level - integer(c_long) :: loc - integer(c_int) :: opt_lev - call atlas__NodesFunctionSpace__minloclev_double(this%c_ptr(),field%c_ptr(),minimum,loc,opt_lev) - location = loc - if( present(level) ) level = opt_lev -end subroutine - -!------------------------------------------------------------------------------ - -subroutine maxloclev_real64_r0(this,field,maximum,location,level) - use atlas_functionspace_NodeColumns_c_binding - use, intrinsic :: iso_c_binding - class(atlas_functionspace_NodeColumns), intent(in) :: this - type(atlas_Field) :: field - real(c_double), intent(out) :: maximum - integer(ATLAS_KIND_GIDX), intent(out) :: location - integer(c_int), intent(out), optional :: level - integer(c_long) :: loc - integer(c_int) :: opt_lev - call atlas__NodesFunctionSpace__maxloclev_double(this%c_ptr(),field%c_ptr(),maximum,loc,opt_lev) - location = loc - if( present(level) ) level = opt_lev -end subroutine - -!------------------------------------------------------------------------------ - -subroutine minloclev_real64_r1(this,field,minimum,location,level) - use atlas_functionspace_NodeColumns_c_binding - use, intrinsic :: iso_c_binding, only : c_double, c_int, c_ptr, c_long, c_f_pointer - class(atlas_functionspace_NodeColumns), intent(in) :: this - type(atlas_Field) :: field - real(c_double), allocatable, intent(out) :: minimum(:) - integer(ATLAS_KIND_GIDX), allocatable, intent(out) :: location(:) - integer(c_int), allocatable, intent(out), optional :: level(:) - type(c_ptr) :: min_cptr, loc_cptr, lev_cptr - real(c_double), pointer :: min_fptr(:) - integer(c_long),pointer :: loc_fptr(:) - integer(c_long),pointer :: lev_fptr(:) - integer :: min_size - call atlas__NodesFunctionSpace__minloclev_arr_double(this%c_ptr(),field%c_ptr(),min_cptr,loc_cptr,lev_cptr,min_size) - call c_f_pointer(min_cptr,min_fptr,(/min_size/)) - call c_f_pointer(loc_cptr,loc_fptr,(/min_size/)) - allocate(minimum(min_size)) - allocate(location(min_size)) - minimum(:) = min_fptr(:) - location(:) = loc_fptr(:) - if( present(level) ) then - call c_f_pointer(lev_cptr,lev_fptr,(/min_size/)) - allocate(level(min_size)) - level(:) = lev_fptr(:) - endif - call c_ptr_free(min_cptr) - call c_ptr_free(loc_cptr) - call c_ptr_free(lev_cptr) -end subroutine - -!------------------------------------------------------------------------------ - -subroutine maxloclev_real64_r1(this,field,maximum,location,level) - use atlas_functionspace_NodeColumns_c_binding - use, intrinsic :: iso_c_binding, only : c_double, c_ptr, c_int, c_long, c_f_pointer - class(atlas_functionspace_NodeColumns), intent(in) :: this - type(atlas_Field) :: field - real(c_double), allocatable, intent(out) :: maximum(:) - integer(ATLAS_KIND_GIDX), allocatable, intent(out) :: location(:) - integer(c_int), allocatable, intent(out), optional :: level(:) - type(c_ptr) :: max_cptr, loc_cptr, lev_cptr - real(c_double), pointer :: max_fptr(:) - integer(c_long),pointer :: loc_fptr(:) - integer(c_long),pointer :: lev_fptr(:) - integer :: max_size - call atlas__NodesFunctionSpace__maxloclev_arr_double(this%c_ptr(),field%c_ptr(),max_cptr,loc_cptr,lev_cptr,max_size) - call c_f_pointer(max_cptr,max_fptr,(/max_size/)) - call c_f_pointer(loc_cptr,loc_fptr,(/max_size/)) - allocate(maximum(max_size)) - allocate(location(max_size)) - maximum(:) = max_fptr(:) - location(:) = loc_fptr(:) - if( present(level) ) then - call c_f_pointer(lev_cptr,lev_fptr,(/max_size/)) - allocate(level(max_size)) - level(:) = lev_fptr(:) - endif - call c_ptr_free(loc_cptr) - call c_ptr_free(max_cptr) - call c_ptr_free(loc_cptr) -end subroutine - -!------------------------------------------------------------------------------ - -subroutine minloclev_int64_r0(this,field,minimum,location,level) - use atlas_functionspace_NodeColumns_c_binding - use, intrinsic :: iso_c_binding, only : c_long, c_int - class(atlas_functionspace_NodeColumns), intent(in) :: this - type(atlas_Field) :: field - integer(c_long), intent(out) :: minimum - integer(ATLAS_KIND_GIDX), intent(out) :: location - integer(c_int), intent(out), optional :: level - integer(c_long) :: loc - integer(c_int) :: opt_lev - call atlas__NodesFunctionSpace__minloclev_long(this%c_ptr(),field%c_ptr(),minimum,loc,opt_lev) - location = loc - if( present(level) ) level = opt_lev -end subroutine - -!------------------------------------------------------------------------------ - -subroutine maxloclev_int64_r0(this,field,maximum,location,level) - use atlas_functionspace_NodeColumns_c_binding - use, intrinsic :: iso_c_binding - class(atlas_functionspace_NodeColumns), intent(in) :: this - type(atlas_Field) :: field - integer(c_long), intent(out) :: maximum - integer(ATLAS_KIND_GIDX), intent(out) :: location - integer(c_int), intent(out), optional :: level - integer(c_long) :: loc - integer(c_int) :: opt_lev - call atlas__NodesFunctionSpace__maxloclev_long(this%c_ptr(),field%c_ptr(),maximum,loc,opt_lev) - location = loc - if( present(level) ) level = opt_lev -end subroutine - -!------------------------------------------------------------------------------ - -subroutine minloclev_int64_r1(this,field,minimum,location,level) - use atlas_functionspace_NodeColumns_c_binding - use, intrinsic :: iso_c_binding, only : c_long, c_int, c_ptr, c_long, c_f_pointer - class(atlas_functionspace_NodeColumns), intent(in) :: this - type(atlas_Field) :: field - integer(c_long), allocatable, intent(out) :: minimum(:) - integer(ATLAS_KIND_GIDX), allocatable, intent(out) :: location(:) - integer(c_int), allocatable, intent(out), optional :: level(:) - type(c_ptr) :: min_cptr, loc_cptr, lev_cptr - integer(c_long), pointer :: min_fptr(:) - integer(c_long),pointer :: loc_fptr(:) - integer(c_long),pointer :: lev_fptr(:) - integer :: min_size - call atlas__NodesFunctionSpace__minloclev_arr_long(this%c_ptr(),field%c_ptr(),min_cptr,loc_cptr,lev_cptr,min_size) - call c_f_pointer(min_cptr,min_fptr,(/min_size/)) - call c_f_pointer(loc_cptr,loc_fptr,(/min_size/)) - allocate(minimum(min_size)) - allocate(location(min_size)) - minimum(:) = min_fptr(:) - location(:) = loc_fptr(:) - if( present(level) ) then - call c_f_pointer(lev_cptr,lev_fptr,(/min_size/)) - allocate(level(min_size)) - level(:) = lev_fptr(:) - endif - call c_ptr_free(min_cptr) - call c_ptr_free(loc_cptr) - call c_ptr_free(lev_cptr) -end subroutine - -!------------------------------------------------------------------------------ - -subroutine maxloclev_int64_r1(this,field,maximum,location,level) - use atlas_functionspace_NodeColumns_c_binding - use, intrinsic :: iso_c_binding, only : c_long, c_int, c_ptr, c_f_pointer - class(atlas_functionspace_NodeColumns), intent(in) :: this - type(atlas_Field) :: field - integer(c_long), allocatable, intent(out) :: maximum(:) - integer(ATLAS_KIND_GIDX), allocatable, intent(out) :: location(:) - integer(c_int), allocatable, intent(out), optional :: level(:) - type(c_ptr) :: max_cptr, loc_cptr, lev_cptr - integer(c_long), pointer :: max_fptr(:) - integer(c_long),pointer :: loc_fptr(:) - integer(c_long),pointer :: lev_fptr(:) - integer :: max_size - call atlas__NodesFunctionSpace__maxloclev_arr_long(this%c_ptr(),field%c_ptr(),max_cptr,loc_cptr,lev_cptr,max_size) - call c_f_pointer(max_cptr,max_fptr,(/max_size/)) - call c_f_pointer(loc_cptr,loc_fptr,(/max_size/)) - allocate(maximum(max_size)) - allocate(location(max_size)) - maximum(:) = max_fptr(:) - location(:) = loc_fptr(:) - if( present(level) ) then - call c_f_pointer(lev_cptr,lev_fptr,(/max_size/)) - allocate(level(max_size)) - level(:) = lev_fptr(:) - endif - call c_ptr_free(max_cptr) - call c_ptr_free(loc_cptr) - call c_ptr_free(lev_cptr) -end subroutine - -!------------------------------------------------------------------------------ - -subroutine minloclev_int32_r0(this,field,minimum,location,level) - use atlas_functionspace_NodeColumns_c_binding - use, intrinsic :: iso_c_binding - class(atlas_functionspace_NodeColumns), intent(in) :: this - type(atlas_Field) :: field - integer(c_int), intent(out) :: minimum - integer(ATLAS_KIND_GIDX), intent(out) :: location - integer(c_int), intent(out) :: level - integer(c_long) :: loc - call atlas__NodesFunctionSpace__minloclev_int(this%c_ptr(),field%c_ptr(),minimum,loc,level) - location = loc -end subroutine - -!------------------------------------------------------------------------------ - -subroutine maxloclev_int32_r0(this,field,maximum,location,level) - use atlas_functionspace_NodeColumns_c_binding - use, intrinsic :: iso_c_binding - class(atlas_functionspace_NodeColumns), intent(in) :: this - type(atlas_Field) :: field - integer(c_int), intent(out) :: maximum - integer(ATLAS_KIND_GIDX), intent(out) :: location - integer(c_int), intent(out) :: level - integer(c_long) :: loc - call atlas__NodesFunctionSpace__maxloclev_int(this%c_ptr(),field%c_ptr(),maximum,loc,level) - location = loc -end subroutine - -!------------------------------------------------------------------------------ - -subroutine minloclev_int32_r1(this,field,minimum,location,level) - use atlas_functionspace_NodeColumns_c_binding - use, intrinsic :: iso_c_binding, only : c_int, c_ptr, c_long, c_f_pointer - class(atlas_functionspace_NodeColumns), intent(in) :: this - type(atlas_Field) :: field - integer(c_int), allocatable, intent(out) :: minimum(:) - integer(ATLAS_KIND_GIDX), allocatable, intent(out) :: location(:) - integer(c_int), allocatable, intent(out) :: level(:) - type(c_ptr) :: min_cptr, loc_cptr, lev_cptr - integer(c_int), pointer :: min_fptr(:) - integer(c_long),pointer :: loc_fptr(:) - integer(c_int),pointer :: lev_fptr(:) - integer :: min_size - call atlas__NodesFunctionSpace__minloclev_arr_int(this%c_ptr(),field%c_ptr(),min_cptr,loc_cptr,lev_cptr,min_size) - call c_f_pointer(min_cptr,min_fptr,(/min_size/)) - call c_f_pointer(loc_cptr,loc_fptr,(/min_size/)) - call c_f_pointer(lev_cptr,lev_fptr,(/min_size/)) - allocate(minimum(min_size)) - allocate(location(min_size)) - allocate(level(min_size)) - minimum(:) = min_fptr(:) - location(:) = loc_fptr(:) - level(:) = lev_fptr(:) - call c_ptr_free(min_cptr) - call c_ptr_free(loc_cptr) - call c_ptr_free(lev_cptr) -end subroutine - -!------------------------------------------------------------------------------ - -subroutine maxloclev_int32_r1(this,field,maximum,location,level) - use atlas_functionspace_NodeColumns_c_binding - use, intrinsic :: iso_c_binding, only : c_int, c_ptr, c_long, c_f_pointer - class(atlas_functionspace_NodeColumns), intent(in) :: this - type(atlas_Field) :: field - integer(c_int), allocatable, intent(out) :: maximum(:) - integer(ATLAS_KIND_GIDX), allocatable, intent(out) :: location(:) - integer(c_int), allocatable, intent(out) :: level(:) - type(c_ptr) :: max_cptr, loc_cptr, lev_cptr - integer(c_int), pointer :: max_fptr(:) - integer(c_long),pointer :: loc_fptr(:) - integer(c_int),pointer :: lev_fptr(:) - integer :: max_size - call atlas__NodesFunctionSpace__maxloclev_arr_int(this%c_ptr(),field%c_ptr(),max_cptr,loc_cptr,lev_cptr,max_size) - call c_f_pointer(max_cptr,max_fptr,(/max_size/)) - call c_f_pointer(loc_cptr,loc_fptr,(/max_size/)) - call c_f_pointer(lev_cptr,lev_fptr,(/max_size/)) - allocate(maximum(max_size)) - allocate(location(max_size)) - allocate(level(max_size)) - maximum(:) = max_fptr(:) - location(:) = loc_fptr(:) - level(:) = lev_fptr(:) - call c_ptr_free(max_cptr) - call c_ptr_free(loc_cptr) - call c_ptr_free(lev_cptr) -end subroutine - -!------------------------------------------------------------------------------ - -subroutine minloc_per_level(this,field,minimum,location) - use atlas_functionspace_NodeColumns_c_binding - class(atlas_functionspace_NodeColumns), intent(in) :: this - type(atlas_Field), intent(in) :: field - type(atlas_Field), intent(inout) :: minimum - type(atlas_Field), intent(inout) :: location - call atlas__NodesFunctionSpace__minloc_per_level(this%c_ptr(),field%c_ptr(),minimum%c_ptr(),location%c_ptr()) -end subroutine - -!------------------------------------------------------------------------------ - -subroutine maxloc_per_level(this,field,maximum,location) - use atlas_functionspace_NodeColumns_c_binding - class(atlas_functionspace_NodeColumns), intent(in) :: this - type(atlas_Field), intent(in) :: field - type(atlas_Field), intent(inout) :: maximum - type(atlas_Field), intent(inout) :: location - call atlas__NodesFunctionSpace__maxloc_per_level(this%c_ptr(),field%c_ptr(),maximum%c_ptr(),location%c_ptr()) -end subroutine - -!------------------------------------------------------------------------------ - -subroutine minimum_per_level(this,field,minimum) - use atlas_functionspace_NodeColumns_c_binding - class(atlas_functionspace_NodeColumns), intent(in) :: this - type(atlas_Field), intent(in) :: field - type(atlas_Field), intent(inout) :: minimum - call atlas__NodesFunctionSpace__min_per_level(this%c_ptr(),field%c_ptr(),minimum%c_ptr()) -end subroutine - -!------------------------------------------------------------------------------ - -subroutine maximum_per_level(this,field,maximum) - use atlas_functionspace_NodeColumns_c_binding - class(atlas_functionspace_NodeColumns), intent(in) :: this - type(atlas_Field), intent(in) :: field - type(atlas_Field), intent(inout) :: maximum - call atlas__NodesFunctionSpace__max_per_level(this%c_ptr(),field%c_ptr(),maximum%c_ptr()) -end subroutine - -!------------------------------------------------------------------------------ - -subroutine sum_per_level(this,field,sum,N) - use atlas_functionspace_NodeColumns_c_binding - use, intrinsic :: iso_c_binding, only : c_int - class(atlas_functionspace_NodeColumns), intent(in) :: this - type(atlas_Field), intent(in) :: field - type(atlas_Field), intent(inout) :: sum - integer(c_int), intent(out), optional :: N - integer(c_int) :: opt_N - call atlas__NodesFunctionSpace__sum_per_level(this%c_ptr(),field%c_ptr(),sum%c_ptr(),opt_N) - if( present(N) ) N = opt_N -end subroutine - -!------------------------------------------------------------------------------ - -subroutine order_independent_sum_per_level(this,field,sum,N) - use atlas_functionspace_NodeColumns_c_binding - use, intrinsic :: iso_c_binding, only : c_int - class(atlas_functionspace_NodeColumns), intent(in) :: this - type(atlas_Field), intent(in) :: field - type(atlas_Field), intent(inout) :: sum - integer(c_int), intent(out), optional :: N - integer(c_int) :: opt_N - call atlas__NodesFunctionSpace__oisum_per_level(this%c_ptr(),field%c_ptr(),sum%c_ptr(),opt_N) - if( present(N) ) N = opt_N -end subroutine - -!------------------------------------------------------------------------------ - -subroutine mean_per_level(this,field,mean,N) - use atlas_functionspace_NodeColumns_c_binding - use, intrinsic :: iso_c_binding, only : c_int - class(atlas_functionspace_NodeColumns), intent(in) :: this - type(atlas_Field), intent(in) :: field - type(atlas_Field), intent(inout) :: mean - integer(c_int), intent(out), optional :: N - integer(c_int) :: opt_N - call atlas__NodesFunctionSpace__mean_per_level(this%c_ptr(),field%c_ptr(),mean%c_ptr(),opt_N) - if( present(N) ) N = opt_N -end subroutine - -!------------------------------------------------------------------------------ - -subroutine mean_and_stddev_per_level(this,field,mean,stddev,N) - use atlas_functionspace_NodeColumns_c_binding - use, intrinsic :: iso_c_binding - class(atlas_functionspace_NodeColumns), intent(in) :: this - type(atlas_Field), intent(in) :: field - type(atlas_Field), intent(inout) :: mean - type(atlas_Field), intent(inout) :: stddev - integer(c_int), intent(out), optional :: N - integer(c_int) :: opt_N - call atlas__NodesFunctionSpace__mean_and_stddev_per_level( & - & this%c_ptr(),field%c_ptr(),mean%c_ptr(),stddev%c_ptr(),opt_N) - if( present(N) ) N = opt_N -end subroutine - -!------------------------------------------------------------------------------- - -ATLAS_FINAL subroutine atlas_functionspace_NodeColumns__final_auto(this) - type(atlas_functionspace_NodeColumns), intent(inout) :: this -#if FCKIT_FINAL_DEBUGGING - write(0,*) "atlas_functionspace_NodeColumns__final_auto" -#endif -#if FCKIT_FINAL_NOT_PROPAGATING - call this%final() -#endif - FCKIT_SUPPRESS_UNUSED( this ) -end subroutine - -!------------------------------------------------------------------------------ - -end module atlas_functionspace_NodeColumns_module - diff --git a/src/atlas_f/functionspace/atlas_functionspace_NodeColumns_module.fypp b/src/atlas_f/functionspace/atlas_functionspace_NodeColumns_module.fypp new file mode 100644 index 000000000..ed2a0891f --- /dev/null +++ b/src/atlas_f/functionspace/atlas_functionspace_NodeColumns_module.fypp @@ -0,0 +1,803 @@ +! (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" +#:include "internals/atlas_generics.fypp" + +#:set ranks = [0,1] + +module atlas_functionspace_NodeColumns_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_Nodes_module, only: atlas_mesh_Nodes +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_Nodes +private :: atlas_GatherScatter +private :: atlas_HaloExchange +private :: atlas_Checksum +private :: atlas_Mesh +private :: atlas_Config +private :: ATLAS_KIND_GIDX + +public :: atlas_functionspace_NodeColumns + +private + +!------------------------------------------------------------------------------ +TYPE, extends(atlas_FunctionSpace) :: atlas_functionspace_NodeColumns + +! Purpose : +! ------- +! *atlas_functionspace_NodeColumns* : Interpretes fields defined in nodes + +! Methods : +! ------- + +! Author : +! ------ +! August-2015 Willem Deconinck *ECMWF* + +!------------------------------------------------------------------------------ +contains + + + procedure, public :: nb_nodes + procedure, public :: mesh + procedure, public :: nodes + + 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 + + + procedure, public :: minimum_per_level + + procedure, public :: maximum_per_level + + procedure, public :: minimum_and_location_per_level => & + & minloc_per_level + + procedure, public :: maximum_and_location_per_level => & + & maxloc_per_level + + procedure, public :: sum_per_level + + procedure, public :: order_independent_sum_per_level + + procedure, public :: mean_per_level + + @:generic_public_interface( minimum ) + @:generic_public_interface( maximum ) + @:generic_public_interface_2( minimum_and_location, prefix1=minloc, prefix2=minloclev ) + @:generic_public_interface_2( maximum_and_location, prefix1=maxloc, prefix2=maxloclev ) + @:generic_public_interface( sum ) + @:generic_public_interface( order_independent_sum ) + @:generic_public_interface( mean ) + @:generic_public_interface( mean_and_standard_deviation, prefix=mean_and_stddev ) + + procedure, public :: mean_and_standard_deviation_per_level => & + & mean_and_stddev_per_level + +#if FCKIT_FINAL_NOT_INHERITING + final :: atlas_functionspace_NodeColumns__final_auto +#endif + +END TYPE atlas_functionspace_NodeColumns + +interface atlas_functionspace_NodeColumns + 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_NodeColumns) :: 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_NodeColumns_c_binding + type(atlas_functionspace_NodeColumns) :: 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__NodesFunctionSpace__new(mesh%CPTR_PGIBUG_A,config%CPTR_PGIBUG_B) ) + call config%final() + call this%return() +end function + +!------------------------------------------------------------------------------ + +function nb_nodes(this) + use atlas_functionspace_NodeColumns_c_binding + integer :: nb_nodes + class(atlas_functionspace_NodeColumns), intent(in) :: this + nb_nodes = atlas__NodesFunctionSpace__nb_nodes(this%CPTR_PGIBUG_A) +end function + +!------------------------------------------------------------------------------ + +function mesh(this) + use atlas_functionspace_NodeColumns_c_binding + type(atlas_Mesh) :: mesh + class(atlas_functionspace_NodeColumns), intent(in) :: this + call mesh%reset_c_ptr( atlas__NodesFunctionSpace__mesh(this%CPTR_PGIBUG_A) ) + call mesh%return() +end function + +!------------------------------------------------------------------------------ + +function nodes(this) + use atlas_functionspace_NodeColumns_c_binding + type(atlas_mesh_Nodes) :: nodes + class(atlas_functionspace_NodeColumns), intent(in) :: this + call nodes%reset_c_ptr( atlas__NodesFunctionSpace__nodes(this%CPTR_PGIBUG_A) ) + call nodes%return() +end function + +!------------------------------------------------------------------------------ + +function get_gather(this) result(gather) + use atlas_functionspace_NodeColumns_c_binding + type(atlas_GatherScatter) :: gather + class(atlas_functionspace_NodeColumns), intent(in) :: this + call gather%reset_c_ptr( atlas__NodesFunctioNSpace__get_gather(this%CPTR_PGIBUG_A) ) +end function + +!------------------------------------------------------------------------------ + +function get_scatter(this) result(gather) + use atlas_functionspace_NodeColumns_c_binding + type(atlas_GatherScatter) :: gather + class(atlas_functionspace_NodeColumns), intent(in) :: this + call gather%reset_c_ptr( atlas__NodesFunctioNSpace__get_scatter(this%CPTR_PGIBUG_A) ) +end function + +!------------------------------------------------------------------------------ + +subroutine gather_fieldset(this,local,global) + use atlas_functionspace_NodeColumns_c_binding + class(atlas_functionspace_NodeColumns), intent(in) :: this + type(atlas_FieldSet), intent(in) :: local + type(atlas_FieldSet), intent(inout) :: global + call atlas__NodesFunctionSpace__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_NodeColumns_c_binding + class(atlas_functionspace_NodeColumns), intent(in) :: this + type(atlas_Field), intent(in) :: local + type(atlas_Field), intent(inout) :: global + call atlas__NodesFunctionSpace__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_NodeColumns_c_binding + class(atlas_functionspace_NodeColumns), intent(in) :: this + type(atlas_FieldSet), intent(in) :: global + type(atlas_FieldSet), intent(inout) :: local + call atlas__NodesFunctionSpace__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_NodeColumns_c_binding + class(atlas_functionspace_NodeColumns), intent(in) :: this + type(atlas_Field), intent(in) :: global + type(atlas_Field), intent(inout) :: local + call atlas__NodesFunctionSpace__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_NodeColumns_c_binding + type(atlas_HaloExchange) :: halo_exchange + class(atlas_functionspace_NodeColumns), intent(in) :: this + call halo_exchange%reset_c_ptr( atlas__NodesFunctioNSpace__get_halo_exchange(this%CPTR_PGIBUG_A) ) +end function + +!------------------------------------------------------------------------------ + +function get_checksum(this) result(checksum) + use atlas_functionspace_NodeColumns_c_binding + type(atlas_Checksum) :: checksum + class(atlas_functionspace_NodeColumns), intent(in) :: this + call checksum%reset_c_ptr( atlas__NodesFunctioNSpace__get_checksum(this%CPTR_PGIBUG_A) ) +end function + +!------------------------------------------------------------------------------ + +function checksum_fieldset(this,fieldset) result(checksum) + use atlas_functionspace_NodeColumns_c_binding + use, intrinsic :: iso_c_binding, only : c_ptr + character(len=:), allocatable :: checksum + class(atlas_functionspace_NodeColumns), intent(in) :: this + type(atlas_FieldSet), intent(in) :: fieldset + type(c_ptr) :: checksum_cptr + integer :: checksum_size, checksum_allocated + call atlas__NodesFunctionSpace__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_NodeColumns_c_binding + use, intrinsic :: iso_c_binding, only : c_ptr + character(len=:), allocatable :: checksum + class(atlas_functionspace_NodeColumns), intent(in) :: this + type(atlas_Field), intent(in) :: field + type(c_ptr) :: checksum_cptr + integer :: checksum_size, checksum_allocated + call atlas__NodesFunctionSpace__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 + +!------------------------------------------------------------------------------ + +#:for dtype,ftype,ctype in types[:4] +subroutine minimum_${dtype}$_r0(this,field,minimum) + use atlas_functionspace_NodeColumns_c_binding + use, intrinsic :: iso_c_binding, only : c_${ctype}$ + class(atlas_functionspace_NodeColumns), intent(in) :: this + type(atlas_Field) :: field + ${ftype}$, intent(out) :: minimum + call atlas__NodesFunctionSpace__min_${ctype}$(this%CPTR_PGIBUG_A,field%CPTR_PGIBUG_A,minimum) +end subroutine + +!------------------------------------------------------------------------------ + +subroutine minimum_${dtype}$_r1(this,field,minimum) + use atlas_functionspace_NodeColumns_c_binding + use, intrinsic :: iso_c_binding, only : c_${ctype}$,c_ptr,c_f_pointer + class(atlas_functionspace_NodeColumns), intent(in) :: this + type(atlas_Field) :: field + ${ftype}$, allocatable, intent(out) :: minimum(:) + type(c_ptr) :: min_cptr + ${ftype}$, pointer :: min_fptr(:) + integer :: min_size + call atlas__NodesFunctionSpace__min_arr_${ctype}$(this%CPTR_PGIBUG_A,field%CPTR_PGIBUG_A,min_cptr,min_size) + call c_f_pointer(min_cptr,min_fptr,(/min_size/)) + allocate(minimum(min_size)) + minimum(:) = min_fptr(:) + call c_ptr_free(min_cptr) +end subroutine + +!------------------------------------------------------------------------------ + +subroutine maximum_${dtype}$_r0(this,field,maximum) + use atlas_functionspace_NodeColumns_c_binding + use, intrinsic :: iso_c_binding, only : c_${ctype}$ + class(atlas_functionspace_NodeColumns), intent(in) :: this + type(atlas_Field) :: field + ${ftype}$, intent(out) :: maximum + call atlas__NodesFunctionSpace__max_${ctype}$(this%CPTR_PGIBUG_A,field%CPTR_PGIBUG_A,maximum) +end subroutine + +!------------------------------------------------------------------------------ + +subroutine maximum_${dtype}$_r1(this,field,maximum) + use atlas_functionspace_NodeColumns_c_binding + use, intrinsic :: iso_c_binding, only : c_${ctype}$, c_ptr, c_f_pointer + class(atlas_functionspace_NodeColumns), intent(in) :: this + type(atlas_Field) :: field + ${ftype}$, allocatable, intent(out) :: maximum(:) + type(c_ptr) :: max_cptr + ${ftype}$, pointer :: max_fptr(:) + integer :: max_size + call atlas__NodesFunctionSpace__max_arr_${ctype}$(this%CPTR_PGIBUG_A,field%CPTR_PGIBUG_A,max_cptr,max_size) + call c_f_pointer(max_cptr,max_fptr,(/max_size/)) + allocate(maximum(max_size)) + maximum(:) = max_fptr(:) + call c_ptr_free(max_cptr) +end subroutine + +!------------------------------------------------------------------------------ + +subroutine minloc_${dtype}$_r0(this,field,minimum,location) + use atlas_functionspace_NodeColumns_c_binding + use, intrinsic :: iso_c_binding, only : c_${ctype}$, c_long + class(atlas_functionspace_NodeColumns), intent(in) :: this + type(atlas_Field) :: field + ${ftype}$, intent(out) :: minimum + integer(ATLAS_KIND_GIDX), intent(out) :: location + integer(c_long) :: loc + call atlas__NodesFunctionSpace__minloc_${ctype}$(this%CPTR_PGIBUG_A,field%CPTR_PGIBUG_A,minimum,loc) + location = loc +end subroutine + +!------------------------------------------------------------------------------ + +subroutine maxloc_${dtype}$_r0(this,field,maximum,location) + use atlas_functionspace_NodeColumns_c_binding + use, intrinsic :: iso_c_binding, only : c_${ctype}$, c_long + class(atlas_functionspace_NodeColumns), intent(in) :: this + type(atlas_Field) :: field + ${ftype}$, intent(out) :: maximum + integer(ATLAS_KIND_GIDX), intent(out) :: location + integer(c_long) :: loc + call atlas__NodesFunctionSpace__maxloc_${ctype}$(this%CPTR_PGIBUG_A,field%CPTR_PGIBUG_A,maximum,loc) + location = loc +end subroutine + +!------------------------------------------------------------------------------ + +subroutine minloc_${dtype}$_r1(this,field,minimum,location) + use atlas_functionspace_NodeColumns_c_binding + use, intrinsic :: iso_c_binding, only : c_${ctype}$, c_ptr, c_f_pointer, c_long + class(atlas_functionspace_NodeColumns), intent(in) :: this + type(atlas_Field) :: field + ${ftype}$, allocatable, intent(out) :: minimum(:) + integer(ATLAS_KIND_GIDX), allocatable, intent(out) :: location(:) + type(c_ptr) :: min_cptr, loc_cptr + ${ftype}$, pointer :: min_fptr(:) + integer(c_long),pointer :: loc_fptr(:) + integer :: min_size + call atlas__NodesFunctionSpace__minloc_arr_${ctype}$(this%CPTR_PGIBUG_A,field%CPTR_PGIBUG_A,min_cptr,loc_cptr,min_size) + call c_f_pointer(min_cptr,min_fptr,(/min_size/)) + call c_f_pointer(loc_cptr,loc_fptr,(/min_size/)) + allocate(minimum(min_size)) + allocate(location(min_size)) + minimum(:) = min_fptr(:) + location(:) = loc_fptr(:) + call c_ptr_free(min_cptr) + call c_ptr_free(loc_cptr) +end subroutine + +!------------------------------------------------------------------------------ + +subroutine maxloc_${dtype}$_r1(this,field,maximum,location) + use atlas_functionspace_NodeColumns_c_binding + use, intrinsic :: iso_c_binding, only : c_${ctype}$, c_ptr, c_f_pointer, c_long + class(atlas_functionspace_NodeColumns), intent(in) :: this + type(atlas_Field) :: field + ${ftype}$, allocatable, intent(out) :: maximum(:) + integer(ATLAS_KIND_GIDX), allocatable, intent(out) :: location(:) + type(c_ptr) :: max_cptr, loc_cptr + ${ftype}$, pointer :: max_fptr(:) + integer(c_long),pointer :: loc_fptr(:) + integer :: max_size + call atlas__NodesFunctionSpace__maxloc_arr_${ctype}$(this%CPTR_PGIBUG_A,field%CPTR_PGIBUG_A,max_cptr,loc_cptr,max_size) + call c_f_pointer(max_cptr,max_fptr,(/max_size/)) + call c_f_pointer(loc_cptr,loc_fptr,(/max_size/)) + allocate(maximum(max_size)) + allocate(location(max_size)) + maximum(:) = max_fptr(:) + location(:) = loc_fptr(:) + call c_ptr_free(max_cptr) + call c_ptr_free(loc_cptr) +end subroutine + +!------------------------------------------------------------------------------ + +subroutine sum_${dtype}$_r0(this,field,sum,N) + use atlas_functionspace_NodeColumns_c_binding + use, intrinsic :: iso_c_binding, only : c_${ctype}$, c_int + class(atlas_functionspace_NodeColumns), intent(in) :: this + type(atlas_Field) :: field + ${ftype}$, intent(out) :: sum + integer(c_int), intent(out), optional :: N + integer(c_int) :: opt_N + call atlas__NodesFunctionSpace__sum_${ctype}$(this%CPTR_PGIBUG_A,field%CPTR_PGIBUG_A,sum,opt_N) + if( present(N) ) N = opt_N +end subroutine + +!------------------------------------------------------------------------------ + +subroutine sum_${dtype}$_r1(this,field,sum,N) + use atlas_functionspace_NodeColumns_c_binding + use, intrinsic :: iso_c_binding, only : c_${ctype}$, c_int, c_ptr, c_f_pointer + use fckit_c_interop_module, only : c_ptr_free + class(atlas_functionspace_NodeColumns), intent(in) :: this + type(atlas_Field) :: field + ${ftype}$, allocatable, intent(out) :: sum(:) + integer(c_int), intent(out), optional :: N + type(c_ptr) :: sum_cptr + ${ftype}$, pointer :: sum_fptr(:) + integer :: sum_size + integer(c_int) :: opt_N + call atlas__NodesFunctionSpace__sum_arr_${ctype}$(this%CPTR_PGIBUG_A,field%CPTR_PGIBUG_A,sum_cptr,sum_size,opt_N) + call c_f_pointer(sum_cptr,sum_fptr,(/sum_size/)) + allocate(sum(sum_size)) + sum(:) = sum_fptr(:) + call c_ptr_free(sum_cptr) + if( present(N) ) N = opt_N +end subroutine + +!------------------------------------------------------------------------------ + +subroutine mean_${dtype}$_r0(this,field,mean,N) + use atlas_functionspace_NodeColumns_c_binding + use, intrinsic :: iso_c_binding + class(atlas_functionspace_NodeColumns), intent(in) :: this + type(atlas_Field) :: field + ${ftype}$, intent(out) :: mean + integer(c_int), intent(out), optional :: N + integer(c_int) :: opt_N + call atlas__NodesFunctionSpace__mean_${ctype}$(this%CPTR_PGIBUG_A,field%CPTR_PGIBUG_A,mean,opt_N) + if( present(N) ) N = opt_N +end subroutine + +!------------------------------------------------------------------------------ + +subroutine mean_${dtype}$_r1(this,field,mean,N) + use atlas_functionspace_NodeColumns_c_binding + use, intrinsic :: iso_c_binding, only : c_${ctype}$, c_int, c_ptr, c_f_pointer + use fckit_c_interop_module, only : c_ptr_free + class(atlas_functionspace_NodeColumns), intent(in) :: this + type(atlas_Field) :: field + ${ftype}$, allocatable, intent(out) :: mean(:) + integer(c_int), intent(out), optional :: N + type(c_ptr) :: mean_cptr + ${ftype}$, pointer :: mean_fptr(:) + integer :: mean_size + integer(c_int) :: opt_N + call atlas__NodesFunctionSpace__mean_arr_${ctype}$(this%CPTR_PGIBUG_A,field%CPTR_PGIBUG_A,mean_cptr,mean_size,opt_N) + call c_f_pointer(mean_cptr,mean_fptr,(/mean_size/)) + allocate(mean(mean_size)) + mean(:) = mean_fptr(:) + call c_ptr_free(mean_cptr) + if( present(N) ) N = opt_N +end subroutine + +!------------------------------------------------------------------------------ + +subroutine mean_and_stddev_${dtype}$_r0(this,field,mean,stddev,N) + use atlas_functionspace_NodeColumns_c_binding + use, intrinsic :: iso_c_binding, only : c_${ctype}$, c_int + class(atlas_functionspace_NodeColumns), intent(in) :: this + type(atlas_Field) :: field + ${ftype}$, intent(out) :: mean + ${ftype}$, intent(out) :: stddev + integer(c_int), intent(out), optional :: N + integer(c_int) :: opt_N + call atlas__NodesFunctionSpace__mean_and_stddev_${ctype}$( & + this%CPTR_PGIBUG_A,field%CPTR_PGIBUG_A,mean,stddev,opt_N) + if( present(N) ) N = opt_N +end subroutine + +!------------------------------------------------------------------------------ + +subroutine mean_and_stddev_${dtype}$_r1(this,field,mean,stddev,N) + use atlas_functionspace_NodeColumns_c_binding + use, intrinsic :: iso_c_binding, only : c_${ctype}$, c_int ,c_ptr, c_f_pointer + use fckit_c_interop_module, only : c_ptr_free + class(atlas_functionspace_NodeColumns), intent(in) :: this + type(atlas_Field) :: field + ${ftype}$, allocatable, intent(out) :: mean(:) + ${ftype}$, allocatable, intent(out) :: stddev(:) + integer(c_int), intent(out), optional :: N + type(c_ptr) :: mean_cptr, stddev_cptr + ${ftype}$, pointer :: mean_fptr(:), stddev_fptr(:) + integer :: varsize + integer(c_int) :: opt_N + call atlas__NodesFunctionSpace__mean_and_stddev_arr_${ctype}$( & + this%CPTR_PGIBUG_A,field%CPTR_PGIBUG_A,mean_cptr,stddev_cptr,varsize,opt_N) + call c_f_pointer(mean_cptr,mean_fptr,(/varsize/)) + call c_f_pointer(stddev_cptr,stddev_fptr,(/varsize/)) + allocate(mean(varsize)) + allocate(stddev(varsize)) + mean(:) = mean_fptr(:) + stddev(:) = stddev_fptr(:) + call c_ptr_free(mean_cptr) + call c_ptr_free(stddev_cptr) + if( present(N) ) N = opt_N +end subroutine + +!------------------------------------------------------------------------------ + +subroutine minloclev_${dtype}$_r0(this,field,minimum,location,level) + use atlas_functionspace_NodeColumns_c_binding + use, intrinsic :: iso_c_binding + class(atlas_functionspace_NodeColumns), intent(in) :: this + type(atlas_Field) :: field + ${ftype}$, intent(out) :: minimum + integer(ATLAS_KIND_GIDX), intent(out) :: location + integer(c_int), intent(out) :: level + integer(c_long) :: loc + integer(c_int) :: opt_lev + call atlas__NodesFunctionSpace__minloclev_${ctype}$(this%CPTR_PGIBUG_A,field%CPTR_PGIBUG_A,minimum,loc,opt_lev) + location = loc + level = opt_lev +end subroutine + +!------------------------------------------------------------------------------ + +subroutine maxloclev_${dtype}$_r0(this,field,maximum,location,level) + use atlas_functionspace_NodeColumns_c_binding + use, intrinsic :: iso_c_binding + class(atlas_functionspace_NodeColumns), intent(in) :: this + type(atlas_Field) :: field + ${ftype}$, intent(out) :: maximum + integer(ATLAS_KIND_GIDX), intent(out) :: location + integer(c_int), intent(out) :: level + integer(c_long) :: loc + integer(c_int) :: opt_lev + call atlas__NodesFunctionSpace__maxloclev_${ctype}$(this%CPTR_PGIBUG_A,field%CPTR_PGIBUG_A,maximum,loc,opt_lev) + location = loc + level = opt_lev +end subroutine + +!------------------------------------------------------------------------------ + +subroutine minloclev_${dtype}$_r1(this,field,minimum,location,level) + use atlas_functionspace_NodeColumns_c_binding + use, intrinsic :: iso_c_binding, only : c_int, c_${ctype}$, c_long, c_ptr, c_f_pointer + class(atlas_functionspace_NodeColumns), intent(in) :: this + type(atlas_Field) :: field + ${ftype}$, allocatable, intent(out) :: minimum(:) + integer(ATLAS_KIND_GIDX), allocatable, intent(out) :: location(:) + integer(c_int), allocatable, intent(out) :: level(:) + type(c_ptr) :: min_cptr, loc_cptr, lev_cptr + ${ftype}$, pointer :: min_fptr(:) + integer(c_long),pointer :: loc_fptr(:) + integer(c_long),pointer :: lev_fptr(:) + integer :: min_size + call atlas__NodesFunctionSpace__minloclev_arr_${ctype}$(this%CPTR_PGIBUG_A,field%CPTR_PGIBUG_A,min_cptr,loc_cptr,lev_cptr,min_size) + call c_f_pointer(min_cptr,min_fptr,(/min_size/)) + call c_f_pointer(loc_cptr,loc_fptr,(/min_size/)) + allocate(minimum(min_size)) + allocate(location(min_size)) + minimum(:) = min_fptr(:) + location(:) = loc_fptr(:) + call c_f_pointer(lev_cptr,lev_fptr,(/min_size/)) + allocate(level(min_size)) + level(:) = lev_fptr(:) + call c_ptr_free(min_cptr) + call c_ptr_free(loc_cptr) + call c_ptr_free(lev_cptr) +end subroutine + +!------------------------------------------------------------------------------ + +subroutine maxloclev_${dtype}$_r1(this,field,maximum,location,level) + use atlas_functionspace_NodeColumns_c_binding + use, intrinsic :: iso_c_binding, only : c_${ctype}$, c_int, c_long , c_f_pointer, c_ptr + class(atlas_functionspace_NodeColumns), intent(in) :: this + type(atlas_Field) :: field + ${ftype}$, allocatable, intent(out) :: maximum(:) + integer(ATLAS_KIND_GIDX), allocatable, intent(out) :: location(:) + integer(c_int), allocatable, intent(out) :: level(:) + type(c_ptr) :: max_cptr, loc_cptr, lev_cptr + ${ftype}$, pointer :: max_fptr(:) + integer(c_long),pointer :: loc_fptr(:) + integer(c_long),pointer :: lev_fptr(:) + integer :: max_size + call atlas__NodesFunctionSpace__maxloclev_arr_${ctype}$(this%CPTR_PGIBUG_A,field%CPTR_PGIBUG_A,max_cptr,loc_cptr,lev_cptr,max_size) + call c_f_pointer(max_cptr,max_fptr,(/max_size/)) + call c_f_pointer(loc_cptr,loc_fptr,(/max_size/)) + allocate(maximum(max_size)) + allocate(location(max_size)) + maximum(:) = max_fptr(:) + location(:) = loc_fptr(:) + call c_f_pointer(lev_cptr,lev_fptr,(/max_size/)) + allocate(level(max_size)) + level(:) = lev_fptr(:) + call c_ptr_free(max_cptr) + call c_ptr_free(loc_cptr) + call c_ptr_free(lev_cptr) +end subroutine + +!------------------------------------------------------------------------------ + +subroutine order_independent_sum_${dtype}$_r0(this,field,sum,N) + use atlas_functionspace_NodeColumns_c_binding + use, intrinsic :: iso_c_binding, only : c_${ctype}$, c_int + class(atlas_functionspace_NodeColumns), intent(in) :: this + type(atlas_Field) :: field + ${ftype}$, intent(out) :: sum + integer(c_int), intent(out), optional :: N + integer(c_int) :: opt_N + call atlas__NodesFunctionSpace__oisum_${ctype}$(this%CPTR_PGIBUG_A,field%CPTR_PGIBUG_A,sum,opt_N) + if( present(N) ) N = opt_N +end subroutine + +!------------------------------------------------------------------------------ + +subroutine order_independent_sum_${dtype}$_r1(this,field,sum,N) + use atlas_functionspace_NodeColumns_c_binding + use, intrinsic :: iso_c_binding, only : c_${ctype}$, c_int, c_ptr, c_f_pointer + use fckit_c_interop_module, only : c_ptr_free + class(atlas_functionspace_NodeColumns), intent(in) :: this + type(atlas_Field) :: field + ${ftype}$, allocatable, intent(out) :: sum(:) + integer(c_int), intent(out), optional :: N + type(c_ptr) :: sum_cptr + ${ftype}$, pointer :: sum_fptr(:) + integer :: sum_size + integer(c_int) :: opt_N + call atlas__NodesFunctionSpace__oisum_arr_${ctype}$(this%CPTR_PGIBUG_A,field%CPTR_PGIBUG_A,sum_cptr,sum_size,opt_N) + call c_f_pointer(sum_cptr,sum_fptr,(/sum_size/)) + allocate(sum(sum_size)) + sum(:) = sum_fptr(:) + call c_ptr_free(sum_cptr) + if( present(N) ) N = opt_N +end subroutine + +#:endfor + +!------------------------------------------------------------------------------ + +subroutine minloc_per_level(this,field,minimum,location) + use atlas_functionspace_NodeColumns_c_binding + class(atlas_functionspace_NodeColumns), intent(in) :: this + type(atlas_Field), intent(in) :: field + type(atlas_Field), intent(inout) :: minimum + type(atlas_Field), intent(inout) :: location + call atlas__NodesFunctionSpace__minloc_per_level( & + this%CPTR_PGIBUG_A,field%CPTR_PGIBUG_A,minimum%CPTR_PGIBUG_A,location%CPTR_PGIBUG_A) +end subroutine + +!------------------------------------------------------------------------------ + +subroutine maxloc_per_level(this,field,maximum,location) + use atlas_functionspace_NodeColumns_c_binding + class(atlas_functionspace_NodeColumns), intent(in) :: this + type(atlas_Field), intent(in) :: field + type(atlas_Field), intent(inout) :: maximum + type(atlas_Field), intent(inout) :: location + call atlas__NodesFunctionSpace__maxloc_per_level( & + this%CPTR_PGIBUG_A,field%CPTR_PGIBUG_A,maximum%CPTR_PGIBUG_A,location%CPTR_PGIBUG_A) +end subroutine + +!------------------------------------------------------------------------------ + +subroutine minimum_per_level(this,field,minimum) + use atlas_functionspace_NodeColumns_c_binding + class(atlas_functionspace_NodeColumns), intent(in) :: this + type(atlas_Field), intent(in) :: field + type(atlas_Field), intent(inout) :: minimum + call atlas__NodesFunctionSpace__min_per_level( & + this%CPTR_PGIBUG_A,field%CPTR_PGIBUG_A,minimum%CPTR_PGIBUG_A) +end subroutine + +!------------------------------------------------------------------------------ + +subroutine maximum_per_level(this,field,maximum) + use atlas_functionspace_NodeColumns_c_binding + class(atlas_functionspace_NodeColumns), intent(in) :: this + type(atlas_Field), intent(in) :: field + type(atlas_Field), intent(inout) :: maximum + call atlas__NodesFunctionSpace__max_per_level( & + this%CPTR_PGIBUG_A,field%CPTR_PGIBUG_A,maximum%CPTR_PGIBUG_A) +end subroutine + +!------------------------------------------------------------------------------ + +subroutine sum_per_level(this,field,sum,N) + use atlas_functionspace_NodeColumns_c_binding + use, intrinsic :: iso_c_binding, only : c_int + class(atlas_functionspace_NodeColumns), intent(in) :: this + type(atlas_Field), intent(in) :: field + type(atlas_Field), intent(inout) :: sum + integer(c_int), intent(out), optional :: N + integer(c_int) :: opt_N + call atlas__NodesFunctionSpace__sum_per_level( & + this%CPTR_PGIBUG_A,field%CPTR_PGIBUG_A,sum%CPTR_PGIBUG_A,opt_N) + if( present(N) ) N = opt_N +end subroutine + +!------------------------------------------------------------------------------ + +subroutine order_independent_sum_per_level(this,field,sum,N) + use atlas_functionspace_NodeColumns_c_binding + use, intrinsic :: iso_c_binding, only : c_int + class(atlas_functionspace_NodeColumns), intent(in) :: this + type(atlas_Field), intent(in) :: field + type(atlas_Field), intent(inout) :: sum + integer(c_int), intent(out), optional :: N + integer(c_int) :: opt_N + call atlas__NodesFunctionSpace__oisum_per_level( & + this%CPTR_PGIBUG_A,field%CPTR_PGIBUG_A,sum%CPTR_PGIBUG_A,opt_N) + if( present(N) ) N = opt_N +end subroutine + +!------------------------------------------------------------------------------ + +subroutine mean_per_level(this,field,mean,N) + use atlas_functionspace_NodeColumns_c_binding + use, intrinsic :: iso_c_binding, only : c_int + class(atlas_functionspace_NodeColumns), intent(in) :: this + type(atlas_Field), intent(in) :: field + type(atlas_Field), intent(inout) :: mean + integer(c_int), intent(out), optional :: N + integer(c_int) :: opt_N + call atlas__NodesFunctionSpace__mean_per_level( & + this%CPTR_PGIBUG_A,field%CPTR_PGIBUG_A,mean%CPTR_PGIBUG_A,opt_N) + if( present(N) ) N = opt_N +end subroutine + +!------------------------------------------------------------------------------ + +subroutine mean_and_stddev_per_level(this,field,mean,stddev,N) + use atlas_functionspace_NodeColumns_c_binding + use, intrinsic :: iso_c_binding + class(atlas_functionspace_NodeColumns), intent(in) :: this + type(atlas_Field), intent(in) :: field + type(atlas_Field), intent(inout) :: mean + type(atlas_Field), intent(inout) :: stddev + integer(c_int), intent(out), optional :: N + integer(c_int) :: opt_N + call atlas__NodesFunctionSpace__mean_and_stddev_per_level( & + & this%CPTR_PGIBUG_A,field%CPTR_PGIBUG_A,mean%CPTR_PGIBUG_A,stddev%CPTR_PGIBUG_A,opt_N) + if( present(N) ) N = opt_N +end subroutine + +!------------------------------------------------------------------------------- + +ATLAS_FINAL subroutine atlas_functionspace_NodeColumns__final_auto(this) + type(atlas_functionspace_NodeColumns), intent(inout) :: this +#if FCKIT_FINAL_DEBUGGING + write(0,*) "atlas_functionspace_NodeColumns__final_auto" +#endif +#if FCKIT_FINAL_NOT_PROPAGATING + call this%final() +#endif + FCKIT_SUPPRESS_UNUSED( this ) +end subroutine + +!------------------------------------------------------------------------------ + +end module atlas_functionspace_NodeColumns_module + diff --git a/src/atlas_f/functionspace/atlas_functionspace_Spectral_module.F90 b/src/atlas_f/functionspace/atlas_functionspace_Spectral_module.F90 index 5fd51a827..a32c31426 100644 --- a/src/atlas_f/functionspace/atlas_functionspace_Spectral_module.F90 +++ b/src/atlas_f/functionspace/atlas_functionspace_Spectral_module.F90 @@ -1,3 +1,11 @@ +! (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_Spectral_module @@ -90,7 +98,7 @@ function atlas_functionspace_Spectral__config(truncation,levels) result(this) call options%set("truncation",truncation) if( present(levels) ) call options%set("levels",levels) - call this%reset_c_ptr( atlas__SpectralFunctionSpace__new__config(options%c_ptr()) ) + call this%reset_c_ptr( atlas__SpectralFunctionSpace__new__config(options%CPTR_PGIBUG_B) ) call options%final() call this%return() @@ -107,7 +115,8 @@ function atlas_functionspace_Spectral__trans(trans,levels) result(this) if( present(levels) ) call options%set("levels",levels) - call this%reset_c_ptr( atlas__SpectralFunctionSpace__new__trans(trans%c_ptr(), options%c_ptr() ) ) + call this%reset_c_ptr( atlas__SpectralFunctionSpace__new__trans(trans%CPTR_PGIBUG_A, & + options%CPTR_PGIBUG_B ) ) call options%final() call this%return() @@ -118,7 +127,7 @@ subroutine gather_field(this,local,global) class(atlas_functionspace_Spectral), intent(in) :: this type(atlas_Field), intent(in) :: local type(atlas_Field), intent(inout) :: global - call atlas__SpectralFunctionSpace__gather(this%c_ptr(),local%c_ptr(),global%c_ptr()) + call atlas__SpectralFunctionSpace__gather(this%CPTR_PGIBUG_A,local%CPTR_PGIBUG_A,global%CPTR_PGIBUG_A) end subroutine subroutine scatter_field(this,global,local) @@ -126,7 +135,7 @@ subroutine scatter_field(this,global,local) class(atlas_functionspace_Spectral), intent(in) :: this type(atlas_Field), intent(in) :: global type(atlas_Field), intent(inout) :: local - call atlas__SpectralFunctionSpace__scatter(this%c_ptr(),global%c_ptr(),local%c_ptr()) + call atlas__SpectralFunctionSpace__scatter(this%CPTR_PGIBUG_A,global%CPTR_PGIBUG_A,local%CPTR_PGIBUG_A) end subroutine subroutine gather_fieldset(this,local,global) @@ -134,7 +143,7 @@ subroutine gather_fieldset(this,local,global) class(atlas_functionspace_Spectral), intent(in) :: this type(atlas_FieldSet), intent(in) :: local type(atlas_FieldSet), intent(inout) :: global - call atlas__SpectralFunctionSpace__gather_fieldset(this%c_ptr(),local%c_ptr(),global%c_ptr()) + call atlas__SpectralFunctionSpace__gather_fieldset(this%CPTR_PGIBUG_A,local%CPTR_PGIBUG_A,global%CPTR_PGIBUG_A) end subroutine subroutine scatter_fieldset(this,global,local) @@ -142,7 +151,7 @@ subroutine scatter_fieldset(this,global,local) class(atlas_functionspace_Spectral), intent(in) :: this type(atlas_FieldSet), intent(in) :: global type(atlas_FieldSet), intent(inout) :: local - call atlas__SpectralFunctionSpace__scatter_fieldset(this%c_ptr(),global%c_ptr(),local%c_ptr()) + call atlas__SpectralFunctionSpace__scatter_fieldset(this%CPTR_PGIBUG_A,global%CPTR_PGIBUG_A,local%CPTR_PGIBUG_A) end subroutine subroutine norm_scalar(this,field,norm,rank) @@ -156,7 +165,7 @@ subroutine norm_scalar(this,field,norm,rank) real(c_double) :: norm_array(1) opt_rank = 0 if( present(rank) ) opt_rank = rank - call atlas__SpectralFunctionSpace__norm(this%c_ptr(),field%c_ptr(),norm_array,opt_rank) + call atlas__SpectralFunctionSpace__norm(this%CPTR_PGIBUG_A,field%CPTR_PGIBUG_A,norm_array,opt_rank) norm = norm_array(1) end subroutine @@ -170,7 +179,7 @@ subroutine norm_array(this,field,norm,rank) integer :: opt_rank opt_rank = 0 if( present(rank) ) opt_rank = rank - call atlas__SpectralFunctionSpace__norm(this%c_ptr(),field%c_ptr(),norm,opt_rank) + call atlas__SpectralFunctionSpace__norm(this%CPTR_PGIBUG_A,field%CPTR_PGIBUG_A,norm,opt_rank) end subroutine !------------------------------------------------------------------------------- diff --git a/src/atlas_f/functionspace/atlas_functionspace_StructuredColumns_module.F90 b/src/atlas_f/functionspace/atlas_functionspace_StructuredColumns_module.F90 index 47a06f50f..fa07ab84c 100644 --- a/src/atlas_f/functionspace/atlas_functionspace_StructuredColumns_module.F90 +++ b/src/atlas_f/functionspace/atlas_functionspace_StructuredColumns_module.F90 @@ -1,24 +1,37 @@ +! (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_StructuredColumns_module -use, intrinsic :: iso_c_binding, only : c_ptr, c_int +use, intrinsic :: iso_c_binding, only : c_ptr, c_double 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_Grid_module, only: atlas_Grid use atlas_Config_module, only: atlas_Config +use atlas_kinds_module, only : ATLAS_KIND_IDX use fckit_owned_object_module, only : fckit_owned_object +use atlas_GridDistribution_module, only : atlas_GridDistribution +use atlas_Vertical_module, only : atlas_Vertical implicit none -private :: c_ptr, c_int +private :: c_ptr, c_double private :: c_str, c_ptr_to_string, c_ptr_free private :: atlas_FunctionSpace private :: atlas_Field private :: atlas_FieldSet private :: atlas_Grid +private :: atlas_GridDistribution +private :: atlas_Vertical private :: atlas_Config private :: fckit_owned_object @@ -41,7 +54,7 @@ module atlas_functionspace_StructuredColumns_module ! August-2015 Willem Deconinck *ECMWF* !------------------------------------------------------------------------------ - integer(c_int), pointer, public :: index(:,:) + integer(ATLAS_KIND_IDX), pointer, public :: index(:,:) contains @@ -54,10 +67,6 @@ module atlas_functionspace_StructuredColumns_module procedure, private :: checksum_field generic, public :: checksum => checksum_fieldset, checksum_field - procedure, private :: halo_exchange_fieldset - procedure, private :: halo_exchange_field - generic, public :: halo_exchange => halo_exchange_fieldset, halo_exchange_field - procedure :: j_begin procedure :: j_end procedure :: i_begin @@ -67,6 +76,9 @@ module atlas_functionspace_StructuredColumns_module procedure :: i_begin_halo procedure :: i_end_halo + procedure :: size => get_size + procedure :: size_owned => get_size_owned + procedure :: xy !! Return xy coordinate field procedure :: partition @@ -87,8 +99,10 @@ module atlas_functionspace_StructuredColumns_module END TYPE atlas_functionspace_StructuredColumns interface atlas_functionspace_StructuredColumns - module procedure StructuredColumns__cptr - module procedure StructuredColumns__grid + module procedure ctor_cptr + module procedure ctor_grid + module procedure ctor_grid_dist + module procedure ctor_grid_dist_levels end interface @@ -105,7 +119,7 @@ subroutine assignment_operator_hook(this,other) FCKIT_SUPPRESS_UNUSED(other) end subroutine -function StructuredColumns__cptr(cptr) result(this) +function ctor_cptr(cptr) result(this) type(atlas_functionspace_StructuredColumns) :: this type(c_ptr), intent(in) :: cptr call this%reset_c_ptr( cptr ) @@ -119,28 +133,70 @@ function empty_config() result(config) call config%return() end function -function StructuredColumns__grid(grid, halo, levels) result(this) +function ctor_grid(grid, halo, levels) result(this) + use atlas_functionspace_StructuredColumns_c_binding + type(atlas_functionspace_StructuredColumns) :: this + class(atlas_Grid), intent(in) :: grid + integer, optional :: halo + integer, optional :: levels + type(atlas_Config) :: config + config = empty_config() ! Due to PGI compiler bug, we have to do this instead of "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__functionspace__StructuredColumns__new__grid( grid%CPTR_PGIBUG_A, & + & config%CPTR_PGIBUG_B ) ) + call this%set_index() + call config%final() + call this%return() +end function + +function ctor_grid_dist(grid, distribution, halo, levels) result(this) use atlas_functionspace_StructuredColumns_c_binding type(atlas_functionspace_StructuredColumns) :: this class(atlas_Grid), intent(in) :: grid + type(atlas_griddistribution), intent(in) :: distribution integer, optional :: halo integer, optional :: levels type(atlas_Config) :: config config = empty_config() ! Due to PGI compiler bug, we have to do this instead of "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__functionspace__StructuredColumns__new__grid( grid%c_ptr(), config%c_ptr() ) ) + call this%reset_c_ptr( atlas__functionspace__StructuredColumns__new__grid_dist( & + & grid%CPTR_PGIBUG_A, distribution%CPTR_PGIBUG_A, config%CPTR_PGIBUG_B ) ) call this%set_index() call config%final() call this%return() end function +function ctor_grid_dist_levels(grid, distribution, levels, halo) result(this) + use atlas_functionspace_StructuredColumns_c_binding + type(atlas_functionspace_StructuredColumns) :: this + class(atlas_Grid), intent(in) :: grid + type(atlas_griddistribution), intent(in) :: distribution + integer, optional :: halo + real(c_double) :: levels(:) + type(atlas_Config) :: config + type(atlas_Vertical) :: vertical + config = empty_config() ! Due to PGI compiler bug, we have to do this insted of "config = atlas_Config()"" + if( present(halo) ) call config%set("halo",halo) + call config%set("levels",size(levels)) + vertical = atlas_Vertical(levels) + call this%reset_c_ptr( atlas__functionspace__StructuredColumns__new__grid_dist_vert( & + & grid%CPTR_PGIBUG_A, distribution%CPTR_PGIBUG_A, vertical%CPTR_PGIBUG_B, & + & config%CPTR_PGIBUG_B ) ) + call this%set_index() + call config%final() + call vertical%final() + call this%return() +end function + + subroutine gather(this,local,global) use atlas_functionspace_StructuredColumns_c_binding class(atlas_functionspace_StructuredColumns), intent(in) :: this type(atlas_Field), intent(in) :: local type(atlas_Field), intent(inout) :: global - call atlas__functionspace__StructuredColumns__gather(this%c_ptr(),local%c_ptr(),global%c_ptr()) + call atlas__functionspace__StructuredColumns__gather(this%CPTR_PGIBUG_A,local%CPTR_PGIBUG_A,global%CPTR_PGIBUG_A) end subroutine subroutine scatter(this,global,local) @@ -148,18 +204,20 @@ subroutine scatter(this,global,local) class(atlas_functionspace_StructuredColumns), intent(in) :: this type(atlas_Field), intent(in) :: global type(atlas_Field), intent(inout) :: local - call atlas__functionspace__StructuredColumns__scatter(this%c_ptr(),global%c_ptr(),local%c_ptr()) + call atlas__functionspace__StructuredColumns__scatter(this%CPTR_PGIBUG_A,global%CPTR_PGIBUG_A,local%CPTR_PGIBUG_A) end subroutine function checksum_fieldset(this,fieldset) result(checksum) + use, intrinsic :: iso_c_binding use atlas_functionspace_StructuredColumns_c_binding character(len=:), allocatable :: checksum class(atlas_functionspace_StructuredColumns), intent(in) :: this type(atlas_FieldSet), intent(in) :: fieldset type(c_ptr) :: checksum_cptr - integer :: checksum_size, checksum_allocated + integer(ATLAS_KIND_IDX) :: checksum_size + integer(c_int) :: checksum_allocated call atlas__fs__StructuredColumns__checksum_fieldset( & - & this%c_ptr(),fieldset%c_ptr(),checksum_cptr,checksum_size,checksum_allocated) + & 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) @@ -167,28 +225,30 @@ function checksum_fieldset(this,fieldset) result(checksum) function checksum_field(this,field) result(checksum) + use, intrinsic :: iso_c_binding use atlas_functionspace_StructuredColumns_c_binding character(len=:), allocatable :: checksum class(atlas_functionspace_StructuredColumns), intent(in) :: this type(atlas_Field), intent(in) :: field type(c_ptr) :: checksum_cptr - integer :: checksum_size, checksum_allocated + integer(ATLAS_KIND_IDX) :: checksum_size + integer(c_int) :: checksum_allocated call atlas__fs__StructuredColumns__checksum_field( & - & this%c_ptr(),field%c_ptr(),checksum_cptr,checksum_size,checksum_allocated) + & 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 subroutine set_index(this) - use, intrinsic :: iso_c_binding, only : c_ptr, c_int, c_f_pointer + use, intrinsic :: iso_c_binding, only : c_ptr, c_f_pointer use atlas_functionspace_StructuredColumns_c_binding class(atlas_functionspace_StructuredColumns), intent(inout) :: this type(c_ptr) :: index_cptr - integer(c_int), pointer :: index_fptr(:) - integer(c_int) :: i_min, i_max, j_min, j_max - integer(c_int) :: ni, nj - call atlas__fs__StructuredColumns__index_host( this%c_ptr(), index_cptr, i_min, i_max, j_min, j_max ) + integer(ATLAS_KIND_IDX), pointer :: index_fptr(:) + integer(ATLAS_KIND_IDX) :: i_min, i_max, j_min, j_max + integer(ATLAS_KIND_IDX) :: ni, nj + call atlas__fs__StructuredColumns__index_host( this%CPTR_PGIBUG_A, index_cptr, i_min, i_max, j_min, j_max ) ni = i_max-i_min+1; nj = j_max-j_min+1; call c_f_pointer( index_cptr, index_fptr, (/ni*nj/) ) @@ -196,79 +256,85 @@ subroutine set_index(this) end subroutine function j_begin(this) result(j) - use, intrinsic :: iso_c_binding, only : c_int use atlas_functionspace_StructuredColumns_c_binding - integer(c_int) :: j + integer(ATLAS_KIND_IDX) :: j class(atlas_functionspace_StructuredColumns), intent(in) :: this - j = atlas__fs__StructuredColumns__j_begin(this%c_ptr()) + j = atlas__fs__StructuredColumns__j_begin(this%CPTR_PGIBUG_A) end function function j_end(this) result(j) - use, intrinsic :: iso_c_binding, only : c_int use atlas_functionspace_StructuredColumns_c_binding - integer(c_int) :: j + integer(ATLAS_KIND_IDX) :: j class(atlas_functionspace_StructuredColumns), intent(in) :: this - j = atlas__fs__StructuredColumns__j_end(this%c_ptr()) + j = atlas__fs__StructuredColumns__j_end(this%CPTR_PGIBUG_A) end function function i_begin(this,j) result(i) - use, intrinsic :: iso_c_binding, only : c_int use atlas_functionspace_StructuredColumns_c_binding - integer(c_int) :: i - integer(c_int), intent(in) :: j + integer(ATLAS_KIND_IDX) :: i + integer(ATLAS_KIND_IDX), intent(in) :: j class(atlas_functionspace_StructuredColumns), intent(in) :: this - i = atlas__fs__StructuredColumns__i_begin(this%c_ptr(),j) + i = atlas__fs__StructuredColumns__i_begin(this%CPTR_PGIBUG_A,j) end function function i_end(this,j) result(i) - use, intrinsic :: iso_c_binding, only : c_int use atlas_functionspace_StructuredColumns_c_binding - integer(c_int) :: i - integer(c_int), intent(in) :: j + integer(ATLAS_KIND_IDX) :: i + integer(ATLAS_KIND_IDX), intent(in) :: j class(atlas_functionspace_StructuredColumns), intent(in) :: this - i = atlas__fs__StructuredColumns__i_end(this%c_ptr(),j) + i = atlas__fs__StructuredColumns__i_end(this%CPTR_PGIBUG_A,j) end function function j_begin_halo(this) result(j) - use, intrinsic :: iso_c_binding, only : c_int use atlas_functionspace_StructuredColumns_c_binding - integer(c_int) :: j + integer(ATLAS_KIND_IDX) :: j class(atlas_functionspace_StructuredColumns), intent(in) :: this - j = atlas__fs__StructuredColumns__j_begin_halo(this%c_ptr()) + j = atlas__fs__StructuredColumns__j_begin_halo(this%CPTR_PGIBUG_A) end function function j_end_halo(this) result(j) - use, intrinsic :: iso_c_binding, only : c_int use atlas_functionspace_StructuredColumns_c_binding - integer(c_int) :: j + integer(ATLAS_KIND_IDX) :: j class(atlas_functionspace_StructuredColumns), intent(in) :: this - j = atlas__fs__StructuredColumns__j_end_halo(this%c_ptr()) + j = atlas__fs__StructuredColumns__j_end_halo(this%CPTR_PGIBUG_A) end function function i_begin_halo(this,j) result(i) - use, intrinsic :: iso_c_binding, only : c_int use atlas_functionspace_StructuredColumns_c_binding - integer(c_int) :: i - integer(c_int), intent(in) :: j + integer(ATLAS_KIND_IDX) :: i + integer(ATLAS_KIND_IDX), intent(in) :: j class(atlas_functionspace_StructuredColumns), intent(in) :: this - i = atlas__fs__StructuredColumns__i_begin_halo(this%c_ptr(),j) + i = atlas__fs__StructuredColumns__i_begin_halo(this%CPTR_PGIBUG_A,j) end function function i_end_halo(this,j) result(i) - use, intrinsic :: iso_c_binding, only : c_int use atlas_functionspace_StructuredColumns_c_binding - integer(c_int) :: i - integer(c_int), intent(in) :: j + integer(ATLAS_KIND_IDX) :: i + integer(ATLAS_KIND_IDX), intent(in) :: j + class(atlas_functionspace_StructuredColumns), intent(in) :: this + i = atlas__fs__StructuredColumns__i_end_halo(this%CPTR_PGIBUG_A,j) +end function + +function get_size(this) result(size) + use atlas_functionspace_StructuredColumns_c_binding + integer(ATLAS_KIND_IDX) :: size class(atlas_functionspace_StructuredColumns), intent(in) :: this - i = atlas__fs__StructuredColumns__i_end_halo(this%c_ptr(),j) + size = atlas__fs__StructuredColumns__size(this%CPTR_PGIBUG_A) +end function + +function get_size_owned(this) result(size) + use atlas_functionspace_StructuredColumns_c_binding + integer(ATLAS_KIND_IDX) :: size + class(atlas_functionspace_StructuredColumns), intent(in) :: this + size = atlas__fs__StructuredColumns__sizeOwned(this%CPTR_PGIBUG_A) end function function xy(this) result(field) use atlas_functionspace_StructuredColumns_c_binding type(atlas_Field) :: field class(atlas_functionspace_StructuredColumns), intent(in) :: this - field = atlas_Field( atlas__fs__StructuredColumns__xy(this%c_ptr()) ) + field = atlas_Field( atlas__fs__StructuredColumns__xy(this%CPTR_PGIBUG_A) ) call field%return() end function @@ -276,7 +342,7 @@ function partition(this) result(field) use atlas_functionspace_StructuredColumns_c_binding type(atlas_Field) :: field class(atlas_functionspace_StructuredColumns), intent(in) :: this - field = atlas_Field( atlas__fs__StructuredColumns__partition(this%c_ptr()) ) + field = atlas_Field( atlas__fs__StructuredColumns__partition(this%CPTR_PGIBUG_A) ) call field%return() end function @@ -284,7 +350,7 @@ function global_index(this) result(field) use atlas_functionspace_StructuredColumns_c_binding type(atlas_Field) :: field class(atlas_functionspace_StructuredColumns), intent(in) :: this - field = atlas_Field( atlas__fs__StructuredColumns__global_index(this%c_ptr()) ) + field = atlas_Field( atlas__fs__StructuredColumns__global_index(this%CPTR_PGIBUG_A) ) call field%return() end function @@ -292,7 +358,7 @@ function index_i(this) result(field) use atlas_functionspace_StructuredColumns_c_binding type(atlas_Field) :: field class(atlas_functionspace_StructuredColumns), intent(in) :: this - field = atlas_Field( atlas__fs__StructuredColumns__index_i(this%c_ptr()) ) + field = atlas_Field( atlas__fs__StructuredColumns__index_i(this%CPTR_PGIBUG_A) ) call field%return() end function @@ -300,26 +366,10 @@ function index_j(this) result(field) use atlas_functionspace_StructuredColumns_c_binding type(atlas_Field) :: field class(atlas_functionspace_StructuredColumns), intent(in) :: this - field = atlas_Field( atlas__fs__StructuredColumns__index_j(this%c_ptr()) ) + field = atlas_Field( atlas__fs__StructuredColumns__index_j(this%CPTR_PGIBUG_A) ) call field%return() end function -subroutine halo_exchange_fieldset(this,fieldset) - use atlas_functionspace_StructuredColumns_c_binding - class(atlas_functionspace_StructuredColumns), intent(in) :: this - type(atlas_FieldSet), intent(inout) :: fieldset - call atlas__fs__StructuredColumns__halo_exchange_fieldset(this%c_ptr(),fieldset%c_ptr()) -end subroutine - -!------------------------------------------------------------------------------ - -subroutine halo_exchange_field(this,field) - use atlas_functionspace_StructuredColumns_c_binding - class(atlas_functionspace_StructuredColumns), intent(in) :: this - type(atlas_Field), intent(inout) :: field - call atlas__fs__StructuredColumns__halo_exchange_field(this%c_ptr(),field%c_ptr()) -end subroutine - !------------------------------------------------------------------------------- ATLAS_FINAL subroutine StructuredColumns__final_auto(this) diff --git a/src/atlas_f/grid/atlas_GridDistribution_module.F90 b/src/atlas_f/grid/atlas_GridDistribution_module.F90 index 4f8a20651..105085d8f 100644 --- a/src/atlas_f/grid/atlas_GridDistribution_module.F90 +++ b/src/atlas_f/grid/atlas_GridDistribution_module.F90 @@ -1,3 +1,11 @@ +! (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_GridDistribution_module @@ -63,10 +71,12 @@ function atlas_GridDistribution__cptr( cptr ) result(this) function atlas_GridDistribution__ctor( part, part0 ) result(this) use atlas_distribution_c_binding + use atlas_kinds_module, only : ATLAS_KIND_IDX type(atlas_GridDistribution) :: this integer, intent(in) :: part(:) integer, intent(in), optional :: part0 - integer:: npts, opt_part0 + integer(ATLAS_KIND_IDX) :: npts + integer :: opt_part0 opt_part0 = 0 if( present(part0) ) opt_part0 = part0 npts = size(part) diff --git a/src/atlas_f/grid/atlas_Grid_module.F90 b/src/atlas_f/grid/atlas_Grid_module.F90 index 1db117ffa..82ecc9447 100644 --- a/src/atlas_f/grid/atlas_Grid_module.F90 +++ b/src/atlas_f/grid/atlas_Grid_module.F90 @@ -1,9 +1,18 @@ +! (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_Grid_module use fckit_owned_object_module, only: fckit_owned_object use atlas_Config_module, only: atlas_Config +use atlas_kinds_module, only : ATLAS_KIND_IDX use, intrinsic :: iso_c_binding, only : c_ptr implicit none @@ -233,16 +242,16 @@ module atlas_Grid_module pure function c_idx_32(f_idx) result(c_idx) use, intrinsic :: iso_c_binding, only : c_long - integer(c_long) :: c_idx + integer(ATLAS_KIND_IDX) :: c_idx integer(c_long), intent(in) :: f_idx - c_idx = f_idx - 1_c_long + c_idx = int(f_idx,ATLAS_KIND_IDX) - 1_ATLAS_KIND_IDX end function pure function c_idx_64(f_idx) result(c_idx) use, intrinsic :: iso_c_binding, only : c_long, c_int - integer(c_long) :: c_idx + integer(ATLAS_KIND_IDX) :: c_idx integer(c_int), intent(in) :: f_idx - c_idx = f_idx - 1_c_long + c_idx = int(f_idx,ATLAS_KIND_IDX) - 1_ATLAS_KIND_IDX end function ! ----------------------------------------------------------------------------- @@ -314,7 +323,7 @@ function atlas_Grid__ctor_config(config) result(this) use atlas_grid_Structured_c_binding type(atlas_Grid) :: this type(atlas_Config), intent(in) :: config - call this%reset_c_ptr( atlas__grid__Structured__config(config%c_ptr()) ) + call this%reset_c_ptr( atlas__grid__Structured__config(config%CPTR_PGIBUG_B) ) call this%return() end function @@ -342,7 +351,7 @@ function atlas_StructuredGrid__ctor_config(config) result(this) use atlas_grid_Structured_c_binding type(atlas_StructuredGrid) :: this type(atlas_Config), intent(in) :: config - call this%reset_c_ptr( atlas__grid__Structured__config(config%c_ptr()) ) + call this%reset_c_ptr( atlas__grid__Structured__config(config%CPTR_PGIBUG_B) ) call this%return() end function @@ -436,7 +445,7 @@ function atlas_Grid__size(this) result(npts) use atlas_grid_Structured_c_binding class(atlas_Grid), intent(in) :: this integer(c_long) :: npts - npts = atlas__grid__Structured__size(this%c_ptr()) + npts = atlas__grid__Structured__size(this%CPTR_PGIBUG_A) end function function Gaussian__N(this) result(N) @@ -444,7 +453,7 @@ function Gaussian__N(this) result(N) use atlas_grid_Structured_c_binding class(atlas_GaussianGrid), intent(in) :: this integer(c_long) :: N - N = atlas__grid__Gaussian__N(this%c_ptr()) + N = atlas__grid__Gaussian__N(this%CPTR_PGIBUG_A) end function function ReducedGaussian__N(this) result(N) @@ -452,7 +461,7 @@ function ReducedGaussian__N(this) result(N) use atlas_grid_Structured_c_binding class(atlas_ReducedGaussianGrid), intent(in) :: this integer(c_long) :: N - N = atlas__grid__Gaussian__N(this%c_ptr()) + N = atlas__grid__Gaussian__N(this%CPTR_PGIBUG_A) end function function RegularGaussian__N(this) result(N) @@ -460,7 +469,7 @@ function RegularGaussian__N(this) result(N) use atlas_grid_Structured_c_binding class(atlas_RegularGaussianGrid), intent(in) :: this integer(c_long) :: N - N = atlas__grid__Gaussian__N(this%c_ptr()) + N = atlas__grid__Gaussian__N(this%CPTR_PGIBUG_A) end function function Structured__ny(this) result(ny) @@ -468,7 +477,7 @@ function Structured__ny(this) result(ny) use atlas_grid_Structured_c_binding class(atlas_StructuredGrid), intent(in) :: this integer(c_long) :: ny - ny = atlas__grid__Structured__ny(this%c_ptr()) + ny = atlas__grid__Structured__ny(this%CPTR_PGIBUG_A) end function @@ -478,7 +487,7 @@ function Structured__nx_int32(this, j) result(nx) integer(c_long) :: nx class(atlas_StructuredGrid), intent(in) :: this integer(c_int), intent(in) :: j - nx = atlas__grid__Structured__nx(this%c_ptr(), c_idx(j) ) + nx = atlas__grid__Structured__nx(this%CPTR_PGIBUG_A, c_idx(j) ) end function function Structured__nx_int64(this, j) result(nx) @@ -487,14 +496,14 @@ function Structured__nx_int64(this, j) result(nx) integer(c_long) :: nx class(atlas_StructuredGrid), intent(in) :: this integer(c_long), intent(in) :: j - nx = atlas__grid__Structured__nx(this%c_ptr(), c_idx(j) ) + nx = atlas__grid__Structured__nx(this%CPTR_PGIBUG_A, c_idx(j) ) end function function Structured__reduced(this) result(reduced) use atlas_grid_Structured_c_binding class(atlas_StructuredGrid), intent(in) :: this logical :: reduced - if( atlas__grid__Structured__reduced(this%c_ptr()) == 1 ) then + if( atlas__grid__Structured__reduced(this%CPTR_PGIBUG_A) == 1 ) then reduced = .true. else reduced = .false. @@ -503,12 +512,12 @@ function Structured__reduced(this) result(reduced) function Structured__nx_array(this) result(nx) use atlas_grid_Structured_c_binding - use, intrinsic :: iso_c_binding , only : c_long, c_size_t, c_f_pointer + use, intrinsic :: iso_c_binding , only : c_long, c_f_pointer class(atlas_StructuredGrid), intent(in) :: this - integer(c_long), pointer :: nx(:) + integer(ATLAS_KIND_IDX), pointer :: nx(:) type (c_ptr) :: nx_c_ptr - integer(c_size_t) :: nx_size - call atlas__grid__Structured__nx_array(this%c_ptr(), nx_c_ptr, nx_size) + integer(ATLAS_KIND_IDX) :: nx_size + call atlas__grid__Structured__nx_array(this%CPTR_PGIBUG_A, nx_c_ptr, nx_size) call c_f_pointer(nx_c_ptr , nx , (/nx_size/)) end function @@ -517,7 +526,7 @@ function Structured__nxmax(this) result(nxmax) use atlas_grid_Structured_c_binding class(atlas_StructuredGrid), intent(in) :: this integer(c_long) :: nxmax - nxmax = atlas__grid__Structured__nxmax(this%c_ptr()) + nxmax = atlas__grid__Structured__nxmax(this%CPTR_PGIBUG_A) end function function Structured__nxmin(this) result(nxmin) @@ -525,7 +534,7 @@ function Structured__nxmin(this) result(nxmin) use atlas_grid_Structured_c_binding class(atlas_StructuredGrid), intent(in) :: this integer(c_long) :: nxmin - nxmin = atlas__grid__Structured__nxmin(this%c_ptr()) + nxmin = atlas__grid__Structured__nxmin(this%CPTR_PGIBUG_A) end function function Structured__y(this, j) result(y) @@ -534,7 +543,7 @@ function Structured__y(this, j) result(y) real(c_double) :: y class(atlas_StructuredGrid), intent(in) :: this integer(c_long), intent(in) :: j - y = atlas__grid__Structured__y(this%c_ptr(), c_idx(j) ) + y = atlas__grid__Structured__y(this%CPTR_PGIBUG_A, c_idx(j) ) end function function Structured__y_32(this, j) result(y) @@ -543,7 +552,7 @@ function Structured__y_32(this, j) result(y) real(c_double) :: y class(atlas_StructuredGrid), intent(in) :: this integer(c_int), intent(in) :: j - y = atlas__grid__Structured__y(this%c_ptr(), c_idx(j) ) + y = atlas__grid__Structured__y(this%CPTR_PGIBUG_A, c_idx(j) ) end function function Structured__y_64(this, j) result(y) @@ -552,17 +561,17 @@ function Structured__y_64(this, j) result(y) real(c_double) :: y class(atlas_StructuredGrid), intent(in) :: this integer(c_long), intent(in) :: j - y = atlas__grid__Structured__y(this%c_ptr(), c_idx(j) ) + y = atlas__grid__Structured__y(this%CPTR_PGIBUG_A, c_idx(j) ) end function function Structured__y_array(this) result(y) use atlas_grid_Structured_c_binding - use, intrinsic :: iso_c_binding , only : c_double, c_size_t, c_f_pointer + use, intrinsic :: iso_c_binding , only : c_double, c_f_pointer class(atlas_StructuredGrid), intent(in) :: this real (c_double) , pointer :: y(:) type (c_ptr) :: y_c_ptr - integer(c_size_t) :: y_size - call atlas__grid__Structured__y_array(this%c_ptr(), & + integer(ATLAS_KIND_IDX) :: y_size + call atlas__grid__Structured__y_array(this%CPTR_PGIBUG_A, & & y_c_ptr, y_size) call c_f_pointer (y_c_ptr, y, (/y_size/)) end function @@ -573,7 +582,7 @@ function Structured__x_32(this, i,j) result(x) class(atlas_StructuredGrid), intent(in) :: this real(c_double) :: x integer(c_int) :: i,j - x = atlas__grid__Structured__x(this%c_ptr(), c_idx(i), c_idx(j)) + x = atlas__grid__Structured__x(this%CPTR_PGIBUG_A, c_idx(i), c_idx(j)) end function function Structured__x_64(this, i,j) result(x) @@ -582,7 +591,7 @@ function Structured__x_64(this, i,j) result(x) class(atlas_StructuredGrid), intent(in) :: this real(c_double) :: x integer(c_long) :: i,j - x = atlas__grid__Structured__x(this%c_ptr(), c_idx(i), c_idx(j)) + x = atlas__grid__Structured__x(this%CPTR_PGIBUG_A, c_idx(i), c_idx(j)) end function function Structured__xy_32(this, i,j) result(xy) @@ -591,7 +600,7 @@ function Structured__xy_32(this, i,j) result(xy) real(c_double) :: xy(2) class(atlas_StructuredGrid), intent(in) :: this integer(c_int) , intent(in) :: i,j - call atlas__grid__Structured__xy(this%c_ptr(), c_idx(i), c_idx(j), xy) + call atlas__grid__Structured__xy(this%CPTR_PGIBUG_A, c_idx(i), c_idx(j), xy) end function function Structured__xy_64(this, i,j) result(xy) @@ -600,7 +609,7 @@ function Structured__xy_64(this, i,j) result(xy) real(c_double) :: xy(2) class(atlas_StructuredGrid), intent(in) :: this integer(c_long) , intent(in) :: i,j - call atlas__grid__Structured__xy(this%c_ptr(), c_idx(i), c_idx(j), xy) + call atlas__grid__Structured__xy(this%CPTR_PGIBUG_A, c_idx(i), c_idx(j), xy) end function function Structured__lonlat_32(this, i,j) result(lonlat) @@ -609,7 +618,7 @@ function Structured__lonlat_32(this, i,j) result(lonlat) real(c_double) :: lonlat(2) class(atlas_StructuredGrid), intent(in) :: this integer(c_int) , intent(in) :: i,j - call atlas__grid__Structured__lonlat(this%c_ptr(), c_idx(i), c_idx(j), lonlat) + call atlas__grid__Structured__lonlat(this%CPTR_PGIBUG_A, c_idx(i), c_idx(j), lonlat) end function function Structured__lonlat_64(this, i,j) result(lonlat) @@ -618,7 +627,7 @@ function Structured__lonlat_64(this, i,j) result(lonlat) real(c_double) :: lonlat(2) class(atlas_StructuredGrid), intent(in) :: this integer(c_long) , intent(in) :: i,j - call atlas__grid__Structured__lonlat(this%c_ptr(), c_idx(i), c_idx(j), lonlat) + call atlas__grid__Structured__lonlat(this%CPTR_PGIBUG_A, c_idx(i), c_idx(j), lonlat) end function ! ---------------------------------------------------------------------------------------- diff --git a/src/atlas_f/grid/atlas_Partitioner_module.F90 b/src/atlas_f/grid/atlas_Partitioner_module.F90 index eb7d9b1d9..924fa671c 100644 --- a/src/atlas_f/grid/atlas_Partitioner_module.F90 +++ b/src/atlas_f/grid/atlas_Partitioner_module.F90 @@ -1,3 +1,11 @@ +! (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_Partitioner_module @@ -63,7 +71,7 @@ function atlas_Partitioner__ctor( config ) result(this) use atlas_partitioner_c_binding type(atlas_Partitioner) :: this type(atlas_Config) :: config - call this%reset_c_ptr( atlas__grid__Partitioner__new( config%c_ptr() ) ) + call this%reset_c_ptr( atlas__grid__Partitioner__new( config%CPTR_PGIBUG_B ) ) call this%return() end function @@ -76,10 +84,12 @@ function atlas_MatchingMeshPartitioner__ctor( mesh, config ) result(this) type(atlas_Config), intent(in), optional :: config type(atlas_Config) :: opt_config if( present(config) ) then - call this%reset_c_ptr( atlas__grid__MatchingMeshPartitioner__new( mesh%c_ptr(), config%c_ptr() ) ) + call this%reset_c_ptr( atlas__grid__MatchingMeshPartitioner__new( & + mesh%CPTR_PGIBUG_A, config%CPTR_PGIBUG_B ) ) else opt_config = atlas_Config() - call this%reset_c_ptr( atlas__grid__MatchingMeshPartitioner__new( mesh%c_ptr(), opt_config%c_ptr() ) ) + call this%reset_c_ptr( atlas__grid__MatchingMeshPartitioner__new( & + mesh%CPTR_PGIBUG_A, opt_config%CPTR_PGIBUG_B ) ) call opt_config%final() endif call this%return() @@ -92,7 +102,7 @@ function partition(this,grid) result(distribution) type(atlas_GridDistribution) :: distribution class(atlas_Partitioner), intent(in) :: this class(atlas_Grid), intent(in) :: grid - distribution = atlas_GridDistribution( atlas__grid__Partitioner__partition( this%c_ptr(), grid%c_ptr() ) ) + distribution = atlas_GridDistribution( atlas__grid__Partitioner__partition( this%CPTR_PGIBUG_A, grid%CPTR_PGIBUG_A ) ) call distribution%return() end function diff --git a/src/atlas_f/grid/atlas_Vertical_module.F90 b/src/atlas_f/grid/atlas_Vertical_module.F90 new file mode 100644 index 000000000..29e8f9e01 --- /dev/null +++ b/src/atlas_f/grid/atlas_Vertical_module.F90 @@ -0,0 +1,110 @@ +! (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_Vertical_module + +use fckit_shared_object_module, only : fckit_shared_object, fckit_c_deleter, fckit_c_nodeleter + +use, intrinsic :: iso_c_binding, only : c_ptr, c_double + +implicit none + +public :: atlas_Vertical + +private + +!----------------------------- +! atlas_Vertical ! +!----------------------------- + + +!------------------------------------------------------------------------------ +TYPE, extends(fckit_shared_object) :: atlas_Vertical + +! Purpose : +! ------- +! *Vertical* : Object describing vertical levels + +! Methods : +! ------- + +! Author : +! ------ +! 28-Nov-2018 Willem Deconinck *ECMWF* + +!------------------------------------------------------------------------------ +contains +#if FCKIT_FINAL_NOT_INHERITING + final :: atlas_Vertical__final_auto +#endif +END TYPE atlas_Vertical + +!------------------------------------------------------------------------------ + +interface atlas_Vertical + module procedure atlas_Vertical__ctor_from_cptr + module procedure atlas_Vertical__ctor_from_array +end interface + +private :: c_ptr, c_double +private :: fckit_shared_object +private :: fckit_c_deleter +private :: fckit_c_nodeleter + +!======================================================== +contains +!======================================================== +! ----------------------------------------------------------------------------- +! Vertical routines + +function atlas_Vertical__ctor_from_cptr( cptr, delete ) result(this) + use atlas_vertical_c_binding + type(c_ptr), value :: cptr + type(atlas_Vertical) :: this + logical, optional :: delete + logical :: opt_delete + opt_delete = .true. + if( present(delete) ) opt_delete = delete + if( opt_delete ) then + call this%reset_c_ptr( cptr, fckit_c_deleter(atlas__Vertical__delete) ) + else + call this%reset_c_ptr( cptr, fckit_c_nodeleter() ) + endif + call this%return() +end function + +function atlas_Vertical__ctor_from_array( levels ) result(this) + use atlas_vertical_c_binding + use atlas_kinds_module, only : ATLAS_KIND_IDX + type(atlas_Vertical) :: this + real(c_double) :: levels(:) + integer(ATLAS_KIND_IDX) :: nb_levels + nb_levels = size(levels) + call this%reset_c_ptr( atlas__Vertical__new(nb_levels, levels), & + & fckit_c_deleter(atlas__Vertical__delete) ) + call this%return() +end function + +! ---------------------------------------------------------------------------------------- + +ATLAS_FINAL subroutine atlas_Vertical__final_auto(this) + type(atlas_Vertical), intent(inout) :: this +#if FCKIT_FINAL_DEBUGGING + write(0,*) "atlas_Vertical__final_auto" +#endif +#if FCKIT_FINAL_NOT_PROPAGATING + call this%final() +#endif + FCKIT_SUPPRESS_UNUSED( this ) +end subroutine + +! ---------------------------------------------------------------------------------------- + +end module atlas_Vertical_module diff --git a/src/atlas_f/internals/Library.cc b/src/atlas_f/internals/Library.cc index c311493de..5d174f743 100644 --- a/src/atlas_f/internals/Library.cc +++ b/src/atlas_f/internals/Library.cc @@ -1,3 +1,15 @@ +/* + * (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 "eckit/eckit_version.h" + #include "atlas/library/Library.h" #include "atlas_f/internals/Library.h" diff --git a/src/atlas_f/internals/Library.h b/src/atlas_f/internals/Library.h index 674ca80ce..aaef9f02c 100644 --- a/src/atlas_f/internals/Library.h +++ b/src/atlas_f/internals/Library.h @@ -1,3 +1,13 @@ +/* + * (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 // C wrapper interfaces to C++ routines diff --git a/src/atlas_f/internals/atlas_generics.fypp b/src/atlas_f/internals/atlas_generics.fypp new file mode 100644 index 000000000..78d78c353 --- /dev/null +++ b/src/atlas_f/internals/atlas_generics.fypp @@ -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. + +#:mute + +#:set ranks = [1,2,3,4] +#:set dim = ['',':',':,:',':,:,:',':,:,:,:',':,:,:,:,:'] + +#:set ftypes = ['integer(c_int)','integer(c_long)','real(c_float)','real(c_double)', 'logical'] +#:set ctypes = ['int','long','float','double', 'int'] +#:set dtypes = ['int32', 'int64', 'real32', 'real64', 'logical32'] +#:set types = list(zip(dtypes,ftypes,ctypes)) + +#:set integer_ftypes = ['integer(c_int)','integer(c_long)'] +#:set integer_ctypes = ['int','long'] +#:set integer_dtypes = ['int32', 'int64'] +#:set integer_types = list(zip(integer_dtypes,integer_ftypes,integer_ctypes)) + +#:set real_ftypes = ['real(c_float)','real(c_double)'] +#:set real_ctypes = ['float','double'] +#:set real_dtypes = ['real32', 'real64'] +#:set real_types = list(zip(real_dtypes,real_ftypes,real_ctypes)) + +#:def generic_public_interface( interface, prefix = None ) +#:if prefix is None +#:set prefix = interface +#:endif +#:set counter = 0 +#:for rank in ranks +#:for dtype in dtypes[:4] + procedure, private :: ${prefix}$_${dtype}$_r${rank}$ + #:set counter = counter + 1 +#:endfor +#:endfor +#:set last = counter +#:set counter = 1 + generic, public :: ${interface}$ => & +#:for rank in ranks +#:for dtype in dtypes[:4] + & ${prefix}$_${dtype}$_r${rank}$#{if counter < last}#, & #{endif}# + #:set counter = counter + 1 +#:endfor +#:endfor +#:enddef + + +#:def generic_public_interface_2( interface, prefix1, prefix2 ) +#:set counter = 0 +#:for rank in ranks +#:for dtype in dtypes[:4] + procedure, private :: ${prefix1}$_${dtype}$_r${rank}$ + #:set counter = counter + 1 +#:endfor +#:endfor +#:for rank in ranks +#:for dtype in dtypes[:4] + procedure, private :: ${prefix2}$_${dtype}$_r${rank}$ + #:set counter = counter + 1 +#:endfor +#:endfor +#:set last = counter +#:set counter = 1 + generic, public :: ${interface}$ => & +#:for rank in ranks +#:for dtype in dtypes[:4] + & ${prefix1}$_${dtype}$_r${rank}$#{if counter < last}#, & #{endif}# + #:set counter = counter + 1 +#:endfor +#:endfor +#:for rank in ranks +#:for dtype in dtypes[:4] + & ${prefix2}$_${dtype}$_r${rank}$#{if counter < last}#, & #{endif}# + #:set counter = counter + 1 +#:endfor +#:endfor +#:enddef + +#:endmute diff --git a/src/atlas_f/internals/atlas_read_file.cc b/src/atlas_f/internals/atlas_read_file.cc index e89b7e82a..cd34f2398 100644 --- a/src/atlas_f/internals/atlas_read_file.cc +++ b/src/atlas_f/internals/atlas_read_file.cc @@ -1,8 +1,21 @@ -#include "eckit/exception/Exceptions.h" +/* + * (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 +#include + #include "eckit/filesystem/PathName.h" #include "eckit/runtime/Main.h" -#include "atlas/runtime/ErrorHandling.h" +#include "atlas/runtime/Exception.h" #include "atlas_f/internals/atlas_read_file.h" namespace atlas { @@ -11,7 +24,7 @@ void read_file( const eckit::PathName& p, std::ostream& out ) { if ( p.exists() ) { std::ifstream in; in.open( p.asString().c_str() ); - if ( !in ) { throw eckit::CantOpenFile( p.asString(), Here() ); } + if ( !in ) { throw_CantOpenFile( p.asString(), Here() ); } else { out << in.rdbuf(); in.close(); @@ -26,25 +39,27 @@ extern "C" { //----------------------------------------------------------------------------- int atlas__read_file( const char* path, char*& content, int& size ) { - ATLAS_ERROR_HANDLING( - - // eckit::FileReadPolicy p = - // eckit::Main::instance().behavior().fileReadPolicy(); + // eckit::FileReadPolicy p = + // eckit::Main::instance().behavior().fileReadPolicy(); - // std::stringstream ss; + // std::stringstream ss; - // if( read( p, path, ss ) ) - // { - // std::string s = ss.str(); - // size = s.size()+1; - // content = new char[size]; - // strcpy(content,s.c_str()); - // return true; - // } + // if( read( p, path, ss ) ) + // { + // std::string s = ss.str(); + // size = s.size()+1; + // content = new char[size]; + // strcpy(content,s.c_str()); + // return true; + // } - std::stringstream ss; atlas::read_file( path, ss ); std::string s = ss.str(); size = s.size() + 1; - content = new char[size]; strcpy( content, s.c_str() ); return true; ); - return false; + std::stringstream ss; + atlas::read_file( path, ss ); + std::string s = ss.str(); + size = s.size() + 1; + content = new char[size]; + strcpy( content, s.c_str() ); + return true; } //----------------------------------------------------------------------------- diff --git a/src/atlas_f/internals/atlas_read_file.h b/src/atlas_f/internals/atlas_read_file.h index 77b9f2037..18d50f3de 100644 --- a/src/atlas_f/internals/atlas_read_file.h +++ b/src/atlas_f/internals/atlas_read_file.h @@ -1,3 +1,12 @@ +/* + * (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. + */ #define Char char diff --git a/src/atlas_f/internals/atlas_write_to_fortran_unit.F90 b/src/atlas_f/internals/atlas_write_to_fortran_unit.F90 index 9f62e7339..0de3929b2 100644 --- a/src/atlas_f/internals/atlas_write_to_fortran_unit.F90 +++ b/src/atlas_f/internals/atlas_write_to_fortran_unit.F90 @@ -1,3 +1,11 @@ +! (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. + subroutine atlas_write_to_fortran_unit(unit,msg_cptr) bind(C) use, intrinsic :: iso_c_binding, only: c_int, c_ptr use fckit_c_interop_module, only : c_ptr_to_string diff --git a/src/atlas_f/interpolation/atlas_Interpolation_module.F90 b/src/atlas_f/interpolation/atlas_Interpolation_module.F90 index 7bc7122b8..4faf51278 100644 --- a/src/atlas_f/interpolation/atlas_Interpolation_module.F90 +++ b/src/atlas_f/interpolation/atlas_Interpolation_module.F90 @@ -1,3 +1,11 @@ +! (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_Interpolation_module @@ -41,6 +49,8 @@ module atlas_Interpolation_module interface atlas_Interpolation module procedure atlas_Interpolation__cptr module procedure atlas_Interpolation__config_funcspace + module procedure atlas_Interpolation__config_funcspace_field + module procedure atlas_Interpolation__config_funcspace_fieldset end interface !======================================================== @@ -62,7 +72,36 @@ function atlas_Interpolation__config_funcspace(config,source,target) result(this type(atlas_Config), intent(in) :: config class(atlas_FunctionSpace), intent(in) :: source class(atlas_FunctionSpace), intent(in) :: target - this = atlas_Interpolation__cptr(atlas__interpolation__new(config%c_ptr(),source%c_ptr(),target%c_ptr())) + this = atlas_Interpolation__cptr(atlas__interpolation__new(config%CPTR_PGIBUG_B, & + source%CPTR_PGIBUG_A,target%CPTR_PGIBUG_A)) + call this%return() +end function + +function atlas_Interpolation__config_funcspace_field(config,source,target) result(this) + use atlas_Interpolation_c_binding + use atlas_Config_module, only : atlas_Config + use atlas_FunctionSpace_module, only : atlas_FunctionSpace + use atlas_Field_module, only : atlas_Field + type(atlas_Interpolation) :: this + type(atlas_Config), intent(in) :: config + class(atlas_FunctionSpace), intent(in) :: source + class(atlas_Field), intent(in) :: target + this = atlas_Interpolation__cptr(atlas__interpolation__new_tgt_field(config%CPTR_PGIBUG_B, & + source%CPTR_PGIBUG_A,target%CPTR_PGIBUG_A)) + call this%return() +end function + +function atlas_Interpolation__config_funcspace_fieldset(config,source,target) result(this) + use atlas_Interpolation_c_binding + use atlas_Config_module, only : atlas_Config + use atlas_FunctionSpace_module, only : atlas_FunctionSpace + use atlas_FieldSet_module, only : atlas_FieldSet + type(atlas_Interpolation) :: this + type(atlas_Config), intent(in) :: config + class(atlas_FunctionSpace), intent(in) :: source + class(atlas_FieldSet), intent(in) :: target + this = atlas_Interpolation__cptr(atlas__interpolation__new_tgt_fieldset(config%CPTR_PGIBUG_B, & + source%CPTR_PGIBUG_A,target%CPTR_PGIBUG_A)) call this%return() end function @@ -72,7 +111,7 @@ subroutine execute_field(this,source,target) class(atlas_Interpolation), intent(in) :: this class(atlas_Field), intent(in) :: source class(atlas_Field), intent(inout) :: target - call atlas__Interpolation__execute_field(this%c_ptr(),source%c_ptr(),target%c_ptr()) + call atlas__Interpolation__execute_field(this%CPTR_PGIBUG_A,source%CPTR_PGIBUG_A,target%CPTR_PGIBUG_A) end subroutine subroutine execute_fieldset(this,source,target) @@ -81,7 +120,7 @@ subroutine execute_fieldset(this,source,target) class(atlas_Interpolation), intent(in) :: this class(atlas_FieldSet), intent(in) :: source class(atlas_FieldSet), intent(inout) :: target - call atlas__Interpolation__execute_fieldset(this%c_ptr(),source%c_ptr(),target%c_ptr()) + call atlas__Interpolation__execute_fieldset(this%CPTR_PGIBUG_A,source%CPTR_PGIBUG_A,target%CPTR_PGIBUG_A) end subroutine !------------------------------------------------------------------------------- diff --git a/src/atlas_f/mesh/atlas_Connectivity_module.F90 b/src/atlas_f/mesh/atlas_Connectivity_module.F90 index dbd637d2e..8cc56983c 100644 --- a/src/atlas_f/mesh/atlas_Connectivity_module.F90 +++ b/src/atlas_f/mesh/atlas_Connectivity_module.F90 @@ -1,18 +1,29 @@ +! (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_connectivity_module -use, intrinsic :: iso_c_binding, only : c_int, c_size_t, c_ptr, c_null_ptr +use, intrinsic :: iso_c_binding, only : c_int, c_ptr, c_null_ptr use fckit_owned_object_module, only : fckit_owned_object use fckit_object_module, only : fckit_object +use atlas_kinds_module, only : ATLAS_KIND_IDX +use atlas_allocate_module, only : atlas_allocate_managedmem, atlas_deallocate_managedmem implicit none private :: c_ptr private :: c_int -private :: c_size_t private :: c_null_ptr private :: fckit_owned_object private :: fckit_object +private :: atlas_allocate_managedmem +private :: atlas_deallocate_managedmem public :: atlas_Connectivity public :: atlas_MultiBlockConnectivity @@ -37,23 +48,34 @@ module atlas_connectivity_module ! Public methods procedure, public :: name => atlas_Connectivity__name - procedure, private :: value_args_int => atlas_Connectivity__value_args_int - procedure, private :: value_args_size_t => atlas_Connectivity__value_args_size_t - generic, public :: value => value_args_int, value_args_size_t + procedure, private :: value_args_int => atlas_Connectivity__value_args_int + procedure, private :: value_args_long => atlas_Connectivity__value_args_long + generic, public :: value => value_args_int, value_args_long procedure, public :: rows => atlas_Connectivity__rows procedure, public :: cols => atlas_Connectivity__cols procedure, public :: maxcols => atlas_Connectivity__maxcols procedure, public :: mincols => atlas_Connectivity__mincols procedure, public :: padded_data => atlas_Connectivity__padded_data - procedure, public :: data => atlas_Connectivity__data - procedure, public :: row => atlas_Connectivity__row + procedure, private :: atlas_Connectivity__data + procedure, private :: atlas_Connectivity__data_int + procedure, private :: atlas_Connectivity__data_long + generic, public :: data => atlas_Connectivity__data, atlas_Connectivity__data_int, atlas_Connectivity__data_long + procedure, private :: atlas_Connectivity__row_int + procedure, private :: atlas_Connectivity__row_long + generic, public :: row => atlas_Connectivity__row_int, atlas_Connectivity__row_long procedure, public :: missing_value => atlas_Connectivity__missing_value - procedure, private :: add_values_args_int => atlas_Connectivity__add_values_args_int - procedure, private :: add_values_args_size_t => atlas_Connectivity__add_values_args_size_t + procedure, private :: add_values_args_idx => atlas_Connectivity__add_values_args_idx +#if ATLAS_BITS_LOCAL != 32 + procedure, private :: add_values_args_int32 => atlas_Connectivity__add_values_args_int32 +#define _add_values_args_int32 , add_values_args_int32 +#else +#define _add_values_args_int32 +#endif + procedure, private :: add_values_args_long => atlas_Connectivity__add_values_args_long procedure, private :: add_missing_args_int => atlas_Connectivity__add_missing_args_int - procedure, private :: add_missing_args_size_t => atlas_Connectivity__add_missing_args_size_t - generic, public :: add => add_values_args_int, add_values_args_size_t, add_missing_args_int, add_missing_args_size_t - + procedure, private :: add_missing_args_long => atlas_Connectivity__add_missing_args_long + generic, public :: add => add_values_args_idx, add_values_args_long, add_missing_args_int, & + & add_missing_args_long _add_values_args_int32 #if FCKIT_FINAL_NOT_INHERITING final :: atlas_Connectivity__final_auto #endif @@ -111,19 +133,19 @@ module atlas_connectivity_module !------------------------------- type :: atlas_ConnectivityAccessRow - integer, pointer :: col(:) + integer(ATLAS_KIND_IDX), pointer :: col(:) contains end type type :: atlas_ConnectivityAccess - integer(c_int), private, pointer :: values_(:) => null() - integer(c_size_t), private, pointer :: displs_(:) => null() - integer(c_size_t), public, pointer :: cols(:) => null() + integer(ATLAS_KIND_IDX), private, pointer :: values_(:) => null() + integer(ATLAS_KIND_IDX), private, pointer :: displs_(:) => null() + integer(ATLAS_KIND_IDX), public, pointer :: cols(:) => null() type(atlas_ConnectivityAccessRow), public, pointer :: row(:) => null() - integer(c_size_t), private :: rows_ - integer, private, pointer :: padded_(:,:) => null() - integer(c_size_t), private :: maxcols_, mincols_ - integer(c_int), private :: missing_value_ + integer(ATLAS_KIND_IDX), private :: rows_ + integer(ATLAS_KIND_IDX), private, pointer :: padded_(:,:) => null() + integer(ATLAS_KIND_IDX), private :: maxcols_, mincols_ + integer(ATLAS_KIND_IDX), private :: missing_value_ type(c_ptr), private :: connectivity_ptr = c_null_ptr contains procedure, public :: rows => access_rows @@ -196,7 +218,7 @@ function Connectivity_constructor(name) result(this) call this%reset_c_ptr( atlas__Connectivity__create() ) call this%set_access() if( present(name) ) then - call atlas__Connectivity__rename(this%c_ptr(),c_str(name)) + call atlas__Connectivity__rename(this%CPTR_PGIBUG_A,c_str(name)) endif call this%return() end function @@ -209,15 +231,15 @@ function atlas_Connectivity__name(this) result(name) class(atlas_Connectivity), intent(in) :: this character(len=:), allocatable :: name type(c_ptr) :: name_c_str - name_c_str = atlas__Connectivity__name(this%c_ptr()) + name_c_str = atlas__Connectivity__name(this%CPTR_PGIBUG_A) name = c_ptr_to_string(name_c_str) end function pure function access_value(this,c,r) result(val) - use, intrinsic :: iso_c_binding, only : c_int, c_size_t - integer(c_int) :: val + use, intrinsic :: iso_c_binding, only : c_int + integer(ATLAS_KIND_IDX) :: val class(atlas_ConnectivityAccess), intent(in) :: this - integer(c_size_t), intent(in) :: r,c + integer(ATLAS_KIND_IDX), intent(in) :: r,c val = this%values_(c+this%displs_(r)) end function @@ -228,134 +250,188 @@ pure function access_rows(this) result(val) val = this%rows_ end function -pure function atlas_Connectivity__value_args_size_t(this,c,r) result(val) - use, intrinsic :: iso_c_binding, only : c_size_t, c_int - integer(c_int) :: val +pure function atlas_Connectivity__value_args_long(this,c,r) result(val) + use, intrinsic :: iso_c_binding, only : c_long + integer(ATLAS_KIND_IDX) :: val class(atlas_Connectivity), intent(in) :: this - integer(c_size_t), intent(in) :: r,c + integer(c_long), intent(in) :: r,c val = this%access%values_(c+this%access%displs_(r)) end function pure function atlas_Connectivity__value_args_int(this,c,r) result(val) use, intrinsic :: iso_c_binding, only : c_int - integer(c_int) :: val + integer(ATLAS_KIND_IDX) :: val class(atlas_Connectivity), intent(in) :: this integer(c_int), intent(in) :: r,c val = this%access%values_(c+this%access%displs_(r)) end function pure function atlas_Connectivity__rows(this) result(val) - use, intrinsic :: iso_c_binding, only : c_size_t - integer(c_size_t) :: val + integer(ATLAS_KIND_IDX) :: val class(atlas_Connectivity), intent(in) :: this val = this%access%rows_ end function function atlas_Connectivity__missing_value(this) result(val) use atlas_connectivity_c_binding - integer(c_int) :: val + integer(ATLAS_KIND_IDX) :: val class(atlas_Connectivity), intent(in) :: this - val = atlas__Connectivity__missing_value(this%c_ptr()) + val = atlas__Connectivity__missing_value(this%CPTR_PGIBUG_A) end function pure function atlas_Connectivity__cols(this,r) result(val) - use, intrinsic :: iso_c_binding, only : c_size_t - integer(c_size_t) :: val + integer(ATLAS_KIND_IDX) :: val class(atlas_Connectivity), intent(in) :: this - integer(c_size_t), intent(in) :: r - val = this%access%cols(r) + integer(c_int), intent(in) :: r + val = this%access%cols(r) end function pure function atlas_Connectivity__mincols(this) result(val) - use, intrinsic :: iso_c_binding, only : c_size_t - integer(c_size_t) :: val + integer(ATLAS_KIND_IDX) :: val class(atlas_Connectivity), intent(in) :: this val = this%access%mincols_ end function pure function atlas_Connectivity__maxcols(this) result(val) - use, intrinsic :: iso_c_binding, only : c_size_t - integer(c_size_t) :: val + integer(ATLAS_KIND_IDX) :: val class(atlas_Connectivity), intent(in) :: this val = this%access%maxcols_ end function subroutine atlas_Connectivity__padded_data(this, padded, cols) - use, intrinsic :: iso_c_binding, only : c_int, c_size_t + use, intrinsic :: iso_c_binding, only : c_int class(atlas_Connectivity), intent(inout) :: this - integer(c_int), pointer, intent(inout) :: padded(:,:) - integer(c_size_t), pointer, intent(inout), optional :: cols(:) + integer(ATLAS_KIND_IDX), pointer, intent(inout) :: padded(:,:) + integer(ATLAS_KIND_IDX), pointer, intent(inout), optional :: cols(:) if( .not. associated(this%access%padded_) ) call update_padded(this%access) padded => this%access%padded_ if( present(cols) ) cols => this%access%cols end subroutine -function c_loc_int32(x) +function c_loc_idx(x) use, intrinsic :: iso_c_binding - integer(c_int), target :: x - type(c_ptr) :: c_loc_int32 - c_loc_int32 = c_loc(x) + integer(ATLAS_KIND_IDX), target :: x + type(c_ptr) :: c_loc_idx + c_loc_idx = c_loc(x) end function -subroutine atlas_Connectivity__data(this, data, ncols) - use, intrinsic :: iso_c_binding, only : c_int, c_f_pointer, c_loc +subroutine atlas_Connectivity__data(this, data) + use, intrinsic :: iso_c_binding, only : c_f_pointer, c_loc, c_int + class(atlas_Connectivity), intent(in) :: this + integer(ATLAS_KIND_IDX), pointer, intent(inout) :: data(:,:) + integer(ATLAS_KIND_IDX) :: maxcols + + maxcols = this%maxcols() + if( maxcols == this%mincols() ) then + if( size(this%access%values_) > 0 ) then + call c_f_pointer (c_loc_idx(this%access%values_(1)), data, & + & (/maxcols,this%access%rows_/)) + endif + else + write(0,*) "ERROR: Cannot point connectivity pointer data(:,:) to irregular table" + endif +end subroutine + +subroutine atlas_Connectivity__data_int(this, data, ncols) + use, intrinsic :: iso_c_binding, only : c_f_pointer, c_loc, c_int class(atlas_Connectivity), intent(in) :: this - integer(c_int), pointer, intent(inout) :: data(:,:) - integer(c_int), intent(out), optional :: ncols - integer(c_int) :: maxcols + integer(ATLAS_KIND_IDX), pointer, intent(inout) :: data(:,:) + integer(c_int), intent(out) :: ncols + integer(ATLAS_KIND_IDX) :: maxcols maxcols = this%maxcols() if( maxcols == this%mincols() ) then if( size(this%access%values_) > 0 ) then - call c_f_pointer (c_loc_int32(this%access%values_(1)), data, & - & (/maxcols,int(this%access%rows_,c_int)/)) - if( present(ncols) ) then - ncols = maxcols - endif + call c_f_pointer (c_loc_idx(this%access%values_(1)), data, & + & (/maxcols,this%access%rows_/)) + ncols = maxcols endif else write(0,*) "ERROR: Cannot point connectivity pointer data(:,:) to irregular table" endif end subroutine +subroutine atlas_Connectivity__data_long(this, data, ncols) + use, intrinsic :: iso_c_binding, only : c_f_pointer, c_loc, c_long + class(atlas_Connectivity), intent(in) :: this + integer(ATLAS_KIND_IDX), pointer, intent(inout) :: data(:,:) + integer(c_long), intent(out) :: ncols + integer(ATLAS_KIND_IDX) :: maxcols -subroutine atlas_Connectivity__row(this, row_idx, row, cols) + maxcols = this%maxcols() + if( maxcols == this%mincols() ) then + if( size(this%access%values_) > 0 ) then + call c_f_pointer (c_loc_idx(this%access%values_(1)), data, & + & (/maxcols,this%access%rows_/)) + ncols = maxcols + endif + else + write(0,*) "ERROR: Cannot point connectivity pointer data(:,:) to irregular table" + endif +end subroutine + +subroutine atlas_Connectivity__row_int(this, row_idx, row, cols) use, intrinsic :: iso_c_binding, only : c_int class(atlas_Connectivity), intent(in) :: this integer(c_int), intent(in) :: row_idx - integer(c_int), pointer, intent(inout) :: row(:) + integer(ATLAS_KIND_IDX), pointer, intent(inout) :: row(:) integer(c_int), intent(out) :: cols row => this%access%values_(this%access%displs_(row_idx)+1:this%access%displs_(row_idx+1)+1) cols = this%access%cols(row_idx) end subroutine -subroutine atlas_Connectivity__add_values_args_size_t(this,rows,cols,values) +subroutine atlas_Connectivity__row_long(this, row_idx, row, cols) + use, intrinsic :: iso_c_binding, only : c_long + class(atlas_Connectivity), intent(in) :: this + integer(c_long), intent(in) :: row_idx + integer(ATLAS_KIND_IDX), pointer, intent(inout) :: row(:) + integer(c_long), intent(out) :: cols + row => this%access%values_(this%access%displs_(row_idx)+1:this%access%displs_(row_idx+1)+1) + cols = this%access%cols(row_idx) +end subroutine + +subroutine atlas_Connectivity__add_values_args_long(this,rows,cols,values) use atlas_connectivity_c_binding - use, intrinsic :: iso_c_binding, only : c_size_t, c_int + use, intrinsic :: iso_c_binding, only : c_long class(atlas_Connectivity), intent(in) :: this - integer(c_size_t) :: rows - integer(c_size_t) :: cols - integer(c_int) :: values(:) - call atlas__connectivity__add_values(this%c_ptr(),rows,cols,values) + integer(c_long), intent(in) :: rows + integer(c_long), intent(in) :: cols + integer(ATLAS_KIND_IDX) :: values(:) + call atlas__connectivity__add_values(this%CPTR_PGIBUG_A,int(rows,ATLAS_KIND_IDX),int(cols,ATLAS_KIND_IDX),values) end subroutine -subroutine atlas_Connectivity__add_values_args_int(this,rows,cols,values) +subroutine atlas_Connectivity__add_values_args_idx(this,rows,cols,values) use atlas_connectivity_c_binding use, intrinsic :: iso_c_binding, only : c_int class(atlas_Connectivity), intent(in) :: this - integer(c_int) :: rows - integer(c_int) :: cols - integer(c_int) :: values(:) - call atlas__connectivity__add_values(this%c_ptr(),int(rows,c_size_t),int(cols,c_size_t),values) + integer(c_int), intent(in) :: rows + integer(c_int), intent(in) :: cols + integer(ATLAS_KIND_IDX), intent(in) :: values(:) + call atlas__connectivity__add_values(this%CPTR_PGIBUG_A,int(rows,ATLAS_KIND_IDX),int(cols,ATLAS_KIND_IDX),values) end subroutine -subroutine atlas_Connectivity__add_missing_args_size_t(this,rows,cols) +#if ATLAS_BITS_LOCAL != 32 +subroutine atlas_Connectivity__add_values_args_int32(this,rows,cols,values) use atlas_connectivity_c_binding - use, intrinsic :: iso_c_binding, only : c_size_t + use, intrinsic :: iso_c_binding, only : c_int class(atlas_Connectivity), intent(in) :: this - integer(c_size_t) :: rows - integer(c_size_t) :: cols - call atlas__connectivity__add_missing(this%c_ptr(),rows,cols) + integer(c_int), intent(in) :: rows + integer(c_int), intent(in) :: cols + integer(c_int), intent(in) :: values(:) + integer(ATLAS_KIND_IDX) :: idx_values(rows*cols) + idx_values(:) = values(:) + call atlas__connectivity__add_values(this%CPTR_PGIBUG_A,int(rows,ATLAS_KIND_IDX),int(cols,ATLAS_KIND_IDX),idx_values) +end subroutine +#endif + + +subroutine atlas_Connectivity__add_missing_args_long(this,rows,cols) + use atlas_connectivity_c_binding + use, intrinsic :: iso_c_binding, only : c_long + class(atlas_Connectivity), intent(in) :: this + integer(c_long) :: rows + integer(c_long) :: cols + call atlas__connectivity__add_missing(this%CPTR_PGIBUG_A,int(rows,ATLAS_KIND_IDX),int(cols,ATLAS_KIND_IDX)) end subroutine subroutine atlas_Connectivity__add_missing_args_int(this,rows,cols) @@ -364,7 +440,7 @@ subroutine atlas_Connectivity__add_missing_args_int(this,rows,cols) class(atlas_Connectivity), intent(in) :: this integer(c_int) :: rows integer(c_int) :: cols - call atlas__connectivity__add_missing(this%c_ptr(),int(rows,c_size_t),int(cols,c_size_t)) + call atlas__connectivity__add_missing(this%CPTR_PGIBUG_A,int(rows,ATLAS_KIND_IDX),int(cols,ATLAS_KIND_IDX)) end subroutine !======================================================== @@ -387,26 +463,25 @@ function MultiBlockConnectivity_constructor(name) result(this) call this%reset_c_ptr( atlas__MultiBlockConnectivity__create() ) call this%set_access() if( present(name) ) then - call atlas__Connectivity__rename(this%c_ptr(),c_str(name)) + call atlas__Connectivity__rename(this%CPTR_PGIBUG_A,c_str(name)) endif call this%return() end function function atlas_MultiBlockConnectivity__blocks(this) result(val) use atlas_connectivity_c_binding - use, intrinsic :: iso_c_binding, only : c_size_t - integer(c_size_t) :: val + integer(ATLAS_KIND_IDX) :: val class(atlas_MultiBlockConnectivity), intent(in) :: this - val = atlas__MultiBlockConnectivity__blocks(this%c_ptr()) + val = atlas__MultiBlockConnectivity__blocks(this%CPTR_PGIBUG_A) end function function atlas_MultiBlockConnectivity__block(this,block_idx) result(block) use atlas_connectivity_c_binding - use, intrinsic :: iso_c_binding, only : c_size_t type(atlas_BlockConnectivity) :: block class(atlas_MultiBlockConnectivity), intent(in) :: this - integer(c_size_t) :: block_idx - call block%reset_c_ptr( atlas__MultiBlockConnectivity__block(this%c_ptr(),block_idx-1) ) + integer(ATLAS_KIND_IDX) :: block_idx + call block%reset_c_ptr( atlas__MultiBlockConnectivity__block( & + this%CPTR_PGIBUG_A,int(block_idx-1_ATLAS_KIND_IDX,ATLAS_KIND_IDX) ) ) end function !======================================================== @@ -421,38 +496,35 @@ function BlockConnectivity_cptr(cptr) result(this) subroutine atlas_BlockConnectivity__data(this,data) use atlas_connectivity_c_binding - use, intrinsic :: iso_c_binding, only : c_int, c_ptr, c_size_t, c_f_pointer + use, intrinsic :: iso_c_binding, only : c_int, c_ptr, c_f_pointer class(atlas_BlockConnectivity), intent(in) :: this - integer(c_int), pointer, intent(inout) :: data(:,:) + integer(ATLAS_KIND_IDX), pointer, intent(inout) :: data(:,:) type(c_ptr) :: data_cptr - integer(c_size_t) :: rows - integer(c_size_t) :: cols - call atlas__BlockConnectivity__data(this%c_ptr(),data_cptr,rows,cols) + integer(ATLAS_KIND_IDX) :: rows + integer(ATLAS_KIND_IDX) :: cols + call atlas__BlockConnectivity__data(this%CPTR_PGIBUG_A,data_cptr,rows,cols) call c_f_pointer (data_cptr, data, [cols,rows]) end subroutine function atlas_BlockConnectivity__rows(this) result(val) use atlas_connectivity_c_binding - use, intrinsic :: iso_c_binding, only : c_size_t - integer(c_size_t) :: val + integer(ATLAS_KIND_IDX) :: val class(atlas_BlockConnectivity), intent(in) :: this - val = atlas__BlockConnectivity__rows(this%c_ptr()) + val = atlas__BlockConnectivity__rows(this%CPTR_PGIBUG_A) end function function atlas_BlockConnectivity__cols(this) result(val) use atlas_connectivity_c_binding - use, intrinsic :: iso_c_binding, only : c_size_t - integer(c_size_t) :: val + integer(ATLAS_KIND_IDX) :: val class(atlas_BlockConnectivity), intent(in) :: this - val = atlas__BlockConnectivity__cols(this%c_ptr()) + val = atlas__BlockConnectivity__cols(this%CPTR_PGIBUG_A) end function function atlas_BlockConnectivity__missing_value(this) result(val) use atlas_connectivity_c_binding - use, intrinsic :: iso_c_binding, only : c_int - integer(c_int) :: val + integer(ATLAS_KIND_IDX) :: val class(atlas_BlockConnectivity), intent(in) :: this - val = atlas__BlockConnectivity__missing_value(this%c_ptr()) + 1 + val = atlas__BlockConnectivity__missing_value(this%CPTR_PGIBUG_A) + 1 end function !======================================================== @@ -462,16 +534,16 @@ subroutine set_access(this) class(atlas_Connectivity), intent(inout) :: this type(c_ptr) :: ctxt integer(c_int) :: have_ctxt - have_ctxt = atlas__connectivity__ctxt(this%c_ptr(),ctxt) + have_ctxt = atlas__connectivity__ctxt(this%CPTR_PGIBUG_A,ctxt) if( have_ctxt == 1 ) then call c_f_pointer(ctxt,this%access) else allocate( this%access ) - call atlas__connectivity__register_ctxt ( this%c_ptr(), c_loc(this%access) ) - call atlas__connectivity__register_update( this%c_ptr(), c_funloc(update_access_c) ) - call atlas__connectivity__register_delete( this%c_ptr(), c_funloc(delete_access_c) ) + call atlas__connectivity__register_ctxt ( this%CPTR_PGIBUG_A, c_loc(this%access) ) + call atlas__connectivity__register_update( this%CPTR_PGIBUG_A, c_funloc(update_access_c) ) + call atlas__connectivity__register_delete( this%CPTR_PGIBUG_A, c_funloc(delete_access_c) ) - this%access%connectivity_ptr = this%c_ptr() + this%access%connectivity_ptr = this%CPTR_PGIBUG_A call update_access(this%access) endif end subroutine @@ -486,16 +558,16 @@ subroutine update_access_c(this_ptr) bind(c) subroutine update_access(this) use atlas_connectivity_c_binding - use, intrinsic :: iso_c_binding, only : c_ptr, c_size_t, c_f_pointer + use, intrinsic :: iso_c_binding, only : c_ptr, c_f_pointer type(atlas_ConnectivityAccess), intent(inout) :: this integer :: jrow type(c_ptr) :: values_cptr type(c_ptr) :: displs_cptr type(c_ptr) :: counts_cptr - integer(c_size_t) :: values_size - integer(c_size_t) :: displs_size - integer(c_size_t) :: counts_size + integer(ATLAS_KIND_IDX) :: values_size + integer(ATLAS_KIND_IDX) :: displs_size + integer(ATLAS_KIND_IDX) :: counts_size this%missing_value_ = atlas__Connectivity__missing_value(this%connectivity_ptr) call atlas__Connectivity__values(this%connectivity_ptr,values_cptr,values_size) @@ -519,11 +591,10 @@ subroutine update_access(this) end subroutine subroutine update_padded(this) - use, intrinsic :: iso_c_binding, only : c_size_t class(atlas_ConnectivityAccess), intent(inout) :: this - integer(c_size_t) :: jrow, jcol - if( associated(this%padded_) ) deallocate(this%padded_) - allocate(this%padded_(this%maxcols_,this%rows())) + integer(ATLAS_KIND_IDX) :: jrow, jcol + if( associated(this%padded_) ) call atlas_deallocate_managedmem( this%padded_ ) + call atlas_allocate_managedmem( this%padded_, [this%maxcols_,this%rows()] ) this%padded_(:,:) = this%missing_value_ do jrow=1,this%rows() do jcol=1,this%cols(jrow) @@ -545,7 +616,7 @@ subroutine delete_access(this) use atlas_connectivity_c_binding type(atlas_ConnectivityAccess), intent(inout) :: this if( associated( this%row ) ) deallocate(this%row) - if( associated( this%padded_) ) deallocate(this%padded_) + if( associated( this%padded_) ) call atlas_deallocate_managedmem(this%padded_) end subroutine !------------------------------------------------------------------------------- diff --git a/src/atlas_f/mesh/atlas_ElementType_module.F90 b/src/atlas_f/mesh/atlas_ElementType_module.F90 index 2f10c5e75..f5ad2c05b 100644 --- a/src/atlas_f/mesh/atlas_ElementType_module.F90 +++ b/src/atlas_f/mesh/atlas_ElementType_module.F90 @@ -1,9 +1,17 @@ +! (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_ElementType_module use fckit_owned_object_module, only : fckit_owned_object - +use atlas_kinds_module, only : ATLAS_KIND_IDX implicit none private :: fckit_owned_object @@ -83,19 +91,17 @@ function atlas_Line__constructor() result(this) end function function nb_nodes(this) - use, intrinsic :: iso_c_binding, only : c_size_t use atlas_elementtype_c_binding - integer(c_size_t) :: nb_nodes + integer(ATLAS_KIND_IDX) :: nb_nodes class(atlas_ElementType), intent(in) :: this - nb_nodes = atlas__mesh__ElementType__nb_nodes(this%c_ptr()) + nb_nodes = atlas__mesh__ElementType__nb_nodes(this%CPTR_PGIBUG_A) end function function nb_edges(this) - use, intrinsic :: iso_c_binding, only : c_size_t use atlas_elementtype_c_binding - integer(c_size_t) :: nb_edges + integer(ATLAS_KIND_IDX) :: nb_edges class(atlas_ElementType), intent(in) :: this - nb_edges = atlas__mesh__ElementType__nb_edges(this%c_ptr()) + nb_edges = atlas__mesh__ElementType__nb_edges(this%CPTR_PGIBUG_A) end function function name(this) @@ -105,7 +111,7 @@ function name(this) character(len=:), allocatable :: name class(atlas_ElementType) :: this type(c_ptr) :: name_c_str - name_c_str = atlas__mesh__ElementType__name(this%c_ptr()) + name_c_str = atlas__mesh__ElementType__name(this%CPTR_PGIBUG_A) name = c_ptr_to_string(name_c_str) end function @@ -115,7 +121,7 @@ function parametric(this) logical :: parametric class(atlas_ElementType), intent(in) :: this integer(c_int) :: parametric_int - parametric_int = atlas__mesh__ElementType__parametric(this%c_ptr()) + parametric_int = atlas__mesh__ElementType__parametric(this%CPTR_PGIBUG_A) if( parametric_int == 0 ) then parametric = .False. else diff --git a/src/atlas_f/mesh/atlas_Elements_module.F90 b/src/atlas_f/mesh/atlas_Elements_module.F90 index 8961b2b5a..7022bf3d3 100644 --- a/src/atlas_f/mesh/atlas_Elements_module.F90 +++ b/src/atlas_f/mesh/atlas_Elements_module.F90 @@ -1,8 +1,17 @@ +! (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_Elements_module use fckit_owned_object_module, only: fckit_owned_object +use atlas_kinds_module, only : ATLAS_KIND_IDX implicit none @@ -27,8 +36,8 @@ module atlas_Elements_module procedure, public :: edge_connectivity procedure, public :: cell_connectivity - generic, public :: add => add_elements_size_t, add_elements_int - generic, public :: field => field_by_idx_size_t, field_by_idx_int, field_by_name + generic, public :: add => add_elements_long, add_elements_int + generic, public :: field => field_by_idx_long, field_by_idx_int, field_by_name procedure, public :: element_type @@ -41,9 +50,9 @@ module atlas_Elements_module ! Private methods procedure, private :: field_by_idx_int - procedure, private :: field_by_idx_size_t + procedure, private :: field_by_idx_long procedure, private :: field_by_name - procedure, private :: add_elements_size_t + procedure, private :: add_elements_long procedure, private :: add_elements_int #if FCKIT_FINAL_NOT_INHERITING @@ -69,11 +78,10 @@ function atlas_Elements__cptr(cptr) result(this) end function function atlas_Elements__size(this) result(val) - use, intrinsic :: iso_c_binding, only: c_size_t use atlas_elements_c_binding - integer(c_size_t) :: val + integer(ATLAS_KIND_IDX) :: val class(atlas_Elements), intent(in) :: this - val = atlas__mesh__Elements__size(this%c_ptr()) + val = atlas__mesh__Elements__size(this%CPTR_PGIBUG_A) end function function node_connectivity(this) result(connectivity) @@ -82,7 +90,7 @@ function node_connectivity(this) result(connectivity) class(atlas_Elements), intent(in) :: this type(atlas_BlockConnectivity) :: connectivity connectivity = atlas_BlockConnectivity( & - atlas__mesh__Elements__node_connectivity(this%c_ptr()) ) + atlas__mesh__Elements__node_connectivity(this%CPTR_PGIBUG_A) ) !call connectivity%return() end function @@ -92,7 +100,7 @@ function edge_connectivity(this) result(connectivity) class(atlas_Elements), intent(in) :: this type(atlas_BlockConnectivity) :: connectivity connectivity = atlas_BlockConnectivity( & - atlas__mesh__Elements__edge_connectivity(this%c_ptr()) ) + atlas__mesh__Elements__edge_connectivity(this%CPTR_PGIBUG_A) ) !call connectivity%return() end function @@ -102,7 +110,7 @@ function cell_connectivity(this) result(connectivity) class(atlas_Elements), intent(in) :: this type(atlas_BlockConnectivity) :: connectivity connectivity = atlas_BlockConnectivity( & - atlas__mesh__Elements__cell_connectivity(this%c_ptr()) ) + atlas__mesh__Elements__cell_connectivity(this%CPTR_PGIBUG_A) ) !call connectivity%return() end function @@ -112,32 +120,31 @@ function element_type(this) result(etype) class(atlas_Elements), intent(in) :: this type(atlas_ElementType) :: etype etype = atlas_ElementType( & - atlas__mesh__Elements__element_type(this%c_ptr()) ) + atlas__mesh__Elements__element_type(this%CPTR_PGIBUG_A) ) call etype%return() end function -subroutine add_elements_size_t(this,nb_elements) - use, intrinsic :: iso_c_binding, only: c_size_t +subroutine add_elements_long(this,nb_elements) + use, intrinsic :: iso_c_binding, only: c_long, c_int use atlas_elements_c_binding class(atlas_Elements), intent(inout) :: this - integer(c_size_t) :: nb_elements - call atlas__mesh__Elements__add(this%c_ptr(),nb_elements) + integer(c_long) :: nb_elements + call atlas__mesh__Elements__add(this%CPTR_PGIBUG_A,int(nb_elements,ATLAS_KIND_IDX)) end subroutine subroutine add_elements_int(this,nb_elements) - use, intrinsic :: iso_c_binding, only: c_size_t, c_int + use, intrinsic :: iso_c_binding, only: c_int use atlas_elements_c_binding class(atlas_Elements), intent(inout) :: this integer(c_int) :: nb_elements - call atlas__mesh__Elements__add(this%c_ptr(),int(nb_elements,c_size_t)) + call atlas__mesh__Elements__add(this%CPTR_PGIBUG_A,int(nb_elements,ATLAS_KIND_IDX)) end subroutine function nb_fields(this) result(val) - use, intrinsic :: iso_c_binding, only: c_size_t use atlas_elements_c_binding - integer(c_size_t) :: val + integer(ATLAS_KIND_IDX) :: val class(atlas_Elements), intent(in) :: this - val = atlas__mesh__Elements__nb_fields(this%c_ptr()) + val = atlas__mesh__Elements__nb_fields(this%CPTR_PGIBUG_A) end function function has_field(this,name) result(val) @@ -146,7 +153,7 @@ function has_field(this,name) result(val) logical :: val class(atlas_Elements), intent(in) :: this character(len=*), intent(in) :: name - if( atlas__mesh__Elements__has_field(this%c_ptr(),c_str(name)) == 0 ) then + if( atlas__mesh__Elements__has_field(this%CPTR_PGIBUG_A,c_str(name)) == 0 ) then val = .False. else val = .True. @@ -160,29 +167,29 @@ function field_by_name(this,name) result(field) type(atlas_Field) :: field class(atlas_Elements), intent(in) :: this character(len=*), intent(in) :: name - field = atlas_Field( atlas__mesh__Elements__field_by_name(this%c_ptr(),c_str(name)) ) + field = atlas_Field( atlas__mesh__Elements__field_by_name(this%CPTR_PGIBUG_A,c_str(name)) ) call field%return() end function -function field_by_idx_size_t(this,idx) result(field) - use, intrinsic :: iso_c_binding, only: c_size_t +function field_by_idx_long(this,idx) result(field) + use, intrinsic :: iso_c_binding, only: c_long use atlas_elements_c_binding use atlas_Field_module, only: atlas_Field type(atlas_Field) :: field class(atlas_Elements), intent(in) :: this - integer(c_size_t), intent(in) :: idx - field = atlas_Field( atlas__mesh__Elements__field_by_idx(this%c_ptr(),idx-1_c_size_t) ) + integer(c_long), intent(in) :: idx + field = atlas_Field( atlas__mesh__Elements__field_by_idx(this%CPTR_PGIBUG_A,int(idx-1_c_long,ATLAS_KIND_IDX) ) ) call field%return() end function function field_by_idx_int(this,idx) result(field) - use, intrinsic :: iso_c_binding, only: c_size_t, c_int + use, intrinsic :: iso_c_binding, only: c_int use atlas_elements_c_binding use atlas_Field_module, only: atlas_Field type(atlas_Field) :: field class(atlas_Elements), intent(in) :: this integer(c_int), intent(in) :: idx - field = atlas_Field( atlas__mesh__Elements__field_by_idx(this%c_ptr(),int(idx-1,c_size_t)) ) + field = atlas_Field( atlas__mesh__Elements__field_by_idx(this%CPTR_PGIBUG_A,int(idx-1_c_int,ATLAS_KIND_IDX) ) ) call field%return() end function @@ -191,7 +198,7 @@ function global_index(this) result(field) use atlas_Field_module, only: atlas_Field type(atlas_Field) :: field class(atlas_Elements), intent(in) :: this - field = atlas_Field( atlas__mesh__Elements__global_index(this%c_ptr()) ) + field = atlas_Field( atlas__mesh__Elements__global_index(this%CPTR_PGIBUG_A) ) call field%return() end function @@ -200,7 +207,7 @@ function remote_index(this) result(field) use atlas_Field_module, only: atlas_Field type(atlas_Field) :: field class(atlas_Elements), intent(in) :: this - field = atlas_Field( atlas__mesh__Elements__remote_index(this%c_ptr()) ) + field = atlas_Field( atlas__mesh__Elements__remote_index(this%CPTR_PGIBUG_A) ) call field%return() end function @@ -209,7 +216,7 @@ function partition(this) result(field) use atlas_Field_module, only: atlas_Field type(atlas_Field) :: field class(atlas_Elements), intent(in) :: this - field = atlas_Field( atlas__mesh__Elements__partition(this%c_ptr()) ) + field = atlas_Field( atlas__mesh__Elements__partition(this%CPTR_PGIBUG_A) ) call field%return() end function @@ -218,24 +225,22 @@ function halo(this) result(field) use atlas_Field_module, only: atlas_Field type(atlas_Field) :: field class(atlas_Elements), intent(in) :: this - field = atlas_Field( atlas__mesh__Elements__halo(this%c_ptr()) ) + field = atlas_Field( atlas__mesh__Elements__halo(this%CPTR_PGIBUG_A) ) call field%return() end function function atlas_Elements__begin(this) result(val) - use, intrinsic :: iso_c_binding, only: c_size_t use atlas_elements_c_binding - integer(c_size_t) :: val + integer(ATLAS_KIND_IDX) :: val class(atlas_Elements), intent(in) :: this - val = atlas__mesh__Elements__begin(this%c_ptr()) + 1 + val = atlas__mesh__Elements__begin(this%CPTR_PGIBUG_A) + 1 end function function atlas_Elements__end(this) result(val) - use, intrinsic :: iso_c_binding, only: c_size_t use atlas_elements_c_binding - integer(c_size_t) :: val + integer(ATLAS_KIND_IDX) :: val class(atlas_Elements), intent(in) :: this - val = atlas__mesh__Elements__end(this%c_ptr()) + val = atlas__mesh__Elements__end(this%CPTR_PGIBUG_A) end function !------------------------------------------------------------------------------- diff --git a/src/atlas_f/mesh/atlas_HybridElements_module.F90 b/src/atlas_f/mesh/atlas_HybridElements_module.F90 index f6f9f719e..f8f312c90 100644 --- a/src/atlas_f/mesh/atlas_HybridElements_module.F90 +++ b/src/atlas_f/mesh/atlas_HybridElements_module.F90 @@ -1,3 +1,11 @@ +! (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_HybridElements_module @@ -7,6 +15,7 @@ module atlas_HybridElements_module use atlas_Field_module, only: atlas_Field use atlas_ElementType_module, only: atlas_ElementType use atlas_Elements_module, only: atlas_Elements +use atlas_kinds_module, only: ATLAS_KIND_IDX implicit none @@ -34,11 +43,17 @@ module atlas_HybridElements_module procedure, public :: edge_connectivity procedure, public :: cell_connectivity - generic, public :: add => add_elements, add_elements_with_nodes, add_field - - generic, public :: field => field_by_idx_size_t, field_by_idx_int, field_by_name +#if ATLAS_BITS_LOCAL != 32 + generic, public :: add => add_elements_int, add_elements_long, add_elements_with_nodes_int, & + & add_elements_with_nodes_long, add_field, & + & add_elements_with_nodes_int_int32, add_elements_with_nodes_long_int32 +#else + generic, public :: add => add_elements_int, add_elements_long, add_elements_with_nodes_int, & + & add_elements_with_nodes_long, add_field +#endif + generic, public :: field => field_by_idx_long, field_by_idx_int, field_by_name - generic, public :: elements => elements_int, elements_size_t + generic, public :: elements => elements_int, elements_long procedure, public :: nb_fields procedure, public :: has_field @@ -50,15 +65,21 @@ module atlas_HybridElements_module procedure, public :: nb_types ! Private methods - procedure, private :: add_elements - procedure, private :: add_elements_with_nodes + procedure, private :: add_elements_int + procedure, private :: add_elements_long + procedure, private :: add_elements_with_nodes_int + procedure, private :: add_elements_with_nodes_long +#if ATLAS_BITS_LOCAL != 32 + procedure, private :: add_elements_with_nodes_int_int32 + procedure, private :: add_elements_with_nodes_long_int32 +#endif procedure, private :: add_field procedure, private :: field_by_idx_int - procedure, private :: field_by_idx_size_t + procedure, private :: field_by_idx_long procedure, private :: field_by_name procedure, private :: elements_int - procedure, private :: elements_size_t + procedure, private :: elements_long #if FCKIT_FINAL_NOT_INHERITING final :: atlas_HybridElements__final_auto @@ -94,9 +115,9 @@ function atlas_HybridElements__constructor() result(this) function atlas_HybridElements__size(this) result(val) use, intrinsic :: iso_c_binding use atlas_hybridelements_c_binding - integer(c_size_t) :: val + integer(ATLAS_KIND_IDX) :: val class(atlas_HybridElements), intent(in) :: this - val = atlas__mesh__HybridElements__size(this%c_ptr()) + val = atlas__mesh__HybridElements__size(this%CPTR_PGIBUG_A) end function function node_connectivity(this) result(connectivity) @@ -104,7 +125,7 @@ function node_connectivity(this) result(connectivity) class(atlas_HybridElements), intent(in) :: this type(atlas_MultiBlockConnectivity) :: connectivity connectivity = atlas_MultiBlockConnectivity( & - atlas__mesh__HybridElements__node_connectivity(this%c_ptr()) ) + atlas__mesh__HybridElements__node_connectivity(this%CPTR_PGIBUG_A) ) call connectivity%return() end function @@ -113,7 +134,7 @@ function edge_connectivity(this) result(connectivity) class(atlas_HybridElements), intent(in) :: this type(atlas_MultiBlockConnectivity) :: connectivity connectivity = atlas_MultiBlockConnectivity( & - atlas__mesh__HybridElements__edge_connectivity(this%c_ptr()) ) + atlas__mesh__HybridElements__edge_connectivity(this%CPTR_PGIBUG_A) ) call connectivity%return() end function @@ -122,52 +143,102 @@ function cell_connectivity(this) result(connectivity) class(atlas_HybridElements), intent(in) :: this type(atlas_MultiBlockConnectivity) :: connectivity connectivity = atlas_MultiBlockConnectivity( & - atlas__mesh__HybridElements__cell_connectivity(this%c_ptr()) ) + atlas__mesh__HybridElements__cell_connectivity(this%CPTR_PGIBUG_A) ) call connectivity%return() end function -subroutine add_elements(this,elementtype,nb_elements) +subroutine add_elements_int(this,elementtype,nb_elements) + use, intrinsic :: iso_c_binding + use atlas_hybridelements_c_binding + class(atlas_HybridElements), intent(inout) :: this + type(atlas_ElementType) :: elementtype + integer(c_int) :: nb_elements + call atlas__mesh__HybridElements__add_elements(this%CPTR_PGIBUG_A,elementtype%CPTR_PGIBUG_A,int(nb_elements,ATLAS_KIND_IDX)) +end subroutine + +subroutine add_elements_long(this,elementtype,nb_elements) use, intrinsic :: iso_c_binding use atlas_hybridelements_c_binding class(atlas_HybridElements), intent(inout) :: this type(atlas_ElementType) :: elementtype - integer(c_size_t) :: nb_elements - call atlas__mesh__HybridElements__add_elements(this%c_ptr(),elementtype%c_ptr(),nb_elements) + integer(c_long) :: nb_elements + call atlas__mesh__HybridElements__add_elements(this%CPTR_PGIBUG_A,elementtype%CPTR_PGIBUG_A,int(nb_elements,ATLAS_KIND_IDX)) +end subroutine + +subroutine add_elements_with_nodes_int(this,elementtype,nb_elements,node_connectivity) + use, intrinsic :: iso_c_binding + use atlas_hybridelements_c_binding + class(atlas_HybridElements), intent(inout) :: this + type(atlas_ElementType), intent(in) :: elementtype + integer(c_int), intent(in) :: nb_elements + integer(ATLAS_KIND_IDX), intent(in) :: node_connectivity(:) + call atlas__mesh__HybridElements__add_elements_with_nodes(this%CPTR_PGIBUG_A,& + & elementtype%CPTR_PGIBUG_A,int(nb_elements,ATLAS_KIND_IDX),node_connectivity,1) end subroutine -subroutine add_elements_with_nodes(this,elementtype,nb_elements,node_connectivity) +subroutine add_elements_with_nodes_long(this,elementtype,nb_elements,node_connectivity) use, intrinsic :: iso_c_binding use atlas_hybridelements_c_binding class(atlas_HybridElements), intent(inout) :: this type(atlas_ElementType), intent(in) :: elementtype - integer(c_size_t), intent(in) :: nb_elements + integer(c_long), intent(in) :: nb_elements + integer(ATLAS_KIND_IDX), intent(in) :: node_connectivity(:) + call atlas__mesh__HybridElements__add_elements_with_nodes(this%CPTR_PGIBUG_A,& + & elementtype%CPTR_PGIBUG_A,int(nb_elements,ATLAS_KIND_IDX),node_connectivity,1) +end subroutine + +#if ATLAS_BITS_LOCAL != 32 +subroutine add_elements_with_nodes_int_int32(this,elementtype,nb_elements,node_connectivity) + use, intrinsic :: iso_c_binding + use atlas_hybridelements_c_binding + class(atlas_HybridElements), intent(inout) :: this + type(atlas_ElementType), intent(in) :: elementtype + integer(c_int), intent(in) :: nb_elements + integer(c_int), intent(in) :: node_connectivity(:) + integer(ATLAS_KIND_IDX), allocatable :: idx_node_connectivity(:) + allocate( idx_node_connectivity( nb_elements * elementtype%nb_nodes() ) ) + idx_node_connectivity(:) = node_connectivity(:) + call atlas__mesh__HybridElements__add_elements_with_nodes(this%CPTR_PGIBUG_A,& + & elementtype%CPTR_PGIBUG_A,int(nb_elements,ATLAS_KIND_IDX),idx_node_connectivity,1) + deallocate( idx_node_connectivity ) +end subroutine + +subroutine add_elements_with_nodes_long_int32(this,elementtype,nb_elements,node_connectivity) + use, intrinsic :: iso_c_binding + use atlas_hybridelements_c_binding + class(atlas_HybridElements), intent(inout) :: this + type(atlas_ElementType), intent(in) :: elementtype + integer(c_long), intent(in) :: nb_elements integer(c_int), intent(in) :: node_connectivity(:) - call atlas__mesh__HybridElements__add_elements_with_nodes(this%c_ptr(),& - & elementtype%c_ptr(),nb_elements,node_connectivity,1) + integer(ATLAS_KIND_IDX), allocatable :: idx_node_connectivity(:) + allocate( idx_node_connectivity( nb_elements * elementtype%nb_nodes() ) ) + idx_node_connectivity(:) = node_connectivity(:) + call atlas__mesh__HybridElements__add_elements_with_nodes(this%CPTR_PGIBUG_A,& + & elementtype%CPTR_PGIBUG_A,int(nb_elements,ATLAS_KIND_IDX),idx_node_connectivity,1) + deallocate( idx_node_connectivity ) end subroutine +#endif subroutine add_field(this,field) use atlas_hybridelements_c_binding class(atlas_HybridElements), intent(inout) :: this type(atlas_Field), intent(in) :: field - call atlas__mesh__HybridElements__add_field(this%c_ptr(), field%c_ptr()) + call atlas__mesh__HybridElements__add_field(this%CPTR_PGIBUG_A, field%CPTR_PGIBUG_A) end subroutine function nb_types(this) result(val) - use, intrinsic :: iso_c_binding use atlas_hybridelements_c_binding - integer(c_size_t) :: val + integer(ATLAS_KIND_IDX) :: val class(atlas_HybridElements), intent(in) :: this - val = atlas__mesh__HybridElements__nb_types(this%c_ptr()) + val = atlas__mesh__HybridElements__nb_types(this%CPTR_PGIBUG_A) end function function nb_fields(this) result(val) - use, intrinsic :: iso_c_binding use atlas_hybridelements_c_binding - integer(c_size_t) :: val + integer(ATLAS_KIND_IDX) :: val class(atlas_HybridElements), intent(in) :: this - val = atlas__mesh__HybridElements__nb_fields(this%c_ptr()) + val = atlas__mesh__HybridElements__nb_fields(this%CPTR_PGIBUG_A) end function function has_field(this,name) result(val) @@ -176,7 +247,7 @@ function has_field(this,name) result(val) logical :: val class(atlas_HybridElements), intent(in) :: this character(len=*), intent(in) :: name - if( atlas__mesh__HybridElements__has_field(this%c_ptr(),c_str(name)) == 0 ) then + if( atlas__mesh__HybridElements__has_field(this%CPTR_PGIBUG_A,c_str(name)) == 0 ) then val = .False. else val = .True. @@ -189,17 +260,17 @@ function field_by_name(this,name) result(field) type(atlas_Field) :: field class(atlas_HybridElements), intent(in) :: this character(len=*), intent(in) :: name - field = atlas_Field( atlas__mesh__HybridElements__field_by_name(this%c_ptr(),c_str(name)) ) + field = atlas_Field( atlas__mesh__HybridElements__field_by_name(this%CPTR_PGIBUG_A,c_str(name)) ) call field%return() end function -function field_by_idx_size_t(this,idx) result(field) +function field_by_idx_long(this,idx) result(field) use, intrinsic :: iso_c_binding use atlas_hybridelements_c_binding type(atlas_Field) :: field class(atlas_HybridElements), intent(in) :: this - integer(c_size_t), intent(in) :: idx - field = atlas_Field( atlas__mesh__HybridElements__field_by_idx(this%c_ptr(),idx-1_c_size_t) ) + integer(c_long), intent(in) :: idx + field = atlas_Field( atlas__mesh__HybridElements__field_by_idx(this%CPTR_PGIBUG_A,int(idx-1_c_long,ATLAS_KIND_IDX) ) ) call field%return() end function @@ -209,7 +280,7 @@ function field_by_idx_int(this,idx) result(field) type(atlas_Field) :: field class(atlas_HybridElements), intent(in) :: this integer(c_int), intent(in) :: idx - field = atlas_Field( atlas__mesh__HybridElements__field_by_idx(this%c_ptr(),int(idx-1,c_size_t)) ) + field = atlas_Field( atlas__mesh__HybridElements__field_by_idx(this%CPTR_PGIBUG_A,int(idx-1_c_int,ATLAS_KIND_IDX) ) ) call field%return() end function @@ -217,7 +288,7 @@ function global_index(this) result(field) use atlas_hybridelements_c_binding type(atlas_Field) :: field class(atlas_HybridElements), intent(in) :: this - field = atlas_Field( atlas__mesh__HybridElements__global_index(this%c_ptr()) ) + field = atlas_Field( atlas__mesh__HybridElements__global_index(this%CPTR_PGIBUG_A) ) call field%return() end function @@ -225,7 +296,7 @@ function remote_index(this) result(field) use atlas_hybridelements_c_binding type(atlas_Field) :: field class(atlas_HybridElements), intent(in) :: this - field = atlas_Field( atlas__mesh__HybridElements__remote_index(this%c_ptr()) ) + field = atlas_Field( atlas__mesh__HybridElements__remote_index(this%CPTR_PGIBUG_A) ) call field%return() end function @@ -233,7 +304,7 @@ function partition(this) result(field) use atlas_hybridelements_c_binding type(atlas_Field) :: field class(atlas_HybridElements), intent(in) :: this - field = atlas_Field( atlas__mesh__HybridElements__partition(this%c_ptr()) ) + field = atlas_Field( atlas__mesh__HybridElements__partition(this%CPTR_PGIBUG_A) ) call field%return() end function @@ -241,17 +312,17 @@ function halo(this) result(field) use atlas_hybridelements_c_binding type(atlas_Field) :: field class(atlas_HybridElements), intent(in) :: this - field = atlas_Field( atlas__mesh__HybridElements__halo(this%c_ptr()) ) + field = atlas_Field( atlas__mesh__HybridElements__halo(this%CPTR_PGIBUG_A) ) call field%return() end function -function elements_size_t(this,idx) result(elements) +function elements_long(this,idx) result(elements) use, intrinsic :: iso_c_binding use atlas_hybridelements_c_binding type(atlas_Elements) :: elements class(atlas_HybridElements), intent(in) :: this - integer(c_size_t), intent(in) :: idx - elements = atlas_Elements( atlas__mesh__HybridElements__elements(this%c_ptr(),idx-1_c_size_t) ) + integer(c_long), intent(in) :: idx + elements = atlas_Elements( atlas__mesh__HybridElements__elements(this%CPTR_PGIBUG_A,int(idx-1_c_long,ATLAS_KIND_IDX) ) ) call elements%return() end function @@ -261,7 +332,7 @@ function elements_int(this,idx) result(elements) type(atlas_Elements) :: elements class(atlas_HybridElements), intent(in) :: this integer(c_int), intent(in) :: idx - elements = atlas_Elements( atlas__mesh__HybridElements__elements(this%c_ptr(),int(idx-1,c_size_t)) ) + elements = atlas_Elements( atlas__mesh__HybridElements__elements(this%CPTR_PGIBUG_A,int(idx-1_c_int,ATLAS_KIND_IDX) ) ) call elements%return() end function diff --git a/src/atlas_f/mesh/atlas_MeshGenerator_module.F90 b/src/atlas_f/mesh/atlas_MeshGenerator_module.F90 index 20221d6d6..0e0c6a4fc 100644 --- a/src/atlas_f/mesh/atlas_MeshGenerator_module.F90 +++ b/src/atlas_f/mesh/atlas_MeshGenerator_module.F90 @@ -1,3 +1,11 @@ +! (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_MeshGenerator_module @@ -60,7 +68,8 @@ function atlas_MeshGenerator__config(config) result(this) if( .not. config%get("type",meshgenerator_type) ) then meshgenerator_type='structured' endif - call this%reset_c_ptr( atlas__MeshGenerator__create(c_str(meshgenerator_type),config%c_ptr()) ) + call this%reset_c_ptr( atlas__MeshGenerator__create( & + c_str(meshgenerator_type),config%CPTR_PGIBUG_B) ) else call this%reset_c_ptr( atlas__MeshGenerator__create_noconfig(c_str('structured')) ) endif @@ -78,9 +87,11 @@ function atlas_MeshGenerator__generate(this,grid,distribution) result(mesh) class(atlas_GridDistribution), intent(in), optional :: distribution call mesh%reset_c_ptr() ! Somehow needed with PGI/16.7 and build-type "bit" if( present(distribution) ) then - mesh = atlas_Mesh( atlas__MeshGenerator__generate__grid_griddist(this%c_ptr(),grid%c_ptr(),distribution%c_ptr()) ) + mesh = atlas_Mesh( atlas__MeshGenerator__generate__grid_griddist( & + this%CPTR_PGIBUG_A,grid%CPTR_PGIBUG_A,distribution%CPTR_PGIBUG_A) ) else - mesh = atlas_Mesh( atlas__MeshGenerator__generate__grid(this%c_ptr(),grid%c_ptr()) ) + mesh = atlas_Mesh( atlas__MeshGenerator__generate__grid( & + this%CPTR_PGIBUG_A,grid%CPTR_PGIBUG_A) ) endif call mesh%return() end function diff --git a/src/atlas_f/mesh/atlas_Mesh_module.F90 b/src/atlas_f/mesh/atlas_Mesh_module.F90 index fde29a362..55c6025db 100644 --- a/src/atlas_f/mesh/atlas_Mesh_module.F90 +++ b/src/atlas_f/mesh/atlas_Mesh_module.F90 @@ -1,3 +1,11 @@ +! (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_Mesh_module @@ -87,7 +95,7 @@ function Mesh__nodes(this) result(nodes) use atlas_mesh_c_binding class(atlas_Mesh), intent(in) :: this type(atlas_mesh_Nodes) :: nodes - nodes = atlas_mesh_Nodes( atlas__Mesh__nodes(this%c_ptr()) ) + nodes = atlas_mesh_Nodes( atlas__Mesh__nodes(this%CPTR_PGIBUG_A) ) call nodes%return() end function @@ -97,7 +105,7 @@ function Mesh__cells(this) result(cells) use atlas_mesh_c_binding class(atlas_Mesh), intent(in) :: this type(atlas_mesh_Cells) :: cells - cells = atlas_mesh_Cells( atlas__Mesh__cells(this%c_ptr()) ) + cells = atlas_mesh_Cells( atlas__Mesh__cells(this%CPTR_PGIBUG_A) ) call cells%return() end function @@ -107,7 +115,7 @@ function Mesh__edges(this) result(edges) use atlas_mesh_c_binding class(atlas_Mesh), intent(in) :: this type(atlas_mesh_Edges) :: edges - edges = atlas_mesh_Edges( atlas__Mesh__Edges(this%c_ptr()) ) + edges = atlas_mesh_Edges( atlas__Mesh__Edges(this%CPTR_PGIBUG_A) ) call edges%return() end function @@ -117,7 +125,7 @@ function footprint(this) use atlas_mesh_c_binding integer(c_size_t) :: footprint class(atlas_Mesh) :: this - footprint = atlas__Mesh__footprint(this%c_ptr()) + footprint = atlas__Mesh__footprint(this%CPTR_PGIBUG_A) end function !------------------------------------------------------------------------------- @@ -125,7 +133,7 @@ function footprint(this) subroutine clone_to_device(this) use atlas_mesh_c_binding class(atlas_Mesh), intent(inout) :: this - call atlas__Mesh__clone_to_device(this%c_ptr()) + call atlas__Mesh__clone_to_device(this%CPTR_PGIBUG_A) end subroutine !------------------------------------------------------------------------------- @@ -133,7 +141,7 @@ subroutine clone_to_device(this) subroutine clone_from_device(this) use atlas_mesh_c_binding class(atlas_Mesh), intent(inout) :: this - call atlas__Mesh__clone_from_device(this%c_ptr()) + call atlas__Mesh__clone_from_device(this%CPTR_PGIBUG_A) end subroutine ! ---------------------------------------------------------------------------------------- @@ -141,7 +149,7 @@ subroutine clone_from_device(this) subroutine sync_host_device(this) use atlas_mesh_c_binding class(atlas_Mesh), intent(inout) :: this - call atlas__Mesh__sync_host_device(this%c_ptr()) + call atlas__Mesh__sync_host_device(this%CPTR_PGIBUG_A) end subroutine !------------------------------------------------------------------------------- diff --git a/src/atlas_f/mesh/atlas_mesh_Cells_module.F90 b/src/atlas_f/mesh/atlas_mesh_Cells_module.F90 index 39ad47253..d2c690428 100644 --- a/src/atlas_f/mesh/atlas_mesh_Cells_module.F90 +++ b/src/atlas_f/mesh/atlas_mesh_Cells_module.F90 @@ -1,3 +1,11 @@ +! (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_mesh_cells_module diff --git a/src/atlas_f/mesh/atlas_mesh_Edges_module.F90 b/src/atlas_f/mesh/atlas_mesh_Edges_module.F90 index 952b2f674..e8c417301 100644 --- a/src/atlas_f/mesh/atlas_mesh_Edges_module.F90 +++ b/src/atlas_f/mesh/atlas_mesh_Edges_module.F90 @@ -1,3 +1,11 @@ +! (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_mesh_Edges_module diff --git a/src/atlas_f/mesh/atlas_mesh_Nodes_module.F90 b/src/atlas_f/mesh/atlas_mesh_Nodes_module.F90 index 6f531f760..0464e4337 100644 --- a/src/atlas_f/mesh/atlas_mesh_Nodes_module.F90 +++ b/src/atlas_f/mesh/atlas_mesh_Nodes_module.F90 @@ -1,17 +1,26 @@ +! (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_mesh_Nodes_module -use, intrinsic :: iso_c_binding, only: c_ptr, c_size_t, c_int +use, intrinsic :: iso_c_binding, only: c_ptr, c_int, c_long use fckit_owned_object_module, only: fckit_owned_object use atlas_Metadata_module, only: atlas_Metadata use atlas_Field_module, only: atlas_Field use atlas_Connectivity_module, only: atlas_Connectivity +use atlas_kinds_module, only : ATLAS_KIND_IDX implicit none private :: fckit_owned_object -private :: c_ptr, c_size_t, c_int +private :: c_ptr, c_int private :: atlas_Metadata private :: atlas_Field private :: atlas_Connectivity @@ -26,7 +35,9 @@ module atlas_mesh_Nodes_module TYPE, extends(fckit_owned_object) :: atlas_mesh_Nodes contains procedure, public :: size => atlas_mesh_Nodes__size -procedure, public :: resize +procedure, private :: resize_int +procedure, private :: resize_long +generic, public :: resize => resize_int, resize_long procedure, private :: add_field procedure, private :: add_connectivity generic, public :: add => & @@ -34,10 +45,10 @@ module atlas_mesh_Nodes_module & add_connectivity procedure, public :: remove_field procedure, private :: field_by_idx_int -procedure, private :: field_by_idx_size_t +procedure, private :: field_by_idx_long procedure, private :: field_by_name generic, public :: field => & - & field_by_idx_size_t, field_by_idx_int, & + & field_by_idx_long, field_by_idx_int, & & field_by_name procedure, public :: nb_fields procedure, public :: has_field @@ -87,9 +98,9 @@ function atlas_mesh_Nodes__constructor() result(this) function atlas_mesh_Nodes__size(this) result(val) use atlas_nodes_c_binding - integer(c_size_t) :: val + integer(ATLAS_KIND_IDX) :: val class(atlas_mesh_Nodes), intent(in) :: this - val = atlas__mesh__Nodes__size(this%c_ptr()) + val = atlas__mesh__Nodes__size(this%CPTR_PGIBUG_A) end function function edge_connectivity(this) result(connectivity) @@ -98,7 +109,7 @@ function edge_connectivity(this) result(connectivity) class(atlas_mesh_Nodes), intent(in) :: this type(atlas_Connectivity) :: connectivity connectivity = atlas_Connectivity( & - atlas__mesh__Nodes__edge_connectivity(this%c_ptr()) ) + atlas__mesh__Nodes__edge_connectivity(this%CPTR_PGIBUG_A) ) call connectivity%return() end function @@ -107,7 +118,7 @@ function cell_connectivity(this) result(connectivity) class(atlas_mesh_Nodes), intent(in) :: this type(atlas_Connectivity) :: connectivity connectivity = atlas_Connectivity( & - atlas__mesh__Nodes__cell_connectivity(this%c_ptr()) ) + atlas__mesh__Nodes__cell_connectivity(this%CPTR_PGIBUG_A) ) call connectivity%return() end function @@ -118,7 +129,7 @@ function connectivity(this,name) class(atlas_mesh_Nodes), intent(in) :: this character(len=*), intent(in) :: name connectivity = atlas_Connectivity( & - atlas__mesh__Nodes__connectivity(this%c_ptr(),c_str(name)) ) + atlas__mesh__Nodes__connectivity(this%CPTR_PGIBUG_A,c_str(name)) ) call connectivity%return() end function @@ -126,7 +137,7 @@ subroutine add_connectivity(this,connectivity) use atlas_nodes_c_binding class(atlas_mesh_Nodes), intent(inout) :: this type(atlas_Connectivity), intent(in) :: connectivity - call atlas__mesh__Nodes__add_connectivity(this%c_ptr(), connectivity%c_ptr()) + call atlas__mesh__Nodes__add_connectivity(this%CPTR_PGIBUG_A, connectivity%CPTR_PGIBUG_A) end subroutine @@ -134,7 +145,7 @@ subroutine add_field(this,field) use atlas_nodes_c_binding class(atlas_mesh_Nodes), intent(inout) :: this type(atlas_Field), intent(in) :: field - call atlas__mesh__Nodes__add_field(this%c_ptr(), field%c_ptr()) + call atlas__mesh__Nodes__add_field(this%CPTR_PGIBUG_A, field%CPTR_PGIBUG_A) end subroutine subroutine remove_field(this,name) @@ -142,14 +153,14 @@ subroutine remove_field(this,name) use fckit_c_interop_module, only: c_str class(atlas_mesh_Nodes), intent(in) :: this character(len=*), intent(in) :: name - call atlas__mesh__Nodes__remove_field(this%c_ptr(),c_str(name)) + call atlas__mesh__Nodes__remove_field(this%CPTR_PGIBUG_A,c_str(name)) end subroutine function nb_fields(this) result(val) use atlas_nodes_c_binding - integer(c_size_t) :: val + integer(ATLAS_KIND_IDX) :: val class(atlas_mesh_Nodes), intent(in) :: this - val = atlas__mesh__Nodes__nb_fields(this%c_ptr()) + val = atlas__mesh__Nodes__nb_fields(this%CPTR_PGIBUG_A) end function function has_field(this,name) result(val) @@ -158,7 +169,7 @@ function has_field(this,name) result(val) logical :: val class(atlas_mesh_Nodes), intent(in) :: this character(len=*), intent(in) :: name - if( atlas__mesh__Nodes__has_field(this%c_ptr(),c_str(name)) == 0 ) then + if( atlas__mesh__Nodes__has_field(this%CPTR_PGIBUG_A,c_str(name)) == 0 ) then val = .False. else val = .True. @@ -171,26 +182,27 @@ function field_by_name(this,name) result(field) type(atlas_Field) :: field class(atlas_mesh_Nodes), intent(in) :: this character(len=*), intent(in) :: name - field = atlas_Field( atlas__mesh__Nodes__field_by_name(this%c_ptr(),c_str(name)) ) + field = atlas_Field( atlas__mesh__Nodes__field_by_name(this%CPTR_PGIBUG_A,c_str(name)) ) call field%return() end function -function field_by_idx_size_t(this,idx) result(field) +function field_by_idx_long(this,idx) result(field) use atlas_nodes_c_binding + use, intrinsic :: iso_c_binding, only: c_long type(atlas_Field) :: field class(atlas_mesh_Nodes), intent(in) :: this - integer(c_size_t), intent(in) :: idx - field = atlas_Field( atlas__mesh__Nodes__field_by_idx(this%c_ptr(),idx-1_c_size_t) ) + integer(c_long), intent(in) :: idx + field = atlas_Field( atlas__mesh__Nodes__field_by_idx(this%CPTR_PGIBUG_A,int(idx-1_c_long,ATLAS_KIND_IDX) ) ) call field%return() end function function field_by_idx_int(this,idx) result(field) use atlas_nodes_c_binding - use, intrinsic :: iso_c_binding, only: c_size_t, c_int + use, intrinsic :: iso_c_binding, only: c_int type(atlas_Field) :: field class(atlas_mesh_Nodes), intent(in) :: this integer(c_int), intent(in) :: idx - field = atlas_Field( atlas__mesh__Nodes__field_by_idx(this%c_ptr(),int(idx-1,c_size_t)) ) + field = atlas_Field( atlas__mesh__Nodes__field_by_idx(this%CPTR_PGIBUG_A,int(idx-1_c_long,ATLAS_KIND_IDX) ) ) call field%return() end function @@ -198,7 +210,7 @@ function xy(this) result(field) use atlas_nodes_c_binding type(atlas_Field) :: field class(atlas_mesh_Nodes), intent(in) :: this - field = atlas_Field( atlas__mesh__Nodes__xy(this%c_ptr()) ) + field = atlas_Field( atlas__mesh__Nodes__xy(this%CPTR_PGIBUG_A) ) call field%return() end function @@ -206,7 +218,7 @@ function lonlat(this) result(field) use atlas_nodes_c_binding type(atlas_Field) :: field class(atlas_mesh_Nodes), intent(in) :: this - field = atlas_Field( atlas__mesh__Nodes__lonlat(this%c_ptr()) ) + field = atlas_Field( atlas__mesh__Nodes__lonlat(this%CPTR_PGIBUG_A) ) call field%return() end function @@ -214,7 +226,7 @@ function global_index(this) result(field) use atlas_nodes_c_binding type(atlas_Field) :: field class(atlas_mesh_Nodes), intent(in) :: this - field = atlas_Field( atlas__mesh__Nodes__global_index(this%c_ptr()) ) + field = atlas_Field( atlas__mesh__Nodes__global_index(this%CPTR_PGIBUG_A) ) call field%return() end function @@ -222,7 +234,7 @@ function remote_index(this) result(field) use atlas_nodes_c_binding type(atlas_Field) :: field class(atlas_mesh_Nodes), intent(in) :: this - field = atlas_Field( atlas__mesh__Nodes__remote_index(this%c_ptr()) ) + field = atlas_Field( atlas__mesh__Nodes__remote_index(this%CPTR_PGIBUG_A) ) call field%return() end function @@ -230,7 +242,7 @@ function partition(this) result(field) use atlas_nodes_c_binding type(atlas_Field) :: field class(atlas_mesh_Nodes), intent(in) :: this - field = atlas_Field( atlas__mesh__Nodes__partition(this%c_ptr()) ) + field = atlas_Field( atlas__mesh__Nodes__partition(this%CPTR_PGIBUG_A) ) call field%return() end function @@ -238,7 +250,7 @@ function ghost(this) result(field) use atlas_nodes_c_binding type(atlas_Field) :: field class(atlas_mesh_Nodes), intent(in) :: this - field = atlas_Field( atlas__mesh__Nodes__ghost(this%c_ptr()) ) + field = atlas_Field( atlas__mesh__Nodes__ghost(this%CPTR_PGIBUG_A) ) call field%return() end function @@ -246,14 +258,23 @@ function metadata(this) use atlas_nodes_c_binding type(atlas_Metadata) :: metadata class(atlas_mesh_Nodes), intent(in) :: this - call metadata%reset_c_ptr( atlas__mesh__Nodes__metadata(this%c_ptr()) ) + call metadata%reset_c_ptr( atlas__mesh__Nodes__metadata(this%CPTR_PGIBUG_A) ) end function -subroutine resize(this,size) +subroutine resize_int(this,size) + use, intrinsic :: iso_c_binding + use atlas_nodes_c_binding + class(atlas_mesh_Nodes), intent(in) :: this + integer(c_int), intent(in) :: size + call atlas__mesh__Nodes__resize(this%CPTR_PGIBUG_A,int(size,ATLAS_KIND_IDX)) +end subroutine + +subroutine resize_long(this,size) + use, intrinsic :: iso_c_binding use atlas_nodes_c_binding class(atlas_mesh_Nodes), intent(in) :: this - integer(c_size_t), intent(in) :: size - call atlas__mesh__Nodes__resize(this%c_ptr(),size) + integer(c_long), intent(in) :: size + call atlas__mesh__Nodes__resize(this%CPTR_PGIBUG_A,int(size,ATLAS_KIND_IDX)) end subroutine function str(this) @@ -263,7 +284,7 @@ function str(this) class(atlas_mesh_Nodes), intent(in) :: this type(c_ptr) :: str_cptr integer(c_int) :: str_size - call atlas__mesh__Nodes__str(this%c_ptr(),str_cptr,str_size) + call atlas__mesh__Nodes__str(this%CPTR_PGIBUG_A,str_cptr,str_size) allocate(character(len=str_size) :: str ) str = c_ptr_to_string(str_cptr) call c_ptr_free(str_cptr) diff --git a/src/atlas_f/mesh/atlas_mesh_actions_module.F90 b/src/atlas_f/mesh/atlas_mesh_actions_module.F90 index a99016f31..8da0c0fb9 100644 --- a/src/atlas_f/mesh/atlas_mesh_actions_module.F90 +++ b/src/atlas_f/mesh/atlas_mesh_actions_module.F90 @@ -1,3 +1,11 @@ +! (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_mesh_actions_module @@ -23,35 +31,35 @@ subroutine atlas_build_parallel_fields(mesh) use atlas_BuildParallelFields_c_binding use atlas_Mesh_module, only: atlas_Mesh type(atlas_Mesh), intent(inout) :: mesh - call atlas__build_parallel_fields(mesh%c_ptr()) + call atlas__build_parallel_fields(mesh%CPTR_PGIBUG_A) end subroutine atlas_build_parallel_fields subroutine atlas_build_nodes_parallel_fields(nodes) use atlas_BuildParallelFields_c_binding use atlas_mesh_Nodes_module, only: atlas_mesh_Nodes type(atlas_mesh_Nodes), intent(inout) :: nodes - call atlas__build_nodes_parallel_fields(nodes%c_ptr()) + call atlas__build_nodes_parallel_fields(nodes%CPTR_PGIBUG_A) end subroutine atlas_build_nodes_parallel_fields subroutine atlas_renumber_nodes_glb_idx(nodes) use atlas_BuildParallelFields_c_binding use atlas_mesh_Nodes_module, only: atlas_mesh_Nodes type(atlas_mesh_Nodes), intent(inout) :: nodes - call atlas__renumber_nodes_glb_idx(nodes%c_ptr()) + call atlas__renumber_nodes_glb_idx(nodes%CPTR_PGIBUG_A) end subroutine atlas_renumber_nodes_glb_idx subroutine atlas_build_edges_parallel_fields(mesh) use atlas_BuildParallelFields_c_binding use atlas_Mesh_module, only: atlas_Mesh type(atlas_Mesh), intent(inout) :: mesh - call atlas__build_edges_parallel_fields(mesh%c_ptr()) + call atlas__build_edges_parallel_fields(mesh%CPTR_PGIBUG_A) end subroutine atlas_build_edges_parallel_fields subroutine atlas_build_periodic_boundaries(mesh) use atlas_BuildPeriodicBoundaries_c_binding use atlas_Mesh_module, only: atlas_Mesh type(atlas_Mesh), intent(inout) :: mesh - call atlas__build_periodic_boundaries(mesh%c_ptr()) + call atlas__build_periodic_boundaries(mesh%CPTR_PGIBUG_A) end subroutine atlas_build_periodic_boundaries subroutine atlas_build_halo(mesh,nelems) @@ -59,42 +67,42 @@ subroutine atlas_build_halo(mesh,nelems) use atlas_Mesh_module, only: atlas_Mesh type(atlas_Mesh), intent(inout) :: mesh integer, intent(in) :: nelems - call atlas__build_halo(mesh%c_ptr(),nelems) + call atlas__build_halo(mesh%CPTR_PGIBUG_A,nelems) end subroutine atlas_build_halo subroutine atlas_build_edges(mesh) use atlas_BuildEdges_c_binding use atlas_Mesh_module, only: atlas_Mesh type(atlas_Mesh), intent(inout) :: mesh - call atlas__build_edges(mesh%c_ptr()) + call atlas__build_edges(mesh%CPTR_PGIBUG_A) end subroutine atlas_build_edges subroutine atlas_build_pole_edges(mesh) use atlas_BuildEdges_c_binding use atlas_Mesh_module, only: atlas_Mesh type(atlas_Mesh), intent(inout) :: mesh - call atlas__build_pole_edges(mesh%c_ptr()) + call atlas__build_pole_edges(mesh%CPTR_PGIBUG_A) end subroutine atlas_build_pole_edges subroutine atlas_build_node_to_edge_connectivity(mesh) use atlas_BuildEdges_c_binding use atlas_Mesh_module, only: atlas_Mesh type(atlas_Mesh), intent(inout) :: mesh - call atlas__build_node_to_edge_connectivity(mesh%c_ptr()) + call atlas__build_node_to_edge_connectivity(mesh%CPTR_PGIBUG_A) end subroutine atlas_build_node_to_edge_connectivity subroutine atlas_build_median_dual_mesh(mesh) use atlas_BuildDualMesh_c_binding use atlas_Mesh_module, only: atlas_Mesh type(atlas_Mesh), intent(inout) :: mesh - call atlas__build_median_dual_mesh(mesh%c_ptr()) + call atlas__build_median_dual_mesh(mesh%CPTR_PGIBUG_A) end subroutine atlas_build_median_dual_mesh subroutine atlas_build_centroid_dual_mesh(mesh) use atlas_BuildDualMesh_c_binding use atlas_Mesh_module, only: atlas_Mesh type(atlas_Mesh), intent(inout) :: mesh - call atlas__build_centroid_dual_mesh(mesh%c_ptr()) + call atlas__build_centroid_dual_mesh(mesh%CPTR_PGIBUG_A) end subroutine atlas_build_centroid_dual_mesh subroutine atlas_write_load_balance_report(mesh,filename) @@ -103,7 +111,7 @@ subroutine atlas_write_load_balance_report(mesh,filename) use atlas_Mesh_module, only: atlas_Mesh type(atlas_Mesh), intent(in) :: mesh character(len=*), intent(in) :: filename - call atlas__write_load_balance_report(mesh%c_ptr(),c_str(filename)) + call atlas__write_load_balance_report(mesh%CPTR_PGIBUG_A,c_str(filename)) end subroutine atlas_write_load_balance_report ! ----------------------------------------------------------------------------- diff --git a/src/atlas_f/numerics/atlas_Method_module.F90 b/src/atlas_f/numerics/atlas_Method_module.F90 index bf72e53ae..8b3f5ab3a 100644 --- a/src/atlas_f/numerics/atlas_Method_module.F90 +++ b/src/atlas_f/numerics/atlas_Method_module.F90 @@ -1,3 +1,11 @@ +! (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_Method_module @@ -60,7 +68,7 @@ function atlas_Method__name(this) result(name) class(atlas_Method), intent(in) :: this character(len=:), allocatable :: name type(c_ptr) :: name_c_str - name_c_str = atlas__Method__name(this%c_ptr()) + name_c_str = atlas__Method__name(this%CPTR_PGIBUG_A) name = c_ptr_to_string(name_c_str) end function diff --git a/src/atlas_f/numerics/atlas_Nabla_module.F90 b/src/atlas_f/numerics/atlas_Nabla_module.F90 index 1f4f5ac1c..f7c321292 100644 --- a/src/atlas_f/numerics/atlas_Nabla_module.F90 +++ b/src/atlas_f/numerics/atlas_Nabla_module.F90 @@ -1,3 +1,11 @@ +! (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_Nabla_module @@ -64,10 +72,10 @@ function atlas_Nabla__method_config(method,config) result(this) type(atlas_Config), intent(in), optional :: config type(atlas_Config) :: opt_config if( present(config) ) then - call this%reset_c_ptr( atlas__Nabla__create(method%c_ptr(),config%c_ptr()) ) + call this%reset_c_ptr( atlas__Nabla__create(method%CPTR_PGIBUG_A,config%CPTR_PGIBUG_B) ) else opt_config = atlas_Config() - call this%reset_c_ptr( atlas__Nabla__create(method%c_ptr(),opt_config%c_ptr()) ) + call this%reset_c_ptr( atlas__Nabla__create(method%CPTR_PGIBUG_A,opt_config%CPTR_PGIBUG_B) ) call opt_config%final() endif call this%return() @@ -79,7 +87,7 @@ subroutine atlas_Nabla__gradient(this,scalar,grad) class(atlas_Nabla), intent(in) :: this class(atlas_Field), intent(in) :: scalar class(atlas_Field), intent(inout) :: grad - call atlas__Nabla__gradient(this%c_ptr(),scalar%c_ptr(),grad%c_ptr()) + call atlas__Nabla__gradient(this%CPTR_PGIBUG_A,scalar%CPTR_PGIBUG_A,grad%CPTR_PGIBUG_A) end subroutine @@ -89,7 +97,7 @@ subroutine atlas_Nabla__divergence(this,vector,div) class(atlas_Nabla), intent(in) :: this class(atlas_Field), intent(in) :: vector class(atlas_Field), intent(inout) :: div - call atlas__Nabla__divergence(this%c_ptr(),vector%c_ptr(),div%c_ptr()) + call atlas__Nabla__divergence(this%CPTR_PGIBUG_A,vector%CPTR_PGIBUG_A,div%CPTR_PGIBUG_A) end subroutine subroutine atlas_Nabla__curl(this,vector,curl) @@ -98,7 +106,7 @@ subroutine atlas_Nabla__curl(this,vector,curl) class(atlas_Nabla), intent(in) :: this class(atlas_Field), intent(in) :: vector class(atlas_Field), intent(inout) :: curl - call atlas__Nabla__curl(this%c_ptr(),vector%c_ptr(),curl%c_ptr()) + call atlas__Nabla__curl(this%CPTR_PGIBUG_A,vector%CPTR_PGIBUG_A,curl%CPTR_PGIBUG_A) end subroutine subroutine atlas_Nabla__laplacian(this,scalar,lapl) @@ -107,7 +115,7 @@ subroutine atlas_Nabla__laplacian(this,scalar,lapl) class(atlas_Nabla), intent(in) :: this class(atlas_Field), intent(in) :: scalar class(atlas_Field), intent(inout) :: lapl - call atlas__Nabla__laplacian(this%c_ptr(),scalar%c_ptr(),lapl%c_ptr()) + call atlas__Nabla__laplacian(this%CPTR_PGIBUG_A,scalar%CPTR_PGIBUG_A,lapl%CPTR_PGIBUG_A) end subroutine !------------------------------------------------------------------------------- diff --git a/src/atlas_f/numerics/atlas_fvm_module.F90 b/src/atlas_f/numerics/atlas_fvm_module.F90 index 793a70779..5b92f75a8 100644 --- a/src/atlas_f/numerics/atlas_fvm_module.F90 +++ b/src/atlas_f/numerics/atlas_fvm_module.F90 @@ -1,3 +1,11 @@ +! (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_fvm_module @@ -67,10 +75,12 @@ function atlas_fvm_Method__mesh_config(mesh,config) result(this) type(atlas_Config), intent(in), optional :: config type(atlas_Config) :: opt_config if( present(config) ) then - call this%reset_c_ptr( atlas__numerics__fvm__Method__new(mesh%c_ptr(),config%c_ptr()) ) + call this%reset_c_ptr( atlas__numerics__fvm__Method__new(mesh%CPTR_PGIBUG_A, & + config%CPTR_PGIBUG_B) ) else opt_config = atlas_Config() - call this%reset_c_ptr( atlas__numerics__fvm__Method__new(mesh%c_ptr(),opt_config%c_ptr()) ) + call this%reset_c_ptr( atlas__numerics__fvm__Method__new(mesh%CPTR_PGIBUG_A, & + opt_config%CPTR_PGIBUG_B) ) call opt_config%final() endif call this%return() @@ -82,7 +92,7 @@ function node_columns(this) type(atlas_functionspace_NodeColumns) :: node_columns class(atlas_fvm_Method) :: this node_columns = atlas_functionspace_NodeColumns( & - & atlas__numerics__fvm__Method__functionspace_nodes(this%c_ptr()) ) + & atlas__numerics__fvm__Method__functionspace_nodes(this%CPTR_PGIBUG_A) ) call node_columns%return() end function @@ -92,7 +102,7 @@ function edge_columns(this) type(atlas_functionspace_EdgeColumns) :: edge_columns class(atlas_fvm_Method) :: this edge_columns = atlas_functionspace_EdgeColumns( & - & atlas__numerics__fvm__Method__functionspace_edges(this%c_ptr()) ) + & atlas__numerics__fvm__Method__functionspace_edges(this%CPTR_PGIBUG_A) ) call edge_columns%return() end function diff --git a/src/atlas_f/output/atlas_output_module.F90 b/src/atlas_f/output/atlas_output_module.F90 index 5ca57d1d0..008a45776 100644 --- a/src/atlas_f/output/atlas_output_module.F90 +++ b/src/atlas_f/output/atlas_output_module.F90 @@ -1,3 +1,11 @@ +! (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_output_module @@ -79,7 +87,7 @@ function atlas_Output__cptr(cptr) result(this) call this%return() end function -function atlas_output_Gmsh__pathname_mode(file,mode,coordinates,levels,gather) result(this) +function atlas_output_Gmsh__pathname_mode(file,mode,coordinates,levels,gather,ghost) result(this) use fckit_c_interop_module, only : c_str use atlas_output_gmsh_c_binding type(atlas_Output) :: this @@ -88,6 +96,7 @@ function atlas_output_Gmsh__pathname_mode(file,mode,coordinates,levels,gather) r character(len=*), intent(in), optional :: coordinates integer, intent(in), optional :: levels(:) logical, intent(in), optional :: gather + logical, intent(in), optional :: ghost character(len=1) :: opt_mode type(atlas_Config) :: opt_config opt_config = atlas_Config() @@ -96,7 +105,9 @@ function atlas_output_Gmsh__pathname_mode(file,mode,coordinates,levels,gather) r if( present(coordinates) ) call opt_config%set("coordinates",coordinates) if( present(levels) ) call opt_config%set("levels",levels) if( present(gather) ) call opt_config%set("gather",gather) - call this%reset_c_ptr( atlas__output__Gmsh__create_pathname_mode_config(c_str(file),c_str(opt_mode),opt_config%c_ptr()) ) + if( present(ghost) ) call opt_config%set("ghost",ghost) + call this%reset_c_ptr( atlas__output__Gmsh__create_pathname_mode_config(c_str(file),c_str(opt_mode),& + opt_config%CPTR_PGIBUG_B) ) call this%return() call opt_config%final() end function @@ -108,10 +119,10 @@ subroutine write_mesh(this,mesh,config) type(atlas_Config), intent(in), optional :: config type(atlas_Config) :: opt_config if( present(config) ) then - call atlas__output__write_mesh(this%c_ptr(),mesh%c_ptr(),config%c_ptr()) + call atlas__output__write_mesh(this%CPTR_PGIBUG_A,mesh%CPTR_PGIBUG_A,config%CPTR_PGIBUG_B) else opt_config = atlas_Config() - call atlas__output__write_mesh(this%c_ptr(),mesh%c_ptr(),opt_config%c_ptr()) + call atlas__output__write_mesh(this%CPTR_PGIBUG_A,mesh%CPTR_PGIBUG_A,opt_config%CPTR_PGIBUG_B) call opt_config%final() endif end subroutine @@ -124,10 +135,12 @@ subroutine write_field_fs(this,field,functionspace,config) type(atlas_Config), intent(in), optional :: config type(atlas_Config) :: opt_config if( present(config) ) then - call atlas__output__write_field_fs(this%c_ptr(),field%c_ptr(),functionspace%c_ptr(),config%c_ptr()) + call atlas__output__write_field_fs(this%CPTR_PGIBUG_A,field%CPTR_PGIBUG_A,functionspace%CPTR_PGIBUG_A, & + config%CPTR_PGIBUG_B) else opt_config = atlas_Config() - call atlas__output__write_field_fs(this%c_ptr(),field%c_ptr(),functionspace%c_ptr(),opt_config%c_ptr()) + call atlas__output__write_field_fs(this%CPTR_PGIBUG_A,field%CPTR_PGIBUG_A,functionspace%CPTR_PGIBUG_A, & + opt_config%CPTR_PGIBUG_B) call opt_config%final() endif end subroutine @@ -140,10 +153,12 @@ subroutine write_fieldset_fs(this,fieldset,functionspace,config) type(atlas_Config), intent(in), optional :: config type(atlas_Config) :: opt_config if( present(config) ) then - call atlas__output__write_fieldset_fs(this%c_ptr(),fieldset%c_ptr(),functionspace%c_ptr(),config%c_ptr()) + call atlas__output__write_fieldset_fs(this%CPTR_PGIBUG_A,fieldset%CPTR_PGIBUG_A,functionspace%CPTR_PGIBUG_A, & + config%CPTR_PGIBUG_B) else opt_config = atlas_Config() - call atlas__output__write_fieldset_fs(this%c_ptr(),fieldset%c_ptr(),functionspace%c_ptr(),opt_config%c_ptr()) + call atlas__output__write_fieldset_fs(this%CPTR_PGIBUG_A,fieldset%CPTR_PGIBUG_A,functionspace%CPTR_PGIBUG_A, & + opt_config%CPTR_PGIBUG_B) call opt_config%final() endif end subroutine @@ -156,10 +171,12 @@ subroutine write_field(this,field,config) type(atlas_Config), intent(in), optional :: config type(atlas_Config) :: opt_config if( present(config) ) then - call atlas__output__write_field(this%c_ptr(),field%c_ptr(),config%c_ptr()) + call atlas__output__write_field(this%CPTR_PGIBUG_A,field%CPTR_PGIBUG_A, & + config%CPTR_PGIBUG_B) else opt_config = atlas_Config() - call atlas__output__write_field(this%c_ptr(),field%c_ptr(),opt_config%c_ptr()) + call atlas__output__write_field(this%CPTR_PGIBUG_A,field%CPTR_PGIBUG_A, & + opt_config%CPTR_PGIBUG_B) call opt_config%final() endif end subroutine @@ -172,10 +189,12 @@ subroutine write_fieldset(this,fieldset,config) type(atlas_Config), intent(in), optional :: config type(atlas_Config) :: opt_config if( present(config) ) then - call atlas__output__write_fieldset(this%c_ptr(),fieldset%c_ptr(),config%c_ptr()) + call atlas__output__write_fieldset(this%CPTR_PGIBUG_A,fieldset%CPTR_PGIBUG_A, & + config%CPTR_PGIBUG_B) else opt_config = atlas_Config() - call atlas__output__write_fieldset(this%c_ptr(),fieldset%c_ptr(),opt_config%c_ptr()) + call atlas__output__write_fieldset(this%CPTR_PGIBUG_A,fieldset%CPTR_PGIBUG_A, & + opt_config%CPTR_PGIBUG_B) call opt_config%final() endif end subroutine diff --git a/src/atlas_f/parallel/atlas_Checksum_module.F90 b/src/atlas_f/parallel/atlas_Checksum_module.F90 deleted file mode 100644 index d7c222059..000000000 --- a/src/atlas_f/parallel/atlas_Checksum_module.F90 +++ /dev/null @@ -1,273 +0,0 @@ -#include "atlas/atlas_f.h" - -module atlas_checksum_module - -use, intrinsic :: iso_c_binding, only : c_ptr, c_int, c_long, c_float, c_double, c_char -use fckit_array_module, only : array_stride, array_view1d -use fckit_c_interop_module, only : c_str_to_string -use fckit_object_module, only : fckit_object - -implicit none - -private :: c_ptr, c_int, c_long, c_float, c_double, c_char -private :: array_stride, array_view1d, c_str_to_string -private :: fckit_object - -public :: atlas_Checksum - -private - -!------------------------------------------------------------------------------ -TYPE, extends(fckit_object) :: atlas_Checksum - -! Purpose : -! ------- -! *Checksum* : - -! Methods : -! ------- -! setup : Setup using arrays detailing proc, glb_idx, remote_idx, max_glb_idx -! execute : Do the Checksum - -! Author : -! ------ -! 27-Jun-2014 Willem Deconinck *ECMWF* - -!------------------------------------------------------------------------------ -contains - procedure, private :: Checksum__setup32 - procedure, private :: Checksum__setup64 - procedure, private :: Checksum__execute_int32_r1 - procedure, private :: Checksum__execute_int32_r2 - procedure, private :: Checksum__execute_int32_r3 - procedure, private :: Checksum__execute_real32_r1 - procedure, private :: Checksum__execute_real32_r2 - procedure, private :: Checksum__execute_real32_r3 - procedure, private :: Checksum__execute_real64_r1 - procedure, private :: Checksum__execute_real64_r3 - procedure, private :: Checksum__execute_real64_r2 - generic :: setup => & - & Checksum__setup32, & - & Checksum__setup64 - generic :: execute => & - & Checksum__execute_int32_r1, & - & Checksum__execute_int32_r2, & - & Checksum__execute_int32_r3, & - & Checksum__execute_real32_r1, & - & Checksum__execute_real32_r2, & - & Checksum__execute_real32_r3, & - & Checksum__execute_real64_r1, & - & Checksum__execute_real64_r2, & - & Checksum__execute_real64_r3 - - procedure, public :: delete => atlas_Checksum__delete - -#if FCKIT_FINAL_NOT_INHERITING - final :: atlas_Checksum__final_auto -#endif - -END TYPE atlas_Checksum - -!------------------------------------------------------------------------------ - -interface atlas_Checksum - module procedure atlas_Checksum__ctor -end interface - -!------------------------------------------------------------------------------ -!======================================================== -contains -!======================================================== - -! ------------------------------------------------------------------------------ -! Checksum routines - -function atlas_Checksum__ctor() result(Checksum) - use atlas_checksum_c_binding - type(atlas_Checksum) :: Checksum - call Checksum%reset_c_ptr( atlas__Checksum__new() ) -end function atlas_checksum__ctor - -subroutine atlas_Checksum__delete(this) - use atlas_checksum_c_binding - class(atlas_Checksum), intent(inout) :: this - if ( .not. this%is_null() ) then - call atlas__Checksum__delete(this%c_ptr()) - end if - call this%reset_c_ptr() -end subroutine atlas_Checksum__delete - -subroutine Checksum__setup32(this, part, remote_idx, glb_idx ) - use atlas_checksum_c_binding - class(atlas_Checksum), intent(in) :: this - integer(c_int), intent(in) :: part(:) - integer(c_int), intent(in) :: remote_idx(:) - integer(c_int), intent(in) :: glb_idx(:) - call atlas__Checksum__setup32( this%c_ptr(), part, remote_idx, 1, & - & glb_idx, size(part) ) -end subroutine Checksum__setup32 - -subroutine Checksum__setup64(this, part, remote_idx, glb_idx) - use atlas_checksum_c_binding - class(atlas_Checksum), intent(in) :: this - integer(c_int), intent(in) :: part(:) - integer(c_int), intent(in) :: remote_idx(:) - integer(c_long), intent(in) :: glb_idx(:) - call atlas__Checksum__setup64( this%c_ptr(), part, remote_idx, 1, & - & glb_idx, size(part) ) -end subroutine Checksum__setup64 - -function Checksum__execute_int32_r1(this, loc_field_data) result(checksum) - use atlas_checksum_c_binding - class(atlas_Checksum), intent(in) :: this - integer, intent(in) :: loc_field_data(:) - character(len=:), allocatable :: checksum - character(kind=c_char) :: checksum_c_str(132) - integer :: lstrides(1), lextents(1), lrank=1 - lstrides = (/ array_stride(loc_field_data,2) /) - lextents = (/ 1 /) - call atlas__Checksum__execute_strided_int( this%c_ptr(), & - & loc_field_data, lstrides, lextents, lrank, checksum_c_str ) - checksum = c_str_to_string(checksum_c_str) -end function Checksum__execute_int32_r1 - -function Checksum__execute_int32_r2(this, loc_field_data) result(checksum) - use atlas_checksum_c_binding - class(atlas_Checksum), intent(in) :: this - integer, intent(in) :: loc_field_data(:,:) - character(len=:), allocatable :: checksum - character(kind=c_char) :: checksum_c_str(132) - integer, pointer :: lview(:) - integer :: lstrides(2), lextents(2), lrank=2 - lstrides = (/ array_stride(loc_field_data,2), array_stride(loc_field_data,1) /) - lextents = (/ 1, size (loc_field_data,1) /) - lview => array_view1d(loc_field_data) - call atlas__Checksum__execute_strided_int( this%c_ptr(), & - & lview, lstrides, lextents, lrank, checksum_c_str ) - checksum = c_str_to_string(checksum_c_str) -end function Checksum__execute_int32_r2 - - -function Checksum__execute_int32_r3(this, loc_field_data) result(checksum) - use atlas_checksum_c_binding - class(atlas_Checksum), intent(in) :: this - integer, intent(in) :: loc_field_data(:,:,:) - character(len=:), allocatable :: checksum - character(kind=c_char) :: checksum_c_str(132) - integer, pointer :: lview(:) - integer :: lstrides(3), lextents(3), lrank=3 - lstrides = (/ array_stride(loc_field_data,3), array_stride(loc_field_data,2) , array_stride(loc_field_data,1) /) - lextents = (/ 1, size (loc_field_data,2) , size(loc_field_data,1) /) - lview => array_view1d(loc_field_data) - call atlas__Checksum__execute_strided_int( this%c_ptr(), & - & lview, lstrides, lextents, lrank, checksum_c_str ) - checksum = c_str_to_string(checksum_c_str) -end function Checksum__execute_int32_r3 - -function Checksum__execute_real32_r1(this, loc_field_data) result(checksum) - use atlas_checksum_c_binding - class(atlas_Checksum), intent(in) :: this - real(c_float), intent(in) :: loc_field_data(:) - character(len=:), allocatable :: checksum - character(kind=c_char) :: checksum_c_str(132) - integer :: lstrides(1), lextents(1), lrank=1 - lstrides = (/ array_stride(loc_field_data,1) /) - lextents = (/ 1 /) - call atlas__Checksum__execute_strided_float( this%c_ptr(), & - & loc_field_data, lstrides, lextents, lrank, checksum_c_str ) - checksum = c_str_to_string(checksum_c_str) -end function Checksum__execute_real32_r1 -function Checksum__execute_real32_r2(this, loc_field_data) result(checksum) - use atlas_checksum_c_binding - class(atlas_Checksum), intent(in) :: this - real(c_float), intent(in) :: loc_field_data(:,:) - character(len=:), allocatable :: checksum - character(kind=c_char) :: checksum_c_str(132) - real(c_float), pointer :: lview(:) - integer :: lstrides(2), lextents(2), lrank=2 - lstrides = (/ array_stride(loc_field_data,2), array_stride(loc_field_data,1) /) - lextents = (/ 1, size (loc_field_data,1) /) - lview => array_view1d(loc_field_data) - call atlas__Checksum__execute_strided_float( this%c_ptr(), & - & lview, lstrides, lextents, lrank, checksum_c_str ) - checksum = c_str_to_string(checksum_c_str) -end function Checksum__execute_real32_r2 -function Checksum__execute_real32_r3(this, loc_field_data) result(checksum) - use atlas_checksum_c_binding - class(atlas_Checksum), intent(in) :: this - real(c_float), intent(in) :: loc_field_data(:,:,:) - character(len=:), allocatable :: checksum - character(kind=c_char) :: checksum_c_str(132) - real(c_float), pointer :: lview(:) - integer :: lstrides(3), lextents(3), lrank=3 - lstrides = (/ array_stride(loc_field_data,3), array_stride(loc_field_data,2) , array_stride(loc_field_data,1) /) - lextents = (/ 1, size (loc_field_data,2) , size (loc_field_data,1) /) - lview => array_view1d(loc_field_data) - call atlas__Checksum__execute_strided_float( this%c_ptr(), & - & lview, lstrides, lextents, lrank, checksum_c_str ) - checksum = c_str_to_string(checksum_c_str) -end function Checksum__execute_real32_r3 - -function Checksum__execute_real64_r1(this, loc_field_data) result(checksum) - use atlas_checksum_c_binding - class(atlas_Checksum), intent(in) :: this - real(c_double), intent(in) :: loc_field_data(:) - character(len=:), allocatable :: checksum - character(kind=c_char) :: checksum_c_str(132) - integer :: lstrides(1), lextents(1), lrank=1 - real(c_double), pointer :: lview(:) - lstrides = (/ array_stride(loc_field_data,1) /) - lextents = (/ 1 /) - lview => array_view1d(loc_field_data) - call atlas__Checksum__execute_strided_double( this%c_ptr(), & - & lview, lstrides, lextents, lrank, checksum_c_str ) - checksum = c_str_to_string(checksum_c_str) -end function Checksum__execute_real64_r1 -function Checksum__execute_real64_r2(this, loc_field_data) result(checksum) - use atlas_checksum_c_binding - class(atlas_Checksum), intent(in) :: this - real(c_double), intent(in) :: loc_field_data(:,:) - character(len=:), allocatable :: checksum - character(kind=c_char) :: checksum_c_str(132) - real(c_double), pointer :: lview(:) - integer :: lstrides(2), lextents(2), lrank=2 - lstrides = (/ array_stride(loc_field_data,2), array_stride(loc_field_data,1) /) - lextents = (/ 1, size (loc_field_data,1) /) - lview => array_view1d(loc_field_data) - call atlas__Checksum__execute_strided_double( this%c_ptr(), & - & lview, lstrides, lextents, lrank, checksum_c_str ) - checksum = c_str_to_string(checksum_c_str) -end function Checksum__execute_real64_r2 -function Checksum__execute_real64_r3(this, loc_field_data) result(checksum) - use atlas_checksum_c_binding - class(atlas_Checksum), intent(in) :: this - real(c_double), intent(in) :: loc_field_data(:,:,:) - character(len=:), allocatable :: checksum - character(kind=c_char) :: checksum_c_str(132) - real(c_double), pointer :: lview(:) - integer :: lstrides(3), lextents(3), lrank=3 - lstrides = (/ array_stride(loc_field_data,3), array_stride(loc_field_data,2) , array_stride(loc_field_data,1) /) - lextents = (/ 1, size (loc_field_data,2) , size (loc_field_data,1) /) - lview => array_view1d(loc_field_data) - call atlas__Checksum__execute_strided_double( this%c_ptr(), & - & lview, lstrides, lextents, lrank, checksum_c_str ) - checksum = c_str_to_string(checksum_c_str) -end function Checksum__execute_real64_r3 - -!------------------------------------------------------------------------------- - -ATLAS_FINAL subroutine atlas_Checksum__final_auto(this) - type(atlas_Checksum), intent(inout) :: this -#if FCKIT_FINAL_DEBUGGING - write(0,*) "atlas_Checksum__final_auto" -#endif -#if FCKIT_FINAL_NOT_PROPAGATING - call this%final() -#endif - FCKIT_SUPPRESS_UNUSED( this ) -end subroutine - -! ----------------------------------------------------------------------------- - -end module atlas_checksum_module - diff --git a/src/atlas_f/parallel/atlas_Checksum_module.fypp b/src/atlas_f/parallel/atlas_Checksum_module.fypp new file mode 100644 index 000000000..d17b54002 --- /dev/null +++ b/src/atlas_f/parallel/atlas_Checksum_module.fypp @@ -0,0 +1,184 @@ +! (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" +#:include "internals/atlas_generics.fypp" + +#:set ranks = [1,2,3] + +module atlas_checksum_module + +use, intrinsic :: iso_c_binding, only : c_ptr, c_int, c_long, c_float, c_double, c_char +use fckit_array_module, only : array_stride, array_view1d +use fckit_c_interop_module, only : c_str_to_string +use fckit_object_module, only : fckit_object +use atlas_kinds_module, only : ATLAS_KIND_IDX + +implicit none + +private :: c_ptr, c_int, c_long, c_float, c_double, c_char +private :: array_stride, array_view1d, c_str_to_string +private :: fckit_object + +public :: atlas_Checksum + +private + +!------------------------------------------------------------------------------ +TYPE, extends(fckit_object) :: atlas_Checksum + +! Purpose : +! ------- +! *Checksum* : + +! Methods : +! ------- +! setup : Setup using arrays detailing proc, glb_idx, remote_idx, max_glb_idx +! execute : Do the Checksum + +! Author : +! ------ +! 27-Jun-2014 Willem Deconinck *ECMWF* + +!------------------------------------------------------------------------------ +contains + procedure, private :: Checksum__setup32 + procedure, private :: Checksum__setup64 + + generic :: setup => & + & Checksum__setup32, & + & Checksum__setup64 + + @:generic_public_interface( execute ) + + procedure, public :: delete => atlas_Checksum__delete + +#if FCKIT_FINAL_NOT_INHERITING + final :: atlas_Checksum__final_auto +#endif + +END TYPE atlas_Checksum + +!------------------------------------------------------------------------------ + +interface atlas_Checksum + module procedure atlas_Checksum__ctor +end interface + +!------------------------------------------------------------------------------ +!======================================================== +contains +!======================================================== + +! ------------------------------------------------------------------------------ +! Checksum routines + +function atlas_Checksum__ctor() result(Checksum) + use atlas_checksum_c_binding + type(atlas_Checksum) :: Checksum + call Checksum%reset_c_ptr( atlas__Checksum__new() ) +end function atlas_checksum__ctor + +subroutine atlas_Checksum__delete(this) + use atlas_checksum_c_binding + class(atlas_Checksum), intent(inout) :: this + if ( .not. this%is_null() ) then + call atlas__Checksum__delete(this%CPTR_PGIBUG_A) + end if + call this%reset_c_ptr() +end subroutine atlas_Checksum__delete + +subroutine Checksum__setup32(this, part, remote_idx, glb_idx ) + use atlas_checksum_c_binding + class(atlas_Checksum), intent(in) :: this + integer(c_int), intent(in) :: part(:) + integer(ATLAS_KIND_IDX), intent(in) :: remote_idx(:) + integer(c_int), intent(in) :: glb_idx(:) + call atlas__Checksum__setup32( this%CPTR_PGIBUG_A, part, remote_idx, 1, & + & glb_idx, size(part) ) +end subroutine Checksum__setup32 + +subroutine Checksum__setup64(this, part, remote_idx, glb_idx) + use atlas_checksum_c_binding + class(atlas_Checksum), intent(in) :: this + integer(c_int), intent(in) :: part(:) + integer(ATLAS_KIND_IDX), intent(in) :: remote_idx(:) + integer(c_long), intent(in) :: glb_idx(:) + call atlas__Checksum__setup64( this%CPTR_PGIBUG_A, part, remote_idx, 1, & + & glb_idx, size(part) ) +end subroutine Checksum__setup64 + +#:for dtype,ftype,ctype in types[:4] + +function execute_${dtype}$_r1(this, loc_field_data) result(checksum) + use atlas_checksum_c_binding + class(atlas_Checksum), intent(in) :: this + ${ftype}$, intent(in) :: loc_field_data(:) + character(len=:), allocatable :: checksum + character(kind=c_char) :: checksum_c_str(132) + integer :: lstrides(1), lextents(1), lrank=1 + ${ftype}$, pointer :: lview(:) + lstrides = (/ array_stride(loc_field_data,1) /) + lextents = (/ 1 /) + lview => array_view1d(loc_field_data) + call atlas__Checksum__execute_strided_${ctype}$( this%CPTR_PGIBUG_A, & + & lview, lstrides, lextents, lrank, checksum_c_str ) + checksum = c_str_to_string(checksum_c_str) +end function + +function execute_${dtype}$_r2(this, loc_field_data) result(checksum) + use atlas_checksum_c_binding + class(atlas_Checksum), intent(in) :: this + ${ftype}$, intent(in) :: loc_field_data(:,:) + character(len=:), allocatable :: checksum + character(kind=c_char) :: checksum_c_str(132) + ${ftype}$, pointer :: lview(:) + integer :: lstrides(2), lextents(2), lrank=2 + lstrides = (/ array_stride(loc_field_data,2), array_stride(loc_field_data,1) /) + lextents = (/ 1, size (loc_field_data,1) /) + lview => array_view1d(loc_field_data) + call atlas__Checksum__execute_strided_${ctype}$( this%CPTR_PGIBUG_A, & + & lview, lstrides, lextents, lrank, checksum_c_str ) + checksum = c_str_to_string(checksum_c_str) +end function + +function execute_${dtype}$_r3(this, loc_field_data) result(checksum) + use atlas_checksum_c_binding + class(atlas_Checksum), intent(in) :: this + ${ftype}$, intent(in) :: loc_field_data(:,:,:) + character(len=:), allocatable :: checksum + character(kind=c_char) :: checksum_c_str(132) + ${ftype}$, pointer :: lview(:) + integer :: lstrides(3), lextents(3), lrank=3 + lstrides = (/ array_stride(loc_field_data,3), array_stride(loc_field_data,2) , array_stride(loc_field_data,1) /) + lextents = (/ 1, size (loc_field_data,2) , size (loc_field_data,1) /) + lview => array_view1d(loc_field_data) + call atlas__Checksum__execute_strided_${ctype}$( this%CPTR_PGIBUG_A, & + & lview, lstrides, lextents, lrank, checksum_c_str ) + checksum = c_str_to_string(checksum_c_str) +end function + +#:endfor + +!------------------------------------------------------------------------------- + +ATLAS_FINAL subroutine atlas_Checksum__final_auto(this) + type(atlas_Checksum), intent(inout) :: this +#if FCKIT_FINAL_DEBUGGING + write(0,*) "atlas_Checksum__final_auto" +#endif +#if FCKIT_FINAL_NOT_PROPAGATING + call this%final() +#endif + FCKIT_SUPPRESS_UNUSED( this ) +end subroutine + +! ----------------------------------------------------------------------------- + +end module atlas_checksum_module + diff --git a/src/atlas_f/parallel/atlas_GatherScatter_module.F90 b/src/atlas_f/parallel/atlas_GatherScatter_module.F90 deleted file mode 100644 index 2a9c88045..000000000 --- a/src/atlas_f/parallel/atlas_GatherScatter_module.F90 +++ /dev/null @@ -1,625 +0,0 @@ -#include "atlas/atlas_f.h" - -module atlas_gatherscatter_module - -use, intrinsic :: iso_c_binding, only : c_ptr, c_int, c_long, c_float, c_double -use fckit_array_module, only : array_stride, array_view1d -use fckit_object_module, only : fckit_object - -implicit none - -private :: c_ptr, c_int, c_long, c_float, c_double -private :: array_stride, array_view1d -private :: fckit_object - -public :: atlas_GatherScatter - -private - -!------------------------------------------------------------------------------ -TYPE, extends(fckit_object) :: atlas_GatherScatter - -! Purpose : -! ------- -! *Gather* : - -! Methods : -! ------- -! setup : Setup using arrays detailing proc, glb_idx, remote_idx, max_glb_idx -! execute : Do the gather - -! Author : -! ------ -! 17-Dec-2013 Willem Deconinck *ECMWF* - -!------------------------------------------------------------------------------ -contains - procedure :: glb_dof => GatherScatter__glb_dof - procedure, private :: GatherScatter__setup32 - procedure, private :: GatherScatter__setup64 - procedure, private :: GatherScatter__gather_int32_r1_r1 - procedure, private :: GatherScatter__gather_int32_r2_r2 - procedure, private :: GatherScatter__gather_int32_r3_r3 - procedure, private :: GatherScatter__gather_int64_r1_r1 - procedure, private :: GatherScatter__gather_int64_r2_r2 - procedure, private :: GatherScatter__gather_int64_r3_r3 - procedure, private :: GatherScatter__gather_real32_r1_r1 - procedure, private :: GatherScatter__gather_real32_r2_r2 - procedure, private :: GatherScatter__gather_real32_r3_r3 - procedure, private :: GatherScatter__gather_real64_r1_r1 - procedure, private :: GatherScatter__gather_real64_r2_r2 - procedure, private :: GatherScatter__gather_real64_r3_r3 - procedure, private :: GatherScatter__scatter_int32_r1_r1 - procedure, private :: GatherScatter__scatter_int32_r2_r2 - procedure, private :: GatherScatter__scatter_int64_r1_r1 - procedure, private :: GatherScatter__scatter_int64_r2_r2 - procedure, private :: GatherScatter__scatter_real32_r1_r1 - procedure, private :: GatherScatter__scatter_real32_r2_r2 - procedure, private :: GatherScatter__scatter_real64_r1_r1 - procedure, private :: GatherScatter__scatter_real64_r2_r2 - procedure, private :: GatherScatter__scatter_real64_r3_r3 - generic :: setup => & - & GatherScatter__setup32, & - & GatherScatter__setup64 - generic :: gather => & - & GatherScatter__gather_int32_r1_r1, & - & GatherScatter__gather_int32_r2_r2, & - & GatherScatter__gather_int32_r3_r3, & - & GatherScatter__gather_int64_r1_r1, & - & GatherScatter__gather_int64_r2_r2, & - & GatherScatter__gather_int64_r3_r3, & - & GatherScatter__gather_real32_r1_r1, & - & GatherScatter__gather_real32_r2_r2, & - & GatherScatter__gather_real32_r3_r3, & - & GatherScatter__gather_real64_r1_r1, & - & GatherScatter__gather_real64_r2_r2, & - & GatherScatter__gather_real64_r3_r3 - generic :: scatter => & - & GatherScatter__scatter_int32_r1_r1, & - & GatherScatter__scatter_int32_r2_r2, & - & GatherScatter__scatter_int64_r1_r1, & - & GatherScatter__scatter_int64_r2_r2, & - & GatherScatter__scatter_real32_r1_r1, & - & GatherScatter__scatter_real32_r2_r2, & - & GatherScatter__scatter_real64_r1_r1, & - & GatherScatter__scatter_real64_r2_r2, & - & GatherScatter__scatter_real64_r3_r3 - - procedure, public :: delete => atlas_GatherScatter__delete - -#if FCKIT_FINAL_NOT_INHERITING - final :: atlas_GatherScatter__final_auto -#endif - -END TYPE atlas_GatherScatter -!------------------------------------------------------------------------------ - -interface atlas_GatherScatter - module procedure atlas_GatherScatter__ctor -end interface - -!------------------------------------------------------------------------------ - - -!======================================================== -contains -!======================================================== - -! ------------------------------------------------------------------------------ -! Gather routines - -function atlas_GatherScatter__ctor() result(gather) - use atlas_gatherscatter_c_binding - type(atlas_GatherScatter) :: gather - call gather%reset_c_ptr( atlas__GatherScatter__new() ) -end function atlas_GatherScatter__ctor - -subroutine atlas_GatherScatter__delete(this) - use atlas_gatherscatter_c_binding - class(atlas_GatherScatter), intent(inout) :: this - if ( .not. this%is_null() ) then - call atlas__GatherScatter__delete(this%c_ptr()) - end if - call this%reset_c_ptr() -end subroutine atlas_GatherScatter__delete - - -subroutine GatherScatter__setup32(this, part, remote_idx, glb_idx) - use atlas_gatherscatter_c_binding - class(atlas_GatherScatter), intent(in) :: this - integer(c_int), intent(in) :: part(:) - integer(c_int), intent(in) :: remote_idx(:) - integer(c_int), intent(in) :: glb_idx(:) - call atlas__GatherScatter__setup32( this%c_ptr(), part, remote_idx, 1, & - & glb_idx, size(part) ) -end subroutine GatherScatter__setup32 - -subroutine GatherScatter__setup64(this, part, remote_idx, glb_idx ) - use atlas_gatherscatter_c_binding - class(atlas_GatherScatter), intent(in) :: this - integer(c_int), intent(in) :: part(:) - integer(c_int), intent(in) :: remote_idx(:) - integer(c_long), intent(in) :: glb_idx(:) - call atlas__GatherScatter__setup64( this%c_ptr(), part, remote_idx, 1, & - & glb_idx, size(part) ) -end subroutine GatherScatter__setup64 - -function GatherScatter__glb_dof(this) result(glb_dof) - use atlas_gatherscatter_c_binding - class(atlas_GatherScatter), intent(in) :: this - integer :: glb_dof - glb_dof = atlas__GatherScatter__glb_dof(this%c_ptr()) -end function GatherScatter__glb_dof - -subroutine GatherScatter__gather_int32_r1_r1(this, loc_field_data, glb_field_data) - use atlas_gatherscatter_c_binding - class(atlas_GatherScatter), intent(in) :: this - integer(c_int), intent(in) :: loc_field_data(:) - integer(c_int), intent(out) :: glb_field_data(:) - integer(c_int), pointer :: lview(:), gview(:) - integer :: lstrides(1), lextents(1), lrank=1 - integer :: gstrides(1), gextents(1), grank=1 - lstrides = (/ array_stride(loc_field_data,2) /) - lextents = (/ 1 /) - lview => array_view1d(loc_field_data) - gstrides = (/ array_stride(glb_field_data,2) /) - gextents = (/ 1 /) - gview => array_view1d(glb_field_data) - if( size(gview) == 0 ) then - allocate(gview(0)) - endif - call atlas__GatherScatter__gather_int( this%c_ptr(), & - & lview, lstrides, lextents, lrank, & - & gview, gstrides, gextents, grank ) -end subroutine GatherScatter__gather_int32_r1_r1 - - -subroutine GatherScatter__gather_int32_r2_r2(this, loc_field_data, glb_field_data) - use atlas_gatherscatter_c_binding - class(atlas_GatherScatter), intent(in) :: this - integer(c_int), intent(in) :: loc_field_data(:,:) - integer(c_int), intent(out) :: glb_field_data(:,:) - integer(c_int), pointer :: lview(:), gview(:) - integer :: lstrides(2), lextents(2), lrank=2 - integer :: gstrides(2), gextents(2), grank=2 - lstrides = (/ array_stride(loc_field_data,2), array_stride(loc_field_data,1) /) - lextents = (/ 1, size (loc_field_data,1) /) - lview => array_view1d(loc_field_data) - gstrides = (/ array_stride(glb_field_data,2), array_stride(glb_field_data,1) /) - gextents = (/ 1, size (glb_field_data,1) /) - gview => array_view1d(glb_field_data) - if( size(gview) == 0 ) then - allocate(gview(0)) - endif - call atlas__GatherScatter__gather_int( this%c_ptr(), & - & lview, lstrides, lextents, lrank, & - & gview, gstrides, gextents, grank ) -end subroutine GatherScatter__gather_int32_r2_r2 - - -subroutine GatherScatter__gather_int32_r3_r3(this, loc_field_data, glb_field_data) - use atlas_gatherscatter_c_binding - class(atlas_GatherScatter), intent(in) :: this - integer(c_int), intent(in) :: loc_field_data(:,:,:) - integer(c_int), intent(out) :: glb_field_data(:,:,:) - integer(c_int), pointer :: lview(:), gview(:) - integer :: lstrides(3), lextents(3), lrank=3 - integer :: gstrides(3), gextents(3), grank=3 - lstrides = (/ array_stride(loc_field_data,3), array_stride(loc_field_data,2) , array_stride(loc_field_data,1) /) - lextents = (/ 1, size (loc_field_data,2) , size(loc_field_data,1) /) - lview => array_view1d(loc_field_data) - gstrides = (/ array_stride(glb_field_data,3), array_stride(glb_field_data,2) , array_stride(glb_field_data,1) /) - gextents = (/ 1, size (glb_field_data,2) , size (glb_field_data,1) /) - gview => array_view1d(glb_field_data) - if( size(gview) == 0 ) then - allocate(gview(0)) - endif - call atlas__GatherScatter__gather_int( this%c_ptr(), & - & lview, lstrides, lextents, lrank, & - & gview, gstrides, gextents, grank ) -end subroutine GatherScatter__gather_int32_r3_r3 - -subroutine GatherScatter__gather_int64_r1_r1(this, loc_field_data, glb_field_data) - use atlas_gatherscatter_c_binding - class(atlas_GatherScatter), intent(in) :: this - integer(c_long), intent(in) :: loc_field_data(:) - integer(c_long), intent(out) :: glb_field_data(:) - integer(c_long), pointer :: lview(:), gview(:) - integer :: lstrides(1), lextents(1), lrank=1 - integer :: gstrides(1), gextents(1), grank=1 - lstrides = (/ array_stride(loc_field_data,2) /) - lextents = (/ 1 /) - lview => array_view1d(loc_field_data) - gstrides = (/ array_stride(glb_field_data,2) /) - gextents = (/ 1 /) - gview => array_view1d(glb_field_data) - if( size(gview) == 0 ) then - allocate(gview(0)) - endif - call atlas__GatherScatter__gather_long( this%c_ptr(), & - & lview, lstrides, lextents, lrank, & - & gview, gstrides, gextents, grank ) -end subroutine GatherScatter__gather_int64_r1_r1 - - -subroutine GatherScatter__gather_int64_r2_r2(this, loc_field_data, glb_field_data) - use atlas_gatherscatter_c_binding - class(atlas_GatherScatter), intent(in) :: this - integer(c_long), intent(in) :: loc_field_data(:,:) - integer(c_long), intent(out) :: glb_field_data(:,:) - integer(c_long), pointer :: lview(:), gview(:) - integer :: lstrides(2), lextents(2), lrank=2 - integer :: gstrides(2), gextents(2), grank=2 - lstrides = (/ array_stride(loc_field_data,2), array_stride(loc_field_data,1) /) - lextents = (/ 1, size (loc_field_data,1) /) - lview => array_view1d(loc_field_data) - gstrides = (/ array_stride(glb_field_data,2), array_stride(glb_field_data,1) /) - gextents = (/ 1, size (glb_field_data,1) /) - gview => array_view1d(glb_field_data) - if( size(gview) == 0 ) then - allocate(gview(0)) - endif - call atlas__GatherScatter__gather_long( this%c_ptr(), & - & lview, lstrides, lextents, lrank, & - & gview, gstrides, gextents, grank ) -end subroutine GatherScatter__gather_int64_r2_r2 - - -subroutine GatherScatter__gather_int64_r3_r3(this, loc_field_data, glb_field_data) - use atlas_gatherscatter_c_binding - class(atlas_GatherScatter), intent(in) :: this - integer(c_long), intent(in) :: loc_field_data(:,:,:) - integer(c_long), intent(out) :: glb_field_data(:,:,:) - integer(c_long), pointer :: lview(:), gview(:) - integer :: lstrides(3), lextents(3), lrank=3 - integer :: gstrides(3), gextents(3), grank=3 - lstrides = (/ array_stride(loc_field_data,3), array_stride(loc_field_data,2) , array_stride(loc_field_data,1) /) - lextents = (/ 1, size (loc_field_data,2) , size(loc_field_data,1) /) - lview => array_view1d(loc_field_data) - gstrides = (/ array_stride(glb_field_data,3), array_stride(glb_field_data,2) , array_stride(glb_field_data,1) /) - gextents = (/ 1, size (glb_field_data,2) , size (glb_field_data,1) /) - gview => array_view1d(glb_field_data) - if( size(gview) == 0 ) then - allocate(gview(0)) - endif - call atlas__GatherScatter__gather_long( this%c_ptr(), & - & lview, lstrides, lextents, lrank, & - & gview, gstrides, gextents, grank ) -end subroutine GatherScatter__gather_int64_r3_r3 - - -subroutine GatherScatter__gather_real32_r1_r1(this, loc_field_data, glb_field_data) - use atlas_gatherscatter_c_binding - class(atlas_GatherScatter), intent(in) :: this - real(c_float), intent(in) :: loc_field_data(:) - real(c_float), intent(out) :: glb_field_data(:) - integer :: lstrides(1), lextents(1), lrank=1 - integer :: gstrides(1), gextents(1), grank=1 - real(c_float), pointer :: lview(:), gview(:) - lstrides = (/ array_stride(loc_field_data,2) /) - lextents = (/ 1 /) - lview => array_view1d(loc_field_data) - gstrides = (/ array_stride(glb_field_data,2) /) - gextents = (/ 1 /) - gview => array_view1d(glb_field_data) - if( size(gview) == 0 ) then - allocate(gview(0)) - endif - call atlas__GatherScatter__gather_float( this%c_ptr(), & - & lview, lstrides, lextents, lrank, & - & gview, gstrides, gextents, grank ) -end subroutine GatherScatter__gather_real32_r1_r1 -subroutine GatherScatter__gather_real32_r2_r2(this, loc_field_data, glb_field_data) - use atlas_gatherscatter_c_binding - class(atlas_GatherScatter), intent(in) :: this - real(c_float), intent(in) :: loc_field_data(:,:) - real(c_float), intent(out) :: glb_field_data(:,:) - real(c_float), pointer :: lview(:), gview(:) - integer :: lstrides(2), lextents(2), lrank=2 - integer :: gstrides(2), gextents(2), grank=2 - lstrides = (/ array_stride(loc_field_data,2), array_stride(loc_field_data,1) /) - lextents = (/ 1, size (loc_field_data,1) /) - lview => array_view1d(loc_field_data) - gstrides = (/ array_stride(glb_field_data,2), array_stride(glb_field_data,1) /) - gextents = (/ 1, size (glb_field_data,1) /) - gview => array_view1d(glb_field_data) - if( size(gview) == 0 ) then - allocate(gview(0)) - endif - call atlas__GatherScatter__gather_float( this%c_ptr(), & - & lview, lstrides, lextents, lrank, & - & gview, gstrides, gextents, grank ) -end subroutine GatherScatter__gather_real32_r2_r2 -subroutine GatherScatter__gather_real32_r3_r3(this, loc_field_data, glb_field_data) - use atlas_gatherscatter_c_binding - class(atlas_GatherScatter), intent(in) :: this - real(c_float), intent(in) :: loc_field_data(:,:,:) - real(c_float), intent(out) :: glb_field_data(:,:,:) - real(c_float), pointer :: lview(:), gview(:) - integer :: lstrides(3), lextents(3), lrank=3 - integer :: gstrides(3), gextents(3), grank=3 - lstrides = (/ array_stride(loc_field_data,3), array_stride(loc_field_data,2) , array_stride(loc_field_data,1) /) - lextents = (/ 1, size (loc_field_data,2) , size (loc_field_data,1) /) - lview => array_view1d(loc_field_data) - gstrides = (/ array_stride(glb_field_data,3), array_stride(glb_field_data,2) , array_stride(glb_field_data,1) /) - gextents = (/ 1, size (glb_field_data,2) , size (glb_field_data,1) /) - gview => array_view1d(glb_field_data) - if( size(gview) == 0 ) then - allocate(gview(0)) - endif - call atlas__GatherScatter__gather_float( this%c_ptr(), & - & lview, lstrides, lextents, lrank, & - & gview, gstrides, gextents, grank ) -end subroutine GatherScatter__gather_real32_r3_r3 - -subroutine GatherScatter__gather_real64_r1_r1(this, loc_field_data, glb_field_data) - use atlas_gatherscatter_c_binding - class(atlas_GatherScatter), intent(in) :: this - real(c_double), intent(in) :: loc_field_data(:) - real(c_double), intent(out) :: glb_field_data(:) - integer :: lstrides(1), lextents(1), lrank=1 - integer :: gstrides(1), gextents(1), grank=1 - real(c_double), pointer :: lview(:), gview(:) - lstrides = (/ array_stride(loc_field_data,1) /) - lextents = (/ 1 /) - lview => array_view1d(loc_field_data) - gstrides = (/ array_stride(glb_field_data,1) /) - gextents = (/ 1 /) - gview => array_view1d(glb_field_data) - !write(0,*) atlas_mpi_rank(),"lstrides",lstrides - !write(0,*) atlas_mpi_rank(),"lextents",lextents - !write(0,*) atlas_mpi_rank(),"gstrides",gstrides - !write(0,*) atlas_mpi_rank(),"gextents",gextents - !write(0,*) atlas_mpi_rank(),"localsize",lstrides(1)*lextents(1)*size(loc_field_data) - !write(0,*) "loc address, size = ",loc(loc_field_data(1)),size(loc_field_data), loc(lview(1)) - !write(0,*) "glb address, size = ",loc(gview(1)),size(gview) - - call atlas__GatherScatter__gather_double( this%c_ptr(), & - & lview, lstrides, lextents, lrank, & - & gview, gstrides, gextents, grank ) -end subroutine GatherScatter__gather_real64_r1_r1 -subroutine GatherScatter__gather_real64_r2_r2(this, loc_field_data, glb_field_data) - use atlas_gatherscatter_c_binding - class(atlas_GatherScatter), intent(in) :: this - real(c_double), intent(in) :: loc_field_data(:,:) - real(c_double), intent(out) :: glb_field_data(:,:) - real(c_double), pointer :: lview(:), gview(:) - integer :: lstrides(2), lextents(2), lrank=2 - integer :: gstrides(2), gextents(2), grank=2 - lstrides = (/ array_stride(loc_field_data,2), array_stride(loc_field_data,1) /) - lextents = (/ 1, size (loc_field_data,1) /) - lview => array_view1d(loc_field_data) - gstrides = (/ array_stride(glb_field_data,2), array_stride(glb_field_data,1) /) - gextents = (/ 1, size (glb_field_data,1) /) - gview => array_view1d(glb_field_data) - if( size(gview) == 0 ) then - allocate(gview(0)) - endif - call atlas__GatherScatter__gather_double( this%c_ptr(), & - & lview, lstrides, lextents, lrank, & - & gview, gstrides, gextents, grank ) -end subroutine GatherScatter__gather_real64_r2_r2 -subroutine GatherScatter__gather_real64_r3_r3(this, loc_field_data, glb_field_data) - use atlas_gatherscatter_c_binding - class(atlas_GatherScatter), intent(in) :: this - real(c_double), intent(in) :: loc_field_data(:,:,:) - real(c_double), intent(out) :: glb_field_data(:,:,:) - real(c_double), pointer :: lview(:), gview(:) - integer :: lstrides(3), lextents(3), lrank=3 - integer :: gstrides(3), gextents(3), grank=3 - lstrides = (/ array_stride(loc_field_data,3), array_stride(loc_field_data,2) , array_stride(loc_field_data,1) /) - lextents = (/ 1, size (loc_field_data,2) , size (loc_field_data,1) /) - lview => array_view1d(loc_field_data) - gstrides = (/ array_stride(glb_field_data,3), array_stride(glb_field_data,2) , array_stride(glb_field_data,1) /) - gextents = (/ 1, size (glb_field_data,2) , size (glb_field_data,1) /) - gview => array_view1d(glb_field_data) - if( size(gview) == 0 ) then - allocate(gview(0)) - endif - call atlas__GatherScatter__gather_double( this%c_ptr(), & - & lview, lstrides, lextents, lrank, & - & gview, gstrides, gextents, grank ) -end subroutine GatherScatter__gather_real64_r3_r3 - -! ----------------------------------------------------------------------------- - -subroutine GatherScatter__scatter_int32_r1_r1(this, glb_field_data, loc_field_data) - use atlas_gatherscatter_c_binding - class(atlas_GatherScatter), intent(in) :: this - integer(c_int), intent(in) :: glb_field_data(:) - integer(c_int), intent(out) :: loc_field_data(:) - integer(c_int), pointer :: lview(:), gview(:) - integer :: lstrides(1), lextents(1), lrank=1 - integer :: gstrides(1), gextents(1), grank=1 - lstrides = (/ array_stride(loc_field_data,1) /) - lextents = (/ 1 /) - lview => array_view1d(loc_field_data) - gstrides = (/ array_stride(glb_field_data,1) /) - gextents = (/ 1 /) - gview => array_view1d(glb_field_data) - call atlas__GatherScatter__scatter_int( this%c_ptr(), & - & gview, gstrides, gextents, grank, & - & lview, lstrides, lextents, lrank ) -end subroutine GatherScatter__scatter_int32_r1_r1 - -subroutine GatherScatter__scatter_int32_r2_r2(this, glb_field_data, loc_field_data) - use atlas_gatherscatter_c_binding - class(atlas_GatherScatter), intent(in) :: this - integer(c_int), intent(in) :: glb_field_data(:,:) - integer(c_int), intent(out) :: loc_field_data(:,:) - integer(c_int), pointer :: lview(:), gview(:) - integer :: lstrides(2), lextents(2), lrank=2 - integer :: gstrides(2), gextents(2), grank=2 - lstrides = (/ array_stride(loc_field_data,2), array_stride(loc_field_data,1) /) - lextents = (/ 1, size (loc_field_data,1) /) - lview => array_view1d(loc_field_data) - gstrides = (/ array_stride(glb_field_data,2), array_stride(glb_field_data,1) /) - gextents = (/ 1, size (glb_field_data,1) /) - gview => array_view1d(glb_field_data) - if( size(gview) == 0 ) then - allocate(gview(0)) - endif - call atlas__GatherScatter__scatter_int( this%c_ptr(), & - & gview, gstrides, gextents, grank, & - & lview, lstrides, lextents, lrank ) -end subroutine GatherScatter__scatter_int32_r2_r2 - -subroutine GatherScatter__scatter_int64_r1_r1(this, glb_field_data, loc_field_data) - use atlas_gatherscatter_c_binding - class(atlas_GatherScatter), intent(in) :: this - integer(c_long), intent(in) :: glb_field_data(:) - integer(c_long), intent(out) :: loc_field_data(:) - integer(c_long), pointer :: lview(:), gview(:) - integer :: lstrides(1), lextents(1), lrank=1 - integer :: gstrides(1), gextents(1), grank=1 - lstrides = (/ array_stride(loc_field_data,1) /) - lextents = (/ 1 /) - lview => array_view1d(loc_field_data) - gstrides = (/ array_stride(glb_field_data,1) /) - gextents = (/ 1 /) - gview => array_view1d(glb_field_data) - call atlas__GatherScatter__scatter_long( this%c_ptr(), & - & gview, gstrides, gextents, grank, & - & lview, lstrides, lextents, lrank ) -end subroutine GatherScatter__scatter_int64_r1_r1 - -subroutine GatherScatter__scatter_int64_r2_r2(this, glb_field_data, loc_field_data) - use atlas_gatherscatter_c_binding - class(atlas_GatherScatter), intent(in) :: this - integer(c_long), intent(in) :: glb_field_data(:,:) - integer(c_long), intent(out) :: loc_field_data(:,:) - integer(c_long), pointer :: lview(:), gview(:) - integer :: lstrides(2), lextents(2), lrank=2 - integer :: gstrides(2), gextents(2), grank=2 - lstrides = (/ array_stride(loc_field_data,2), array_stride(loc_field_data,1) /) - lextents = (/ 1, size (loc_field_data,1) /) - lview => array_view1d(loc_field_data) - gstrides = (/ array_stride(glb_field_data,2), array_stride(glb_field_data,1) /) - gextents = (/ 1, size (glb_field_data,1) /) - gview => array_view1d(glb_field_data) - if( size(gview) == 0 ) then - allocate(gview(0)) - endif - call atlas__GatherScatter__scatter_long( this%c_ptr(), & - & gview, gstrides, gextents, grank, & - & lview, lstrides, lextents, lrank ) -end subroutine GatherScatter__scatter_int64_r2_r2 - - -subroutine GatherScatter__scatter_real32_r1_r1(this, glb_field_data, loc_field_data) - use atlas_gatherscatter_c_binding - class(atlas_GatherScatter), intent(in) :: this - real(c_float), intent(in) :: glb_field_data(:) - real(c_float), intent(out) :: loc_field_data(:) - real(c_float), pointer :: lview(:), gview(:) - integer :: lstrides(1), lextents(1), lrank=1 - integer :: gstrides(1), gextents(1), grank=1 - lstrides = (/ array_stride(loc_field_data,1) /) - lextents = (/ 1 /) - lview => array_view1d(loc_field_data) - gstrides = (/ array_stride(glb_field_data,1) /) - gextents = (/ 1 /) - gview => array_view1d(glb_field_data) - call atlas__GatherScatter__scatter_float( this%c_ptr(), & - & gview, gstrides, gextents, grank, & - & lview, lstrides, lextents, lrank ) -end subroutine GatherScatter__scatter_real32_r1_r1 -subroutine GatherScatter__scatter_real32_r2_r2(this, glb_field_data, loc_field_data) - use atlas_gatherscatter_c_binding - class(atlas_GatherScatter), intent(in) :: this - real(c_float), intent(in) :: glb_field_data(:,:) - real(c_float), intent(out) :: loc_field_data(:,:) - real(c_float), pointer :: lview(:), gview(:) - integer :: lstrides(2), lextents(2), lrank=2 - integer :: gstrides(2), gextents(2), grank=2 - lstrides = (/ array_stride(loc_field_data,2), array_stride(loc_field_data,1) /) - lextents = (/ 1, size (loc_field_data,1) /) - lview => array_view1d(loc_field_data) - gstrides = (/ array_stride(glb_field_data,2), array_stride(glb_field_data,1) /) - gextents = (/ 1, size (glb_field_data,1) /) - gview => array_view1d(glb_field_data) - if( size(gview) == 0 ) then - allocate(gview(0)) - endif - call atlas__GatherScatter__scatter_float( this%c_ptr(), & - & gview, gstrides, gextents, grank, & - & lview, lstrides, lextents, lrank ) -end subroutine GatherScatter__scatter_real32_r2_r2 -subroutine GatherScatter__scatter_real64_r1_r1(this, glb_field_data, loc_field_data) - use atlas_gatherscatter_c_binding - class(atlas_GatherScatter), intent(in) :: this - real(c_double), intent(in) :: glb_field_data(:) - real(c_double), intent(out) :: loc_field_data(:) - real(c_double), pointer :: lview(:), gview(:) - integer :: lstrides(1), lextents(1), lrank=1 - integer :: gstrides(1), gextents(1), grank=1 - lstrides = (/ array_stride(loc_field_data,1) /) - lextents = (/ 1 /) - lview => array_view1d(loc_field_data) - gstrides = (/ array_stride(glb_field_data,1) /) - gextents = (/ 1 /) - gview => array_view1d(glb_field_data) - call atlas__GatherScatter__scatter_double( this%c_ptr(), & - & gview, gstrides, gextents, grank, & - & lview, lstrides, lextents, lrank ) -end subroutine GatherScatter__scatter_real64_r1_r1 -subroutine GatherScatter__scatter_real64_r2_r2(this, glb_field_data, loc_field_data) - use atlas_gatherscatter_c_binding - class(atlas_GatherScatter), intent(in) :: this - real(c_double), intent(in) :: glb_field_data(:,:) - real(c_double), intent(out) :: loc_field_data(:,:) - real(c_double), pointer :: lview(:), gview(:) - integer :: lstrides(2), lextents(2), lrank=2 - integer :: gstrides(2), gextents(2), grank=2 - lstrides = (/ array_stride(loc_field_data,2), array_stride(loc_field_data,1) /) - lextents = (/ 1, size (loc_field_data,1) /) - lview => array_view1d(loc_field_data) - gstrides = (/ array_stride(glb_field_data,2), array_stride(glb_field_data,1) /) - gextents = (/ 1, size (glb_field_data,1) /) - gview => array_view1d(glb_field_data) - if( size(gview) == 0 ) then - allocate(gview(0)) - endif - call atlas__GatherScatter__scatter_double( this%c_ptr(), & - & gview, gstrides, gextents, grank, & - & lview, lstrides, lextents, lrank ) -end subroutine GatherScatter__scatter_real64_r2_r2 - -subroutine GatherScatter__scatter_real64_r3_r3(this, glb_field_data, loc_field_data) - use atlas_gatherscatter_c_binding - class(atlas_GatherScatter), intent(in) :: this - real(c_double), intent(in) :: glb_field_data(:,:,:) - real(c_double), intent(out) :: loc_field_data(:,:,:) - real(c_double), pointer :: lview(:), gview(:) - integer :: lstrides(3), lextents(3), lrank=3 - integer :: gstrides(3), gextents(3), grank=3 - lstrides = (/ array_stride(loc_field_data,3), array_stride(loc_field_data,2), array_stride(loc_field_data,1) /) - lextents = (/ 1, size (loc_field_data,2) , size (loc_field_data,1) /) - lview => array_view1d(loc_field_data) - gstrides = (/ array_stride(glb_field_data,3), array_stride(glb_field_data,2), array_stride(glb_field_data,1) /) - gextents = (/ 1, size (glb_field_data,2) , size (glb_field_data,1) /) - gview => array_view1d(glb_field_data) - if( size(gview) == 0 ) then - allocate(gview(0)) - endif - call atlas__GatherScatter__scatter_double( this%c_ptr(), & - & gview, gstrides, gextents, grank, & - & lview, lstrides, lextents, lrank ) -end subroutine GatherScatter__scatter_real64_r3_r3 - -!------------------------------------------------------------------------------- - -ATLAS_FINAL subroutine atlas_GatherScatter__final_auto(this) - type(atlas_GatherScatter), intent(inout) :: this -#if FCKIT_FINAL_DEBUGGING - write(0,*) "atlas_GatherScatter__final_auto" -#endif -#if FCKIT_FINAL_NOT_PROPAGATING - call this%final() -#endif - FCKIT_SUPPRESS_UNUSED( this ) -end subroutine - -! ----------------------------------------------------------------------------- - -end module atlas_gatherscatter_module diff --git a/src/atlas_f/parallel/atlas_GatherScatter_module.fypp b/src/atlas_f/parallel/atlas_GatherScatter_module.fypp new file mode 100644 index 000000000..3dc164729 --- /dev/null +++ b/src/atlas_f/parallel/atlas_GatherScatter_module.fypp @@ -0,0 +1,279 @@ +! (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" +#:include "internals/atlas_generics.fypp" + +#:set ranks = [1,2,3] + +module atlas_gatherscatter_module + +use, intrinsic :: iso_c_binding, only : c_ptr, c_int, c_long, c_float, c_double +use fckit_array_module, only : array_stride, array_view1d +use fckit_object_module, only : fckit_object +use atlas_kinds_module, only : ATLAS_KIND_IDX + +implicit none + +private :: c_ptr, c_int, c_long, c_float, c_double +private :: array_stride, array_view1d +private :: fckit_object + +public :: atlas_GatherScatter + +private + +!------------------------------------------------------------------------------ +TYPE, extends(fckit_object) :: atlas_GatherScatter + +! Purpose : +! ------- +! *Gather* : + +! Methods : +! ------- +! setup : Setup using arrays detailing proc, glb_idx, remote_idx, max_glb_idx +! execute : Do the gather + +! Author : +! ------ +! 17-Dec-2013 Willem Deconinck *ECMWF* + +!------------------------------------------------------------------------------ +contains + procedure :: glb_dof => GatherScatter__glb_dof + procedure, private :: GatherScatter__setup32 + procedure, private :: GatherScatter__setup64 + + generic :: setup => & + & GatherScatter__setup32, & + & GatherScatter__setup64 + + @:generic_public_interface( gather ) + @:generic_public_interface( scatter ) + + + procedure, public :: delete => atlas_GatherScatter__delete + +#if FCKIT_FINAL_NOT_INHERITING + final :: atlas_GatherScatter__final_auto +#endif + +END TYPE atlas_GatherScatter +!------------------------------------------------------------------------------ + +interface atlas_GatherScatter + module procedure atlas_GatherScatter__ctor +end interface + +!------------------------------------------------------------------------------ + + +!======================================================== +contains +!======================================================== + +! ------------------------------------------------------------------------------ +! Gather routines + +function atlas_GatherScatter__ctor() result(gather) + use atlas_gatherscatter_c_binding + type(atlas_GatherScatter) :: gather + call gather%reset_c_ptr( atlas__GatherScatter__new() ) +end function atlas_GatherScatter__ctor + +subroutine atlas_GatherScatter__delete(this) + use atlas_gatherscatter_c_binding + class(atlas_GatherScatter), intent(inout) :: this + if ( .not. this%is_null() ) then + call atlas__GatherScatter__delete(this%CPTR_PGIBUG_A) + end if + call this%reset_c_ptr() +end subroutine atlas_GatherScatter__delete + + +subroutine GatherScatter__setup32(this, part, remote_idx, glb_idx) + use atlas_gatherscatter_c_binding + class(atlas_GatherScatter), intent(in) :: this + integer(c_int), intent(in) :: part(:) + integer(ATLAS_KIND_IDX), intent(in) :: remote_idx(:) + integer(c_int), intent(in) :: glb_idx(:) + call atlas__GatherScatter__setup32( this%CPTR_PGIBUG_A, part, remote_idx, 1, & + & glb_idx, size(part) ) +end subroutine GatherScatter__setup32 + +subroutine GatherScatter__setup64(this, part, remote_idx, glb_idx ) + use atlas_gatherscatter_c_binding + class(atlas_GatherScatter), intent(in) :: this + integer(c_int), intent(in) :: part(:) + integer(ATLAS_KIND_IDX), intent(in) :: remote_idx(:) + integer(c_long), intent(in) :: glb_idx(:) + call atlas__GatherScatter__setup64( this%CPTR_PGIBUG_A, part, remote_idx, 1, & + & glb_idx, size(part) ) +end subroutine GatherScatter__setup64 + +function GatherScatter__glb_dof(this) result(glb_dof) + use atlas_gatherscatter_c_binding + class(atlas_GatherScatter), intent(in) :: this + integer :: glb_dof + glb_dof = atlas__GatherScatter__glb_dof(this%CPTR_PGIBUG_A) +end function GatherScatter__glb_dof + +! ----------------------------------------------------------------------------- + +#:for dtype,ftype,ctype in types[:4] + +subroutine gather_${dtype}$_r1(this, loc_field_data, glb_field_data) + use atlas_gatherscatter_c_binding + class(atlas_GatherScatter), intent(in) :: this + ${ftype}$, intent(in) :: loc_field_data(:) + ${ftype}$, intent(out) :: glb_field_data(:) + integer :: lstrides(1), lextents(1), lrank=1 + integer :: gstrides(1), gextents(1), grank=1 + ${ftype}$, pointer :: lview(:), gview(:) + lstrides = (/ array_stride(loc_field_data,2) /) + lextents = (/ 1 /) + lview => array_view1d(loc_field_data) + gstrides = (/ array_stride(glb_field_data,2) /) + gextents = (/ 1 /) + gview => array_view1d(glb_field_data) + if( size(gview) == 0 ) then + allocate(gview(0)) + endif + call atlas__GatherScatter__gather_${ctype}$( this%CPTR_PGIBUG_A, & + & lview, lstrides, lextents, lrank, & + & gview, gstrides, gextents, grank ) +end subroutine + +subroutine gather_${dtype}$_r2(this, loc_field_data, glb_field_data) + use atlas_gatherscatter_c_binding + class(atlas_GatherScatter), intent(in) :: this + ${ftype}$, intent(in) :: loc_field_data(:,:) + ${ftype}$, intent(out) :: glb_field_data(:,:) + ${ftype}$, pointer :: lview(:), gview(:) + integer :: lstrides(2), lextents(2), lrank=2 + integer :: gstrides(2), gextents(2), grank=2 + lstrides = (/ array_stride(loc_field_data,2), array_stride(loc_field_data,1) /) + lextents = (/ 1, size (loc_field_data,1) /) + lview => array_view1d(loc_field_data) + gstrides = (/ array_stride(glb_field_data,2), array_stride(glb_field_data,1) /) + gextents = (/ 1, size (glb_field_data,1) /) + gview => array_view1d(glb_field_data) + if( size(gview) == 0 ) then + allocate(gview(0)) + endif + call atlas__GatherScatter__gather_${ctype}$( this%CPTR_PGIBUG_A, & + & lview, lstrides, lextents, lrank, & + & gview, gstrides, gextents, grank ) +end subroutine + +subroutine gather_${dtype}$_r3(this, loc_field_data, glb_field_data) + use atlas_gatherscatter_c_binding + class(atlas_GatherScatter), intent(in) :: this + ${ftype}$, intent(in) :: loc_field_data(:,:,:) + ${ftype}$, intent(out) :: glb_field_data(:,:,:) + ${ftype}$, pointer :: lview(:), gview(:) + integer :: lstrides(3), lextents(3), lrank=3 + integer :: gstrides(3), gextents(3), grank=3 + lstrides = (/ array_stride(loc_field_data,3), array_stride(loc_field_data,2) , array_stride(loc_field_data,1) /) + lextents = (/ 1, size (loc_field_data,2) , size (loc_field_data,1) /) + lview => array_view1d(loc_field_data) + gstrides = (/ array_stride(glb_field_data,3), array_stride(glb_field_data,2) , array_stride(glb_field_data,1) /) + gextents = (/ 1, size (glb_field_data,2) , size (glb_field_data,1) /) + gview => array_view1d(glb_field_data) + if( size(gview) == 0 ) then + allocate(gview(0)) + endif + call atlas__GatherScatter__gather_${ctype}$( this%CPTR_PGIBUG_A, & + & lview, lstrides, lextents, lrank, & + & gview, gstrides, gextents, grank ) +end subroutine + +! ----------------------------------------------------------------------------- + +subroutine scatter_${dtype}$_r1(this, glb_field_data, loc_field_data) + use atlas_gatherscatter_c_binding + class(atlas_GatherScatter), intent(in) :: this + ${ftype}$, intent(in) :: glb_field_data(:) + ${ftype}$, intent(out) :: loc_field_data(:) + ${ftype}$, pointer :: lview(:), gview(:) + integer :: lstrides(1), lextents(1), lrank=1 + integer :: gstrides(1), gextents(1), grank=1 + lstrides = (/ array_stride(loc_field_data,1) /) + lextents = (/ 1 /) + lview => array_view1d(loc_field_data) + gstrides = (/ array_stride(glb_field_data,1) /) + gextents = (/ 1 /) + gview => array_view1d(glb_field_data) + call atlas__GatherScatter__scatter_${ctype}$( this%CPTR_PGIBUG_A, & + & gview, gstrides, gextents, grank, & + & lview, lstrides, lextents, lrank ) +end subroutine + +subroutine scatter_${dtype}$_r2(this, glb_field_data, loc_field_data) + use atlas_gatherscatter_c_binding + class(atlas_GatherScatter), intent(in) :: this + ${ftype}$, intent(in) :: glb_field_data(:,:) + ${ftype}$, intent(out) :: loc_field_data(:,:) + ${ftype}$, pointer :: lview(:), gview(:) + integer :: lstrides(2), lextents(2), lrank=2 + integer :: gstrides(2), gextents(2), grank=2 + lstrides = (/ array_stride(loc_field_data,2), array_stride(loc_field_data,1) /) + lextents = (/ 1, size (loc_field_data,1) /) + lview => array_view1d(loc_field_data) + gstrides = (/ array_stride(glb_field_data,2), array_stride(glb_field_data,1) /) + gextents = (/ 1, size (glb_field_data,1) /) + gview => array_view1d(glb_field_data) + if( size(gview) == 0 ) then + allocate(gview(0)) + endif + call atlas__GatherScatter__scatter_${ctype}$( this%CPTR_PGIBUG_A, & + & gview, gstrides, gextents, grank, & + & lview, lstrides, lextents, lrank ) +end subroutine + +subroutine scatter_${dtype}$_r3(this, glb_field_data, loc_field_data) + use atlas_gatherscatter_c_binding + class(atlas_GatherScatter), intent(in) :: this + ${ftype}$, intent(in) :: glb_field_data(:,:,:) + ${ftype}$, intent(out) :: loc_field_data(:,:,:) + ${ftype}$, pointer :: lview(:), gview(:) + integer :: lstrides(3), lextents(3), lrank=3 + integer :: gstrides(3), gextents(3), grank=3 + lstrides = (/ array_stride(loc_field_data,3), array_stride(loc_field_data,2), array_stride(loc_field_data,1) /) + lextents = (/ 1, size (loc_field_data,2) , size (loc_field_data,1) /) + lview => array_view1d(loc_field_data) + gstrides = (/ array_stride(glb_field_data,3), array_stride(glb_field_data,2), array_stride(glb_field_data,1) /) + gextents = (/ 1, size (glb_field_data,2) , size (glb_field_data,1) /) + gview => array_view1d(glb_field_data) + if( size(gview) == 0 ) then + allocate(gview(0)) + endif + call atlas__GatherScatter__scatter_${ctype}$( this%CPTR_PGIBUG_A, & + & gview, gstrides, gextents, grank, & + & lview, lstrides, lextents, lrank ) +end subroutine + +#:endfor + +!------------------------------------------------------------------------------- + +ATLAS_FINAL subroutine atlas_GatherScatter__final_auto(this) + type(atlas_GatherScatter), intent(inout) :: this +#if FCKIT_FINAL_DEBUGGING + write(0,*) "atlas_GatherScatter__final_auto" +#endif +#if FCKIT_FINAL_NOT_PROPAGATING + call this%final() +#endif + FCKIT_SUPPRESS_UNUSED( this ) +end subroutine + +! ----------------------------------------------------------------------------- + +end module atlas_gatherscatter_module diff --git a/src/atlas_f/parallel/atlas_HaloExchange_module.F90 b/src/atlas_f/parallel/atlas_HaloExchange_module.F90 deleted file mode 100644 index fc7625c55..000000000 --- a/src/atlas_f/parallel/atlas_HaloExchange_module.F90 +++ /dev/null @@ -1,297 +0,0 @@ -#include "atlas/atlas_f.h" - -module atlas_haloexchange_module - -use, intrinsic :: iso_c_binding, only : c_ptr, c_long, c_float, c_double -use fckit_array_module, only : array_stride, array_view1d -use fckit_object_module, only : fckit_object - -implicit none - -private :: c_ptr, c_long, c_float, c_double -private :: array_stride, array_view1d -private :: fckit_object - -public :: atlas_HaloExchange - -private - -!------------------------------------------------------------------------------ -TYPE, extends(fckit_object) :: atlas_HaloExchange - -! Purpose : -! ------- -! *HaloExchange* : - -! Methods : -! ------- -! setup : Setup using arrays detailing proc and glb_idx, bounds and parbound -! execute : Do the halo exchange - -! Author : -! ------ -! 17-Dec-2013 Willem Deconinck *ECMWF* - -!------------------------------------------------------------------------------ -contains - procedure :: setup => HaloExchange__setup - procedure, private :: HaloExchange__execute_int32_r1 - procedure, private :: HaloExchange__execute_int32_r2 - procedure, private :: HaloExchange__execute_int32_r3 - procedure, private :: HaloExchange__execute_int64_r1 - procedure, private :: HaloExchange__execute_int64_r2 - procedure, private :: HaloExchange__execute_int64_r3 - procedure, private :: HaloExchange__execute_real32_r1 - procedure, private :: HaloExchange__execute_real32_r2 - procedure, private :: HaloExchange__execute_real32_r3 - procedure, private :: HaloExchange__execute_real32_r4 - procedure, private :: HaloExchange__execute_real64_r1 - procedure, private :: HaloExchange__execute_real64_r2 - procedure, private :: HaloExchange__execute_real64_r3 - procedure, private :: HaloExchange__execute_real64_r4 - generic :: execute => & - & HaloExchange__execute_int32_r1, & - & HaloExchange__execute_int32_r2, & - & HaloExchange__execute_int32_r3, & - & HaloExchange__execute_int64_r1, & - & HaloExchange__execute_int64_r2, & - & HaloExchange__execute_int64_r3, & - & HaloExchange__execute_real32_r1, & - & HaloExchange__execute_real32_r2, & - & HaloExchange__execute_real32_r3, & - & HaloExchange__execute_real32_r4, & - & HaloExchange__execute_real64_r1, & - & HaloExchange__execute_real64_r2, & - & HaloExchange__execute_real64_r3, & - & HaloExchange__execute_real64_r4 - - procedure, public :: delete => atlas_HaloExchange__delete - -#if FCKIT_FINAL_NOT_INHERITING - final :: atlas_HaloExchange__final_auto -#endif - -END TYPE atlas_HaloExchange -!------------------------------------------------------------------------------ - -interface atlas_HaloExchange - module procedure atlas_HaloExchange__ctor -end interface - -!======================================================== -contains -!======================================================== - - -! ------------------------------------------------------------------------------ -! HaloExchange routines - -function atlas_HaloExchange__ctor() result(halo_exchange) - use atlas_haloexchange_c_binding - type(atlas_HaloExchange) :: halo_exchange - call halo_exchange%reset_c_ptr( atlas__HaloExchange__new() ) -end function atlas_HaloExchange__ctor - -subroutine atlas_HaloExchange__delete(this) - use atlas_haloexchange_c_binding - class(atlas_HaloExchange), intent(inout) :: this - if ( .not. this%is_null() ) then - call atlas__HaloExchange__delete(this%c_ptr()) - end if - call this%reset_c_ptr() -end subroutine atlas_HaloExchange__delete - -subroutine HaloExchange__setup(this, part, remote_idx) - use atlas_haloexchange_c_binding - class(atlas_HaloExchange), intent(in) :: this - integer, intent(in) :: part(:) - integer, intent(in) :: remote_idx(:) - call atlas__HaloExchange__setup( this%c_ptr(), part, remote_idx, 1, size(part) ) -end subroutine HaloExchange__setup - - -subroutine HaloExchange__execute_int32_r1(this, field_data) - use atlas_haloexchange_c_binding - class(atlas_HaloExchange), intent(in) :: this - integer, intent(inout) :: field_data(:) - integer :: strides(1), extents(1) - strides = (/ array_stride(field_data,1) /) - extents = (/ 1 /) - call atlas__HaloExchange__execute_strided_int( this%c_ptr(), field_data, & - & strides, extents, 1 ) -end subroutine HaloExchange__execute_int32_r1 - -subroutine HaloExchange__execute_int32_r2(this, field_data) - use atlas_haloexchange_c_binding - class(atlas_HaloExchange), intent(in) :: this - integer, intent(inout) :: field_data(:,:) - integer, pointer :: view(:) - integer :: strides(2), extents(2) - view => array_view1d(field_data) - strides = (/ array_stride(field_data,2) , array_stride(field_data,1) /) - extents = (/ 1 , ubound(field_data,1) /) - call atlas__HaloExchange__execute_strided_int( this%c_ptr(), view, & - & strides, extents, 2 ) -end subroutine HaloExchange__execute_int32_r2 - -subroutine HaloExchange__execute_int32_r3(this, field_data) - use atlas_haloexchange_c_binding - class(atlas_HaloExchange), intent(in) :: this - integer, intent(inout) :: field_data(:,:,:) - integer, pointer :: view(:) - integer :: strides(3), extents(3) - view => array_view1d(field_data) - strides = (/ array_stride(field_data,3), array_stride(field_data,2) , array_stride(field_data,1) /) - extents = (/ 1, ubound(field_data,2) , ubound(field_data,1) /) - call atlas__HaloExchange__execute_strided_int( this%c_ptr(), view, & - & strides, extents, 3 ) -end subroutine HaloExchange__execute_int32_r3 - -subroutine HaloExchange__execute_int64_r1(this, field_data) - use atlas_haloexchange_c_binding - class(atlas_HaloExchange), intent(in) :: this - integer(c_long), intent(inout) :: field_data(:) - integer :: strides(1), extents(1) - strides = (/ array_stride(field_data,1) /) - extents = (/ 1 /) - call atlas__HaloExchange__execute_strided_long( this%c_ptr(), field_data, & - & strides, extents, 1 ) -end subroutine HaloExchange__execute_int64_r1 - -subroutine HaloExchange__execute_int64_r2(this, field_data) - use atlas_haloexchange_c_binding - class(atlas_HaloExchange), intent(in) :: this - integer(c_long), intent(inout) :: field_data(:,:) - integer(c_long), pointer :: view(:) - integer :: strides(2), extents(2) - view => array_view1d(field_data) - strides = (/ array_stride(field_data,2) , array_stride(field_data,1) /) - extents = (/ 1 , ubound(field_data,1) /) - call atlas__HaloExchange__execute_strided_long( this%c_ptr(), view, & - & strides, extents, 2 ) -end subroutine HaloExchange__execute_int64_r2 - -subroutine HaloExchange__execute_int64_r3(this, field_data) - use atlas_haloexchange_c_binding - class(atlas_HaloExchange), intent(in) :: this - integer(c_long), intent(inout) :: field_data(:,:,:) - integer(c_long), pointer :: view(:) - integer :: strides(3), extents(3) - view => array_view1d(field_data) - strides = (/ array_stride(field_data,3), array_stride(field_data,2) , array_stride(field_data,1) /) - extents = (/ 1, ubound(field_data,2) , ubound(field_data,1) /) - call atlas__HaloExchange__execute_strided_long( this%c_ptr(), view, & - & strides, extents, 3 ) -end subroutine HaloExchange__execute_int64_r3 - -subroutine HaloExchange__execute_real32_r1(this, field_data) - use atlas_haloexchange_c_binding - class(atlas_HaloExchange), intent(in) :: this - real(c_float), intent(inout) :: field_data(:) - integer :: strides(1), extents(1) - strides = (/ array_stride(field_data,1) /) - extents = (/ 1 /) - call atlas__HaloExchange__execute_strided_float( this%c_ptr(), field_data, & - & strides, extents, 1 ) -end subroutine HaloExchange__execute_real32_r1 -subroutine HaloExchange__execute_real32_r2(this, field_data) - use atlas_haloexchange_c_binding - class(atlas_HaloExchange), intent(in) :: this - real(c_float), intent(inout) :: field_data(:,:) - real(c_float), pointer :: view(:) - integer :: strides(2), extents(2) - view => array_view1d(field_data) - strides = (/ array_stride(field_data,2) , array_stride(field_data,1) /) - extents = (/ 1 , ubound(field_data,1) /) - call atlas__HaloExchange__execute_strided_float( this%c_ptr(), view, & - & strides, extents, 2 ) -end subroutine HaloExchange__execute_real32_r2 -subroutine HaloExchange__execute_real32_r3(this, field_data) - use atlas_haloexchange_c_binding - class(atlas_HaloExchange), intent(in) :: this - real(c_float), intent(inout) :: field_data(:,:,:) - real(c_float), pointer :: view(:) - integer :: strides(3), extents(3), rank=3 - view => array_view1d(field_data) - strides = (/ array_stride(field_data,3), array_stride(field_data,2) , array_stride(field_data,1) /) - extents = (/ 1, ubound(field_data,2) , ubound(field_data,1) /) - call atlas__HaloExchange__execute_strided_float( this%c_ptr(), view, & - & strides, extents, rank ) -end subroutine HaloExchange__execute_real32_r3 -subroutine HaloExchange__execute_real32_r4(this, field_data) - use atlas_haloexchange_c_binding - class(atlas_HaloExchange), intent(in) :: this - real(c_float), intent(inout) :: field_data(:,:,:,:) - real(c_float), pointer :: view(:) - integer :: strides(4), extents(4), rank=4 - view => array_view1d(field_data) - strides = (/ array_stride(field_data,4), array_stride(field_data,3), array_stride(field_data,2), array_stride(field_data,1) /) - extents = (/ 1, ubound(field_data,3), ubound(field_data,2), ubound(field_data,1) /) - call atlas__HaloExchange__execute_strided_float( this%c_ptr(), view, & - & strides, extents, rank ) -end subroutine HaloExchange__execute_real32_r4 - -subroutine HaloExchange__execute_real64_r1(this, field_data) - use atlas_haloexchange_c_binding - class(atlas_HaloExchange), intent(in) :: this - real(c_double), intent(inout) :: field_data(:) - integer :: strides(1), extents(1) - strides = (/ array_stride(field_data,1) /) - extents = (/ 1 /) - call atlas__HaloExchange__execute_strided_double( this%c_ptr(), field_data, & - & strides, extents, 1 ) -end subroutine HaloExchange__execute_real64_r1 -subroutine HaloExchange__execute_real64_r2(this, field_data) - use atlas_haloexchange_c_binding - class(atlas_HaloExchange), intent(in) :: this - real(c_double), intent(inout) :: field_data(:,:) - real(c_double), pointer :: view(:) - integer :: strides(2), extents(2) - view => array_view1d(field_data) - strides = (/ array_stride(field_data,2) , array_stride(field_data,1) /) - extents = (/ 1 , ubound(field_data,1) /) - call atlas__HaloExchange__execute_strided_double( this%c_ptr(), view, & - & strides, extents, 2 ) -end subroutine HaloExchange__execute_real64_r2 -subroutine HaloExchange__execute_real64_r3(this, field_data) - use atlas_haloexchange_c_binding - class(atlas_HaloExchange), intent(in) :: this - real(c_double), intent(inout) :: field_data(:,:,:) - real(c_double), pointer :: view(:) - integer :: strides(3), extents(3), rank=3 - view => array_view1d(field_data) - strides = (/ array_stride(field_data,3), array_stride(field_data,2) , array_stride(field_data,1) /) - extents = (/ 1, ubound(field_data,2) , ubound(field_data,1) /) - call atlas__HaloExchange__execute_strided_double( this%c_ptr(), view, & - & strides, extents, rank ) -end subroutine HaloExchange__execute_real64_r3 -subroutine HaloExchange__execute_real64_r4(this, field_data) - use atlas_haloexchange_c_binding - class(atlas_HaloExchange), intent(in) :: this - real(c_double), intent(inout) :: field_data(:,:,:,:) - real(c_double), pointer :: view(:) - integer :: strides(4), extents(4), rank=4 - view => array_view1d(field_data) - strides = (/ array_stride(field_data,4), array_stride(field_data,3), array_stride(field_data,2), array_stride(field_data,1) /) - extents = (/ 1, ubound(field_data,3), ubound(field_data,2), ubound(field_data,1) /) - call atlas__HaloExchange__execute_strided_double( this%c_ptr(), view, & - & strides, extents, rank ) -end subroutine HaloExchange__execute_real64_r4 - -!------------------------------------------------------------------------------- - -ATLAS_FINAL subroutine atlas_HaloExchange__final_auto(this) - type(atlas_HaloExchange), intent(inout) :: this -#if FCKIT_FINAL_DEBUGGING - write(0,*) "atlas_HaloExchange__final_auto" -#endif -#if FCKIT_FINAL_NOT_PROPAGATING - call this%final() -#endif - FCKIT_SUPPRESS_UNUSED( this ) -end subroutine - -! ----------------------------------------------------------------------------- - -end module atlas_haloexchange_module - diff --git a/src/atlas_f/parallel/atlas_HaloExchange_module.fypp b/src/atlas_f/parallel/atlas_HaloExchange_module.fypp new file mode 100644 index 000000000..339982170 --- /dev/null +++ b/src/atlas_f/parallel/atlas_HaloExchange_module.fypp @@ -0,0 +1,153 @@ +! (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" +#:include "internals/atlas_generics.fypp" + +#:set ranks = [1,2,3] + +module atlas_haloexchange_module + +use, intrinsic :: iso_c_binding, only : c_ptr, c_int, c_long, c_float, c_double +use fckit_array_module, only : array_stride, array_view1d +use fckit_object_module, only : fckit_object +use atlas_kinds_module, only : ATLAS_KIND_IDX + +implicit none + +private :: c_ptr, c_int, c_long, c_float, c_double +private :: array_stride, array_view1d +private :: fckit_object + +public :: atlas_HaloExchange + +private + +!------------------------------------------------------------------------------ +TYPE, extends(fckit_object) :: atlas_HaloExchange + +! Purpose : +! ------- +! *HaloExchange* : + +! Methods : +! ------- +! setup : Setup using arrays detailing proc and glb_idx, bounds and parbound +! execute : Do the halo exchange + +! Author : +! ------ +! 17-Dec-2013 Willem Deconinck *ECMWF* + +!------------------------------------------------------------------------------ +contains + procedure :: setup => HaloExchange__setup + @:generic_public_interface( execute, HaloExchange__execute ) + + procedure, public :: delete => atlas_HaloExchange__delete + +#if FCKIT_FINAL_NOT_INHERITING + final :: atlas_HaloExchange__final_auto +#endif + +END TYPE atlas_HaloExchange +!------------------------------------------------------------------------------ + +interface atlas_HaloExchange + module procedure atlas_HaloExchange__ctor +end interface + +!======================================================== +contains +!======================================================== + + +! ------------------------------------------------------------------------------ +! HaloExchange routines + +function atlas_HaloExchange__ctor() result(halo_exchange) + use atlas_haloexchange_c_binding + type(atlas_HaloExchange) :: halo_exchange + call halo_exchange%reset_c_ptr( atlas__HaloExchange__new() ) +end function atlas_HaloExchange__ctor + +subroutine atlas_HaloExchange__delete(this) + use atlas_haloexchange_c_binding + class(atlas_HaloExchange), intent(inout) :: this + if ( .not. this%is_null() ) then + call atlas__HaloExchange__delete(this%CPTR_PGIBUG_A) + end if + call this%reset_c_ptr() +end subroutine atlas_HaloExchange__delete + +subroutine HaloExchange__setup(this, part, remote_idx) + use atlas_haloexchange_c_binding + class(atlas_HaloExchange), intent(in) :: this + integer(c_int), intent(in) :: part(:) + integer(ATLAS_KIND_IDX), intent(in) :: remote_idx(:) + call atlas__HaloExchange__setup( this%CPTR_PGIBUG_A, part, remote_idx, 1, size(part) ) +end subroutine HaloExchange__setup + +#:for dtype,ftype,ctype in types[:4] + +subroutine HaloExchange__execute_${dtype}$_r1(this, field_data) + use atlas_haloexchange_c_binding + class(atlas_HaloExchange), intent(in) :: this + ${ftype}$, intent(inout) :: field_data(:) + integer :: strides(1), extents(1) + strides = (/ array_stride(field_data,1) /) + extents = (/ 1 /) + call atlas__HaloExchange__execute_strided_${ctype}$( this%CPTR_PGIBUG_A, field_data, & + & strides, extents, 1 ) +end subroutine + +subroutine HaloExchange__execute_${dtype}$_r2(this, field_data) + use atlas_haloexchange_c_binding + class(atlas_HaloExchange), intent(in) :: this + ${ftype}$, intent(inout) :: field_data(:,:) + ${ftype}$, pointer :: view(:) + integer :: strides(2), extents(2) + view => array_view1d(field_data) + strides = (/ array_stride(field_data,2) , array_stride(field_data,1) /) + extents = (/ 1 , ubound(field_data,1) /) + call atlas__HaloExchange__execute_strided_${ctype}$( this%CPTR_PGIBUG_A, view, & + & strides, extents, 2 ) +end subroutine + +subroutine HaloExchange__execute_${dtype}$_r3(this, field_data) + use atlas_haloexchange_c_binding + class(atlas_HaloExchange), intent(in) :: this + ${ftype}$, intent(inout) :: field_data(:,:,:) + ${ftype}$, pointer :: view(:) + integer :: strides(3), extents(3) + view => array_view1d(field_data) + strides = (/ array_stride(field_data,3), array_stride(field_data,2) , array_stride(field_data,1) /) + extents = (/ 1, ubound(field_data,2) , ubound(field_data,1) /) + call atlas__HaloExchange__execute_strided_${ctype}$( this%CPTR_PGIBUG_A, view, & + & strides, extents, 3 ) +end subroutine + +#:endfor + +!------------------------------------------------------------------------------- + +ATLAS_FINAL subroutine atlas_HaloExchange__final_auto(this) + type(atlas_HaloExchange), intent(inout) :: this +#if FCKIT_FINAL_DEBUGGING + write(0,*) "atlas_HaloExchange__final_auto" +#endif +#if FCKIT_FINAL_NOT_PROPAGATING + call this%final() +#endif + FCKIT_SUPPRESS_UNUSED( this ) +end subroutine + +! ----------------------------------------------------------------------------- + +end module atlas_haloexchange_module + diff --git a/src/atlas_f/parallel/atlas_mpi_module.F90 b/src/atlas_f/parallel/atlas_mpi_module.F90 deleted file mode 100644 index a948f30b3..000000000 --- a/src/atlas_f/parallel/atlas_mpi_module.F90 +++ /dev/null @@ -1,24 +0,0 @@ -module atlas_mpi_module -use fckit_mpi_module, only : fckit_mpi_comm -private - -public :: atlas_mpi_comm -public :: atlas_mpi_set_comm - -private :: fckit_mpi_comm - -contains - -function atlas_mpi_comm() - use fckit_mpi_module - type(fckit_mpi_comm) :: atlas_mpi_comm - atlas_mpi_comm = fckit_mpi_comm() -end function atlas_mpi_comm - -subroutine atlas_mpi_set_comm(comm) - use fckit_mpi_module - integer :: comm - call fckit_mpi_setCommDefault(comm) -end subroutine atlas_mpi_set_comm - -end module atlas_mpi_module diff --git a/src/atlas_f/runtime/atlas_Trace_module.F90 b/src/atlas_f/runtime/atlas_Trace_module.F90 new file mode 100644 index 000000000..434fc101e --- /dev/null +++ b/src/atlas_f/runtime/atlas_Trace_module.F90 @@ -0,0 +1,208 @@ +! (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_Trace_module + +use fckit_shared_object_module, only : fckit_shared_object + +implicit none + +private :: fckit_shared_object + +public :: atlas_Trace + + +private + +!----------------------------- +! atlas_Trace ! +!----------------------------- + +type, extends(fckit_shared_object) :: atlas_Trace +contains +! Public methods + + procedure, public :: running + procedure, public :: start + procedure, public :: stop + procedure, public :: pause + procedure, public :: resume + procedure, public :: elapsed + +#if FCKIT_FINAL_NOT_INHERITING + final :: atlas_Trace__final_auto +#endif +end type + +interface atlas_Trace + module procedure atlas_Trace__loc + module procedure atlas_Trace__labels_1 + module procedure atlas_Trace__labels_2 + module procedure atlas_Trace__labels_3 + module procedure atlas_Trace__labels_4 + module procedure atlas_Trace__labels_5 +end interface + +!======================================================== +contains +!======================================================== + +function atlas_Trace__loc(file,line,title) result(this) + use, intrinsic :: iso_c_binding, only : c_ptr + use atlas_Trace_c_binding + use fckit_c_interop_module + type(atlas_Trace) :: this + character(len=*) , intent(in) :: file + integer , intent(in) :: line + character(len=*) , intent(in) :: title + call this%reset_c_ptr( new_atlas_Trace( c_str(file), line, c_str(title) ), fckit_c_deleter(delete_atlas_Trace) ) + call this%return() +end function + +function atlas_Trace__labels_1(file,line,title,label) result(this) + use, intrinsic :: iso_c_binding, only : c_ptr + use atlas_Trace_c_binding + use fckit_c_interop_module + type(atlas_Trace) :: this + character(len=*) , intent(in) :: file + integer , intent(in) :: line + character(len=*) , intent(in) :: title + character(len=*) , intent(in) :: label + call this%reset_c_ptr( new_atlas_Trace_labels_1( c_str(file), line, c_str(title), c_str(label) ), & + & fckit_c_deleter(delete_atlas_Trace) ) +end function +function atlas_Trace__labels_2(file,line,title,label1,label2) result(this) + use, intrinsic :: iso_c_binding, only : c_ptr + use atlas_Trace_c_binding + use fckit_c_interop_module + type(atlas_Trace) :: this + character(len=*) , intent(in) :: file + integer , intent(in) :: line + character(len=*) , intent(in) :: title + character(len=*) , intent(in) :: label1 + character(len=*) , intent(in) :: label2 + call this%reset_c_ptr( new_atlas_Trace_labels_2( c_str(file), line, c_str(title), c_str(label1), c_str(label2) ), & + & fckit_c_deleter(delete_atlas_Trace) ) +end function +function atlas_Trace__labels_3(file,line,title,label1,label2,label3) result(this) + use, intrinsic :: iso_c_binding, only : c_ptr + use atlas_Trace_c_binding + use fckit_c_interop_module + type(atlas_Trace) :: this + character(len=*) , intent(in) :: file + integer , intent(in) :: line + character(len=*) , intent(in) :: title + character(len=*) , intent(in) :: label1 + character(len=*) , intent(in) :: label2 + character(len=*) , intent(in) :: label3 + call this%reset_c_ptr( new_atlas_Trace_labels_3( c_str(file), line, c_str(title), c_str(label1), c_str(label2), & + & c_str(label3) ), fckit_c_deleter(delete_atlas_Trace) ) +end function +function atlas_Trace__labels_4(file,line,title,label1,label2,label3,label4) result(this) + use, intrinsic :: iso_c_binding, only : c_ptr + use atlas_Trace_c_binding + use fckit_c_interop_module + type(atlas_Trace) :: this + character(len=*) , intent(in) :: file + integer , intent(in) :: line + character(len=*) , intent(in) :: title + character(len=*) , intent(in) :: label1 + character(len=*) , intent(in) :: label2 + character(len=*) , intent(in) :: label3 + character(len=*) , intent(in) :: label4 + call this%reset_c_ptr( new_atlas_Trace_labels_4( c_str(file), line, c_str(title), c_str(label1), c_str(label2), & + & c_str(label3), c_str(label4) ), fckit_c_deleter(delete_atlas_Trace) ) +end function +function atlas_Trace__labels_5(file,line,title,label1,label2,label3,label4,label5) result(this) + use, intrinsic :: iso_c_binding, only : c_ptr + use atlas_Trace_c_binding + use fckit_c_interop_module + type(atlas_Trace) :: this + character(len=*) , intent(in) :: file + integer , intent(in) :: line + character(len=*) , intent(in) :: title + character(len=*) , intent(in) :: label1 + character(len=*) , intent(in) :: label2 + character(len=*) , intent(in) :: label3 + character(len=*) , intent(in) :: label4 + character(len=*) , intent(in) :: label5 + call this%reset_c_ptr( new_atlas_Trace_labels_5( c_str(file), line, c_str(title), c_str(label1), c_str(label2), & + & c_str(label3), c_str(label4), c_str(label5) ), fckit_c_deleter(delete_atlas_Trace) ) +end function +!------------------------------------------------------------------------------- + +function running( this ) + use atlas_Trace_c_binding + logical :: running + class(atlas_Trace) :: this + if( atlas_Trace__running( this%CPTR_PGIBUG_B ) == 0 ) then + running = .False. + else + running = .True. + endif +end function + +!------------------------------------------------------------------------------- + +function elapsed( this ) + use, intrinsic :: iso_c_binding, only : c_double + use atlas_Trace_c_binding + real(c_double) :: elapsed + class(atlas_Trace) :: this + elapsed = atlas_Trace__elapsed( this%CPTR_PGIBUG_B ) +end function + +!------------------------------------------------------------------------------- + +subroutine start( this ) + use atlas_Trace_c_binding + class(atlas_Trace) :: this + call atlas_Trace__start( this%CPTR_PGIBUG_B ) +end subroutine + +!------------------------------------------------------------------------------- + +subroutine stop( this ) + use atlas_Trace_c_binding + class(atlas_Trace) :: this + call atlas_Trace__stop( this%CPTR_PGIBUG_B ) +end subroutine + +!------------------------------------------------------------------------------- + +subroutine pause( this ) + use atlas_Trace_c_binding + class(atlas_Trace) :: this + call atlas_Trace__pause( this%CPTR_PGIBUG_B ) +end subroutine + +!------------------------------------------------------------------------------- + +subroutine resume( this ) + use atlas_Trace_c_binding + class(atlas_Trace) :: this + call atlas_Trace__resume( this%CPTR_PGIBUG_B ) +end subroutine + +!------------------------------------------------------------------------------- + +ATLAS_FINAL subroutine atlas_Trace__final_auto(this) + type(atlas_Trace), intent(inout) :: this +#if FCKIT_FINAL_DEBUGGING + write(0,*) "atlas_Trace__final_auto" +#endif +#if FCKIT_FINAL_NOT_PROPAGATING + call this%final() +#endif + FCKIT_SUPPRESS_UNUSED( this ) +end subroutine + +end module atlas_Trace_module + diff --git a/src/atlas_f/runtime/atlas_trace.cc b/src/atlas_f/runtime/atlas_trace.cc new file mode 100644 index 000000000..8889dcd64 --- /dev/null +++ b/src/atlas_f/runtime/atlas_trace.cc @@ -0,0 +1,101 @@ +/* + * (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_trace.h" + +#include +#include + +#include "atlas/runtime/Exception.h" +#include "atlas/runtime/Log.h" +#include "atlas/runtime/Trace.h" +#include "atlas/runtime/trace/CodeLocation.h" + +namespace atlas { + +//static std::vector Labels( int size, const char* labels[] ) { +// std::vector _labels; +// _labels.reserve( size ); +// for ( int i = 0; i < size; ++i ) { +// _labels.emplace_back( labels[i] ); +// } +// return _labels; +//} + +extern "C" { + +Trace* new_atlas_Trace( const char* file, int line, const char* title ) { + return new Trace( CodeLocation( file, line, nullptr, true ), std::string( title ) ); +} + +Trace* new_atlas_Trace_labels_1( const char* file, int line, const char* title, const char* label1 ) { + std::vector labels{label1}; + return new Trace( CodeLocation( file, line, nullptr, true ), std::string( title ), labels ); +} +Trace* new_atlas_Trace_labels_2( const char* file, int line, const char* title, const char* label1, + const char* label2 ) { + std::vector labels{label1, label2}; + return new Trace( CodeLocation( file, line, nullptr, true ), std::string( title ), labels ); +} +Trace* new_atlas_Trace_labels_3( const char* file, int line, const char* title, const char* label1, const char* label2, + const char* label3 ) { + std::vector labels{label1, label2, label3}; + return new Trace( CodeLocation( file, line, nullptr, true ), std::string( title ), labels ); +} +Trace* new_atlas_Trace_labels_4( const char* file, int line, const char* title, const char* label1, const char* label2, + const char* label3, const char* label4 ) { + std::vector labels{label1, label2, label3, label4}; + return new Trace( CodeLocation( file, line, nullptr, true ), std::string( title ), labels ); +} +Trace* new_atlas_Trace_labels_5( const char* file, int line, const char* title, const char* label1, const char* label2, + const char* label3, const char* label4, const char* label5 ) { + std::vector labels{label1, label2, label3, label4, label5}; + return new Trace( CodeLocation( file, line, nullptr, true ), std::string( title ), labels ); +} + +void delete_atlas_Trace( Trace* This ) { + ATLAS_ASSERT( This != nullptr, "Cannot delete uninitialised atlas_Trace" ); + delete This; + This = nullptr; +} + +void atlas_Trace__start( Trace* This ) { + ATLAS_ASSERT( This != nullptr, "Cannot start uninitialised atlas_Trace" ); + This->start(); +} + +void atlas_Trace__stop( Trace* This ) { + ATLAS_ASSERT( This != nullptr, "Cannot stop uninitialised atlas_Trace" ); + This->stop(); +} + +void atlas_Trace__pause( Trace* This ) { + ATLAS_ASSERT( This != nullptr, "Cannot pause uninitialised atlas_Trace" ); + This->pause(); +} + +void atlas_Trace__resume( Trace* This ) { + ATLAS_ASSERT( This != nullptr, "Cannot resume uninitialised atlas_Trace" ); + This->resume(); +} + +int atlas_Trace__running( Trace* This ) { + ATLAS_ASSERT( This != nullptr, "Cannot check 'running' status of uninitialised atlas_Trace" ); + return This->running(); +} + +double atlas_Trace__elapsed( Trace* This ) { + ATLAS_ASSERT( This != nullptr, "Cannot check elapsed time of uninitialised atlas_Trace" ); + return This->elapsed(); +} + +} // extern C + +} // namespace atlas diff --git a/src/atlas_f/runtime/atlas_trace.h b/src/atlas_f/runtime/atlas_trace.h new file mode 100644 index 000000000..7d1aca713 --- /dev/null +++ b/src/atlas_f/runtime/atlas_trace.h @@ -0,0 +1,38 @@ +/* + * (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 atlas { +class Trace; +} + +extern "C" { + +atlas::Trace* new_atlas_Trace( const char* file, int line, const char* title ); +atlas::Trace* new_atlas_Trace_labels_1( const char* file, int line, const char* title, const char* label1 ); +atlas::Trace* new_atlas_Trace_labels_2( const char* file, int line, const char* title, const char* label1, + const char* label2 ); +atlas::Trace* new_atlas_Trace_labels_3( const char* file, int line, const char* title, const char* label1, + const char* label2, const char* label3 ); +atlas::Trace* new_atlas_Trace_labels_4( const char* file, int line, const char* title, const char* label1, + const char* label2, const char* label3, const char* label4 ); +atlas::Trace* new_atlas_Trace_labels_5( const char* file, int line, const char* title, const char* label1, + const char* label2, const char* label3, const char* label4, + const char* label5 ); +void delete_atlas_Trace( atlas::Trace* This ); +void atlas_Trace__start( atlas::Trace* This ); +void atlas_Trace__stop( atlas::Trace* This ); +void atlas_Trace__pause( atlas::Trace* This ); +void atlas_Trace__resume( atlas::Trace* This ); +int atlas_Trace__running( atlas::Trace* This ); +double atlas_Trace__elapsed( atlas::Trace* This ); + +} // extern C diff --git a/src/atlas_f/trans/atlas_Trans_module.F90 b/src/atlas_f/trans/atlas_Trans_module.F90 index de6baebce..fac94f63b 100644 --- a/src/atlas_f/trans/atlas_Trans_module.F90 +++ b/src/atlas_f/trans/atlas_Trans_module.F90 @@ -1,3 +1,11 @@ +! (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_Trans_module @@ -100,11 +108,11 @@ module atlas_Trans_module #define THROW_ERROR call te("atlas_Trans_module.F90",__LINE__) subroutine te(file,line) - use atlas_Error_module, only: atlas_code_location, atlas_throw_usererror + use fckit_exception_module, only : fckit_exception character(len=*), intent(in) :: file integer, intent(in) :: line - call atlas_throw_usererror("Cannot use atlas_Trans since atlas is compiled without" // & - & "ENABLE_TRANS=ON",atlas_code_location(file,line)) + call fckit_exception%throw( "Cannot use atlas_Trans since atlas is compiled without" // & + & "ENABLE_TRANS=ON", file, line ) end subroutine function atlas_Trans__ctor( grid, nsmax ) result(this) @@ -115,9 +123,9 @@ function atlas_Trans__ctor( grid, nsmax ) result(this) integer, intent(in), optional :: nsmax #if ATLAS_HAVE_TRANS if( present(nsmax) ) then - call this%reset_c_ptr( atlas__Trans__new( grid%c_ptr(), nsmax ) ) + call this%reset_c_ptr( atlas__Trans__new( grid%CPTR_PGIBUG_A, nsmax ) ) else - call this%reset_c_ptr( atlas__Trans__new( grid%c_ptr(), 0 ) ) + call this%reset_c_ptr( atlas__Trans__new( grid%CPTR_PGIBUG_A, 0 ) ) endif #else ! IGNORE @@ -133,7 +141,7 @@ function handle( this ) integer :: handle class(atlas_Trans) :: this #if ATLAS_HAVE_TRANS - handle = atlas__Trans__handle (this%c_ptr()) + handle = atlas__Trans__handle (this%CPTR_PGIBUG_A) #else THROW_ERROR handle = 0 @@ -146,7 +154,7 @@ function truncation( this ) integer :: truncation class(atlas_Trans) :: this #if ATLAS_HAVE_TRANS - truncation = atlas__Trans__truncation (this%c_ptr()) + truncation = atlas__Trans__truncation (this%CPTR_PGIBUG_A) #else THROW_ERROR truncation = 0 @@ -159,7 +167,7 @@ function nb_spectral_coefficients( this ) integer :: nb_spectral_coefficients class(atlas_Trans) :: this #if ATLAS_HAVE_TRANS - nb_spectral_coefficients = atlas__Trans__nspec2 (this%c_ptr()) + nb_spectral_coefficients = atlas__Trans__nspec2 (this%CPTR_PGIBUG_A) #else THROW_ERROR nb_spectral_coefficients = 0 @@ -172,7 +180,7 @@ function nb_spectral_coefficients_global( this ) integer :: nb_spectral_coefficients_global class(atlas_Trans) :: this #if ATLAS_HAVE_TRANS - nb_spectral_coefficients_global = atlas__Trans__nspec2g (this%c_ptr()) + nb_spectral_coefficients_global = atlas__Trans__nspec2g (this%CPTR_PGIBUG_A) #else THROW_ERROR nb_spectral_coefficients_global = 0 @@ -185,7 +193,7 @@ function nb_gridpoints( this ) integer :: nb_gridpoints class(atlas_Trans) :: this #if ATLAS_HAVE_TRANS - nb_gridpoints = atlas__Trans__ngptot (this%c_ptr()) + nb_gridpoints = atlas__Trans__ngptot (this%CPTR_PGIBUG_A) #else THROW_ERROR nb_gridpoints = 0 @@ -198,7 +206,7 @@ function nb_gridpoints_global( this ) integer :: nb_gridpoints_global class(atlas_Trans) :: this #if ATLAS_HAVE_TRANS - nb_gridpoints_global = atlas__Trans__ngptotg (this%c_ptr()) + nb_gridpoints_global = atlas__Trans__ngptotg (this%CPTR_PGIBUG_A) #else THROW_ERROR nb_gridpoints_global = 0 @@ -212,7 +220,7 @@ function grid( this ) class(atlas_Trans) :: this type(atlas_Grid) :: grid #if ATLAS_HAVE_TRANS - grid = atlas_Grid( atlas__Trans__grid(this%c_ptr()) ) + grid = atlas_Grid( atlas__Trans__grid(this%CPTR_PGIBUG_A) ) call grid%return() #else THROW_ERROR @@ -233,15 +241,15 @@ subroutine dirtrans_fieldset(this, gpfields, spfields, config) type(atlas_Config) :: p if( present(config) ) then - call p%reset_c_ptr( config%c_ptr() ) + call p%reset_c_ptr( config%CPTR_PGIBUG_B ) else p = atlas_Config() endif - call atlas__Trans__dirtrans_fieldset( this%c_ptr(), & - & gpfields%c_ptr(), & - & spfields%c_ptr(), & - & p%c_ptr() ) + call atlas__Trans__dirtrans_fieldset( this%CPTR_PGIBUG_A, & + & gpfields%CPTR_PGIBUG_A, & + & spfields%CPTR_PGIBUG_A, & + & p%CPTR_PGIBUG_B ) if( .not. present(config) ) then call p%final() @@ -266,15 +274,15 @@ subroutine invtrans_fieldset(this, spfields, gpfields, config) type(atlas_Config) :: p if( present(config) ) then - call p%reset_c_ptr( config%c_ptr() ) + call p%reset_c_ptr( config%CPTR_PGIBUG_B ) else p = atlas_Config() endif - call atlas__Trans__invtrans_fieldset( this%c_ptr(), & - & spfields%c_ptr(), & - & gpfields%c_ptr(), & - & p%c_ptr() ) + call atlas__Trans__invtrans_fieldset( this%CPTR_PGIBUG_A, & + & spfields%CPTR_PGIBUG_A, & + & gpfields%CPTR_PGIBUG_A, & + & p%CPTR_PGIBUG_B ) if( .not. present(config) ) then call p%final() @@ -298,15 +306,15 @@ subroutine dirtrans_field(this, gpfield, spfield, config) type(atlas_Config) :: p if( present(config) ) then - call p%reset_c_ptr( config%c_ptr() ) + call p%reset_c_ptr( config%CPTR_PGIBUG_B ) else p = atlas_Config() endif - call atlas__Trans__dirtrans_field( this%c_ptr(), & - & gpfield%c_ptr(), & - & spfield%c_ptr(), & - & p%c_ptr() ) + call atlas__Trans__dirtrans_field( this%CPTR_PGIBUG_A, & + & gpfield%CPTR_PGIBUG_A, & + & spfield%CPTR_PGIBUG_A, & + & p%CPTR_PGIBUG_B ) if( .not. present(config) ) then call p%final() @@ -331,16 +339,16 @@ subroutine dirtrans_wind2vordiv_field(this, gpwind, spvor, spdiv, config) type(atlas_Config) :: p if( present(config) ) then - call p%reset_c_ptr( config%c_ptr() ) + call p%reset_c_ptr( config%CPTR_PGIBUG_B ) else p = atlas_Config() endif - call atlas__Trans__dirtrans_wind2vordiv_field( this%c_ptr(), & - & gpwind%c_ptr(), & - & spvor%c_ptr(), & - & spdiv%c_ptr(), & - & p%c_ptr() ) + call atlas__Trans__dirtrans_wind2vordiv_field( this%CPTR_PGIBUG_A, & + & gpwind%CPTR_PGIBUG_A, & + & spvor%CPTR_PGIBUG_A, & + & spdiv%CPTR_PGIBUG_A, & + & p%CPTR_PGIBUG_B ) if( .not. present(config) ) then call p%final() @@ -367,15 +375,15 @@ subroutine invtrans_field(this, spfield, gpfield, config) type(atlas_Config) :: p if( present(config) ) then - call p%reset_c_ptr( config%c_ptr() ) + call p%reset_c_ptr( config%CPTR_PGIBUG_B ) else p = atlas_Config() endif - call atlas__Trans__invtrans_field( this%c_ptr(), & - & spfield%c_ptr(), & - & gpfield%c_ptr(), & - & p%c_ptr() ) + call atlas__Trans__invtrans_field( this%CPTR_PGIBUG_A, & + & spfield%CPTR_PGIBUG_A, & + & gpfield%CPTR_PGIBUG_A, & + & p%CPTR_PGIBUG_B ) if( .not. present(config) ) then call p%final() @@ -401,16 +409,16 @@ subroutine invtrans_vordiv2wind_field(this, spvor, spdiv, gpwind, config) type(atlas_Config) :: p if( present(config) ) then - call p%reset_c_ptr( config%c_ptr() ) + call p%reset_c_ptr( config%CPTR_PGIBUG_B ) else p = atlas_Config() endif - call atlas__Trans__invtrans_vordiv2wind_field( this%c_ptr(), & - & spvor%c_ptr(), & - & spdiv%c_ptr(), & - & gpwind%c_ptr(), & - & p%c_ptr() ) + call atlas__Trans__invtrans_vordiv2wind_field( this%CPTR_PGIBUG_A, & + & spvor%CPTR_PGIBUG_A, & + & spdiv%CPTR_PGIBUG_A, & + & gpwind%CPTR_PGIBUG_A, & + & p%CPTR_PGIBUG_B ) if( .not. present(config) ) then call p%final() @@ -435,10 +443,10 @@ subroutine invtrans_grad_field(this, spfield, gpfield) #if ATLAS_HAVE_TRANS type(atlas_Config) :: config config = atlas_Config() - call atlas__Trans__invtrans_grad_field( this%c_ptr(), & - & spfield%c_ptr(), & - & gpfield%c_ptr(), & - & config%c_ptr()) + call atlas__Trans__invtrans_grad_field( this%CPTR_PGIBUG_A, & + & spfield%CPTR_PGIBUG_A, & + & gpfield%CPTR_PGIBUG_A, & + & config%CPTR_PGIBUG_B) call config%final() #else THROW_ERROR @@ -457,7 +465,7 @@ subroutine gathspec_r1(this, local, global) real(c_double), intent(in) :: local(:) real(c_double), intent(inout) :: global(:) #if ATLAS_HAVE_TRANS - call atlas__Trans__gathspec(this%c_ptr(), 1, (/1/), local, global ) + call atlas__Trans__gathspec(this%CPTR_PGIBUG_A, 1, (/1/), local, global ) #else THROW_ERROR FCKIT_SUPPRESS_UNUSED( this ) @@ -479,7 +487,7 @@ subroutine gathspec_r2(this, local, global) destination(:) = 1 local_view => array_view1d(local) global_view => array_view1d(global) - call atlas__Trans__gathspec(this%c_ptr(), size(local,1), destination, local_view, global_view ) + call atlas__Trans__gathspec(this%CPTR_PGIBUG_A, size(local,1), destination, local_view, global_view ) #else THROW_ERROR FCKIT_SUPPRESS_UNUSED( this ) @@ -501,7 +509,7 @@ subroutine specnorm_r1_scalar(this, spectra, norm, rank) real(c_double) :: norms(1) rank_opt = 0 if( present(rank) ) rank_opt = rank - call atlas__Trans__specnorm(this%c_ptr(), 1, spectra, norms, rank_opt ) + call atlas__Trans__specnorm(this%CPTR_PGIBUG_A, 1, spectra, norms, rank_opt ) norm = norms(1) #else norm=0 @@ -526,7 +534,7 @@ subroutine specnorm_r2(this, spectra, norm, rank) rank_opt = 0 if( present(rank) ) rank_opt = rank spectra_view => array_view1d(spectra) - call atlas__Trans__specnorm(this%c_ptr(), size(spectra,1), spectra_view, norm, rank_opt ) + call atlas__Trans__specnorm(this%CPTR_PGIBUG_A, size(spectra,1), spectra_view, norm, rank_opt ) #else THROW_ERROR FCKIT_SUPPRESS_UNUSED( this ) diff --git a/src/atlas_f/util/atlas_Config_module.F90 b/src/atlas_f/util/atlas_Config_module.F90 index 02e5c6d00..713656c2a 100644 --- a/src/atlas_f/util/atlas_Config_module.F90 +++ b/src/atlas_f/util/atlas_Config_module.F90 @@ -1,3 +1,11 @@ +! (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_config_module @@ -149,7 +157,7 @@ function atlas_Config__has(this, name) result(value) character(len=*), intent(in) :: name logical :: value integer :: value_int - value_int = atlas__Config__has(this%c_ptr(), c_str(name) ) + value_int = atlas__Config__has(this%CPTR_PGIBUG_B, c_str(name) ) if( value_int == 1 ) then value = .True. else @@ -163,7 +171,7 @@ subroutine atlas_Config__set_config(this, name, value) class(atlas_Config), intent(inout) :: this character(len=*), intent(in) :: name class(atlas_Config), intent(in) :: value - call atlas__Config__set_config(this%c_ptr(), c_str(name), value%c_ptr() ) + call atlas__Config__set_config(this%CPTR_PGIBUG_B, c_str(name), value%CPTR_PGIBUG_B ) end subroutine atlas_Config__set_config subroutine atlas_Config__set_config_list(this, name, value) @@ -177,9 +185,9 @@ subroutine atlas_Config__set_config_list(this, name, value) integer :: j if( size(value) > 0 ) then do j=1,size(value) - value_cptrs(j) = value(j)%c_ptr() + value_cptrs(j) = value(j)%CPTR_PGIBUG_B enddo - call atlas__Config__set_config_list(this%c_ptr(), c_str(name), c_loc(value_cptrs(1)), size(value_cptrs) ) + call atlas__Config__set_config_list(this%CPTR_PGIBUG_B, c_str(name), c_loc(value_cptrs(1)), size(value_cptrs) ) endif end subroutine atlas_Config__set_config_list @@ -196,7 +204,7 @@ subroutine atlas_Config__set_logical(this, name, value) else value_int = 0 end if - call atlas__Config__set_int(this%c_ptr(), c_str(name), value_int ) + call atlas__Config__set_int(this%CPTR_PGIBUG_B, c_str(name), value_int ) end subroutine atlas_Config__set_logical subroutine atlas_Config__set_int32(this, name, value) @@ -205,7 +213,7 @@ subroutine atlas_Config__set_int32(this, name, value) class(atlas_Config), intent(inout) :: this character(len=*), intent(in) :: name integer, intent(in) :: value - call atlas__Config__set_int(this%c_ptr(), c_str(name), value) + call atlas__Config__set_int(this%CPTR_PGIBUG_B, c_str(name), value) end subroutine atlas_Config__set_int32 subroutine atlas_Config__set_real32(this, name, value) @@ -215,7 +223,7 @@ subroutine atlas_Config__set_real32(this, name, value) class(atlas_Config), intent(inout) :: this character(len=*), intent(in) :: name real(c_float), intent(in) :: value - call atlas__Config__set_float(this%c_ptr(), c_str(name) ,value) + call atlas__Config__set_float(this%CPTR_PGIBUG_B, c_str(name) ,value) end subroutine atlas_Config__set_real32 subroutine atlas_Config__set_real64(this, name, value) @@ -225,7 +233,7 @@ subroutine atlas_Config__set_real64(this, name, value) class(atlas_Config), intent(inout) :: this character(len=*), intent(in) :: name real(c_double), intent(in) :: value - call atlas__Config__set_double(this%c_ptr(), c_str(name) ,value) + call atlas__Config__set_double(this%CPTR_PGIBUG_B, c_str(name) ,value) end subroutine atlas_Config__set_real64 subroutine atlas_Config__set_string(this, name, value) @@ -234,7 +242,7 @@ subroutine atlas_Config__set_string(this, name, value) class(atlas_Config), intent(inout) :: this character(len=*), intent(in) :: name character(len=*), intent(in) :: value - call atlas__Config__set_string(this%c_ptr(), c_str(name) , c_str(value) ) + call atlas__Config__set_string(this%CPTR_PGIBUG_B, c_str(name) , c_str(value) ) end subroutine atlas_Config__set_string function atlas_Config__get_config(this, name, value) result(found) @@ -246,7 +254,7 @@ function atlas_Config__get_config(this, name, value) result(found) class(atlas_Config), intent(inout) :: value integer :: found_int value = atlas_Config() - found_int = atlas__Config__get_config( this%c_ptr(), c_str(name), value%c_ptr() ) + found_int = atlas__Config__get_config( this%CPTR_PGIBUG_B, c_str(name), value%CPTR_PGIBUG_B ) found = .False. if (found_int == 1) found = .True. end function atlas_Config__get_config @@ -266,7 +274,7 @@ function atlas_Config__get_config_list(this, name, value) result(found) integer :: found_int integer :: j value_list_cptr = c_null_ptr - found_int = atlas__Config__get_config_list(this%c_ptr(), c_str(name), & + found_int = atlas__Config__get_config_list(this%CPTR_PGIBUG_B, c_str(name), & & value_list_cptr, value_list_size, value_list_allocated ) if( found_int == 1 ) then call c_f_pointer(value_list_cptr,value_cptrs,(/value_list_size/)) @@ -290,7 +298,7 @@ function atlas_Config__get_logical(this, name, value) result(found) logical, intent(inout) :: value integer :: value_int integer :: found_int - found_int = atlas__Config__get_int(this%c_ptr(),c_str(name), value_int ) + found_int = atlas__Config__get_int(this%CPTR_PGIBUG_B,c_str(name), value_int ) found = .False. if (found_int == 1) found = .True. if (found) then @@ -310,7 +318,7 @@ function atlas_Config__get_int32(this, name, value) result(found) character(len=*), intent(in) :: name integer, intent(inout) :: value integer :: found_int - found_int = atlas__Config__get_int(this%c_ptr(), c_str(name), value ) + found_int = atlas__Config__get_int(this%CPTR_PGIBUG_B, c_str(name), value ) found = .False. if (found_int == 1) found = .True. end function atlas_Config__get_int32 @@ -324,7 +332,7 @@ function atlas_Config__get_real32(this, name, value) result(found) character(len=*), intent(in) :: name real(c_float), intent(inout) :: value integer :: found_int - found_int = atlas__Config__get_float(this%c_ptr(), c_str(name), value ) + found_int = atlas__Config__get_float(this%CPTR_PGIBUG_B, c_str(name), value ) found = .False. if (found_int == 1) found = .True. end function atlas_Config__get_real32 @@ -338,7 +346,7 @@ function atlas_Config__get_real64(this, name, value) result(found) character(len=*), intent(in) :: name real(c_double), intent(inout) :: value integer :: found_int - found_int = atlas__Config__get_double(this%c_ptr(), c_str(name), value ) + found_int = atlas__Config__get_double(this%CPTR_PGIBUG_B, c_str(name), value ) found = .False. if (found_int == 1) found = .True. end function atlas_Config__get_real64 @@ -355,7 +363,7 @@ function atlas_Config__get_string(this, name, value) result(found) integer :: found_int integer(c_int) :: value_size integer(c_int) :: value_allocated - found_int = atlas__Config__get_string(this%c_ptr(),c_str(name),value_cptr,value_size,value_allocated) + found_int = atlas__Config__get_string(this%CPTR_PGIBUG_B,c_str(name),value_cptr,value_size,value_allocated) if( found_int == 1 ) then if( allocated(value) ) deallocate(value) allocate(character(len=value_size) :: value ) @@ -373,7 +381,7 @@ subroutine atlas_Config__set_array_int32(this, name, value) class(atlas_Config), intent(in) :: this character(len=*), intent(in) :: name integer(c_int), intent(in) :: value(:) - call atlas__Config__set_array_int(this%c_ptr(), c_str(name), & + call atlas__Config__set_array_int(this%CPTR_PGIBUG_B, c_str(name), & & value, size(value) ) end subroutine atlas_Config__set_array_int32 @@ -384,7 +392,7 @@ subroutine atlas_Config__set_array_int64(this, name, value) class(atlas_Config), intent(in) :: this character(len=*), intent(in) :: name integer(c_long), intent(in) :: value(:) - call atlas__Config__set_array_long(this%c_ptr(), c_str(name), & + call atlas__Config__set_array_long(this%CPTR_PGIBUG_B, c_str(name), & & value, size(value) ) end subroutine atlas_Config__set_array_int64 @@ -395,7 +403,7 @@ subroutine atlas_Config__set_array_real32(this, name, value) class(atlas_Config), intent(in) :: this character(len=*), intent(in) :: name real(c_float), intent(in) :: value(:) - call atlas__Config__set_array_float(this%c_ptr(), c_str(name), & + call atlas__Config__set_array_float(this%CPTR_PGIBUG_B, c_str(name), & & value, size(value) ) end subroutine atlas_Config__set_array_real32 @@ -406,7 +414,7 @@ subroutine atlas_Config__set_array_real64(this, name, value) class(atlas_Config), intent(in) :: this character(len=*), intent(in) :: name real(c_double), intent(in) :: value(:) - call atlas__Config__set_array_double(this%c_ptr(), c_str(name), & + call atlas__Config__set_array_double(this%CPTR_PGIBUG_B, c_str(name), & & value, size(value) ) end subroutine atlas_Config__set_array_real64 @@ -423,7 +431,7 @@ function atlas_Config__get_array_int32(this, name, value) result(found) integer :: value_size integer :: value_allocated integer :: found_int - found_int = atlas__Config__get_array_int(this%c_ptr(), c_str(name), & + found_int = atlas__Config__get_array_int(this%CPTR_PGIBUG_B, c_str(name), & & value_cptr, value_size, value_allocated ) if (found_int ==1 ) then call c_f_pointer(value_cptr,value_fptr,(/value_size/)) @@ -449,7 +457,7 @@ function atlas_Config__get_array_int64(this, name, value) result(found) integer :: value_size integer :: value_allocated integer :: found_int - found_int = atlas__Config__get_array_long(this%c_ptr(), c_str(name), & + found_int = atlas__Config__get_array_long(this%CPTR_PGIBUG_B, c_str(name), & & value_cptr, value_size, value_allocated ) if (found_int == 1) then call c_f_pointer(value_cptr,value_fptr,(/value_size/)) @@ -475,7 +483,7 @@ function atlas_Config__get_array_real32(this, name, value) result(found) integer :: value_size integer :: value_allocated integer :: found_int - found_int = atlas__Config__get_array_float(this%c_ptr(), c_str(name), & + found_int = atlas__Config__get_array_float(this%CPTR_PGIBUG_B, c_str(name), & & value_cptr, value_size, value_allocated ) if (found_int == 1 ) then call c_f_pointer(value_cptr,value_fptr,(/value_size/)) @@ -501,7 +509,7 @@ function atlas_Config__get_array_real64(this, name, value) result(found) integer :: value_size integer :: value_allocated integer :: found_int - found_int = atlas__Config__get_array_double(this%c_ptr(), c_str(name), & + found_int = atlas__Config__get_array_double(this%CPTR_PGIBUG_B, c_str(name), & & value_cptr, value_size, value_allocated ) if (found_int == 1) then call c_f_pointer(value_cptr,value_fptr,(/value_size/)) @@ -523,7 +531,7 @@ function atlas_Config__json(this) result(json) type(c_ptr) :: json_cptr integer(c_int) :: json_size integer(c_int) :: json_allocated - call atlas__Config__json(this%c_ptr(),json_cptr,json_size,json_allocated) + call atlas__Config__json(this%CPTR_PGIBUG_B,json_cptr,json_size,json_allocated) allocate(character(len=json_size) :: json ) json = c_ptr_to_string(json_cptr) if( json_allocated == 1 ) call c_ptr_free(json_cptr) diff --git a/src/atlas_f/util/atlas_Error_module.F90 b/src/atlas_f/util/atlas_Error_module.F90 deleted file mode 100644 index 4daa7a0e4..000000000 --- a/src/atlas_f/util/atlas_Error_module.F90 +++ /dev/null @@ -1,424 +0,0 @@ -#include "atlas/atlas_f.h" - -module atlas_Error_module - -implicit none -private - -public :: atlas_CodeLocation -public :: atlas_code_location_str -public :: atlas_code_location -public :: atlas_abort -public :: atlas_throw_exception -public :: atlas_throw_notimplemented -public :: atlas_throw_outofrange -public :: atlas_throw_seriousbug -public :: atlas_throw_usererror -public :: atlas_throw_assertionfailed -public :: atlas_err_code -public :: atlas_err_msg -public :: atlas_err_set_aborts -public :: atlas_err_set_throws -public :: atlas_err_set_backtrace -public :: atlas_err -public :: atlas_noerr -public :: atlas_err_clear -public :: atlas_err_success - -! Error codes -integer, parameter, public :: & - atlas_err_cleared = 1, & - atlas_err_noerr = 0, & - atlas_err_exception = -1, & - atlas_err_usererror = -2, & - atlas_err_seriousbug = -3, & - atlas_err_notimplemented = -4, & - atlas_err_assertionfailed = -5, & - atlas_err_badparameter = -6, & - atlas_err_outofrange = -7, & - atlas_err_stop = -100, & - atlas_err_abort = -101, & - atlas_err_cancel = -102, & - atlas_err_readerror = -200, & - atlas_err_writeerror = -201, & - atlas_err_unknown = -999 - -integer, private, parameter :: ATLAS_CODELOCATION_FILE_STRLEN = 1024 -integer, private, parameter :: ATLAS_CODELOCATION_FUNCTION_STRLEN = 1024 - -TYPE :: atlas_CodeLocation - integer :: line - character(len=ATLAS_CODELOCATION_FILE_STRLEN) :: file - character(len=ATLAS_CODELOCATION_FILE_STRLEN) :: function -contains - procedure :: str => CodeLocation__str -ENDTYPE - -interface atlas_code_location_str - module procedure code_location_str_FILE_LINE -end interface - -interface atlas_abort - module procedure atlas_abort_null - module procedure atlas_abort_msg - module procedure atlas_abort_msg_loc -end interface atlas_abort - -interface atlas_throw_exception - module procedure atlas_throw_exception_msg - module procedure atlas_throw_exception_msg_loc - module procedure atlas_throw_exception_loc -end interface atlas_throw_exception - -interface atlas_throw_notimplemented - module procedure atlas_throw_notimplemented_msg - module procedure atlas_throw_notimplemented_loc - module procedure atlas_throw_notimplemented_msg_loc -end interface atlas_throw_notimplemented - -interface atlas_throw_outofrange - module procedure atlas_throw_outofrange_msg - module procedure atlas_throw_outofrange_loc - module procedure atlas_throw_outofrange_msg_loc - module procedure atlas_throw_outofrange_range - module procedure atlas_throw_outofrange_range_loc -end interface atlas_throw_outofrange - -interface atlas_throw_seriousbug - module procedure atlas_throw_seriousbug_msg - module procedure atlas_throw_seriousbug_loc - module procedure atlas_throw_seriousbug_msg_loc -end interface atlas_throw_seriousbug - -interface atlas_throw_usererror - module procedure atlas_throw_usererror_msg - module procedure atlas_throw_usererror_loc - module procedure atlas_throw_usererror_msg_loc -end interface atlas_throw_usererror - -interface atlas_throw_assertionfailed - module procedure atlas_throw_assertionfailed_msg - module procedure atlas_throw_assertionfailed_loc - module procedure atlas_throw_assertionfailed_msg_loc -end interface atlas_throw_assertionfailed - - -interface atlas_code_location - module procedure code_location_null - module procedure code_location_file_line - module procedure code_location_file_line_func -end interface atlas_code_location - -!------------------------------------------------------------------------------ -!======================================================== -contains -!======================================================== - - - -function atlas_err_code() - use atlas_errorhandling_c_binding - use, intrinsic :: iso_c_binding, only: c_ptr - integer :: atlas_err_code - atlas_err_code = atlas__Error_code() -end function - -function atlas_err_msg() - use, intrinsic :: iso_c_binding, only: c_ptr - use atlas_errorhandling_c_binding - use fckit_c_interop_module , only: c_ptr_to_string - type(c_ptr) :: msg_cptr - character(len=:), allocatable :: atlas_err_msg - msg_cptr = atlas__Error_msg() - atlas_err_msg = c_ptr_to_string(msg_cptr) -end function - -subroutine atlas_err_set_aborts( aborts ) - use atlas_errorhandling_c_binding - logical, intent(in) :: aborts - if( aborts ) then - call atlas__Error_set_aborts(1) - else - call atlas__Error_set_aborts(0) - endif -end subroutine - -subroutine atlas_err_set_throws( throws ) - use atlas_errorhandling_c_binding - logical, intent(in) :: throws - if( throws ) then - call atlas__Error_set_throws(1) - else - call atlas__Error_set_throws(0) - endif -end subroutine - -subroutine atlas_err_set_backtrace( backtrace ) - use atlas_errorhandling_c_binding - logical, intent(in) :: backtrace - if( backtrace ) then - call atlas__Error_set_backtrace(1) - else - call atlas__Error_set_backtrace(0) - endif -end subroutine - - -function CodeLocation__str(self) result( str ) - class(atlas_CodeLocation) :: self - character(len(self%file)+5) :: str - write(str,'(A,A1,I4)') self%file,":",self%line -end function - -function code_location_str_FILE_LINE(file,line) result( str ) - character(len=*), intent(in) :: file - integer, intent(in) :: line - character(len(file)+5) :: str - type(atlas_CodeLocation) :: code_location - code_location = code_location_file_line(file,line) - str = code_location%str() -end function - - -function code_location_null() result( code_location ) - type(atlas_CodeLocation) :: code_location - code_location%file = "" - code_location%line = 0 - code_location%function = "" -end function - -function code_location_file_line(file,line) result( code_location ) - character(len=*), intent(in) :: file - integer, intent(in) :: line - type(atlas_CodeLocation) :: code_location - code_location%file = file - code_location%line = line - code_location%function = "" -end function - -function code_location_file_line_func(file,line,func) result( code_location ) - character(len=*), intent(in) :: file, func - integer, intent(in) :: line - type(atlas_CodeLocation) :: code_location - code_location%file = file - code_location%line = line - code_location%function = func -end function - -subroutine atlas_abort_null() - use fckit_c_interop_module, only: c_str - use atlas_errorhandling_c_binding - call atlas__abort(c_str(""),c_str(""),0,c_str("")) -end subroutine - -subroutine atlas_abort_msg(msg) - use fckit_c_interop_module, only: c_str - use atlas_errorhandling_c_binding - character(len=*), intent(in) :: msg - call atlas__abort(c_str(msg),c_str(""),0,c_str("")) -end subroutine - -subroutine atlas_abort_msg_loc(msg,code_loc) - use fckit_c_interop_module, only: c_str - use atlas_errorhandling_c_binding - character(len=*), intent(in) :: msg - type(atlas_CodeLocation), intent(in) :: code_loc - call atlas__abort(c_str(msg),c_str(code_loc%file),code_loc%line,c_str(code_loc%function)) -end subroutine - -! ----------------------------------------------------------------------------- - -subroutine atlas_throw_exception_msg(msg) - use fckit_c_interop_module, only: c_str - use atlas_errorhandling_c_binding - character(len=*), intent(in) :: msg - call atlas__throw_exception(c_str(msg),c_str(""),0,c_str("")) -end subroutine - -subroutine atlas_throw_exception_loc(code_loc) - use fckit_c_interop_module, only: c_str - use atlas_errorhandling_c_binding - type(atlas_CodeLocation), intent(in) :: code_loc - call atlas__throw_exception(c_str(""),c_str(code_loc%file),code_loc%line,c_str(code_loc%function)) -end subroutine - -subroutine atlas_throw_exception_msg_loc(msg,code_loc) - use fckit_c_interop_module, only: c_str - use atlas_errorhandling_c_binding - character(len=*), intent(in) :: msg - type(atlas_CodeLocation), intent(in) :: code_loc - call atlas__throw_exception(c_str(msg),c_str(code_loc%file),code_loc%line,c_str(code_loc%function)) -end subroutine - -! ----------------------------------------------------------------------------- - -subroutine atlas_throw_notimplemented_loc(code_loc) - use fckit_c_interop_module, only: c_str - use atlas_errorhandling_c_binding - type(atlas_CodeLocation), intent(in) :: code_loc - call atlas__throw_notimplemented(c_str(""),c_str(code_loc%file),code_loc%line,c_str(code_loc%function)) -end subroutine - -subroutine atlas_throw_notimplemented_msg(msg) - use fckit_c_interop_module, only: c_str - use atlas_errorhandling_c_binding - character(len=*), intent(in) :: msg - call atlas__throw_notimplemented(c_str(msg),c_str(""),0,c_str("")) -end subroutine - -subroutine atlas_throw_notimplemented_msg_loc(msg,code_loc) - use fckit_c_interop_module, only: c_str - use atlas_errorhandling_c_binding - character(len=*), intent(in) :: msg - type(atlas_CodeLocation), intent(in) :: code_loc - call atlas__throw_notimplemented(c_str(msg),c_str(code_loc%file),code_loc%line,c_str(code_loc%function)) -end subroutine - -! ----------------------------------------------------------------------------- - -subroutine atlas_throw_outofrange_loc(code_loc) - use fckit_c_interop_module, only: c_str - use atlas_errorhandling_c_binding - type(atlas_CodeLocation), intent(in) :: code_loc - call atlas__throw_outofrange(c_str(""),c_str(code_loc%file),code_loc%line,c_str(code_loc%function)) -end subroutine - -subroutine atlas_throw_outofrange_msg(msg) - use fckit_c_interop_module, only: c_str - use atlas_errorhandling_c_binding - character(len=*), intent(in) :: msg - call atlas__throw_outofrange(c_str(msg),c_str(""),0,c_str("")) -end subroutine - -subroutine atlas_throw_outofrange_msg_loc(msg,code_loc) - use fckit_c_interop_module, only: c_str - use atlas_errorhandling_c_binding - character(len=*), intent(in) :: msg - type(atlas_CodeLocation), intent(in) :: code_loc - call atlas__throw_outofrange(c_str(msg),c_str(code_loc%file),code_loc%line,c_str(code_loc%function)) -end subroutine - -subroutine atlas_throw_outofrange_range_loc(arrayname,idx,max,code_loc) - use fckit_c_interop_module, only: c_str - use atlas_errorhandling_c_binding - character(len=*), intent(in) :: arrayname - integer, intent(in) :: idx, max - type(atlas_CodeLocation), intent(in) :: code_loc - character(len=80) :: msg - write(msg,'(A,I0,A,I0,A,A)') "Index ",idx," is greater than maximum ",max," in array ",arrayname - call atlas__throw_outofrange(c_str(msg),c_str(code_loc%file),code_loc%line,c_str(code_loc%function)) -end subroutine - -subroutine atlas_throw_outofrange_range(arrayname,idx,max) - use fckit_c_interop_module, only: c_str - use atlas_errorhandling_c_binding - character(len=*), intent(in) :: arrayname - integer, intent(in) :: idx, max - character(len=80) :: msg - write(msg,'(A,I0,A,I0,A,A)') "Index ",idx," is greater than maximum ",max," in array ",arrayname - call atlas__throw_outofrange(c_str(msg),c_str(""),0,c_str("")) -end subroutine - -! ----------------------------------------------------------------------------- - -subroutine atlas_throw_usererror_loc(code_loc) - use fckit_c_interop_module, only: c_str - use atlas_errorhandling_c_binding - type(atlas_CodeLocation), intent(in) :: code_loc - call atlas__throw_usererror(c_str(""),c_str(code_loc%file),code_loc%line,c_str(code_loc%function)) -end subroutine - -subroutine atlas_throw_usererror_msg(msg) - use fckit_c_interop_module, only: c_str - use atlas_errorhandling_c_binding - character(len=*), intent(in) :: msg - call atlas__throw_usererror(c_str(msg),c_str(""),0,c_str("")) -end subroutine - -subroutine atlas_throw_usererror_msg_loc(msg,code_loc) - use fckit_c_interop_module, only: c_str - use atlas_errorhandling_c_binding - character(len=*), intent(in) :: msg - type(atlas_CodeLocation), intent(in) :: code_loc - call atlas__throw_usererror(c_str(msg),c_str(code_loc%file),code_loc%line,c_str(code_loc%function)) -end subroutine - -! ----------------------------------------------------------------------------- - -subroutine atlas_throw_assertionfailed_loc(code_loc) - use fckit_c_interop_module, only: c_str - use atlas_errorhandling_c_binding - type(atlas_CodeLocation), intent(in) :: code_loc - call atlas__throw_assertionfailed(c_str(""),c_str(code_loc%file),code_loc%line,c_str(code_loc%function)) -end subroutine - -subroutine atlas_throw_assertionfailed_msg(msg) - use fckit_c_interop_module, only: c_str - use atlas_errorhandling_c_binding - character(len=*), intent(in) :: msg - call atlas__throw_assertionfailed(c_str(msg),c_str(""),0,c_str("")) -end subroutine - -subroutine atlas_throw_assertionfailed_msg_loc(msg,code_loc) - use fckit_c_interop_module, only: c_str - use atlas_errorhandling_c_binding - character(len=*), intent(in) :: msg - type(atlas_CodeLocation), intent(in) :: code_loc - call atlas__throw_assertionfailed(c_str(msg),c_str(code_loc%file),code_loc%line,c_str(code_loc%function)) -end subroutine - -! ----------------------------------------------------------------------------- - -subroutine atlas_throw_seriousbug_loc(code_loc) - use fckit_c_interop_module, only: c_str - use atlas_errorhandling_c_binding - type(atlas_CodeLocation), intent(in) :: code_loc - call atlas__throw_seriousbug(c_str(""),c_str(code_loc%file),code_loc%line,c_str(code_loc%function)) -end subroutine - -subroutine atlas_throw_seriousbug_msg(msg) - use fckit_c_interop_module, only: c_str - use atlas_errorhandling_c_binding - character(len=*), intent(in) :: msg - call atlas__throw_seriousbug(c_str(msg),c_str(""),0,c_str("")) -end subroutine - -subroutine atlas_throw_seriousbug_msg_loc(msg,code_loc) - use fckit_c_interop_module, only: c_str - use atlas_errorhandling_c_binding - character(len=*), intent(in) :: msg - type(atlas_CodeLocation), intent(in) :: code_loc - call atlas__throw_seriousbug(c_str(msg),c_str(code_loc%file),code_loc%line,c_str(code_loc%function)) -end subroutine - -! ----------------------------------------------------------------------------- -subroutine atlas_err_clear() - use atlas_errorhandling_c_binding - call atlas__Error_clear() -end subroutine - -subroutine atlas_err_success() - use atlas_errorhandling_c_binding - call atlas__Error_success() -end subroutine - -function atlas_noerr() - logical :: atlas_noerr - if( atlas_err_code() == atlas_err_noerr ) then - atlas_noerr = .True. - else - atlas_noerr = .False. - endif -end function - -function atlas_err() - logical :: atlas_err - if( atlas_err_code() /= atlas_err_noerr ) then - atlas_err = .True. - else - atlas_err = .False. - endif -end function - -end module atlas_Error_module - diff --git a/src/atlas_f/util/atlas_JSON_module.F90 b/src/atlas_f/util/atlas_JSON_module.F90 index 6b03183b7..4abaacf94 100644 --- a/src/atlas_f/util/atlas_JSON_module.F90 +++ b/src/atlas_f/util/atlas_JSON_module.F90 @@ -1,3 +1,11 @@ +! (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_JSON_module diff --git a/src/atlas_f/util/atlas_Metadata_module.F90 b/src/atlas_f/util/atlas_Metadata_module.F90 index 92068e207..186cec3c6 100644 --- a/src/atlas_f/util/atlas_Metadata_module.F90 +++ b/src/atlas_f/util/atlas_Metadata_module.F90 @@ -1,3 +1,11 @@ +! (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_metadata_module @@ -97,7 +105,7 @@ subroutine atlas_Metadata__delete(this) use atlas_metadata_c_binding class(atlas_Metadata), intent(inout) :: this if ( .not. this%is_null() ) then - call atlas__Metadata__delete(this%c_ptr()) + call atlas__Metadata__delete(this%CPTR_PGIBUG_A) end if call this%reset_c_ptr() end subroutine atlas_Metadata__delete @@ -109,7 +117,7 @@ function Metadata__has(this, name) result(value) character(len=*), intent(in) :: name logical :: value integer :: value_int - value_int = atlas__Metadata__has(this%c_ptr(), c_str(name) ) + value_int = atlas__Metadata__has(this%CPTR_PGIBUG_A, c_str(name) ) if( value_int == 1 ) then value = .True. else @@ -129,7 +137,7 @@ subroutine Metadata__set_logical(this, name, value) else value_int = 0 end if - call atlas__Metadata__set_int(this%c_ptr(), c_str(name), value_int ) + call atlas__Metadata__set_int(this%CPTR_PGIBUG_A, c_str(name), value_int ) end subroutine Metadata__set_logical subroutine Metadata__set_int32(this, name, value) @@ -138,7 +146,7 @@ subroutine Metadata__set_int32(this, name, value) class(atlas_Metadata), intent(inout) :: this character(len=*), intent(in) :: name integer, intent(in) :: value - call atlas__Metadata__set_int(this%c_ptr(), c_str(name), value) + call atlas__Metadata__set_int(this%CPTR_PGIBUG_A, c_str(name), value) end subroutine Metadata__set_int32 subroutine Metadata__set_real32(this, name, value) @@ -148,7 +156,7 @@ subroutine Metadata__set_real32(this, name, value) class(atlas_Metadata), intent(inout) :: this character(len=*), intent(in) :: name real(c_float), intent(in) :: value - call atlas__Metadata__set_float(this%c_ptr(), c_str(name) ,value) + call atlas__Metadata__set_float(this%CPTR_PGIBUG_A, c_str(name) ,value) end subroutine Metadata__set_real32 subroutine Metadata__set_real64(this, name, value) @@ -158,7 +166,7 @@ subroutine Metadata__set_real64(this, name, value) class(atlas_Metadata), intent(inout) :: this character(len=*), intent(in) :: name real(c_double), intent(in) :: value - call atlas__Metadata__set_double(this%c_ptr(), c_str(name) ,value) + call atlas__Metadata__set_double(this%CPTR_PGIBUG_A, c_str(name) ,value) end subroutine Metadata__set_real64 subroutine Metadata__set_string(this, name, value) @@ -167,7 +175,7 @@ subroutine Metadata__set_string(this, name, value) class(atlas_Metadata), intent(inout) :: this character(len=*), intent(in) :: name character(len=*), intent(in) :: value - call atlas__Metadata__set_string(this%c_ptr(), c_str(name) , c_str(value) ) + call atlas__Metadata__set_string(this%CPTR_PGIBUG_A, c_str(name) , c_str(value) ) end subroutine Metadata__set_string subroutine Metadata__get_logical(this, name, value) @@ -177,7 +185,7 @@ subroutine Metadata__get_logical(this, name, value) character(len=*), intent(in) :: name logical, intent(out) :: value integer :: value_int - value_int = atlas__Metadata__get_int(this%c_ptr(),c_str(name) ) + value_int = atlas__Metadata__get_int(this%CPTR_PGIBUG_A,c_str(name) ) if (value_int > 0) then value = .True. else @@ -191,7 +199,7 @@ subroutine Metadata__get_int32(this, name, value) class(atlas_Metadata), intent(in) :: this character(len=*), intent(in) :: name integer, intent(out) :: value - value = atlas__Metadata__get_int(this%c_ptr(), c_str(name) ) + value = atlas__Metadata__get_int(this%CPTR_PGIBUG_A, c_str(name) ) end subroutine Metadata__get_int32 subroutine Metadata__get_real32(this, name, value) @@ -201,7 +209,7 @@ subroutine Metadata__get_real32(this, name, value) class(atlas_Metadata), intent(in) :: this character(len=*), intent(in) :: name real(c_float), intent(out) :: value - value = atlas__Metadata__get_float(this%c_ptr(), c_str(name) ) + value = atlas__Metadata__get_float(this%CPTR_PGIBUG_A, c_str(name) ) end subroutine Metadata__get_real32 subroutine Metadata__get_real64(this, name, value) @@ -211,7 +219,7 @@ subroutine Metadata__get_real64(this, name, value) class(atlas_Metadata), intent(in) :: this character(len=*), intent(in) :: name real(c_double), intent(out) :: value - value = atlas__Metadata__get_double(this%c_ptr(), c_str(name) ) + value = atlas__Metadata__get_double(this%CPTR_PGIBUG_A, c_str(name) ) end subroutine Metadata__get_real64 subroutine Metadata__get_string(this, name, value) @@ -221,7 +229,7 @@ subroutine Metadata__get_string(this, name, value) character(len=*), intent(in) :: name character(len=:), allocatable, intent(out) :: value character(len=MAX_STR_LEN) :: value_cstr - call atlas__Metadata__get_string(this%c_ptr(), c_str(name), value_cstr, MAX_STR_LEN ) + call atlas__Metadata__get_string(this%CPTR_PGIBUG_A, c_str(name), value_cstr, MAX_STR_LEN ) value = c_str_to_string(value_cstr) end subroutine Metadata__get_string @@ -232,7 +240,7 @@ subroutine Metadata__set_array_int32(this, name, value) class(atlas_Metadata), intent(in) :: this character(len=*), intent(in) :: name integer(c_int), intent(in) :: value(:) - call atlas__Metadata__set_array_int(this%c_ptr(), c_str(name), & + call atlas__Metadata__set_array_int(this%CPTR_PGIBUG_A, c_str(name), & & value, size(value) ) end subroutine Metadata__set_array_int32 @@ -243,7 +251,7 @@ subroutine Metadata__set_array_int64(this, name, value) class(atlas_Metadata), intent(in) :: this character(len=*), intent(in) :: name integer(c_long), intent(in) :: value(:) - call atlas__Metadata__set_array_long(this%c_ptr(), c_str(name), & + call atlas__Metadata__set_array_long(this%CPTR_PGIBUG_A, c_str(name), & & value, size(value) ) end subroutine Metadata__set_array_int64 @@ -254,7 +262,7 @@ subroutine Metadata__set_array_real32(this, name, value) class(atlas_Metadata), intent(in) :: this character(len=*), intent(in) :: name real(c_float), intent(in) :: value(:) - call atlas__Metadata__set_array_float(this%c_ptr(), c_str(name), & + call atlas__Metadata__set_array_float(this%CPTR_PGIBUG_A, c_str(name), & & value, size(value) ) end subroutine Metadata__set_array_real32 @@ -265,7 +273,7 @@ subroutine Metadata__set_array_real64(this, name, value) class(atlas_Metadata), intent(in) :: this character(len=*), intent(in) :: name real(c_double), intent(in) :: value(:) - call atlas__Metadata__set_array_double(this%c_ptr(), c_str(name), & + call atlas__Metadata__set_array_double(this%CPTR_PGIBUG_A, c_str(name), & & value, size(value) ) end subroutine Metadata__set_array_real64 @@ -280,7 +288,7 @@ subroutine Metadata__get_array_int32(this, name, value) integer(c_int), pointer :: value_fptr(:) integer :: value_size integer :: value_allocated - call atlas__Metadata__get_array_int(this%c_ptr(), c_str(name), & + call atlas__Metadata__get_array_int(this%CPTR_PGIBUG_A, c_str(name), & & value_cptr, value_size, value_allocated ) call c_f_pointer(value_cptr,value_fptr,[value_size]) allocate(value(value_size)) @@ -299,7 +307,7 @@ subroutine Metadata__get_array_int64(this, name, value) integer(c_long), pointer :: value_fptr(:) integer :: value_size integer :: value_allocated - call atlas__Metadata__get_array_long(this%c_ptr(), c_str(name), & + call atlas__Metadata__get_array_long(this%CPTR_PGIBUG_A, c_str(name), & & value_cptr, value_size, value_allocated ) call c_f_pointer(value_cptr,value_fptr,(/value_size/)) allocate(value(value_size)) @@ -318,7 +326,7 @@ subroutine Metadata__get_array_real32(this, name, value) real(c_float), pointer :: value_fptr(:) integer :: value_size integer :: value_allocated - call atlas__Metadata__get_array_float(this%c_ptr(), c_str(name), & + call atlas__Metadata__get_array_float(this%CPTR_PGIBUG_A, c_str(name), & & value_cptr, value_size, value_allocated ) call c_f_pointer(value_cptr,value_fptr,(/value_size/)) allocate(value(value_size)) @@ -337,7 +345,7 @@ subroutine Metadata__get_array_real64(this, name, value) real(c_double), pointer :: value_fptr(:) integer :: value_size integer :: value_allocated - call atlas__Metadata__get_array_double(this%c_ptr(), c_str(name), & + call atlas__Metadata__get_array_double(this%CPTR_PGIBUG_A, c_str(name), & & value_cptr, value_size, value_allocated ) call c_f_pointer(value_cptr,value_fptr,(/value_size/)) allocate(value(value_size)) @@ -350,7 +358,7 @@ subroutine MetaData__print(this,channel) use fckit_log_module, only : fckit_logchannel class(atlas_Metadata), intent(in) :: this type(fckit_logchannel), intent(in) :: channel - call atlas__Metadata__print(this%c_ptr(),channel%c_ptr()) + call atlas__Metadata__print(this%CPTR_PGIBUG_A,channel%CPTR_PGIBUG_A) end subroutine Metadata__print function Metadata__json(this) result(json) @@ -362,7 +370,7 @@ function Metadata__json(this) result(json) type(c_ptr) :: json_cptr integer(c_int) :: json_size integer(c_int) :: json_allocated - call atlas__Metadata__json(this%c_ptr(),json_cptr,json_size,json_allocated) + call atlas__Metadata__json(this%CPTR_PGIBUG_A,json_cptr,json_size,json_allocated) allocate(character(len=json_size) :: json ) json = c_ptr_to_string(json_cptr) if( json_allocated == 1 ) call c_ptr_free(json_cptr) diff --git a/src/atlas_f/util/atlas_allocate_module.F90 b/src/atlas_f/util/atlas_allocate_module.F90 new file mode 100644 index 000000000..1f69ff4b8 --- /dev/null +++ b/src/atlas_f/util/atlas_allocate_module.F90 @@ -0,0 +1,235 @@ +! (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_allocate_module + +implicit none +private + +public :: atlas_allocate_managedmem +public :: atlas_deallocate_managedmem + + +interface atlas_allocate_managedmem + module procedure atlas_allocate_managedmem_real64_r1 + module procedure atlas_allocate_managedmem_real32_r1 + module procedure atlas_allocate_managedmem_int32_r1 + module procedure atlas_allocate_managedmem_int64_r1 + module procedure atlas_allocate_managedmem_real64_r2 + module procedure atlas_allocate_managedmem_real32_r2 + module procedure atlas_allocate_managedmem_int32_r2 + module procedure atlas_allocate_managedmem_int64_r2 +end interface + +interface atlas_deallocate_managedmem + module procedure atlas_deallocate_managedmem_real64_r1 + module procedure atlas_deallocate_managedmem_real32_r1 + module procedure atlas_deallocate_managedmem_int32_r1 + module procedure atlas_deallocate_managedmem_int64_r1 + module procedure atlas_deallocate_managedmem_real64_r2 + module procedure atlas_deallocate_managedmem_real32_r2 + module procedure atlas_deallocate_managedmem_int32_r2 + module procedure atlas_deallocate_managedmem_int64_r2 +end interface + +!------------------------------------------------------------------------------ +contains +!------------------------------------------------------------------------------ + +subroutine atlas_allocate_managedmem_real64_r1( A, dims ) + use, intrinsic :: iso_c_binding + use atlas_allocate_c_binding + real(c_double), pointer :: a(:) + integer(c_int) :: dims(:) + type(c_ptr) :: value_cptr + call atlas__allocate_managedmem_double( value_cptr, dims(1) ) + call c_f_pointer(value_cptr,a,dims) +end subroutine + +subroutine atlas_allocate_managedmem_real32_r1( A, dims ) + use, intrinsic :: iso_c_binding + use atlas_allocate_c_binding + real(c_float), pointer :: a(:) + integer(c_int) :: dims(:) + type(c_ptr) :: value_cptr + call atlas__allocate_managedmem_float( value_cptr, dims(1) ) + call c_f_pointer(value_cptr,a,dims) +end subroutine + +subroutine atlas_allocate_managedmem_int32_r1( A, dims ) + use, intrinsic :: iso_c_binding + use atlas_allocate_c_binding + integer(c_int), pointer :: a(:) + integer(c_int) :: dims(:) + type(c_ptr) :: value_cptr + call atlas__allocate_managedmem_int( value_cptr, dims(1) ) + call c_f_pointer(value_cptr,a,dims) +end subroutine + +subroutine atlas_allocate_managedmem_int64_r1( A, dims ) + use, intrinsic :: iso_c_binding + use atlas_allocate_c_binding + integer(c_long), pointer :: a(:) + integer(c_int) :: dims(:) + type(c_ptr) :: value_cptr + call atlas__allocate_managedmem_long( value_cptr, dims(1) ) + call c_f_pointer(value_cptr,a,dims) +end subroutine + +subroutine atlas_allocate_managedmem_int32_r2( A, dims ) + use, intrinsic :: iso_c_binding + use atlas_allocate_c_binding + integer(c_int), pointer :: a(:,:) + integer(c_int) :: dims(:) + type(c_ptr) :: value_cptr + call atlas__allocate_managedmem_int( value_cptr, dims(1)*dims(2) ) + call c_f_pointer(value_cptr,a,dims) +end subroutine + +subroutine atlas_allocate_managedmem_int64_r2( A, dims ) + use, intrinsic :: iso_c_binding + use atlas_allocate_c_binding + integer(c_long), pointer :: a(:,:) + integer(c_int) :: dims(:) + type(c_ptr) :: value_cptr + call atlas__allocate_managedmem_long( value_cptr, dims(1)*dims(2) ) + call c_f_pointer(value_cptr,a,dims) +end subroutine + +subroutine atlas_allocate_managedmem_real64_r2( A, dims ) + use, intrinsic :: iso_c_binding + use atlas_allocate_c_binding + real(c_double), pointer :: a(:,:) + integer(c_int) :: dims(:) + type(c_ptr) :: value_cptr + call atlas__allocate_managedmem_double( value_cptr, dims(1)*dims(2) ) + call c_f_pointer(value_cptr,a,dims) +end subroutine + +subroutine atlas_allocate_managedmem_real32_r2( A, dims ) + use, intrinsic :: iso_c_binding + use atlas_allocate_c_binding + real(c_float), pointer :: a(:,:) + integer(c_int) :: dims(:) + type(c_ptr) :: value_cptr + call atlas__allocate_managedmem_float( value_cptr, dims(1)*dims(2) ) + call c_f_pointer(value_cptr,a,dims) +end subroutine + +!------------------------------------------------------------------------------ + +! These functions are private in fckit_array_module + +function c_loc_int32(x) + use, intrinsic :: iso_c_binding + integer(c_int32_t), target :: x + type(c_ptr) :: c_loc_int32 + c_loc_int32 = c_loc(x) +end function + +! ============================================================================= + +function c_loc_int64(x) + use, intrinsic :: iso_c_binding + integer(c_int64_t), target :: x + type(c_ptr) :: c_loc_int64 + c_loc_int64 = c_loc(x) +end function + +! ============================================================================= + +function c_loc_real32(x) + use, intrinsic :: iso_c_binding + real(c_float), target :: x + type(c_ptr) :: c_loc_real32 + c_loc_real32 = c_loc(x) +end function + +! ============================================================================= + +function c_loc_real64(x) + use, intrinsic :: iso_c_binding + real(c_double), target :: x + type(c_ptr) :: c_loc_real64 + c_loc_real64 = c_loc(x) +end function + +! ============================================================================= + +!------------------------------------------------------------------------------ + +subroutine atlas_deallocate_managedmem_real64_r1( A ) + use, intrinsic :: iso_c_binding + use atlas_allocate_c_binding + real(c_double), pointer :: a(:) + call atlas__deallocate_managedmem( c_loc_real64(A(1)) ) + nullify( a ) +end subroutine + +subroutine atlas_deallocate_managedmem_real32_r1( A ) + use, intrinsic :: iso_c_binding + use atlas_allocate_c_binding + real(c_float), pointer :: a(:) + call atlas__deallocate_managedmem( c_loc_real32(A(1)) ) + nullify( a ) +end subroutine + +subroutine atlas_deallocate_managedmem_int32_r1( A ) + use, intrinsic :: iso_c_binding + use atlas_allocate_c_binding + integer(c_int), pointer :: a(:) + call atlas__deallocate_managedmem( c_loc_int32(A(1)) ) + nullify( a ) +end subroutine + +subroutine atlas_deallocate_managedmem_int64_r1( A ) + use, intrinsic :: iso_c_binding + use atlas_allocate_c_binding + integer(c_long), pointer :: a(:) + call atlas__deallocate_managedmem( c_loc_int64(A(1)) ) + nullify( a ) +end subroutine + +subroutine atlas_deallocate_managedmem_real64_r2( A ) + use, intrinsic :: iso_c_binding + use atlas_allocate_c_binding + real(c_double), pointer :: a(:,:) + call atlas__deallocate_managedmem( c_loc_real64(A(1,1)) ) + nullify( a ) +end subroutine + +subroutine atlas_deallocate_managedmem_real32_r2( A ) + use, intrinsic :: iso_c_binding + use atlas_allocate_c_binding + real(c_float), pointer :: a(:,:) + call atlas__deallocate_managedmem( c_loc_real32(A(1,1)) ) + nullify( a ) +end subroutine + +subroutine atlas_deallocate_managedmem_int32_r2( A ) + use, intrinsic :: iso_c_binding + use atlas_allocate_c_binding + integer(c_int), pointer :: a(:,:) + call atlas__deallocate_managedmem( c_loc_int32(A(1,1)) ) + nullify( a ) +end subroutine + +subroutine atlas_deallocate_managedmem_int64_r2( A ) + use, intrinsic :: iso_c_binding + use atlas_allocate_c_binding + integer(c_long), pointer :: a(:,:) + call atlas__deallocate_managedmem( c_loc_int64(A(1,1)) ) + nullify( a ) +end subroutine + +!------------------------------------------------------------------------------ + +end module atlas_allocate_module + diff --git a/src/atlas_f/util/atlas_kinds_module.F90 b/src/atlas_f/util/atlas_kinds_module.F90 index 821939d83..3bbbb6a92 100644 --- a/src/atlas_f/util/atlas_kinds_module.F90 +++ b/src/atlas_f/util/atlas_kinds_module.F90 @@ -1,3 +1,11 @@ +! (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_kinds_module @@ -27,7 +35,13 @@ module atlas_kinds_module #error ATLAS_BITS_GLOBAL must be either 32 or 64 #endif +#if ATLAS_BITS_LOCAL == 32 integer, parameter :: ATLAS_KIND_IDX = c_int +#elif ATLAS_BITS_LOCAL == 64 +integer, parameter :: ATLAS_KIND_IDX = c_long +#else +#error ATLAS_BITS_LOCAL must be either 32 or 64 +#endif integer, parameter :: ATLAS_KIND_REAL64 = c_double integer, parameter :: ATLAS_KIND_REAL32 = c_float diff --git a/src/sandbox/benchmark_ifs_setup/atlas-benchmark-ifs-setup.cc b/src/sandbox/benchmark_ifs_setup/atlas-benchmark-ifs-setup.cc index 638ed29df..86372547e 100644 --- a/src/sandbox/benchmark_ifs_setup/atlas-benchmark-ifs-setup.cc +++ b/src/sandbox/benchmark_ifs_setup/atlas-benchmark-ifs-setup.cc @@ -28,11 +28,11 @@ #include "atlas/numerics/fvm/Method.h" #include "atlas/output/detail/GmshIO.h" #include "atlas/parallel/mpi/mpi.h" +#include "atlas/parallel/omp/omp.h" #include "atlas/runtime/AtlasTool.h" #include "atlas/runtime/Log.h" #include "atlas/runtime/Trace.h" #include "atlas/util/Config.h" -#include "atlas/parallel/omp/omp.h" //------------------------------------------------------------------------------ @@ -62,12 +62,15 @@ class Tool : public AtlasTool { //----------------------------------------------------------------------------- -static int halo_default() { return 2; } +static int halo_default() { + return 2; +} Tool::Tool( int argc, char** argv ) : AtlasTool( argc, argv ) { add_option( new SimpleOption( "grid", "Grid unique identifier\n" + indent() + " Example values: N80, F40, O24, L32" ) ); - add_option( new SimpleOption( "halo", "Number of halos (default="+std::to_string(halo_default())+")" ) ); + add_option( + new SimpleOption( "halo", "Number of halos (default=" + std::to_string( halo_default() ) + ")" ) ); } //----------------------------------------------------------------------------- @@ -85,7 +88,7 @@ void Tool::execute( const Args& args ) { try { grid = Grid( key ); } - catch ( eckit::BadParameter& e ) { + catch ( eckit::Exception& e ) { } } else { diff --git a/src/sandbox/benchmark_sorting/atlas-benchmark-sorting.cc b/src/sandbox/benchmark_sorting/atlas-benchmark-sorting.cc index c7a996c31..7c91c6208 100644 --- a/src/sandbox/benchmark_sorting/atlas-benchmark-sorting.cc +++ b/src/sandbox/benchmark_sorting/atlas-benchmark-sorting.cc @@ -15,10 +15,10 @@ #include #include #include +#include #include #include -#include "eckit/exception/Exceptions.h" #include "eckit/filesystem/PathName.h" #include "atlas/grid.h" @@ -90,7 +90,7 @@ void make_nodes_global_index_human_readable( const mesh::actions::BuildHalo& bui if ( do_all ) { points_to_edit.resize( nodes_glb_idx.size() ); - for ( size_t i = 0; i < nodes_glb_idx.size(); ++i ) + for ( idx_t i = 0; i < nodes_glb_idx.size(); ++i ) points_to_edit[i] = i; } else { @@ -215,7 +215,7 @@ void Tool::execute( const Args& args ) { try { grid = Grid( key ); } - catch ( eckit::BadParameter& e ) { + catch ( eckit::Exception& ) { } } else { diff --git a/src/sandbox/example_fortran/CMakeLists.txt b/src/sandbox/example_fortran/CMakeLists.txt index 008cbe971..63304be30 100644 --- a/src/sandbox/example_fortran/CMakeLists.txt +++ b/src/sandbox/example_fortran/CMakeLists.txt @@ -1,3 +1,10 @@ +# (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. if( HAVE_FORTRAN ) diff --git a/src/sandbox/example_fortran/example_fortran.F90 b/src/sandbox/example_fortran/example_fortran.F90 index 5f1ef9923..542cb3e66 100644 --- a/src/sandbox/example_fortran/example_fortran.F90 +++ b/src/sandbox/example_fortran/example_fortran.F90 @@ -1,3 +1,10 @@ +! (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" diff --git a/src/sandbox/fortran_acc_fields/atlas-acc-fields.F90 b/src/sandbox/fortran_acc_fields/atlas-acc-fields.F90 index aeda9073b..d335a38ea 100644 --- a/src/sandbox/fortran_acc_fields/atlas-acc-fields.F90 +++ b/src/sandbox/fortran_acc_fields/atlas-acc-fields.F90 @@ -1,3 +1,11 @@ +! (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. + program atlas_acc_fields use atlas_module implicit none diff --git a/src/sandbox/fortran_object/CMakeLists.txt b/src/sandbox/fortran_object/CMakeLists.txt index ca5628496..9e1572853 100644 --- a/src/sandbox/fortran_object/CMakeLists.txt +++ b/src/sandbox/fortran_object/CMakeLists.txt @@ -1,3 +1,10 @@ +# (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. if( CMAKE_Fortran_COMPILER_LOADED ) diff --git a/src/sandbox/fortran_object/fortran_object.F90 b/src/sandbox/fortran_object/fortran_object.F90 index 12a9025ab..ef8373bab 100644 --- a/src/sandbox/fortran_object/fortran_object.F90 +++ b/src/sandbox/fortran_object/fortran_object.F90 @@ -1,3 +1,11 @@ +! (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. + ! Purpose of this program is to test if the compiler can support ! the final keyword for specifying a destructor for a derived type. ! Unfortunately gfortran version < 4.9 does not support it, diff --git a/src/sandbox/fortran_submodule/CMakeLists.txt b/src/sandbox/fortran_submodule/CMakeLists.txt index b6a9f5969..c19ed4f71 100644 --- a/src/sandbox/fortran_submodule/CMakeLists.txt +++ b/src/sandbox/fortran_submodule/CMakeLists.txt @@ -1,3 +1,10 @@ +# (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. if( CMAKE_Fortran_COMPILER_LOADED ) diff --git a/src/sandbox/fortran_submodule/sb_module.F90 b/src/sandbox/fortran_submodule/sb_module.F90 index f3fcbd2aa..c8cf21031 100644 --- a/src/sandbox/fortran_submodule/sb_module.F90 +++ b/src/sandbox/fortran_submodule/sb_module.F90 @@ -1,4 +1,10 @@ -! (C) Copyright 2013-2015 ECMWF. +! (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_defines_fortran.h" diff --git a/src/sandbox/grid_distribution/atlas-grid-distribution.cc b/src/sandbox/grid_distribution/atlas-grid-distribution.cc index 20d629698..071cf1fa4 100644 --- a/src/sandbox/grid_distribution/atlas-grid-distribution.cc +++ b/src/sandbox/grid_distribution/atlas-grid-distribution.cc @@ -17,6 +17,9 @@ #include #include +#include "eckit/exception/Exceptions.h" +#include "eckit/filesystem/PathName.h" + #include "atlas/grid.h" #include "atlas/grid/Distribution.h" #include "atlas/grid/Partitioner.h" @@ -26,8 +29,6 @@ #include "atlas/runtime/AtlasTool.h" #include "atlas/runtime/Log.h" #include "atlas/util/Config.h" -#include "eckit/exception/Exceptions.h" -#include "eckit/filesystem/PathName.h" //------------------------------------------------------------------------------ @@ -79,7 +80,7 @@ void Tool::execute( const Args& args ) { try { grid = Grid( key ); } - catch ( eckit::BadParameter& e ) { + catch ( eckit::Exception& e ) { } } else if ( path_in.path().size() ) { @@ -88,7 +89,7 @@ void Tool::execute( const Args& args ) { try { grid = Grid( Config( path_in ) ); } - catch ( eckit::BadParameter& e ) { + catch ( eckit::Exception& e ) { } } else { diff --git a/src/sandbox/interpolation-fortran/atlas-interpolation-fortran.F90 b/src/sandbox/interpolation-fortran/atlas-interpolation-fortran.F90 index 945a5b94e..0e88d2399 100644 --- a/src/sandbox/interpolation-fortran/atlas-interpolation-fortran.F90 +++ b/src/sandbox/interpolation-fortran/atlas-interpolation-fortran.F90 @@ -1,3 +1,11 @@ +! (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. + program atlas_interpolation_fortran use atlas_module implicit none @@ -17,9 +25,11 @@ program atlas_interpolation_fortran type(atlas_Config) :: interpolation_config type(atlas_Interpolation) :: interpolation_AB type(atlas_Interpolation) :: interpolation_BA +type(atlas_Trace) :: trace call atlas_library%initialise() +trace = atlas_Trace( "atlas-interpolation-fortran.F90", __LINE__, "Complete execution" ) ! Setup a meshgenerator meshgenerator = atlas_MeshGenerator() @@ -93,6 +103,8 @@ program atlas_interpolation_fortran call grid_A%final() call grid_B%final() +call trace%final() + call atlas_library%finalise() contains diff --git a/src/sandbox/interpolation/PartitionedMesh.cc b/src/sandbox/interpolation/PartitionedMesh.cc index 32a6518d1..57b221fa2 100644 --- a/src/sandbox/interpolation/PartitionedMesh.cc +++ b/src/sandbox/interpolation/PartitionedMesh.cc @@ -31,7 +31,7 @@ PartitionedMesh::PartitionedMesh( const std::string& partitioner, const std::str void PartitionedMesh::writeGmsh( const std::string& fileName, const FieldSet& fields ) { util::Config output_config; - output_config.set( "coordinates", std::string( "xyz" ) ); + //output_config.set( "coordinates", std::string( "xyz" ) ); output_config.set( "ghost", true ); output::Gmsh out( fileName, output_config ); diff --git a/src/sandbox/interpolation/atlas-parallel-interpolation.cc b/src/sandbox/interpolation/atlas-parallel-interpolation.cc index 18bad95c6..61d46516d 100644 --- a/src/sandbox/interpolation/atlas-parallel-interpolation.cc +++ b/src/sandbox/interpolation/atlas-parallel-interpolation.cc @@ -23,6 +23,26 @@ using namespace atlas; +auto vortex_rollup = []( double lon, double lat, double t ) { + // lon and lat in radians! + + // Formula found in "A Lagrangian Particle Method with Remeshing for Tracer Transport on the Sphere" + // by Peter Bosler, James Kent, Robert Krasny, CHristiane Jablonowski, JCP 2015 + + auto sqr = []( const double x ) { return x * x; }; + auto sech = []( const double x ) { return 1. / std::cosh( x ); }; + const double T = 1.; + const double Omega = 2. * M_PI / T; + t *= T; + const double lambda_prime = std::atan2( -std::cos( lon - Omega * t ), std::tan( lat ) ); + const double rho = 3. * std::sqrt( 1. - sqr( std::cos( lat ) ) * sqr( std::sin( lon - Omega * t ) ) ); + double omega = 0.; + double a = util::Earth::radius(); + if ( rho != 0. ) { omega = 0.5 * 3 * std::sqrt( 3 ) * a * Omega * sqr( sech( rho ) ) * std::tanh( rho ) / rho; } + double q = 1. - std::tanh( 0.2 * rho * std::sin( lambda_prime - omega / a * t ) ); + return q; +}; + class AtlasParallelInterpolation : public AtlasTool { void execute( const AtlasTool::Args& args ); std::string briefDescription() { return "Demonstration of parallel interpolation"; } @@ -44,6 +64,8 @@ class AtlasParallelInterpolation : public AtlasTool { new SimpleOption( "output-polygons", "Output Python script that plots partitions polygons" ) ); add_option( new SimpleOption( "method", "interpolation method (default finite-element)" ) ); + add_option( new SimpleOption( "backward-method", + "backward interpolation method (default finite-element)" ) ); add_option( new SimpleOption( "backend", "linear algebra backend" ) ); add_option( new SimpleOption( "k-nearest-neighbours", "k-nearest neighbours (default 1)" ) ); add_option( new SimpleOption( "with-backward", "Also do backward interpolation (default false)" ) ); @@ -86,10 +108,14 @@ void AtlasParallelInterpolation::execute( const AtlasTool::Args& args ) { bool log_statistics = false; args.get( "log-statistics", log_statistics ); - size_t log_rank = 0; + idx_t log_rank = 0; args.get( "log-rank", log_rank ); - if ( eckit::mpi::comm().rank() != log_rank ) { Log::reset(); } + if ( idx_t( eckit::mpi::comm().rank() ) != log_rank ) { Log::reset(); } + + std::string interpolation_method = "finite-element"; + args.get( "method", interpolation_method ); + if ( args.get( "backend", option ) ) { eckit::linalg::LinearAlgebra::backend( option ); } @@ -97,10 +123,13 @@ void AtlasParallelInterpolation::execute( const AtlasTool::Args& args ) { // source mesh is partitioned on its own, the target mesh uses // (pre-partitioned) source mesh - option = args.get( "source-gridname", option ) ? option : "O16"; - Grid src_grid( option ); + auto source_gridname = args.getString( "source-gridname", "O16" ); + auto target_gridname = args.getString( "target-gridname", "O32" ); + Log::info() << "atlas-parallel-interpolation from source grid " << source_gridname << " to " << target_gridname + << std::endl; + Grid src_grid( source_gridname ); - size_t source_mesh_halo = 0; + idx_t source_mesh_halo = 0; args.get( "source-mesh-halo", source_mesh_halo ); interpolation::PartitionedMesh src( args.get( "source-mesh-partitioner", option ) ? option : "equal_regions", @@ -108,11 +137,9 @@ void AtlasParallelInterpolation::execute( const AtlasTool::Args& args ) { args.get( "source-mesh-generator-triangulate", trigs ) ? trigs : false, args.get( "source-mesh-generator-angle", angle ) ? angle : 0. ); - option = args.get( "target-gridname", option ) ? option : "O32"; - Grid tgt_grid( option ); + Grid tgt_grid( target_gridname ); - size_t target_mesh_halo = 0; - args.get( "target-mesh-halo", target_mesh_halo ); + idx_t target_mesh_halo = args.getInt( "target-mesh-halo", 0 ); interpolation::PartitionedMesh tgt( args.get( "target-mesh-partitioner", option ) ? option : "spherical-polygon", args.get( "target-mesh-generator", option ) ? option : "structured", @@ -121,9 +148,25 @@ void AtlasParallelInterpolation::execute( const AtlasTool::Args& args ) { Log::info() << "Partitioning source grid, halo of " << eckit::Plural( source_mesh_halo, "element" ) << std::endl; src.partition( src_grid ); - functionspace::NodeColumns src_functionspace( src.mesh(), option::halo( source_mesh_halo ) ); + FunctionSpace src_functionspace; + bool structured = false; + for ( auto& is_structured : {"structured-bicubic", "bicubic", "structured-bilinear", "bilinear"} ) { + if ( interpolation_method == is_structured ) { + structured = true; + break; + } + } + if ( structured ) { + src_functionspace = + functionspace::StructuredColumns{src.mesh().grid(), option::halo( std::max( 2, source_mesh_halo ) ) | + util::Config( "periodic_points", true )}; + } + else { + src_functionspace = functionspace::NodeColumns{src.mesh(), option::halo( source_mesh_halo )}; + } src.writeGmsh( "src-mesh.msh" ); + Log::info() << "Partitioning target grid, halo of " << eckit::Plural( target_mesh_halo, "element" ) << std::endl; tgt.partition( tgt_grid, src ); functionspace::NodeColumns tgt_functionspace( tgt.mesh(), option::halo( target_mesh_halo ) ); @@ -138,18 +181,17 @@ void AtlasParallelInterpolation::execute( const AtlasTool::Args& args ) { // FunctionSpace halo Log::info() << "Computing forward/backward interpolator" << std::endl; - std::string interpolation_method = "finite-element"; - args.get( "method", interpolation_method ); - Interpolation interpolator_forward( option::type( interpolation_method ), src_functionspace, tgt_functionspace ); Interpolation interpolator_backward; bool with_backward = false; args.get( "with-backward", with_backward ); if ( with_backward ) { + std::string backward_interpolation_method = "finite-element"; + args.get( "method", backward_interpolation_method ); Log::info() << "Computing backward interpolator" << std::endl; interpolator_backward = - Interpolation( option::type( interpolation_method ), tgt_functionspace, src_functionspace ); + Interpolation( option::type( backward_interpolation_method ), tgt_functionspace, src_functionspace ); } if ( args.getBool( "forward-interpolator-output", false ) ) { interpolator_forward.print( Log::info() ); } @@ -164,10 +206,20 @@ void AtlasParallelInterpolation::execute( const AtlasTool::Args& args ) { // Helper constants const double deg2rad = M_PI / 180., c_lat = 0. * M_PI, c_lon = 1. * M_PI, c_rad = 2. * M_PI / 9.; - array::ArrayView lonlat = array::make_view( src.mesh().nodes().lonlat() ); + array::ArrayView lonlat = [&]() { + if ( auto fs = functionspace::NodeColumns( src_functionspace ) ) { + return array::make_view( fs.nodes().lonlat() ); + } + else if ( auto fs = functionspace::StructuredColumns( src_functionspace ) ) { + return array::make_view( fs.xy() ); + } + else { + ATLAS_NOTIMPLEMENTED; + } + }(); array::ArrayView src_scalar_1 = array::make_view( src_fields[0] ), src_scalar_2 = array::make_view( src_fields[1] ); - for ( size_t j = 0; j < src.mesh().nodes().size(); ++j ) { + for ( idx_t j = 0; j < lonlat.shape( 0 ); ++j ) { const double lon = deg2rad * lonlat( j, 0 ); // (lon) const double lat = deg2rad * lonlat( j, 1 ); // (lat) const double c2 = std::cos( lat ), s1 = std::sin( ( lon - c_lon ) / 2. ), @@ -175,16 +227,18 @@ void AtlasParallelInterpolation::execute( const AtlasTool::Args& args ) { src_scalar_1( j ) = dist < c_rad ? 0.5 * ( 1. + std::cos( M_PI * dist / c_rad ) ) : 0.; src_scalar_2( j ) = -src_scalar_1( j ); - double x = lonlat( j, 0 ) - 180.; - double y = lonlat( j, 1 ); + // double x = lonlat( j, 0 ) - 180.; + // double y = lonlat( j, 1 ); + + // src_scalar_1( j ) = -std::tanh( y / 10. * std::cos( 50. / std::sqrt( x * x + y * y ) ) - + // x / 10. * std::sin( 50. / std::sqrt( x * x + y * y ) ) ); - src_scalar_1( j ) = -std::tanh( y / 10. * std::cos( 50. / std::sqrt( x * x + y * y ) ) - - x / 10. * std::sin( 50. / std::sqrt( x * x + y * y ) ) ); + src_scalar_1( j ) = vortex_rollup( lon, lat, 1. ); } } FieldSet tgt_fields; - for ( size_t i = 0; i < src_fields.size(); ++i ) { + for ( idx_t i = 0; i < src_fields.size(); ++i ) { tgt_fields.add( tgt_functionspace.createField( option::name( src_fields[i].name() ) ) ); } @@ -210,22 +264,23 @@ void AtlasParallelInterpolation::execute( const AtlasTool::Args& args ) { Log::info() << "Interpolations done" << std::endl; // Report simple statistics (on source & target) - if ( log_statistics ) { - double meanA, minA, maxA, meanB, minB, maxB; - size_t nA, nB; - - for ( size_t i = 0; i < src_fields.size(); ++i ) { - src_functionspace.minimum( src_fields[i], minA ); - src_functionspace.maximum( src_fields[i], maxA ); - src_functionspace.mean( src_fields[i], meanA, nA ); - - tgt_functionspace.minimum( tgt_fields[i], minB ); - tgt_functionspace.maximum( tgt_fields[i], maxB ); - tgt_functionspace.mean( tgt_fields[i], meanB, nB ); - - Log::info() << "Field '" << src_fields[i].name() << "' (N,min,mean,max):" - << "\n\tsource:\t" << nA << ",\t" << minA << ",\t" << meanA << ",\t" << maxA << "\n\ttarget:\t" - << nB << ",\t" << minB << ",\t" << meanB << ",\t" << maxB << std::endl; + if ( auto src_nodecolumns = functionspace::NodeColumns{src_functionspace} ) { + if ( log_statistics ) { + double meanA, minA, maxA, meanB, minB, maxB; + idx_t nA, nB; + + for ( idx_t i = 0; i < src_fields.size(); ++i ) { + src_nodecolumns.minimum( src_fields[i], minA ); + src_nodecolumns.maximum( src_fields[i], maxA ); + src_nodecolumns.mean( src_fields[i], meanA, nA ); + tgt_functionspace.minimum( tgt_fields[i], minB ); + tgt_functionspace.maximum( tgt_fields[i], maxB ); + tgt_functionspace.mean( tgt_fields[i], meanB, nB ); + + Log::info() << "Field '" << src_fields[i].name() << "' (N,min,mean,max):" + << "\n\tsource:\t" << nA << ",\t" << minA << ",\t" << meanA << ",\t" << maxA + << "\n\ttarget:\t" << nB << ",\t" << minB << ",\t" << meanB << ",\t" << maxB << std::endl; + } } } diff --git a/src/tests/AtlasTestEnvironment.h b/src/tests/AtlasTestEnvironment.h index 9da6d7e3a..9284b39f2 100644 --- a/src/tests/AtlasTestEnvironment.h +++ b/src/tests/AtlasTestEnvironment.h @@ -16,13 +16,15 @@ #include "eckit/config/LibEcKit.h" #include "eckit/config/Resource.h" -#include "eckit/eckit_config.h" +#include "eckit/eckit.h" #include "eckit/log/PrefixTarget.h" #include "eckit/mpi/Comm.h" #include "eckit/runtime/Main.h" #include "eckit/testing/Test.h" +#include "eckit/types/Types.h" #include "atlas/library/Library.h" +#include "atlas/runtime/Exception.h" #include "atlas/runtime/Log.h" #include "atlas/runtime/Trace.h" #include "atlas/runtime/trace/StopWatch.h" @@ -31,11 +33,19 @@ namespace atlas { namespace test { +using eckit::types::is_approximately_equal; + //---------------------------------------------------------------------------------------------------------------------- +#ifdef MAYBE_UNUSED +#elif defined( __GNUC__ ) +#define MAYBE_UNUSED __attribute__( ( unused ) ) +#else +#define MAYBE_UNUSED +#endif + // Redefine macro's defined in "eckit/testing/Test.h" to include trace // information - #undef CASE #define CASE( description ) \ void UNIQUE_NAME2( test_, __LINE__ )( std::string&, int&, int ); \ @@ -55,8 +65,8 @@ namespace test { eckit::mpi::comm().abort(); \ } \ } \ - void UNIQUE_NAME2( traced_test_, __LINE__ )( std::string & _test_subsection, int& _num_subsections, \ - int _subsection ) + void UNIQUE_NAME2( traced_test_, __LINE__ )( MAYBE_UNUSED std::string & _test_subsection, \ + MAYBE_UNUSED int& _num_subsections, MAYBE_UNUSED int _subsection ) #undef SECTION #define SECTION( name ) \ diff --git a/src/tests/CMakeLists.txt b/src/tests/CMakeLists.txt index b82fecc35..46f9d7eff 100644 --- a/src/tests/CMakeLists.txt +++ b/src/tests/CMakeLists.txt @@ -62,8 +62,10 @@ macro( atlas_add_cuda_test ) endmacro() +add_subdirectory( acc ) add_subdirectory( array ) add_subdirectory( util ) +add_subdirectory( runtime ) add_subdirectory( parallel ) add_subdirectory( field ) add_subdirectory( grid ) diff --git a/src/tests/TestMeshes.h b/src/tests/TestMeshes.h index bfc6e518a..2f57fc6d1 100644 --- a/src/tests/TestMeshes.h +++ b/src/tests/TestMeshes.h @@ -11,18 +11,18 @@ #include "atlas/grid.h" #include "atlas/library/config.h" #include "atlas/mesh/Mesh.h" -#include "atlas/meshgenerator/StructuredMeshGenerator.h" +#include "atlas/meshgenerator.h" #include "atlas/parallel/mpi/mpi.h" using namespace atlas; using namespace atlas::grid; -// using namespace atlas::grid::detail::grid::reduced; namespace atlas { namespace test { Mesh generate_mesh( const StructuredGrid& grid ) { - meshgenerator::StructuredMeshGenerator generate; + auto config = util::Config( "partitioner", "equal_regions" ); + StructuredMeshGenerator generate( config ); return generate( grid ); } diff --git a/src/tests/acc/CMakeLists.txt b/src/tests/acc/CMakeLists.txt new file mode 100644 index 000000000..a54653393 --- /dev/null +++ b/src/tests/acc/CMakeLists.txt @@ -0,0 +1,35 @@ +# (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. + + +if( ATLAS_HAVE_GRIDTOOLS_STORAGE AND GRIDTOOLS_HAVE_CUDA AND ENABLE_TESTS AND HAVE_FCTEST AND ATLAS_HAVE_ACC ) + + string (REPLACE ";" " " ACC_Fortran_FLAGS_STR "${ACC_Fortran_FLAGS}") + + + set_source_files_properties( fctest_unified_memory_with_openacc.F90 PROPERTIES COMPILE_FLAGS ${ACC_Fortran_FLAGS_STR} ) + add_fctest( + TARGET atlas_test_unified_memory_with_openacc + SOURCES fctest_unified_memory_with_openacc.F90 + fctest_unified_memory_with_openacc_cxx.cc + LIBS atlas_f + LINKER_LANGUAGE Fortran + ) + target_link_libraries( atlas_test_unified_memory_with_openacc ${ACC_Fortran_FLAGS} ) + + + add_fctest( + TARGET atlas_test_connectivity_openacc + SOURCES fctest_connectivity_openacc.F90 + LIBS atlas_f + LINKER_LANGUAGE Fortran + ) + target_link_libraries( atlas_test_connectivity_openacc ${ACC_Fortran_FLAGS} ) + set_target_properties( atlas_test_connectivity_openacc PROPERTIES COMPILE_FLAGS "${ACC_Fortran_FLAGS_STR}" ) + +endif() \ No newline at end of file diff --git a/src/tests/acc/fctest_connectivity_openacc.F90 b/src/tests/acc/fctest_connectivity_openacc.F90 new file mode 100644 index 000000000..4cf726452 --- /dev/null +++ b/src/tests/acc/fctest_connectivity_openacc.F90 @@ -0,0 +1,335 @@ +! (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 Connectivity +! @author Willem Deconinck + +#include "fckit/fctest.h" + + +! ----------------------------------------------------------------------------- + +TESTSUITE(fctest_atlas_Connectivity) + +! ----------------------------------------------------------------------------- +TESTSUITE_INIT() + use fckit_module + call fckit_main%init() +END_TESTSUITE_INIT + +TEST( test_connectivity ) +#if 1 + use fckit_module + use atlas_connectivity_module + use atlas_kinds_module + use atlas_field_module + use, intrinsic :: iso_c_binding + + implicit none + type(atlas_Connectivity) :: connectivity + integer(ATLAS_KIND_IDX), pointer :: padded(:,:), row(:), data(:,:) + integer(ATLAS_KIND_IDX), pointer :: cols(:) + integer(c_int) :: ncols + type(atlas_Field) :: field + real(8), pointer :: values(:) + integer :: i, j + + call fckit_log%info("test_connectivity starting") + + connectivity = atlas_Connectivity("hybrid") + FCTEST_CHECK_EQUAL( connectivity%owners(), 1 ) + + FCTEST_CHECK_EQUAL(connectivity%name(),"hybrid") + + FCTEST_CHECK_EQUAL(connectivity%rows(),0) + FCTEST_CHECK_EQUAL(connectivity%missing_value(),0) + + call connectivity%add(2,4, & + & [ 1, 2, 3, 4, & + & 5, 6, 7, 8 ] ) + + FCTEST_CHECK_EQUAL(connectivity%mincols(),4) + FCTEST_CHECK_EQUAL(connectivity%maxcols(),4) + FCTEST_CHECK_EQUAL(connectivity%rows(), 2) + + call connectivity%data(data,ncols) + FCTEST_CHECK_EQUAL(ncols,4) + FCTEST_CHECK_EQUAL(data(1,1), 1) + FCTEST_CHECK_EQUAL(data(2,1), 2) + FCTEST_CHECK_EQUAL(data(3,1), 3) + FCTEST_CHECK_EQUAL(data(4,1), 4) + FCTEST_CHECK_EQUAL(data(1,2), 5) + FCTEST_CHECK_EQUAL(data(2,2), 6) + FCTEST_CHECK_EQUAL(data(3,2), 7) + FCTEST_CHECK_EQUAL(data(4,2), 8) + + field = atlas_Field(atlas_real(8),shape=[20]) + call field%data(values) + values(:) = 0. + call field%clone_to_device() + + +!$acc data present(values) +!$acc kernels + do i=1,2 + do j=1,4 + values(i) = values(i) + data(j,i) + end do + enddo +!$acc end kernels +!$acc end data + + call field%clone_from_device() + FCTEST_CHECK_EQUAL( values(1) , 10._8 ) + FCTEST_CHECK_EQUAL( values(2) , 26._8 ) + values(:) = 0. + call field%clone_to_device() + + + call connectivity%add(2,3, & + & [ 9, 10, 11, & + & 12, 13, 14 ] ) + + FCTEST_CHECK_EQUAL(connectivity%mincols(),3) + FCTEST_CHECK_EQUAL(connectivity%maxcols(),4) + FCTEST_CHECK_EQUAL(connectivity%rows(), 4) + + call connectivity%add(2,4) + call connectivity%add(2,3) + + !============= Functional access =============! + + FCTEST_CHECK_EQUAL(connectivity%value(1,1), 1) + FCTEST_CHECK_EQUAL(connectivity%value(2,1), 2) + FCTEST_CHECK_EQUAL(connectivity%value(3,1), 3) + FCTEST_CHECK_EQUAL(connectivity%value(4,1), 4) + FCTEST_CHECK_EQUAL(connectivity%value(1,2), 5) + FCTEST_CHECK_EQUAL(connectivity%value(2,2), 6) + FCTEST_CHECK_EQUAL(connectivity%value(3,2), 7) + FCTEST_CHECK_EQUAL(connectivity%value(4,2), 8) + + FCTEST_CHECK_EQUAL(connectivity%value(1,3), 9) + FCTEST_CHECK_EQUAL(connectivity%value(2,3), 10) + FCTEST_CHECK_EQUAL(connectivity%value(3,3), 11) + FCTEST_CHECK_EQUAL(connectivity%value(1,4), 12) + FCTEST_CHECK_EQUAL(connectivity%value(2,4), 13) + FCTEST_CHECK_EQUAL(connectivity%value(3,4), 14) + + + !============= Padded Data pointer access =============! + + call connectivity%data(data,ncols) + + + call connectivity%padded_data(padded,cols) + FCTEST_CHECK_EQUAL(padded(1,1), 1) + FCTEST_CHECK_EQUAL(padded(2,1), 2) + FCTEST_CHECK_EQUAL(padded(3,1), 3) + FCTEST_CHECK_EQUAL(padded(4,1), 4) + FCTEST_CHECK_EQUAL(padded(1,2), 5) + FCTEST_CHECK_EQUAL(padded(2,2), 6) + FCTEST_CHECK_EQUAL(padded(3,2), 7) + FCTEST_CHECK_EQUAL(padded(4,2), 8) + + FCTEST_CHECK_EQUAL(padded(1,3), 9) + FCTEST_CHECK_EQUAL(padded(2,3), 10) + FCTEST_CHECK_EQUAL(padded(3,3), 11) + FCTEST_CHECK_EQUAL(padded(1,4), 12) + FCTEST_CHECK_EQUAL(padded(2,4), 13) + FCTEST_CHECK_EQUAL(padded(3,4), 14) + +!$acc data present(values) +!$acc kernels + do i=1,4 + do j=1,cols(i) + values(i) = values(i) + padded(j,i) + end do + enddo +!$acc end kernels +!$acc end data + + call field%clone_from_device() + FCTEST_CHECK_EQUAL( values(1) , 10._8 ) + FCTEST_CHECK_EQUAL( values(2) , 26._8 ) + FCTEST_CHECK_EQUAL( values(3) , 30._8 ) + FCTEST_CHECK_EQUAL( values(4) , 39._8 ) + values(:) = 0. + call field%clone_to_device() + +#endif + call connectivity%final() +END_TEST + +! ----------------------------------------------------------------------------- + +TEST( test_multiblockconnectivity ) +#if 1 + use fckit_module + use atlas_connectivity_module + use atlas_kinds_module + use atlas_field_module + use, intrinsic :: iso_c_binding + + implicit none + type(atlas_MultiBlockConnectivity) :: multiblock + type(atlas_BlockConnectivity) :: block + integer(ATLAS_KIND_IDX), pointer :: data(:,:), padded(:,:) + integer(ATLAS_KIND_IDX), pointer :: cols(:) + + type(atlas_Field) :: field + real(8), pointer :: values(:) + integer :: i, j + + type(atlas_Connectivity) :: base + + call fckit_log%info("test_multiblockconnectivity starting") + + field = atlas_Field(atlas_real(8),shape=[20]) + call field%data(values) + values(:) = 0 + call field%clone_to_device() + + multiblock = atlas_MultiBlockConnectivity() + + FCTEST_CHECK_EQUAL( multiblock%owners(), 1 ) + FCTEST_CHECK_EQUAL(multiblock%name(),"") + FCTEST_CHECK_EQUAL(multiblock%rows(),0) + FCTEST_CHECK_EQUAL(multiblock%blocks(),0) + + call multiblock%add(2,4, & + & [ 1, 2, 3, 4, & + & 5, 6, 7, 8 ] ) + + FCTEST_CHECK_EQUAL(multiblock%mincols(),4) + FCTEST_CHECK_EQUAL(multiblock%maxcols(),4) + FCTEST_CHECK_EQUAL(multiblock%rows(), 2) + FCTEST_CHECK_EQUAL(multiblock%blocks(), 1) + + call multiblock%add(2,3, & + & [ 9, 10, 11, & + & 12, 13, 14 ] ) + + FCTEST_CHECK_EQUAL(multiblock%mincols(),3) + FCTEST_CHECK_EQUAL(multiblock%maxcols(),4) + FCTEST_CHECK_EQUAL(multiblock%blocks(), 2) + + block = multiblock%block(1_ATLAS_KIND_IDX) + !FCTEST_CHECK_EQUAL( block%owners(), 2 ) + + FCTEST_CHECK_EQUAL( block%rows(), 2 ) + FCTEST_CHECK_EQUAL( block%cols(), 4 ) + + call block%data(data) + FCTEST_CHECK_EQUAL(data(1,1), 1) + FCTEST_CHECK_EQUAL(data(2,1), 2) + FCTEST_CHECK_EQUAL(data(3,1), 3) + FCTEST_CHECK_EQUAL(data(4,1), 4) + FCTEST_CHECK_EQUAL(data(1,2), 5) + FCTEST_CHECK_EQUAL(data(2,2), 6) + FCTEST_CHECK_EQUAL(data(3,2), 7) + FCTEST_CHECK_EQUAL(data(4,2), 8) + +!$acc data present(values) +!$acc kernels + do i=1,2 + do j=1,4 + values(i) = values(i) + data(j,i) + end do + enddo +!$acc end kernels +!$acc end data + call field%clone_from_device() + FCTEST_CHECK_EQUAL( values(1) , 10._8 ) + FCTEST_CHECK_EQUAL( values(2) , 26._8 ) + values(:) = 0. + call field%clone_to_device() + + block = multiblock%block(2_ATLAS_KIND_IDX) + !FCTEST_CHECK_EQUAL( block%owners(), 2 ) + + FCTEST_CHECK_EQUAL( block%rows(), 2 ) + FCTEST_CHECK_EQUAL( block%cols(), 3 ) + + call block%data(data) + FCTEST_CHECK_EQUAL(data(1,1), 9) + FCTEST_CHECK_EQUAL(data(2,1), 10) + FCTEST_CHECK_EQUAL(data(3,1), 11) + FCTEST_CHECK_EQUAL(data(1,2), 12) + FCTEST_CHECK_EQUAL(data(2,2), 13) + FCTEST_CHECK_EQUAL(data(3,2), 14) + +!$acc data present(values) +!$acc kernels + do i=1,2 + do j=1,3 + values(i) = values(i) + data(j,i) + end do + enddo +!$acc end kernels +!$acc end data + + call field%clone_from_device() + FCTEST_CHECK_EQUAL( values(1) , 30._8 ) + FCTEST_CHECK_EQUAL( values(2) , 39._8 ) + values(:) = 0. + call field%clone_to_device() + + call block%final() + + FCTEST_CHECK_EQUAL( multiblock%owners(), 1 ) + base = multiblock + FCTEST_CHECK_EQUAL( base%owners(), 2 ) + FCTEST_CHECK_EQUAL( multiblock%owners(), 2 ) + + call base%padded_data(padded,cols) + FCTEST_CHECK_EQUAL(padded(1,1), 1) + FCTEST_CHECK_EQUAL(padded(2,1), 2) + FCTEST_CHECK_EQUAL(padded(3,1), 3) + FCTEST_CHECK_EQUAL(padded(4,1), 4) + FCTEST_CHECK_EQUAL(padded(1,2), 5) + FCTEST_CHECK_EQUAL(padded(2,2), 6) + FCTEST_CHECK_EQUAL(padded(3,2), 7) + FCTEST_CHECK_EQUAL(padded(4,2), 8) + + FCTEST_CHECK_EQUAL(padded(1,3), 9) + FCTEST_CHECK_EQUAL(padded(2,3), 10) + FCTEST_CHECK_EQUAL(padded(3,3), 11) + FCTEST_CHECK_EQUAL(padded(1,4), 12) + FCTEST_CHECK_EQUAL(padded(2,4), 13) + FCTEST_CHECK_EQUAL(padded(3,4), 14) + +!$acc data present(values) +!$acc kernels + do i=1,4 + do j=1,cols(i) + values(i) = values(i) + padded(j,i) + end do + enddo +!$acc end kernels +!$acc end data + + call field%clone_from_device() + FCTEST_CHECK_EQUAL( values(1) , 10._8 ) + FCTEST_CHECK_EQUAL( values(2) , 26._8 ) + FCTEST_CHECK_EQUAL( values(3) , 30._8 ) + FCTEST_CHECK_EQUAL( values(4) , 39._8 ) + values(:) = 0. + call field%clone_to_device() + + call multiblock%final() + + FCTEST_CHECK_EQUAL( base%owners(), 1 ) + + call base%final() +#endif +END_TEST + +! ----------------------------------------------------------------------------- + +END_TESTSUITE + diff --git a/src/tests/acc/fctest_unified_memory_with_openacc.F90 b/src/tests/acc/fctest_unified_memory_with_openacc.F90 new file mode 100644 index 000000000..7c13cfc03 --- /dev/null +++ b/src/tests/acc/fctest_unified_memory_with_openacc.F90 @@ -0,0 +1,91 @@ +! (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. + +! @author Willem Deconinck + +#include "fckit/fctest.h" + +! ----------------------------------------------------------------------------- + +module allocate_unified_module + +interface + + subroutine allocate_unified_impl( a, N ) bind(C,name="allocate_unified_impl") + use, intrinsic :: iso_c_binding + type(c_ptr) :: a + integer(c_int), value :: N + end subroutine + +end interface + +contains + + subroutine allocate_unified( a, N ) + use, intrinsic :: iso_c_binding + real(c_double), pointer :: a(:) + integer(c_int) :: N + type(c_ptr) :: value_cptr + call allocate_unified_impl(value_cptr, N) + call c_f_pointer(value_cptr,a,(/N/)) + end subroutine + +end module + +TESTSUITE(fctest_atlas_openacc_with_unified_memory) + +! ----------------------------------------------------------------------------- + +TESTSUITE_INIT +END_TESTSUITE_INIT + +! ----------------------------------------------------------------------------- + +TESTSUITE_FINALIZE +END_TESTSUITE_FINALIZE + +! ----------------------------------------------------------------------------- + +TEST( test_openacc_with_unified_memory ) + use, intrinsic :: iso_c_binding + use allocate_unified_module + implicit none + + real(c_double), pointer :: value(:) + integer :: i + integer :: N + N = 100 + + call allocate_unified(value, N) + + ! On host: + do i=1,N + value(i) = i + enddo + + ! On device (automatic copies on access because unified memory) +!$acc kernels + do i=1,N + value(i) = value(i) * 10 + enddo +!$acc end kernels + + ! On host: + do i=1,N + FCTEST_CHECK_CLOSE( value(i), real( 10*i, c_double), real( 0.0001, c_double ) ) + enddo +END_TEST + +! ----------------------------------------------------------------------------- +! +! NOTE: To be certain that cuda kernel is being generated and launched, run this +! test with "nvprof -s " +! +! ----------------------------------------------------------------------------- + +END_TESTSUITE + diff --git a/src/tests/acc/fctest_unified_memory_with_openacc_cxx.cc b/src/tests/acc/fctest_unified_memory_with_openacc_cxx.cc new file mode 100644 index 000000000..ace78d994 --- /dev/null +++ b/src/tests/acc/fctest_unified_memory_with_openacc_cxx.cc @@ -0,0 +1,17 @@ +/* + * (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 + +extern "C" { +void allocate_unified_impl( double** a, int N ) { + cudaMallocManaged( a, N * sizeof( double ) ); +} +} diff --git a/src/tests/acceptance_tests/CMakeLists.txt b/src/tests/acceptance_tests/CMakeLists.txt index 149843ed4..fa230989b 100644 --- a/src/tests/acceptance_tests/CMakeLists.txt +++ b/src/tests/acceptance_tests/CMakeLists.txt @@ -1,3 +1,11 @@ +# (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. + ecbuild_add_executable( TARGET atlas_atest_mgrids SOURCES atest_mgrids.cc LIBS atlas diff --git a/src/tests/array/test_array.cc b/src/tests/array/test_array.cc index 4b406762e..5c6e5b4ab 100644 --- a/src/tests/array/test_array.cc +++ b/src/tests/array/test_array.cc @@ -8,7 +8,7 @@ * nor does it submit to any jurisdiction. */ -#include "eckit/memory/SharedPtr.h" +#include #include "atlas/array.h" #include "atlas/array/MakeView.h" @@ -95,19 +95,19 @@ CASE( "test_localview" ) { EXPECT( hv.size() == 8ul * 4ul * 2ul ); // Initialize fields - for ( size_t i = 0; i < ds->shape( 0 ); ++i ) { - for ( size_t j = 0; j < ds->shape( 1 ); ++j ) { - for ( size_t k = 0; k < ds->shape( 2 ); ++k ) { + for ( idx_t i = 0; i < ds->shape( 0 ); ++i ) { + for ( idx_t j = 0; j < ds->shape( 1 ); ++j ) { + for ( idx_t k = 0; k < ds->shape( 2 ); ++k ) { hv( i, j, k ) = ( i * 100 ) + ( j * 10 ) + ( k ); } } } // Check values - for ( size_t i = 0; i < ds->shape( 0 ); ++i ) { + for ( idx_t i = 0; i < ds->shape( 0 ); ++i ) { LocalView lv = hv.slice( i, Range::all(), Range::all() ); - for ( size_t j = 0; j < lv.shape( 0 ); ++j ) { - for ( size_t k = 0; k < lv.shape( 1 ); ++k ) { + for ( idx_t j = 0; j < lv.shape( 0 ); ++j ) { + for ( idx_t k = 0; k < lv.shape( 1 ); ++k ) { EXPECT( lv( j, k ) == ( i * 100 ) + ( j * 10 ) + ( k ) ); } } @@ -205,8 +205,7 @@ CASE( "test_spec_layout_rev" ) { delete ds; - EXPECT_THROWS_AS( Array::create( make_shape( 4, 5, 6, 2 ), make_layout( 0, 1, 3, 2 ) ), - eckit::BadParameter ); + EXPECT_THROWS_AS( Array::create( make_shape( 4, 5, 6, 2 ), make_layout( 0, 1, 3, 2 ) ), eckit::Exception ); } #endif @@ -214,9 +213,9 @@ CASE( "test_resize_throw" ) { Array* ds = Array::create( 32, 5, 33 ); EXPECT_NO_THROW( ds->resize( 32, 5, 33 ) ); - EXPECT_THROWS_AS( ds->resize( 32, 4, 33 ), eckit::BadParameter ); - EXPECT_THROWS_AS( ds->resize( 32, 5, 32 ), eckit::BadParameter ); - EXPECT_THROWS_AS( ds->resize( 32, 5, 33, 4 ), eckit::BadParameter ); + EXPECT_NO_THROW( ds->resize( 32, 4, 33 ) ); + EXPECT_NO_THROW( ds->resize( 32, 5, 32 ) ); + EXPECT_THROWS_AS( ds->resize( 32, 5, 33, 4 ), eckit::Exception ); delete ds; } @@ -247,7 +246,7 @@ CASE( "test_copy_gt_ctr" ) { EXPECT( hv2( 2, 1 ) == 4 ); EXPECT( hv2( 1, 1 ) == 7 ); - auto dims = hv.data_view().storage_info().dims(); + auto dims = hv.data_view().storage_info().total_lengths(); ATLAS_DEBUG_VAR( dims[0] ); ATLAS_DEBUG_VAR( dims[1] ); EXPECT( dims[0] == 3 ); @@ -419,7 +418,7 @@ CASE( "test_insert" ) { CASE( "test_insert_throw" ) { Array* ds = Array::create( 7, 5, 8 ); - EXPECT_THROWS_AS( ds->insert( 8, 2 ), eckit::BadParameter ); + EXPECT_THROWS_AS( ds->insert( 8, 2 ), eckit::Exception ); } CASE( "test_wrap_storage" ) { @@ -544,13 +543,13 @@ CASE( "test_wrap" ) { EXPECT( arr_t.rank() == 2 ); array::ArrayView arrv_t = array::make_view( arr_t ); - for ( size_t i = 0; i < arrv_t.shape( 0 ); ++i ) { - for ( size_t j = 0; j < arrv_t.shape( 1 ); ++j ) { + for ( idx_t i = 0; i < arrv_t.shape( 0 ); ++i ) { + for ( idx_t j = 0; j < arrv_t.shape( 1 ); ++j ) { arrv_t( i, j ) = i * 10 + j - 1; } } - eckit::SharedPtr arr( array::Array::wrap( + std::unique_ptr arr( array::Array::wrap( arrv_t.data(), array::ArraySpec{array::make_shape( 3 ), array::make_strides( arr_t.stride( 0 ) )} ) ); EXPECT( arr->shape( 0 ) == 3 ); diff --git a/src/tests/array/test_array_slicer.cc b/src/tests/array/test_array_slicer.cc index 85e1a4e80..c4bfc3bd3 100644 --- a/src/tests/array/test_array_slicer.cc +++ b/src/tests/array/test_array_slicer.cc @@ -8,8 +8,6 @@ * nor does it submit to any jurisdiction. */ -#include "eckit/memory/SharedPtr.h" - #include "atlas/array.h" #include "atlas/array/MakeView.h" #include "atlas/array/helpers/ArraySlicer.h" @@ -222,6 +220,11 @@ CASE( "test_array_slicer_of_slice" ) { auto subslice2 = subslicer.apply( Range::all(), Range::all() ); auto subslice3 = subslicer.apply( Range::all(), 0 ); auto subslice4 = subslicer.apply( 0, Range::to( 2 ) ); + + EXPECT( is_approximately_equal( double( subslice1 ), 133. ) ); + EXPECT( subslice2.size() == slice.size() ); + EXPECT( subslice3.size() == slice.shape( 0 ) ); + EXPECT( subslice4.size() == 2 ); } CASE( "test_arrayview_slice_type" ) { diff --git a/src/tests/array/test_svector_kernel.cu b/src/tests/array/test_svector_kernel.cu index 200d1a46e..79631133b 100644 --- a/src/tests/array/test_svector_kernel.cu +++ b/src/tests/array/test_svector_kernel.cu @@ -8,6 +8,8 @@ * does it submit to any jurisdiction. */ +#include + #include "atlas/library/config.h" #include "tests/AtlasTestEnvironment.h" #include "atlas/array/SVector.h" @@ -46,7 +48,7 @@ CASE( "test_svector" ) cudaError_t err = cudaMallocManaged(&result, sizeof(bool)); if(err != cudaSuccess) - throw eckit::AssertionFailed("failed to allocate GPU memory"); + throw_AssertionFailed("failed to allocate GPU memory"); *result=true; kernel_exe<<<1,1>>>(list_ints.data(), list_ints.size(), 0, result); @@ -54,7 +56,7 @@ CASE( "test_svector" ) err = cudaGetLastError(); if(err != cudaSuccess) - throw eckit::AssertionFailed("failed to execute kernel"); + throw_AssertionFailed("failed to execute kernel"); EXPECT( *result ); EXPECT( list_ints[0] == 4); @@ -82,7 +84,7 @@ CASE( "test_svector_resize" ) cudaError_t err = cudaMallocManaged(&result, sizeof(bool)); if(err != cudaSuccess) - throw eckit::AssertionFailed("failed to allocate GPU memory"); + throw_AssertionFailed("failed to allocate GPU memory"); *result=true; @@ -94,7 +96,7 @@ CASE( "test_svector_resize" ) err = cudaGetLastError(); if(err != cudaSuccess) - throw eckit::AssertionFailed("failed to execute kernel"); + throw_AssertionFailed("failed to execute kernel"); EXPECT( *result ); EXPECT( list_ints[3] == 4); diff --git a/src/tests/field/CMakeLists.txt b/src/tests/field/CMakeLists.txt index 7853cbde5..2d0f53dcc 100644 --- a/src/tests/field/CMakeLists.txt +++ b/src/tests/field/CMakeLists.txt @@ -20,6 +20,14 @@ if( HAVE_FCTEST ) LIBS atlas_f ) + add_fctest( TARGET atlas_fctest_field_view + LINKER_LANGUAGE Fortran + SOURCES fctest_field_view.F90 + LIBS atlas_f + OMP 3 + CONDITION ATLAS_HAVE_OMP + ) + add_fctest( TARGET atlas_fctest_field_host CONDITION ATLAS_HAVE_GRIDTOOLS_STORAGE AND ATLAS_GRIDTOOLS_STORAGE_BACKEND_HOST LINKER_LANGUAGE Fortran diff --git a/src/tests/field/external_acc_routine.F90 b/src/tests/field/external_acc_routine.F90 index 12a8e2a6f..013686b0a 100644 --- a/src/tests/field/external_acc_routine.F90 +++ b/src/tests/field/external_acc_routine.F90 @@ -1,3 +1,11 @@ +! (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. + subroutine external_acc_routine(view) implicit none @@ -9,4 +17,4 @@ subroutine external_acc_routine(view) !$acc end kernels !$acc end data -end subroutine external_acc_routine \ No newline at end of file +end subroutine external_acc_routine diff --git a/src/tests/field/fctest_field.F90 b/src/tests/field/fctest_field.F90 index 79e7b6aee..b350d6900 100644 --- a/src/tests/field/fctest_field.F90 +++ b/src/tests/field/fctest_field.F90 @@ -152,7 +152,7 @@ module fcta_Field_fixture field = atlas_Field("field_2",atlas_integer(),(/2,10/)) call fieldset%add( field ) - FCTEST_CHECK_EQUAL( fieldset%size(), 3_c_size_t ) + FCTEST_CHECK_EQUAL( fieldset%size(), 3 ) field = fieldset%field(1) FCTEST_CHECK_EQUAL( field%name(), "field_0" ) diff --git a/src/tests/field/fctest_field_gpu.F90 b/src/tests/field/fctest_field_gpu.F90 index 52d6c5751..4c907fe89 100644 --- a/src/tests/field/fctest_field_gpu.F90 +++ b/src/tests/field/fctest_field_gpu.F90 @@ -69,7 +69,7 @@ subroutine external_acc_routine(view) end subroutine external_acc_routine end interface -field = atlas_Field(kind=atlas_real(8),shape=[5,3]) +field = atlas_Field(kind=atlas_real(4),shape=[5,3]) call field%data(view) view(:,:) = 0 diff --git a/src/tests/field/fctest_field_host.F90 b/src/tests/field/fctest_field_host.F90 index 4a79cfffe..eaa5f78b2 100644 --- a/src/tests/field/fctest_field_host.F90 +++ b/src/tests/field/fctest_field_host.F90 @@ -47,7 +47,7 @@ module fcta_Field_fxt field = atlas_Field(kind=atlas_real(8),shape=[10,5]) -call field%host_data(host) +call field%data(host) FCTEST_CHECK( .not. field%host_needs_update() ) FCTEST_CHECK( .not. field%device_needs_update() ) diff --git a/src/tests/field/fctest_field_view.F90 b/src/tests/field/fctest_field_view.F90 new file mode 100644 index 000000000..c70a932d4 --- /dev/null +++ b/src/tests/field/fctest_field_view.F90 @@ -0,0 +1,89 @@ +! (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" + +! ----------------------------------------------------------------------------- + +module fcta_Field_view_fixture +use atlas_module +use, intrinsic :: iso_c_binding +use, intrinsic :: iso_fortran_env +implicit none +end module + +! ----------------------------------------------------------------------------- + +TESTSUITE_WITH_FIXTURE(fctest_atlas_Field_view,fcta_Field_view_fixture) + +! ----------------------------------------------------------------------------- + +TESTSUITE_INIT + call atlas_library%initialise() +END_TESTSUITE_INIT + +! ----------------------------------------------------------------------------- + +TESTSUITE_FINALIZE + call atlas_library%finalise() +END_TESTSUITE_FINALIZE + +! ----------------------------------------------------------------------------- + +TEST( test_field_data_view) +use omp_lib + +implicit none + +integer, parameter :: lon = 20, lev = 16, blocks = 138 +type(atlas_Field) :: field +real(kind=REAL64), pointer :: global(:,:,:), local(:,:) +integer :: i, j, k, pid, num_threads + +field = atlas_Field(kind=atlas_real(kind=REAL64), shape=[lon, lev, blocks]) +FCTEST_CHECK_EQUAL( field%rank() , 3 ) +FCTEST_CHECK_EQUAL( field%shape(1) , lon ) +FCTEST_CHECK_EQUAL( field%shape(2) , lev ) +FCTEST_CHECK_EQUAL( field%shape(3) , blocks ) + +!$OMP PARALLEL PRIVATE(k, global, local) SHARED(field) +num_threads = omp_get_num_threads() + +!$OMP DO SCHEDULE(DYNAMIC,1) +do k=1, blocks + pid = omp_get_thread_num() + + call field%data(global) + local => global(:,:,k) + + local(:,:) = real(pid, REAL64) +end do +!$OMP END DO +!$OMP END PARALLEL + +call field%data(global) + +do k=1, blocks + do j=1, lev + do i=1, lon + FCTEST_CHECK( global(i,j,k) >= 0.0 ) + FCTEST_CHECK( global(i,j,k) <= REAL(num_threads, REAL64) ) + end do + end do +end do + +END_TEST + + +! ----------------------------------------------------------------------------- + +END_TESTSUITE + diff --git a/src/tests/functionspace/CMakeLists.txt b/src/tests/functionspace/CMakeLists.txt index 7c23ae5dd..eda39944c 100644 --- a/src/tests/functionspace/CMakeLists.txt +++ b/src/tests/functionspace/CMakeLists.txt @@ -8,6 +8,10 @@ if( HAVE_FCTEST ) + if( NOT HAVE_TRANS ) + set( TRANSI_HAVE_MPI 1 ) + endif() + add_fctest( TARGET atlas_fctest_functionspace MPI 4 CONDITION ECKIT_HAVE_MPI AND TRANSI_HAVE_MPI @@ -34,3 +38,32 @@ ecbuild_add_test( TARGET atlas_test_pointcloud SOURCES test_pointcloud.cc LIBS atlas ) + +ecbuild_add_test( TARGET atlas_test_reduced_halo + SOURCES test_reduced_halo.cc + LIBS atlas +) + +ecbuild_add_test( TARGET atlas_test_stencil + SOURCES test_stencil.cc + LIBS atlas +) + +ecbuild_add_executable( TARGET atlas_test_stencil_parallel + SOURCES test_stencil_parallel.cc + LIBS atlas + NOINSTALL +) + +ecbuild_add_test( TARGET atlas_test_stencil_parallel_mpi4 + COMMAND $ + MPI 4 + CONDITION ECKIT_HAVE_MPI +) + +ecbuild_add_test( TARGET atlas_test_stencil_parallel_mpi16 + COMMAND $ + MPI 16 + CONDITION ECKIT_HAVE_MPI +) + diff --git a/src/tests/functionspace/fctest_functionspace.F90 b/src/tests/functionspace/fctest_functionspace.F90 index 294c91627..015c061a1 100644 --- a/src/tests/functionspace/fctest_functionspace.F90 +++ b/src/tests/functionspace/fctest_functionspace.F90 @@ -380,15 +380,31 @@ module fcta_FunctionSpace_fxt type(atlas_Field) :: field, template type(atlas_mesh_Edges) :: edges integer :: halo_size, nb_edges +type( atlas_trace ) :: trace +type( atlas_trace ) :: trace_a +type( atlas_trace ) :: trace_b + +type( atlas_Output ) :: gmsh + +trace = atlas_Trace("fctest_functionspace.F90",__LINE__,"test_edges") halo_size = 0 grid = atlas_StructuredGrid("N24") meshgenerator = atlas_MeshGenerator() mesh = meshgenerator%generate(grid) + +gmsh = atlas_Output_gmsh("test_edges.msh") +call gmsh%write(mesh) +call gmsh%final() + FCTEST_CHECK_EQUAL( mesh%owners(), 1 ) edges = mesh%edges() FCTEST_CHECK_EQUAL( edges%owners(), 3 ) ! Mesh holds 2 references (facets == edges) + +trace_a = atlas_Trace("fctest_functionspace.F90",__LINE__,"EdgeColumns, no-levels") fs = atlas_functionspace_EdgeColumns(mesh) +call trace_a%final() + FCTEST_CHECK_EQUAL( mesh%owners(), 2 ) FCTEST_CHECK_EQUAL( edges%owners(), 3 ) edges = fs%edges() @@ -473,7 +489,9 @@ module fcta_FunctionSpace_fxt call field%final() call template%final() +trace_b = atlas_Trace("fctest_functionspace.F90",__LINE__,"EdgeColumns, 5 levels") fs = atlas_functionspace_EdgeColumns(mesh,levels=5) +call trace_b%final() field = fs%create_field(atlas_real(c_float)) FCTEST_CHECK_EQUAL( field%rank() , 2 ) FCTEST_CHECK_EQUAL( field%name() , "" ) @@ -485,6 +503,9 @@ module fcta_FunctionSpace_fxt call edges%final() call mesh%final() call grid%final() + +call trace%final() + #else #warning test test_edges disabled #endif @@ -496,7 +517,7 @@ module fcta_FunctionSpace_fxt type(atlas_functionspace_StructuredColumns) :: fs type(atlas_functionspace) :: fs_base type(atlas_functionspace_StructuredColumns) :: fs_struct -integer :: i, j +integer(ATLAS_KIND_IDX) :: i, j character(len=10) str type(atlas_Field) :: field diff --git a/src/tests/functionspace/test_functionspace.cc b/src/tests/functionspace/test_functionspace.cc index 96c1c80e6..3de411e31 100644 --- a/src/tests/functionspace/test_functionspace.cc +++ b/src/tests/functionspace/test_functionspace.cc @@ -14,13 +14,15 @@ #include "atlas/array/ArrayView.h" #include "atlas/array/MakeView.h" #include "atlas/field/Field.h" +#include "atlas/field/FieldSet.h" #include "atlas/functionspace/NodeColumns.h" #include "atlas/functionspace/Spectral.h" #include "atlas/grid/Grid.h" +#include "atlas/grid/StructuredGrid.h" #include "atlas/library/Library.h" #include "atlas/mesh/Mesh.h" #include "atlas/mesh/Nodes.h" -#include "atlas/meshgenerator/StructuredMeshGenerator.h" +#include "atlas/meshgenerator.h" #include "atlas/parallel/mpi/mpi.h" #include "atlas/trans/Trans.h" @@ -37,7 +39,7 @@ namespace test { CASE( "test_functionspace_NodeColumns_no_halo" ) { Grid grid( "O8" ); - Mesh mesh = meshgenerator::StructuredMeshGenerator().generate( grid ); + Mesh mesh = StructuredMeshGenerator().generate( grid ); functionspace::NodeColumns nodes_fs( mesh ); Field field( nodes_fs.createField() ); array::ArrayView value = array::make_view( field ); @@ -58,15 +60,15 @@ CASE( "test_functionspace_NodeColumns_no_halo" ) { CASE( "test_functionspace_NodeColumns" ) { // ScopedPtr grid( Grid::create("O2") ); - grid::ReducedGaussianGrid grid( {4, 8, 8, 4} ); + ReducedGaussianGrid grid( {4, 8, 8, 4} ); - meshgenerator::StructuredMeshGenerator generator; + StructuredMeshGenerator generator; // generator.options.set("3d",true); Mesh mesh = generator.generate( grid ); // grid.reset(); - size_t nb_levels = 10; + idx_t nb_levels = 10; functionspace::NodeColumns nodes_fs( mesh, option::halo( 1 ) | option::levels( nb_levels ) ); // NodesColumnFunctionSpace columns_fs("columns",mesh,nb_levels,Halo(1)); @@ -141,7 +143,7 @@ CASE( "test_functionspace_NodeColumns" ) { Field field = nodes_fs.createField( option::name( "partition" ) ); array::ArrayView arr = array::make_view( field ); - arr.assign( mpi::comm().rank() ); + arr.assign( int( mpi::comm().rank() ) ); // field->dump( Log::info() ); nodes_fs.haloExchange( field ); // field->dump( Log::info() ); @@ -149,7 +151,7 @@ CASE( "test_functionspace_NodeColumns" ) { Field field2 = nodes_fs.createField( option::name( "partition2" ) | option::variables( 2 ) ); Log::info() << "field2.rank() = " << field2.rank() << std::endl; array::ArrayView arr2 = array::make_view( field2 ); - arr2.assign( mpi::comm().rank() ); + arr2.assign( int( mpi::comm().rank() ) ); // field2->dump( Log::info() ); nodes_fs.haloExchange( field2 ); @@ -175,7 +177,7 @@ CASE( "test_functionspace_NodeColumns" ) { Log::info() << "glb_field.shape(0) = " << glb_field.shape( 0 ) << std::endl; EXPECT( glb_field.metadata().get( "global" ) == true ); - EXPECT( glb_field.metadata().get( "owner" ) == root ); + EXPECT( glb_field.metadata().get( "owner" ) == int( root ) ); // glb_field->dump( Log::info() ); @@ -204,7 +206,7 @@ CASE( "test_functionspace_NodeColumns" ) { double sum; double mean; double stddev; - size_t N; + idx_t N; gidx_t gidx_max; gidx_t gidx_min; @@ -259,7 +261,7 @@ CASE( "test_functionspace_NodeColumns" ) { std::vector sum; std::vector mean; std::vector stddev; - size_t N; + idx_t N; std::vector gidx_max; std::vector gidx_min; @@ -311,10 +313,10 @@ CASE( "test_functionspace_NodeColumns" ) { double sum; double mean; double stddev; - size_t N; + idx_t N; gidx_t gidx_max; gidx_t gidx_min; - size_t level; + idx_t level; EXPECT( field.levels() == nb_levels ); @@ -386,16 +388,16 @@ CASE( "test_functionspace_NodeColumns" ) { if ( 1 ) { const Field& field = columns_vector_field; const functionspace::NodeColumns fs = nodes_fs; - size_t nvar = field.variables(); + idx_t nvar = field.variables(); std::vector max; std::vector min; std::vector sum; std::vector mean; std::vector stddev; - size_t N; + idx_t N; std::vector gidx_max; std::vector gidx_min; - std::vector levels; + std::vector levels; array::ArrayView vec_arr = array::make_view( field ); vec_arr.assign( mpi::comm().rank() + 1 ); @@ -467,9 +469,9 @@ CASE( "test_functionspace_NodeColumns" ) { } CASE( "test_SpectralFunctionSpace" ) { - size_t truncation = 159; - size_t nb_levels = 10; - size_t nspec2g = ( truncation + 1 ) * ( truncation + 2 ); + idx_t truncation = 159; + idx_t nb_levels = 10; + idx_t nspec2g = ( truncation + 1 ) * ( truncation + 2 ); Spectral spectral_fs( truncation ); @@ -504,10 +506,10 @@ CASE( "test_SpectralFunctionSpace" ) { CASE( "test_SpectralFunctionSpace_trans_dist" ) { trans::Trans trans( Grid( "F80" ), 159 ); - size_t nb_levels( 10 ); + idx_t nb_levels( 10 ); Spectral spectral_fs( trans ); - size_t nspec2 = spectral_fs.nb_spectral_coefficients(); + idx_t nspec2 = spectral_fs.nb_spectral_coefficients(); Field surface_scalar_field = spectral_fs.createField( option::name( "scalar" ) ); @@ -543,11 +545,11 @@ CASE( "test_SpectralFunctionSpace_trans_dist" ) { // == eckit::testing::make_view(columns_scalar_shape,columns_scalar_shape+2)); } CASE( "test_SpectralFunctionSpace_trans_global" ) { - size_t nb_levels( 10 ); - size_t truncation = 159; + idx_t nb_levels( 10 ); + idx_t truncation = 159; Spectral spectral_fs( truncation, option::levels( nb_levels ) ); - size_t nspec2g = spectral_fs.nb_spectral_coefficients_global(); + idx_t nspec2g = spectral_fs.nb_spectral_coefficients_global(); Field surface_scalar_field = spectral_fs.createField( option::name( "scalar" ) | option::levels( false ) | option::global() ); diff --git a/src/tests/functionspace/test_reduced_halo.cc b/src/tests/functionspace/test_reduced_halo.cc new file mode 100644 index 000000000..5b2652186 --- /dev/null +++ b/src/tests/functionspace/test_reduced_halo.cc @@ -0,0 +1,93 @@ +/* + * (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 +#include +#include +#include "atlas/functionspace/EdgeColumns.h" +#include "atlas/functionspace/NodeColumns.h" +#include "atlas/grid/StructuredGrid.h" +#include "atlas/mesh/HybridElements.h" +#include "atlas/mesh/Mesh.h" +#include "atlas/mesh/Nodes.h" +#include "atlas/meshgenerator.h" +#include "atlas/parallel/mpi/mpi.h" +#include "tests/AtlasTestEnvironment.h" + +using namespace atlas::functionspace; +using namespace atlas::grid; +using namespace atlas::meshgenerator; + +namespace atlas { +namespace test { + +template +Container reversed( const Container& a ) { + Container a_reversed = a; + std::reverse( a_reversed.begin(), a_reversed.end() ); + return a_reversed; +} + +static std::array false_true{false, true}; + +//----------------------------------------------------------------------------- + +CASE( "halo nodes" ) { + Grid grid( "O8" ); + std::vector halos{0, 1, 2, 3, 4}; + std::vector nodes{560, 592, 624, 656, 688}; + + for ( bool reduce : false_true ) { + SECTION( std::string( reduce ? "reduced" : "increased" ) ) { + Mesh mesh = StructuredMeshGenerator().generate( grid ); + EXPECT( mesh.nodes().size() == nodes[0] ); + + for ( int h : ( reduce ? reversed( halos ) : halos ) ) { + NodeColumns fs( mesh, option::halo( h ) ); + if ( mpi::comm().size() == 1 ) { EXPECT( fs.nb_nodes() == nodes[h] ); } + } + } + } +} + +//----------------------------------------------------------------------------- + +CASE( "halo edges" ) { + Grid grid( "O8" ); + std::vector halos{0, 1, 2, 3, 4}; + std::vector edges{1559, 1649, 1739, 1829, 1919}; + + for ( bool reduce : false_true ) { + for ( bool with_pole_edges : false_true ) { + int pole_edges = with_pole_edges ? StructuredGrid( grid ).nx().front() : 0; + + SECTION( std::string( reduce ? "reduced " : "increased " ) + + std::string( with_pole_edges ? "with_pole_edges" : "without_pole_edges" ) ) { + Mesh mesh = StructuredMeshGenerator().generate( grid ); + EXPECT( mesh.edges().size() == 0 ); + + for ( int h : ( reduce ? reversed( halos ) : halos ) ) { + EdgeColumns fs( mesh, option::halo( h ) | option::pole_edges( with_pole_edges ) ); + if ( mpi::comm().size() == 1 ) { EXPECT( fs.nb_edges() == edges[h] + pole_edges ); } + } + } + } + } +} + +//----------------------------------------------------------------------------- + +} // namespace test +} // namespace atlas + +int main( int argc, char** argv ) { + return atlas::test::run( argc, argv ); +} diff --git a/src/tests/functionspace/test_stencil.cc b/src/tests/functionspace/test_stencil.cc new file mode 100644 index 000000000..1baa55ecf --- /dev/null +++ b/src/tests/functionspace/test_stencil.cc @@ -0,0 +1,274 @@ +/* + * (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 "eckit/linalg/LinearAlgebra.h" +#include "eckit/linalg/Vector.h" +#include "eckit/memory/ScopedPtr.h" +#include "eckit/types/Types.h" + +#include "atlas/array.h" +#include "atlas/array/ArrayView.h" +#include "atlas/array/MakeView.h" +#include "atlas/field/Field.h" +#include "atlas/functionspace/NodeColumns.h" +#include "atlas/functionspace/PointCloud.h" +#include "atlas/functionspace/StructuredColumns.h" +#include "atlas/grid/Partitioner.h" +#include "atlas/grid/Stencil.h" +#include "atlas/grid/StencilComputer.h" +#include "atlas/grid/StructuredGrid.h" +#include "atlas/library/Library.h" +#include "atlas/mesh/Mesh.h" +#include "atlas/meshgenerator.h" +#include "atlas/output/Gmsh.h" +#include "atlas/parallel/mpi/mpi.h" +#include "atlas/util/CoordinateEnums.h" +#include "atlas/util/MicroDeg.h" + +#include "tests/AtlasTestEnvironment.h" + +using namespace eckit; +using namespace atlas::functionspace; +using namespace atlas::util; + + +namespace atlas { +namespace test { + +//----------------------------------------------------------------------------- + +std::vector IFS_vertical_coordinates( idx_t nlev ) { + std::vector zcoord( nlev ); + double dzcoord = 1. / double( nlev ); + for ( idx_t jlev = 0; jlev < nlev; ++jlev ) { + zcoord[jlev] = 0.5 * dzcoord + jlev * dzcoord; + } + return zcoord; +} + +std::vector zrange( idx_t nlev, double min, double max ) { + std::vector zcoord( nlev ); + double dzcoord = ( max - min ) / double( nlev - 1 ); + for ( idx_t jlev = 0; jlev < nlev; ++jlev ) { + zcoord[jlev] = min + jlev * dzcoord; + } + return zcoord; +} + +double cubic( double x, double min, double max ) { + double x0 = min; + double x1 = 0.5 * ( max + min ); + double x2 = max; + double xmax = 0.5 * ( x0 + x1 ); + return ( x - x0 ) * ( x - x1 ) * ( x - x2 ) / ( ( xmax - x0 ) * ( xmax - x1 ) * ( xmax - x2 ) ); +} + + +CASE( "test finding of North-West grid point" ) { + std::string gridname = eckit::Resource( "--grid", "O8" ); + + StructuredGrid grid( gridname ); + + constexpr double tol = 0.5e-6; + + constexpr idx_t halo = 2; + + ComputeNorth compute_j_north( grid, halo ); + ComputeWest compute_i_west( grid, halo ); + + struct IJ { + idx_t i; + idx_t j; + }; + idx_t ny = grid.ny(); + + if ( mpi::comm().size() == 1 ) { + auto entries = { + std::make_tuple( PointXY{0. + 0.5 * tol, grid.y( 0 ) + 0.5 * tol}, IJ{0, 0} ), + std::make_tuple( PointXY{0. - 0.5 * tol, grid.y( 0 ) - 0.5 * tol}, IJ{0, 0} ), + std::make_tuple( PointXY{0. + 2.0 * tol, grid.y( 0 ) + 2.0 * tol}, IJ{0, -1} ), + std::make_tuple( PointXY{0. - 2.0 * tol, grid.y( 0 ) - 2.0 * tol}, IJ{-1, 0} ), + std::make_tuple( PointXY{360. + 0.5 * tol, grid.y( ny - 1 ) + 0.5 * tol}, IJ{grid.nx( ny - 1 ), ny - 1} ), + std::make_tuple( PointXY{360. - 0.5 * tol, grid.y( ny - 1 ) - 0.5 * tol}, IJ{grid.nx( ny - 1 ), ny - 1} ), + std::make_tuple( PointXY{360. + 2.0 * tol, grid.y( ny - 1 ) + 2.0 * tol}, IJ{grid.nx( ny - 2 ), ny - 2} ), + std::make_tuple( PointXY{360. - 2.0 * tol, grid.y( ny - 1 ) - 2.0 * tol}, + IJ{grid.nx( ny - 1 ) - 1, ny - 1} ), + }; + for ( auto entry : entries ) { + auto p = std::get<0>( entry ); + auto index = std::get<1>( entry ); + EXPECT( compute_j_north( p.y() ) == index.j ); + EXPECT( compute_i_west( p.x(), index.j ) == index.i ); + } + } +} + +CASE( "test horizontal stencil" ) { + //if ( mpi::comm().size() == 1 ) { + std::string gridname = eckit::Resource( "--grid", "O8" ); + + StructuredGrid grid( gridname ); + int halo = eckit::Resource( "--halo", 2 ); + util::Config config; + config.set( "halo", halo ); + config.set( "levels", 9 ); + config.set( "periodic_points", true ); + functionspace::StructuredColumns fs( grid, grid::Partitioner( "equal_regions" ), config ); + + HorizontalStencil<4> stencil; + + ComputeHorizontalStencil compute_stencil( grid, stencil.width() ); + + auto departure_points = { + PointXY( 0., 90. ), + PointXY( 0., -90. ), + PointXY( 0., 0. ), + PointXY( 360., 0. ), + }; + for ( auto p : departure_points ) { + Log::info() << p << std::endl; + compute_stencil( p.x(), p.y(), stencil ); + for ( idx_t j = 0; j < stencil.width(); ++j ) { + Log::info() << stencil.i( 0, j ) << " " << stencil.j( j ) << " -- " + << "x,y = " << fs.compute_xy( stencil.i( 0, j ), stencil.j( j ) ) << std::endl; + } + Log::info() << std::endl; + } +} + +CASE( "test horizontal stencil linear" ) { + //if ( mpi::comm().size() == 1 ) { + std::string gridname = eckit::Resource( "--grid", "O8" ); + + StructuredGrid grid( gridname ); + //int halo = eckit::Resource( "--halo", 2 ); + util::Config config; + config.set( "levels", 9 ); + config.set( "periodic_points", true ); + functionspace::StructuredColumns fs( grid, grid::Partitioner( "equal_regions" ), config ); + + HorizontalStencil<2> stencil; + + ComputeHorizontalStencil compute_stencil( grid, stencil.width() ); + + auto departure_points = { + PointXY( 0., 90. ), PointXY( 0., -90. ), PointXY( 0., 0. ), PointXY( 360., 0. ), PointXY( 359.9, 0. ), + }; + for ( auto p : departure_points ) { + Log::info() << p << std::endl; + compute_stencil( p.x(), p.y(), stencil ); + for ( idx_t j = 0; j < stencil.width(); ++j ) { + for ( idx_t i = 0; i < stencil.width(); ++i ) { + Log::info() << stencil.i( i, j ) << " " << stencil.j( j ) << " -- " + << "x,y = " << fs.compute_xy( stencil.i( i, j ), stencil.j( j ) ) << std::endl; + } + Log::info() << std::endl; + } + } +} + + +//----------------------------------------------------------------------------- + +CASE( "test vertical stencil" ) { + SECTION( "Initialize ComputeLower from raw data (as e.g. given from IFS)" ) { + double z[] = {0.1, 0.3, 0.5, 0.7, 0.9}; + EXPECT_NO_THROW( + ComputeLower{Vertical( 5, array::make_view( z, 5 ), std::vector{0., 1.} )} ); + } + + + idx_t nlev = 10; + auto zcoord = IFS_vertical_coordinates( nlev ); + double dzcoord = 1. / double( nlev ); + + auto vertical = Vertical( nlev, zcoord, std::vector{0., 1.} ); + + SECTION( "Test compute_lower works as expected " ) { + ComputeLower compute_lower( vertical ); + + const double eps = 1.e-14; + + for ( idx_t k = 0; k < nlev; ++k ) { + idx_t k_expected = std::max( 0, std::min( nlev - 1, k ) ); + EXPECT( compute_lower( zcoord[k] ) == k_expected ); + EXPECT( compute_lower( zcoord[k] - eps ) == k_expected ); + EXPECT( compute_lower( zcoord[k] + eps ) == k_expected ); + EXPECT( compute_lower( zcoord[k] + 0.5 * dzcoord ) == k_expected ); + } + } + + SECTION( "Compute vertical stencil" ) { + ComputeVerticalStencil compute_vertical_stencil( vertical, 4 ); + std::vector departure_points{0.0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0}; + for ( auto p : departure_points ) { + VerticalStencil<4> stencil; + compute_vertical_stencil( p, stencil ); + Log::info() << p << " : "; + for ( idx_t k = 0; k < stencil.width(); ++k ) { + Log::info() << stencil.k( k ) << "[" << vertical[stencil.k( k )] << "] "; + } + Log::info() << " interval = " << stencil.k_interval() << std::endl; + if ( p < vertical[0] ) { EXPECT( stencil.k_interval() == -1 ); } + else if ( p < vertical[1] ) { + EXPECT( stencil.k_interval() == 0 ); + } + else if ( p > vertical[nlev - 1] ) { + EXPECT( stencil.k_interval() == 3 ); + } + else if ( p > vertical[nlev - 2] ) { + EXPECT( stencil.k_interval() == 2 ); + } + else { + EXPECT( stencil.k_interval() == 1 ); + } + } + } +} + + //----------------------------------------------------------------------------- + +#if 1 +CASE( "ifs method to find nearest grid point" ) { + // see satrad/module/gaussgrid.F90 + std::string gridname = eckit::Resource( "--grid", "O8" ); + StructuredGrid grid( gridname ); + + auto p = PointXY{0., grid.y( 0 )}; + idx_t kgrib_lat, kgrib_lon; + { + double x = p.x(); + double y = p.y(); + std::vector pdlat( grid.ny() ); + for ( idx_t j = 0; j < grid.ny(); ++j ) { + pdlat[j] = std::abs( y - grid.y( j ) ); + } + + auto iterator = std::min_element( pdlat.begin(), pdlat.end() ); + kgrib_lat = static_cast( iterator - pdlat.begin() ); + + double zfirstlon = grid.x( 0, kgrib_lat ); + double zdlon = grid.x( 1, kgrib_lat ) - zfirstlon; + double zsafelon = std::fmod( x - zfirstlon + 720., 360. ); + kgrib_lon = static_cast( std::fmod( std::round( zsafelon / zdlon ), grid.nx( kgrib_lat ) ) ); + } + EXPECT( kgrib_lon == 0 ); + EXPECT( kgrib_lat == 0 ); +} +#endif +//----------------------------------------------------------------------------- + +} // namespace test +} // namespace atlas + +int main( int argc, char** argv ) { + return atlas::test::run( argc, argv ); +} diff --git a/src/tests/functionspace/test_stencil_parallel.cc b/src/tests/functionspace/test_stencil_parallel.cc new file mode 100644 index 000000000..0c6c9da26 --- /dev/null +++ b/src/tests/functionspace/test_stencil_parallel.cc @@ -0,0 +1,101 @@ +/* + * (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/array.h" +#include "atlas/functionspace/StructuredColumns.h" +#include "atlas/grid/Partitioner.h" +#include "atlas/grid/Stencil.h" +#include "atlas/grid/StencilComputer.h" +#include "atlas/grid/StructuredGrid.h" +#include "atlas/library/Library.h" +#include "atlas/parallel/mpi/mpi.h" + +#include "tests/AtlasTestEnvironment.h" + +using namespace atlas::functionspace; +using namespace atlas::util; +using namespace atlas::grid; + + +namespace atlas { +namespace test { + +//----------------------------------------------------------------------------- + +CASE( "test horizontal stencil" ) { + std::string gridname = eckit::Resource( "--grid", "O16" ); + + StructuredGrid grid( gridname ); + int halo = eckit::Resource( "--halo", 2 ); + Config config; + config.set( "halo", halo ); + config.set( "periodic_points", true ); + StructuredColumns fs( grid, Partitioner( "equal_regions" ), config ); + + auto gidx = array::make_view( fs.global_index() ); + + HorizontalStencil<4> stencil; + + ComputeHorizontalStencil compute_stencil( grid, stencil.width() ); + + auto test = [&]( std::vector& points ) { + for ( auto p : points ) { + std::cout << p << std::endl; + compute_stencil( p.x(), p.y(), stencil ); + for ( idx_t j = 0; j < stencil.width(); ++j ) { + std::cout << gidx( fs.index( stencil.i( 0, j ), stencil.j( j ) ) ) << std::endl; + for ( idx_t i = 0; i < stencil.width(); ++i ) { + std::cout << stencil.i( i, j ) << ", " << stencil.j( j ); + std::cout << " -- " + << "x,y = " << fs.compute_xy( stencil.i( i, j ), stencil.j( j ) ) << std::endl; + EXPECT( stencil.j( j ) >= fs.j_begin_halo() ); + EXPECT( stencil.j( j ) < fs.j_end_halo() ); + EXPECT( stencil.i( i, j ) >= fs.i_begin_halo( stencil.j( j ) ) ); + EXPECT( stencil.i( i, j ) < fs.i_end_halo( stencil.j( j ) ) ); + } + } + std::cout << std::endl; + } + }; + + std::vector departure_points; + + if ( mpi::comm().size() == 4 ) { + SECTION( "mpi-size = 4, mpi-rank = 2 " ) { + if ( mpi::comm().rank() == 2 ) { + departure_points = { + PointXY( 236.25, -30.9375 ), + }; + test( departure_points ); + } + } + } + + if ( mpi::comm().size() == 16 ) { + SECTION( "ATLAS-186 workaround" ) { + if ( mpi::comm().rank() == 12 ) { + // ATLAS-186: point that is found using matching-mesh domain decomposition, which does not really match the halo of StructuredColumns + departure_points = { + PointXY( 205.3125, -67.5 ), + }; + test( departure_points ); + } + } + } +} + +//----------------------------------------------------------------------------- + +} // namespace test +} // namespace atlas + +int main( int argc, char** argv ) { + return atlas::test::run( argc, argv ); +} diff --git a/src/tests/functionspace/test_structuredcolumns.cc b/src/tests/functionspace/test_structuredcolumns.cc index aa8eaeaa7..79f7b5ca3 100644 --- a/src/tests/functionspace/test_structuredcolumns.cc +++ b/src/tests/functionspace/test_structuredcolumns.cc @@ -8,6 +8,7 @@ * nor does it submit to any jurisdiction. */ +#include "eckit/log/Bytes.h" #include "eckit/memory/ScopedPtr.h" #include "eckit/types/Types.h" @@ -16,10 +17,11 @@ #include "atlas/field/Field.h" #include "atlas/functionspace/NodeColumns.h" #include "atlas/functionspace/StructuredColumns.h" -#include "atlas/grid/Grid.h" +#include "atlas/grid/Partitioner.h" +#include "atlas/grid/StructuredGrid.h" #include "atlas/library/Library.h" #include "atlas/mesh/Mesh.h" -#include "atlas/meshgenerator/MeshGenerator.h" +#include "atlas/meshgenerator.h" #include "atlas/output/Gmsh.h" #include "atlas/parallel/mpi/mpi.h" #include "atlas/util/CoordinateEnums.h" @@ -37,11 +39,15 @@ namespace test { //----------------------------------------------------------------------------- CASE( "test_functionspace_StructuredColumns_no_halo" ) { - int root = 0; - Grid grid( "O8" ); + size_t root = 0; + std::string gridname = eckit::Resource( "--grid", "O8" ); + Grid grid( gridname ); util::Config config; config.set( "halo", 0 ); + config.set( "periodic_points", true ); functionspace::StructuredColumns fs( grid, grid::Partitioner( "equal_regions" ), config ); + ATLAS_DEBUG_VAR( fs.size() ); + ATLAS_DEBUG_VAR( eckit::Bytes( fs.footprint() ) ); Field field = fs.createField( option::name( "field" ) ); Field field_glb = fs.createField( option::name( "field_global" ) | option::global( root ) ); @@ -78,19 +84,20 @@ CASE( "test_functionspace_StructuredColumns_no_halo" ) { 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4}; - EXPECT( value_glb.size() == check.size() ); - for ( size_t j = 0; j < value_glb.size(); ++j ) { + EXPECT( value_glb.size() == idx_t( check.size() ) ); + for ( idx_t j = 0; j < value_glb.size(); ++j ) { EXPECT( value_glb( j ) == check[j] ); } } + ATLAS_TRACE_SCOPE( "output gmsh" ) { + output::Gmsh gmsh( "structured.msh" ); - output::Gmsh gmsh( "structured.msh" ); - - gmsh.write( MeshGenerator( "structured" ).generate( grid ) ); - gmsh.write( field ); + gmsh.write( MeshGenerator( "structured" ).generate( grid ) ); + gmsh.write( field ); + } } -CASE( "test_functionspace_StructuredColumns_halo" ) { +CASE( "test_functionspace_StructuredColumns_halo with output" ) { ATLAS_DEBUG_VAR( mpi::comm().size() ); // grid::StructuredGrid grid( // grid::StructuredGrid::XSpace( {0.,360.} , {2,4,6,6,4,2} , false ), @@ -100,11 +107,12 @@ CASE( "test_functionspace_StructuredColumns_halo" ) { std::string gridname = eckit::Resource( "--grid", "O8" ); - grid::StructuredGrid grid( gridname ); + StructuredGrid grid( gridname ); int halo = eckit::Resource( "--halo", 2 ); util::Config config; config.set( "halo", halo ); + config.set( "periodic_points", true ); functionspace::StructuredColumns fs( grid, grid::Partitioner( "equal_regions" ), config ); Field field = fs.createField( option::name( "field" ) ); @@ -128,127 +136,168 @@ CASE( "test_functionspace_StructuredColumns_halo" ) { // EXPECT( fs.checksum(field) == "cef2694016492d408fa157b7c59ce741" ); - eckit::PathName filepath( "test_functionspace_StructuredColumns_halo_p" + std::to_string( mpi::comm().rank() ) + - ".py" ); - - std::ofstream f( filepath.asString().c_str(), std::ios::trunc ); - - f << "\n" - "import matplotlib.pyplot as plt" - "\n" - "from matplotlib.path import Path" - "\n" - "import matplotlib.patches as patches" - "\n" - "" - "\n" - "from itertools import cycle" - "\n" - "import matplotlib.cm as cm" - "\n" - "import numpy as np" - "\n" - "" - "\n" - "fig = plt.figure(figsize=(20,10))" - "\n" - "ax = fig.add_subplot(111,aspect='equal')" - "\n" - ""; - - double xmin = std::numeric_limits::max(); - double xmax = -std::numeric_limits::max(); - double ymin = std::numeric_limits::max(); - double ymax = -std::numeric_limits::max(); - f << "\n" - "x = ["; - for ( idx_t j = fs.j_begin_halo(); j < fs.j_end_halo(); ++j ) { - for ( idx_t i = fs.i_begin_halo( j ); i < fs.i_end_halo( j ); ++i ) { - idx_t n = fs.index( i, j ); - f << xy( n, XX ) << ", "; - xmin = std::min( xmin, xy( n, XX ) ); - xmax = std::max( xmax, xy( n, XX ) ); + ATLAS_TRACE_SCOPE( "Output python" ) { + eckit::PathName filepath( "test_functionspace_StructuredColumns_halo_p" + std::to_string( mpi::comm().rank() ) + + ".py" ); + + std::ofstream f( filepath.asString().c_str(), std::ios::trunc ); + + f << "\n" + "import matplotlib.pyplot as plt" + "\n" + "from matplotlib.path import Path" + "\n" + "import matplotlib.patches as patches" + "\n" + "" + "\n" + "from itertools import cycle" + "\n" + "import matplotlib.cm as cm" + "\n" + "import numpy as np" + "\n" + "" + "\n" + "fig = plt.figure(figsize=(20,10))" + "\n" + "ax = fig.add_subplot(111,aspect='equal')" + "\n" + ""; + + double xmin = std::numeric_limits::max(); + double xmax = -std::numeric_limits::max(); + double ymin = std::numeric_limits::max(); + double ymax = -std::numeric_limits::max(); + f << "\n" + "x = ["; + for ( idx_t j = fs.j_begin_halo(); j < fs.j_end_halo(); ++j ) { + for ( idx_t i = fs.i_begin_halo( j ); i < fs.i_end_halo( j ); ++i ) { + idx_t n = fs.index( i, j ); + f << xy( n, XX ) << ", "; + xmin = std::min( xmin, xy( n, XX ) ); + xmax = std::max( xmax, xy( n, XX ) ); + } } - } - f << "]"; - - f << "\n" - "y = ["; - for ( idx_t j = fs.j_begin_halo(); j < fs.j_end_halo(); ++j ) { - for ( idx_t i = fs.i_begin_halo( j ); i < fs.i_end_halo( j ); ++i ) { - idx_t n = fs.index( i, j ); - f << xy( n, YY ) << ", "; - ymin = std::min( ymin, xy( n, YY ) ); - ymax = std::max( ymax, xy( n, YY ) ); + f << "]"; + + f << "\n" + "y = ["; + for ( idx_t j = fs.j_begin_halo(); j < fs.j_end_halo(); ++j ) { + for ( idx_t i = fs.i_begin_halo( j ); i < fs.i_end_halo( j ); ++i ) { + idx_t n = fs.index( i, j ); + f << xy( n, YY ) << ", "; + ymin = std::min( ymin, xy( n, YY ) ); + ymax = std::max( ymax, xy( n, YY ) ); + } } - } - f << "]"; - - f << "\n" - "g = ["; - for ( idx_t j = fs.j_begin_halo(); j < fs.j_end_halo(); ++j ) { - for ( idx_t i = fs.i_begin_halo( j ); i < fs.i_end_halo( j ); ++i ) { - idx_t n = fs.index( i, j ); - f << g( n ) << ", "; + f << "]"; + + f << "\n" + "g = ["; + for ( idx_t j = fs.j_begin_halo(); j < fs.j_end_halo(); ++j ) { + for ( idx_t i = fs.i_begin_halo( j ); i < fs.i_end_halo( j ); ++i ) { + idx_t n = fs.index( i, j ); + f << g( n ) << ", "; + } + } + f << "]"; + + f << "\n" + "p = ["; + for ( idx_t j = fs.j_begin_halo(); j < fs.j_end_halo(); ++j ) { + for ( idx_t i = fs.i_begin_halo( j ); i < fs.i_end_halo( j ); ++i ) { + idx_t n = fs.index( i, j ); + f << p( n ) << ", "; + } + } + f << "]"; + + f << "\n" + "r = ["; + for ( idx_t j = fs.j_begin_halo(); j < fs.j_end_halo(); ++j ) { + for ( idx_t i = fs.i_begin_halo( j ); i < fs.i_end_halo( j ); ++i ) { + idx_t n = fs.index( i, j ); + f << r( n ) << ", "; + } } + f << "]"; + + f << "\n" + "" + "\n" + "c = [ cm.Paired( float(pp%13)/12. ) for pp in p ]" + "\n" + "ax.scatter(x, y, color=c, marker='o')" + "\n" + "for i in range(" + << fs.size() + << "):" + "\n" + " ax.annotate(g[i], (x[i],y[i]), fontsize=8)" + "\n" + ""; + f << "\n" + "ax.set_xlim( " + << std::min( 0., xmin ) << "-5, " << std::max( 360., xmax ) + << "+5)" + "\n" + "ax.set_ylim( " + << std::min( -90., ymin ) << "-5, " << std::max( 90., ymax ) + << "+5)" + "\n" + "ax.set_xticks([0,45,90,135,180,225,270,315,360])" + "\n" + "ax.set_yticks([-90,-45,0,45,90])" + "\n" + "plt.grid()" + "\n" + "plt.show()" + "\n"; } - f << "]"; +} + +//----------------------------------------------------------------------------- + +CASE( "test_functionspace_StructuredColumns_halo checks without output" ) { + std::string gridname = eckit::Resource( "--grid", "O8" ); + + StructuredGrid grid( gridname ); + + int halo = eckit::Resource( "--halo", 2 ); + util::Config config; + config.set( "halo", halo ); + config.set( "levels", 10 ); + config.set( "periodic_points", true ); + functionspace::StructuredColumns fs( grid, grid::Partitioner( "equal_regions" ), config ); + auto for_ij = fs.for_ij(); + + Field field = fs.createField( option::name( "field" ) ); + + auto value = array::make_view( field ); + auto xy = array::make_view( fs.xy() ); - f << "\n" - "p = ["; - for ( idx_t j = fs.j_begin_halo(); j < fs.j_end_halo(); ++j ) { - for ( idx_t i = fs.i_begin_halo( j ); i < fs.i_end_halo( j ); ++i ) { + for ( idx_t j = fs.j_begin(); j < fs.j_end(); ++j ) { + for ( idx_t i = fs.i_begin( j ); i < fs.i_end( j ); ++i ) { idx_t n = fs.index( i, j ); - f << p( n ) << ", "; + for ( idx_t k = 0; k < fs.levels(); ++k ) { + value( n, k ) = util::microdeg( xy( n, XX ) ); + } } } - f << "]"; - f << "\n" - "r = ["; - for ( idx_t j = fs.j_begin_halo(); j < fs.j_end_halo(); ++j ) { - for ( idx_t i = fs.i_begin_halo( j ); i < fs.i_end_halo( j ); ++i ) { - idx_t n = fs.index( i, j ); - f << r( n ) << ", "; + ATLAS_TRACE_SCOPE( "control each value " ) + for_ij( [=]( idx_t i, idx_t j ) { + idx_t n = fs.index( i, j ); + for ( idx_t k = 0; k < fs.levels(); ++k ) { + EXPECT( value( n, k ) == util::microdeg( xy( n, XX ) ) ); } - } - f << "]"; - - f << "\n" - "" - "\n" - "c = [ cm.Paired( float(pp%13)/12. ) for pp in p ]" - "\n" - "ax.scatter(x, y, color=c, marker='o')" - "\n" - "for i in range(" - << fs.size() - << "):" - "\n" - " ax.annotate(g[i], (x[i],y[i]), fontsize=8)" - "\n" - ""; - f << "\n" - "ax.set_xlim( " - << std::min( 0., xmin ) << "-5, " << std::max( 360., xmax ) - << "+5)" - "\n" - "ax.set_ylim( " - << std::min( -90., ymin ) << "-5, " << std::max( 90., ymax ) - << "+5)" - "\n" - "ax.set_xticks([0,45,90,135,180,225,270,315,360])" - "\n" - "ax.set_yticks([-90,-45,0,45,90])" - "\n" - "plt.grid()" - "\n" - "plt.show()" - "\n"; + } ); } //----------------------------------------------------------------------------- + } // namespace test } // namespace atlas diff --git a/src/tests/grid/CMakeLists.txt b/src/tests/grid/CMakeLists.txt index 1acbc2063..766f6201d 100644 --- a/src/tests/grid/CMakeLists.txt +++ b/src/tests/grid/CMakeLists.txt @@ -21,8 +21,10 @@ foreach(test test_field test_grid_ptr test_grids + test_vertical test_rotation - test_state) + test_state + test_grid_hash) ecbuild_add_test( TARGET atlas_${test} SOURCES ${test}.cc LIBS atlas ) diff --git a/src/tests/grid/test_domain.cc b/src/tests/grid/test_domain.cc index d43711274..30b5b47f4 100644 --- a/src/tests/grid/test_domain.cc +++ b/src/tests/grid/test_domain.cc @@ -13,7 +13,7 @@ #include #include "atlas/domain.h" -#include "atlas/grid/Grid.h" +#include "atlas/grid/StructuredGrid.h" #include "atlas/runtime/Log.h" #include "atlas/util/Config.h" @@ -37,7 +37,6 @@ CASE( "test_domain_rectangular" ) { CASE( "test_domain_rectangular_tolerance" ) { using grid::LinearSpacing; - using grid::StructuredGrid; Domain domain = RectangularDomain( {-27, 45}, {33, 73} ); RectangularDomain rd = domain; diff --git a/src/tests/grid/test_field.cc b/src/tests/grid/test_field.cc index 30bc597c2..5c0f4629f 100644 --- a/src/tests/grid/test_field.cc +++ b/src/tests/grid/test_field.cc @@ -8,22 +8,18 @@ * nor does it submit to any jurisdiction. */ -#include "eckit/memory/SharedPtr.h" + #include "eckit/runtime/Tool.h" #include "eckit/value/CompositeParams.h" -#include "atlas/array/DataType.h" -#include "atlas/array/MakeView.h" +#include "atlas/array.h" #include "atlas/field/FieldSet.h" -#include "atlas/field/State.h" #include "atlas/grid.h" #include "atlas/grid/Grid.h" #include "atlas/library/Library.h" -#include "atlas/mesh/Mesh.h" -#include "atlas/mesh/Nodes.h" -#include "atlas/meshgenerator/DelaunayMeshGenerator.h" #include "atlas/parallel/mpi/mpi.h" #include "atlas/runtime/Log.h" +#include "atlas/util/ObjectHandle.h" #include "tests/AtlasTestEnvironment.h" @@ -31,7 +27,6 @@ using namespace std; using namespace eckit; using namespace atlas; using namespace atlas::grid; -using namespace atlas::meshgenerator; //----------------------------------------------------------------------------- @@ -103,7 +98,7 @@ CASE( "test_implicit_conversion" ) { CASE( "test_wrap_rawdata_through_array" ) { std::vector rawdata( 20, 8. ); - SharedPtr array( array::Array::wrap( rawdata.data(), array::make_shape( 10, 2 ) ) ); + util::ObjectHandle array( array::Array::wrap( rawdata.data(), array::make_shape( 10, 2 ) ) ); Field field( "wrapped", array.get() ); EXPECT( array->owners() == 2 ); @@ -112,7 +107,7 @@ CASE( "test_wrap_rawdata_through_array" ) { } CASE( "test_wrap_rawdata_direct" ) { - std::vector rawdata( 20, 8. ); + std::vector rawdata( 10 * 2, 8. ); Field field( "wrapped", rawdata.data(), array::make_shape( 10, 2 ) ); EXPECT( field.array().owners() == 1 ); @@ -120,6 +115,12 @@ CASE( "test_wrap_rawdata_direct" ) { EXPECT( cfieldv( 9, 1 ) == 8. ); } +CASE( "test_wrap_rawdata_through_field" ) { + std::vector rawdata( 10 * 2, 8. ); + Field field( "name", rawdata.data(), array::make_shape( 10, 2 ) ); +} + + //----------------------------------------------------------------------------- } // namespace test diff --git a/src/tests/grid/test_grid_hash.cc b/src/tests/grid/test_grid_hash.cc new file mode 100644 index 000000000..8b70287fc --- /dev/null +++ b/src/tests/grid/test_grid_hash.cc @@ -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. + */ + +#include +#include +#include + +#include "atlas/domain.h" +#include "atlas/grid/Grid.h" +#include "atlas/runtime/Log.h" +#include "atlas/util/Config.h" + +#include "eckit/utils/MD5.h" +#include "tests/AtlasTestEnvironment.h" + +using Hash = eckit::MD5; + +namespace atlas { +namespace test { + +//---------------------------------------------------------------------------------------------------------------------- + +CASE( "test_global" ) { + auto grids = { + std::make_tuple( Grid( "O32" ), "79599ee4825339e0ebbcd427d79d0177" ), + std::make_tuple( Grid( "O32", Domain() ), "79599ee4825339e0ebbcd427d79d0177" ), + std::make_tuple( Grid( "O32", RectangularDomain( {0, 360}, {90, -90} ) ), "79599ee4825339e0ebbcd427d79d0177" ), + std::make_tuple( Grid( "O32", ZonalBandDomain( {90, -90} ) ), "79599ee4825339e0ebbcd427d79d0177" ), + }; + + int c{0}; + for ( auto entry : grids ) { + Grid grid = std::get<0>( entry ); + std::string hash = std::get<1>( entry ); + SECTION( "grid: " + std::to_string( c ) ) { + Hash h; + grid.hash( h ); + if ( hash.empty() ) { Log::info() << "grid " << c << " hash = " << std::string( h ) << std::endl; } + EXPECT( std::string( h ) == hash ); + } + c++; + } +} + +//----------------------------------------------------------------------------- + +} // namespace test +} // namespace atlas + +int main( int argc, char** argv ) { + return atlas::test::run( argc, argv ); +} diff --git a/src/tests/grid/test_grid_ptr.cc b/src/tests/grid/test_grid_ptr.cc index 4cf73042d..eaf68f2db 100644 --- a/src/tests/grid/test_grid_ptr.cc +++ b/src/tests/grid/test_grid_ptr.cc @@ -12,19 +12,18 @@ #include #include -#include "atlas/grid/Grid.h" +#include "atlas/grid/Iterator.h" +#include "atlas/grid/StructuredGrid.h" #include "atlas/mesh/Mesh.h" -#include "atlas/meshgenerator/StructuredMeshGenerator.h" +#include "atlas/meshgenerator.h" #include "atlas/output/Gmsh.h" #include "atlas/runtime/Log.h" #include "atlas/util/Config.h" #include "tests/AtlasTestEnvironment.h" -using Grid = atlas::Grid; -using StructuredGrid = atlas::grid::StructuredGrid; -using RegularGrid = atlas::grid::RegularGrid; -using Config = atlas::util::Config; +using Grid = atlas::Grid; +using Config = atlas::util::Config; namespace atlas { namespace test { @@ -87,7 +86,7 @@ CASE( "test_from_string_O32_with_domain" ) { EXPECT( structured.nx().front() == 6 ); output::Gmsh gmsh( "test_grid_ptr_O32_subdomain.msh" ); - Mesh mesh = meshgenerator::StructuredMeshGenerator().generate( grid ); + Mesh mesh = StructuredMeshGenerator().generate( grid ); gmsh.write( mesh ); } @@ -127,7 +126,7 @@ CASE( "test_structured_1" ) { EXPECT( regular.y().back() == -90. ); output::Gmsh gmsh( "test_grid_ptr.msh" ); - Mesh mesh = meshgenerator::StructuredMeshGenerator().generate( grid ); + Mesh mesh = StructuredMeshGenerator().generate( grid ); gmsh.write( mesh ); } @@ -141,7 +140,7 @@ CASE( "test_structured_2" ) { EXPECT( grid ); output::Gmsh gmsh( "test_grid_ptr_structured_2.msh" ); - Mesh mesh = meshgenerator::StructuredMeshGenerator().generate( grid ); + Mesh mesh = StructuredMeshGenerator().generate( grid ); gmsh.write( mesh ); Log::info() << grid.spec() << std::endl; diff --git a/src/tests/grid/test_grids.cc b/src/tests/grid/test_grids.cc index fdc049704..5d1ca840f 100644 --- a/src/tests/grid/test_grids.cc +++ b/src/tests/grid/test_grids.cc @@ -12,8 +12,6 @@ #include #include -#include "eckit/memory/Builder.h" -#include "eckit/memory/Factory.h" #include "eckit/types/FloatCompare.h" #include "atlas/grid.h" @@ -24,11 +22,7 @@ #include "tests/AtlasTestEnvironment.h" -using StructuredGrid = atlas::grid::StructuredGrid; -using UnstructuredGrid = atlas::grid::UnstructuredGrid; -using Grid = atlas::Grid; -using Regular = atlas::grid::RegularGrid; -using ReducedGaussianGrid = atlas::grid::ReducedGaussianGrid; +using Grid = atlas::Grid; namespace atlas { namespace test { @@ -45,7 +39,7 @@ CASE( "test_factory" ) { } CASE( "test_regular_gg" ) { - Regular grid( "F32" ); + RegularGrid grid( "F32" ); EXPECT( grid.ny() == 64 ); EXPECT( grid.size() == 8192 ); @@ -68,7 +62,7 @@ CASE( "test_reduced_gg" ) { EXPECT( grid.ny() == 64 ); EXPECT( grid.size() == 6114 ); - grid = grid::ReducedGaussianGrid( {4, 6, 8, 8, 6, 4} ); + grid = ReducedGaussianGrid( {4, 6, 8, 8, 6, 4} ); EXPECT( grid.ny() == 6 ); EXPECT( grid.size() == 8 + 12 + 16 ); @@ -85,20 +79,20 @@ CASE( "test_reduced_gg_ifs" ) { CASE( "test_regular_ll" ) { // Constructor for N=8 - size_t nlon = 32; - size_t nlat = 16; + idx_t nlon = 32; + idx_t nlat = 16; std::stringstream name; name << "Slat" << nlon << "x" << nlat; - Regular grid( name.str() ); + RegularGrid grid( name.str() ); EXPECT( grid.nx() == nlon ); EXPECT( grid.ny() == nlat ); EXPECT( grid.size() == 512 ); // EXPECT(grid.type() == "shifted_lat"); - EXPECT( grid.y( 0 ) == 90. - 0.5 * ( 180. / 16. ) ); - EXPECT( grid.y( grid.ny() - 1 ) == -90. + 0.5 * ( 180. / 16. ) ); - EXPECT( grid.x( 0 ) == 0. ); - EXPECT( grid.x( grid.nx() - 1 ) == 360. - 360. / 32. ); + EXPECT( is_approximately_equal( grid.y( 0 ), 90. - 0.5 * ( 180. / 16. ) ) ); + EXPECT( is_approximately_equal( grid.y( grid.ny() - 1 ), -90. + 0.5 * ( 180. / 16. ) ) ); + EXPECT( is_approximately_equal( grid.x( 0 ), 0. ) ); + EXPECT( is_approximately_equal( grid.x( grid.nx() - 1 ), 360. - 360. / 32. ) ); // Construct using builders/factories @@ -118,17 +112,17 @@ CASE( "test_regular_ll" ) { EXPECT( grid.size() == 512 ); // EXPECT(gridptr->type() == "shifted_lat"); - Regular ll_poles( "L4x3" ); + RegularGrid ll_poles( "L4x3" ); EXPECT( ll_poles.nx() == 4 ); EXPECT( ll_poles.ny() == 3 ); - Regular ll_nopoles( "Slat4x2" ); + RegularGrid ll_nopoles( "Slat4x2" ); EXPECT( ll_nopoles.nx() == 4 ); EXPECT( ll_nopoles.ny() == 2 ); - EXPECT( eckit::types::is_approximately_equal( ll_nopoles.y( 0 ), 45. ) ); // tolerance was previously 1.e-5 - EXPECT( eckit::types::is_approximately_equal( ll_nopoles.y( 1 ), -45. ) ); // tolerance was previously 1.e-5 - EXPECT( eckit::types::is_approximately_equal( ll_nopoles.x( 0 ), 0. ) ); // tolerance was previously 1.e-5 - EXPECT( eckit::types::is_approximately_equal( ll_nopoles.x( 1 ), 90. ) ); // tolerance was previously 1.e-5 + EXPECT( is_approximately_equal( ll_nopoles.y( 0 ), 45. ) ); // tolerance was previously 1.e-5 + EXPECT( is_approximately_equal( ll_nopoles.y( 1 ), -45. ) ); // tolerance was previously 1.e-5 + EXPECT( is_approximately_equal( ll_nopoles.x( 0 ), 0. ) ); // tolerance was previously 1.e-5 + EXPECT( is_approximately_equal( ll_nopoles.x( 1 ), 90. ) ); // tolerance was previously 1.e-5 } CASE( "test_reducedgaussian" ) { diff --git a/src/tests/grid/test_state.cc b/src/tests/grid/test_state.cc index 9a61d5c2a..94b30a8ae 100644 --- a/src/tests/grid/test_state.cc +++ b/src/tests/grid/test_state.cc @@ -11,7 +11,6 @@ #include #include -#include "eckit/exception/Exceptions.h" #include "eckit/memory/ScopedPtr.h" #include "eckit/parser/JSON.h" #include "eckit/parser/JSONParser.h" @@ -25,6 +24,7 @@ #include "atlas/library/Library.h" #include "atlas/library/config.h" #include "atlas/mesh/Mesh.h" +#include "atlas/runtime/Exception.h" #include "atlas/runtime/Log.h" #include "tests/AtlasTestEnvironment.h" @@ -49,11 +49,11 @@ class MyStateGenerator : public StateGenerator { // --- Implementation (in .cc file) void MyStateGenerator::generate( State& state, const eckit::Parametrisation& p ) const { const util::Config* params = dynamic_cast( &p ); - if ( !params ) { throw eckit::Exception( "Parametrisation has to be of atlas::util::Config type" ); } + if ( !params ) { throw_Exception( "Parametrisation has to be of atlas::util::Config type" ); } util::Config geometry; if ( !params->get( "geometry", geometry ) ) { - throw eckit::BadParameter( "Could not find 'geometry' in Parametrisation", Here() ); + throw_Exception( "Could not find 'geometry' in Parametrisation", Here() ); } std::string grid_uid; @@ -62,7 +62,7 @@ void MyStateGenerator::generate( State& state, const eckit::Parametrisation& p ) if ( !geometry.has( "ngptot" ) ) { geometry.set( "ngptot", grid.size() ); } } - if ( !geometry.has( "ngptot" ) ) { throw eckit::BadParameter( "Could not find 'ngptot' in Parametrisation" ); } + if ( !geometry.has( "ngptot" ) ) { throw_Exception( "Could not find 'ngptot' in Parametrisation" ); } std::vector fields; if ( params->get( "fields", fields ) ) { @@ -120,7 +120,7 @@ CASE( "state" ) { CASE( "state_generator" ) { EXPECT( StateGeneratorFactory::has( "MyStateGenerator" ) ); - eckit::ScopedPtr stategenerator( StateGeneratorFactory::build( "MyStateGenerator" ) ); + std::unique_ptr stategenerator( StateGeneratorFactory::build( "MyStateGenerator" ) ); } CASE( "state_create" ) { diff --git a/src/tests/grid/test_vertical.cc b/src/tests/grid/test_vertical.cc new file mode 100644 index 000000000..94a76feaf --- /dev/null +++ b/src/tests/grid/test_vertical.cc @@ -0,0 +1,60 @@ +/* + * (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 "atlas/grid/Vertical.h" +#include "atlas/option.h" + +#include "tests/AtlasTestEnvironment.h" + +namespace atlas { +namespace test { + +//----------------------------------------------------------------------------- + +std::vector zrange( idx_t nlev, double min, double max ) { + std::vector zcoord( nlev ); + double dzcoord = ( max - min ) / double( nlev - 1 ); + for ( idx_t jlev = 0; jlev < nlev; ++jlev ) { + zcoord[jlev] = min + jlev * dzcoord; + } + return zcoord; +} + +//----------------------------------------------------------------------------- + +CASE( "test vertical; default constructor" ) { + Vertical vertical; + EXPECT( vertical.size() == 0 ); + EXPECT( vertical.k_begin() == 0 ); + EXPECT( vertical.k_end() == 0 ); +} +CASE( "test vertical; config levels" ) { + Vertical vertical( option::levels( 10 ) ); + EXPECT( vertical.size() == 10 ); + EXPECT( vertical.k_begin() == 0 ); + EXPECT( vertical.k_end() == 10 ); +} +CASE( "test vertical; array" ) { + Vertical vertical( 5, zrange( 5, 0., 1. ) ); + EXPECT( vertical.size() == 5 ); + EXPECT( vertical.k_begin() == 0 ); + EXPECT( vertical.k_end() == 5 ); +} + +//----------------------------------------------------------------------------- + + +} // namespace test +} // namespace atlas + +int main( int argc, char** argv ) { + return atlas::test::run( argc, argv ); +} diff --git a/src/tests/interpolation/CMakeLists.txt b/src/tests/interpolation/CMakeLists.txt index 73cd96d13..738b75bdf 100644 --- a/src/tests/interpolation/CMakeLists.txt +++ b/src/tests/interpolation/CMakeLists.txt @@ -16,3 +16,27 @@ ecbuild_add_test( TARGET atlas_test_interpolation_finite_element SOURCES test_interpolation_finite_element.cc LIBS atlas ) + +ecbuild_add_test( TARGET atlas_test_interpolation_cubic_prototype + SOURCES test_interpolation_cubic_prototype.cc CubicInterpolationPrototype.h + LIBS atlas +) + +ecbuild_add_executable( TARGET atlas_test_interpolation_structured2D + SOURCES test_interpolation_structured2D.cc + LIBS atlas + NOINSTALL +) + +ecbuild_add_test( TARGET atlas_test_interpolation_bilinear + COMMAND atlas_test_interpolation_structured2D ARGS --scheme linear +) + +ecbuild_add_test( TARGET atlas_test_interpolation_bicubic + COMMAND atlas_test_interpolation_structured2D ARGS --scheme cubic +) + +ecbuild_add_test( TARGET atlas_test_interpolation_biquasicubic + COMMAND atlas_test_interpolation_structured2D ARGS --scheme quasicubic +) + diff --git a/src/tests/interpolation/CubicInterpolationPrototype.h b/src/tests/interpolation/CubicInterpolationPrototype.h new file mode 100644 index 000000000..545d8687d --- /dev/null +++ b/src/tests/interpolation/CubicInterpolationPrototype.h @@ -0,0 +1,434 @@ +/* + * (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/array/ArrayView.h" +#include "atlas/array/MakeView.h" +#include "atlas/functionspace/StructuredColumns.h" +#include "atlas/grid/Grid.h" +#include "atlas/grid/Stencil.h" +#include "atlas/grid/StencilComputer.h" +#include "atlas/grid/Vertical.h" +#include "eckit/linalg/SparseMatrix.h" + + +#include "atlas/runtime/Log.h" +#include "eckit/types/Types.h" + +using namespace eckit; +using namespace atlas::functionspace; +using namespace atlas::util; + +namespace atlas { +namespace test { + +//----------------------------------------------------------------------------- + +class CubicVerticalInterpolation { + ComputeVerticalStencil compute_vertical_stencil_; + Vertical vertical_; + static constexpr idx_t stencil_width() { return 4; } + static constexpr idx_t stencil_size() { return stencil_width() * stencil_width(); } + idx_t first_level_; + idx_t last_level_; + bool limiter_; + +public: + CubicVerticalInterpolation( const Vertical& vertical, const eckit::Configuration& config = util::NoConfig() ) : + compute_vertical_stencil_( vertical, stencil_width() ), + vertical_( vertical ), + first_level_( vertical_.k_begin() ), + last_level_( vertical_.k_end() - 1 ) { + limiter_ = config.getBool( "limiter", false ); + } + struct Weights { + std::array weights_k; + }; + using Stencil = VerticalStencil<4>; + + template + void compute_stencil( const double z, stencil_t& stencil ) const { + compute_vertical_stencil_( z, stencil ); + } + + template + void compute_weights( const double z, const stencil_t& stencil, weights_t& weights ) const { + auto& w = weights.weights_k; + + std::array zvec; + for ( idx_t k = 0; k < 4; ++k ) { + zvec[k] = vertical_( stencil.k( k ) ); + } + + // auto quadratic_interpolation = [z]( const double zvec[], double w[] ) { + // double d01 = zvec[0] - zvec[1]; + // double d02 = zvec[0] - zvec[2]; + // double d12 = zvec[1] - zvec[2]; + // double dc0 = d01 * d02; + // double dc1 = -d01 * d12; + // double d0 = z - zvec[0]; + // double d1 = z - zvec[1]; + // double d2 = z - zvec[2]; + // w[0] = ( d1 * d2 ) / dc0; + // w[1] = ( d0 * d2 ) / dc1; + // w[2] = 1. - w[0] - w[1]; + // }; + + if ( stencil.k_interval() == -1 ) { + // constant extrapolation + // lev0 lev1 lev2 lev3 + // + |------X------X------X + // w=1 w=0 w=0 w=0 + w[0] = 1.; + w[1] = 0.; + w[2] = 0.; + w[3] = 0.; + return; + } + else if ( stencil.k_interval() == 3 ) { + // constant extrapolation + // lev(n-4) lev(n-3) lev(n-2) lev(n-1) + // X---------X---------X---------| + + // w=0 w=0 w=0 w=1 + w[0] = 0.; + w[1] = 0.; + w[2] = 0.; + w[3] = 1.; + return; + } + // else if ( stencil.k_interval() == 0 ) { + // // quadratic interpolation + // // lev0 lev1 lev2 lev3 + // // | + | | | + // // w=0 + // quadratic_interpolation( zvec.data(), w.data() ); + // w[3] = 0.; + // return; + // } + // else if ( stencil.k_interval() == 2 ) { + // // quadratic interpolation + // // lev(n-4) lev(n-3) lev(n-2) lev(n-1) + // // | | | + | + // // w=0 + // quadratic_interpolation( zvec.data() + 1, w.data() + 1 ); + // w[0] = 0.; + // return; + // } + + // cubic interpolation + // lev(k+0) lev(k+1) lev(k+2) lev(k+3) + // | | x | | + double d01 = zvec[0] - zvec[1]; + double d02 = zvec[0] - zvec[2]; + double d03 = zvec[0] - zvec[3]; + double d12 = zvec[1] - zvec[2]; + double d13 = zvec[1] - zvec[3]; + double d23 = zvec[2] - zvec[3]; + double dc0 = d01 * d02 * d03; + double dc1 = -d01 * d12 * d13; + double dc2 = d02 * d12 * d23; + + double d0 = z - zvec[0]; + double d1 = z - zvec[1]; + double d2 = z - zvec[2]; + double d3 = z - zvec[3]; + + w[0] = ( d1 * d2 * d3 ) / dc0; + w[1] = ( d0 * d2 * d3 ) / dc1; + w[2] = ( d0 * d1 * d3 ) / dc2; + w[3] = 1. - w[0] - w[1] - w[2]; + } + + template + void interpolate( const stencil_t& stencil, const weights_t& weights, const array_t& input, double& output ) const { + output = 0.; + const auto& w = weights.weights_k; + for ( idx_t k = 0; k < stencil_width(); ++k ) { + output += w[k] * input[stencil.k( k )]; + } + + + if ( limiter_ ) { + idx_t k = stencil.k_interval(); + idx_t k1, k2; + if ( k < 0 ) { k1 = k2 = 0; } + else if ( k > 2 ) { + k1 = k2 = 3; + } + else { + k1 = k; + k2 = k + 1; + } + double f1 = input[stencil.k( k1 )]; + double f2 = input[stencil.k( k2 )]; + double maxval = std::max( f1, f2 ); + double minval = std::min( f1, f2 ); + output = std::min( maxval, std::max( minval, output ) ); + } + } + + template + double operator()( const double z, const array_t& input ) const { + VerticalStencil stencil; + compute_vertical_stencil_( z, stencil ); + Weights weights; + compute_weights( z, stencil, weights ); + double output; + interpolate( stencil, weights, input, output ); + return output; + } +}; + +//----------------------------------------------------------------------------- + +class CubicHorizontalInterpolation { + functionspace::StructuredColumns fs_; + ComputeHorizontalStencil compute_horizontal_stencil_; + static constexpr idx_t stencil_width() { return 4; } + static constexpr idx_t stencil_size() { return stencil_width() * stencil_width(); } + bool limiter_{false}; + +public: + using Stencil = HorizontalStencil<4>; + +public: + CubicHorizontalInterpolation( const functionspace::StructuredColumns& fs ) : + fs_( fs ), + compute_horizontal_stencil_( fs.grid(), stencil_width() ) {} + template + void compute_weights( const double x, const double y, weights_t& weights ) const { + HorizontalStencil stencil; + compute_horizontal_stencil_( x, y, stencil ); + compute_weights( x, y, stencil, weights ); + } + + struct Weights { + std::array, 4> weights_i; + std::array weights_j; + }; + + template + void compute_stencil( const double x, const double y, stencil_t& stencil ) const { + compute_horizontal_stencil_( x, y, stencil ); + } + + template + void compute_weights( const double x, const double y, const stencil_t& stencil, weights_t& weights ) const { + PointXY P1, P2; + std::array yvec; + for ( idx_t j = 0; j < stencil_width(); ++j ) { + auto& weights_i = weights.weights_i[j]; + fs_.compute_xy( stencil.i( 1, j ), stencil.j( j ), P1 ); + fs_.compute_xy( stencil.i( 2, j ), stencil.j( j ), P2 ); + double alpha = ( P2.x() - x ) / ( P2.x() - P1.x() ); + double alpha_sqr = alpha * alpha; + double two_minus_alpha = 2. - alpha; + double one_minus_alpha_sqr = 1. - alpha_sqr; + weights_i[0] = -alpha * one_minus_alpha_sqr / 6.; + weights_i[1] = 0.5 * alpha * ( 1. + alpha ) * two_minus_alpha; + weights_i[2] = 0.5 * one_minus_alpha_sqr * two_minus_alpha; + weights_i[3] = 1. - weights_i[0] - weights_i[1] - weights_i[2]; + yvec[j] = P1.y(); + } + double dl12 = yvec[0] - yvec[1]; + double dl13 = yvec[0] - yvec[2]; + double dl14 = yvec[0] - yvec[3]; + double dl23 = yvec[1] - yvec[2]; + double dl24 = yvec[1] - yvec[3]; + double dl34 = yvec[2] - yvec[3]; + double dcl1 = dl12 * dl13 * dl14; + double dcl2 = -dl12 * dl23 * dl24; + double dcl3 = dl13 * dl23 * dl34; + + double dl1 = y - yvec[0]; + double dl2 = y - yvec[1]; + double dl3 = y - yvec[2]; + double dl4 = y - yvec[3]; + + auto& weights_j = weights.weights_j; + weights_j[0] = ( dl2 * dl3 * dl4 ) / dcl1; + weights_j[1] = ( dl1 * dl3 * dl4 ) / dcl2; + weights_j[2] = ( dl1 * dl2 * dl4 ) / dcl3; + weights_j[3] = 1. - weights_j[0] - weights_j[1] - weights_j[2]; + } + + template + void interpolate( const stencil_t& stencil, const weights_t& weights, const array_t& input, double& output ) { + std::array, stencil_width()> index; + const auto& weights_j = weights.weights_j; + output = 0.; + for ( idx_t j = 0; j < stencil_width(); ++j ) { + const auto& weights_i = weights.weights_i[j]; + for ( idx_t i = 0; i < stencil_width(); ++i ) { + idx_t n = fs_.index( stencil.i( i, j ), stencil.j( j ) ); + output += weights_i[i] * weights_j[j] * input[n]; + index[j][i] = n; + } + } + + if ( limiter_ ) { limit( output, index, input ); } + } + + template + void limit( double& output, const std::array, 4>& index, const array_t& input ) { + // Limit output to max/min of values in stencil marked by '*' + // x x x x + // x *-----* x + // / P | + // x *------ * x + // x x x x + double maxval = std::numeric_limits::lowest(); + double minval = std::numeric_limits::max(); + for ( idx_t j = 1; j < 3; ++j ) { + for ( idx_t i = 1; i < 3; ++i ) { + idx_t n = index[j][i]; + double val = input[n]; + maxval = std::max( maxval, val ); + minval = std::min( minval, val ); + } + } + output = std::min( maxval, std::max( minval, output ) ); + } + + + template + double operator()( const double x, const double y, const array_t& input ) { + HorizontalStencil stencil; + compute_horizontal_stencil_( x, y, stencil ); + Weights weights; + compute_weights( x, y, stencil, weights ); + double output; + interpolate( stencil, weights, input, output ); + return output; + } + + struct WorkSpace { + HorizontalStencil<4> stencil; + Weights weights; + }; + + using Triplet = eckit::linalg::Triplet; + using Triplets = std::vector; + + // Thread private workspace + Triplets compute_triplets( const idx_t row, const double x, const double y, WorkSpace& ws ) { + Triplets triplets; + triplets.reserve( stencil_size() ); + insert_triplets( row, x, y, triplets, ws ); + return triplets; + } + + Triplets reserve_triplets( size_t N ) { + Triplets triplets; + triplets.reserve( N * stencil_size() ); + return triplets; + } + + void insert_triplets( const idx_t row, const double x, const double y, Triplets& triplets, WorkSpace& ws ) { + compute_horizontal_stencil_( x, y, ws.stencil ); + compute_weights( x, y, ws.stencil, ws.weights ); + const auto& wj = ws.weights.weights_j; + for ( idx_t j = 0; j < stencil_width(); ++j ) { + const auto& wi = ws.weights.weights_i[j]; + for ( idx_t i = 0; i < stencil_width(); ++i ) { + idx_t col = fs_.index( ws.stencil.i( i, j ), ws.stencil.j( j ) ); + double w = wi[i] * wj[j]; + triplets.emplace_back( row, col, w ); + } + } + } +}; + +//----------------------------------------------------------------------------- + +class Cubic3DInterpolation { + functionspace::StructuredColumns fs_; + CubicHorizontalInterpolation horizontal_interpolation_; + CubicVerticalInterpolation vertical_interpolation_; + static constexpr idx_t stencil_width() { return 4; } + static constexpr idx_t stencil_size() { return stencil_width() * stencil_width(); } + +public: + struct Weights { + std::array, 4> weights_i; + std::array weights_j; + std::array weights_k; + }; + + using Stencil = Stencil3D<4>; + + Cubic3DInterpolation( const functionspace::StructuredColumns& fs ) : + fs_( fs ), + horizontal_interpolation_( fs ), + vertical_interpolation_( fs.vertical() ) {} + + template + void compute_stencil( const double x, const double y, const double z, stencil_t& stencil ) const { + horizontal_interpolation_.compute_stencil( x, y, stencil ); + vertical_interpolation_.compute_stencil( z, stencil ); + } + + template + void compute_weights( const double x, const double y, const double z, weights_t& weights ) const { + Stencil stencil; + compute_stencil( x, y, z, stencil ); + compute_weights( x, y, z, stencil, weights ); + } + + template + void compute_weights( const double x, const double y, const double z, const stencil_t& stencil, + weights_t& weights ) const { + horizontal_interpolation_.compute_weights( x, y, stencil, weights ); + vertical_interpolation_.compute_weights( z, stencil, weights ); + } + + template + void interpolate( const stencil_t& stencil, const weights_t& weights, const array_t& input, double& output ) { + output = 0.; + const auto& wj = weights.weights_j; + const auto& wk = weights.weights_k; + + for ( idx_t j = 0; j < stencil_width(); ++j ) { + const auto& wi = weights.weights_i[j]; + for ( idx_t i = 0; i < stencil_width(); ++i ) { + idx_t n = fs_.index( stencil.i( i, j ), stencil.j( j ) ); + for ( idx_t k = 0; k < stencil_width(); ++k ) { + output += wi[i] * wj[j] * wk[k] * input( n, stencil.k( k ) ); + } + } + } + } + + template + double operator()( const double x, const double y, const double z, const array_t& input ) { + Stencil stencil; + Weights weights; + compute_stencil( x, y, z, stencil ); + compute_weights( x, y, z, stencil, weights ); + double output; + interpolate( stencil, weights, input, output ); + return output; + } + + template + double operator()( const point_t& p, const array_t& input ) { + Stencil stencil; + Weights weights; + compute_stencil( p[0], p[1], p[2], stencil ); + compute_weights( p[0], p[1], p[2], stencil, weights ); + double output; + interpolate( stencil, weights, input, output ); + return output; + } +}; + +//----------------------------------------------------------------------------- + +} // namespace test +} // namespace atlas diff --git a/src/tests/interpolation/test_interpolation_cubic_prototype.cc b/src/tests/interpolation/test_interpolation_cubic_prototype.cc new file mode 100644 index 000000000..3808f3053 --- /dev/null +++ b/src/tests/interpolation/test_interpolation_cubic_prototype.cc @@ -0,0 +1,382 @@ +/* + * (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 + +#include "eckit/linalg/LinearAlgebra.h" +#include "eckit/linalg/Vector.h" +#include "eckit/types/Types.h" + +#include "atlas/array.h" +#include "atlas/field/Field.h" +#include "atlas/functionspace/NodeColumns.h" +#include "atlas/functionspace/PointCloud.h" +#include "atlas/functionspace/StructuredColumns.h" +#include "atlas/grid/Partitioner.h" +#include "atlas/grid/StructuredGrid.h" +#include "atlas/interpolation.h" +#include "atlas/library/Library.h" +#include "atlas/mesh/Mesh.h" +#include "atlas/meshgenerator.h" +#include "atlas/output/Gmsh.h" +#include "atlas/parallel/mpi/mpi.h" +#include "atlas/util/CoordinateEnums.h" +#include "atlas/util/MicroDeg.h" + +#include "CubicInterpolationPrototype.h" +#include "tests/AtlasTestEnvironment.h" + +using namespace atlas::functionspace; +using namespace atlas::grid; +using namespace atlas::util; +using namespace atlas::array; + +namespace atlas { +namespace test { + +//----------------------------------------------------------------------------- + +std::vector IFS_full_levels_uniform( idx_t nlev ) { + std::vector zcoord( nlev ); + double dzcoord = 1. / double( nlev ); + for ( idx_t jlev = 0; jlev < nlev; ++jlev ) { + zcoord[jlev] = 0.5 * dzcoord + jlev * dzcoord; + } + return zcoord; +} + +std::vector zrange( idx_t nlev, double min, double max ) { + std::vector zcoord( nlev ); + + double dzcoord = ( max - min ) / double( nlev - 1 ); + for ( idx_t jlev = 0; jlev < nlev; ++jlev ) { + zcoord[jlev] = min + jlev * dzcoord; + } + return zcoord; +} + +double cubic( double x, double min, double max ) { + double x0 = min; + double x1 = 0.5 * ( max + min ); + double x2 = max; + double xmax = 0.5 * ( x0 + x1 ); + return ( x - x0 ) * ( x - x1 ) * ( x - x2 ) / ( ( xmax - x0 ) * ( xmax - x1 ) * ( xmax - x2 ) ); +} + +CASE( "test vertical cubic interpolation" ) { + idx_t nlev = 10; + auto vertical = Vertical{nlev, IFS_full_levels_uniform( nlev )}; + bool limiter = true; + CubicVerticalInterpolation interpolate( vertical, util::Config( "limiter", limiter ) ); + std::vector departure_points{0.0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0, 0.3246}; + array::ArrayT array( nlev ); + auto view = array::make_view( array ); + Log::info() << "source:" << std::endl; + for ( idx_t k = 0; k < nlev; ++k ) { + view( k ) = cubic( vertical( k ), 0., 1. ); + Log::info() << " " << vertical( k ) << " : " << view( k ) << std::endl; + } + + Log::info() << "interpolation:" << std::endl; + for ( auto p : departure_points ) { + Log::info() << " " << std::setw( 6 ) << p << " : " << std::setw( 12 ) << interpolate( p, view ) + << " expected : " << cubic( p, 0., 1. ) << std::endl; + if ( p >= vertical.front() && p <= vertical.back() && !limiter ) { + EXPECT( eckit::types::is_approximately_equal( interpolate( p, view ), cubic( p, 0., 1. ) ) ); + } + } +} + +//----------------------------------------------------------------------------- + +CASE( "test horizontal cubic interpolation" ) { + //if ( mpi::comm().size() == 1 ) { + std::string gridname = eckit::Resource( "--grid", "O8" ); + + StructuredGrid grid( gridname ); + int halo = eckit::Resource( "--halo", 2 ); + Config config; + config.set( "halo", halo ); + config.set( "levels", 9 ); + config.set( "periodic_points", true ); + StructuredColumns fs( grid, Partitioner( "equal_regions" ), config ); + + Field field = fs.createField( option::levels( 0 ) ); + auto f = array::make_view( field ); + auto xy = array::make_view( fs.xy() ); + + auto fx = []( double x ) { return cubic( x, 0., 360. ); }; + auto fy = []( double y ) { return cubic( y, -90., 90. ); }; + auto fxy = [fx, fy]( double x, double y ) { return fx( x ) * fy( y ); }; + + for ( idx_t j = 0; j < fs.size(); ++j ) { + f( j ) = fxy( xy( j, XX ), xy( j, YY ) ); + } + + CubicHorizontalInterpolation cubic_interpolation( fs ); + + auto departure_points = { + PointXY( 0.13257, 45.6397 ), + }; + for ( auto p : departure_points ) { + Log::info() << p << " --> " << cubic_interpolation( p.x(), p.y(), f ) << std::endl; + EXPECT( is_approximately_equal( cubic_interpolation( p.x(), p.y(), f ), fxy( p.x(), p.y() ) ) ); + } +} + +//----------------------------------------------------------------------------- + +bool operator==( const eckit::linalg::Triplet& t1, const eckit::linalg::Triplet& t2 ) { + if ( t1.row() != t2.row() ) return false; + if ( t1.col() != t2.col() ) return false; + if ( !is_approximately_equal( t1.value(), t2.value() ) ) return false; + + return true; +} +bool operator!=( const eckit::linalg::Triplet& t1, const eckit::linalg::Triplet& t2 ) { + return !( t1 == t2 ); +} +bool operator==( const std::vector& t1, const std::vector& t2 ) { + if ( t1.size() != t2.size() ) return false; + for ( size_t i = 0; i < t1.size(); ++i ) { + if ( t1[i] != t2[i] ) return false; + } + return true; +} +std::ostream& operator<<( std::ostream& out, const LocalView& array ) { + out << "{ "; + for ( idx_t i = 0; i < array.size(); ++i ) { + out << array( i ); + if ( i < array.size() - 1 ) { out << ","; } + out << " "; + } + out << "}"; + return out; +} + +//----------------------------------------------------------------------------- + +CASE( "test horizontal cubic interpolation triplets" ) { + //if ( mpi::comm().size() == 1 ) { + std::string gridname = eckit::Resource( "--grid", "O8" ); + + StructuredGrid grid( gridname ); + int halo = eckit::Resource( "--halo", 2 ); + Config config; + config.set( "halo", halo ); + config.set( "levels", 9 ); + config.set( "periodic_points", true ); + StructuredColumns fs( grid, Partitioner( "equal_regions" ), config ); + + Field field = fs.createField( option::levels( 0 ) ); + auto f = array::make_view( field ); + auto xy = array::make_view( fs.xy() ); + + for ( idx_t j = 0; j < fs.size(); ++j ) { + f( j ) = xy( j, XX ); + } + + CubicHorizontalInterpolation cubic_interpolation( fs ); + + auto departure_points = PointCloud{PointXY(), + { + {0.13257, 45.6397}, + {360., -90.}, + }}; + auto departure_lonlat = make_view( departure_points.lonlat() ); + + CubicHorizontalInterpolation::WorkSpace ws; + CubicHorizontalInterpolation::Triplets triplets; + for ( idx_t row = 0; row < departure_points.size(); ++row ) { + auto triplets_row = + cubic_interpolation.compute_triplets( row, departure_lonlat( row, XX ), departure_lonlat( row, YY ), ws ); + Log::info() << departure_lonlat.slice( row, array::Range::all() ) << " --> {\n"; + for ( auto triplet : triplets_row ) { + Log::info() << " " << triplet << " ,\n"; + } + Log::info() << " } " << std::endl; + std::copy( triplets_row.begin(), triplets_row.end(), std::back_inserter( triplets ) ); + } + + auto triplets2 = cubic_interpolation.reserve_triplets( departure_points.size() ); + { + idx_t row{0}; + for ( auto p : departure_points.iterate().xy() ) { + cubic_interpolation.insert_triplets( row++, p.x(), p.y(), triplets2, ws ); + } + } + + + EXPECT( triplets2 == triplets ); + + eckit::linalg::SparseMatrix matrix( departure_points.size(), fs.size(), triplets2 ); + Log::info() << matrix << std::endl; + + std::vector tgt( departure_points.size() ); + eckit::linalg::Vector v_src( const_cast( f.data() ), f.size() ); + eckit::linalg::Vector v_tgt( tgt.data(), tgt.size() ); + eckit::linalg::LinearAlgebra::backend().spmv( matrix, v_src, v_tgt ); + Log::info() << "output = " << tgt << std::endl; +} + +//----------------------------------------------------------------------------- + +CASE( "test 3d cubic interpolation" ) { + //if ( mpi::comm().size() == 1 ) { + std::string gridname = eckit::Resource( "--grid", "O8" ); + idx_t nlev = 11; + + Vertical vertical( nlev, zrange( nlev, 0., 1. ) ); + Log::info() << zrange( nlev, 0., 1. ) << std::endl; + ; + + StructuredGrid grid( gridname ); + int halo = eckit::Resource( "--halo", 2 ); + Config config; + config.set( "halo", halo ); + config.set( "periodic_points", true ); + StructuredColumns fs( grid, vertical, Partitioner( "equal_regions" ), config ); + + Field input = fs.createField(); + auto f = array::make_view( input ); + auto xy = array::make_view( fs.xy() ); + const auto& z = fs.vertical(); + + auto fx = []( double x ) { return cubic( x, 0., 360. ); }; + auto fy = []( double y ) { return cubic( y, -90., 90. ); }; + auto fz = []( double z ) { return cubic( z, 0., 1. ); }; + auto fp = [fx, fy, fz]( const PointXYZ& p ) { return fx( p.x() ) * fy( p.y() ) * fz( p.z() ); }; + + for ( idx_t n = 0; n < fs.size(); ++n ) { + for ( idx_t k = fs.k_begin(); k < fs.k_end(); ++k ) { + PointXYZ p{ + xy( n, XX ), + xy( n, YY ), + z( k ), + }; + f( n, k ) = fp( p ); + } + } + input.set_dirty( false ); // to avoid halo-exchange + + + auto departure_points = PointCloud( + PointXYZ(), { + {90., -45., 0.25}, {0., -45., 0.25}, {180., -45., 0.25}, {360., -45., 0.25}, {90., -90., 0.25}, + {90., 0., 0.25}, {90., 90., 0.25}, {10., -45., 0.25}, {20., -45., 0.25}, {30., -45., 0.25}, + {40., -45., 0.25}, {50., -45., 0.25}, {60., -45., 0.25}, {70., -45., 0.25}, {80., -45., 0.25}, + {90., -45., 0.25}, {10., -10., 0.25}, {20., -20., 0.25}, {30., -30., 0.25}, {40., -40., 0.25}, + {50., -50., 0.25}, {60., -60., 0.25}, {70., -70., 0.25}, {80., -80., 0.25}, {90., -90., 0.25}, + {60., -60., 0.6}, {90., -45., 0.16}, {90., -45., 0.6}, {90., -45., 1.}, {90., -45., 0.}, + {90., -45., 0.1}, {45., 33., 0.7}, {359., 20., 0.1}, {360., 88., 0.9}, {0.1, -89., 1.}, + + {90., -45., 0.25}, {0., -45., 0.25}, {180., -45., 0.25}, {360., -45., 0.25}, {90., -90., 0.25}, + {90., 0., 0.25}, {90., 90., 0.25}, {10., -45., 0.25}, {20., -45., 0.25}, {30., -45., 0.25}, + {40., -45., 0.25}, {50., -45., 0.25}, {60., -45., 0.25}, {70., -45., 0.25}, {80., -45., 0.25}, + {90., -45., 0.25}, {10., -10., 0.25}, {20., -20., 0.25}, {30., -30., 0.25}, {40., -40., 0.25}, + {50., -50., 0.25}, {60., -60., 0.25}, {70., -70., 0.25}, {80., -80., 0.25}, {90., -90., 0.25}, + {60., -60., 0.6}, {90., -45., 0.16}, {90., -45., 0.6}, {90., -45., 1.}, {90., -45., 0.}, + {90., -45., 0.1}, {45., 33., 0.7}, {359., 20., 0.1}, {360., 88., 0.9}, {0.1, -89., 1.}, + + {90., -45., 0.25}, {0., -45., 0.25}, {180., -45., 0.25}, {360., -45., 0.25}, {90., -90., 0.25}, + {90., 0., 0.25}, {90., 90., 0.25}, {10., -45., 0.25}, {20., -45., 0.25}, {30., -45., 0.25}, + {40., -45., 0.25}, {50., -45., 0.25}, {60., -45., 0.25}, {70., -45., 0.25}, {80., -45., 0.25}, + {90., -45., 0.25}, {10., -10., 0.25}, {20., -20., 0.25}, {30., -30., 0.25}, {40., -40., 0.25}, + {50., -50., 0.25}, {60., -60., 0.25}, {70., -70., 0.25}, {80., -80., 0.25}, {90., -90., 0.25}, + {60., -60., 0.6}, {90., -45., 0.16}, {90., -45., 0.6}, {90., -45., 1.}, {90., -45., 0.}, + {90., -45., 0.1}, {45., 33., 0.7}, {359., 20., 0.1}, {360., 88., 0.9}, {0.1, -89., 1.}, + } ); + + SECTION( "prototype" ) { + Cubic3DInterpolation cubic_interpolation( fs ); + + for ( auto p : departure_points.iterate().xyz() ) { + double interpolated = cubic_interpolation( p, f ); + double exact = fp( p ); + Log::info() << p << " --> " << interpolated << " [exact] " << exact << std::endl; + EXPECT( is_approximately_equal( interpolated, exact ) ); + } + } + + + SECTION( "official version" ) { + auto matrix_free = Config( "matrix_free", true ); + Interpolation interpolation( option::type( "tricubic" ) | matrix_free, fs, departure_points ); + + Field output = Field( "output", make_datatype(), make_shape( departure_points.size() ) ); + interpolation.execute( input, output ); + + auto output_view = array::make_view( output ); + idx_t n{0}; + for ( auto p : departure_points.iterate().xyz() ) { + double interpolated = output_view( n++ ); + double exact = fp( p ); + Log::info() << p << " --> " << interpolated << " [exact] " << exact << std::endl; + EXPECT( is_approximately_equal( interpolated, exact ) ); + } + } + + SECTION( "SL-like" ) { + auto matrix_free = Config( "matrix_free", true ); + + auto dp_field = fs.createField( option::variables( 3 ) ); + + { + auto iterator = departure_points.iterate().xyz().begin(); + auto iterator_end = departure_points.iterate().xyz().end(); + auto dp = array::make_view( dp_field ); + for ( idx_t n = 0; n < dp.shape( 0 ); ++n ) { + for ( idx_t k = 0; k < dp.shape( 1 ); ++k ) { + PointXYZ p{0, 0, 0}; + if ( iterator != iterator_end ) { + p = *iterator; + ++iterator; + } + dp( n, k, LON ) = p.x(); + dp( n, k, LAT ) = p.y(); + dp( n, k, ZZ ) = p.z(); + } + } + } + Interpolation interpolation( option::type( "tricubic" ) | matrix_free, fs, dp_field ); + + Field output = fs.createField(); + interpolation.execute( input, output ); + + auto output_view = array::make_view( output ); + + + auto iterator = departure_points.iterate().xyz().begin(); + auto iterator_end = departure_points.iterate().xyz().end(); + + for ( idx_t n = 0; n < output_view.shape( 0 ); ++n ) { + for ( idx_t k = 0; k < output_view.shape( 1 ); ++k ) { + PointXYZ p{0, 0, 0}; + if ( iterator != iterator_end ) { + p = *iterator; + ++iterator; + + double interpolated = output_view( n, k ); + double exact = fp( p ); + Log::info() << p << " --> " << interpolated << " [exact] " << exact << std::endl; + EXPECT( is_approximately_equal( interpolated, exact ) ); + } + } + } + } +} + +} // namespace test +} // namespace atlas + +int main( int argc, char** argv ) { + return atlas::test::run( argc, argv ); +} diff --git a/src/tests/interpolation/test_interpolation_finite_element.cc b/src/tests/interpolation/test_interpolation_finite_element.cc index 2a3c614a0..ed20dff9d 100644 --- a/src/tests/interpolation/test_interpolation_finite_element.cc +++ b/src/tests/interpolation/test_interpolation_finite_element.cc @@ -52,14 +52,14 @@ CASE( "test_interpolation_finite_element" ) { auto func = []( double x ) -> double { return std::sin( x * M_PI / 180. ); }; - Interpolation interpolation( Config( "type", "finite-element" ), fs, pointcloud ); + Interpolation interpolation( option::type( "finite-element" ), fs, pointcloud ); Field field_source = fs.createField( option::name( "source" ) ); Field field_target( "target", array::make_datatype(), array::make_shape( pointcloud.size() ) ); auto lonlat = array::make_view( fs.nodes().lonlat() ); auto source = array::make_view( field_source ); - for ( size_t j = 0; j < fs.nodes().size(); ++j ) { + for ( idx_t j = 0; j < fs.nodes().size(); ++j ) { source( j ) = func( lonlat( j, LON ) ); } @@ -70,7 +70,7 @@ CASE( "test_interpolation_finite_element" ) { auto check = std::vector{func( 00. ), func( 10. ), func( 20. ), func( 30. ), func( 40. ), func( 50. ), func( 60. ), func( 70. ), func( 80. ), func( 90. )}; - for ( size_t j = 0; j < pointcloud.size(); ++j ) { + for ( idx_t j = 0; j < pointcloud.size(); ++j ) { static double interpolation_tolerance = 1.e-4; Log::info() << target( j ) << " " << check[j] << std::endl; EXPECT( eckit::types::is_approximately_equal( target( j ), check[j], interpolation_tolerance ) ); diff --git a/src/tests/interpolation/test_interpolation_structured2D.cc b/src/tests/interpolation/test_interpolation_structured2D.cc new file mode 100644 index 000000000..2a766cc50 --- /dev/null +++ b/src/tests/interpolation/test_interpolation_structured2D.cc @@ -0,0 +1,395 @@ +/* + * (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/array.h" +#include "atlas/field/Field.h" +#include "atlas/field/FieldSet.h" +#include "atlas/functionspace/NodeColumns.h" +#include "atlas/functionspace/PointCloud.h" +#include "atlas/functionspace/StructuredColumns.h" +#include "atlas/grid/Grid.h" +#include "atlas/grid/Iterator.h" +#include "atlas/interpolation.h" +#include "atlas/library/Library.h" +#include "atlas/mesh/Mesh.h" +#include "atlas/meshgenerator.h" +#include "atlas/output/Gmsh.h" +#include "atlas/util/CoordinateEnums.h" + +#include "tests/AtlasTestEnvironment.h" + +using atlas::functionspace::NodeColumns; +using atlas::functionspace::StructuredColumns; +using atlas::util::Config; + +namespace atlas { +namespace test { + +//----------------------------------------------------------------------------- + +static Config scheme() { + Config scheme; + std::string scheme_str = eckit::Resource( "--scheme", "linear" ); + if ( scheme_str == "linear" ) { + scheme.set( "type", "structured-linear2D" ); + scheme.set( "halo", 1 ); + // The stencil does not require any halo, but we set it to 1 for pole treatment! + } + if ( scheme_str == "cubic" ) { + scheme.set( "type", "structured-cubic2D" ); + scheme.set( "halo", 2 ); + } + if ( scheme_str == "quasicubic" ) { + scheme.set( "type", "structured-quasicubic2D" ); + scheme.set( "halo", 2 ); + } + scheme.set( "name", scheme_str ); + return scheme; +} + +std::string input_gridname( const std::string& default_grid ) { + return eckit::Resource( "--input-grid", default_grid ); +} + +std::string output_gridname( const std::string& default_grid ) { + return eckit::Resource( "--output-grid", default_grid ); +} + +Grid rotated_mercator() { + Config gridspec; + gridspec.set( "type", "regional" ); + gridspec.set( "nx", 50 ); + gridspec.set( "ny", 40 ); + gridspec.set( "dx", 50000 ); + gridspec.set( "dy", 50000 ); + gridspec.set( "lonlat(centre)", std::vector{4., 50} ); + gridspec.set( "projection", [] { + Config projection; + projection.set( "type", "rotated_mercator" ); + projection.set( "north_pole", std::vector{-176., 40.} ); + return projection; + }() ); + return Grid{gridspec}; +} + +Grid lambert() { + Config gridspec; + gridspec.set( "type", "regional" ); + gridspec.set( "nx", 50 ); + gridspec.set( "ny", 40 ); + gridspec.set( "dx", 50000 ); + gridspec.set( "dy", 50000 ); + gridspec.set( "lonlat(centre)", std::vector{4., 50} ); + gridspec.set( "projection", [] { + Config projection; + projection.set( "type", "lambert" ); + projection.set( "latitude1", 50. ); + projection.set( "longitude0", 4. ); + return projection; + }() ); + return Grid{gridspec}; +} + +Grid rotated( const std::string& name ) { + Config gridspec; + gridspec.set( "name", name ); + gridspec.set( "projection", [] { + Config projection; + projection.set( "type", "rotated_lonlat" ); + projection.set( "north_pole", std::vector{-176., 40.} ); + return projection; + }() ); + return Grid{gridspec}; +} + +FunctionSpace output_functionspace( const Grid& grid ) { + MeshGenerator meshgen( "structured" ); + Mesh output_mesh = meshgen.generate( grid ); + return NodeColumns{output_mesh}; +} + +double vortex_rollup( double lon, double lat, double t ) { + // lon and lat in degrees! + + // Formula found in "A Lagrangian Particle Method with Remeshing for Tracer Transport on the Sphere" + // by Peter Bosler, James Kent, Robert Krasny, CHristiane Jablonowski, JCP 2015 + + lon *= M_PI / 180.; + lat *= M_PI / 180.; + + auto sqr = []( const double x ) { return x * x; }; + auto sech = []( const double x ) { return 1. / std::cosh( x ); }; + const double T = 1.; + const double Omega = 2. * M_PI / T; + t *= T; + const double lambda_prime = std::atan2( -std::cos( lon - Omega * t ), std::tan( lat ) ); + const double rho = 3. * std::sqrt( 1. - sqr( std::cos( lat ) ) * sqr( std::sin( lon - Omega * t ) ) ); + double omega = 0.; + double a = util::Earth::radius(); + if ( rho != 0. ) { omega = 0.5 * 3 * std::sqrt( 3 ) * a * Omega * sqr( sech( rho ) ) * std::tanh( rho ) / rho; } + double q = 1. - std::tanh( 0.2 * rho * std::sin( lambda_prime - omega / a * t ) ); + return q; +}; + +CASE( "which scheme?" ) { + Log::info() << scheme().getString( "type" ) << std::endl; +} + +CASE( "test_interpolation_structured using functionspace API" ) { + Grid grid( input_gridname( "O32" ) ); + + // Cubic interpolation requires a StructuredColumns functionspace with 2 halos + StructuredColumns input_fs( grid, scheme() ); + + auto test = [&]( const FunctionSpace& output_fs ) { + // The output functionspace can currently be either NodeColumns or PointCloud + + Interpolation interpolation( scheme(), input_fs, output_fs ); + + Field field_source = input_fs.createField( option::name( "source" ) ); + Field field_target = output_fs.createField( option::name( "target" ) ); + + auto lonlat = array::make_view( input_fs.xy() ); + auto source = array::make_view( field_source ); + for ( idx_t n = 0; n < input_fs.size(); ++n ) { + source( n ) = vortex_rollup( lonlat( n, LON ), lonlat( n, LAT ), 1. ); + } + + EXPECT( field_source.dirty() ); + + interpolation.execute( field_source, field_target ); + }; + + SECTION( "Interpolate from " + grid.name() + " to " + output_gridname( "O64" ) ) { + EXPECT_NO_THROW( test( output_functionspace( Grid{output_gridname( "O64" )} ) ) ); + } + SECTION( "Interpolate from " + grid.name() + " to rotated " + output_gridname( "O64" ) ) { + EXPECT_NO_THROW( test( output_functionspace( rotated( output_gridname( "O64" ) ) ) ) ); + } + SECTION( "Interpolate from " + grid.name() + " to lambert" ) { + EXPECT_NO_THROW( test( output_functionspace( lambert() ) ) ); + } + SECTION( "Interpolate from " + grid.name() + " to rotaded_mercator" ) { + EXPECT_NO_THROW( test( output_functionspace( rotated_mercator() ) ) ); + } +} + +CASE( "test_interpolation_structured using grid API" ) { + // Using the grid API we can hide interpolation method specific requirements + // such as which functionspace needs to be set-up. + // Currently the assumption is that grids are serial + + Grid input_grid( input_gridname( "O32" ) ); + + auto test = [&]( const Grid& output_grid ) { + Interpolation interpolation( scheme(), input_grid, output_grid ); + + // Allocate and initialise own memory here to show possibilities + // Note that allocated size must be possibly enlarged depending on interpolation method + // allocates stencil halo + std::vector src_data( interpolation.source().size() ); + std::vector tgt_data( interpolation.target().size() ); + + idx_t n{0}; + for ( auto p : input_grid.lonlat() ) { + src_data[n++] = vortex_rollup( p.lon(), p.lat(), 1. ); + } + + // Wrap memory in atlas Fields and interpolate + Field field_source{"source", src_data.data(), array::make_shape( src_data.size() )}; + Field field_target{"target", tgt_data.data(), array::make_shape( tgt_data.size() )}; + + // Wrapping data does not set the field to have dirty halo's + { + EXPECT( not field_source.dirty() ); + field_source.set_dirty(); + } + + EXPECT( field_source.dirty() ); + interpolation.execute( field_source, field_target ); + + ATLAS_TRACE_SCOPE( "output" ) { + output::Gmsh gmsh( + scheme().getString( "name" ) + "-output-section" + std::to_string( _subsection ) + ".msh", + Config( "coordinates", "xy" ) ); + gmsh.write( MeshGenerator( "structured" ).generate( output_grid ) ); + gmsh.write( field_target, StructuredColumns( output_grid ) ); + } + }; + + SECTION( "Interpolate from " + input_grid.name() + " to " + output_gridname( "O64" ) ) { + EXPECT_NO_THROW( test( Grid{output_gridname( "O64" )} ) ); + } + SECTION( "Interpolate from " + input_grid.name() + " to rotated " + output_gridname( "O64" ) ) { + EXPECT_NO_THROW( test( rotated( output_gridname( "O64" ) ) ) ); + } + SECTION( "Interpolate from " + input_grid.name() + " to lambert" ) { + ; + EXPECT_NO_THROW( test( lambert() ) ); + } + SECTION( "Interpolate from " + input_grid.name() + " to rotaded_mercator" ) { + EXPECT_NO_THROW( test( rotated_mercator() ) ); + } +} + +CASE( "test_interpolation_structured using fs API multiple levels" ) { + Grid input_grid( input_gridname( "O32" ) ); + Grid output_grid( output_gridname( "O64" ) ); + + // Cubic interpolation requires a StructuredColumns functionspace with 2 halos + StructuredColumns input_fs( input_grid, scheme() | option::levels( 3 ) ); + + MeshGenerator meshgen( "structured" ); + Mesh output_mesh = meshgen.generate( output_grid ); + FunctionSpace output_fs = NodeColumns{output_mesh, option::levels( 3 )}; + + Interpolation interpolation( scheme(), input_fs, output_fs ); + + Field field_source = input_fs.createField( option::name( "source" ) ); + Field field_target = output_fs.createField( option::name( "target" ) ); + + auto lonlat = array::make_view( input_fs.xy() ); + auto source = array::make_view( field_source ); + for ( idx_t n = 0; n < input_fs.size(); ++n ) { + for ( idx_t k = 0; k < 3; ++k ) { + source( n, k ) = vortex_rollup( lonlat( n, LON ), lonlat( n, LAT ), 0.5 + double( k ) / 2 ); + } + }; + interpolation.execute( field_source, field_target ); + + ATLAS_TRACE_SCOPE( "output" ) { + output::Gmsh gmsh( + scheme().getString( "name" ) + "-multilevel-output-section" + std::to_string( _subsection ) + ".msh", + Config( "coordinates", "xy" ) ); + gmsh.write( output_mesh ); + output_fs.haloExchange( field_target ); + gmsh.write( field_target ); + } +} + +CASE( "test_interpolation_structured using fs API for fieldset" ) { + Grid input_grid( input_gridname( "O32" ) ); + Grid output_grid( output_gridname( "O64" ) ); + + // Cubic interpolation requires a StructuredColumns functionspace with 2 halos + StructuredColumns input_fs( input_grid, scheme() | option::levels( 3 ) ); + + MeshGenerator meshgen( "structured" ); + Mesh output_mesh = meshgen.generate( output_grid ); + FunctionSpace output_fs = NodeColumns{output_mesh, option::levels( 3 )}; + + auto lonlat = array::make_view( input_fs.xy() ); + + FieldSet fields_source; + FieldSet fields_target; + using Value = float; + for ( idx_t f = 0; f < 3; ++f ) { + auto field_source = fields_source.add( input_fs.createField() ); + fields_target.add( output_fs.createField() ); + + auto source = array::make_view( field_source ); + for ( idx_t n = 0; n < input_fs.size(); ++n ) { + for ( idx_t k = 0; k < 3; ++k ) { + source( n, k ) = vortex_rollup( lonlat( n, LON ), lonlat( n, LAT ), 0.5 + double( k ) / 2 ); + } + }; + } + + SECTION( "with matrix" ) { + Interpolation interpolation( scheme(), input_fs, output_fs ); + interpolation.execute( fields_source, fields_target ); + + ATLAS_TRACE_SCOPE( "output" ) { + output::Gmsh gmsh( scheme().getString( "name" ) + "-multilevel-fieldset-output-section" + + std::to_string( _subsection ) + ".msh", + Config( "coordinates", "xy" ) ); + gmsh.write( output_mesh ); + output_fs.haloExchange( fields_target ); + gmsh.write( fields_target ); + } + } + + + SECTION( "matrix free" ) { + Interpolation interpolation( scheme() | Config( "matrix_free", true ), input_fs, output_fs ); + interpolation.execute( fields_source, fields_target ); + ATLAS_TRACE_SCOPE( "output" ) { + output::Gmsh gmsh( scheme().getString( "name" ) + "-multilevel-fieldset-output-section" + + std::to_string( _subsection ) + ".msh", + Config( "coordinates", "xy" ) ); + gmsh.write( output_mesh ); + output_fs.haloExchange( fields_target ); + gmsh.write( fields_target ); + } + } +} + + +/// @brief Compute magnitude of flow with rotation-angle beta +/// (beta=0 --> zonal, beta=pi/2 --> meridional) +Field rotated_flow( const StructuredColumns& fs, const double& beta ) { + const double radius = util::Earth::radius(); + const double USCAL = 20.; + const double pvel = USCAL / radius; + const double deg2rad = M_PI / 180.; + + array::ArrayView lonlat_deg = array::make_view( fs.xy() ); + + Field field = fs.createField( option::vector() ); + array::ArrayView var = array::make_view( field ); + + idx_t nnodes = var.shape( 0 ); + for ( idx_t jnode = 0; jnode < nnodes; ++jnode ) { + double x = lonlat_deg( jnode, LON ) * deg2rad; + double y = lonlat_deg( jnode, LAT ) * deg2rad; + double Ux = + pvel * ( std::cos( beta ) + std::tan( y ) * std::cos( x ) * std::sin( beta ) ) * radius * std::cos( y ); + double Uy = -pvel * std::sin( x ) * std::sin( beta ) * radius; + var( jnode, LON ) = Ux; + var( jnode, LAT ) = Uy; + } + return field; +} + +CASE( "test_interpolation_structured for vectors" ) { + Grid input_grid( input_gridname( "O32" ) ); + Grid output_grid( output_gridname( "O64" ) ); + + // Cubic interpolation requires a StructuredColumns functionspace with 2 halos + StructuredColumns input_fs( input_grid, option::halo( 2 ) ); + + MeshGenerator meshgen( "structured" ); + Mesh output_mesh = meshgen.generate( output_grid ); + FunctionSpace output_fs = NodeColumns{output_mesh}; + + Interpolation interpolation( scheme(), input_fs, output_fs ); + + Field field_source = rotated_flow( input_fs, M_PI_4 ); + Field field_target = output_fs.createField( option::name( "target" ) | option::vector() ); + + interpolation.execute( field_source, field_target ); + + ATLAS_TRACE_SCOPE( "output" ) { + output::Gmsh gmsh( + scheme().getString( "name" ) + "-vector-output-section" + std::to_string( _subsection ) + ".msh", + Config( "coordinates", "xy" ) ); + gmsh.write( output_mesh ); + output_fs.haloExchange( field_target ); + gmsh.write( field_target ); + } +} + + +} // namespace test +} // namespace atlas + +int main( int argc, char** argv ) { + return atlas::test::run( argc, argv ); +} diff --git a/src/tests/io/test_pointcloud_io.cc b/src/tests/io/test_pointcloud_io.cc index e45996df1..29cbe9106 100644 --- a/src/tests/io/test_pointcloud_io.cc +++ b/src/tests/io/test_pointcloud_io.cc @@ -9,10 +9,9 @@ */ #include +#include #include -#include "eckit/exception/Exceptions.h" -#include "eckit/memory/ScopedPtr.h" #include "eckit/types/FloatCompare.h" #include "atlas/array/MakeView.h" @@ -103,7 +102,7 @@ CASE( "read_inexistent_file" ) { CASE( "read_badly_formatted_file" ) { EXPECT( test_write_file_bad( "pointcloud.txt" ) ); - EXPECT_THROWS_AS( output::detail::PointCloudIO::read( "pointcloud.txt" ), eckit::BadParameter ); + EXPECT_THROWS_AS( output::detail::PointCloudIO::read( "pointcloud.txt" ), eckit::Exception ); } CASE( "read_grid_sample_file" ) { @@ -323,7 +322,7 @@ CASE( "write_read_write_field" ) { /* data read from file*/ field.size() ); array::ArrayView field_data = array::make_view( field ); - for ( size_t i = 0; i < field_data.size(); ++i ) { + for ( idx_t i = 0; i < field_data.size(); ++i ) { EXPECT( eckit::types::is_approximately_equal( funny_formula( i ), field_data( i ), 0.001 ) ); // 0.001% relative error EXPECT( eckit::types::is_approximately_equal( funny_formula( i ), field_data( i ), diff --git a/src/tests/mesh/CMakeLists.txt b/src/tests/mesh/CMakeLists.txt index c6c06d349..5e43f0824 100644 --- a/src/tests/mesh/CMakeLists.txt +++ b/src/tests/mesh/CMakeLists.txt @@ -38,21 +38,21 @@ endif() ecbuild_add_test( TARGET atlas_test_parfields MPI 2 - CONDITION ECKIT_HAVE_MPI AND TRANSI_HAVE_MPI + CONDITION ECKIT_HAVE_MPI SOURCES test_parfields.cc LIBS atlas ) ecbuild_add_test( TARGET atlas_test_halo MPI 5 - CONDITION ECKIT_HAVE_MPI AND TRANSI_HAVE_MPI + CONDITION ECKIT_HAVE_MPI SOURCES test_halo.cc ../TestMeshes.h LIBS atlas ) ecbuild_add_test( TARGET atlas_test_distmesh MPI 5 - CONDITION ECKIT_HAVE_MPI AND TRANSI_HAVE_MPI + CONDITION ECKIT_HAVE_MPI SOURCES test_distmesh.cc ../TestMeshes.h LIBS atlas ) diff --git a/src/tests/mesh/fctest_connectivity.F90 b/src/tests/mesh/fctest_connectivity.F90 index 8c5577814..73e283393 100644 --- a/src/tests/mesh/fctest_connectivity.F90 +++ b/src/tests/mesh/fctest_connectivity.F90 @@ -26,12 +26,13 @@ #if 1 use fckit_module use atlas_connectivity_module + use atlas_kinds_module use, intrinsic :: iso_c_binding implicit none type(atlas_Connectivity) :: connectivity - integer(c_int), pointer :: padded(:,:), row(:), data(:,:) - integer(c_size_t), pointer :: cols(:) + integer(ATLAS_KIND_IDX), pointer :: padded(:,:), row(:), data(:,:) + integer(ATLAS_KIND_IDX), pointer :: cols(:) integer(c_int) :: ncols call fckit_log%info("test_connectivity starting") @@ -41,16 +42,16 @@ FCTEST_CHECK_EQUAL(connectivity%name(),"hybrid") - FCTEST_CHECK_EQUAL(connectivity%rows(),0_c_size_t) + FCTEST_CHECK_EQUAL(connectivity%rows(),0) FCTEST_CHECK_EQUAL(connectivity%missing_value(),0) call connectivity%add(2,4, & & [ 1, 2, 3, 4, & & 5, 6, 7, 8 ] ) - FCTEST_CHECK_EQUAL(connectivity%mincols(),4_c_size_t) - FCTEST_CHECK_EQUAL(connectivity%maxcols(),4_c_size_t) - FCTEST_CHECK_EQUAL(connectivity%rows(), 2_c_size_t) + FCTEST_CHECK_EQUAL(connectivity%mincols(),4) + FCTEST_CHECK_EQUAL(connectivity%maxcols(),4) + FCTEST_CHECK_EQUAL(connectivity%rows(), 2) call connectivity%data(data,ncols) @@ -68,9 +69,9 @@ & [ 9, 10, 11, & & 12, 13, 14 ] ) - FCTEST_CHECK_EQUAL(connectivity%mincols(),3_c_size_t) - FCTEST_CHECK_EQUAL(connectivity%maxcols(),4_c_size_t) - FCTEST_CHECK_EQUAL(connectivity%rows(), 4_c_size_t) + FCTEST_CHECK_EQUAL(connectivity%mincols(),3) + FCTEST_CHECK_EQUAL(connectivity%maxcols(),4) + FCTEST_CHECK_EQUAL(connectivity%rows(), 4) call connectivity%add(2,4) call connectivity%add(2,3) @@ -167,13 +168,14 @@ TEST( test_multiblockconnectivity ) use fckit_module use atlas_connectivity_module + use atlas_kinds_module use, intrinsic :: iso_c_binding implicit none type(atlas_MultiBlockConnectivity) :: multiblock type(atlas_BlockConnectivity) :: block - integer(c_int), pointer :: data(:,:), padded(:,:) - integer(c_size_t), pointer :: cols(:) + integer(ATLAS_KIND_IDX), pointer :: data(:,:), padded(:,:) + integer(ATLAS_KIND_IDX), pointer :: cols(:) type(atlas_Connectivity) :: base @@ -183,31 +185,31 @@ FCTEST_CHECK_EQUAL( multiblock%owners(), 1 ) FCTEST_CHECK_EQUAL(multiblock%name(),"") - FCTEST_CHECK_EQUAL(multiblock%rows(),0_c_size_t) - FCTEST_CHECK_EQUAL(multiblock%blocks(),0_c_size_t) + FCTEST_CHECK_EQUAL(multiblock%rows(),0) + FCTEST_CHECK_EQUAL(multiblock%blocks(),0) call multiblock%add(2,4, & & [ 1, 2, 3, 4, & & 5, 6, 7, 8 ] ) - FCTEST_CHECK_EQUAL(multiblock%mincols(),4_c_size_t) - FCTEST_CHECK_EQUAL(multiblock%maxcols(),4_c_size_t) - FCTEST_CHECK_EQUAL(multiblock%rows(), 2_c_size_t) - FCTEST_CHECK_EQUAL(multiblock%blocks(), 1_c_size_t) + FCTEST_CHECK_EQUAL(multiblock%mincols(),4) + FCTEST_CHECK_EQUAL(multiblock%maxcols(),4) + FCTEST_CHECK_EQUAL(multiblock%rows(), 2) + FCTEST_CHECK_EQUAL(multiblock%blocks(), 1) call multiblock%add(2,3, & & [ 9, 10, 11, & & 12, 13, 14 ] ) - FCTEST_CHECK_EQUAL(multiblock%mincols(),3_c_size_t) - FCTEST_CHECK_EQUAL(multiblock%maxcols(),4_c_size_t) - FCTEST_CHECK_EQUAL(multiblock%blocks(), 2_c_size_t) + FCTEST_CHECK_EQUAL(multiblock%mincols(),3) + FCTEST_CHECK_EQUAL(multiblock%maxcols(),4) + FCTEST_CHECK_EQUAL(multiblock%blocks(), 2) - block = multiblock%block(1_c_size_t) + block = multiblock%block(1_ATLAS_KIND_IDX) !FCTEST_CHECK_EQUAL( block%owners(), 2 ) - FCTEST_CHECK_EQUAL( block%rows(), 2_c_size_t ) - FCTEST_CHECK_EQUAL( block%cols(), 4_c_size_t ) + FCTEST_CHECK_EQUAL( block%rows(), 2 ) + FCTEST_CHECK_EQUAL( block%cols(), 4 ) call block%data(data) FCTEST_CHECK_EQUAL(data(1,1), 1) @@ -219,11 +221,11 @@ FCTEST_CHECK_EQUAL(data(3,2), 7) FCTEST_CHECK_EQUAL(data(4,2), 8) - block = multiblock%block(2_c_size_t) + block = multiblock%block(2_ATLAS_KIND_IDX) !FCTEST_CHECK_EQUAL( block%owners(), 2 ) - FCTEST_CHECK_EQUAL( block%rows(), 2_c_size_t ) - FCTEST_CHECK_EQUAL( block%cols(), 3_c_size_t ) + FCTEST_CHECK_EQUAL( block%rows(), 2 ) + FCTEST_CHECK_EQUAL( block%cols(), 3 ) call block%data(data) FCTEST_CHECK_EQUAL(data(1,1), 9) diff --git a/src/tests/mesh/fctest_elements.F90 b/src/tests/mesh/fctest_elements.F90 index 0c50d95ae..60fb503d7 100644 --- a/src/tests/mesh/fctest_elements.F90 +++ b/src/tests/mesh/fctest_elements.F90 @@ -41,7 +41,7 @@ use atlas_Elements_module use atlas_connectivity_module use atlas_field_module - use, intrinsic :: iso_c_binding + use atlas_kinds_module implicit none type(atlas_mesh_Cells) :: cells @@ -49,18 +49,18 @@ type(atlas_Field) :: field, field2 type(atlas_Elements) :: elements type(atlas_ElementType) :: element_type - integer(c_int), pointer :: data(:,:) - integer(c_size_t) :: jfield + integer(ATLAS_KIND_IDX), pointer :: data(:,:) + integer(ATLAS_KIND_IDX) :: jfield write(*,*) "test_hybridelements starting" cells = atlas_mesh_Cells() FCTEST_CHECK_EQUAL( cells%owners(), 1 ) - FCTEST_CHECK_EQUAL( cells%size(), 0_c_size_t ) + FCTEST_CHECK_EQUAL( cells%size(), 0 ) node_connectivity = cells%node_connectivity() FCTEST_CHECK_EQUAL( node_connectivity%owners(), 2 ) - FCTEST_CHECK_EQUAL( node_connectivity%rows(), 0_c_size_t ) + FCTEST_CHECK_EQUAL( node_connectivity%rows(), 0 ) FCTEST_CHECK( cells%has_field("glb_idx") ) FCTEST_CHECK( cells%has_field("partition") ) FCTEST_CHECK( cells%has_field("remote_idx") ) @@ -95,7 +95,7 @@ - call cells%add( atlas_Triangle(), 5_c_size_t , & + call cells%add( atlas_Triangle(), 5 , & & [ 1, 2 ,3, & & 4, 5, 6, & & 7, 8, 9, & @@ -103,10 +103,10 @@ & 13, 14, 15 ] ) - FCTEST_CHECK_EQUAL( cells%size(), 5_c_size_t ) - FCTEST_CHECK_EQUAL( cells%nb_types(), 1_c_size_t ) - FCTEST_CHECK_EQUAL( node_connectivity%rows(), 5_c_size_t ) - FCTEST_CHECK_EQUAL( node_connectivity%maxcols(), 3_c_size_t ) + FCTEST_CHECK_EQUAL( cells%size(), 5 ) + FCTEST_CHECK_EQUAL( cells%nb_types(), 1 ) + FCTEST_CHECK_EQUAL( node_connectivity%rows(), 5 ) + FCTEST_CHECK_EQUAL( node_connectivity%maxcols(), 3 ) call node_connectivity%data(data) @@ -126,19 +126,19 @@ FCTEST_CHECK_EQUAL( data(2,5) , 14 ) FCTEST_CHECK_EQUAL( data(3,5) , 15 ) - call cells%add( atlas_Quadrilateral(), 2_c_size_t , & + call cells%add( atlas_Quadrilateral(), 2 , & & [ 16, 17, 18, 19, & & 20, 21, 22, 23 ] ) - FCTEST_CHECK_EQUAL( cells%nb_types(), 2_c_size_t ) - FCTEST_CHECK_EQUAL( cells%size(), 7_c_size_t ) - FCTEST_CHECK_EQUAL( node_connectivity%rows(), 7_c_size_t ) - FCTEST_CHECK_EQUAL( node_connectivity%mincols(), 3_c_size_t ) - FCTEST_CHECK_EQUAL( node_connectivity%maxcols(), 4_c_size_t ) + FCTEST_CHECK_EQUAL( cells%nb_types(), 2 ) + FCTEST_CHECK_EQUAL( cells%size(), 7 ) + FCTEST_CHECK_EQUAL( node_connectivity%rows(), 7 ) + FCTEST_CHECK_EQUAL( node_connectivity%mincols(), 3 ) + FCTEST_CHECK_EQUAL( node_connectivity%maxcols(), 4 ) elements = cells%elements(1) FCTEST_CHECK_EQUAL( elements%owners(), 2 ) - FCTEST_CHECK_EQUAL( elements%size(), 5_c_size_t ) + FCTEST_CHECK_EQUAL( elements%size(), 5 ) element_type = elements%element_type() ! Should print ERROR @@ -177,6 +177,7 @@ use atlas_Elements_module use atlas_connectivity_module use atlas_field_module + use atlas_kinds_module use, intrinsic :: iso_c_binding implicit none @@ -184,26 +185,26 @@ type(atlas_BlockConnectivity) :: node_connectivity type(atlas_Elements) :: elements type(atlas_ElementType) :: element_type - integer(c_int), pointer :: data(:,:) + integer(ATLAS_KIND_IDX), pointer :: data(:,:) write(*,*) "test_elements starting" cells = atlas_mesh_Cells() - call cells%add( atlas_Triangle(), 5_c_size_t , & + call cells%add( atlas_Triangle(), 5 , & & [ 1, 2 ,3, & & 4, 5, 6, & & 7, 8, 9, & & 10, 11, 12, & & 13, 14, 15 ] ) - call cells%add( atlas_Quadrilateral(), 2_c_size_t , & + call cells%add( atlas_Quadrilateral(), 2 , & & [ 16, 17, 18, 19, & & 20, 21, 22, 23 ] ) elements = cells%elements(1) - FCTEST_CHECK_EQUAL( elements%begin(), 1_c_size_t ) - FCTEST_CHECK_EQUAL( elements%end(), 5_c_size_t ) + FCTEST_CHECK_EQUAL( elements%begin(), 1 ) + FCTEST_CHECK_EQUAL( elements%end(), 5 ) element_type = elements%element_type() FCTEST_CHECK_EQUAL( element_type%owners(), 2 ) @@ -211,8 +212,8 @@ node_connectivity = elements%node_connectivity() !FCTEST_CHECK_EQUAL( node_connectivity%owners(), 2 ) - FCTEST_CHECK_EQUAL( element_type%nb_nodes(), 3_c_size_t ) - FCTEST_CHECK_EQUAL( element_type%nb_edges(), 3_c_size_t ) + FCTEST_CHECK_EQUAL( element_type%nb_nodes(), 3 ) + FCTEST_CHECK_EQUAL( element_type%nb_edges(), 3 ) FCTEST_CHECK_EQUAL( element_type%name(), "Triangle" ) FCTEST_CHECK( element_type%parametric() ) @@ -237,14 +238,14 @@ elements = cells%elements(2) - FCTEST_CHECK_EQUAL( elements%begin(), 6_c_size_t ) - FCTEST_CHECK_EQUAL( elements%end(), 7_c_size_t ) + FCTEST_CHECK_EQUAL( elements%begin(), 6 ) + FCTEST_CHECK_EQUAL( elements%end(), 7 ) element_type = elements%element_type() FCTEST_CHECK_EQUAL( element_type%owners(), 2 ) - FCTEST_CHECK_EQUAL( element_type%nb_nodes(), 4_c_size_t ) - FCTEST_CHECK_EQUAL( element_type%nb_edges(), 4_c_size_t ) + FCTEST_CHECK_EQUAL( element_type%nb_nodes(), 4 ) + FCTEST_CHECK_EQUAL( element_type%nb_edges(), 4 ) FCTEST_CHECK_EQUAL( element_type%name(), "Quadrilateral" ) FCTEST_CHECK( element_type%parametric() ) @@ -268,8 +269,8 @@ ! Add elements to triangles elements = cells%elements(1) call elements%add(2) - FCTEST_CHECK_EQUAL( elements%begin(), 1_c_size_t ) - FCTEST_CHECK_EQUAL( elements%end(), 7_c_size_t ) + FCTEST_CHECK_EQUAL( elements%begin(), 1 ) + FCTEST_CHECK_EQUAL( elements%end(), 7 ) node_connectivity = elements%node_connectivity() call node_connectivity%data(data) @@ -283,8 +284,8 @@ elements = cells%elements(2) - FCTEST_CHECK_EQUAL( elements%begin(), 8_c_size_t ) - FCTEST_CHECK_EQUAL( elements%end(), 9_c_size_t ) + FCTEST_CHECK_EQUAL( elements%begin(), 8 ) + FCTEST_CHECK_EQUAL( elements%end(), 9 ) call elements%final() diff --git a/src/tests/mesh/fctest_mesh.F90 b/src/tests/mesh/fctest_mesh.F90 index 01d937808..c7f28a9da 100644 --- a/src/tests/mesh/fctest_mesh.F90 +++ b/src/tests/mesh/fctest_mesh.F90 @@ -51,13 +51,13 @@ end module fcta_Mesh_fixture nodes = mesh%nodes() nb_nodes = nodes%size() FCTEST_CHECK_EQUAL( nb_nodes, 0 ) - FCTEST_CHECK_EQUAL( nodes%size() , 0_c_size_t ) + FCTEST_CHECK_EQUAL( nodes%size() , 0 ) FCTEST_CHECK( nodes%has_field("partition") ) FCTEST_CHECK( nodes%has_field("remote_idx") ) - call nodes%resize(10_c_size_t) + call nodes%resize(10) nb_nodes = nodes%size() FCTEST_CHECK_EQUAL( nb_nodes, 10 ) - FCTEST_CHECK_EQUAL( nodes%size() , 10_c_size_t ) + FCTEST_CHECK_EQUAL( nodes%size() , 10 ) call atlas_log%info( nodes%str() ) call mesh%final() diff --git a/src/tests/mesh/fctest_meshgen.F90 b/src/tests/mesh/fctest_meshgen.F90 index b0b67c071..24fe03064 100644 --- a/src/tests/mesh/fctest_meshgen.F90 +++ b/src/tests/mesh/fctest_meshgen.F90 @@ -135,9 +135,10 @@ type(atlas_mesh_Edges) :: edges type(atlas_Field) :: field type(atlas_functionspace_NodeColumns) :: functionspace_nodes + type(atlas_functionspace_EdgeColumns) :: functionspace_edges type(atlas_HaloExchange) :: halo_exchange type(atlas_Output) :: gmsh - integer(c_int), pointer :: ridx(:) + integer(ATLAS_KIND_IDX), pointer :: ridx(:) real(c_double), pointer :: arr1d(:), arr2d(:,:) integer :: i, nnodes, nghost @@ -151,15 +152,14 @@ nodes = mesh%nodes() call meshgenerator%final() - call atlas_build_parallel_fields(mesh) - call atlas_build_periodic_boundaries(mesh) - call atlas_build_halo(mesh,1) - call atlas_build_edges(mesh) - call atlas_build_pole_edges(mesh) + functionspace_edges = atlas_functionspace_EdgeColumns(mesh,halo=1) + functionspace_nodes = atlas_functionspace_NodeColumns(mesh,halo=1) call atlas_build_median_dual_mesh(mesh) nnodes = nodes%size() + FCTEST_CHECK_EQUAL( nnodes, 3672 ) + field = nodes%field("remote_idx") call field%data(ridx) nghost = 0 @@ -169,6 +169,8 @@ write(0,*) "nghost =",nghost + FCTEST_CHECK_EQUAL( nghost, 144 ) + call atlas_log%info( nodes%str() ) @@ -180,12 +182,12 @@ halo_exchange = functionspace_nodes%get_halo_exchange() call halo_exchange%execute(arr1d) + edges = mesh%edges() field = edges%field("dual_normals") call field%data(arr2d) call field%final() - - gmsh = atlas_output_Gmsh("testf2.msh") + gmsh = atlas_output_Gmsh("testf2.msh",ghost=.true.) call gmsh%write(mesh) call atlas_write_load_balance_report(mesh,"N24_loadbalance.dat") diff --git a/src/tests/mesh/test_accumulate_facets.cc b/src/tests/mesh/test_accumulate_facets.cc index d02eecce6..e4f88c6a2 100644 --- a/src/tests/mesh/test_accumulate_facets.cc +++ b/src/tests/mesh/test_accumulate_facets.cc @@ -15,7 +15,8 @@ #include "atlas/mesh/Mesh.h" #include "atlas/mesh/actions/BuildEdges.h" #include "atlas/mesh/detail/AccumulateFacets.h" -#include "atlas/meshgenerator/StructuredMeshGenerator.h" +#include "atlas/meshgenerator.h" +#include "atlas/option.h" #include "atlas/util/Unique.h" #include "tests/AtlasTestEnvironment.h" @@ -30,8 +31,7 @@ namespace test { CASE( "test_accumulate_facets" ) { Grid grid( "O2" ); - meshgenerator::StructuredMeshGenerator generator( - Config( "angle", 29.0 )( "triangulate", false )( "ghost_at_end", false ) ); + StructuredMeshGenerator generator( Config( "angle", 29.0 )( "triangulate", false )( "ghost_at_end", false ) ); Mesh mesh = generator.generate( grid ); @@ -41,8 +41,8 @@ CASE( "test_accumulate_facets" ) { // storage for edge-to-cell-connectivity shape=(nb_edges,2) std::vector edge_to_cell_data; - size_t nb_edges; - size_t nb_inner_edges; + idx_t nb_edges; + idx_t nb_inner_edges; idx_t missing_value; // Accumulate facets of cells ( edges in 2D ) @@ -242,12 +242,11 @@ CASE( "test_accumulate_facets" ) { CASE( "test_build_edges" ) { idx_t missing_value = -1; Grid grid( "O2" ); - meshgenerator::StructuredMeshGenerator generator( - Config( "angle", 29.0 )( "triangulate", false )( "ghost_at_end", false ) ); + StructuredMeshGenerator generator( Config( "angle", 29.0 )( "triangulate", false )( "ghost_at_end", false ) ); Mesh mesh = generator.generate( grid ); // Accumulate facets of cells ( edges in 2D ) - mesh::actions::build_edges( mesh ); + mesh::actions::build_edges( mesh, option::pole_edges( false ) ); idx_t edge_nodes_check[] = { 0, 21, 21, 22, 22, 1, 1, 0, 22, 23, 23, 2, 2, 1, 3, 25, 25, 26, 26, 4, 4, 3, 26, 27, 27, 5, 5, @@ -268,7 +267,7 @@ CASE( "test_build_edges" ) { const mesh::HybridElements::Connectivity& edge_node_connectivity = mesh.edges().node_connectivity(); EXPECT( mesh.projection().units() == "degrees" ); const util::UniqueLonLat compute_uid( mesh ); - for ( size_t jedge = 0; jedge < mesh.edges().size(); ++jedge ) { + for ( idx_t jedge = 0; jedge < mesh.edges().size(); ++jedge ) { if ( compute_uid( edge_nodes_check[2 * jedge + 0] ) < compute_uid( edge_nodes_check[2 * jedge + 1] ) ) { EXPECT( edge_nodes_check[2 * jedge + 0] == edge_node_connectivity( jedge, 0 ) ); EXPECT( edge_nodes_check[2 * jedge + 1] == edge_node_connectivity( jedge, 1 ) ); @@ -456,7 +455,7 @@ CASE( "test_build_edges" ) { const mesh::HybridElements::Connectivity& cell_node_connectivity = mesh.cells().node_connectivity(); const mesh::HybridElements::Connectivity& edge_cell_connectivity = mesh.edges().cell_connectivity(); const util::UniqueLonLat compute_uid( mesh ); - for ( size_t jedge = 0; jedge < mesh.edges().size(); ++jedge ) { + for ( idx_t jedge = 0; jedge < mesh.edges().size(); ++jedge ) { idx_t e1 = edge_to_cell_check[2 * jedge + 0]; idx_t e2 = edge_to_cell_check[2 * jedge + 1]; if ( e2 == edge_cell_connectivity.missing_value() || @@ -474,9 +473,9 @@ CASE( "test_build_edges" ) { { const MultiBlockConnectivity& elem_edge_connectivity = mesh.cells().edge_connectivity(); - for ( size_t jelem = 0; jelem < mesh.cells().size(); ++jelem ) { + for ( idx_t jelem = 0; jelem < mesh.cells().size(); ++jelem ) { std::cout << jelem << " : "; - for ( size_t jedge = 0; jedge < elem_edge_connectivity.cols( jelem ); ++jedge ) { + for ( idx_t jedge = 0; jedge < elem_edge_connectivity.cols( jelem ); ++jedge ) { std::cout << elem_edge_connectivity( jelem, jedge ) << " "; } std::cout << std::endl; @@ -486,23 +485,28 @@ CASE( "test_build_edges" ) { CASE( "test_build_edges_triangles_only" ) { Grid grid( "O2" ); - meshgenerator::StructuredMeshGenerator generator( - Config( "angle", 29.0 )( "triangulate", false )( "ghost_at_end", false ) ); + StructuredMeshGenerator generator( Config( "angle", 29.0 )( "triangulate", true )( "ghost_at_end", false ) ); Mesh mesh = generator.generate( grid ); // Accumulate facets of cells ( edges in 2D ) - mesh::actions::build_edges( mesh ); + mesh::actions::build_edges( mesh, option::pole_edges( false ) ); { const MultiBlockConnectivity& elem_edge_connectivity = mesh.cells().edge_connectivity(); - for ( size_t jelem = 0; jelem < mesh.cells().size(); ++jelem ) { - std::cout << jelem << " : "; - for ( size_t jedge = 0; jedge < elem_edge_connectivity.cols( jelem ); ++jedge ) { + const MultiBlockConnectivity& elem_node_connectivity = mesh.cells().node_connectivity(); + for ( idx_t jelem = 0; jelem < mesh.cells().size(); ++jelem ) { + std::cout << jelem << " : edges ( "; + for ( idx_t jedge = 0; jedge < elem_edge_connectivity.cols( jelem ); ++jedge ) { std::cout << elem_edge_connectivity( jelem, jedge ) << " "; } - std::cout << std::endl; + std::cout << ") | nodes ( "; + for ( idx_t jnode = 0; jnode < elem_node_connectivity.cols( jelem ); ++jnode ) { + std::cout << elem_node_connectivity( jelem, jnode ) << " "; + } + std::cout << ")" << std::endl; } } + std::cout << "( if you see all -1 entries, those are patch elements at the pole )" << std::endl; } //----------------------------------------------------------------------------- diff --git a/src/tests/mesh/test_cgal_mesh_gen_from_points.cc b/src/tests/mesh/test_cgal_mesh_gen_from_points.cc index 73e5c6e99..84d7bd680 100644 --- a/src/tests/mesh/test_cgal_mesh_gen_from_points.cc +++ b/src/tests/mesh/test_cgal_mesh_gen_from_points.cc @@ -18,7 +18,7 @@ #include "atlas/library/Library.h" #include "atlas/library/config.h" #include "atlas/mesh/Mesh.h" -#include "atlas/meshgenerator/DelaunayMeshGenerator.h" +#include "atlas/meshgenerator.h" #include "atlas/output/Gmsh.h" using namespace atlas; @@ -36,7 +36,7 @@ int main( int argc, char** argv ) { Grid grid( "L33x11" ); // Build a mesh from grid - DelaunayMeshGenerator generate; + MeshGenerator generate( "delaunay" ); Mesh mesh = generate( grid ); Gmsh gmsh( "earth.msh", util::Config( "coordinates", "xyz" ) ); diff --git a/src/tests/mesh/test_connectivity.cc b/src/tests/mesh/test_connectivity.cc index 81356dd94..e6c224d85 100644 --- a/src/tests/mesh/test_connectivity.cc +++ b/src/tests/mesh/test_connectivity.cc @@ -147,7 +147,7 @@ CASE( "test_irregular_connectivity" ) { EXPECT( conn( 7, 1 ) == 9 IN_FORTRAN ); EXPECT( conn( 7, 2 ) == 4 IN_FORTRAN ); - constexpr size_t cols[3] = {3, 7, 1}; + constexpr idx_t cols[3] = {3, 7, 1}; EXPECT( conn.cols( 2 ) == 4 ); // insert in position 2, 3 rows with cols[3] number of columns conn.insert( 2, 3, cols ); @@ -240,11 +240,11 @@ CASE("test_multi_block_connectivity_default") { 11, 12, 13, 14, 17, 18, 21, 24}; - size_t displ[7] = {0, 3, 6, 10, 14, 18, 20}; - size_t counts[7] = {3, 3, 4, 4, 4, 2, 2}; + idx_t displ[7] = {0, 3, 6, 10, 14, 18, 20}; + idx_t counts[7] = {3, 3, 4, 4, 4, 2, 2}; - size_t block_displ[3] = {0, 2, 5}; - size_t block_cols[3] = {3, 4, 2}; + idx_t block_displ[3] = {0, 2, 5}; + idx_t block_cols[3] = {3, 4, 2}; MultiBlockConnectivity mbc(values, 7, displ, counts, 3, block_displ, block_cols); EXPECT(mbc(0, 2) == 4 ); @@ -342,13 +342,11 @@ CASE( "test_multi_block_connectivity_add_block" ) { EXPECT( mbc( 1, 2, 0 ) == 11 ); const BlockConnectivity& b0 = mbc.block( 0 ); - EXPECT( b0.owns() == false ); EXPECT( b0( 0, 2 ) == 1 ); EXPECT( b0( 1, 1 ) == 4 ); EXPECT( b0( 2, 2 ) == 76 ); const BlockConnectivity& b1 = mbc.block( 1 ); - EXPECT( b1.owns() == false ); EXPECT( b1( 0, 0 ) == 31 ); EXPECT( b1( 1, 1 ) == 41 ); EXPECT( b1( 2, 0 ) == 11 ); diff --git a/src/tests/mesh/test_connectivity_kernel.cu b/src/tests/mesh/test_connectivity_kernel.cu index c30d90930..f6e08e301 100644 --- a/src/tests/mesh/test_connectivity_kernel.cu +++ b/src/tests/mesh/test_connectivity_kernel.cu @@ -25,10 +25,8 @@ namespace test { __global__ -void kernel_block(BlockConnectivityImpl* conn_, bool* result) +void kernel_block(BlockConnectivityImpl conn, bool* result) { - BlockConnectivityImpl& conn = *conn_; - *result &= (conn.rows() == 2); *result &= (conn.cols() == 5); @@ -38,11 +36,9 @@ void kernel_block(BlockConnectivityImpl* conn_, bool* result) } __global__ -void kernel_irr(IrregularConnectivityImpl* conn_, bool* result) +void kernel_irr(IrregularConnectivityImpl conn, bool* result) { - IrregularConnectivityImpl& conn = *conn_; - *result = true; *result &= (conn.rows()== 2); @@ -58,11 +54,9 @@ void kernel_irr(IrregularConnectivityImpl* conn_, bool* result) } __global__ -void kernel_multiblock(MultiBlockConnectivityImpl* conn_, bool* result) +void kernel_multiblock(MultiBlockConnectivityImpl conn, bool* result) { - MultiBlockConnectivityImpl& conn = *conn_; - *result = true; *result &= (conn.blocks()== 1); @@ -108,10 +102,7 @@ CASE( "test_block_connectivity" ) EXPECT(conn(1,3) == 84); EXPECT(conn(1,4) == 45); - conn.cloneToDevice(); - EXPECT( !conn.deviceNeedsUpdate() ); - - kernel_block<<<1,1>>>(conn.gpu_object_ptr(), result); + kernel_block<<<1,1>>>(conn, result); cudaDeviceSynchronize(); @@ -120,7 +111,6 @@ CASE( "test_block_connectivity" ) // copy back, although not strickly needed since the gpu copy does not modify values, // but for the sake of testing it - conn.cloneFromDevice(); EXPECT((conn)(0,4) == 356 ); } @@ -140,10 +130,7 @@ CASE( "test_irregular_connectivity" ) cudaMallocManaged(&result, sizeof(bool)); *result = true; - conn.cloneToDevice(); - EXPECT( !conn.deviceNeedsUpdate() ); - - kernel_irr<<<1,1>>>(conn.gpu_object_ptr(), result); + kernel_irr<<<1,1>>>(conn, result); cudaDeviceSynchronize(); @@ -151,7 +138,6 @@ CASE( "test_irregular_connectivity" ) // copy back, although not strickly needed since the gpu copy does not modify values, // but for the sake of testing it - conn.cloneFromDevice(); EXPECT(conn(0,1) == 3 IN_FORTRAN); } @@ -172,10 +158,7 @@ CASE( "test_multiblock_connectivity" ) cudaMallocManaged(&result, sizeof(bool)); *result = true; - conn.cloneToDevice(); - EXPECT( !conn.deviceNeedsUpdate() ); - - kernel_multiblock<<<1,1>>>(conn.gpu_object_ptr(), result); + kernel_multiblock<<<1,1>>>(conn, result); cudaDeviceSynchronize(); @@ -183,7 +166,6 @@ CASE( "test_multiblock_connectivity" ) // copy back, although not strickly needed since the gpu copy does not modify values, // but for the sake of testing it - conn.cloneFromDevice(); EXPECT(conn.block(0)(0,0) == 1 IN_FORTRAN); } diff --git a/src/tests/mesh/test_distmesh.cc b/src/tests/mesh/test_distmesh.cc index e1bf2bed3..3cb896f1c 100644 --- a/src/tests/mesh/test_distmesh.cc +++ b/src/tests/mesh/test_distmesh.cc @@ -47,11 +47,11 @@ namespace test { double dual_volume( Mesh& mesh ) { mesh::Nodes& nodes = mesh.nodes(); mesh::IsGhostNode is_ghost_node( nodes ); - int nb_nodes = nodes.size(); + idx_t nb_nodes = nodes.size(); array::ArrayView dual_volumes = array::make_view( nodes.field( "dual_volumes" ) ); double area = 0; - for ( int node = 0; node < nb_nodes; ++node ) { + for ( idx_t node = 0; node < nb_nodes; ++node ) { if ( !is_ghost_node( node ) ) { area += dual_volumes( node ); } } @@ -67,7 +67,7 @@ CASE( "test_distribute_t63" ) { // meshgenerator::StructuredMeshGenerator generate( util::Config // ("nb_parts",1) // ("part",0) ); - meshgenerator::StructuredMeshGenerator generate; + StructuredMeshGenerator generate( util::Config( "partitioner", "equal_regions" ) ); // long lon[] = {4,6,8,8,8}; // test::TestGrid grid(5,lon); @@ -84,7 +84,10 @@ CASE( "test_distribute_t63" ) { mesh::actions::build_halo( m, 1 ); // mesh::actions::renumber_nodes_glb_idx(m.nodes()); mesh::actions::build_edges( m ); - mesh::actions::build_pole_edges( m ); + + Gmsh( "dist.msh", util::Config( "ghost", true ) ).write( m ); + + mesh::actions::build_edges_parallel_fields( m ); mesh::actions::build_median_dual_mesh( m ); @@ -102,22 +105,22 @@ CASE( "test_distribute_t63" ) { const array::ArrayView part = array::make_view( m.nodes().partition() ); const array::ArrayView ghost = array::make_view( m.nodes().ghost() ); - const array::ArrayView flags = array::make_view( m.nodes().field( "flags" ) ); + const array::ArrayView flags = array::make_view( m.nodes().flags() ); Log::info() << "partition = [ "; - for ( size_t jnode = 0; jnode < part.size(); ++jnode ) { + for ( idx_t jnode = 0; jnode < part.size(); ++jnode ) { Log::info() << part( jnode ) << " "; } Log::info() << "]" << std::endl; Log::info() << "ghost = [ "; - for ( size_t jnode = 0; jnode < part.size(); ++jnode ) { + for ( idx_t jnode = 0; jnode < part.size(); ++jnode ) { Log::info() << ghost( jnode ) << " "; } Log::info() << "]" << std::endl; Log::info() << "flags = [ "; - for ( size_t jnode = 0; jnode < part.size(); ++jnode ) { + for ( idx_t jnode = 0; jnode < part.size(); ++jnode ) { Log::info() << mesh::Nodes::Topology::check( flags( jnode ), mesh::Nodes::Topology::GHOST ) << " "; EXPECT( mesh::Nodes::Topology::check( flags( jnode ), mesh::Nodes::Topology::GHOST ) == ghost( jnode ) ); } diff --git a/src/tests/mesh/test_elements.cc b/src/tests/mesh/test_elements.cc index ef66b3ef1..784eea839 100644 --- a/src/tests/mesh/test_elements.cc +++ b/src/tests/mesh/test_elements.cc @@ -12,9 +12,6 @@ #include #include -#include "eckit/exception/Exceptions.h" -#include "eckit/memory/ScopedPtr.h" - #include "atlas/field/Field.h" #include "atlas/grid/Grid.h" #include "atlas/library/Library.h" @@ -24,7 +21,7 @@ #include "atlas/mesh/Elements.h" #include "atlas/mesh/Mesh.h" #include "atlas/mesh/Nodes.h" -#include "atlas/meshgenerator/StructuredMeshGenerator.h" +#include "atlas/meshgenerator.h" #include "atlas/runtime/Log.h" #include "tests/AtlasTestEnvironment.h" @@ -42,7 +39,7 @@ CASE( "hybrid_elements" ) { idx_t triangle_nodes[] = {1, 5, 3, 1, 5, 2}; - size_t triags_type_idx = hybrid_elements.add( new Triangle(), 2, triangle_nodes ); + idx_t triags_type_idx = hybrid_elements.add( new Triangle(), 2, triangle_nodes ); EXPECT( triags_type_idx == 0 ); @@ -55,19 +52,19 @@ CASE( "hybrid_elements" ) { quad_nodes[2] = 2; quad_nodes[3] = 3; - size_t quads_type_idx = hybrid_elements.add( new Quadrilateral(), 1, quad_nodes ); + idx_t quads_type_idx = hybrid_elements.add( new Quadrilateral(), 1, quad_nodes ); EXPECT( quads_type_idx == 1 ); { const HybridElements::Connectivity& connectivity = hybrid_elements.node_connectivity(); - for ( size_t e = 0; e < hybrid_elements.size(); ++e ) { + for ( idx_t e = 0; e < hybrid_elements.size(); ++e ) { eckit::Log::info() << e << std::endl; eckit::Log::info() << " " << hybrid_elements.name( e ) << std::endl; eckit::Log::info() << " nb_nodes = " << hybrid_elements.nb_nodes( e ) << std::endl; eckit::Log::info() << " nb_edges = " << hybrid_elements.nb_edges( e ) << std::endl; eckit::Log::info() << " nodes = [ "; - for ( size_t n = 0; n < hybrid_elements.nb_nodes( e ); ++n ) { + for ( idx_t n = 0; n < hybrid_elements.nb_nodes( e ); ++n ) { eckit::Log::info() << connectivity( e, n ) << " "; } eckit::Log::info() << "]" << std::endl; @@ -87,7 +84,7 @@ CASE( "hybrid_elements" ) { eckit::Log::info() << std::endl; idx_t quad0[4] = {9, 8, 7, 6}; { - for ( size_t t = 0; t < hybrid_elements.nb_types(); ++t ) { + for ( idx_t t = 0; t < hybrid_elements.nb_types(); ++t ) { Elements& elements = hybrid_elements.elements( t ); const BlockConnectivity& block_connectivity = elements.node_connectivity(); if ( t == 0 ) { @@ -126,9 +123,9 @@ CASE( "hybrid_elements" ) { eckit::Log::info() << "name = " << elements.name() << std::endl; eckit::Log::info() << "nb_elements = " << elements.size() << std::endl; const BlockConnectivity& connectivity = elements.node_connectivity(); - for ( size_t e = 0; e < elements.size(); ++e ) { + for ( idx_t e = 0; e < elements.size(); ++e ) { eckit::Log::info() << " nodes = [ "; - for ( size_t n = 0; n < elements.nb_nodes(); ++n ) { + for ( idx_t n = 0; n < elements.nb_nodes(); ++n ) { eckit::Log::info() << connectivity( e, n ) << " "; } eckit::Log::info() << "]" << std::endl; @@ -136,7 +133,7 @@ CASE( "hybrid_elements" ) { } } - size_t nb_elements = 3; + idx_t nb_elements = 3; EXPECT( hybrid_elements.size() == nb_elements ); EXPECT( hybrid_elements.global_index().size() == nb_elements ); EXPECT( hybrid_elements.partition().size() == nb_elements ); @@ -166,9 +163,9 @@ CASE( "elements" ) { eckit::Log::info() << "name = " << elements.name() << std::endl; eckit::Log::info() << "nb_elements = " << elements.size() << std::endl; const BlockConnectivity& connectivity = elements.node_connectivity(); - for ( size_t e = 0; e < elements.size(); ++e ) { + for ( idx_t e = 0; e < elements.size(); ++e ) { eckit::Log::info() << " nodes = [ "; - for ( size_t n = 0; n < elements.nb_nodes(); ++n ) { + for ( idx_t n = 0; n < elements.nb_nodes(); ++n ) { eckit::Log::info() << connectivity( e, n ) << " "; } eckit::Log::info() << "]" << std::endl; @@ -178,15 +175,15 @@ CASE( "elements" ) { HybridElements hybrid_elements; hybrid_elements.add( elements ); { - for ( size_t t = 0; t < hybrid_elements.nb_types(); ++t ) { + for ( idx_t t = 0; t < hybrid_elements.nb_types(); ++t ) { Elements& elements = hybrid_elements.elements( t ); elements.node_connectivity().set( 0, triag1 ); eckit::Log::info() << "name = " << elements.name() << std::endl; eckit::Log::info() << "nb_elements = " << elements.size() << std::endl; const BlockConnectivity& connectivity = elements.node_connectivity(); - for ( size_t e = 0; e < elements.size(); ++e ) { + for ( idx_t e = 0; e < elements.size(); ++e ) { eckit::Log::info() << " nodes = [ "; - for ( size_t n = 0; n < elements.nb_nodes(); ++n ) { + for ( idx_t n = 0; n < elements.nb_nodes(); ++n ) { eckit::Log::info() << connectivity( e, n ) << " "; } eckit::Log::info() << "]" << std::endl; @@ -201,9 +198,9 @@ CASE( "hybrid_connectivity" ) { idx_t triangle_nodes[] = {1, 5, 3, 1, 5, 2}; MultiBlockConnectivity hybrid_connectivity; hybrid_connectivity.add( 2, 3, triangle_nodes ); - for ( size_t e = 0; e < hybrid_connectivity.rows(); ++e ) { + for ( idx_t e = 0; e < hybrid_connectivity.rows(); ++e ) { eckit::Log::info() << " cols = [ "; - for ( size_t n = 0; n < hybrid_connectivity.cols( e ); ++n ) { + for ( idx_t n = 0; n < hybrid_connectivity.cols( e ); ++n ) { eckit::Log::info() << hybrid_connectivity( e, n ) << " "; } eckit::Log::info() << "]" << std::endl; @@ -212,19 +209,19 @@ CASE( "hybrid_connectivity" ) { idx_t quad_nodes[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11}; hybrid_connectivity.add( 3, 4, quad_nodes ); - for ( size_t e = 0; e < hybrid_connectivity.rows(); ++e ) { + for ( idx_t e = 0; e < hybrid_connectivity.rows(); ++e ) { eckit::Log::info() << " cols = [ "; - for ( size_t n = 0; n < hybrid_connectivity.cols( e ); ++n ) { + for ( idx_t n = 0; n < hybrid_connectivity.cols( e ); ++n ) { eckit::Log::info() << hybrid_connectivity( e, n ) << " "; } eckit::Log::info() << "]" << std::endl; } - for ( size_t b = 0; b < hybrid_connectivity.blocks(); ++b ) { + for ( idx_t b = 0; b < hybrid_connectivity.blocks(); ++b ) { const BlockConnectivity& block = hybrid_connectivity.block( b ); - for ( size_t r = 0; r < block.rows(); ++r ) { + for ( idx_t r = 0; r < block.rows(); ++r ) { eckit::Log::info() << " cols = [ "; - for ( size_t c = 0; c < block.cols(); ++c ) { + for ( idx_t c = 0; c < block.cols(); ++c ) { eckit::Log::info() << block( r, c ) << " "; } eckit::Log::info() << "]" << std::endl; @@ -239,9 +236,9 @@ CASE( "block_connectivity" ) { BlockConnectivity block; block.add( 2, 3, triangle_nodes ); block.add( 2, 3, triangle_nodes ); - for ( size_t r = 0; r < block.rows(); ++r ) { + for ( idx_t r = 0; r < block.rows(); ++r ) { eckit::Log::info() << " cols = [ "; - for ( size_t c = 0; c < block.cols(); ++c ) { + for ( idx_t c = 0; c < block.cols(); ++c ) { eckit::Log::info() << block( r, c ) << " "; } eckit::Log::info() << "]" << std::endl; @@ -269,18 +266,18 @@ CASE( "irregularconnectivity_insert" ) { connectivity.insert( 1, 2, 3, c2 ); connectivity.insert( 2, 1, 5 ); - size_t iregular_c[] = {2, 3, 4, 1}; + idx_t iregular_c[] = {2, 3, 4, 1}; connectivity.insert( 5, 4, iregular_c ); idx_t values[] = {1, 2, 3, 4, 13, 14, 15, -1, -1, -1, -1, -1, 16, 17, 18, 5, 6, 7, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 9, 10, 11, 12}; idx_t counts[] = {4, 3, 5, 3, 4, 2, 3, 4, 1, 4}; - size_t n( 0 ); - size_t r( 0 ); - for ( size_t jrow = 0; jrow < connectivity.rows(); ++jrow ) { + idx_t n( 0 ); + idx_t r( 0 ); + for ( idx_t jrow = 0; jrow < connectivity.rows(); ++jrow ) { EXPECT( connectivity.cols( jrow ) == counts[r++] ); - for ( size_t jcol = 0; jcol < connectivity.cols( jrow ); ++jcol ) { + for ( idx_t jcol = 0; jcol < connectivity.cols( jrow ); ++jcol ) { EXPECT( connectivity( jrow, jcol ) == values[n++] ); } } @@ -302,8 +299,8 @@ CASE( "multiblockconnectivity_insert" ) { EXPECT( connectivity.block( 1 ).cols() == 3 ); std::cout << "block 0" << std::endl; - for ( size_t jrow = 0; jrow < connectivity.block( 0 ).rows(); ++jrow ) { - for ( size_t jcol = 0; jcol < connectivity.block( 0 ).cols(); ++jcol ) { + for ( idx_t jrow = 0; jrow < connectivity.block( 0 ).rows(); ++jrow ) { + for ( idx_t jcol = 0; jcol < connectivity.block( 0 ).cols(); ++jcol ) { std::cout << connectivity.block( 0 )( jrow, jcol ) << " "; } std::cout << std::endl; @@ -316,8 +313,8 @@ CASE( "multiblockconnectivity_insert" ) { EXPECT( connectivity.block( 1 ).rows() == 4 ); std::cout << "\nfull\n"; - for ( size_t jrow = 0; jrow < connectivity.rows(); ++jrow ) { - for ( size_t jcol = 0; jcol < connectivity.cols( jrow ); ++jcol ) { + for ( idx_t jrow = 0; jrow < connectivity.rows(); ++jrow ) { + for ( idx_t jcol = 0; jcol < connectivity.cols( jrow ); ++jcol ) { std::cout << connectivity( jrow, jcol ) << " "; } std::cout << std::endl; @@ -326,11 +323,11 @@ CASE( "multiblockconnectivity_insert" ) { 11, 12, 13, 14, 15, 23, 24, 25, 26, 27, 28, 16, 17, 18}; idx_t counts[] = {4, 4, 4, 4, 3, 3, 3, 3}; - size_t n( 0 ); - size_t r( 0 ); - for ( size_t jrow = 0; jrow < connectivity.rows(); ++jrow ) { + idx_t n( 0 ); + idx_t r( 0 ); + for ( idx_t jrow = 0; jrow < connectivity.rows(); ++jrow ) { EXPECT( connectivity.cols( jrow ) == counts[r++] ); - for ( size_t jcol = 0; jcol < connectivity.cols( jrow ); ++jcol ) { + for ( idx_t jcol = 0; jcol < connectivity.cols( jrow ); ++jcol ) { EXPECT( connectivity( jrow, jcol ) == values[n++] ); } } @@ -351,10 +348,10 @@ CASE( "cells_insert" ) { EXPECT( cells.elements( 1 ).node_connectivity().rows() == 2 ); Log::info() << "Update elements(0)" << std::endl; - size_t pos0 = cells.elements( 0 ).add( 3 ); + idx_t pos0 = cells.elements( 0 ).add( 3 ); Log::info() << "Update elements(1)" << std::endl; - size_t pos1 = cells.elements( 1 ).add( 2 ); + idx_t pos1 = cells.elements( 1 ).add( 2 ); EXPECT( pos0 == 3 ); EXPECT( pos1 == 2 ); @@ -369,16 +366,16 @@ CASE( "cells_insert" ) { const BlockConnectivity& conn2 = cells.elements( 1 ).node_connectivity(); std::cout << "\nconn1\n"; - for ( size_t jrow = 0; jrow < conn1.rows(); ++jrow ) { - for ( size_t jcol = 0; jcol < conn1.cols(); ++jcol ) { + for ( idx_t jrow = 0; jrow < conn1.rows(); ++jrow ) { + for ( idx_t jcol = 0; jcol < conn1.cols(); ++jcol ) { std::cout << conn1( jrow, jcol ) << " "; } std::cout << std::endl; } std::cout << "\nconn2\n"; - for ( size_t jrow = 0; jrow < conn2.rows(); ++jrow ) { - for ( size_t jcol = 0; jcol < conn2.cols(); ++jcol ) { + for ( idx_t jrow = 0; jrow < conn2.rows(); ++jrow ) { + for ( idx_t jcol = 0; jcol < conn2.cols(); ++jcol ) { std::cout << conn2( jrow, jcol ) << " "; } std::cout << std::endl; @@ -393,7 +390,7 @@ CASE( "cells_add_add" ) { HybridElements::Connectivity& conn = cells.node_connectivity(); - int nodes[] = {0, 1, 2, 3}; + idx_t nodes[] = {0, 1, 2, 3}; conn.set( 0, nodes ); diff --git a/src/tests/mesh/test_halo.cc b/src/tests/mesh/test_halo.cc index c08c9f3dc..e6ab04457 100644 --- a/src/tests/mesh/test_halo.cc +++ b/src/tests/mesh/test_halo.cc @@ -110,10 +110,6 @@ CASE( "test_custom" ) { mesh::actions::build_nodes_parallel_fields( m.nodes() ); mesh::actions::build_periodic_boundaries( m ); mesh::actions::build_halo( m, 1 ); - // mesh::actions::build_edges(m); - // mesh::actions::build_pole_edges(m); - // mesh::actions::build_edges_parallel_fields(m.function_space("edges"),m.nodes()); - // mesh::actions::build_centroid_dual_mesh(m); std::stringstream filename; filename << "custom.msh"; @@ -124,6 +120,8 @@ CASE( "test_custom" ) { auto lonlat = array::make_view( m.nodes().lonlat() ); +#if ATLAS_BITS_GLOBAL == 64 + std::vector check; switch ( mpi::comm().rank() ) { case 0: @@ -206,7 +204,7 @@ CASE( "test_custom" ) { check.clear(); } std::vector uid( m.nodes().size() ); - for ( size_t j = 0; j < m.nodes().size(); ++j ) { + for ( idx_t j = 0; j < m.nodes().size(); ++j ) { uid[j] = util::unique_lonlat( lonlat( j, 0 ), lonlat( j, 1 ) ); } if ( check.size() && mpi::comm().size() == 5 ) { @@ -215,7 +213,7 @@ CASE( "test_custom" ) { EXPECT( uid.size() == check.size() ); EXPECT( uid == check ); } - +#endif // FunctionSpace& edges = m.function_space("edges"); // array::array::ArrayView dual_volumes ( nodes.field( // "dual_volumes" ) ); diff --git a/src/tests/mesh/test_ll.cc b/src/tests/mesh/test_ll.cc index 18f3e6d23..2bebb7994 100644 --- a/src/tests/mesh/test_ll.cc +++ b/src/tests/mesh/test_ll.cc @@ -11,7 +11,7 @@ #include "atlas/grid/Grid.h" #include "atlas/library/Library.h" #include "atlas/mesh/Mesh.h" -#include "atlas/meshgenerator/StructuredMeshGenerator.h" +#include "atlas/meshgenerator.h" #include "atlas/output/Gmsh.h" #include "atlas/parallel/mpi/mpi.h" @@ -24,7 +24,7 @@ namespace test { CASE( "test_ll_meshgen_one_part" ) { Grid g( "L5" ); - Mesh m = meshgenerator::StructuredMeshGenerator().generate( g ); + Mesh m = StructuredMeshGenerator().generate( g ); output::Gmsh( "L5.msh" ).write( m ); } diff --git a/src/tests/mesh/test_meshgen3d.cc b/src/tests/mesh/test_meshgen3d.cc index 3e85d425f..d3a3dfec6 100644 --- a/src/tests/mesh/test_meshgen3d.cc +++ b/src/tests/mesh/test_meshgen3d.cc @@ -11,7 +11,7 @@ #include "atlas/grid.h" #include "atlas/mesh/Mesh.h" #include "atlas/mesh/Nodes.h" -#include "atlas/meshgenerator/StructuredMeshGenerator.h" +#include "atlas/meshgenerator.h" #include "atlas/output/Gmsh.h" #include "tests/AtlasTestEnvironment.h" @@ -31,7 +31,7 @@ CASE( "test_create_mesh" ) { util::Config opts; opts.set( "3d", true ); ///< creates links along date-line opts.set( "include_pole", true ); ///< triangulate the pole point - meshgenerator::StructuredMeshGenerator generate( opts ); + StructuredMeshGenerator generate( opts ); // opts.set("nb_parts",1); // default = 1 // opts.set("part", 0); // default = 0 diff --git a/src/tests/mesh/test_parfields.cc b/src/tests/mesh/test_parfields.cc index fb208d351..dfd2460be 100644 --- a/src/tests/mesh/test_parfields.cc +++ b/src/tests/mesh/test_parfields.cc @@ -22,7 +22,7 @@ #include "atlas/mesh/Nodes.h" #include "atlas/mesh/actions/BuildParallelFields.h" #include "atlas/mesh/actions/BuildPeriodicBoundaries.h" -#include "atlas/meshgenerator/StructuredMeshGenerator.h" +#include "atlas/meshgenerator.h" #include "atlas/output/Gmsh.h" #include "atlas/parallel/mpi/mpi.h" #include "atlas/util/CoordinateEnums.h" @@ -45,18 +45,18 @@ class IsGhost { public: IsGhost( const mesh::Nodes& nodes ) : part_( make_view( nodes.partition() ) ), - ridx_( make_indexview( nodes.remote_index() ) ), + ridx_( make_indexview( nodes.remote_index() ) ), mypart_( mpi::comm().rank() ) {} - bool operator()( size_t idx ) const { + bool operator()( idx_t idx ) const { if ( part_( idx ) != mypart_ ) return true; - if ( ridx_( idx ) != (int)idx ) return true; + if ( ridx_( idx ) != idx ) return true; return false; } private: array::ArrayView part_; - IndexView ridx_; + IndexView ridx_; int mypart_; }; @@ -70,10 +70,11 @@ CASE( "test1" ) { mesh::Nodes& nodes = m.nodes(); nodes.resize( 10 ); - array::ArrayView xy = make_view( nodes.xy() ); - array::ArrayView glb_idx = make_view( nodes.global_index() ); - array::ArrayView part = make_view( nodes.partition() ); - array::ArrayView flags = make_view( nodes.field( "flags" ) ); + auto xy = make_view( nodes.xy() ); + auto lonlat = make_view( nodes.lonlat() ); + auto glb_idx = make_view( nodes.global_index() ); + auto part = make_view( nodes.partition() ); + auto flags = make_view( nodes.flags() ); flags.assign( Topology::NONE ); // This is typically available @@ -123,11 +124,16 @@ CASE( "test1" ) { xy( 9, YY ) = -80.; Topology::set( flags( 9 ), Topology::BC | Topology::EAST ); + for ( idx_t n = 0; n < xy.shape( 0 ); ++n ) { + lonlat( n, LON ) = xy( n, XX ); + lonlat( n, LAT ) = xy( n, YY ); + } + mesh::actions::build_parallel_fields( m ); EXPECT( nodes.has_field( "remote_idx" ) ); - IndexView loc = make_indexview( nodes.remote_index() ); + auto loc = make_indexview( nodes.remote_index() ); EXPECT( loc( 0 ) == 0 ); EXPECT( loc( 1 ) == 1 ); EXPECT( loc( 2 ) == 2 ); @@ -185,7 +191,8 @@ CASE( "test2" ) { util::Config meshgen_options; meshgen_options.set( "angle", 27.5 ); meshgen_options.set( "triangulate", false ); - meshgenerator::StructuredMeshGenerator generate( meshgen_options ); + meshgen_options.set( "partitioner", "equal_regions" ); + StructuredMeshGenerator generate( meshgen_options ); Mesh m = generate( Grid( "N32" ) ); mesh::actions::build_parallel_fields( m ); @@ -193,8 +200,8 @@ CASE( "test2" ) { test::IsGhost is_ghost( nodes ); - size_t nb_ghost = 0; - for ( size_t jnode = 0; jnode < nodes.size(); ++jnode ) { + idx_t nb_ghost = 0; + for ( idx_t jnode = 0; jnode < nodes.size(); ++jnode ) { if ( is_ghost( jnode ) ) ++nb_ghost; } @@ -205,7 +212,7 @@ CASE( "test2" ) { mesh::actions::build_periodic_boundaries( m ); int nb_periodic = -nb_ghost; - for ( size_t jnode = 0; jnode < nodes.size(); ++jnode ) { + for ( idx_t jnode = 0; jnode < nodes.size(); ++jnode ) { if ( is_ghost( jnode ) ) ++nb_periodic; } diff --git a/src/tests/mesh/test_rgg.cc b/src/tests/mesh/test_rgg.cc index 2ef7cde43..cdbd43c44 100644 --- a/src/tests/mesh/test_rgg.cc +++ b/src/tests/mesh/test_rgg.cc @@ -27,7 +27,7 @@ #include "atlas/mesh/Mesh.h" #include "atlas/mesh/Nodes.h" #include "atlas/mesh/actions/BuildParallelFields.h" -#include "atlas/meshgenerator/StructuredMeshGenerator.h" +#include "atlas/meshgenerator.h" #include "atlas/output/Gmsh.h" #include "atlas/parallel/mpi/mpi.h" #include "atlas/runtime/Log.h" @@ -55,17 +55,17 @@ namespace test { //----------------------------------------------------------------------------- -static grid::ReducedGaussianGrid debug_grid() { +static ReducedGaussianGrid debug_grid() { return {6, 10, 18, 22, 22, 22, 22, 18, 10, 6}; } -static grid::StructuredGrid minimal_grid( int N, long lon[] ) { +static StructuredGrid minimal_grid( int N, long lon[] ) { std::vector nx( 2 * N ); for ( long j = 0; j < N; ++j ) { nx[j] = lon[j]; nx[nx.size() - 1 - j] = nx[j]; } - return grid::ReducedGaussianGrid( nx ); + return ReducedGaussianGrid( nx ); } double compute_lonlat_area( Mesh& mesh ) { @@ -78,20 +78,20 @@ double compute_lonlat_area( Mesh& mesh ) { const mesh::BlockConnectivity& triag_nodes = triags.node_connectivity(); double area = 0; - for ( size_t e = 0; e < quads.size(); ++e ) { - int n0 = quad_nodes( e, 0 ); - int n1 = quad_nodes( e, 1 ); - int n2 = quad_nodes( e, 2 ); - int n3 = quad_nodes( e, 3 ); + for ( idx_t e = 0; e < quads.size(); ++e ) { + idx_t n0 = quad_nodes( e, 0 ); + idx_t n1 = quad_nodes( e, 1 ); + idx_t n2 = quad_nodes( e, 2 ); + idx_t n3 = quad_nodes( e, 3 ); double x0 = lonlat( n0, LON ), x1 = lonlat( n1, LON ), x2 = lonlat( n2, LON ), x3 = lonlat( n3, LON ); double y0 = lonlat( n0, LAT ), y1 = lonlat( n1, LAT ), y2 = lonlat( n2, LAT ), y3 = lonlat( n3, LAT ); area += std::abs( x0 * ( y1 - y2 ) + x1 * ( y2 - y0 ) + x2 * ( y0 - y1 ) ) * 0.5; area += std::abs( x2 * ( y3 - y0 ) + x3 * ( y0 - y2 ) + x0 * ( y2 - y3 ) ) * 0.5; } - for ( size_t e = 0; e < triags.size(); ++e ) { - int n0 = triag_nodes( e, 0 ); - int n1 = triag_nodes( e, 1 ); - int n2 = triag_nodes( e, 2 ); + for ( idx_t e = 0; e < triags.size(); ++e ) { + idx_t n0 = triag_nodes( e, 0 ); + idx_t n1 = triag_nodes( e, 1 ); + idx_t n2 = triag_nodes( e, 2 ); double x0 = lonlat( n0, LON ), x1 = lonlat( n1, LON ), x2 = lonlat( n2, LON ); double y0 = lonlat( n0, LAT ), y1 = lonlat( n1, LAT ), y2 = lonlat( n2, LAT ); area += std::abs( x0 * ( y1 - y2 ) + x1 * ( y2 - y0 ) + x2 * ( y0 - y1 ) ) * 0.5; @@ -214,7 +214,7 @@ CASE( "test_rgg_meshgen_one_part" ) { // generate.options.set("part", 0); DISABLE { // This is all valid for meshes generated with MINIMAL NB TRIAGS ENABLE { - meshgenerator::StructuredMeshGenerator generate( default_opts( "3d", true )( "include_pole", false ) ); + StructuredMeshGenerator generate( default_opts( "3d", true )( "include_pole", false ) ); m = generate( atlas::test::debug_grid() ); EXPECT( m.nodes().size() == 156 ); EXPECT( m.cells().elements( 0 ).size() == 134 ); @@ -228,7 +228,7 @@ CASE( "test_rgg_meshgen_one_part" ) { } ENABLE { - meshgenerator::StructuredMeshGenerator generate( default_opts( "3d", false )( "include_pole", false ) ); + StructuredMeshGenerator generate( default_opts( "3d", false )( "include_pole", false ) ); m = generate( atlas::test::debug_grid() ); EXPECT( m.nodes().size() == 166 ); EXPECT( m.cells().elements( 0 ).size() == 134 ); @@ -242,7 +242,7 @@ CASE( "test_rgg_meshgen_one_part" ) { } ENABLE { - meshgenerator::StructuredMeshGenerator generate( default_opts( "3d", true )( "include_pole", true ) ); + StructuredMeshGenerator generate( default_opts( "3d", true )( "include_pole", true ) ); m = generate( atlas::test::debug_grid() ); EXPECT( m.nodes().size() == 158 ); EXPECT( m.cells().elements( 0 ).size() == 134 ); @@ -258,7 +258,7 @@ CASE( "test_rgg_meshgen_one_part" ) { Mesh mesh; ENABLE { - meshgenerator::StructuredMeshGenerator generate( default_opts( "3d", false )( "include_pole", false ) ); + StructuredMeshGenerator generate( default_opts( "3d", false )( "include_pole", false ) ); int nlat = 2; long lon[] = {4, 6}; mesh = generate( test::minimal_grid( nlat, lon ) ); @@ -273,7 +273,7 @@ CASE( "test_rgg_meshgen_one_part" ) { } // 3 latitudes ENABLE { - meshgenerator::StructuredMeshGenerator generate( default_opts( "3d", false )( "include_pole", false ) ); + StructuredMeshGenerator generate( default_opts( "3d", false )( "include_pole", false ) ); int nlat = 3; long lon[] = {4, 6, 8}; mesh = generate( test::minimal_grid( nlat, lon ) ); @@ -284,7 +284,7 @@ CASE( "test_rgg_meshgen_one_part" ) { } // 4 latitudes ENABLE { - meshgenerator::StructuredMeshGenerator generate( default_opts( "3d", false )( "include_pole", false ) ); + StructuredMeshGenerator generate( default_opts( "3d", false )( "include_pole", false ) ); int nlat = 4; long lon[] = {4, 6, 8, 10}; mesh = generate( test::minimal_grid( nlat, lon ) ); @@ -295,7 +295,7 @@ CASE( "test_rgg_meshgen_one_part" ) { } // 5 latitudes WIP ENABLE { - meshgenerator::StructuredMeshGenerator generate( default_opts( "3d", false )( "include_pole", false ) ); + StructuredMeshGenerator generate( default_opts( "3d", false )( "include_pole", false ) ); int nlat = 5; long lon[] = {6, 10, 18, 22, 22}; mesh = generate( test::minimal_grid( nlat, lon ) ); @@ -309,12 +309,12 @@ CASE( "test_rgg_meshgen_one_part" ) { CASE( "test_rgg_meshgen_many_parts" ) { EXPECT( grid::detail::partitioner::PartitionerFactory::has( "equal_regions" ) ); - size_t nb_parts = 20; + int nb_parts = 20; // Alternative grid for debugging // int nlat=10; // long lon[] = { 10, 10, 10, 10, 10, 10, 10, 10, 10, 10 }; // test::MinimalGrid grid(nlat,lon); - grid::StructuredGrid grid = Grid( "N32" ); + StructuredGrid grid = Grid( "N32" ); // RegularGrid grid(128,64); /* @@ -336,20 +336,19 @@ ASSERT(0); std::vector all_owned( grid.size(), -1 ); - for ( size_t p = 0; p < nb_parts; ++p ) { + for ( int p = 0; p < nb_parts; ++p ) { ATLAS_DEBUG_VAR( p ); - meshgenerator::StructuredMeshGenerator generate( util::Config( "partitioner", "equal_regions" )( - "nb_parts", nb_parts )( "part", p )( "include_pole", false )( "3d", false ) ); + StructuredMeshGenerator generate( util::Config( "partitioner", "equal_regions" )( "nb_parts", nb_parts )( + "part", p )( "include_pole", false )( "3d", false ) ); ATLAS_DEBUG_HERE(); Mesh m = generate( grid ); ATLAS_DEBUG_HERE(); m.metadata().set( "part", p ); Log::info() << "generated grid " << p << std::endl; - array::ArrayView part = array::make_view( m.nodes().partition() ); - array::ArrayView gidx = array::make_view( m.nodes().global_index() ); - array::ArrayView lonlat = array::make_view( m.nodes().lonlat() ); + array::ArrayView part = array::make_view( m.nodes().partition() ); + array::ArrayView gidx = array::make_view( m.nodes().global_index() ); area += test::compute_lonlat_area( m ); ATLAS_DEBUG_HERE(); @@ -366,18 +365,18 @@ ASSERT(0); output::Gmsh( "T63.msh" ).write( m ); mesh::Nodes& nodes = m.nodes(); - size_t nb_nodes = nodes.size(); + idx_t nb_nodes = nodes.size(); // Test if all nodes are connected { std::vector node_elem_connections( nb_nodes, 0 ); const mesh::HybridElements::Connectivity& cell_node_connectivity = m.cells().node_connectivity(); - for ( size_t jelem = 0; jelem < m.cells().size(); ++jelem ) { - for ( size_t jnode = 0; jnode < cell_node_connectivity.cols( jelem ); ++jnode ) + for ( idx_t jelem = 0; jelem < static_cast( m.cells().size() ); ++jelem ) { + for ( idx_t jnode = 0; jnode < cell_node_connectivity.cols( jelem ); ++jnode ) node_elem_connections[cell_node_connectivity( jelem, jnode )]++; } - for ( size_t jnode = 0; jnode < nb_nodes; ++jnode ) { + for ( idx_t jnode = 0; jnode < nb_nodes; ++jnode ) { if ( node_elem_connections[jnode] == 0 ) { std::stringstream ss; ss << "part " << p << ": node_gid " << gidx( jnode ) << " is not connected to any element."; @@ -387,9 +386,9 @@ ASSERT(0); } // Test if all nodes are owned - for ( size_t n = 0; n < nb_nodes; ++n ) { + for ( idx_t n = 0; n < nb_nodes; ++n ) { if ( gidx( n ) <= grid.size() ) { - if ( size_t( part( n ) ) == p ) { + if ( part( n ) == p ) { ++nb_owned; if ( all_owned[gidx( n ) - 1] != -1 ) std::cout << "node " << gidx( n ) << " already visited by " << all_owned[gidx( n ) - 1] @@ -417,26 +416,26 @@ CASE( "test_meshgen_ghost_at_end" ) { atlas::util::Config cfg; cfg.set( "part", 1 ); cfg.set( "nb_parts", 8 ); - meshgenerator::StructuredMeshGenerator meshgenerator( cfg ); - Mesh mesh = meshgenerator.generate( grid ); - const array::ArrayView part = array::make_view( mesh.nodes().partition() ); - const array::ArrayView ghost = array::make_view( mesh.nodes().ghost() ); - const array::ArrayView flags = array::make_view( mesh.nodes().field( "flags" ) ); + StructuredMeshGenerator meshgenerator( cfg ); + Mesh mesh = meshgenerator.generate( grid ); + const auto part = array::make_view( mesh.nodes().partition() ); + const auto ghost = array::make_view( mesh.nodes().ghost() ); + const auto flags = array::make_view( mesh.nodes().flags() ); Log::info() << "partition = [ "; - for ( size_t jnode = 0; jnode < part.size(); ++jnode ) { + for ( idx_t jnode = 0; jnode < part.size(); ++jnode ) { Log::info() << part( jnode ) << " "; } Log::info() << "]" << std::endl; Log::info() << "ghost = [ "; - for ( size_t jnode = 0; jnode < part.size(); ++jnode ) { + for ( idx_t jnode = 0; jnode < part.size(); ++jnode ) { Log::info() << ghost( jnode ) << " "; } Log::info() << "]" << std::endl; Log::info() << "flags = [ "; - for ( size_t jnode = 0; jnode < part.size(); ++jnode ) { + for ( idx_t jnode = 0; jnode < part.size(); ++jnode ) { Log::info() << mesh::Nodes::Topology::check( flags( jnode ), mesh::Nodes::Topology::GHOST ) << " "; EXPECT( mesh::Nodes::Topology::check( flags( jnode ), mesh::Nodes::Topology::GHOST ) == ghost( jnode ) ); } diff --git a/src/tests/mesh/test_shapefunctions.cc b/src/tests/mesh/test_shapefunctions.cc index da2b48061..823ae51bf 100644 --- a/src/tests/mesh/test_shapefunctions.cc +++ b/src/tests/mesh/test_shapefunctions.cc @@ -10,9 +10,8 @@ #include -#include "eckit/exception/Exceptions.h" -#include "eckit/memory/Owned.h" -#include "eckit/memory/SharedPtr.h" +#include "atlas/util/Object.h" +#include "atlas/util/ObjectHandle.h" // #include "tests/TestMeshes.h" #include "atlas/mpi/mpi.h" @@ -225,18 +224,15 @@ class Polynomial { std::vector mononomials_; }; -class ShapeFunction : public eckit::Owned { -public: - typedef eckit::SharedPtr Ptr; - +class ShapeFunction : public util::Object { public: ShapeFunction() {} virtual ~ShapeFunction() {} }; -class ElementType : public eckit::Owned { +class ElementType : public util::Object { public: - typedef eckit::SharedPtr Ptr; + typedef util::ObjectHandle Ptr; typedef std::vector Vector; public: @@ -339,10 +335,7 @@ class Structured1D : public ElementType { } }; -class Nodes : public eckit::Owned { -public: - typedef eckit::SharedPtr Ptr; - +class Nodes : public util::Object { public: Nodes() { npts_ = 0; @@ -388,13 +381,13 @@ class NewFunctionSpace { /// @brief Element type at index const ElementType& element_type( size_t idx ) const { - ASSERT( idx < element_types_.size() ); + ATLAS_ASSERT( idx < element_types_.size() ); return *element_types_[idx]; } /// @brief Number of elements for element type at given index size_t nb_elements_in_element_type( size_t idx ) const { - ASSERT( idx < nelem_per_type_.size() ); + ATLAS_ASSERT( idx < nelem_per_type_.size() ); return nelem_per_type_[idx]; } @@ -429,7 +422,7 @@ class NewFunctionSpace { void set_nb_nodes( int nb_nodes ) { nb_nodes_ = nb_nodes; if ( nproma_ == 0 ) nproma_ = 1; - ASSERT( nb_nodes_ % nproma_ == 0 ); + ATLAS_ASSERT( nb_nodes_ % nproma_ == 0 ); nblk_ = nb_nodes_ / nproma_; } @@ -438,7 +431,7 @@ class NewFunctionSpace { nproma_ = nproma; nblk_ = 0; if ( nb_nodes_ != 0 ) { - ASSERT( nb_nodes_ % nproma_ == 0 ); + ATLAS_ASSERT( nb_nodes_ % nproma_ == 0 ); nblk_ = nb_nodes_ / nproma_; } } @@ -507,7 +500,7 @@ class NewFunctionSpace { default: if ( idx_type >= 0 ) return idx_type; } - throw eckit::SeriousBug( "idx_type not recognized" ); + throw_Exception( "idx_type not recognized" ); return 0; } @@ -630,8 +623,8 @@ IndexView make_IndexView( atlas::array::ArrayT& array, size_t offset = 0; size_t strides[2]; size_t shape[2]; - ASSERT( element_type_index < elements.nb_element_types() ); - ASSERT( array.shape( 1 ) == elements.N_max() ); + ATLAS_ASSERT( element_type_index < elements.nb_element_types() ); + ATLAS_ASSERT( array.shape( 1 ) == elements.N_max() ); for ( int i = 0; i < element_type_index; ++i ) { offset += elements.nb_elements_in_element_type( i ) * elements.N_max(); @@ -713,7 +706,7 @@ CASE( "test_functionspace" ) { elem_connectivity( 3, 3 ) = 34; /// Access the data - atlas::IndexView triag_node_connectivity = make_IndexView( element_node_connectivity, fs, 0 ); + atlas::IndexView triag_node_connectivity = make_IndexView( element_node_connectivity, fs, 0 ); EXPECT( triag_node_connectivity.shape( 0 ) == 2 ); EXPECT( triag_node_connectivity.shape( 1 ) == 3 ); EXPECT( triag_node_connectivity( 0, 0 ) == 1 ); @@ -726,7 +719,7 @@ CASE( "test_functionspace" ) { BOOST_CHECK_THROW( triag_node_connectivity( 0, 3 ), eckit::OutOfRange ); // should fail (OUT OF RANGE) - atlas::IndexView quad_node_connectivity = make_IndexView( element_node_connectivity, fs, 1 ); + atlas::IndexView quad_node_connectivity = make_IndexView( element_node_connectivity, fs, 1 ); EXPECT( quad_node_connectivity.shape(0 == 2 ); EXPECT( quad_node_connectivity.shape(1 == 4 ); EXPECT( quad_node_connectivity(0,0 == 21 ); diff --git a/src/tests/numerics/fctest_fvm_nabla.F90 b/src/tests/numerics/fctest_fvm_nabla.F90 index a2b4d9e06..092dd5481 100644 --- a/src/tests/numerics/fctest_fvm_nabla.F90 +++ b/src/tests/numerics/fctest_fvm_nabla.F90 @@ -204,8 +204,8 @@ SUBROUTINE FV_GRADIENT(PVAR,PGRAD) TYPE(ATLAS_CONNECTIVITY) :: EDGE2NODE, NODE2EDGE REAL(KIND=JPRB), POINTER :: ZLONLAT(:,:),ZDUAL_VOLUMES(:),ZDUAL_NORMALS(:,:),& & ZNODE2EDGE_SIGN(:,:) -INTEGER(KIND=JPIM),POINTER :: IEDGE2NODE(:,:) -INTEGER(KIND=JPIM),POINTER :: INODE2EDGE(:) +INTEGER(KIND=ATLAS_KIND_IDX),POINTER :: IEDGE2NODE(:,:) +INTEGER(KIND=ATLAS_KIND_IDX),POINTER :: INODE2EDGE(:) INTEGER(KIND=JPIM) :: INODE2EDGE_SIZE INTEGER(KIND=JPIM) :: JNODE,JEDGE,JLEV,INEDGES,IP1,IP2,IEDGE,INODES REAL(KIND=JPRB) :: ZAVG,ZSIGN,ZMETRIC_X,ZMETRIC_Y diff --git a/src/tests/numerics/fctest_ifs_setup.F90 b/src/tests/numerics/fctest_ifs_setup.F90 index e8f06bfb1..f3d6b6f59 100644 --- a/src/tests/numerics/fctest_ifs_setup.F90 +++ b/src/tests/numerics/fctest_ifs_setup.F90 @@ -32,7 +32,6 @@ ! ----------------------------------------------------------------------------- TEST( test_fv ) -use, intrinsic :: iso_c_binding, only : c_size_t use atlas_module implicit none @@ -102,7 +101,7 @@ call node_to_node%final() node_to_node = nodes%connectivity("node") - FCTEST_CHECK_EQUAL( node_to_node%rows(), 0_c_size_t ) + FCTEST_CHECK_EQUAL( node_to_node%rows(), 0 ) FCTEST_CHECK_EQUAL( node_to_node%name(),"node") node_to_node = nodes%connectivity("node") diff --git a/src/tests/numerics/test_fvm_nabla.cc b/src/tests/numerics/test_fvm_nabla.cc index 115ce4c08..0238dea07 100644 --- a/src/tests/numerics/test_fvm_nabla.cc +++ b/src/tests/numerics/test_fvm_nabla.cc @@ -14,12 +14,13 @@ #include "atlas/array/MakeView.h" #include "atlas/field/Field.h" #include "atlas/field/FieldSet.h" +#include "atlas/grid/Distribution.h" #include "atlas/grid/Grid.h" #include "atlas/grid/Partitioner.h" #include "atlas/library/Library.h" #include "atlas/mesh/Mesh.h" #include "atlas/mesh/Nodes.h" -#include "atlas/meshgenerator/StructuredMeshGenerator.h" +#include "atlas/meshgenerator.h" #include "atlas/numerics/Nabla.h" #include "atlas/numerics/fvm/Method.h" #include "atlas/option.h" @@ -68,14 +69,14 @@ void rotated_flow( const fvm::Method& fvm, Field& field, const double& beta ) { array::ArrayView lonlat_deg = array::make_view( fvm.mesh().nodes().lonlat() ); array::ArrayView var = array::make_view( field ); - size_t nnodes = fvm.mesh().nodes().size(); - for ( size_t jnode = 0; jnode < nnodes; ++jnode ) { + idx_t nnodes = fvm.mesh().nodes().size(); + for ( idx_t jnode = 0; jnode < nnodes; ++jnode ) { double x = lonlat_deg( jnode, LON ) * deg2rad; double y = lonlat_deg( jnode, LAT ) * deg2rad; double Ux = pvel * ( std::cos( beta ) + std::tan( y ) * std::cos( x ) * std::sin( beta ) ) * radius * std::cos( y ); double Uy = -pvel * std::sin( x ) * std::sin( beta ) * radius; - for ( size_t jlev = 0; jlev < field.levels(); ++jlev ) { + for ( idx_t jlev = 0; jlev < field.levels(); ++jlev ) { var( jnode, jlev, LON ) = Ux; var( jnode, jlev, LAT ) = Uy; } @@ -93,14 +94,14 @@ void rotated_flow_magnitude( const fvm::Method& fvm, Field& field, const double& auto lonlat_deg = array::make_view( fvm.mesh().nodes().lonlat() ); auto var = array::make_view( field ); - size_t nnodes = fvm.mesh().nodes().size(); - for ( size_t jnode = 0; jnode < nnodes; ++jnode ) { + idx_t nnodes = fvm.mesh().nodes().size(); + for ( idx_t jnode = 0; jnode < nnodes; ++jnode ) { double x = lonlat_deg( jnode, LON ) * deg2rad; double y = lonlat_deg( jnode, LAT ) * deg2rad; double Ux = pvel * ( std::cos( beta ) + std::tan( y ) * std::cos( x ) * std::sin( beta ) ) * radius * std::cos( y ); double Uy = -pvel * std::sin( x ) * std::sin( beta ) * radius; - for ( size_t jlev = 0; jlev < field.levels(); ++jlev ) + for ( idx_t jlev = 0; jlev < field.levels(); ++jlev ) var( jnode, jlev ) = std::sqrt( Ux * Ux + Uy * Uy ); } } @@ -129,7 +130,7 @@ CASE( "test_build" ) { CASE( "test_grad" ) { Log::info() << "test_grad" << std::endl; - size_t nlev = 1; + idx_t nlev = 1; auto radius = option::radius( "Earth" ); Grid grid( griduid() ); MeshGenerator meshgenerator( "structured" ); @@ -137,7 +138,7 @@ CASE( "test_grad" ) { fvm::Method fvm( mesh, radius | option::levels( nlev ) ); Nabla nabla( fvm ); - size_t nnodes = mesh.nodes().size(); + idx_t nnodes = mesh.nodes().size(); FieldSet fields; fields.add( fvm.node_columns().createField( option::name( "scalar" ) ) ); @@ -179,8 +180,8 @@ CASE( "test_grad" ) { auto ryder = array::make_view( fields["ryder"] ); const auto grad = array::make_view( fields["grad"] ); const auto rgrad = array::make_view( fields["rgrad"] ); - for ( size_t jnode = 0; jnode < nnodes; ++jnode ) { - for ( size_t jlev = 0; jlev < nlev; ++jlev ) { + for ( idx_t jnode = 0; jnode < nnodes; ++jnode ) { + for ( idx_t jlev = 0; jlev < nlev; ++jlev ) { xder( jnode, jlev ) = grad( jnode, jlev, LON ); yder( jnode, jlev ) = grad( jnode, jlev, LAT ); rxder( jnode, jlev ) = rgrad( jnode, jlev, LON ); @@ -267,7 +268,7 @@ CASE( "test_curl" ) { auto windXgradY = array::make_view( fields["windXgradY"] ); auto windYgradX = array::make_view( fields["windYgradX"] ); auto windYgradY = array::make_view( fields["windYgradY"] ); - for ( size_t j = 0; j < windX.size(); ++j ) { + for ( idx_t j = 0; j < windX.size(); ++j ) { static const idx_t lev0 = 0; static const idx_t XdX = XX * 2 + XX; static const idx_t XdY = XX * 2 + YY; diff --git a/src/tests/parallel/test_gather.cc b/src/tests/parallel/test_gather.cc index 061992d39..4d83335d6 100644 --- a/src/tests/parallel/test_gather.cc +++ b/src/tests/parallel/test_gather.cc @@ -37,14 +37,16 @@ std::vector vec( const T ( &list )[N] ) { struct Fixture { Fixture() { + rank = static_cast( mpi::comm().rank() ); + comm_size = static_cast( mpi::comm().size() ); int nnodes_c[] = {6, 6, 7}; nb_nodes = vec( nnodes_c ); - Nl = nb_nodes[mpi::comm().rank()]; + Nl = nb_nodes[rank]; switch ( mpi::comm().rank() ) { case 0: { //./----> extra ghost point with nonstandard gidx int part_c[] = {2, 0, 0, 0, 1, 2}; part = vec( part_c ); - int ridx_c[] = {4, 1, 2, 3, 1, 3}; + idx_t ridx_c[] = {4, 1, 2, 3, 1, 3}; ridx = vec( ridx_c ); gidx_t gidx_c[] = {9, 1, 2, 3, 4, 20}; gidx = vec( gidx_c ); @@ -53,7 +55,7 @@ struct Fixture { case 1: { int part_c[] = {0, 1, 1, 1, 2, 2}; part = vec( part_c ); - int ridx_c[] = {3, 1, 2, 3, 2, 3}; + idx_t ridx_c[] = {3, 1, 2, 3, 2, 3}; ridx = vec( ridx_c ); gidx_t gidx_c[] = {3, 4, 5, 6, 7, 8}; gidx = vec( gidx_c ); @@ -62,7 +64,7 @@ struct Fixture { case 2: { int part_c[] = {1, 1, 2, 2, 2, 0, 0}; part = vec( part_c ); - int ridx_c[] = {2, 3, 2, 3, 4, 1, 2}; + idx_t ridx_c[] = {2, 3, 2, 3, 4, 1, 2}; ridx = vec( ridx_c ); gidx_t gidx_c[] = {5, 6, 7, 8, 9, 1, 2}; gidx = vec( gidx_c ); @@ -74,13 +76,15 @@ struct Fixture { parallel::GatherScatter gather_scatter; std::vector nb_nodes; std::vector part; - std::vector ridx; + std::vector ridx; std::vector gidx; int Nl; - size_t root; + int root; + int rank; + int comm_size; - int Ng() { return mpi::comm().rank() == root ? gather_scatter.glb_dof() : 0; } + int Ng() { return rank == root ? gather_scatter.glb_dof() : 0; } }; //----------------------------------------------------------------------------- @@ -90,19 +94,19 @@ CASE( "test_gather" ) { Fixture f; SECTION( "test_gather_rank0" ) { - for ( f.root = 0; f.root < mpi::comm().size(); ++f.root ) { + for ( f.root = 0; f.root < f.comm_size; ++f.root ) { std::vector loc( f.Nl ); std::vector glb( f.Ng() ); for ( int j = 0; j < f.Nl; ++j ) { - loc[j] = ( size_t( f.part[j] ) != mpi::comm().rank() ? 0 : f.gidx[j] * 10 ); + loc[j] = ( idx_t( f.part[j] ) != f.rank ? 0 : f.gidx[j] * 10 ); } - size_t strides[] = {1}; - size_t extents[] = {1}; + idx_t strides[] = {1}; + idx_t extents[] = {1}; f.gather_scatter.gather( loc.data(), strides, extents, 1, glb.data(), strides, extents, 1, f.root ); - if ( mpi::comm().rank() == f.root ) { + if ( f.rank == f.root ) { POD glb_c[] = {10, 20, 30, 40, 50, 60, 70, 80, 90}; EXPECT( glb == eckit::testing::make_view( glb_c, glb_c + f.Ng() ) ); } @@ -111,7 +115,7 @@ CASE( "test_gather" ) { #if 1 SECTION( "test_gather_rank1_deprecated" ) { - for ( f.root = 0; f.root < mpi::comm().size(); ++f.root ) { + for ( f.root = 0; f.root < f.comm_size; ++f.root ) { array::ArrayT loc( f.Nl, 2 ); array::ArrayT glb( f.Ng(), 2 ); array::ArrayT glb1( f.Ng(), 1 ); @@ -124,20 +128,20 @@ CASE( "test_gather" ) { // Gather complete field { - size_t loc_strides[] = {loc.stride( 0 ), loc.stride( 1 )}; - size_t loc_extents[] = {1, loc.shape( 1 )}; - size_t glb_strides[] = {glb.stride( 0 ), glb.stride( 1 )}; - size_t glb_extents[] = {1, glb.shape( 1 )}; + idx_t loc_strides[] = {loc.stride( 0 ), loc.stride( 1 )}; + idx_t loc_extents[] = {1, loc.shape( 1 )}; + idx_t glb_strides[] = {glb.stride( 0 ), glb.stride( 1 )}; + idx_t glb_extents[] = {1, glb.shape( 1 )}; f.gather_scatter.gather( loc.data(), loc_strides, loc_extents, 2, glb.data(), glb_strides, glb_extents, 2, f.root ); } - if ( mpi::comm().rank() == f.root ) { + if ( f.rank == f.root ) { auto glbv = array::make_view( glb ); POD glb_c[] = {10, 100, 20, 200, 30, 300, 40, 400, 50, 500, 60, 600, 70, 700, 80, 800, 90, 900}; - size_t c( 0 ); - for ( size_t i = 0; i < glb.shape( 0 ); ++i ) { - for ( size_t j = 0; j < glb.shape( 1 ); ++j ) { + idx_t c( 0 ); + for ( idx_t i = 0; i < glb.shape( 0 ); ++i ) { + for ( idx_t j = 0; j < glb.shape( 1 ); ++j ) { EXPECT( glbv( i, j ) == glb_c[c++] ); } } @@ -145,20 +149,20 @@ CASE( "test_gather" ) { // Gather only first component { - size_t loc_strides[] = {loc.stride( 0 ), 2}; - size_t loc_extents[] = {1, 1}; - size_t glb_strides[] = {glb1.stride( 0 ), glb1.stride( 1 )}; - size_t glb_extents[] = {1, glb1.shape( 1 )}; + idx_t loc_strides[] = {loc.stride( 0 ), 2}; + idx_t loc_extents[] = {1, 1}; + idx_t glb_strides[] = {glb1.stride( 0 ), glb1.stride( 1 )}; + idx_t glb_extents[] = {1, glb1.shape( 1 )}; f.gather_scatter.gather( loc.data(), loc_strides, loc_extents, 2, glb1.data(), glb_strides, glb_extents, 2, f.root ); } - if ( mpi::comm().rank() == f.root ) { + if ( f.rank == f.root ) { auto glbv = array::make_view( glb1 ); POD glb1_c[] = {10, 20, 30, 40, 50, 60, 70, 80, 90}; - size_t c( 0 ); - for ( size_t i = 0; i < glb1.shape( 0 ); ++i ) { - for ( size_t j = 0; j < glb1.shape( 1 ); ++j ) { + idx_t c( 0 ); + for ( idx_t i = 0; i < glb1.shape( 0 ); ++i ) { + for ( idx_t j = 0; j < glb1.shape( 1 ); ++j ) { EXPECT( glbv( i, j ) == glb1_c[c++] ); } } @@ -166,19 +170,19 @@ CASE( "test_gather" ) { // Gather only second component { - size_t loc_strides[] = {loc.stride( 0 ), 2}; - size_t loc_extents[] = {1, 1}; - size_t glb_strides[] = {glb2.stride( 0 ), glb2.stride( 1 )}; - size_t glb_extents[] = {1, glb2.shape( 2 )}; + idx_t loc_strides[] = {loc.stride( 0 ), 2}; + idx_t loc_extents[] = {1, 1}; + idx_t glb_strides[] = {glb2.stride( 0 ), glb2.stride( 1 )}; + idx_t glb_extents[] = {1, glb2.shape( 2 )}; f.gather_scatter.gather( loc.data() + 1, loc_strides, loc_extents, 1, glb2.data(), glb_strides, glb_extents, 1, f.root ); } - if ( mpi::comm().rank() == f.root ) { + if ( f.rank == f.root ) { auto glbv = array::make_view( glb2 ); POD glb2_c[] = {100, 200, 300, 400, 500, 600, 700, 800, 900}; - size_t c( 0 ); - for ( size_t i = 0; i < glb2.shape( 0 ); ++i ) { - for ( size_t j = 0; j < glb2.shape( 1 ); ++j ) { + idx_t c( 0 ); + for ( idx_t i = 0; i < glb2.shape( 0 ); ++i ) { + for ( idx_t j = 0; j < glb2.shape( 1 ); ++j ) { EXPECT( glbv( i, j ) == glb2_c[c++] ); } } @@ -188,30 +192,30 @@ CASE( "test_gather" ) { #endif SECTION( "test_gather_rank1" ) { - for ( f.root = 0; f.root < mpi::comm().size(); ++f.root ) { + for ( f.root = 0; f.root < f.comm_size; ++f.root ) { array::ArrayT loc( f.Nl, 2 ); array::ArrayT glb( f.Ng(), 2 ); array::ArrayT glb1( f.Ng(), 1 ); array::ArrayT glb2( f.Ng(), 1 ); array::ArrayView locv = array::make_view( loc ); for ( int j = 0; j < f.Nl; ++j ) { - locv( j, 0 ) = ( size_t( f.part[j] ) != mpi::comm().rank() ? 0 : f.gidx[j] * 10 ); - locv( j, 1 ) = ( size_t( f.part[j] ) != mpi::comm().rank() ? 0 : f.gidx[j] * 100 ); + locv( j, 0 ) = ( idx_t( f.part[j] ) != f.rank ? 0 : f.gidx[j] * 10 ); + locv( j, 1 ) = ( idx_t( f.part[j] ) != f.rank ? 0 : f.gidx[j] * 100 ); } // Gather complete field #if 0 { - size_t loc_strides[] = {2,1}; - size_t loc_extents[] = {size_t(f.Nl), 2}; - size_t loc_rank = 2; - size_t loc_mpl_idxpos[] = {0}; - size_t loc_mpl_rank = 1; - size_t glb_strides[] = {2,1}; - size_t glb_extents[] = {size_t(f.Ng()), 2}; - size_t glb_rank = 2; - size_t glb_mpl_idxpos[] = {0}; - size_t glb_mpl_rank = 1; + idx_t loc_strides[] = {2,1}; + idx_t loc_extents[] = {idx_t(f.Nl), 2}; + idx_t loc_rank = 2; + idx_t loc_mpl_idxpos[] = {0}; + idx_t loc_mpl_rank = 1; + idx_t glb_strides[] = {2,1}; + idx_t glb_extents[] = {idx_t(f.Ng()), 2}; + idx_t glb_rank = 2; + idx_t glb_mpl_idxpos[] = {0}; + idx_t glb_mpl_rank = 1; parallel::detail::MPL_ArrayView lview(loc.data(),loc_strides,loc_extents,loc_rank,loc_mpl_idxpos,loc_mpl_rank); parallel::detail::MPL_ArrayView gview(glb.data(),glb_strides,glb_extents,glb_rank,glb_mpl_idxpos,glb_mpl_rank); @@ -244,16 +248,16 @@ CASE( "test_gather" ) { // Gather only first component #if 0 { - size_t loc_strides[] = {2,2}; - size_t loc_extents[] = {size_t(f.Nl), 1}; - size_t loc_rank = 2; - size_t loc_mpl_idxpos[] = {0}; - size_t loc_mpl_rank = 1; - size_t glb_strides[] = {1}; - size_t glb_extents[] = {size_t(f.Ng())}; - size_t glb_rank = 1; - size_t glb_mpl_idxpos[] = {0}; - size_t glb_mpl_rank = 1; + idx_t loc_strides[] = {2,2}; + idx_t loc_extents[] = {idx_t(f.Nl), 1}; + idx_t loc_rank = 2; + idx_t loc_mpl_idxpos[] = {0}; + idx_t loc_mpl_rank = 1; + idx_t glb_strides[] = {1}; + idx_t glb_extents[] = {idx_t(f.Ng())}; + idx_t glb_rank = 1; + idx_t glb_mpl_idxpos[] = {0}; + idx_t glb_mpl_rank = 1; parallel::detail::MPL_ArrayView lview(loc.data(),loc_strides,loc_extents,loc_rank,loc_mpl_idxpos,loc_mpl_rank); EXPECT(lview.var_rank() == 1); EXPECT(lview.var_stride(0) == 2); @@ -284,16 +288,16 @@ CASE( "test_gather" ) { // Gather only second component #if 0 { - size_t loc_strides[] = {2,2}; - size_t loc_extents[] = {size_t(f.Nl), 1}; - size_t loc_rank = 2; - size_t loc_mpl_idxpos[] = {0}; - size_t loc_mpl_rank = 1; - size_t glb_strides[] = {1}; - size_t glb_extents[] = {size_t(f.Ng())}; - size_t glb_rank = 1; - size_t glb_mpl_idxpos[] = {0}; - size_t glb_mpl_rank = 1; + idx_t loc_strides[] = {2,2}; + idx_t loc_extents[] = {idxt(f.Nl), 1}; + idx_t loc_rank = 2; + idx_t loc_mpl_idxpos[] = {0}; + idx_t loc_mpl_rank = 1; + idx_t glb_strides[] = {1}; + idx_t glb_extents[] = {idx_t(f.Ng())}; + idx_t glb_rank = 1; + idx_t glb_mpl_idxpos[] = {0}; + idx_t glb_mpl_rank = 1; f.gather_scatter.gather( loc.data()+1, loc_strides, loc_extents, loc_rank, loc_mpl_idxpos, loc_mpl_rank, glb2.data(), glb_strides, glb_extents, glb_rank, glb_mpl_idxpos, glb_mpl_rank, f.root ); @@ -308,7 +312,7 @@ CASE( "test_gather" ) { } SECTION( "test_gather_rank2" ) { - for ( f.root = 0; f.root < mpi::comm().size(); ++f.root ) { + for ( f.root = 0; f.root < f.comm_size; ++f.root ) { array::ArrayT loc( f.Nl, 3, 2 ); array::ArrayT glb( f.Ng(), 3, 2 ); array::ArrayT glbx1( f.Ng(), 3 ); @@ -330,16 +334,16 @@ CASE( "test_gather" ) { // Gather complete field #if 0 { - size_t loc_strides[] = {6,2,1}; - size_t loc_extents[] = {size_t(f.Nl), 3, 2}; - size_t loc_rank = 3; - size_t loc_mpl_idxpos[] = {0}; - size_t loc_mpl_rank = 1; - size_t glb_strides[] = {6,2,1}; - size_t glb_extents[] = {size_t(f.Ng()), 3, 2}; - size_t glb_rank = 3; - size_t glb_mpl_idxpos[] = {0}; - size_t glb_mpl_rank = 1; + idx_t loc_strides[] = {6,2,1}; + idx_t loc_extents[] = {idx_t(f.Nl), 3, 2}; + idx_t loc_rank = 3; + idx_t loc_mpl_idxpos[] = {0}; + idx_t loc_mpl_rank = 1; + idx_t glb_strides[] = {6,2,1}; + idx_t glb_extents[] = {idx_t(f.Ng()), 3, 2}; + idx_t glb_rank = 3; + idx_t glb_mpl_idxpos[] = {0}; + idx_t glb_mpl_rank = 1; f.gather_scatter.gather( loc.data(), loc_strides, loc_extents, loc_rank, loc_mpl_idxpos, loc_mpl_rank, glb.data(), glb_strides, glb_extents, glb_rank, glb_mpl_idxpos, glb_mpl_rank, f.root ); @@ -362,16 +366,16 @@ CASE( "test_gather" ) { // Gather var 1 #if 0 { - size_t loc_strides[] = {6,2,2}; - size_t loc_extents[] = {size_t(f.Nl), 3, 1}; - size_t loc_rank = 3; - size_t loc_mpl_idxpos[] = {0}; - size_t loc_mpl_rank = 1; - size_t glb_strides[] = {6,1}; - size_t glb_extents[] = {size_t(f.Ng()), 3}; - size_t glb_rank = 2; - size_t glb_mpl_idxpos[] = {0}; - size_t glb_mpl_rank = 1; + idx_t loc_strides[] = {6,2,2}; + idx_t loc_extents[] = {idx_t(f.Nl), 3, 1}; + idx_t loc_rank = 3; + idx_t loc_mpl_idxpos[] = {0}; + idx_t loc_mpl_rank = 1; + idx_t glb_strides[] = {6,1}; + idx_t glb_extents[] = {idx_t(f.Ng()), 3}; + idx_t glb_rank = 2; + idx_t glb_mpl_idxpos[] = {0}; + idx_t glb_mpl_rank = 1; f.gather_scatter.gather( &locv(0,0,0), loc_strides, loc_extents, loc_rank, loc_mpl_idxpos, loc_mpl_rank, glbx1.data(), glb_strides, glb_extents, glb_rank, glb_mpl_idxpos, glb_mpl_rank, f.root ); @@ -394,16 +398,16 @@ CASE( "test_gather" ) { // Gather var 2 #if 0 { - size_t loc_strides[] = {6,2,2}; - size_t loc_extents[] = {size_t(f.Nl), 3, 1}; - size_t loc_rank = 3; - size_t loc_mpl_idxpos[] = {0}; - size_t loc_mpl_rank = 1; - size_t glb_strides[] = {6,1}; - size_t glb_extents[] = {size_t(f.Ng()), 3}; - size_t glb_rank = 2; - size_t glb_mpl_idxpos[] = {0}; - size_t glb_mpl_rank = 1; + idx_t loc_strides[] = {6,2,2}; + idx_t loc_extents[] = {idx_t(f.Nl), 3, 1}; + idx_t loc_rank = 3; + idx_t loc_mpl_idxpos[] = {0}; + idx_t loc_mpl_rank = 1; + idx_t glb_strides[] = {6,1}; + idx_t glb_extents[] = {idx_t(f.Ng()), 3}; + idx_t glb_rank = 2; + idx_t glb_mpl_idxpos[] = {0}; + idx_t glb_mpl_rank = 1; f.gather_scatter.gather( &locv(0,0,1), loc_strides, loc_extents, loc_rank, loc_mpl_idxpos, loc_mpl_rank, glbx2.data(), glb_strides, glb_extents, glb_rank, glb_mpl_idxpos, glb_mpl_rank, f.root ); @@ -426,16 +430,16 @@ CASE( "test_gather" ) { // Gather lev 1 #if 0 { - size_t loc_strides[] = {6,6,1}; - size_t loc_extents[] = {size_t(f.Nl), 1, 2}; - size_t loc_rank = 3; - size_t loc_mpl_idxpos[] = {0}; - size_t loc_mpl_rank = 1; - size_t glb_strides[] = {2,1}; - size_t glb_extents[] = {size_t(f.Ng()), 2}; - size_t glb_rank = 2; - size_t glb_mpl_idxpos[] = {0}; - size_t glb_mpl_rank = 1; + idx_t loc_strides[] = {6,6,1}; + idx_t loc_extents[] = {idx_t(f.Nl), 1, 2}; + idx_t loc_rank = 3; + idx_t loc_mpl_idxpos[] = {0}; + idx_t loc_mpl_rank = 1; + idx_t glb_strides[] = {2,1}; + idx_t glb_extents[] = {idx_t(f.Ng()), 2}; + idx_t glb_rank = 2; + idx_t glb_mpl_idxpos[] = {0}; + idx_t glb_mpl_rank = 1; f.gather_scatter.gather( &locv(0,0,0), loc_strides, loc_extents, loc_rank, loc_mpl_idxpos, loc_mpl_rank, glb1x.data(), glb_strides, glb_extents, glb_rank, glb_mpl_idxpos, glb_mpl_rank, @@ -459,16 +463,16 @@ CASE( "test_gather" ) { // Gather lev 2 #if 0 { - size_t loc_strides[] = {6,6,1}; - size_t loc_extents[] = {size_t(f.Nl), 1, 2}; - size_t loc_rank = 3; - size_t loc_mpl_idxpos[] = {0}; - size_t loc_mpl_rank = 1; - size_t glb_strides[] = {2,1}; - size_t glb_extents[] = {size_t(f.Ng()), 2}; - size_t glb_rank = 2; - size_t glb_mpl_idxpos[] = {0}; - size_t glb_mpl_rank = 1; + idx_t loc_strides[] = {6,6,1}; + idx_t loc_extents[] = {idx_t(f.Nl), 1, 2}; + idx_t loc_rank = 3; + idx_t loc_mpl_idxpos[] = {0}; + idx_t loc_mpl_rank = 1; + idx_t glb_strides[] = {2,1}; + idx_t glb_extents[] = {idx_t(f.Ng()), 2}; + idx_t glb_rank = 2; + idx_t glb_mpl_idxpos[] = {0}; + idx_t glb_mpl_rank = 1; f.gather_scatter.gather( &locv(0,1,0), loc_strides, loc_extents, loc_rank, loc_mpl_idxpos, loc_mpl_rank, glb2x.data(), glb_strides, glb_extents, glb_rank, glb_mpl_idxpos, glb_mpl_rank, f.root ); @@ -491,16 +495,16 @@ CASE( "test_gather" ) { // Gather lev 3 var 2 #if 0 { - size_t loc_strides[] = {6,6,2}; - size_t loc_extents[] = {size_t(f.Nl), 1, 1}; - size_t loc_rank = 3; - size_t loc_mpl_idxpos[] = {0}; - size_t loc_mpl_rank = 1; - size_t glb_strides[] = {1}; - size_t glb_extents[] = {size_t(f.Ng())}; - size_t glb_rank = 1; - size_t glb_mpl_idxpos[] = {0}; - size_t glb_mpl_rank = 1; + idx_t loc_strides[] = {6,6,2}; + idx_t loc_extents[] = {idx_t(f.Nl), 1, 1}; + idx_t loc_rank = 3; + idx_t loc_mpl_idxpos[] = {0}; + idx_t loc_mpl_rank = 1; + idx_t glb_strides[] = {1}; + idx_t glb_extents[] = {idx_t(f.Ng())}; + idx_t glb_rank = 1; + idx_t glb_mpl_idxpos[] = {0}; + idx_t glb_mpl_rank = 1; f.gather_scatter.gather( &locv(0,2,1), loc_strides, loc_extents, loc_rank, loc_mpl_idxpos, loc_mpl_rank, glb32.data(), glb_strides, glb_extents, glb_rank, glb_mpl_idxpos, glb_mpl_rank, @@ -524,7 +528,7 @@ CASE( "test_gather" ) { } SECTION( "test_gather_rank0_ArrayView" ) { - for ( f.root = 0; f.root < mpi::comm().size(); ++f.root ) { + for ( f.root = 0; f.root < f.comm_size; ++f.root ) { array::ArrayT loc( f.Nl ); array::ArrayT glb( f.Ng() ); @@ -536,9 +540,9 @@ CASE( "test_gather" ) { // Gather complete field { f.gather_scatter.gather( locv, glbv, f.root ); } - if ( mpi::comm().rank() == f.root ) { + if ( f.rank == f.root ) { POD glb_c[] = {10, 20, 30, 40, 50, 60, 70, 80, 90}; - for ( size_t n = 0; n < glb.shape( 0 ); ++n ) { + for ( idx_t n = 0; n < glb.shape( 0 ); ++n ) { EXPECT( glbv( n ) == glb_c[n] ); } } @@ -546,7 +550,7 @@ CASE( "test_gather" ) { } SECTION( "test_gather_rank1_ArrayView" ) { - for ( f.root = 0; f.root < mpi::comm().size(); ++f.root ) { + for ( f.root = 0; f.root < f.comm_size; ++f.root ) { array::ArrayT loc( f.Nl, 2 ); array::ArrayT glb( f.Ng(), 2 ); @@ -559,13 +563,13 @@ CASE( "test_gather" ) { // Gather complete field { f.gather_scatter.gather( locv, glbv, f.root ); } - if ( mpi::comm().rank() == f.root ) { + if ( f.rank == f.root ) { POD glb_c[] = {-10, 10, -20, 20, -30, 30, -40, 40, -50, 50, -60, 60, -70, 70, -80, 80, -90, 90}; auto glbv = array::make_view( glb ); - size_t c( 0 ); - for ( size_t i = 0; i < glb.shape( 0 ); ++i ) { - for ( size_t j = 0; j < glb.shape( 1 ); ++j ) { + idx_t c( 0 ); + for ( idx_t i = 0; i < glb.shape( 0 ); ++i ) { + for ( idx_t j = 0; j < glb.shape( 1 ); ++j ) { EXPECT( glbv( i, j ) == glb_c[c++] ); } } @@ -574,7 +578,7 @@ CASE( "test_gather" ) { } SECTION( "test_gather_rank2_ArrayView" ) { - for ( f.root = 0; f.root < mpi::comm().size(); ++f.root ) { + for ( f.root = 0; f.root < f.comm_size; ++f.root ) { array::ArrayT loc( f.Nl, 3, 2 ); array::ArrayT glb( f.Ng(), 3, 2 ); @@ -591,14 +595,14 @@ CASE( "test_gather" ) { // Gather complete field { f.gather_scatter.gather( locv, glbv, f.root ); } - if ( mpi::comm().rank() == f.root ) { + if ( f.rank == f.root ) { POD glb_c[] = {-1, 1, -10, 10, -100, 100, -2, 2, -20, 20, -200, 200, -3, 3, -30, 30, -300, 300, -4, 4, -40, 40, -400, 400, -5, 5, -50, 50, -500, 500, -6, 6, -60, 60, -600, 600, -7, 7, -70, 70, -700, 700, -8, 8, -80, 80, -800, 800, -9, 9, -90, 90, -900, 900}; - size_t c( 0 ); - for ( size_t i = 0; i < glb.shape( 0 ); ++i ) { - for ( size_t j = 0; j < glb.shape( 1 ); ++j ) { - for ( size_t k = 0; k < glb.shape( 2 ); ++k ) { + idx_t c( 0 ); + for ( idx_t i = 0; i < glb.shape( 0 ); ++i ) { + for ( idx_t j = 0; j < glb.shape( 1 ); ++j ) { + for ( idx_t k = 0; k < glb.shape( 2 ); ++k ) { EXPECT( glbv( i, j, k ) == glb_c[c++] ); } } @@ -609,17 +613,17 @@ CASE( "test_gather" ) { } SECTION( "test_scatter_rank2_ArrayView" ) { - for ( f.root = 0; f.root < mpi::comm().size(); ++f.root ) { + for ( f.root = 0; f.root < f.comm_size; ++f.root ) { array::ArrayT loc( f.Nl, 3, 2 ); array::ArrayT glb( f.Ng(), 3, 2 ); array::ArrayView locv = array::make_view( loc ); array::ArrayView glbv = array::make_view( glb ); - if ( mpi::comm().rank() == f.root ) { + if ( f.rank == f.root ) { POD glb_c[] = {-1, 1, -10, 10, -100, 100, -2, 2, -20, 20, -200, 200, -3, 3, -30, 30, -300, 300, -4, 4, -40, 40, -400, 400, -5, 5, -50, 50, -500, 500, -6, 6, -60, 60, -600, 600, -7, 7, -70, 70, -700, 700, -8, 8, -80, 80, -800, 800, -9, 9, -90, 90, -900, 900}; - size_t c( 0 ); + idx_t c( 0 ); for ( int i = 0; i < glb.shape( 0 ); ++i ) { for ( int j = 0; j < glb.shape( 1 ); ++j ) { for ( int k = 0; k < glb.shape( 2 ); ++k ) { @@ -640,11 +644,11 @@ CASE( "test_gather" ) { -2, 2, -20, 20, -200, 200, -3, 3, -30, 30, -300, 300, nan, nan, nan, nan, nan, nan, nan, nan, nan, nan, nan, nan}; - size_t c( 0 ); - for ( size_t i = 0; i < loc.shape( 0 ); ++i ) { - for ( size_t j = 0; j < loc.shape( 1 ); ++j ) { - for ( size_t k = 0; k < loc.shape( 2 ); ++k ) { - EXPECT( locv( i, j, k ) == loc_c[c++] ); + idx_t c( 0 ); + for ( idx_t i = 0; i < loc.shape( 0 ); ++i ) { + for ( idx_t j = 0; j < loc.shape( 1 ); ++j ) { + for ( idx_t k = 0; k < loc.shape( 2 ); ++k ) { + EXPECT( is_approximately_equal( locv( i, j, k ), loc_c[c++] ) ); } } } @@ -654,11 +658,11 @@ CASE( "test_gather" ) { POD loc_c[] = {nan, nan, nan, nan, nan, nan, -4, 4, -40, 40, -400, 400, -5, 5, -50, 50, -500, 500, -6, 6, -60, 60, -600, 600, nan, nan, nan, nan, nan, nan, nan, nan, nan, nan, nan, nan}; - size_t c( 0 ); - for ( size_t i = 0; i < loc.shape( 0 ); ++i ) { - for ( size_t j = 0; j < loc.shape( 1 ); ++j ) { - for ( size_t k = 0; k < loc.shape( 2 ); ++k ) { - EXPECT( locv( i, j, k ) == loc_c[c++] ); + idx_t c( 0 ); + for ( idx_t i = 0; i < loc.shape( 0 ); ++i ) { + for ( idx_t j = 0; j < loc.shape( 1 ); ++j ) { + for ( idx_t k = 0; k < loc.shape( 2 ); ++k ) { + EXPECT( is_approximately_equal( locv( i, j, k ), loc_c[c++] ) ); } } } @@ -668,11 +672,11 @@ CASE( "test_gather" ) { POD loc_c[] = {nan, nan, nan, nan, nan, nan, nan, nan, nan, nan, nan, nan, -7, 7, -70, 70, -700, 700, -8, 8, -80, 80, -800, 800, -9, 9, -90, 90, -900, 900, nan, nan, nan, nan, nan, nan, nan, nan, nan, nan, nan, nan}; - size_t c( 0 ); - for ( size_t i = 0; i < loc.shape( 0 ); ++i ) { - for ( size_t j = 0; j < loc.shape( 1 ); ++j ) { - for ( size_t k = 0; k < loc.shape( 2 ); ++k ) { - EXPECT( locv( i, j, k ) == loc_c[c++] ); + idx_t c( 0 ); + for ( idx_t i = 0; i < loc.shape( 0 ); ++i ) { + for ( idx_t j = 0; j < loc.shape( 1 ); ++j ) { + for ( idx_t k = 0; k < loc.shape( 2 ); ++k ) { + EXPECT( is_approximately_equal( locv( i, j, k ), loc_c[c++] ) ); } } } diff --git a/src/tests/parallel/test_haloexchange.cc b/src/tests/parallel/test_haloexchange.cc index cd7d1b7c8..7ee9f472f 100644 --- a/src/tests/parallel/test_haloexchange.cc +++ b/src/tests/parallel/test_haloexchange.cc @@ -10,10 +10,9 @@ #include #include +#include #include -#include "eckit/memory/SharedPtr.h" - #include "atlas/array.h" #include "atlas/array/ArrayView.h" #include "atlas/array/MakeView.h" @@ -68,7 +67,7 @@ struct validate_impl { template static void apply( array::ArrayView& arrv, DATA_TYPE arr_c[], std::array& strides, Int... dims ) { - for ( size_t cnt = 0; cnt < arrv.template shape(); ++cnt ) { + for ( idx_t cnt = 0; cnt < arrv.template shape(); ++cnt ) { validate_impl::apply( arrv, arr_c, strides, dims..., cnt ); } } @@ -99,7 +98,7 @@ struct validate { strides[Rank - 1] = 1; compute_strides::apply( arrv, strides ); - for ( size_t i = 0; i < arrv.template shape<0>(); ++i ) { + for ( idx_t i = 0; i < arrv.template shape<0>(); ++i ) { validate_impl::apply( arrv, arr_c, strides, i ); } } @@ -112,30 +111,30 @@ struct Fixture { N = nb_nodes[mpi::comm().rank()]; switch ( mpi::comm().rank() ) { case 0: { - int part_c[] = {2, 0, 0, 0, 1}; - part = vec( part_c ); - int ridx_c[] = {4, 1, 2, 3, 1}; - ridx = vec( ridx_c ); - POD gidx_c[] = {0, 1, 2, 3, 0}; - gidx = vec( gidx_c ); + int part_c[] = {2, 0, 0, 0, 1}; + part = vec( part_c ); + idx_t ridx_c[] = {4, 1, 2, 3, 1}; + ridx = vec( ridx_c ); + POD gidx_c[] = {0, 1, 2, 3, 0}; + gidx = vec( gidx_c ); break; } case 1: { - int part_c[] = {0, 1, 1, 1, 2, 2}; - part = vec( part_c ); - int ridx_c[] = {3, 1, 2, 3, 2, 3}; - ridx = vec( ridx_c ); - POD gidx_c[] = {0, 4, 5, 6, 0, 0}; - gidx = vec( gidx_c ); + int part_c[] = {0, 1, 1, 1, 2, 2}; + part = vec( part_c ); + idx_t ridx_c[] = {3, 1, 2, 3, 2, 3}; + ridx = vec( ridx_c ); + POD gidx_c[] = {0, 4, 5, 6, 0, 0}; + gidx = vec( gidx_c ); break; } case 2: { - int part_c[] = {1, 1, 2, 2, 2, 0, 0}; - part = vec( part_c ); - int ridx_c[] = {2, 3, 2, 3, 4, 1, 2}; - ridx = vec( ridx_c ); - POD gidx_c[] = {0, 0, 7, 8, 9, 0, 0}; - gidx = vec( gidx_c ); + int part_c[] = {1, 1, 2, 2, 2, 0, 0}; + part = vec( part_c ); + idx_t ridx_c[] = {2, 3, 2, 3, 4, 1, 2}; + ridx = vec( ridx_c ); + POD gidx_c[] = {0, 0, 7, 8, 9, 0, 0}; + gidx = vec( gidx_c ); break; } } @@ -144,7 +143,7 @@ struct Fixture { parallel::HaloExchange halo_exchange; std::vector nb_nodes; std::vector part; - std::vector ridx; + std::vector ridx; std::vector gidx; int N; @@ -236,17 +235,17 @@ void test_rank1_strided_v1( Fixture& f ) { // (i.e. we are only selecting and exchanging the first component of the // field) - eckit::SharedPtr arr( array::Array::wrap( arrv_t.data(), - array::ArraySpec { - array::make_shape( f.N, 1 ), + std::unique_ptr arr( array::Array::wrap( arrv_t.data(), + array::ArraySpec { + array::make_shape( f.N, 1 ), #if ATLAS_GRIDTOOLS_STORAGE_BACKEND_CUDA - array::make_strides( 32, 1 ) - } + array::make_strides( 32, 1 ) + } #else - array::make_strides( 2, 1 ) - } + array::make_strides( 2, 1 ) + } #endif - ) ); + ) ); arr->syncHostDevice(); @@ -291,7 +290,7 @@ void test_rank1_strided_v2( Fixture& f ) { // (i.e. we are only selecting and exchanging the first component of the // field) - eckit::SharedPtr arr( array::Array::wrap( &( arrv_t( 0, 1 ) ), array::ArraySpec { + std::unique_ptr arr( array::Array::wrap( &( arrv_t( 0, 1 ) ), array::ArraySpec { array::make_shape( f.N, 1 ), #if ATLAS_GRIDTOOLS_STORAGE_BACKEND_CUDA array::make_strides( 32, 1 ) @@ -371,14 +370,13 @@ void test_rank2_l1( Fixture& f ) { } arr_t.syncHostDevice(); - eckit::SharedPtr arr( array::Array::wrap( arrv_t.data(), array::ArraySpec { + std::unique_ptr arr( array::Array::wrap( arrv_t.data(), array::ArraySpec { array::make_shape( f.N, 1, 2 ), #if ATLAS_GRIDTOOLS_STORAGE_BACKEND_CUDA array::make_strides( 96, 32, 1 ) #else array::make_strides(6, 2, 1) #endif - } ) ); arr_t.syncHostDevice(); @@ -433,7 +431,7 @@ void test_rank2_l2_v2( Fixture& f ) { } } - eckit::SharedPtr arr( array::Array::wrap( &arrv_t( 0, 1, 1 ), array::ArraySpec { + std::unique_ptr arr( array::Array::wrap( &arrv_t( 0, 1, 1 ), array::ArraySpec { array::make_shape( f.N, 1, 1 ), #if ATLAS_GRIDTOOLS_STORAGE_BACKEND_CUDA array::make_strides( 192, 32, 1 ) @@ -490,7 +488,7 @@ void test_rank2_v2( Fixture& f ) { } } - eckit::SharedPtr arr( array::Array::wrap( &arrv_t( 0, 0, 1 ), array::ArraySpec { + std::unique_ptr arr( array::Array::wrap( &arrv_t( 0, 0, 1 ), array::ArraySpec { array::make_shape( f.N, 3, 1 ), #if ATLAS_GRIDTOOLS_STORAGE_BACKEND_CUDA array::make_strides( 192, 32, 2 ) @@ -537,7 +535,7 @@ void test_rank2_v2( Fixture& f ) { } void test_rank0_wrap( Fixture& f ) { - eckit::SharedPtr arr( array::Array::wrap( f.gidx.data(), array::make_shape( f.N ) ) ); + std::unique_ptr arr( array::Array::wrap( f.gidx.data(), array::make_shape( f.N ) ) ); array::ArrayView arrv = array::make_view( *arr ); arr->syncHostDevice(); diff --git a/src/tests/parallel/test_sync.F90 b/src/tests/parallel/test_sync.F90 index 47962480d..cea44ec1a 100644 --- a/src/tests/parallel/test_sync.F90 +++ b/src/tests/parallel/test_sync.F90 @@ -1,4 +1,9 @@ ! (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. ! =================================================================== ! test_sync program diff --git a/src/tests/runtime/CMakeLists.txt b/src/tests/runtime/CMakeLists.txt new file mode 100644 index 000000000..4ee831302 --- /dev/null +++ b/src/tests/runtime/CMakeLists.txt @@ -0,0 +1,25 @@ +# (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. + +ecbuild_add_test( TARGET atlas_test_trace + SOURCES test_trace.cc + LIBS atlas + ENVIRONMENT ATLAS_TRACE_REPORT=1 + OMP 2 +) + +if( HAVE_FCTEST ) + +add_fctest( TARGET atlas_fctest_trace + SOURCES fctest_trace.fypp + LINKER_LANGUAGE Fortran + LIBS atlas_f + ENVIRONMENT ATLAS_TRACE_REPORT=1 +) + +endif() diff --git a/src/tests/runtime/fctest_trace.fypp b/src/tests/runtime/fctest_trace.fypp new file mode 100644 index 000000000..8e3bada3f --- /dev/null +++ b/src/tests/runtime/fctest_trace.fypp @@ -0,0 +1,85 @@ +! (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" +#:include "atlas/atlas_f.fypp" + +! ----------------------------------------------------------------------------- + +module fcta_trace_fixture +use atlas_module +use, intrinsic :: iso_c_binding +@:ENABLE_ATLAS_MACROS() +implicit none +contains +end module + +! ----------------------------------------------------------------------------- + +TESTSUITE_WITH_FIXTURE(fctest_atlas_trace,fcta_trace_fixture) + +! ----------------------------------------------------------------------------- + +subroutine sub2() + type(atlas_Trace) :: trace + @:ATLAS_TRACE_BEGIN( trace, "sub2" ) + FCTEST_CHECK( trace%running() ) + @:ATLAS_TRACE_END( trace ) +end subroutine + +subroutine sub1() + integer :: i + type(atlas_Trace) :: trace + trace = @{ ATLAS_TRACE( "sub1" ) }@ + FCTEST_CHECK( trace%running() ) + + do i=1,10 + call sub2() + enddo + + call trace%final() +end subroutine + +TESTSUITE_INIT + call atlas_library%initialise() +END_TESTSUITE_INIT + +! ----------------------------------------------------------------------------- + +TESTSUITE_FINALIZE + use fckit_main_module + call atlas_library%finalise() +END_TESTSUITE_FINALIZE + +! ----------------------------------------------------------------------------- + +TEST( test_trace ) +implicit none + + type(atlas_Trace) :: trace + + trace = atlas_Trace("${_FILE_}$",${_LINE_}$,"test_trace") + + FCTEST_CHECK( trace%running() ) + + call sub1() + + call trace%stop() + FCTEST_CHECK( .not. trace%running() ) + + call trace%final() + + +END_TEST +! ----------------------------------------------------------------------------- + +END_TESTSUITE + diff --git a/src/tests/runtime/test_trace.cc b/src/tests/runtime/test_trace.cc new file mode 100644 index 000000000..f67e2226e --- /dev/null +++ b/src/tests/runtime/test_trace.cc @@ -0,0 +1,61 @@ +/* + * (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/parallel/omp/omp.h" +#include "atlas/runtime/Trace.h" +#include "tests/AtlasTestEnvironment.h" + + +namespace atlas { +namespace test { + +CASE( "test elapsed" ) { + auto trace = Trace( Here() ); + + EXPECT( trace.running() ); + + EXPECT( trace.elapsed() == 0. ); + + trace.pause(); + + EXPECT( trace.running() ); + + double elapsed = trace.elapsed(); + EXPECT( elapsed != 0. ); + EXPECT( trace.elapsed() == elapsed ); + + trace.resume(); + + EXPECT( trace.running() ); + + trace.stop(); + + EXPECT( trace.elapsed() != elapsed ); +} + +CASE( "test trace OpenMP" ) { + atlas_omp_parallel_for( int i = 0; i < 10; ++i ) { + auto trace = Trace( Here(), "loop" ); + if ( ATLAS_HAVE_OMP ) { + trace.stop(); + if ( atlas_omp_get_thread_num() > 0 ) { EXPECT( trace.elapsed() == 0. ); } + else { + EXPECT( trace.elapsed() != 0. ); + } + } + } +} + +} // namespace test +} // namespace atlas + +int main( int argc, char** argv ) { + return atlas::test::run( argc, argv ); +} diff --git a/src/tests/trans/test_trans.cc b/src/tests/trans/test_trans.cc index 4c2e3b03a..5f8d00916 100644 --- a/src/tests/trans/test_trans.cc +++ b/src/tests/trans/test_trans.cc @@ -10,6 +10,7 @@ #include +#include "eckit/exception/Exceptions.h" #include "eckit/filesystem/PathName.h" #include "eckit/io/DataHandle.h" @@ -26,11 +27,12 @@ #include "atlas/library/Library.h" #include "atlas/mesh/Mesh.h" #include "atlas/mesh/Nodes.h" -#include "atlas/meshgenerator/StructuredMeshGenerator.h" +#include "atlas/meshgenerator.h" #include "atlas/output/Gmsh.h" #include "atlas/parallel/mpi/mpi.h" #include "atlas/trans/Trans.h" #include "atlas/trans/VorDivToUV.h" +#include "atlas/trans/detail/TransFactory.h" #include "tests/AtlasTestEnvironment.h" @@ -65,7 +67,7 @@ void read_rspecg( trans::TransImpl& trans, std::vector& rspecg, std::vec nfld = 2; if ( mpi::comm().rank() == 0 ) { rspecg.resize( nfld * trans.spectralCoefficients() ); - for ( int i = 0; i < trans.spectralCoefficients(); ++i ) { + for ( size_t i = 0; i < trans.spectralCoefficients(); ++i ) { rspecg[i * nfld + 0] = ( i == 0 ? 1. : 0. ); // scalar field 1 rspecg[i * nfld + 1] = ( i == 0 ? 2. : 0. ); // scalar field 2 } @@ -86,7 +88,7 @@ void read_rspecg( Field spec ) { int nb_spectral_coefficients_global = functionspace::Spectral( spec.functionspace() ).nb_spectral_coefficients_global(); auto view = array::make_view( spec ); - ASSERT( view.shape( 1 ) >= 2 ); + ATLAS_ASSERT( view.shape( 1 ) >= 2 ); for ( int i = 0; i < nb_spectral_coefficients_global; ++i ) { view( i, 0 ) = ( i == 0 ? 1. : 0. ); // scalar field 1 view( i, 1 ) = ( i == 0 ? 2. : 0. ); // scalar field 2 @@ -103,7 +105,7 @@ CASE( "test_trans_distribution_matches_atlas" ) { // Create grid and trans object Grid g( "N80" ); - EXPECT( grid::StructuredGrid( g ).ny() == 160 ); + EXPECT( StructuredGrid( g ).ny() == 160 ); auto trans_partitioner = new TransPartitioner(); grid::Partitioner partitioner( trans_partitioner ); @@ -116,8 +118,8 @@ CASE( "test_trans_distribution_matches_atlas" ) { EXPECT( trans.truncation() == 159 ); // -------------- do checks -------------- // - EXPECT( t->nproc == mpi::comm().size() ); - EXPECT( t->myproc == mpi::comm().rank() + 1 ); + EXPECT( t->nproc == int( mpi::comm().size() ) ); + EXPECT( t->myproc == int( mpi::comm().rank() + 1 ) ); if ( mpi::comm().rank() == 0 ) // all tasks do the same, so only one needs to check { @@ -128,12 +130,12 @@ CASE( "test_trans_distribution_matches_atlas" ) { EXPECT( t->n_regions_NS == trans_partitioner->nb_bands() ); EXPECT( t->n_regions_EW == max_nb_regions_EW ); - EXPECT( distribution.nb_partitions() == mpi::comm().size() ); - EXPECT( distribution.partition().size() == g.size() ); + EXPECT( distribution.nb_partitions() == idx_t( mpi::comm().size() ) ); + EXPECT( idx_t( distribution.partition().size() ) == g.size() ); std::vector npts( distribution.nb_partitions(), 0 ); - for ( size_t j = 0; j < g.size(); ++j ) + for ( idx_t j = 0; j < g.size(); ++j ) ++npts[distribution.partition( j )]; EXPECT( t->ngptotg == g.size() ); @@ -254,7 +256,7 @@ CASE( "test_distribution" ) { CASE( "test_generate_mesh" ) { Log::info() << "test_generate_mesh" << std::endl; Grid g( "O80" ); - meshgenerator::StructuredMeshGenerator generate( atlas::util::Config( "angle", 0 )( "triangulate", true ) ); + StructuredMeshGenerator generate( atlas::util::Config( "angle", 0 )( "triangulate", true ) ); Mesh m_default = generate( g ); @@ -270,7 +272,7 @@ CASE( "test_generate_mesh" ) { array::ArrayView p_trans = array::make_view( m_trans.nodes().partition() ); array::ArrayView p_eqreg = array::make_view( m_eqreg.nodes().partition() ); - for ( size_t j = 0; j < p_default.shape( 0 ); ++j ) { + for ( idx_t j = 0; j < p_default.shape( 0 ); ++j ) { EXPECT( p_default( j ) == p_trans( j ) ); EXPECT( p_default( j ) == p_eqreg( j ) ); } @@ -282,7 +284,7 @@ CASE( "test_spectral_fields" ) { Log::info() << "test_spectral_fields" << std::endl; Grid g( "O48" ); - meshgenerator::StructuredMeshGenerator generate( atlas::util::Config( "angle", 0 )( "triangulate", false ) ); + StructuredMeshGenerator generate( atlas::util::Config( "angle", 0 )( "triangulate", false ) ); Mesh m = generate( g ); trans::Trans trans( g, 47 ); @@ -292,8 +294,8 @@ CASE( "test_spectral_fields" ) { Field spf = spectral.createField( option::name( "spf" ) ); Field gpf = nodal.createField( option::name( "gpf" ) ); - - array::make_view( gpf ).assign(0); + + array::make_view( gpf ).assign( 0 ); EXPECT_NO_THROW( trans.dirtrans( gpf, spf ) ); EXPECT_NO_THROW( trans.invtrans( spf, gpf ) ); @@ -307,7 +309,7 @@ CASE( "test_spectral_fields" ) { EXPECT_NO_THROW( trans.invtrans( spfields, gpfields ) ); gpfields.add( gpf ); - EXPECT_THROWS_AS( trans.dirtrans( gpfields, spfields ), eckit::SeriousBug ); + EXPECT_THROWS_AS( trans.dirtrans( gpfields, spfields ), eckit::Exception ); } CASE( "test_nomesh" ) { @@ -317,7 +319,7 @@ CASE( "test_nomesh" ) { trans::Trans trans( g, 47 ); functionspace::Spectral spectral( trans ); - functionspace::StructuredColumns gridpoints( g ); + functionspace::StructuredColumns gridpoints( g, grid::Partitioner( "trans" ) ); Field spfg = spectral.createField( option::name( "spf" ) | option::global() ); Field spf = spectral.createField( option::name( "spf" ) ); @@ -335,7 +337,7 @@ CASE( "test_nomesh" ) { if ( mpi::comm().rank() == 0 ) { array::ArrayView sp = array::make_view( spf ); EXPECT( eckit::types::is_approximately_equal( sp( 0 ), 4., 0.001 ) ); - for ( size_t jp = 0; jp < sp.size(); ++jp ) { + for ( idx_t jp = 0; jp < sp.size(); ++jp ) { Log::debug() << "sp(" << jp << ") : " << sp( jp ) << std::endl; } } @@ -346,7 +348,7 @@ CASE( "test_nomesh" ) { if ( mpi::comm().rank() == 0 ) { array::ArrayView gpg = array::make_view( gpfg ); - for ( size_t jp = 0; jp < gpg.size(); ++jp ) { + for ( idx_t jp = 0; jp < gpg.size(); ++jp ) { EXPECT( eckit::types::is_approximately_equal( gpg( jp ), 4., 0.001 ) ); Log::debug() << "gpg(" << jp << ") : " << gpg( jp ) << std::endl; } @@ -367,7 +369,7 @@ CASE( "test_trans_factory" ) { trans::TransFactory::list( Log::info() ); Log::info() << std::endl; - functionspace::StructuredColumns gp( Grid( "O48" ) ); + functionspace::StructuredColumns gp( Grid( "O48" ), grid::Partitioner( "trans" ) ); functionspace::Spectral sp( 47 ); trans::Trans trans1 = trans::Trans( gp, sp ); @@ -382,13 +384,13 @@ CASE( "test_trans_using_grid" ) { trans::Trans trans( Grid( "O48" ), 47 ); - functionspace::StructuredColumns gp( trans.grid() ); + functionspace::StructuredColumns gp( trans.grid(), grid::Partitioner( "trans" ) ); functionspace::Spectral sp( trans.truncation() ); Field spf = sp.createField( option::name( "spf" ) ); Field gpf = gp.createField( option::name( "gpf" ) ); - array::make_view( gpf ).assign(0); + array::make_view( gpf ).assign( 0 ); EXPECT_NO_THROW( trans.dirtrans( gpf, spf ) ); EXPECT_NO_THROW( trans.invtrans( spf, gpf ) ); @@ -402,7 +404,7 @@ CASE( "test_trans_using_grid" ) { EXPECT_NO_THROW( trans.invtrans( spfields, gpfields ) ); gpfields.add( gpf ); - EXPECT_THROWS_AS( trans.dirtrans( gpfields, spfields ), eckit::SeriousBug ); + EXPECT_THROWS_AS( trans.dirtrans( gpfields, spfields ), eckit::Exception ); } CASE( "test_trans_using_functionspace_NodeColumns" ) { @@ -416,7 +418,7 @@ CASE( "test_trans_using_functionspace_NodeColumns" ) { Field spf = sp.createField( option::name( "spf" ) ); Field gpf = gp.createField( option::name( "gpf" ) ); - array::make_view( gpf ).assign(0); + array::make_view( gpf ).assign( 0 ); EXPECT_NO_THROW( trans.dirtrans( gpf, spf ) ); EXPECT_NO_THROW( trans.invtrans( spf, gpf ) ); @@ -430,13 +432,13 @@ CASE( "test_trans_using_functionspace_NodeColumns" ) { EXPECT_NO_THROW( trans.invtrans( spfields, gpfields ) ); gpfields.add( gpf ); - EXPECT_THROWS_AS( trans.dirtrans( gpfields, spfields ), eckit::SeriousBug ); + EXPECT_THROWS_AS( trans.dirtrans( gpfields, spfields ), eckit::Exception ); } CASE( "test_trans_using_functionspace_StructuredColumns" ) { Log::info() << "test_trans_using_functionspace_StructuredColumns" << std::endl; - functionspace::StructuredColumns gp( Grid( "O48" ) ); + functionspace::StructuredColumns gp( Grid( "O48" ), grid::Partitioner( "trans" ) ); functionspace::Spectral sp( 47 ); trans::Trans trans( gp, sp ); @@ -444,7 +446,7 @@ CASE( "test_trans_using_functionspace_StructuredColumns" ) { Field spf = sp.createField( option::name( "spf" ) ); Field gpf = gp.createField( option::name( "gpf" ) ); - array::make_view( gpf ).assign(0); + array::make_view( gpf ).assign( 0 ); EXPECT_NO_THROW( trans.dirtrans( gpf, spf ) ); EXPECT_NO_THROW( trans.invtrans( spf, gpf ) ); @@ -458,7 +460,7 @@ CASE( "test_trans_using_functionspace_StructuredColumns" ) { EXPECT_NO_THROW( trans.invtrans( spfields, gpfields ) ); gpfields.add( gpf ); - EXPECT_THROWS_AS( trans.dirtrans( gpfields, spfields ), eckit::SeriousBug ); + EXPECT_THROWS_AS( trans.dirtrans( gpfields, spfields ), eckit::Exception ); } CASE( "test_trans_MIR_lonlat" ) { @@ -481,7 +483,7 @@ CASE( "test_trans_MIR_lonlat" ) { CASE( "test_trans_VorDivToUV" ) { int nfld = 1; // TODO: test for nfld>1 std::vector truncation_array{1}; // truncation_array{159,160,1279}; - for ( int i = 0; i < truncation_array.size(); ++i ) { + for ( size_t i = 0; i < truncation_array.size(); ++i ) { int truncation = truncation_array[i]; int nspec2 = ( truncation + 1 ) * ( truncation + 2 ); diff --git a/src/tests/trans/test_trans_invtrans_grad.cc b/src/tests/trans/test_trans_invtrans_grad.cc index ac5bff210..00d337123 100644 --- a/src/tests/trans/test_trans_invtrans_grad.cc +++ b/src/tests/trans/test_trans_invtrans_grad.cc @@ -10,6 +10,7 @@ #include +#include "atlas/array.h" #include "atlas/field/FieldSet.h" #include "atlas/functionspace/NodeColumns.h" #include "atlas/functionspace/Spectral.h" @@ -20,14 +21,13 @@ #include "atlas/library/Library.h" #include "atlas/mesh/Mesh.h" #include "atlas/mesh/Nodes.h" -#include "atlas/meshgenerator/StructuredMeshGenerator.h" +#include "atlas/meshgenerator.h" #include "atlas/option.h" #include "atlas/output/Gmsh.h" #include "atlas/parallel/mpi/mpi.h" #include "atlas/trans/Trans.h" #include "atlas/util/CoordinateEnums.h" #include "atlas/util/Earth.h" -#include "atlas/array.h" #include "tests/AtlasTestEnvironment.h" @@ -51,15 +51,15 @@ struct AtlasTransEnvironment : public AtlasTestEnvironment { /// @brief Compute magnitude of flow with rotation-angle beta /// (beta=0 --> zonal, beta=pi/2 --> meridional) -static void rotated_flow_magnitude( grid::StructuredGrid& grid, double var[], const double& beta ) { +static void rotated_flow_magnitude( StructuredGrid& grid, double var[], const double& beta ) { const double radius = util::Earth::radius(); const double USCAL = 20.; const double pvel = USCAL / radius; const double deg2rad = M_PI / 180.; - size_t n( 0 ); - for ( size_t jlat = 0; jlat < grid.ny(); ++jlat ) { - for ( size_t jlon = 0; jlon < grid.nx( jlat ); ++jlon ) { + idx_t n( 0 ); + for ( idx_t jlat = 0; jlat < grid.ny(); ++jlat ) { + for ( idx_t jlon = 0; jlon < grid.nx( jlat ); ++jlon ) { const double x = grid.x( jlon, jlat ) * deg2rad; const double y = grid.y( jlat ) * deg2rad; const double Ux = @@ -97,7 +97,7 @@ void rotated_flow_magnitude( const functionspace::NodeColumns& fs, Field& field, CASE( "test_invtrans_ifsStyle" ) { std::string grid_uid( "O80" ); - grid::StructuredGrid g( grid_uid ); + StructuredGrid g( grid_uid ); long N = g.ny() / 2; trans::TransIFS trans( g, 2 * N - 1 ); Log::info() << "Trans initialized" << std::endl; @@ -129,7 +129,7 @@ CASE( "test_invtrans_ifsStyle" ) { // Output { - Mesh mesh = meshgenerator::StructuredMeshGenerator().generate( g ); + Mesh mesh = StructuredMeshGenerator().generate( g ); functionspace::StructuredColumns gp( g ); output::Gmsh gmsh( grid_uid + "-grid.msh" ); Field scalar( "scalar", rgp.data(), array::make_shape( gp.size() ) ); @@ -144,9 +144,9 @@ CASE( "test_invtrans_ifsStyle" ) { CASE( "test_invtrans_grad" ) { std::string grid_uid( "O48" ); - grid::StructuredGrid g( grid_uid ); - Mesh mesh = meshgenerator::StructuredMeshGenerator().generate( g ); - long N = g.ny() / 2; + StructuredGrid g( grid_uid ); + Mesh mesh = StructuredMeshGenerator().generate( g ); + idx_t N = g.ny() / 2; trans::Trans trans( g, 2 * N - 1 ); functionspace::NodeColumns gp( mesh ); functionspace::Spectral sp( trans ); @@ -169,7 +169,7 @@ CASE( "test_invtrans_grad" ) { // Output { - Mesh mesh = meshgenerator::StructuredMeshGenerator().generate( g ); + Mesh mesh = StructuredMeshGenerator().generate( g ); functionspace::StructuredColumns gp( g ); output::Gmsh gmsh( grid_uid + "-nodes.msh" ); gmsh.write( mesh ); diff --git a/src/tests/trans/test_trans_localcache.cc b/src/tests/trans/test_trans_localcache.cc index 6220706ec..636e01461 100644 --- a/src/tests/trans/test_trans_localcache.cc +++ b/src/tests/trans/test_trans_localcache.cc @@ -15,7 +15,6 @@ #include "atlas/grid.h" #include "atlas/library/Library.h" -#include "atlas/meshgenerator/StructuredMeshGenerator.h" #include "atlas/option.h" #include "atlas/parallel/mpi/mpi.h" #include "atlas/runtime/Trace.h" @@ -37,8 +36,6 @@ struct AtlasTransEnvironment : public AtlasTestEnvironment { } }; -using grid::GaussianGrid; -using grid::StructuredGrid; using trans::Cache; using trans::LegendreCache; using trans::LegendreCacheCreator; diff --git a/src/tests/trans/test_transgeneral.cc b/src/tests/trans/test_transgeneral.cc index a12685406..01ba01753 100644 --- a/src/tests/trans/test_transgeneral.cc +++ b/src/tests/trans/test_transgeneral.cc @@ -24,7 +24,7 @@ #include "atlas/library/Library.h" #include "atlas/mesh/Mesh.h" #include "atlas/mesh/Nodes.h" -#include "atlas/meshgenerator/StructuredMeshGenerator.h" +#include "atlas/meshgenerator.h" #include "atlas/output/Gmsh.h" #include "atlas/parallel/mpi/mpi.h" #include "atlas/runtime/Trace.h" @@ -274,7 +274,7 @@ double sphericalharmonics_analytic_point( // Andreas Mueller *ECMWF* // void spectral_transform_grid_analytic( - const size_t trc, // truncation (in) + const int trc, // truncation (in) bool trcFT, // truncation for Fourier transformation (in) const double n, // total wave number (implemented so far for n<4) const double m, // zonal wave number (implemented so far for m<4, m g.y( 0 ) ) { jlatMin++; }; @@ -318,17 +318,17 @@ void spectral_transform_grid_analytic( } int idx = 0; - for ( size_t j = 0; j < g.ny(); ++j ) { + for ( idx_t j = 0; j < g.ny(); ++j ) { double lat = g.y( j ) * util::Constants::degreesToRadians(); int ftrc = trc + 1; if ( trcFT ) { ftrc = trans::fourier_truncation( trc, gs_global.nx( jlatMin + j ), gs_global.nxmax(), gs_global.ny(), - lat, grid::RegularGrid( gs_global ) ); + lat, RegularGrid( gs_global ) ); } /*Log::info() << "j=" << j << " ftrc=" << ftrc << " trc=" << trc << " nx=" << gs_global.nx( jlatMin + j ) << " nxmax=" << gs_global.nxmax() << " nlats=" << gs_global.ny() << " lat=" << g.y( j ) << " jlatMin=" << jlatMin << std::endl;*/ - for ( size_t i = 0; i < g.nx( j ); ++i ) { + for ( idx_t i = 0; i < g.nx( j ); ++i ) { double lon = g.x( i, j ) * util::Constants::degreesToRadians(); // compute spherical harmonics: @@ -364,7 +364,7 @@ double compute_rms( const size_t N, // length of the arrays double array2[] ) // second of the two arrays { double rms = 0., rmax = 0.; - for ( int idx = 0; idx < N; idx++ ) { + for ( size_t idx = 0; idx < N; idx++ ) { double diff = array1[idx] - array2[idx]; rms += diff * diff; rmax = std::max( rmax, std::abs( array2[idx] ) ); @@ -383,13 +383,12 @@ CASE( "test_trans_vordiv_with_translib" ) { // test transgeneral by comparing its result with the trans library // this test is based on the test_nomesh case in test_trans.cc - std::ostream& out = Log::info(); - double tolerance = 1.e-13; + double tolerance = 1.e-13; // Grid: (Adjust the following line if the test takes too long!) Grid g( "F64" ); - grid::StructuredGrid gs( g ); + StructuredGrid gs( g ); int ndgl = gs.ny(); //int trc = ndgl - 1; // linear int trc = ndgl / 2. - 1; // cubic @@ -617,8 +616,6 @@ CASE( "test_trans_domain" ) { // test transgeneral by comparing with analytic solution on a cropped domain // this test also includes testing caching - std::ostream& out = Log::info(); - //Domain testdomain = ZonalBandDomain( {-90., 90.} ); //Domain testdomain = ZonalBandDomain( {-.5, .5} ); //Domain testdomain = RectangularDomain( {0., 30.}, {-.05, .05} ); @@ -639,7 +636,6 @@ CASE( "test_trans_domain" ) { // fourierTrc1, fourierTrc2: need to be false if no global grid can be constructed // (like for grids created with LinearSpacing) - using grid::StructuredGrid; //using LinearSpacing = grid::LinearSpacing; //StructuredGrid g2( LinearSpacing( {0., 180.}, 3 ), LinearSpacing( {89., 90.}, 2 ) ); // when using LinearSpacing: set fourierTrc2 to false @@ -810,8 +806,6 @@ CASE( "test_trans_pole" ) { // test transform at the pole and with LinearSpacing grids // not using caching in this test because not useful for LinearSpacing grids - std::ostream& out = Log::info(); - //Domain testdomain = ZonalBandDomain( {-90., 90.} ); //Domain testdomain = ZonalBandDomain( {-.5, .5} ); //Domain testdomain = RectangularDomain( {0., 30.}, {-.05, .05} ); @@ -833,7 +827,6 @@ CASE( "test_trans_pole" ) { // fourierTrc1, fourierTrc2: need to be false if no global grid can be constructed // (like for grids created with LinearSpacing) - using grid::StructuredGrid; using LinearSpacing = grid::LinearSpacing; StructuredGrid g2( LinearSpacing( {0., 180.}, 3 ), LinearSpacing( {89., 90.}, 2 ) ); // when using LinearSpacing: set fourierTrc2 to false @@ -994,7 +987,6 @@ CASE( "test_trans_southpole" ) { Log::info() << "test_trans_southpole" << std::endl; // test created for MIR-283 (limited area domain on the southern hemisphere with L-grid) - std::ostream& out = Log::info(); //Domain testdomain = ZonalBandDomain( {-90., 90.} ); //Domain testdomain = ZonalBandDomain( {-.5, .5} ); @@ -1019,8 +1011,7 @@ CASE( "test_trans_southpole" ) { // fourierTrc1, fourierTrc2: need to be false if no global grid can be constructed // (like for grids created with LinearSpacing) - using grid::StructuredGrid; - using LinearSpacing = grid::LinearSpacing; + //using LinearSpacing = grid::LinearSpacing; //StructuredGrid g2( LinearSpacing( {0., 10.}, 2 ), LinearSpacing( {-10., -90.}, 9 ) ); // when using LinearSpacing: set fourierTrc2 to false @@ -1182,8 +1173,7 @@ CASE( "test_trans_unstructured" ) { Log::info() << "test_trans_unstructured" << std::endl; // test transgeneral by comparing with analytic solution on an unstructured grid - std::ostream& out = Log::info(); - double tolerance = 1.e-13; + double tolerance = 1.e-13; //Domain testdomain = RectangularDomain( {20., 25.}, {40., 60.} ); Domain testdomain = RectangularDomain( {0., 90.}, {0., 90.} ); @@ -1191,12 +1181,12 @@ CASE( "test_trans_unstructured" ) { Grid grid_global( "F32" ); Grid g( grid_global, testdomain ); int trc = 31; - grid::StructuredGrid gs( g ); + StructuredGrid gs( g ); std::vector pts( g.size() ); - int idx( 0 ); - for ( size_t j = 0; j < gs.ny(); ++j ) { + idx_t idx( 0 ); + for ( idx_t j = 0; j < gs.ny(); ++j ) { double lat = gs.y( j ); - for ( size_t i = 0; i < gs.nx( j ); ++i ) { + for ( idx_t i = 0; i < gs.nx( j ); ++i ) { double lon = gs.x( i, j ); if ( i == j && lat > 0 ) { //Log::info() << "idx=" << idx << " lon=" << lon << " lat=" << lat << std::endl; @@ -1204,7 +1194,7 @@ CASE( "test_trans_unstructured" ) { } } } - Grid gu = grid::UnstructuredGrid( new std::vector( &pts[0], &pts[idx] ) ); + Grid gu = UnstructuredGrid( new std::vector( &pts[0], &pts[idx] ) ); Log::info() << "gu: size=" << gu.size() << std::endl; double rav1 = 0., rav2 = 0.; // compute average rms errors of transLocal1 and transLocal2 @@ -1329,7 +1319,7 @@ CASE( "test_trans_unstructured" ) { } #endif -//----------------------------------------------------------------------------- + //----------------------------------------------------------------------------- #if 0 CASE( "test_trans_fourier_truncation" ) { diff --git a/src/tests/util/CMakeLists.txt b/src/tests/util/CMakeLists.txt index 9ff675620..fc72e9f75 100644 --- a/src/tests/util/CMakeLists.txt +++ b/src/tests/util/CMakeLists.txt @@ -15,12 +15,6 @@ if( HAVE_FCTEST ) LIBS atlas_f ) - add_fctest( TARGET atlas_fctest_error - LINKER_LANGUAGE Fortran - SOURCES fctest_error.F90 - LIBS atlas_f - ) - add_fctest( TARGET atlas_fctest_parametrisation CONDITION NOT atlas_fctest_parametrisation_DISABLED LINKER_LANGUAGE Fortran @@ -36,7 +30,7 @@ if( HAVE_FCTEST ) endif() -foreach( test earth flags footprint indexview polygon ) +foreach( test earth flags footprint indexview polygon point ) ecbuild_add_test( TARGET atlas_test_${test} SOURCES test_${test}.cc LIBS atlas diff --git a/src/tests/util/fctest_metadata.F90 b/src/tests/util/fctest_metadata.F90 index 2ade5e262..5404315d3 100644 --- a/src/tests/util/fctest_metadata.F90 +++ b/src/tests/util/fctest_metadata.F90 @@ -10,6 +10,7 @@ ! @author Willem Deconinck #include "fckit/fctest.h" +#include "atlas/atlas_f.h" ! ----------------------------------------------------------------------------- @@ -57,7 +58,7 @@ end module fcta_Metadata_fixture metadata = atlas_Metadata() - write(0,*) "metadata%c_ptr() = ", c_ptr_to_loc(metadata%c_ptr()) + write(0,*) "metadata%c_ptr() = ", c_ptr_to_loc(metadata%CPTR_PGIBUG_A) call metadata%set("true",.True.) call metadata%set("false",.False.) diff --git a/src/tests/util/fctest_parametrisation.F90 b/src/tests/util/fctest_parametrisation.F90 index 1bcc21bb1..ae889f829 100644 --- a/src/tests/util/fctest_parametrisation.F90 +++ b/src/tests/util/fctest_parametrisation.F90 @@ -15,6 +15,7 @@ module fctest_atlas_Config_fixture use atlas_module +use fckit_module, only : fckit_exception implicit none end module fctest_atlas_Config_fixture @@ -154,8 +155,8 @@ end module fctest_atlas_Config_fixture call atlas_log%info(params%json()) if( params%get("records",records) ) then do jrec=1,size(records) - if( .not. records(jrec)%get("name",name) ) call atlas_abort("name not found") - if( .not. records(jrec)%get("age",age) ) call atlas_abort("age not found") + if( .not. records(jrec)%get("name",name) ) call fckit_exception%abort("name not found") + if( .not. records(jrec)%get("age",age) ) call fckit_exception%abort("age not found") write(msg,'(2A,I0,A)') name," is ",age," years old"; call atlas_log%info(msg) enddo do jrec=1,size(records) @@ -187,8 +188,8 @@ end module fctest_atlas_Config_fixture if( params%get("records",records) ) then do jrec=1,size(records) - if( .not. records(jrec)%get("name",name) ) call atlas_abort("name not found") - if( .not. records(jrec)%get("age",age) ) call atlas_abort("age not found") + if( .not. records(jrec)%get("name",name) ) call fckit_exception%abort("name not found") + if( .not. records(jrec)%get("age",age) ) call fckit_exception%abort("age not found") write(msg,'(2A,I0,A)') name," is ",age," years old"; call atlas_log%info(msg) enddo do jrec=1,size(records) diff --git a/src/tests/util/test_footprint.cc b/src/tests/util/test_footprint.cc index 19876a460..8a5169a7d 100644 --- a/src/tests/util/test_footprint.cc +++ b/src/tests/util/test_footprint.cc @@ -18,7 +18,7 @@ #include "atlas/mesh/HybridElements.h" #include "atlas/mesh/Mesh.h" #include "atlas/mesh/Nodes.h" -#include "atlas/meshgenerator/MeshGenerator.h" +#include "atlas/meshgenerator.h" #include "atlas/runtime/Log.h" #include "atlas/util/Metadata.h" @@ -50,14 +50,14 @@ CASE( "test_broadcast_to_self" ) { Log::info() << "Footprint for mesh generated from grid " << grid.name() << std::endl; Log::info() << "mesh.footprint = " << eckit::Bytes( mesh.footprint() ) << std::endl; Log::info() << " .nodes.footprint = " << eckit::Bytes( mesh.nodes().footprint() ) << std::endl; - for ( size_t f = 0; f < mesh.nodes().nb_fields(); ++f ) { + for ( idx_t f = 0; f < mesh.nodes().nb_fields(); ++f ) { Log::info() << " ." + mesh.nodes().field( f ).name() + ".footprint = " << eckit::Bytes( mesh.nodes().field( f ).footprint() ) << std::endl; } Log::info() << " .cells.footprint = " << eckit::Bytes( mesh.cells().footprint() ) << std::endl; - for ( size_t f = 0; f < mesh.cells().nb_fields(); ++f ) { + for ( idx_t f = 0; f < mesh.cells().nb_fields(); ++f ) { Log::info() << " ." + mesh.cells().field( f ).name() + ".footprint = " << eckit::Bytes( mesh.cells().field( f ).footprint() ) << std::endl; } diff --git a/src/tests/util/test_point.cc b/src/tests/util/test_point.cc new file mode 100644 index 000000000..59340ad33 --- /dev/null +++ b/src/tests/util/test_point.cc @@ -0,0 +1,64 @@ +/* + * (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 + +#include "atlas/util/Point.h" + +#include "tests/AtlasTestEnvironment.h" + +using atlas::util::Earth; + +namespace atlas { +namespace test { + + +CASE( "test PointLonLat normalisation" ) { + // latitude at Valparaíso-Shanghai mid-point + PointLonLat p; + + p = PointLonLat( -71.6, -33. ); + p.normalise(); + EXPECT( is_approximately_equal( p.lon(), -71.6 + 360. ) ); + p.normalise( -180., 180. ); + EXPECT( is_approximately_equal( p.lon(), -71.6 ) ); + + p = PointLonLat( 121.8, 31.4 ); + p.normalise( -180., 180. ); + EXPECT( is_approximately_equal( p.lon(), 121.8 ) ); + + p = PointLonLat( 181., 31.4 ); + p.normalise( -180., 180. ); + EXPECT( is_approximately_equal( p.lon(), 181. - 360. ) ); + + p = PointLonLat( 180., 31.4 ); + p.normalise( -180., 180. ); + EXPECT( is_approximately_equal( p.lon(), 180. ) ); + + p = PointLonLat( 180., 31.4 ); + p.normalise( -180 ); + EXPECT( is_approximately_equal( p.lon(), -180. ) ); + + p = PointLonLat( -180., 31.4 ); + p.normalise( -180., 180. ); + EXPECT( is_approximately_equal( p.lon(), -180. ) ); + + p = PointLonLat( -180., 31.4 ); + p.normalise( -180. ); + EXPECT( is_approximately_equal( p.lon(), -180. ) ); +} + +} // namespace test +} // namespace atlas + +int main( int argc, char** argv ) { + return atlas::test::run( argc, argv ); +} diff --git a/src/tests/util/test_polygon.cc b/src/tests/util/test_polygon.cc index 656e46e27..fe3c6059f 100644 --- a/src/tests/util/test_polygon.cc +++ b/src/tests/util/test_polygon.cc @@ -22,8 +22,8 @@ namespace test { CASE( "test_polygon_something" ) { using util::SphericalPolygon; - using p = PointLonLat; - typedef std::pair point_inside_t; + using p = PointLonLat; + using point_inside_t = std::pair; SphericalPolygon poly( std::vector{ p( 122.143, 35.9951 ), p( 120, 30.4576 ), p( 118.125, 24.9199 ), p( 116.471, 19.3822 ), diff --git a/tools/apply-clang-format.sh b/tools/apply-clang-format.sh index 51f68ba34..4494e5dac 100755 --- a/tools/apply-clang-format.sh +++ b/tools/apply-clang-format.sh @@ -1,6 +1,20 @@ #!/usr/bin/env bash +# (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. + + SCRIPTDIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" cd $SCRIPTDIR/../src + +echo "Applying $(clang-format --version) ..." + find . -iname *.h -o -iname *.cc | xargs clang-format -i -style=file +echo "Applying $(clang-format --version) ... done" + diff --git a/tools/c2f.py b/tools/c2f.py index 31c77e07b..034e903af 100755 --- a/tools/c2f.py +++ b/tools/c2f.py @@ -25,7 +25,7 @@ 'size_t', 'float', 'double', - '_Bool' + '_Bool', ] c2ftype = { @@ -36,7 +36,7 @@ 'size_t':'integer(c_size_t)', 'float':'real(c_float)', 'double':'real(c_double)', - "_Bool":"logical(c_bool)", + '_Bool':'logical(c_bool)', } ftype2use = { @@ -282,10 +282,19 @@ def statements(self): parser.add_argument("file", type=str, help="file to parse") parser.add_argument("-o", "--output", type=str, help="output") parser.add_argument("-m", "--module", type=str, help="module") +parser.add_argument("-t", "--types", type=str, help='e.g. {"idx_t":"integer(c_int)","gidx_t":"integer(c_long)"}' ) parsed = parser.parse_args() input = parsed.file output = parsed.output module = parsed.module + +if( parsed.types ) : + import json + extra_types = json.loads( str(parsed.types) ) + for k in extra_types: + supported.append(k) + c2ftype[k] = extra_types[k] + if not module: module = output module = str(re.sub(r'(.+)(\..+)',r'\1',module)) @@ -341,7 +350,7 @@ def statements(self): for statement in code.statements(): try: intf += Function(statement).fortran_interface()+"\n" - except ParsingFailed( e ): + except ParsingFailed as e: print("\n\n"+"-"*80+"\n"+"Automatic generation of Fortran bindings failed for file\n\n"+ " "+input+"\n\n"+"ParsingFailed for statement:\n\n"+ " "+statement+"\n\nError: "+str(e)+"\n"+"-"*80+"\n") diff --git a/tools/install-dep.sh b/tools/install-dep.sh index c9b731aed..8c29427cb 100755 --- a/tools/install-dep.sh +++ b/tools/install-dep.sh @@ -1,5 +1,13 @@ #! /usr/bin/env bash +# (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. + SCRIPTDIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" export PATH=$SCRIPTDIR:$PATH diff --git a/tools/install-mpi.sh b/tools/install-mpi.sh index 3ae513d45..f019fa565 100755 --- a/tools/install-mpi.sh +++ b/tools/install-mpi.sh @@ -19,11 +19,11 @@ case "$os" in Darwin) case "$MPI" in mpich) - brew upgrade mpich || brew install mpich + brew ls --versions mpich || brew install mpich ;; openmpi) - brew upgrade openmpi || brew install openmpi - echo "localhost slots=12" >> /usr/local/etc/openmpi-default-hostfile + brew ls --versions openmpi || brew install openmpi + echo "localhost slots=72" >> /usr/local/etc/openmpi-default-hostfile ;; *) echo "Unknown MPI implementation: $MPI" @@ -85,6 +85,7 @@ case "$os" in ${SCRIPTDIR}/reduce-output.sh make -j4 ${SCRIPTDIR}/reduce-output.sh make install MPI_INSTALLED=true + echo "localhost slots=72" >> ${PREFIX}/etc/openmpi-default-hostfile cd - fi ;; diff --git a/tools/reduce-output.sh b/tools/reduce-output.sh index 4b88d3b9d..5faa2a34e 100755 --- a/tools/reduce-output.sh +++ b/tools/reduce-output.sh @@ -1,4 +1,14 @@ #!/bin/bash + +# (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. + + # Abort on Error set -e @@ -30,4 +40,4 @@ $@ >> $BUILD_OUTPUT 2>&1 dump_output # nicely terminate the ping output loop -kill $PING_LOOP_PID \ No newline at end of file +kill $PING_LOOP_PID diff --git a/tools/source-me.sh b/tools/source-me.sh index b855d6766..1fa1c5947 100644 --- a/tools/source-me.sh +++ b/tools/source-me.sh @@ -1,2 +1,10 @@ +# (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. + SCRIPTDIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" export PATH=$SCRIPTDIR:$PATH