diff --git a/CHANGELOG.md b/CHANGELOG.md index b7743f5a2..519370fd2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,15 @@ This project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html ## [Unreleased] +## [0.20.1] - 2019-04-08 +### Fixed +- Make feature BOUNDSCHECKING work again. It was not turned on for DEBUG builds +- Workaround clang OpenMP bug +- Fix Segfault due to unexpected order of destruction of singleton objects + +### Added +- atlas-grids tool can now be used to compute approximate North-South grid resolution + ## [0.20.0] - 2019-03-06 ### Fixed - Pole edges hould not be created for global regular grids with points at poles @@ -176,6 +185,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.20.1]: https://github.com/ecmwf/atlas/compare/0.20.0...0.20.1 [0.20.0]: https://github.com/ecmwf/atlas/compare/0.20.0...0.19.2 [0.19.2]: https://github.com/ecmwf/atlas/compare/0.19.1...0.19.2 [0.19.1]: https://github.com/ecmwf/atlas/compare/0.19.0...0.19.1 diff --git a/CMakeLists.txt b/CMakeLists.txt index 6763ccf69..a32af1d43 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -36,6 +36,7 @@ ecbuild_debug( " eckit_FEATURES : [${eckit_FEATURES}]" ) ################################################################################ # Features that can be enabled / disabled with -DENABLE_ +include( features/BOUNDSCHECKING ) include( features/FORTRAN ) include( features/MPI ) include( features/OMP ) diff --git a/VERSION b/VERSION index 5a03fb737..847e9aef6 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -0.20.0 +0.20.1 diff --git a/src/apps/atlas-grids.cc b/src/apps/atlas-grids.cc index 87c42ed3b..e31e43b8b 100644 --- a/src/apps/atlas-grids.cc +++ b/src/apps/atlas-grids.cc @@ -29,6 +29,51 @@ #include "atlas/grid/detail/grid/GridFactory.h" #include "atlas/runtime/AtlasTool.h" +namespace atlas { + +template +class FixedFormat { +public: + using value_type = Value; + FixedFormat( value_type x, long precision ) : x_( x ), precision_( precision > 0 ? precision : 20 ) {} + void print( std::ostream& out ) const { + for ( long precision = 0; precision <= precision_; ++precision ) { + if ( is_precision( precision ) || precision == precision_ ) { + out << std::setprecision( precision ); + out << std::fixed << x_; + break; + } + } + } + + bool is_precision( long precision ) const { + std::stringstream ss; + ss << std::setprecision( precision ); + ss << std::fixed << x_; + value_type _x; + ss >> _x; + return std::abs( x_ - _x ) < 1.e-20; + } + + friend std::ostream& operator<<( std::ostream& out, const FixedFormat& This ) { + This.print( out ); + return out; + } + +private: + float x_; + long precision_; +}; + +FixedFormat fixed_format( double x, long precision ) { + return FixedFormat( x, precision ); +} +FixedFormat fixed_format( float x, long precision ) { + return FixedFormat( x, precision ); +} + +} // namespace atlas + //---------------------------------------------------------------------------------------------------------------------- struct AtlasGrids : public atlas::AtlasTool { @@ -54,6 +99,9 @@ struct AtlasGrids : public atlas::AtlasTool { add_option( new SimpleOption( "check", "Check grid" ) ); add_option( new SimpleOption( "check-uid", "Check grid uid required" ) ); add_option( new SimpleOption( "check-boundingbox", "Check grid bounding_box(n,w,s,e) required" ) ); + add_option( new SimpleOption( "precision", "Precision used for float output" ) ); + add_option( + new SimpleOption( "approximate-resolution", "Approximate resolution in degrees (North-South)" ) ); } }; @@ -85,7 +133,10 @@ int AtlasGrids::execute( const Args& args ) { bool list = false; args.get( "list", list ); - bool do_run = list || ( !key.empty() && ( info || json || rtable || check ) ); + bool approximate_resolution = false; + args.get( "approximate-resolution", approximate_resolution ); + + bool do_run = list || ( !key.empty() && ( info || json || rtable || check || approximate_resolution ) ); if ( !key.empty() && !do_run ) { Log::error() << "Option wrong or missing after '" << key << "'" << std::endl; @@ -240,6 +291,24 @@ int AtlasGrids::execute( const Args& args ) { } } + if ( approximate_resolution ) { + if ( auto structuredgrid = StructuredGrid( grid ) ) { + if ( structuredgrid.domain().global() ) { + auto deg = ( structuredgrid.y().front() - structuredgrid.y().back() ) / ( structuredgrid.ny() - 1 ); + + long precision = -1; + args.get( "precision", precision ); + Log::info() << fixed_format( deg, precision ) << std::endl; + } + else { + ATLAS_NOTIMPLEMENTED; + } + } + else { + ATLAS_NOTIMPLEMENTED; + } + } + if ( json ) { std::stringstream stream; eckit::JSON js( stream ); diff --git a/src/atlas/functionspace/CellColumns.cc b/src/atlas/functionspace/CellColumns.cc index e53c01df3..e5352b569 100644 --- a/src/atlas/functionspace/CellColumns.cc +++ b/src/atlas/functionspace/CellColumns.cc @@ -79,6 +79,7 @@ class CellColumnsHaloExchangeCache : public util::Cache get_or_create( const Mesh& mesh ) { + registerMesh( *mesh.get() ); creator_type creator = std::bind( &CellColumnsHaloExchangeCache::create, mesh ); return Base::get_or_create( key( *mesh.get() ), creator ); } @@ -92,7 +93,6 @@ class CellColumnsHaloExchangeCache : public util::CacheattachObserver( instance() ); value_type* value = new value_type(); value->setup( array::make_view( mesh.cells().partition() ).data(), array::make_view( mesh.cells().remote_index() ).data(), REMOTE_IDX_BASE, @@ -113,6 +113,7 @@ class CellColumnsGatherScatterCache : public util::Cache get_or_create( const Mesh& mesh ) { + registerMesh( *mesh.get() ); creator_type creator = std::bind( &CellColumnsGatherScatterCache::create, mesh ); return Base::get_or_create( key( *mesh.get() ), creator ); } @@ -126,7 +127,6 @@ class CellColumnsGatherScatterCache : public util::CacheattachObserver( instance() ); value_type* value = new value_type(); value->setup( array::make_view( mesh.cells().partition() ).data(), array::make_view( mesh.cells().remote_index() ).data(), REMOTE_IDX_BASE, @@ -147,6 +147,7 @@ class CellColumnsChecksumCache : public util::Cache get_or_create( const Mesh& mesh ) { + registerMesh( *mesh.get() ); creator_type creator = std::bind( &CellColumnsChecksumCache::create, mesh ); return Base::get_or_create( key( *mesh.get() ), creator ); } @@ -160,7 +161,6 @@ class CellColumnsChecksumCache : public util::CacheattachObserver( instance() ); value_type* value = new value_type(); util::ObjectHandle gather( CellColumnsGatherScatterCache::instance().get_or_create( mesh ) ); @@ -247,10 +247,7 @@ array::ArrayShape CellColumns::config_shape( const eckit::Configuration& config } CellColumns::CellColumns( const Mesh& mesh, const eckit::Configuration& config ) : - mesh_( mesh ), - cells_( mesh_.cells() ), - nb_levels_( config.getInt( "levels", 0 ) ), - nb_cells_( 0 ) { + mesh_( mesh ), cells_( mesh_.cells() ), nb_levels_( config.getInt( "levels", 0 ) ), nb_cells_( 0 ) { ATLAS_TRACE(); if ( config.has( "halo" ) ) { halo_ = mesh::Halo( config.getInt( "halo" ) ); @@ -769,8 +766,7 @@ void atlas__fs__CellColumns__checksum_field( const CellColumns* This, const fiel CellColumns::CellColumns() : FunctionSpace(), functionspace_( nullptr ) {} CellColumns::CellColumns( const FunctionSpace& functionspace ) : - FunctionSpace( functionspace ), - functionspace_( dynamic_cast( get() ) ) {} + FunctionSpace( functionspace ), functionspace_( dynamic_cast( get() ) ) {} CellColumns::CellColumns( const Mesh& mesh, const eckit::Configuration& config ) : FunctionSpace( new detail::CellColumns( mesh, config ) ), diff --git a/src/atlas/functionspace/EdgeColumns.cc b/src/atlas/functionspace/EdgeColumns.cc index c4def6bb2..9448adc8e 100644 --- a/src/atlas/functionspace/EdgeColumns.cc +++ b/src/atlas/functionspace/EdgeColumns.cc @@ -80,6 +80,7 @@ class EdgeColumnsHaloExchangeCache : public util::Cache get_or_create( const Mesh& mesh ) { + registerMesh( *mesh.get() ); creator_type creator = std::bind( &EdgeColumnsHaloExchangeCache::create, mesh ); return Base::get_or_create( key( *mesh.get() ), creator ); } @@ -93,7 +94,6 @@ 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, @@ -114,6 +114,7 @@ class EdgeColumnsGatherScatterCache : public util::Cache get_or_create( const Mesh& mesh ) { + registerMesh( *mesh.get() ); creator_type creator = std::bind( &EdgeColumnsGatherScatterCache::create, mesh ); return Base::get_or_create( key( *mesh.get() ), creator ); } @@ -127,7 +128,6 @@ 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, @@ -148,6 +148,7 @@ class EdgeColumnsChecksumCache : public util::Cache get_or_create( const Mesh& mesh ) { + registerMesh( *mesh.get() ); creator_type creator = std::bind( &EdgeColumnsChecksumCache::create, mesh ); return Base::get_or_create( key( *mesh.get() ), creator ); } @@ -161,7 +162,6 @@ class EdgeColumnsChecksumCache : public util::CacheattachObserver( instance() ); value_type* value = new value_type(); util::ObjectHandle gather( EdgeColumnsGatherScatterCache::instance().get_or_create( mesh ) ); @@ -248,10 +248,7 @@ array::ArrayShape EdgeColumns::config_shape( const eckit::Configuration& config } EdgeColumns::EdgeColumns( const Mesh& mesh, const eckit::Configuration& config ) : - mesh_( mesh ), - edges_( mesh_.edges() ), - nb_levels_( config.getInt( "levels", 0 ) ), - nb_edges_( 0 ) { + mesh_( mesh ), edges_( mesh_.edges() ), nb_levels_( config.getInt( "levels", 0 ) ), nb_edges_( 0 ) { ATLAS_TRACE(); if ( config.has( "halo" ) ) { halo_ = mesh::Halo( config.getInt( "halo" ) ); @@ -767,8 +764,7 @@ void atlas__fs__EdgeColumns__checksum_field( const EdgeColumns* This, const fiel EdgeColumns::EdgeColumns() : FunctionSpace(), functionspace_( nullptr ) {} EdgeColumns::EdgeColumns( const FunctionSpace& functionspace ) : - FunctionSpace( functionspace ), - functionspace_( dynamic_cast( get() ) ) {} + FunctionSpace( functionspace ), functionspace_( dynamic_cast( get() ) ) {} EdgeColumns::EdgeColumns( const Mesh& mesh, const eckit::Configuration& config ) : FunctionSpace( new detail::EdgeColumns( mesh, config ) ), diff --git a/src/atlas/functionspace/NodeColumns.cc b/src/atlas/functionspace/NodeColumns.cc index a1cefe89d..b491489bb 100644 --- a/src/atlas/functionspace/NodeColumns.cc +++ b/src/atlas/functionspace/NodeColumns.cc @@ -80,6 +80,7 @@ class NodeColumnsHaloExchangeCache : public util::Cache get_or_create( const Mesh& mesh, long halo ) { + registerMesh( *mesh.get() ); creator_type creator = std::bind( &NodeColumnsHaloExchangeCache::create, mesh, halo ); return Base::get_or_create( key( *mesh.get(), halo ), creator ); } @@ -97,8 +98,6 @@ class NodeColumnsHaloExchangeCache : public util::CacheattachObserver( instance() ); - value_type* value = new value_type(); std::ostringstream ss; @@ -125,6 +124,7 @@ class NodeColumnsGatherScatterCache : public util::Cache get_or_create( const Mesh& mesh ) { + registerMesh( *mesh.get() ); creator_type creator = std::bind( &NodeColumnsGatherScatterCache::create, mesh ); return Base::get_or_create( key( *mesh.get() ), creator ); } @@ -138,8 +138,6 @@ class NodeColumnsGatherScatterCache : public util::CacheattachObserver( instance() ); - value_type* value = new value_type(); mesh::IsGhostNode is_ghost( mesh.nodes() ); @@ -176,6 +174,7 @@ class NodeColumnsChecksumCache : public util::Cache get_or_create( const Mesh& mesh ) { + registerMesh( *mesh.get() ); creator_type creator = std::bind( &NodeColumnsChecksumCache::create, mesh ); return Base::get_or_create( key( *mesh.get() ), creator ); } @@ -189,7 +188,6 @@ class NodeColumnsChecksumCache : public util::CacheattachObserver( instance() ); value_type* value = new value_type(); util::ObjectHandle gather( NodeColumnsGatherScatterCache::instance().get_or_create( mesh ) ); @@ -201,10 +199,7 @@ class NodeColumnsChecksumCache : public util::Cache( get() ) ) {} + FunctionSpace( functionspace ), functionspace_( dynamic_cast( get() ) ) {} namespace { detail::NodeColumns* make_functionspace( Mesh mesh, const eckit::Configuration& config ) { diff --git a/src/atlas/functionspace/detail/StructuredColumns.cc b/src/atlas/functionspace/detail/StructuredColumns.cc index 7449c544b..b7cfa42ee 100644 --- a/src/atlas/functionspace/detail/StructuredColumns.cc +++ b/src/atlas/functionspace/detail/StructuredColumns.cc @@ -102,6 +102,8 @@ class StructuredColumnsHaloExchangeCache : public util::Cache get_or_create( const detail::StructuredColumns& funcspace ) { + registerGrid( *funcspace.grid().get() ); + creator_type creator = std::bind( &StructuredColumnsHaloExchangeCache::create, &funcspace ); return Base::get_or_create( key( *funcspace.grid().get(), funcspace.halo() ), remove_key( *funcspace.grid().get() ), creator ); @@ -122,8 +124,6 @@ class StructuredColumnsHaloExchangeCache : public util::Cachegrid().get()->attachObserver( instance() ); - value_type* value = new value_type(); value->setup( array::make_view( funcspace->partition() ).data(), @@ -146,6 +146,7 @@ class StructuredColumnsGatherScatterCache : public util::Cache get_or_create( const detail::StructuredColumns& funcspace ) { + registerGrid( *funcspace.grid().get() ); creator_type creator = std::bind( &StructuredColumnsGatherScatterCache::create, &funcspace ); return Base::get_or_create( key( *funcspace.grid().get() ), creator ); } @@ -159,8 +160,6 @@ class StructuredColumnsGatherScatterCache : public util::Cachegrid().get()->attachObserver( instance() ); - value_type* value = new value_type(); value->setup( array::make_view( funcspace->partition() ).data(), @@ -183,6 +182,7 @@ class StructuredColumnsChecksumCache : public util::Cache get_or_create( const detail::StructuredColumns& funcspace ) { + registerGrid( *funcspace.grid().get() ); creator_type creator = std::bind( &StructuredColumnsChecksumCache::create, &funcspace ); return Base::get_or_create( key( *funcspace.grid().get() ), creator ); } @@ -196,7 +196,6 @@ class StructuredColumnsChecksumCache : public util::Cachegrid().get()->attachObserver( instance() ); value_type* value = new value_type(); util::ObjectHandle gather( StructuredColumnsGatherScatterCache::instance().get_or_create( *funcspace ) ); @@ -385,9 +384,7 @@ StructuredColumns::StructuredColumns( const Grid& grid, const grid::Distribution 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 ) ) { + vertical_( vertical ), nb_levels_( vertical_.size() ), grid_( new StructuredGrid( grid ) ) { setup( distribution, config ); } @@ -396,9 +393,7 @@ StructuredColumns::StructuredColumns( const Grid& grid, const Vertical& vertical 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 ) ) { + vertical_( vertical ), nb_levels_( vertical_.size() ), grid_( new StructuredGrid( grid ) ) { ATLAS_TRACE( "StructuredColumns constructor" ); grid::Partitioner partitioner( p ); diff --git a/src/atlas/functionspace/detail/StructuredColumns_setup.cc b/src/atlas/functionspace/detail/StructuredColumns_setup.cc index e55225336..84c5e3a6d 100644 --- a/src/atlas/functionspace/detail/StructuredColumns_setup.cc +++ b/src/atlas/functionspace/detail/StructuredColumns_setup.cc @@ -274,8 +274,8 @@ void StructuredColumns::setup( const grid::Distribution& distribution, const eck }; auto compute_i_less_equal_x = [this, &eps]( const double& x, idx_t j ) -> idx_t { - const double dx = grid_->xspace().dx()[j]; - idx_t i = idx_t( std::floor( ( x + eps - grid_->xspace().xmin()[j] ) / dx ) ); + const double dx = grid_->dx(j); + idx_t i = idx_t( std::floor( ( x + eps - grid_->xmin(j) ) / dx ) ); return i; }; @@ -346,6 +346,7 @@ void StructuredColumns::setup( const grid::Distribution& distribution, const eck } 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 ) { diff --git a/src/atlas/grid/StructuredGrid.h b/src/atlas/grid/StructuredGrid.h index f1c5fed87..e8de1c8fb 100644 --- a/src/atlas/grid/StructuredGrid.h +++ b/src/atlas/grid/StructuredGrid.h @@ -88,6 +88,13 @@ class StructuredGrid : public Grid { /// y coordinate for given grid row {j} inline double y( idx_t j ) const { return grid_->y( j ); } + /// increment in x for a given grid row {j} + inline double dx( idx_t j ) const { return grid_->dx( j ); } + + /// x coordinate of beginning of a given grid row {j} + inline double xmin( idx_t j ) const { return grid_->xmin( j ); } + + using Grid::xy; void xy( idx_t i, idx_t j, double xy[] ) const { grid_->xy( i, j, xy ); } diff --git a/src/atlas/grid/detail/grid/Grid.cc b/src/atlas/grid/detail/grid/Grid.cc index a29db3a49..f935375f1 100644 --- a/src/atlas/grid/detail/grid/Grid.cc +++ b/src/atlas/grid/detail/grid/Grid.cc @@ -104,8 +104,10 @@ Grid::Grid() { } Grid::~Grid() { - for ( GridObserver* o : grid_observers_ ) { + while ( grid_observers_.size() ) { + GridObserver* o = grid_observers_.back(); o->onGridDestruction( *this ); + o->unregisterGrid( *this ); // will also delete observer from mesh } } diff --git a/src/atlas/grid/detail/grid/Grid.h b/src/atlas/grid/detail/grid/Grid.h index 15052e6bf..320b68024 100644 --- a/src/atlas/grid/detail/grid/Grid.h +++ b/src/atlas/grid/detail/grid/Grid.h @@ -10,6 +10,7 @@ #pragma once +#include #include #include #include @@ -149,7 +150,28 @@ class Grid : public util::Object { }; class GridObserver { +private: + std::vector registered_grids_; + public: + void registerGrid( const Grid& grid ) { + if ( std::find( registered_grids_.begin(), registered_grids_.end(), &grid ) == registered_grids_.end() ) { + registered_grids_.push_back( &grid ); + grid.attachObserver( *this ); + } + } + void unregisterGrid( const Grid& grid ) { + auto found = std::find( registered_grids_.begin(), registered_grids_.end(), &grid ); + if ( found != registered_grids_.end() ) { + registered_grids_.erase( found ); + grid.detachObserver( *this ); + } + } + virtual ~GridObserver() { + for ( auto grid : registered_grids_ ) { + grid->detachObserver( *this ); + } + } virtual void onGridDestruction( Grid& ) = 0; }; diff --git a/src/atlas/grid/detail/grid/Structured.h b/src/atlas/grid/detail/grid/Structured.h index 6bc0906f0..8e45710f5 100644 --- a/src/atlas/grid/detail/grid/Structured.h +++ b/src/atlas/grid/detail/grid/Structured.h @@ -309,6 +309,8 @@ class Structured : public Grid { inline double dx( idx_t j ) const { return dx_[j]; } + inline double xmin( idx_t j ) const { return xmin_[j]; } + inline double x( idx_t i, idx_t j ) const { return xmin_[j] + static_cast( i ) * dx_[j]; } inline double y( idx_t j ) const { return y_[j]; } diff --git a/src/atlas/interpolation/method/fe/FiniteElement.cc b/src/atlas/interpolation/method/fe/FiniteElement.cc index 3d7d779e6..13e34dfdd 100644 --- a/src/atlas/interpolation/method/fe/FiniteElement.cc +++ b/src/atlas/interpolation/method/fe/FiniteElement.cc @@ -62,7 +62,7 @@ void FiniteElement::setup( const Grid& source, const Grid& target ) { auto functionspace = []( const Grid& grid ) { Mesh mesh; if ( StructuredGrid{grid} ) { - mesh = MeshGenerator( "structured", util::Config( "three_dimensional", true ) ).generate( grid ); + mesh = MeshGenerator( "structured", util::Config( "3d", true ) ).generate( grid ); } else { mesh = MeshGenerator( "delaunay" ).generate( grid ); diff --git a/src/atlas/interpolation/method/knn/KNearestNeighbours.cc b/src/atlas/interpolation/method/knn/KNearestNeighbours.cc index d2d3a6d35..896a507fc 100644 --- a/src/atlas/interpolation/method/knn/KNearestNeighbours.cc +++ b/src/atlas/interpolation/method/knn/KNearestNeighbours.cc @@ -49,7 +49,7 @@ void KNearestNeighbours::setup( const Grid& source, const Grid& target ) { auto functionspace = []( const Grid& grid ) -> FunctionSpace { Mesh mesh; if ( StructuredGrid( grid ) ) { - mesh = MeshGenerator( "structured", util::Config( "three_dimensional", true ) ).generate( grid ); + mesh = MeshGenerator( "structured", util::Config( "3d", true ) ).generate( grid ); } else { mesh = MeshGenerator( "delaunay" ).generate( grid ); diff --git a/src/atlas/interpolation/method/knn/NearestNeighbour.cc b/src/atlas/interpolation/method/knn/NearestNeighbour.cc index d148d6aec..d7eebf11f 100644 --- a/src/atlas/interpolation/method/knn/NearestNeighbour.cc +++ b/src/atlas/interpolation/method/knn/NearestNeighbour.cc @@ -40,7 +40,7 @@ void NearestNeighbour::setup( const Grid& source, const Grid& target ) { auto functionspace = []( const Grid& grid ) -> FunctionSpace { Mesh mesh; if ( StructuredGrid( grid ) ) { - mesh = MeshGenerator( "structured", util::Config( "three_dimensional" ) ).generate( grid ); + mesh = MeshGenerator( "structured", util::Config( "3d", true ) ).generate( grid ); } else { mesh = MeshGenerator( "delaunay" ).generate( grid ); diff --git a/src/atlas/library/Library.cc b/src/atlas/library/Library.cc index 79bc91ee2..e9ec725be 100644 --- a/src/atlas/library/Library.cc +++ b/src/atlas/library/Library.cc @@ -207,6 +207,14 @@ void Library::finalise() { Log::debug() << "Atlas finalised" << std::endl; Log::flush(); + + if ( debugChannel() ) { + debug_channel_.reset( new eckit::Channel( new eckit::PrefixTarget( "ATLAS_DEBUG" ) ) ); + } + if ( infoChannel() ) { + info_ = false; + info_channel_.reset( new eckit::Channel( new eckit::PrefixTarget( "ATLAS_INFO" ) ) ); + } } eckit::Channel& Library::infoChannel() const { diff --git a/src/atlas/mesh/actions/BuildDualMesh.cc b/src/atlas/mesh/actions/BuildDualMesh.cc index 5a2acd6a4..4d38441a0 100644 --- a/src/atlas/mesh/actions/BuildDualMesh.cc +++ b/src/atlas/mesh/actions/BuildDualMesh.cc @@ -90,6 +90,12 @@ void make_dual_normals_outward( Mesh& mesh ); void build_median_dual_mesh( Mesh& mesh ) { ATLAS_TRACE(); + bool median_dual_mesh = false; + mesh.metadata().get( "median_dual_mesh", median_dual_mesh ); + if ( median_dual_mesh ) { + return; + } + mesh.metadata().set( "median_dual_mesh", true ); mesh::Nodes& nodes = mesh.nodes(); mesh::HybridElements& edges = mesh.edges(); diff --git a/src/atlas/mesh/detail/MeshImpl.cc b/src/atlas/mesh/detail/MeshImpl.cc index e91700794..dc894de28 100644 --- a/src/atlas/mesh/detail/MeshImpl.cc +++ b/src/atlas/mesh/detail/MeshImpl.cc @@ -43,8 +43,10 @@ MeshImpl::MeshImpl() : nodes_( new mesh::Nodes() ), dimensionality_( 2 ) { } MeshImpl::~MeshImpl() { - for ( MeshObserver* o : mesh_observers_ ) { + while ( mesh_observers_.size() ) { + MeshObserver* o = mesh_observers_.back(); o->onMeshDestruction( *this ); + o->unregisterMesh( *this ); // will also delete observer from mesh } } diff --git a/src/atlas/mesh/detail/MeshImpl.h b/src/atlas/mesh/detail/MeshImpl.h index 4aa40f866..2d5ea2048 100644 --- a/src/atlas/mesh/detail/MeshImpl.h +++ b/src/atlas/mesh/detail/MeshImpl.h @@ -155,7 +155,29 @@ class MeshImpl : public util::Object { //---------------------------------------------------------------------------------------------------------------------- class MeshObserver { +private: + std::vector registered_meshes_; + public: + void registerMesh( const MeshImpl& mesh ) { + if ( std::find( registered_meshes_.begin(), registered_meshes_.end(), &mesh ) == registered_meshes_.end() ) { + registered_meshes_.push_back( &mesh ); + mesh.attachObserver( *this ); + } + } + void unregisterMesh( const MeshImpl& mesh ) { + auto found = std::find( registered_meshes_.begin(), registered_meshes_.end(), &mesh ); + if ( found != registered_meshes_.end() ) { + registered_meshes_.erase( found ); + mesh.detachObserver( *this ); + } + } + virtual ~MeshObserver() { + for ( auto mesh : registered_meshes_ ) { + mesh->detachObserver( *this ); + } + } + virtual void onMeshDestruction( MeshImpl& ) = 0; }; diff --git a/src/atlas/parallel/omp/sort.h b/src/atlas/parallel/omp/sort.h index 9a48a9081..480009b02 100644 --- a/src/atlas/parallel/omp/sort.h +++ b/src/atlas/parallel/omp/sort.h @@ -32,6 +32,16 @@ #endif #endif +#ifndef ATLAS_OMP_TASK_UNTIED_SUPPORTED +#define ATLAS_OMP_TASK_UNTIED_SUPPORTED 1 +#endif +#ifdef __clang__ +#if __clang_major__ <= 7 +#undef ATLAS_OMP_TASK_UNTIED_SUPPORTED +#define ATLAS_OMP_TASK_UNTIED_SUPPORTED 0 +#endif +#endif + namespace atlas { namespace omp { @@ -103,9 +113,17 @@ void merge_sort_recursive( const RandomAccessIterator& iterator, size_t begin, s // --> it would be preferred to use taskgroup and taskyield instead of taskwait, // but this leads to segfaults on Cray (cce/8.5.8) { +#if ATLAS_OMP_TASK_UNTIED_SUPPORTED #pragma omp task shared( iterator ) untied if ( size >= ( 1 << 15 ) ) +#else +#pragma omp task shared( iterator ) +#endif merge_sort_recursive( iterator, begin, mid, compare ); +#if ATLAS_OMP_TASK_UNTIED_SUPPORTED #pragma omp task shared( iterator ) untied if ( size >= ( 1 << 15 ) ) +#else +#pragma omp task shared( iterator ) +#endif merge_sort_recursive( iterator, mid, end, compare ); //#pragma omp taskyield #pragma omp taskwait @@ -221,3 +239,6 @@ void merge_blocks( RandomAccessIterator first, RandomAccessIterator last, Random } // namespace omp } // namespace atlas + +#undef ATLAS_OMP_TASK_UNTIED_SUPPORTED +#undef ATLAS_HAVE_OMP_SORTING diff --git a/src/tests/grid/test_grids.cc b/src/tests/grid/test_grids.cc index af27be1b3..e1a211f69 100644 --- a/src/tests/grid/test_grids.cc +++ b/src/tests/grid/test_grids.cc @@ -382,6 +382,37 @@ CASE( "test_structured_triangulated" ) { } } +CASE( "test_structured_from_config" ) { + Config config; + config.set( "type", "structured" ); + config.set( "xspace", []() { + Config config; + config.set( "type", "linear" ); + config.set( "N", 40 ); + config.set( "start", 5 ); + config.set( "end", 365 ); + config.set( "endpoint", false ); + return config; + }() ); + config.set( "yspace", []() { + Config config; + config.set( "type", "custom" ); + config.set( "N", 9 ); + config.set( "values", std::vector{5., 15., 25., 35., 45., 55., 65., 75., 85.} ); + return config; + }() ); + StructuredGrid g{config}; + for ( idx_t j = 0; j < g.ny(); ++j ) { + EXPECT_EQ( g.nx(j) , 40 ); + EXPECT_EQ( g.x(0,j), 5. ); + EXPECT_EQ( g.x(g.nx(j),j), 365.); + EXPECT_EQ( g.dx(j), 9.); + EXPECT_EQ( g.xmin(j), 5.); + } + EXPECT( not g.domain().global() ); +} + + //----------------------------------------------------------------------------- } // namespace test